Add helper functions for adding an item to an array only if it's not already contained (#17833)

* Add helper functions for adding an item to an array only if it's not already contained

* One more use of appendIfUnique
This commit is contained in:
Andy 2017-08-24 08:03:05 -07:00 committed by GitHub
parent cd2ea9a12f
commit 2fede097f3
3 changed files with 42 additions and 57 deletions

View file

@ -1881,10 +1881,9 @@ namespace ts {
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
function visit(symbol: Symbol): SymbolTable {
if (!(symbol && symbol.flags & SymbolFlags.HasExports && !contains(visitedSymbols, symbol))) {
if (!(symbol && symbol.flags & SymbolFlags.HasExports && pushIfUnique(visitedSymbols, symbol))) {
return;
}
visitedSymbols.push(symbol);
const symbols = cloneMap(symbol.exports);
// All export * declarations are collected in an __export symbol by the binder
const exportStars = symbol.exports.get(InternalSymbolName.ExportStar);
@ -2060,10 +2059,10 @@ namespace ts {
}
function getAccessibleSymbolChainFromSymbolTableWorker(symbols: SymbolTable, visitedSymbolTables: SymbolTable[]): Symbol[] {
if (contains<SymbolTable>(visitedSymbolTables, symbols)) {
if (!pushIfUnique(visitedSymbolTables, symbols)) {
return undefined;
}
visitedSymbolTables.push(symbols);
const result = trySymbolTable(symbols);
visitedSymbolTables.pop();
return result;
@ -2276,14 +2275,7 @@ namespace ts {
// since we will do the emitting later in trackSymbol.
if (shouldComputeAliasToMakeVisible) {
getNodeLinks(declaration).isVisible = true;
if (aliasesToMakeVisible) {
if (!contains(aliasesToMakeVisible, anyImportSyntax)) {
aliasesToMakeVisible.push(anyImportSyntax);
}
}
else {
aliasesToMakeVisible = [anyImportSyntax];
}
aliasesToMakeVisible = appendIfUnique(aliasesToMakeVisible, anyImportSyntax);
}
return true;
}
@ -3981,9 +3973,7 @@ namespace ts {
forEach(declarations, declaration => {
getNodeLinks(declaration).isVisible = true;
const resultNode = getAnyImportSyntax(declaration) || declaration;
if (!contains(result, resultNode)) {
result.push(resultNode);
}
pushIfUnique(result, resultNode);
if (isInternalModuleImportEqualsDeclaration(declaration)) {
// Add the referenced top container visible
@ -4793,12 +4783,7 @@ namespace ts {
function appendTypeParameters(typeParameters: TypeParameter[], declarations: ReadonlyArray<TypeParameterDeclaration>): TypeParameter[] {
for (const declaration of declarations) {
const tp = getDeclaredTypeOfTypeParameter(getSymbolOfNode(declaration));
if (!typeParameters) {
typeParameters = [tp];
}
else if (!contains(typeParameters, tp)) {
typeParameters.push(tp);
}
typeParameters = appendIfUnique(typeParameters, tp);
}
return typeParameters;
}
@ -5521,9 +5506,7 @@ namespace ts {
if (!match) {
return undefined;
}
if (!contains(result, match)) {
(result || (result = [])).push(match);
}
result = appendIfUnique(result, match);
}
return result;
}
@ -6073,12 +6056,7 @@ namespace ts {
const modifiers = prop ? getDeclarationModifierFlagsFromSymbol(prop) : 0;
if (prop && !(modifiers & excludeModifiers)) {
commonFlags &= prop.flags;
if (!props) {
props = [prop];
}
else if (!contains(props, prop)) {
props.push(prop);
}
props = appendIfUnique(props, prop);
checkFlags |= (isReadonlySymbol(prop) ? CheckFlags.Readonly : 0) |
(!(modifiers & ModifierFlags.NonPublicAccessibilityModifier) ? CheckFlags.ContainsPublic : 0) |
(modifiers & ModifierFlags.Protected ? CheckFlags.ContainsProtected : 0) |
@ -6237,12 +6215,7 @@ namespace ts {
let result: TypeParameter[];
forEach(getEffectiveTypeParameterDeclarations(declaration), node => {
const tp = getDeclaredTypeOfTypeParameter(node.symbol);
if (!contains(result, tp)) {
if (!result) {
result = [];
}
result.push(tp);
}
result = appendIfUnique(result, tp);
});
return result;
}
@ -11715,9 +11688,7 @@ namespace ts {
if (type === declaredType && declaredType === initialType) {
return type;
}
if (!contains(antecedentTypes, type)) {
antecedentTypes.push(type);
}
pushIfUnique(antecedentTypes, type);
// If an antecedent type is not a subset of the declared type, we need to perform
// subtype reduction. This happens when a "foreign" type is injected into the control
// flow using the instanceof operator or a user defined type predicate.
@ -11783,9 +11754,7 @@ namespace ts {
if (cached) {
return cached;
}
if (!contains(antecedentTypes, type)) {
antecedentTypes.push(type);
}
pushIfUnique(antecedentTypes, type);
// If an antecedent type is not a subset of the declared type, we need to perform
// subtype reduction. This happens when a "foreign" type is injected into the control
// flow using the instanceof operator or a user defined type predicate.
@ -16826,9 +16795,7 @@ namespace ts {
? Diagnostics.Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member
: Diagnostics.Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
if (!contains(aggregatedTypes, type)) {
aggregatedTypes.push(type);
}
pushIfUnique(aggregatedTypes, type);
}
});
@ -16880,9 +16847,7 @@ namespace ts {
if (type.flags & TypeFlags.Never) {
hasReturnOfTypeNever = true;
}
else if (!contains(aggregatedTypes, type)) {
aggregatedTypes.push(type);
}
pushIfUnique(aggregatedTypes, type);
}
else {
hasReturnWithNoExpression = true;
@ -16893,9 +16858,7 @@ namespace ts {
return undefined;
}
if (strictNullChecks && aggregatedTypes.length && hasReturnWithNoExpression) {
if (!contains(aggregatedTypes, undefinedType)) {
aggregatedTypes.push(undefinedType);
}
pushIfUnique(aggregatedTypes, undefinedType);
}
return aggregatedTypes;
}

View file

@ -771,6 +771,32 @@ namespace ts {
return to;
}
/**
* @return Whether the value was added.
*/
export function pushIfUnique<T>(array: T[], toAdd: T): boolean {
if (contains(array, toAdd)) {
return false;
}
else {
array.push(toAdd);
return true;
}
}
/**
* Unlike `pushIfUnique`, this can take `undefined` as an input, and returns a new array.
*/
export function appendIfUnique<T>(array: T[] | undefined, toAdd: T): T[] {
if (array) {
pushIfUnique(array, toAdd);
return array;
}
else {
return [toAdd];
}
}
/**
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
*/

View file

@ -2636,9 +2636,7 @@ namespace ts {
if (some(helpers)) {
const emitNode = getOrCreateEmitNode(node);
for (const helper of helpers) {
if (!contains(emitNode.helpers, helper)) {
emitNode.helpers = append(emitNode.helpers, helper);
}
emitNode.helpers = appendIfUnique(emitNode.helpers, helper);
}
}
return node;
@ -2680,9 +2678,7 @@ namespace ts {
const helper = sourceEmitHelpers[i];
if (predicate(helper)) {
helpersRemoved++;
if (!contains(targetEmitNode.helpers, helper)) {
targetEmitNode.helpers = append(targetEmitNode.helpers, helper);
}
targetEmitNode.helpers = appendIfUnique(targetEmitNode.helpers, helper);
}
else if (helpersRemoved > 0) {
sourceEmitHelpers[i - helpersRemoved] = helper;