diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index af0a83156b5..8d050687297 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2886,16 +2886,17 @@ module ts { } function getPropertiesOfType(type: Type): Symbol[] { - if (type.flags & TypeFlags.Union) { - return getPropertiesOfUnionType(type); - } - return getPropertiesOfObjectType(getApparentType(type)); + type = getApparentType(type); + return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(type) : getPropertiesOfObjectType(type); } // For a type parameter, return the base constraint of the type parameter. For the string, number, // boolean, and symbol primitive types, return the corresponding object types. Otherwise return the // type itself. Note that the apparent type of a union type is the union type itself. function getApparentType(type: Type): Type { + if (type.flags & TypeFlags.Union) { + type = getReducedTypeOfUnionType(type); + } if (type.flags & TypeFlags.TypeParameter) { do { type = getConstraintOfTypeParameter(type); @@ -2968,27 +2969,27 @@ module ts { // necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from // Object and Function as appropriate. function getPropertyOfType(type: Type, name: string): Symbol { + type = getApparentType(type); + if (type.flags & TypeFlags.ObjectType) { + let resolved = resolveObjectOrUnionTypeMembers(type); + if (hasProperty(resolved.members, name)) { + let symbol = resolved.members[name]; + if (symbolIsValue(symbol)) { + return symbol; + } + } + if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { + let symbol = getPropertyOfObjectType(globalFunctionType, name); + if (symbol) { + return symbol; + } + } + return getPropertyOfObjectType(globalObjectType, name); + } if (type.flags & TypeFlags.Union) { return getPropertyOfUnionType(type, name); } - if (!(type.flags & TypeFlags.ObjectType)) { - type = getApparentType(type); - if (!(type.flags & TypeFlags.ObjectType)) { - return undefined; - } - } - let resolved = resolveObjectOrUnionTypeMembers(type); - if (hasProperty(resolved.members, name)) { - let symbol = resolved.members[name]; - if (symbolIsValue(symbol)) { - return symbol; - } - } - if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) { - let symbol = getPropertyOfObjectType(globalFunctionType, name); - if (symbol) return symbol; - } - return getPropertyOfObjectType(globalObjectType, name); + return undefined; } function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] { @@ -3563,6 +3564,10 @@ module ts { } } + // The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag + // is true when creating a union type from a type node and when instantiating a union type. In both of those + // cases subtype reduction has to be deferred to properly support recursive union types. For example, a + // type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration. function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type { if (types.length === 0) { return emptyObjectType; @@ -3587,10 +3592,19 @@ module ts { if (!type) { type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes)); type.types = sortedTypes; + type.reducedType = noSubtypeReduction ? undefined : type; } return type; } + function getReducedTypeOfUnionType(type: UnionType): Type { + // If union type was created without subtype reduction, perform the deferred reduction now + if (!type.reducedType) { + type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false); + } + return type.reducedType; + } + function getTypeFromUnionTypeNode(node: UnionTypeNode): Type { let links = getNodeLinks(node); if (!links.resolvedType) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 43c210331a5..a8e0544f4ea 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -121,7 +121,6 @@ module ts { WhileKeyword, WithKeyword, // Strict mode reserved words - AsKeyword, ImplementsKeyword, InterfaceKeyword, LetKeyword, @@ -132,6 +131,7 @@ module ts { StaticKeyword, YieldKeyword, // Contextual keywords + AsKeyword, AnyKeyword, BooleanKeyword, ConstructorKeyword, @@ -1512,6 +1512,8 @@ module ts { export interface UnionType extends Type { types: Type[]; // Constituent types /* @internal */ + reducedType: Type; // Reduced union type (all subtypes removed) + /* @internal */ resolvedProperties: SymbolTable; // Cache of resolved properties } diff --git a/src/services/navigateTo.ts b/src/services/navigateTo.ts index 6e9c234c656..aec3bdf765f 100644 --- a/src/services/navigateTo.ts +++ b/src/services/navigateTo.ts @@ -10,11 +10,10 @@ module ts.NavigateTo { forEach(program.getSourceFiles(), sourceFile => { cancellationToken.throwIfCancellationRequested(); - let declarations = sourceFile.getNamedDeclarations(); - for (let declaration of declarations) { - var name = getDeclarationName(declaration); - if (name !== undefined) { - + let nameToDeclarations = sourceFile.getNamedDeclarations(); + for (let name in nameToDeclarations) { + let declarations = getProperty(nameToDeclarations, name); + if (declarations) { // First do a quick check to see if the name of the declaration matches the // last portion of the (possibly) dotted name they're searching for. let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name); @@ -23,24 +22,26 @@ module ts.NavigateTo { continue; } - // It was a match! If the pattern has dots in it, then also see if the - // declaration container matches as well. - if (patternMatcher.patternContainsDots) { - let containers = getContainers(declaration); - if (!containers) { - return undefined; + for (let declaration of declarations) { + // It was a match! If the pattern has dots in it, then also see if the + // declaration container matches as well. + if (patternMatcher.patternContainsDots) { + let containers = getContainers(declaration); + if (!containers) { + return undefined; + } + + matches = patternMatcher.getMatches(containers, name); + + if (!matches) { + continue; + } } - matches = patternMatcher.getMatches(containers, name); - - if (!matches) { - continue; - } + let fileName = sourceFile.fileName; + let matchKind = bestMatchKind(matches); + rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration }); } - - let fileName = sourceFile.fileName; - let matchKind = bestMatchKind(matches); - rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration }); } } }); @@ -67,30 +68,14 @@ module ts.NavigateTo { return true; } - function getDeclarationName(declaration: Declaration): string { - let result = getTextOfIdentifierOrLiteral(declaration.name); - if (result !== undefined) { - return result; - } - - if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { - let expr = (declaration.name).expression; - if (expr.kind === SyntaxKind.PropertyAccessExpression) { - return (expr).name.text; - } - - return getTextOfIdentifierOrLiteral(expr); - } - - return undefined; - } - function getTextOfIdentifierOrLiteral(node: Node) { - if (node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.StringLiteral || - node.kind === SyntaxKind.NumericLiteral) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { - return (node).text; + return (node).text; + } } return undefined; diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index 7c5ea3aa97f..d413f611209 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -1,180 +1,180 @@ -/* @internal */ -module ts { - export module OutliningElementsCollector { - export function collectElements(sourceFile: SourceFile): OutliningSpan[] { - let elements: OutliningSpan[] = []; - let collapseText = "..."; - - function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) { - if (hintSpanNode && startElement && endElement) { - let span: OutliningSpan = { - textSpan: createTextSpanFromBounds(startElement.pos, endElement.end), - hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end), - bannerText: collapseText, - autoCollapse: autoCollapse - }; - elements.push(span); - } - } - - function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) { - if (commentSpan) { - let span: OutliningSpan = { - textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), - hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), - bannerText: collapseText, - autoCollapse: autoCollapse - }; - elements.push(span); - } - } - - function addOutliningForLeadingCommentsForNode(n: Node) { - let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); - - if (comments) { - let firstSingleLineCommentStart = -1; - let lastSingleLineCommentEnd = -1; - let isFirstSingleLineComment = true; - let singleLineCommentCount = 0; - - for (let currentComment of comments) { - - // For single line comments, combine consecutive ones (2 or more) into - // a single span from the start of the first till the end of the last - if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) { - if (isFirstSingleLineComment) { - firstSingleLineCommentStart = currentComment.pos; - } - isFirstSingleLineComment = false; - lastSingleLineCommentEnd = currentComment.end; - singleLineCommentCount++; - } - else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) { - combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); - addOutliningSpanComments(currentComment, /*autoCollapse*/ false); - - singleLineCommentCount = 0; - lastSingleLineCommentEnd = -1; - isFirstSingleLineComment = true; - } - } - - combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); - } - } - - function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) { - // Only outline spans of two or more consecutive single line comments - if (count > 1) { - let multipleSingleLineComments = { - pos: start, - end: end, - kind: SyntaxKind.SingleLineCommentTrivia - } - - addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false); - } - } - - function autoCollapse(node: Node) { - return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; - } - - let depth = 0; - let maxDepth = 20; - function walk(n: Node): void { - if (depth > maxDepth) { - return; - } - - if (isDeclaration(n)) { - addOutliningForLeadingCommentsForNode(n); - } - - switch (n.kind) { - case SyntaxKind.Block: - if (!isFunctionBlock(n)) { - let parent = n.parent; - let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - - // Check if the block is standalone, or 'attached' to some parent statement. - // If the latter, we want to collaps the block, but consider its hint span - // to be the entire span of the parent. - if (parent.kind === SyntaxKind.DoStatement || - parent.kind === SyntaxKind.ForInStatement || - parent.kind === SyntaxKind.ForOfStatement || - parent.kind === SyntaxKind.ForStatement || - parent.kind === SyntaxKind.IfStatement || - parent.kind === SyntaxKind.WhileStatement || - parent.kind === SyntaxKind.WithStatement || - parent.kind === SyntaxKind.CatchClause) { - - addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); - break; - } - - if (parent.kind === SyntaxKind.TryStatement) { - // Could be the try-block, or the finally-block. - let tryStatement = parent; - if (tryStatement.tryBlock === n) { - addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); - break; - } - else if (tryStatement.finallyBlock === n) { - let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); - if (finallyKeyword) { - addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n)); - break; - } - } - - // fall through. - } - - // Block was a standalone block. In this case we want to only collapse - // the span of the block, independent of any parent span. - let span = createTextSpanFromBounds(n.getStart(), n.end); - elements.push({ - textSpan: span, - hintSpan: span, - bannerText: collapseText, - autoCollapse: autoCollapse(n) - }); - break; - } - // Fallthrough. - - case SyntaxKind.ModuleBlock: { - let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n)); - break; - } - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.ObjectLiteralExpression: - case SyntaxKind.CaseBlock: { - let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); - let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); - addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n)); - break; - } - case SyntaxKind.ArrayLiteralExpression: - let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile); - let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile); - addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n)); - break; - } - depth++; - forEachChild(n, walk); - depth--; - } - - walk(sourceFile); - return elements; - } - } +/* @internal */ +module ts { + export module OutliningElementsCollector { + export function collectElements(sourceFile: SourceFile): OutliningSpan[] { + let elements: OutliningSpan[] = []; + let collapseText = "..."; + + function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) { + if (hintSpanNode && startElement && endElement) { + let span: OutliningSpan = { + textSpan: createTextSpanFromBounds(startElement.pos, endElement.end), + hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + + function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) { + if (commentSpan) { + let span: OutliningSpan = { + textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end), + bannerText: collapseText, + autoCollapse: autoCollapse + }; + elements.push(span); + } + } + + function addOutliningForLeadingCommentsForNode(n: Node) { + let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile); + + if (comments) { + let firstSingleLineCommentStart = -1; + let lastSingleLineCommentEnd = -1; + let isFirstSingleLineComment = true; + let singleLineCommentCount = 0; + + for (let currentComment of comments) { + + // For single line comments, combine consecutive ones (2 or more) into + // a single span from the start of the first till the end of the last + if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) { + if (isFirstSingleLineComment) { + firstSingleLineCommentStart = currentComment.pos; + } + isFirstSingleLineComment = false; + lastSingleLineCommentEnd = currentComment.end; + singleLineCommentCount++; + } + else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) { + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + addOutliningSpanComments(currentComment, /*autoCollapse*/ false); + + singleLineCommentCount = 0; + lastSingleLineCommentEnd = -1; + isFirstSingleLineComment = true; + } + } + + combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd); + } + } + + function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) { + // Only outline spans of two or more consecutive single line comments + if (count > 1) { + let multipleSingleLineComments = { + pos: start, + end: end, + kind: SyntaxKind.SingleLineCommentTrivia + } + + addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false); + } + } + + function autoCollapse(node: Node) { + return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; + } + + let depth = 0; + let maxDepth = 20; + function walk(n: Node): void { + if (depth > maxDepth) { + return; + } + + if (isDeclaration(n)) { + addOutliningForLeadingCommentsForNode(n); + } + + switch (n.kind) { + case SyntaxKind.Block: + if (!isFunctionBlock(n)) { + let parent = n.parent; + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + + // Check if the block is standalone, or 'attached' to some parent statement. + // If the latter, we want to collaps the block, but consider its hint span + // to be the entire span of the parent. + if (parent.kind === SyntaxKind.DoStatement || + parent.kind === SyntaxKind.ForInStatement || + parent.kind === SyntaxKind.ForOfStatement || + parent.kind === SyntaxKind.ForStatement || + parent.kind === SyntaxKind.IfStatement || + parent.kind === SyntaxKind.WhileStatement || + parent.kind === SyntaxKind.WithStatement || + parent.kind === SyntaxKind.CatchClause) { + + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + + if (parent.kind === SyntaxKind.TryStatement) { + // Could be the try-block, or the finally-block. + let tryStatement = parent; + if (tryStatement.tryBlock === n) { + addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + else if (tryStatement.finallyBlock === n) { + let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile); + if (finallyKeyword) { + addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n)); + break; + } + } + + // fall through. + } + + // Block was a standalone block. In this case we want to only collapse + // the span of the block, independent of any parent span. + let span = createTextSpanFromBounds(n.getStart(), n.end); + elements.push({ + textSpan: span, + hintSpan: span, + bannerText: collapseText, + autoCollapse: autoCollapse(n) + }); + break; + } + // Fallthrough. + + case SyntaxKind.ModuleBlock: { + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n)); + break; + } + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.ObjectLiteralExpression: + case SyntaxKind.CaseBlock: { + let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile); + let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile); + addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n)); + break; + } + case SyntaxKind.ArrayLiteralExpression: + let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile); + let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile); + addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n)); + break; + } + depth++; + forEachChild(n, walk); + depth--; + } + + walk(sourceFile); + return elements; + } + } } \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index c57dea2e1c3..98a7fe0499f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -63,7 +63,8 @@ module ts { /* @internal */ scriptSnapshot: IScriptSnapshot; /* @internal */ nameTable: Map; - getNamedDeclarations(): Declaration[]; + /* @internal */ getNamedDeclarations(): Map; + getLineAndCharacterOfPosition(pos: number): LineAndCharacter; getLineStarts(): number[]; getPositionOfLineAndCharacter(line: number, character: number): number; @@ -749,7 +750,7 @@ module ts { public identifiers: Map; public nameTable: Map; - private namedDeclarations: Declaration[]; + private namedDeclarations: Map; public update(newText: string, textChangeRange: TextChangeRange): SourceFile { return updateSourceFile(this, newText, textChangeRange); @@ -767,7 +768,7 @@ module ts { return ts.getPositionOfLineAndCharacter(this, line, character); } - public getNamedDeclarations() { + public getNamedDeclarations(): Map { if (!this.namedDeclarations) { this.namedDeclarations = this.computeNamedDeclarations(); } @@ -775,12 +776,57 @@ module ts { return this.namedDeclarations; } - private computeNamedDeclarations() { - let namedDeclarations: Declaration[] = []; + private computeNamedDeclarations(): Map { + let result: Map = {}; forEachChild(this, visit); - return namedDeclarations; + return result; + + function addDeclaration(declaration: Declaration) { + let name = getDeclarationName(declaration); + if (name) { + let declarations = getDeclarations(name); + declarations.push(declaration); + } + } + + function getDeclarations(name: string) { + return getProperty(result, name) || (result[name] = []); + } + + function getDeclarationName(declaration: Declaration) { + if (declaration.name) { + let result = getTextOfIdentifierOrLiteral(declaration.name); + if (result !== undefined) { + return result; + } + + if (declaration.name.kind === SyntaxKind.ComputedPropertyName) { + let expr = (declaration.name).expression; + if (expr.kind === SyntaxKind.PropertyAccessExpression) { + return (expr).name.text; + } + + return getTextOfIdentifierOrLiteral(expr); + } + } + + return undefined; + } + + function getTextOfIdentifierOrLiteral(node: Node) { + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + node.kind === SyntaxKind.NumericLiteral) { + + return (node).text; + } + } + + return undefined; + } function visit(node: Node): void { switch (node.kind) { @@ -788,22 +834,22 @@ module ts { case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: let functionDeclaration = node; + let declarationName = getDeclarationName(functionDeclaration); - if (functionDeclaration.name && functionDeclaration.name.getFullWidth() > 0) { - let lastDeclaration = namedDeclarations.length > 0 ? - namedDeclarations[namedDeclarations.length - 1] : - undefined; + if (declarationName) { + let declarations = getDeclarations(declarationName); + let lastDeclaration = lastOrUndefined(declarations); // Check whether this declaration belongs to an "overload group". - if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) { + if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) { // Overwrite the last declaration if it was an overload // and this one is an implementation. if (functionDeclaration.body && !(lastDeclaration).body) { - namedDeclarations[namedDeclarations.length - 1] = functionDeclaration; + declarations[declarations.length - 1] = functionDeclaration; } } else { - namedDeclarations.push(functionDeclaration); + declarations.push(functionDeclaration); } forEachChild(node, visit); @@ -824,10 +870,8 @@ module ts { case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeLiteral: - if ((node).name) { - namedDeclarations.push(node); - } - // fall through + addDeclaration(node); + // fall through case SyntaxKind.Constructor: case SyntaxKind.VariableStatement: case SyntaxKind.VariableDeclarationList: @@ -858,7 +902,7 @@ module ts { case SyntaxKind.EnumMember: case SyntaxKind.PropertyDeclaration: case SyntaxKind.PropertySignature: - namedDeclarations.push(node); + addDeclaration(node); break; case SyntaxKind.ExportDeclaration: @@ -875,7 +919,7 @@ module ts { // Handle default import case e.g.: // import d from "mod"; if (importClause.name) { - namedDeclarations.push(importClause); + addDeclaration(importClause); } // Handle named bindings in imports e.g.: @@ -883,7 +927,7 @@ module ts { // import {a, b as B} from "mod"; if (importClause.namedBindings) { if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { - namedDeclarations.push(importClause.namedBindings); + addDeclaration(importClause.namedBindings); } else { forEach((importClause.namedBindings).elements, visit); @@ -2260,8 +2304,6 @@ module ts { let ruleProvider: formatting.RulesProvider; let program: Program; - // this checker is used to answer all LS questions except errors - let typeInfoResolver: TypeChecker; let useCaseSensitivefileNames = false; let cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken()); @@ -2343,8 +2385,10 @@ module ts { } program = newProgram; - typeInfoResolver = program.getTypeChecker(); + // Make sure all the nodes in the program are both bound, and have their parent + // pointers set property. + program.getTypeChecker(); return; function getOrCreateSourceFile(fileName: string): SourceFile { @@ -2428,15 +2472,8 @@ module ts { return program; } - /** - * Clean up any semantic caches that are not needed. - * The host can call this method if it wants to jettison unused memory. - * We will just dump the typeChecker and recreate a new one. this should have the effect of destroying all the semantic caches. - */ function cleanupSemanticCache(): void { - if (program) { - typeInfoResolver = program.getTypeChecker(); - } + // TODO: Should we jettison the program (or it's type checker) here? } function dispose(): void { @@ -2453,10 +2490,6 @@ module ts { return program.getSyntacticDiagnostics(getValidSourceFile(fileName)); } - function isJavaScript(fileName: string) { - return fileExtensionIs(fileName, ".js"); - } - /** * getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors * If '-d' enabled, report both semantic and emitter errors @@ -2704,32 +2737,8 @@ module ts { return unescapeIdentifier(displayName); } - function createCompletionEntry(symbol: Symbol, typeChecker: TypeChecker, location: Node): CompletionEntry { - // Try to get a valid display name for this symbol, if we could not find one, then ignore it. - // We would like to only show things that can be added after a dot, so for instance numeric properties can - // not be accessed with a dot (a.1 <- invalid) - let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true); - if (!displayName) { - return undefined; - } - - // TODO(drosen): Right now we just permit *all* semantic meanings when calling - // 'getSymbolKind' which is permissible given that it is backwards compatible; but - // really we should consider passing the meaning for the node so that we don't report - // that a suggestion for a value is an interface. We COULD also just do what - // 'getSymbolModifiers' does, which is to use the first declaration. - - // Use a 'sortText' of 0' so that all symbol completion entries come before any other - // entries (like JavaScript identifier entries). - return { - name: displayName, - kind: getSymbolKind(symbol, typeChecker, location), - kindModifiers: getSymbolModifiers(symbol), - sortText: "0", - }; - } - function getCompletionData(fileName: string, position: number) { + let typeChecker = program.getTypeChecker(); let syntacticStart = new Date().getTime(); let sourceFile = getValidSourceFile(fileName); @@ -2813,29 +2822,29 @@ module ts { isNewIdentifierLocation = false; if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // This is an alias, follow what it aliases if (symbol && symbol.flags & SymbolFlags.Alias) { - symbol = typeInfoResolver.getAliasedSymbol(symbol); + symbol = typeChecker.getAliasedSymbol(symbol); } if (symbol && symbol.flags & SymbolFlags.HasExports) { // Extract module or enum members - let exportedSymbols = typeInfoResolver.getExportsOfModule(symbol); + let exportedSymbols = typeChecker.getExportsOfModule(symbol); forEach(exportedSymbols, symbol => { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); } } - let type = typeInfoResolver.getTypeAtLocation(node); + let type = typeChecker.getTypeAtLocation(node); if (type) { // Filter private properties forEach(type.getApparentProperties(), symbol => { - if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { + if (typeChecker.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); @@ -2849,12 +2858,12 @@ module ts { isMemberCompletion = true; isNewIdentifierLocation = true; - let contextualType = typeInfoResolver.getContextualType(containingObjectLiteral); + let contextualType = typeChecker.getContextualType(containingObjectLiteral); if (!contextualType) { return false; } - let contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType); + let contextualTypeMembers = typeChecker.getPropertiesOfType(contextualType); if (contextualTypeMembers && contextualTypeMembers.length > 0) { // Add filtered items to the completion list symbols = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); @@ -2871,9 +2880,9 @@ module ts { let exports: Symbol[]; if (importDeclaration.moduleSpecifier) { - let moduleSpecifierSymbol = typeInfoResolver.getSymbolAtLocation(importDeclaration.moduleSpecifier); + let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier); if (moduleSpecifierSymbol) { - exports = typeInfoResolver.getExportsOfModule(moduleSpecifierSymbol); + exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol); } } @@ -2922,7 +2931,7 @@ module ts { /// TODO filter meaning based on the current context let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias; - symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings); + symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings); } return true; @@ -3285,6 +3294,31 @@ module ts { return entries; } + function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry { + // Try to get a valid display name for this symbol, if we could not find one, then ignore it. + // We would like to only show things that can be added after a dot, so for instance numeric properties can + // not be accessed with a dot (a.1 <- invalid) + let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true); + if (!displayName) { + return undefined; + } + + // TODO(drosen): Right now we just permit *all* semantic meanings when calling + // 'getSymbolKind' which is permissible given that it is backwards compatible; but + // really we should consider passing the meaning for the node so that we don't report + // that a suggestion for a value is an interface. We COULD also just do what + // 'getSymbolModifiers' does, which is to use the first declaration. + + // Use a 'sortText' of 0' so that all symbol completion entries come before any other + // entries (like JavaScript identifier entries). + return { + name: displayName, + kind: getSymbolKind(symbol, location), + kindModifiers: getSymbolModifiers(symbol), + sortText: "0", + }; + } + function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] { let start = new Date().getTime(); var entries: CompletionEntry[] = []; @@ -3292,7 +3326,7 @@ module ts { if (symbols) { var nameToSymbol: Map = {}; for (let symbol of symbols) { - let entry = createCompletionEntry(symbol, typeInfoResolver, location); + let entry = createCompletionEntry(symbol, location); if (entry) { let id = escapeIdentifier(entry.name); if (!lookUp(nameToSymbol, id)) { @@ -3324,7 +3358,7 @@ module ts { let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined); if (symbol) { - let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, typeInfoResolver, location, SemanticMeaning.All); + let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, location, SemanticMeaning.All); return { name: entryName, kind: displayPartsDocumentationsAndSymbolKind.symbolKind, @@ -3351,7 +3385,7 @@ module ts { } // TODO(drosen): use contextual SemanticMeaning. - function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location: Node): string { + function getSymbolKind(symbol: Symbol, location: Node): string { let flags = symbol.getFlags(); if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; @@ -3360,7 +3394,7 @@ module ts { if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver, location); + let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location); if (result === ScriptElementKind.unknown) { if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement; @@ -3371,11 +3405,13 @@ module ts { return result; } - function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, typeResolver: TypeChecker, location: Node) { - if (typeResolver.isUndefinedSymbol(symbol)) { + function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) { + let typeChecker = program.getTypeChecker(); + + if (typeChecker.isUndefinedSymbol(symbol)) { return ScriptElementKind.variableElement; } - if (typeResolver.isArgumentsSymbol(symbol)) { + if (typeChecker.isArgumentsSymbol(symbol)) { return ScriptElementKind.localVariableElement; } if (flags & SymbolFlags.Variable) { @@ -3399,7 +3435,7 @@ module ts { if (flags & SymbolFlags.Property) { if (flags & SymbolFlags.UnionProperty) { // If union property is result of union of non method (property/accessors/variables), it is labeled as property - let unionPropertyKind = forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => { + let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { let rootSymbolFlags = rootSymbol.getFlags(); if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) { return ScriptElementKind.memberVariableElement; @@ -3409,7 +3445,7 @@ module ts { if (!unionPropertyKind) { // If this was union of all methods, //make sure it has call signatures before we can label it as method - let typeOfUnionProperty = typeInfoResolver.getTypeOfSymbolAtLocation(symbol, location); + let typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (typeOfUnionProperty.getCallSignatures().length) { return ScriptElementKind.memberFunctionElement; } @@ -3442,15 +3478,16 @@ module ts { : ScriptElementKindModifier.none; } + // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, - typeResolver: TypeChecker, location: Node, - // TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location - semanticMeaning = getMeaningFromLocation(location)) { + location: Node, semanticMeaning = getMeaningFromLocation(location)) { + + let typeChecker = program.getTypeChecker(); let displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[]; let symbolFlags = symbol.flags; - let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, typeResolver, location); + let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location); let hasAddedSymbolInfo: boolean; let type: Type; @@ -3462,7 +3499,7 @@ module ts { } let signature: Signature; - type = typeResolver.getTypeOfSymbolAtLocation(symbol, location); + type = typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (type) { if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { let right = (location.parent).name; @@ -3483,7 +3520,7 @@ module ts { if (callExpression) { let candidateSignatures: Signature[] = []; - signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures); + signature = typeChecker.getResolvedSignature(callExpression, candidateSignatures); if (!signature && candidateSignatures.length) { // Use the first candidate: signature = candidateSignatures[0]; @@ -3532,7 +3569,7 @@ module ts { displayParts.push(spacePart()); } if (!(type.flags & TypeFlags.Anonymous)) { - displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); + displayParts.push.apply(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments)); } addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature); break; @@ -3549,8 +3586,8 @@ module ts { // get the signature from the declaration and write it let functionDeclaration = location.parent; let allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures(); - if (!typeResolver.isImplementationOfOverload(functionDeclaration)) { - signature = typeResolver.getSignatureFromDeclaration(functionDeclaration); + if (!typeChecker.isImplementationOfOverload(functionDeclaration)) { + signature = typeChecker.getSignatureFromDeclaration(functionDeclaration); } else { signature = allSignatures[0]; @@ -3593,7 +3630,7 @@ module ts { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); displayParts.push(spacePart()); - displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, typeResolver.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); @@ -3629,7 +3666,7 @@ module ts { else { // Method/function type parameter let signatureDeclaration = getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent; - let signature = typeResolver.getSignatureFromDeclaration(signatureDeclaration); + let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration); if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) { displayParts.push(keywordPart(SyntaxKind.NewKeyword)); displayParts.push(spacePart()); @@ -3637,14 +3674,14 @@ module ts { else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) { addFullSymbolName(signatureDeclaration.symbol); } - displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature)); } } if (symbolFlags & SymbolFlags.EnumMember) { addPrefixForAnyFunctionOrVar(symbol, "enum member"); let declaration = symbol.declarations[0]; if (declaration.kind === SyntaxKind.EnumMember) { - let constantValue = typeResolver.getConstantValue(declaration); + let constantValue = typeChecker.getConstantValue(declaration); if (constantValue !== undefined) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -3671,7 +3708,7 @@ module ts { displayParts.push(punctuationPart(SyntaxKind.CloseParenToken)); } else { - let internalAliasSymbol = typeResolver.getSymbolAtLocation(importEqualsDeclaration.moduleReference); + let internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference); if (internalAliasSymbol) { displayParts.push(spacePart()); displayParts.push(operatorPart(SyntaxKind.EqualsToken)); @@ -3696,12 +3733,12 @@ module ts { // If the type is type parameter, format it specially if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) { let typeParameterParts = mapToDisplayParts(writer => { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(type, writer, enclosingDeclaration); }); displayParts.push.apply(displayParts, typeParameterParts); } else { - displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, type, enclosingDeclaration)); + displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration)); } } else if (symbolFlags & SymbolFlags.Function || @@ -3716,7 +3753,7 @@ module ts { } } else { - symbolKind = getSymbolKind(symbol, typeResolver, location); + symbolKind = getSymbolKind(symbol, location); } } @@ -3733,7 +3770,7 @@ module ts { } function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) { - let fullSymbolDisplayParts = symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, + let fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing); displayParts.push.apply(displayParts, fullSymbolDisplayParts); } @@ -3765,7 +3802,7 @@ module ts { } function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags?: TypeFormatFlags) { - displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); + displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature)); if (allSignatures.length > 1) { displayParts.push(spacePart()); displayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -3780,7 +3817,7 @@ module ts { function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) { let typeParameterParts = mapToDisplayParts(writer => { - typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration); }); displayParts.push.apply(displayParts, typeParameterParts); } @@ -3799,7 +3836,9 @@ module ts { return undefined; } - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); + if (!symbol) { // Try getting just type at this position and show switch (node.kind) { @@ -3809,13 +3848,13 @@ module ts { case SyntaxKind.ThisKeyword: case SyntaxKind.SuperKeyword: // For the identifiers/this/super etc get the type at position - let type = typeInfoResolver.getTypeAtLocation(node); + let type = typeChecker.getTypeAtLocation(node); if (type) { return { kind: ScriptElementKind.unknown, kindModifiers: ScriptElementKindModifier.none, textSpan: createTextSpan(node.getStart(), node.getWidth()), - displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)), + displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)), documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined }; } @@ -3824,7 +3863,7 @@ module ts { return undefined; } - let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node); + let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), node); return { kind: displayPartsDocumentationsAndKind.symbolKind, kindModifiers: getSymbolModifiers(symbol), @@ -3880,7 +3919,8 @@ module ts { return undefined; } - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let typeChecker = program.getTypeChecker(); + let symbol = typeChecker.getSymbolAtLocation(node); // Could not find a symbol e.g. node is string or number keyword, // or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol @@ -3895,7 +3935,7 @@ module ts { if (symbol.flags & SymbolFlags.Alias) { let declaration = symbol.declarations[0]; if (node.kind === SyntaxKind.Identifier && node.parent === declaration) { - symbol = typeInfoResolver.getAliasedSymbol(symbol); + symbol = typeChecker.getAliasedSymbol(symbol); } } @@ -3905,25 +3945,25 @@ module ts { // is performed at the location of property access, we would like to go to definition of the property in the short-hand // assignment. This case and others are handled by the following code. if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) { - let shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); + let shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration); if (!shorthandSymbol) { return []; } let shorthandDeclarations = shorthandSymbol.getDeclarations(); - let shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node); - let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol); - let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node); + let shorthandSymbolKind = getSymbolKind(shorthandSymbol, node); + let shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol); + let shorthandContainerName = typeChecker.symbolToString(symbol.parent, node); return map(shorthandDeclarations, declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); } let result: DefinitionInfo[] = []; let declarations = symbol.getDeclarations(); - let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - let symbolKind = getSymbolKind(symbol, typeInfoResolver, node); + let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol + let symbolKind = getSymbolKind(symbol, node); let containerSymbol = symbol.parent; - let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : ""; + let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { @@ -4682,7 +4722,9 @@ module ts { return getReferencedSymbolsForNodes(node, program.getSourceFiles(), findInStrings, findInComments); } - function getReferencedSymbolsForNodes(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[]{ + function getReferencedSymbolsForNodes(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] { + let typeChecker = program.getTypeChecker(); + // Labels if (isLabelName(node)) { if (isJumpStatementTarget(node)) { @@ -4705,7 +4747,7 @@ module ts { return getReferencesForSuperKeyword(node); } - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { @@ -4756,7 +4798,7 @@ module ts { return result; function getDefinition(symbol: Symbol): DefinitionInfo { - let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), typeInfoResolver, node); + let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node); let name = map(info.displayParts, p => p.text).join(""); let declarations = symbol.declarations; if (!declarations || declarations.length === 0) { @@ -4806,7 +4848,7 @@ module ts { return location.getText(); } - name = typeInfoResolver.symbolToString(symbol); + name = typeChecker.symbolToString(symbol); return stripQuotes(name); } @@ -5042,10 +5084,10 @@ module ts { return; } - let referenceSymbol = typeInfoResolver.getSymbolAtLocation(referenceLocation); + let referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation); if (referenceSymbol) { let referenceSymbolDeclaration = referenceSymbol.valueDeclaration; - let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration); var relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation); if (relatedSymbol) { @@ -5270,7 +5312,7 @@ module ts { // If the symbol is an alias, add what it alaises to the list if (isImportOrExportSpecifierImportSymbol(symbol)) { - result.push(typeInfoResolver.getAliasedSymbol(symbol)); + result.push(typeChecker.getAliasedSymbol(symbol)); } // If the location is in a context sensitive location (i.e. in an object literal) try @@ -5278,7 +5320,7 @@ module ts { // type to the search set if (isNameOfPropertyAssignment(location)) { forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => { - result.push.apply(result, typeInfoResolver.getRootSymbols(contextualSymbol)); + result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol)); }); /* Because in short-hand property assignment, location has two meaning : property name and as value of the property @@ -5292,7 +5334,7 @@ module ts { * so that when matching with potential reference symbol, both symbols from property declaration and variable declaration * will be included correctly. */ - let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(location.parent); + let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(location.parent); if (shorthandValueSymbol) { result.push(shorthandValueSymbol); } @@ -5300,7 +5342,7 @@ module ts { // If this is a union property, add all the symbols from all its source symbols in all unioned types. // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list - forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => { + forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { if (rootSymbol !== symbol) { result.push(rootSymbol); } @@ -5330,9 +5372,9 @@ module ts { function getPropertySymbolFromTypeReference(typeReference: HeritageClauseElement) { if (typeReference) { - let type = typeInfoResolver.getTypeAtLocation(typeReference); + let type = typeChecker.getTypeAtLocation(typeReference); if (type) { - let propertySymbol = typeInfoResolver.getPropertyOfType(type, propertyName); + let propertySymbol = typeChecker.getPropertyOfType(type, propertyName); if (propertySymbol) { result.push(propertySymbol); } @@ -5352,7 +5394,7 @@ module ts { // If the reference symbol is an alias, check if what it is aliasing is one of the search // symbols. if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) { - var aliasedSymbol = typeInfoResolver.getAliasedSymbol(referenceSymbol); + var aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol); if (searchSymbols.indexOf(aliasedSymbol) >= 0) { return aliasedSymbol; } @@ -5363,13 +5405,13 @@ module ts { // compare to our searchSymbol if (isNameOfPropertyAssignment(referenceLocation)) { return forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => { - return forEach(typeInfoResolver.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); + return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined); }); } // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) // Or a union property, use its underlying unioned symbols - return forEach(typeInfoResolver.getRootSymbols(referenceSymbol), rootSymbol => { + return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => { // if it is in the list, then we are done if (searchSymbols.indexOf(rootSymbol) >= 0) { return rootSymbol; @@ -5390,7 +5432,7 @@ module ts { function getPropertySymbolsFromContextualType(node: Node): Symbol[] { if (isNameOfPropertyAssignment(node)) { let objectLiteral = node.parent.parent; - let contextualType = typeInfoResolver.getContextualType(objectLiteral); + let contextualType = typeChecker.getContextualType(objectLiteral); let name = (node).text; if (contextualType) { if (contextualType.flags & TypeFlags.Union) { @@ -5682,7 +5724,7 @@ module ts { let sourceFile = getValidSourceFile(fileName); - return SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken); + return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken); } /// Syntactic features @@ -5763,6 +5805,7 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); + let typeChecker = program.getTypeChecker(); let result: ClassifiedSpan[] = []; processNode(sourceFile); @@ -5815,7 +5858,7 @@ module ts { // Only walk into nodes that intersect the requested span. if (node && textSpanIntersectsWith(span, node.getStart(), node.getWidth())) { if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); if (symbol) { let type = classifySymbol(symbol, getMeaningFromLocation(node)); if (type) { @@ -6297,12 +6340,13 @@ module ts { synchronizeHostData(); let sourceFile = getValidSourceFile(fileName); + let typeChecker = program.getTypeChecker(); let node = getTouchingWord(sourceFile, position); // Can only rename an identifier. if (node && node.kind === SyntaxKind.Identifier) { - let symbol = typeInfoResolver.getSymbolAtLocation(node); + let symbol = typeChecker.getSymbolAtLocation(node); // Only allow a symbol to be renamed if it actually has at least one declaration. if (symbol) { @@ -6319,13 +6363,13 @@ module ts { } } - let kind = getSymbolKind(symbol, typeInfoResolver, node); + let kind = getSymbolKind(symbol, node); if (kind) { return { canRename: true, localizedErrorMessage: undefined, displayName: symbol.name, - fullDisplayName: typeInfoResolver.getFullyQualifiedName(symbol), + fullDisplayName: typeChecker.getFullyQualifiedName(symbol), kind: kind, kindModifiers: getSymbolModifiers(symbol), triggerSpan: createTextSpan(node.getStart(), node.getWidth()) diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts index e311048191f..77aba4c85c1 100644 --- a/src/services/signatureHelp.ts +++ b/src/services/signatureHelp.ts @@ -178,7 +178,9 @@ module ts.SignatureHelp { argumentCount: number; } - export function getSignatureHelpItems(sourceFile: SourceFile, position: number, typeInfoResolver: TypeChecker, cancellationToken: CancellationTokenObject): SignatureHelpItems { + export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems { + let typeChecker = program.getTypeChecker(); + // Decide whether to show signature help let startingToken = findTokenOnLeftOfPosition(sourceFile, position); if (!startingToken) { @@ -196,15 +198,61 @@ module ts.SignatureHelp { let call = argumentInfo.invocation; let candidates = []; - let resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates); + let resolvedSignature = typeChecker.getResolvedSignature(call, candidates); cancellationToken.throwIfCancellationRequested(); if (!candidates.length) { + // We didn't have any sig help items produced by the TS compiler. If this is a JS + // file, then see if we can figure out anything better. + if (isJavaScript(sourceFile.fileName)) { + return createJavaScriptSignatureHelpItems(argumentInfo); + } + return undefined; } return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo); + function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo): SignatureHelpItems { + if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) { + return undefined; + } + + // See if we can find some symbol with the call expression name that has call signatures. + let callExpression = argumentInfo.invocation; + let expression = callExpression.expression; + let name = expression.kind === SyntaxKind.Identifier + ? expression + : expression.kind === SyntaxKind.PropertyAccessExpression + ? (expression).name + : undefined; + + if (!name || !name.text) { + return undefined; + } + + let typeChecker = program.getTypeChecker(); + for (let sourceFile of program.getSourceFiles()) { + let nameToDeclarations = sourceFile.getNamedDeclarations(); + let declarations = getProperty(nameToDeclarations, name.text); + + if (declarations) { + for (let declaration of declarations) { + let symbol = declaration.symbol; + if (symbol) { + let type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration); + if (type) { + let callSignatures = type.getCallSignatures(); + if (callSignatures && callSignatures.length) { + return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo); + } + } + } + } + } + } + } + /** * Returns relevant information for the argument list and the current argument if we are * in the argument of an invocation; returns undefined otherwise. @@ -494,8 +542,8 @@ module ts.SignatureHelp { let invocation = argumentListInfo.invocation; let callTarget = getInvokedExpression(invocation) - let callTargetSymbol = typeInfoResolver.getSymbolAtLocation(callTarget); - let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); + let callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget); + let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined); let items: SignatureHelpItem[] = map(candidates, candidateSignature => { let signatureHelpParameters: SignatureHelpParameter[]; let prefixDisplayParts: SymbolDisplayPart[] = []; @@ -511,12 +559,12 @@ module ts.SignatureHelp { signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray; suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken)); let parameterParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation)); suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts); } else { let typeParameterParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation)); prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts); prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken)); @@ -526,7 +574,7 @@ module ts.SignatureHelp { } let returnTypeParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation)); suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts); return { @@ -561,7 +609,7 @@ module ts.SignatureHelp { function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter { let displayParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation)); let isOptional = hasQuestionToken(parameter.valueDeclaration); @@ -575,7 +623,7 @@ module ts.SignatureHelp { function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter { let displayParts = mapToDisplayParts(writer => - typeInfoResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation)); + typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation)); return { name: typeParameter.symbol.name, diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 26b581e27b6..5e1460bbdcd 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -652,4 +652,8 @@ module ts { typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags); }); } + + export function isJavaScript(fileName: string) { + return fileExtensionIs(fileName, ".js"); + } } \ No newline at end of file diff --git a/tests/baselines/reference/APISample_compile.types b/tests/baselines/reference/APISample_compile.types index d147ded3f0e..dba54c8e1e5 100644 --- a/tests/baselines/reference/APISample_compile.types +++ b/tests/baselines/reference/APISample_compile.types @@ -67,11 +67,11 @@ export function compile(fileNames: string[], options: ts.CompilerOptions): void >line : number, Symbol(line, Decl(APISample_compile.ts, 20, 13)) >character : number, Symbol(character, Decl(APISample_compile.ts, 20, 19)) >diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start) : ts.LineAndCharacter ->diagnostic.file.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>diagnostic.file.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >diagnostic.file : ts.SourceFile, Symbol(ts.Diagnostic.file, Decl(typescript.d.ts, 1062, 26)) >diagnostic : ts.Diagnostic, Symbol(diagnostic, Decl(APISample_compile.ts, 19, 27)) >file : ts.SourceFile, Symbol(ts.Diagnostic.file, Decl(typescript.d.ts, 1062, 26)) ->getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >diagnostic.start : number, Symbol(ts.Diagnostic.start, Decl(typescript.d.ts, 1063, 25)) >diagnostic : ts.Diagnostic, Symbol(diagnostic, Decl(APISample_compile.ts, 19, 27)) >start : number, Symbol(ts.Diagnostic.start, Decl(typescript.d.ts, 1063, 25)) diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index c285bc15390..220b5c1c6fa 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -237,9 +237,9 @@ export function delint(sourceFile: ts.SourceFile) { >line : number, Symbol(line, Decl(APISample_linter.ts, 51, 13)) >character : number, Symbol(character, Decl(APISample_linter.ts, 51, 19)) >sourceFile.getLineAndCharacterOfPosition(node.getStart()) : ts.LineAndCharacter ->sourceFile.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>sourceFile.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >sourceFile : ts.SourceFile, Symbol(sourceFile, Decl(APISample_linter.ts, 13, 23)) ->getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >node.getStart() : number >node.getStart : (sourceFile?: ts.SourceFile) => number, Symbol(ts.Node.getStart, Decl(typescript.d.ts, 1226, 53)) >node : ts.Node, Symbol(node, Decl(APISample_linter.ts, 50, 20)) diff --git a/tests/baselines/reference/APISample_transform.types b/tests/baselines/reference/APISample_transform.types index 6e27f70d877..594b1b5f7f4 100644 --- a/tests/baselines/reference/APISample_transform.types +++ b/tests/baselines/reference/APISample_transform.types @@ -19,9 +19,9 @@ const source = "let x: string = 'string'"; let result = ts.transpile(source, { module: ts.ModuleKind.CommonJS }); >result : string, Symbol(result, Decl(APISample_transform.ts, 13, 3)) >ts.transpile(source, { module: ts.ModuleKind.CommonJS }) : string ->ts.transpile : (input: string, compilerOptions?: ts.CompilerOptions, fileName?: string, diagnostics?: ts.Diagnostic[]) => string, Symbol(ts.transpile, Decl(typescript.d.ts, 1729, 5)) +>ts.transpile : (input: string, compilerOptions?: ts.CompilerOptions, fileName?: string, diagnostics?: ts.Diagnostic[]) => string, Symbol(ts.transpile, Decl(typescript.d.ts, 1728, 5)) >ts : typeof ts, Symbol(ts, Decl(APISample_transform.ts, 9, 6)) ->transpile : (input: string, compilerOptions?: ts.CompilerOptions, fileName?: string, diagnostics?: ts.Diagnostic[]) => string, Symbol(ts.transpile, Decl(typescript.d.ts, 1729, 5)) +>transpile : (input: string, compilerOptions?: ts.CompilerOptions, fileName?: string, diagnostics?: ts.Diagnostic[]) => string, Symbol(ts.transpile, Decl(typescript.d.ts, 1728, 5)) >source : string, Symbol(source, Decl(APISample_transform.ts, 11, 5)) >{ module: ts.ModuleKind.CommonJS } : { [x: string]: ts.ModuleKind; module: ts.ModuleKind; } >module : ts.ModuleKind, Symbol(module, Decl(APISample_transform.ts, 13, 35)) diff --git a/tests/baselines/reference/APISample_watcher.types b/tests/baselines/reference/APISample_watcher.types index abc915e3776..a8683302d9a 100644 --- a/tests/baselines/reference/APISample_watcher.types +++ b/tests/baselines/reference/APISample_watcher.types @@ -59,7 +59,7 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { const servicesHost: ts.LanguageServiceHost = { >servicesHost : ts.LanguageServiceHost, Symbol(servicesHost, Decl(APISample_watcher.ts, 23, 9)) >ts : any, Symbol(ts, Decl(APISample_watcher.ts, 12, 6)) ->LanguageServiceHost : ts.LanguageServiceHost, Symbol(ts.LanguageServiceHost, Decl(typescript.d.ts, 1295, 5)) +>LanguageServiceHost : ts.LanguageServiceHost, Symbol(ts.LanguageServiceHost, Decl(typescript.d.ts, 1294, 5)) >{ getScriptFileNames: () => rootFileNames, getScriptVersion: (fileName) => files[fileName] && files[fileName].version.toString(), getScriptSnapshot: (fileName) => { if (!fs.existsSync(fileName)) { return undefined; } return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString()); }, getCurrentDirectory: () => process.cwd(), getCompilationSettings: () => options, getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options), } : { getScriptFileNames: () => string[]; getScriptVersion: (fileName: string) => string; getScriptSnapshot: (fileName: string) => ts.IScriptSnapshot; getCurrentDirectory: () => any; getCompilationSettings: () => ts.CompilerOptions; getDefaultLibFileName: (options: ts.CompilerOptions) => string; } getScriptFileNames: () => rootFileNames, @@ -103,11 +103,11 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { return ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString()); >ts.ScriptSnapshot.fromString(fs.readFileSync(fileName).toString()) : ts.IScriptSnapshot ->ts.ScriptSnapshot.fromString : (text: string) => ts.IScriptSnapshot, Symbol(ts.ScriptSnapshot.fromString, Decl(typescript.d.ts, 1288, 27)) ->ts.ScriptSnapshot : typeof ts.ScriptSnapshot, Symbol(ts.ScriptSnapshot, Decl(typescript.d.ts, 1287, 5)) +>ts.ScriptSnapshot.fromString : (text: string) => ts.IScriptSnapshot, Symbol(ts.ScriptSnapshot.fromString, Decl(typescript.d.ts, 1287, 27)) +>ts.ScriptSnapshot : typeof ts.ScriptSnapshot, Symbol(ts.ScriptSnapshot, Decl(typescript.d.ts, 1286, 5)) >ts : typeof ts, Symbol(ts, Decl(APISample_watcher.ts, 12, 6)) ->ScriptSnapshot : typeof ts.ScriptSnapshot, Symbol(ts.ScriptSnapshot, Decl(typescript.d.ts, 1287, 5)) ->fromString : (text: string) => ts.IScriptSnapshot, Symbol(ts.ScriptSnapshot.fromString, Decl(typescript.d.ts, 1288, 27)) +>ScriptSnapshot : typeof ts.ScriptSnapshot, Symbol(ts.ScriptSnapshot, Decl(typescript.d.ts, 1286, 5)) +>fromString : (text: string) => ts.IScriptSnapshot, Symbol(ts.ScriptSnapshot.fromString, Decl(typescript.d.ts, 1287, 27)) >fs.readFileSync(fileName).toString() : any >fs.readFileSync(fileName).toString : any >fs.readFileSync(fileName) : any @@ -136,9 +136,9 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { >(options) => ts.getDefaultLibFilePath(options) : (options: ts.CompilerOptions) => string >options : ts.CompilerOptions, Symbol(options, Decl(APISample_watcher.ts, 35, 32)) >ts.getDefaultLibFilePath(options) : string ->ts.getDefaultLibFilePath : (options: ts.CompilerOptions) => string, Symbol(ts.getDefaultLibFilePath, Decl(typescript.d.ts, 1737, 44)) +>ts.getDefaultLibFilePath : (options: ts.CompilerOptions) => string, Symbol(ts.getDefaultLibFilePath, Decl(typescript.d.ts, 1736, 44)) >ts : typeof ts, Symbol(ts, Decl(APISample_watcher.ts, 12, 6)) ->getDefaultLibFilePath : (options: ts.CompilerOptions) => string, Symbol(ts.getDefaultLibFilePath, Decl(typescript.d.ts, 1737, 44)) +>getDefaultLibFilePath : (options: ts.CompilerOptions) => string, Symbol(ts.getDefaultLibFilePath, Decl(typescript.d.ts, 1736, 44)) >options : ts.CompilerOptions, Symbol(options, Decl(APISample_watcher.ts, 35, 32)) }; @@ -147,14 +147,14 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { const services = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()) >services : ts.LanguageService, Symbol(services, Decl(APISample_watcher.ts, 39, 9)) >ts.createLanguageService(servicesHost, ts.createDocumentRegistry()) : ts.LanguageService ->ts.createLanguageService : (host: ts.LanguageServiceHost, documentRegistry?: ts.DocumentRegistry) => ts.LanguageService, Symbol(ts.createLanguageService, Decl(typescript.d.ts, 1735, 97)) +>ts.createLanguageService : (host: ts.LanguageServiceHost, documentRegistry?: ts.DocumentRegistry) => ts.LanguageService, Symbol(ts.createLanguageService, Decl(typescript.d.ts, 1734, 97)) >ts : typeof ts, Symbol(ts, Decl(APISample_watcher.ts, 12, 6)) ->createLanguageService : (host: ts.LanguageServiceHost, documentRegistry?: ts.DocumentRegistry) => ts.LanguageService, Symbol(ts.createLanguageService, Decl(typescript.d.ts, 1735, 97)) +>createLanguageService : (host: ts.LanguageServiceHost, documentRegistry?: ts.DocumentRegistry) => ts.LanguageService, Symbol(ts.createLanguageService, Decl(typescript.d.ts, 1734, 97)) >servicesHost : ts.LanguageServiceHost, Symbol(servicesHost, Decl(APISample_watcher.ts, 23, 9)) >ts.createDocumentRegistry() : ts.DocumentRegistry ->ts.createDocumentRegistry : () => ts.DocumentRegistry, Symbol(ts.createDocumentRegistry, Decl(typescript.d.ts, 1733, 193)) +>ts.createDocumentRegistry : () => ts.DocumentRegistry, Symbol(ts.createDocumentRegistry, Decl(typescript.d.ts, 1732, 193)) >ts : typeof ts, Symbol(ts, Decl(APISample_watcher.ts, 12, 6)) ->createDocumentRegistry : () => ts.DocumentRegistry, Symbol(ts.createDocumentRegistry, Decl(typescript.d.ts, 1733, 193)) +>createDocumentRegistry : () => ts.DocumentRegistry, Symbol(ts.createDocumentRegistry, Decl(typescript.d.ts, 1732, 193)) // Now let's watch the files rootFileNames.forEach(fileName => { @@ -231,16 +231,16 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { let output = services.getEmitOutput(fileName); >output : ts.EmitOutput, Symbol(output, Decl(APISample_watcher.ts, 64, 11)) >services.getEmitOutput(fileName) : ts.EmitOutput ->services.getEmitOutput : (fileName: string) => ts.EmitOutput, Symbol(ts.LanguageService.getEmitOutput, Decl(typescript.d.ts, 1339, 132)) +>services.getEmitOutput : (fileName: string) => ts.EmitOutput, Symbol(ts.LanguageService.getEmitOutput, Decl(typescript.d.ts, 1338, 132)) >services : ts.LanguageService, Symbol(services, Decl(APISample_watcher.ts, 39, 9)) ->getEmitOutput : (fileName: string) => ts.EmitOutput, Symbol(ts.LanguageService.getEmitOutput, Decl(typescript.d.ts, 1339, 132)) +>getEmitOutput : (fileName: string) => ts.EmitOutput, Symbol(ts.LanguageService.getEmitOutput, Decl(typescript.d.ts, 1338, 132)) >fileName : string, Symbol(fileName, Decl(APISample_watcher.ts, 63, 22)) if (!output.emitSkipped) { >!output.emitSkipped : boolean ->output.emitSkipped : boolean, Symbol(ts.EmitOutput.emitSkipped, Decl(typescript.d.ts, 1542, 34)) +>output.emitSkipped : boolean, Symbol(ts.EmitOutput.emitSkipped, Decl(typescript.d.ts, 1541, 34)) >output : ts.EmitOutput, Symbol(output, Decl(APISample_watcher.ts, 64, 11)) ->emitSkipped : boolean, Symbol(ts.EmitOutput.emitSkipped, Decl(typescript.d.ts, 1542, 34)) +>emitSkipped : boolean, Symbol(ts.EmitOutput.emitSkipped, Decl(typescript.d.ts, 1541, 34)) console.log(`Emitting ${fileName}`); >console.log(`Emitting ${fileName}`) : any @@ -268,9 +268,9 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { output.outputFiles.forEach(o => { >output.outputFiles.forEach(o => { fs.writeFileSync(o.name, o.text, "utf8"); }) : void >output.outputFiles.forEach : (callbackfn: (value: ts.OutputFile, index: number, array: ts.OutputFile[]) => void, thisArg?: any) => void, Symbol(Array.forEach, Decl(lib.d.ts, 1108, 95)) ->output.outputFiles : ts.OutputFile[], Symbol(ts.EmitOutput.outputFiles, Decl(typescript.d.ts, 1541, 26)) +>output.outputFiles : ts.OutputFile[], Symbol(ts.EmitOutput.outputFiles, Decl(typescript.d.ts, 1540, 26)) >output : ts.EmitOutput, Symbol(output, Decl(APISample_watcher.ts, 64, 11)) ->outputFiles : ts.OutputFile[], Symbol(ts.EmitOutput.outputFiles, Decl(typescript.d.ts, 1541, 26)) +>outputFiles : ts.OutputFile[], Symbol(ts.EmitOutput.outputFiles, Decl(typescript.d.ts, 1540, 26)) >forEach : (callbackfn: (value: ts.OutputFile, index: number, array: ts.OutputFile[]) => void, thisArg?: any) => void, Symbol(Array.forEach, Decl(lib.d.ts, 1108, 95)) >o => { fs.writeFileSync(o.name, o.text, "utf8"); } : (o: ts.OutputFile) => void >o : ts.OutputFile, Symbol(o, Decl(APISample_watcher.ts, 74, 35)) @@ -280,12 +280,12 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { >fs.writeFileSync : any >fs : any, Symbol(fs, Decl(APISample_watcher.ts, 9, 11)) >writeFileSync : any ->o.name : string, Symbol(ts.OutputFile.name, Decl(typescript.d.ts, 1550, 26)) +>o.name : string, Symbol(ts.OutputFile.name, Decl(typescript.d.ts, 1549, 26)) >o : ts.OutputFile, Symbol(o, Decl(APISample_watcher.ts, 74, 35)) ->name : string, Symbol(ts.OutputFile.name, Decl(typescript.d.ts, 1550, 26)) ->o.text : string, Symbol(ts.OutputFile.text, Decl(typescript.d.ts, 1552, 36)) +>name : string, Symbol(ts.OutputFile.name, Decl(typescript.d.ts, 1549, 26)) +>o.text : string, Symbol(ts.OutputFile.text, Decl(typescript.d.ts, 1551, 36)) >o : ts.OutputFile, Symbol(o, Decl(APISample_watcher.ts, 74, 35)) ->text : string, Symbol(ts.OutputFile.text, Decl(typescript.d.ts, 1552, 36)) +>text : string, Symbol(ts.OutputFile.text, Decl(typescript.d.ts, 1551, 36)) >"utf8" : string }); @@ -302,24 +302,24 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { >services.getCompilerOptionsDiagnostics() .concat(services.getSyntacticDiagnostics(fileName)) : ts.Diagnostic[] >services.getCompilerOptionsDiagnostics() .concat : { (...items: U[]): ts.Diagnostic[]; (...items: ts.Diagnostic[]): ts.Diagnostic[]; }, Symbol(Array.concat, Decl(lib.d.ts, 1025, 13), Decl(lib.d.ts, 1030, 46)) >services.getCompilerOptionsDiagnostics() : ts.Diagnostic[] ->services.getCompilerOptionsDiagnostics : () => ts.Diagnostic[], Symbol(ts.LanguageService.getCompilerOptionsDiagnostics, Decl(typescript.d.ts, 1313, 63)) +>services.getCompilerOptionsDiagnostics : () => ts.Diagnostic[], Symbol(ts.LanguageService.getCompilerOptionsDiagnostics, Decl(typescript.d.ts, 1312, 63)) >services : ts.LanguageService, Symbol(services, Decl(APISample_watcher.ts, 39, 9)) ->getCompilerOptionsDiagnostics : () => ts.Diagnostic[], Symbol(ts.LanguageService.getCompilerOptionsDiagnostics, Decl(typescript.d.ts, 1313, 63)) +>getCompilerOptionsDiagnostics : () => ts.Diagnostic[], Symbol(ts.LanguageService.getCompilerOptionsDiagnostics, Decl(typescript.d.ts, 1312, 63)) .concat(services.getSyntacticDiagnostics(fileName)) >concat : { (...items: U[]): ts.Diagnostic[]; (...items: ts.Diagnostic[]): ts.Diagnostic[]; }, Symbol(Array.concat, Decl(lib.d.ts, 1025, 13), Decl(lib.d.ts, 1030, 46)) >services.getSyntacticDiagnostics(fileName) : ts.Diagnostic[] ->services.getSyntacticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSyntacticDiagnostics, Decl(typescript.d.ts, 1311, 37)) +>services.getSyntacticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSyntacticDiagnostics, Decl(typescript.d.ts, 1310, 37)) >services : ts.LanguageService, Symbol(services, Decl(APISample_watcher.ts, 39, 9)) ->getSyntacticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSyntacticDiagnostics, Decl(typescript.d.ts, 1311, 37)) +>getSyntacticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSyntacticDiagnostics, Decl(typescript.d.ts, 1310, 37)) >fileName : string, Symbol(fileName, Decl(APISample_watcher.ts, 79, 23)) .concat(services.getSemanticDiagnostics(fileName)); >concat : { (...items: U[]): ts.Diagnostic[]; (...items: ts.Diagnostic[]): ts.Diagnostic[]; }, Symbol(Array.concat, Decl(lib.d.ts, 1025, 13), Decl(lib.d.ts, 1030, 46)) >services.getSemanticDiagnostics(fileName) : ts.Diagnostic[] ->services.getSemanticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSemanticDiagnostics, Decl(typescript.d.ts, 1312, 64)) +>services.getSemanticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSemanticDiagnostics, Decl(typescript.d.ts, 1311, 64)) >services : ts.LanguageService, Symbol(services, Decl(APISample_watcher.ts, 39, 9)) ->getSemanticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSemanticDiagnostics, Decl(typescript.d.ts, 1312, 64)) +>getSemanticDiagnostics : (fileName: string) => ts.Diagnostic[], Symbol(ts.LanguageService.getSemanticDiagnostics, Decl(typescript.d.ts, 1311, 64)) >fileName : string, Symbol(fileName, Decl(APISample_watcher.ts, 79, 23)) allDiagnostics.forEach(diagnostic => { @@ -350,11 +350,11 @@ function watch(rootFileNames: string[], options: ts.CompilerOptions) { >line : number, Symbol(line, Decl(APISample_watcher.ts, 87, 21)) >character : number, Symbol(character, Decl(APISample_watcher.ts, 87, 27)) >diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start) : ts.LineAndCharacter ->diagnostic.file.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>diagnostic.file.getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >diagnostic.file : ts.SourceFile, Symbol(ts.Diagnostic.file, Decl(typescript.d.ts, 1062, 26)) >diagnostic : ts.Diagnostic, Symbol(diagnostic, Decl(APISample_watcher.ts, 84, 31)) >file : ts.SourceFile, Symbol(ts.Diagnostic.file, Decl(typescript.d.ts, 1062, 26)) ->getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1263, 46)) +>getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter, Symbol(ts.SourceFile.getLineAndCharacterOfPosition, Decl(typescript.d.ts, 1262, 26)) >diagnostic.start : number, Symbol(ts.Diagnostic.start, Decl(typescript.d.ts, 1063, 25)) >diagnostic : ts.Diagnostic, Symbol(diagnostic, Decl(APISample_watcher.ts, 84, 31)) >start : number, Symbol(ts.Diagnostic.start, Decl(typescript.d.ts, 1063, 25)) diff --git a/tests/baselines/reference/unionTypeReduction.js b/tests/baselines/reference/unionTypeReduction.js new file mode 100644 index 00000000000..1c914489ecc --- /dev/null +++ b/tests/baselines/reference/unionTypeReduction.js @@ -0,0 +1,25 @@ +//// [unionTypeReduction.ts] +interface I2 { + (): number; + (q): boolean; +} + +interface I3 { + (): number; +} + +var i2: I2, i3: I3; + +var e1: I2 | I3; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); + + +//// [unionTypeReduction.js] +var i2, i3; +var e1; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); diff --git a/tests/baselines/reference/unionTypeReduction.types b/tests/baselines/reference/unionTypeReduction.types new file mode 100644 index 00000000000..e4dffff8174 --- /dev/null +++ b/tests/baselines/reference/unionTypeReduction.types @@ -0,0 +1,42 @@ +=== tests/cases/conformance/types/union/unionTypeReduction.ts === +interface I2 { +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) + + (): number; + (q): boolean; +>q : any, Symbol(q, Decl(unionTypeReduction.ts, 2, 5)) +} + +interface I3 { +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) + + (): number; +} + +var i2: I2, i3: I3; +>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3)) +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) +>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11)) +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) + +var e1: I2 | I3; +>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3)) +>I2 : I2, Symbol(I2, Decl(unionTypeReduction.ts, 0, 0)) +>I3 : I3, Symbol(I3, Decl(unionTypeReduction.ts, 3, 1)) + +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 +>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3)) +>i2 || i3 : I3 +>i2 : I2, Symbol(i2, Decl(unionTypeReduction.ts, 9, 3)) +>i3 : I3, Symbol(i3, Decl(unionTypeReduction.ts, 9, 11)) + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +>r1 : number, Symbol(r1, Decl(unionTypeReduction.ts, 14, 3)) +>e1() : number +>e1 : I2 | I3, Symbol(e1, Decl(unionTypeReduction.ts, 11, 3)) + +var r2 = e2(); +>r2 : number, Symbol(r2, Decl(unionTypeReduction.ts, 15, 3)) +>e2() : number +>e2 : I3, Symbol(e2, Decl(unionTypeReduction.ts, 12, 3)) + diff --git a/tests/cases/conformance/types/union/unionTypeReduction.ts b/tests/cases/conformance/types/union/unionTypeReduction.ts new file mode 100644 index 00000000000..8bc3d1cdc8c --- /dev/null +++ b/tests/cases/conformance/types/union/unionTypeReduction.ts @@ -0,0 +1,16 @@ +interface I2 { + (): number; + (q): boolean; +} + +interface I3 { + (): number; +} + +var i2: I2, i3: I3; + +var e1: I2 | I3; +var e2 = i2 || i3; // Type of e2 immediately reduced to I3 + +var r1 = e1(); // Type of e1 reduced to I3 upon accessing property or signature +var r2 = e2(); diff --git a/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts b/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts index 1e072acd1fa..a9205b97f1f 100644 --- a/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts +++ b/tests/cases/fourslash/completionEntryForPropertyFromUnionOfModuleType.ts @@ -2,9 +2,11 @@ ////module E { //// export var n = 1; +//// export var x = 0; ////} ////module F { //// export var n = 1; +//// export var y = 0; ////} ////var q: typeof E | typeof F; ////var j = q./*1*/ diff --git a/tests/cases/fourslash/definitionNameOnEnumMember.ts b/tests/cases/fourslash/definitionNameOnEnumMember.ts index d88e1ef688e..3844d4a46f3 100644 --- a/tests/cases/fourslash/definitionNameOnEnumMember.ts +++ b/tests/cases/fourslash/definitionNameOnEnumMember.ts @@ -7,5 +7,6 @@ ////} ////var enumMember = e./*1*/thirdMember; +debugger; goTo.marker("1"); verify.verifyDefinitionsName("thirdMember", "e"); \ No newline at end of file diff --git a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts index 674d5f4b623..0e18e543ec3 100644 --- a/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts +++ b/tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts @@ -19,8 +19,8 @@ goTo.marker("propertyReference"); verify.definitionCountIs(2); goTo.definition(0); -verify.caretAtMarker("propertyDefinition2"); +verify.caretAtMarker("propertyDefinition1"); goTo.marker("propertyReference"); goTo.definition(1); -verify.caretAtMarker("propertyDefinition1"); +verify.caretAtMarker("propertyDefinition2"); diff --git a/tests/cases/fourslash/navigationItemsOverloads2.ts b/tests/cases/fourslash/navigationItemsOverloads2.ts index 2c33ef65f0d..98908c84e98 100644 --- a/tests/cases/fourslash/navigationItemsOverloads2.ts +++ b/tests/cases/fourslash/navigationItemsOverloads2.ts @@ -8,5 +8,5 @@ ////interface I { //// interfaceMethodSignature(b: boolean): boolean; ////} - +debugger; verify.navigationItemsListCount(2, "interfaceMethodSignature", "exact"); diff --git a/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts index d2a9ec8e25f..21b7d33dd41 100644 --- a/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts +++ b/tests/cases/fourslash/navigationItemsOverloadsBroken1.ts @@ -4,7 +4,7 @@ ////function overload1(b: boolean): boolean; ////function overload1(b: number): boolean; //// -////var heyImNotInterruptingAnythingAmI = '?'; +////var x= '?'; //// ////function overload1(f: typeof overload): boolean; ////function overload1(x: any, b = (function overload() { return false })): boolean { @@ -15,7 +15,7 @@ ////function overload2(b: boolean): boolean; ////function overload2(b: number): boolean; //// -////function iJustRuinEverything(x: any, b = (function overload() { return false })): boolean { +////function y(x: any, b = (function overload() { return false })): boolean { //// throw overload; ////} //// @@ -24,6 +24,6 @@ //// throw overload; ////} -verify.navigationItemsListCount(2, "overload1", "exact"); -verify.navigationItemsListCount(2, "overload2", "exact"); -verify.navigationItemsListCount(4, "overload", "prefix"); \ No newline at end of file +verify.navigationItemsListCount(1, "overload1", "exact"); +verify.navigationItemsListCount(1, "overload2", "exact"); +verify.navigationItemsListCount(2, "overload", "prefix"); \ No newline at end of file