completions: Add assertions that symbols are defined (#21764)

* completions: Add assertions that symbols are defined

* Add assertion messages
This commit is contained in:
Andy 2018-02-08 10:20:01 -08:00 committed by GitHub
parent 353cfbddc6
commit 2a17825428
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 15 deletions

View File

@ -2901,6 +2901,13 @@ namespace ts {
return value;
}
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message: string): A {
for (const v of value) {
assertDefined(v, message);
}
return value;
}
export function assertNever(member: never, message?: string, stackCrawlMark?: AnyFunction): never {
return fail(message || `Illegal value: ${member}`, stackCrawlMark || assertNever);
}

View File

@ -912,7 +912,7 @@ namespace ts.Completions {
getTypeScriptMemberSymbols();
}
else if (isRightOfOpenTag) {
const tagSymbols = typeChecker.getJsxIntrinsicTagNames();
const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNames(), "getJsxIntrinsicTagNames() should all be defined");
if (tryGetGlobalSymbols()) {
symbols = tagSymbols.concat(symbols.filter(s => !!(s.flags & (SymbolFlags.Value | SymbolFlags.Alias))));
}
@ -923,7 +923,7 @@ namespace ts.Completions {
}
else if (isStartingCloseTag) {
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
const tagSymbol = typeChecker.getSymbolAtLocation(tagName);
const tagSymbol = Debug.assertDefined(typeChecker.getSymbolAtLocation(tagName));
if (!typeChecker.isUnknownSymbol(tagSymbol)) {
symbols = [tagSymbol];
@ -971,7 +971,7 @@ namespace ts.Completions {
if (symbol.flags & (SymbolFlags.Module | SymbolFlags.Enum)) {
// Extract module or enum members
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
const exportedSymbols = Debug.assertEachDefined(typeChecker.getExportsOfModule(symbol), "getExportsOfModule() should all be defined");
const isValidValueAccess = (symbol: Symbol) => typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name);
const isValidTypeAccess = (symbol: Symbol) => symbolCanBeReferencedAtTypeLocation(symbol);
const isValidAccess = isRhsOfImportDeclaration ?
@ -1111,7 +1111,7 @@ namespace ts.Completions {
const symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
symbols = Debug.assertEachDefined(typeChecker.getSymbolsInScope(scopeNode, symbolMeanings), "getSymbolsInScope() should all be defined");
// Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
if (options.includeInsertTextCompletions && scopeNode.kind !== SyntaxKind.SourceFile) {
@ -1452,7 +1452,7 @@ namespace ts.Completions {
if (typeMembers && typeMembers.length > 0) {
// Add filtered items to the completion list
symbols = filterObjectMembersList(typeMembers, existingMembers);
symbols = filterObjectMembersList(typeMembers, Debug.assertDefined(existingMembers));
}
return true;
}
@ -1926,11 +1926,7 @@ namespace ts.Completions {
existingImportsOrExports.set(name.escapedText, true);
}
if (existingImportsOrExports.size === 0) {
return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default);
}
return filter(exportsOfModule, e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName));
return exportsOfModule.filter(e => e.escapedName !== InternalSymbolName.Default && !existingImportsOrExports.get(e.escapedName));
}
/**
@ -1940,7 +1936,7 @@ namespace ts.Completions {
* do not occur at the current position and have not otherwise been typed.
*/
function filterObjectMembersList(contextualMemberSymbols: Symbol[], existingMembers: ReadonlyArray<Declaration>): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
if (existingMembers.length === 0) {
return contextualMemberSymbols;
}
@ -1980,7 +1976,7 @@ namespace ts.Completions {
existingMemberNames.set(existingName, true);
}
return filter(contextualMemberSymbols, m => !existingMemberNames.get(m.escapedName));
return contextualMemberSymbols.filter(m => !existingMemberNames.get(m.escapedName));
}
/**
@ -2066,7 +2062,7 @@ namespace ts.Completions {
}
}
return filter(symbols, a => !seenNames.get(a.escapedName));
return symbols.filter(a => !seenNames.get(a.escapedName));
}
function isCurrentlyEditingNode(node: Node): boolean {
@ -2248,13 +2244,13 @@ namespace ts.Completions {
*/
function getPropertiesForCompletion(type: Type, checker: TypeChecker, isForAccess: boolean): Symbol[] {
if (!(type.flags & TypeFlags.Union)) {
return type.getApparentProperties();
return Debug.assertEachDefined(type.getApparentProperties(), "getApparentProperties() should all be defined");
}
const { types } = type as UnionType;
// If we're providing completions for an object literal, skip primitive, array-like, or callable types since those shouldn't be implemented by object literals.
const filteredTypes = isForAccess ? types : types.filter(memberType =>
!(memberType.flags & TypeFlags.Primitive || checker.isArrayLikeType(memberType) || typeHasCallOrConstructSignatures(memberType, checker)));
return checker.getAllPossiblePropertiesOfTypes(filteredTypes);
return Debug.assertEachDefined(checker.getAllPossiblePropertiesOfTypes(filteredTypes), "getAllPossiblePropertiesOfTypes() should all be defined");
}
}