From 417cea9cc0923ca15772082d5a799f05c510ce87 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Oct 2014 17:33:16 -0700 Subject: [PATCH 01/16] move completion list position detection to the new tree --- src/services/services.ts | 324 +++++++++--------- src/services/utilities.ts | 7 +- .../completionListAfterNumericLiteral.ts | 4 +- .../completionListAfterNumericLiteral1.ts | 2 +- .../fourslash/completionListInComments2.ts | 7 + .../fourslash/completionListInComments3.ts | 26 ++ .../completionListPrivateMembers3.ts | 31 ++ ...entifiers-should-not-show-in-completion.ts | 1 + 8 files changed, 241 insertions(+), 161 deletions(-) create mode 100644 tests/cases/fourslash/completionListInComments2.ts create mode 100644 tests/cases/fourslash/completionListInComments3.ts create mode 100644 tests/cases/fourslash/completionListPrivateMembers3.ts diff --git a/src/services/services.ts b/src/services/services.ts index b0c69aa99fe..66d59a5f0a3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -38,6 +38,7 @@ module ts { getFullWidth(): number; getLeadingTriviaWidth(sourceFile?: SourceFile): number; getFullText(sourceFile?: SourceFile): string; + getText(sourceFile?: SourceFile): string; getFirstToken(sourceFile?: SourceFile): Node; getLastToken(sourceFile?: SourceFile): Node; } @@ -130,6 +131,10 @@ module ts { return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end); } + public getText(sourceFile?: SourceFile): string { + return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd()); + } + private addSyntheticNodes(nodes: Node[], pos: number, end: number): number { scanner.setTextPos(pos); while (pos < end) { @@ -1921,15 +1926,15 @@ module ts { } function isCallExpressionTarget(node: Node): boolean { - if (node.parent.kind === SyntaxKind.PropertyAccess && (node.parent).right === node) + if (node && node.parent && node.parent.kind === SyntaxKind.PropertyAccess && (node.parent).right === node) node = node.parent; - return node.parent.kind === SyntaxKind.CallExpression && (node.parent).func === node; + return node && node.parent && node.parent.kind === SyntaxKind.CallExpression && (node.parent).func === node; } function isNewExpressionTarget(node: Node): boolean { - if (node.parent.kind === SyntaxKind.PropertyAccess && (node.parent).right === node) + if (node && node.parent && node.parent.kind === SyntaxKind.PropertyAccess && (node.parent).right === node) node = node.parent; - return node.parent.kind === SyntaxKind.NewExpression && (node.parent).func === node; + return node && node.parent && node.parent.kind === SyntaxKind.NewExpression && (node.parent).func === node; } function isNameOfFunctionDeclaration(node: Node): boolean { @@ -1968,6 +1973,39 @@ module ts { (node.parent.kind === SyntaxKind.ImportDeclaration && (node.parent).externalModuleName === node)); } + /** Returns true if the position is within a comment */ + function isInsideComment(sourceFile: SourceFile, position: number): boolean { + var token = getTokenAtPosition(sourceFile, position); + + // The position has to be: 1. in the leading trivia (before tokek.getStart()), and 2. within a comment + return position <= token.getStart() && + (isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || + isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); + + function isInsideCommentRange(comments: CommentRange[]): boolean { + return forEach(comments, comment => { + // either we are 1. completely inside the comment, or 2. at the end of + if (comment.pos < position && position < comment.end) { + return true; + } + else if (position === comment.end) { + var text = sourceFile.text; + var width = comment.end - comment.pos; + // is single line comment or just /* + if (width <=2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) { + return true; + } + else { + // is unterminated multiline comment + return text.charCodeAt(comment.end - 1) !== CharacterCodes.slash && + text.charCodeAt(comment.end - 2) !== CharacterCodes.asterisk; + } + } + return false; + }); + } + } + enum SemanticMeaning { None = 0x0, Value = 0x1, @@ -2281,40 +2319,58 @@ module ts { }); } - function isCompletionListBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { + function isCompletionListBlocker(sourceFile: SourceFile, position: number): boolean { // We shouldn't be getting a position that is outside the file because // isEntirelyInsideComment can't handle when the position is out of bounds, // callers should be fixed, however we should be resilient to bad inputs // so we return true (this position is a blocker for getting completions) - if (position < 0 || position > TypeScript.fullWidth(sourceUnit)) { + if (position < 0 || position > sourceFile.end) { return true; } // This method uses Fidelity completely. Some information can be reached using the AST, but not everything. - return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position) || - TypeScript.Syntax.isEntirelyInStringOrRegularExpressionLiteral(sourceUnit, position) || - isIdentifierDefinitionLocation(sourceUnit, position) || - isRightOfIllegalDot(sourceUnit, position); + return isInsideComment(sourceFile, position) || + isEntirelyInStringOrRegularExpressionLiteral(sourceFile, position) || + isIdentifierDefinitionLocation(sourceFile, position) || + isRightOfIllegalDot(sourceFile, position); } - function getContainingObjectLiteralApplicableForCompletion(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxElement { + function isEntirelyInStringOrRegularExpressionLiteral(sourceFile: SourceFile, position: number): boolean { + var token = getTouchingPropertyName(sourceFile, position); + + // || token.kind === SyntaxKind.RegularExpressionLiteral + if (token.kind === SyntaxKind.StringLiteral) { + // The position has to be either: 1. entirely within the token text, or + // 2. at the end position, and the string literal is not terminated + var start = token.getStart(); + var end = token.getEnd(); + if (start < position && position < end) { + return true; + } + else if (position === end) { + var width = end - start; + return width <= 1 || sourceFile.text.charCodeAt(start) !== sourceFile.text.charCodeAt(end - 1); + } + } + else if (token.kind === SyntaxKind.RegularExpressionLiteral) { + return token.getStart() < position && position < token.getEnd(); + } + return false; + } + + function getContainingObjectLiteralApplicableForCompletion(sourceFile: SourceFile, position: number): ObjectLiteral { // The locations in an object literal expression that are applicable for completion are property name definition locations. - var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); if (previousToken) { var parent = previousToken.parent; - switch (previousToken.kind()) { - case TypeScript.SyntaxKind.OpenBraceToken: // var x = { | - case TypeScript.SyntaxKind.CommaToken: // var x = { a: 0, | - if (parent && parent.kind() === TypeScript.SyntaxKind.SeparatedList) { - parent = parent.parent; + switch (previousToken.kind) { + case SyntaxKind.OpenBraceToken: // var x = { | + case SyntaxKind.CommaToken: // var x = { a: 0, | + if (parent && parent.kind === SyntaxKind.ObjectLiteral) { + return parent; } - - if (parent && parent.kind() === TypeScript.SyntaxKind.ObjectLiteralExpression) { - return parent; - } - break; } } @@ -2322,47 +2378,67 @@ module ts { return undefined; } - function isIdentifierDefinitionLocation(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + function isFunction(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return true; + } + return false; + } - if (positionedToken) { - var containingNodeKind = TypeScript.Syntax.containingNode(positionedToken) && TypeScript.Syntax.containingNode(positionedToken).kind(); - switch (positionedToken.kind()) { - case TypeScript.SyntaxKind.CommaToken: - return containingNodeKind === TypeScript.SyntaxKind.ParameterList || - containingNodeKind === TypeScript.SyntaxKind.VariableDeclaration || - containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { foo, | + function isIdentifierDefinitionLocation(sourceFile: SourceFile, position: number): boolean { + var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); + if (previousToken) { + var containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case SyntaxKind.CommaToken: + return containingNodeKind === SyntaxKind.VariableDeclaration || + containingNodeKind === SyntaxKind.VariableStatement || + containingNodeKind === SyntaxKind.EnumDeclaration || // enum { foo, | + isFunction(containingNodeKind); - case TypeScript.SyntaxKind.OpenParenToken: - return containingNodeKind === TypeScript.SyntaxKind.ParameterList || - containingNodeKind === TypeScript.SyntaxKind.CatchClause; + case SyntaxKind.OpenParenToken: + return containingNodeKind === SyntaxKind.CatchBlock || + isFunction(containingNodeKind); - case TypeScript.SyntaxKind.OpenBraceToken: - return containingNodeKind === TypeScript.SyntaxKind.EnumDeclaration; // enum { | + case SyntaxKind.OpenBraceToken: + return containingNodeKind === SyntaxKind.EnumDeclaration; // enum { | + // containingNodeKind === SyntaxKind.InterfaceDeclaration; - case TypeScript.SyntaxKind.PublicKeyword: - case TypeScript.SyntaxKind.PrivateKeyword: - case TypeScript.SyntaxKind.StaticKeyword: - case TypeScript.SyntaxKind.DotDotDotToken: - return containingNodeKind === TypeScript.SyntaxKind.Parameter; + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.DotDotDotToken: + return containingNodeKind === SyntaxKind.Parameter; - case TypeScript.SyntaxKind.ClassKeyword: - case TypeScript.SyntaxKind.ModuleKeyword: - case TypeScript.SyntaxKind.EnumKeyword: - case TypeScript.SyntaxKind.InterfaceKeyword: - case TypeScript.SyntaxKind.FunctionKeyword: - case TypeScript.SyntaxKind.VarKeyword: - case TypeScript.SyntaxKind.GetKeyword: - case TypeScript.SyntaxKind.SetKeyword: + case SyntaxKind.ClassKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.VarKeyword: + case SyntaxKind.GetKeyword: + case SyntaxKind.SetKeyword: return true; } // Previous token may have been a keyword that was converted to an identifier. - switch (positionedToken.text()) { + switch (previousToken.getText()) { case "class": case "interface": case "enum": case "module": + case "function": + case "var": return true; } } @@ -2370,44 +2446,28 @@ module ts { return false; } - function getNonIdentifierCompleteTokenOnLeft(sourceUnit: TypeScript.SourceUnitSyntax, position: number): TypeScript.ISyntaxToken { - var positionedToken = TypeScript.Syntax.findCompleteTokenOnLeft(sourceUnit, position, /*includeSkippedTokens*/true); + function getNonIdentifierCompleteTokenOnLeft(sourceFile: SourceFile, position: number): Node { + var previousToken = findTokenOnLeftOfPosition(sourceFile, position); - if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() == TypeScript.SyntaxKind.EndOfFileToken) { - // EndOfFile token is not interesting, get the one before it - positionedToken = TypeScript. previousToken(positionedToken, /*includeSkippedTokens*/true); - } - - if (positionedToken && position === TypeScript.end(positionedToken) && positionedToken.kind() === TypeScript.SyntaxKind.IdentifierName) { + if (previousToken && position <= previousToken.end && previousToken.kind === SyntaxKind.Identifier) { // The caret is at the end of an identifier, the decision to provide completion depends on the previous token - positionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true); + previousToken = findPrecedingToken(previousToken.pos, sourceFile); } - return positionedToken; + return previousToken; } - function isRightOfIllegalDot(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean { - var positionedToken = getNonIdentifierCompleteTokenOnLeft(sourceUnit, position); + function isRightOfIllegalDot(sourceFile: SourceFile, position: number): boolean { + var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); - if (positionedToken) { - switch (positionedToken.kind()) { - case TypeScript.SyntaxKind.DotToken: - var leftOfDotPositionedToken = TypeScript.previousToken(positionedToken, /*includeSkippedTokens*/true); - return leftOfDotPositionedToken && leftOfDotPositionedToken.kind() === TypeScript.SyntaxKind.NumericLiteral; - - case TypeScript.SyntaxKind.NumericLiteral: - var text = positionedToken.text(); - return text.charAt(text.length - 1) === "."; - } + if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) { + var text = previousToken.getFullText(); + return text.charAt(text.length - 1) === "."; } return false; } - function isPunctuation(kind: SyntaxKind) { - return (SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation); - } - function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] { if (!existingMembers || existingMembers.length === 0) { return contextualMemberSymbols; @@ -2445,65 +2505,28 @@ module ts { var sourceFile = getSourceFile(filename); var sourceUnit = sourceFile.getSourceUnit(); - if (isCompletionListBlocker(sourceFile.getSyntaxTree().sourceUnit(), position)) { + if (isCompletionListBlocker(sourceFile, position)) { host.log("Returning an empty list because completion was blocked."); return null; } - var node = TypeScript.ASTHelpers.getAstAtPosition(sourceUnit, position, /*useTrailingTriviaAsLimChar*/ true, /*forceInclusive*/ true); - - if (node && node.kind() === TypeScript.SyntaxKind.IdentifierName && - TypeScript.start(node) === TypeScript.end(node)) { - // Ignore missing name nodes - node = node.parent; - } - - var isRightOfDot = false; - if (node && - node.kind() === TypeScript.SyntaxKind.MemberAccessExpression && - TypeScript.end((node).expression) < position) { - + var node: Node; + var isRightOfDot: boolean; + var token = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); + if (token && token.kind === SyntaxKind.DotToken && + (token.parent.kind === SyntaxKind.PropertyAccess || token.parent.kind === SyntaxKind.QualifiedName)) { + node = (token.parent).left; isRightOfDot = true; - node = (node).expression; - } - else if (node && - node.kind() === TypeScript.SyntaxKind.QualifiedName && - TypeScript.end((node).left) < position) { - - isRightOfDot = true; - node = (node).left; - } - else if (node && node.parent && - node.kind() === TypeScript.SyntaxKind.IdentifierName && - node.parent.kind() === TypeScript.SyntaxKind.MemberAccessExpression && - (node.parent).name === node) { - - isRightOfDot = true; - node = (node.parent).expression; - } - else if (node && node.parent && - node.kind() === TypeScript.SyntaxKind.IdentifierName && - node.parent.kind() === TypeScript.SyntaxKind.QualifiedName && - (node.parent).right === node) { - - isRightOfDot = true; - node = (node.parent).left; - } - - // TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node - var precedingToken = findTokenOnLeftOfPosition(sourceFile, TypeScript.end(node)); - var mappedNode: Node; - if (!precedingToken) { - mappedNode = sourceFile; - } - else if (isPunctuation(precedingToken.kind)) { - mappedNode = precedingToken.parent; } else { - mappedNode = precedingToken; - } + node = !token ? sourceFile : token.parent; + isRightOfDot = false; - Debug.assert(mappedNode, "Could not map a Fidelity node to an AST node"); + // we are at the end of a container node, we do not want to be inside it, as that would affect our completion results + // e.g. function f(a) {}| <- 'a' should not be visible here + if (token && token.kind === SyntaxKind.CloseBraceToken && position === token.end) { + } + } // Get the completions activeCompletionSession = { @@ -2511,7 +2534,7 @@ module ts { position: position, entries: [], symbols: {}, - location: mappedNode, + location: node, typeChecker: typeInfoResolver }; @@ -2520,8 +2543,8 @@ module ts { var symbols: Symbol[] = []; isMemberCompletion = true; - if (mappedNode.kind === SyntaxKind.Identifier || mappedNode.kind === SyntaxKind.QualifiedName || mappedNode.kind === SyntaxKind.PropertyAccess) { - var symbol = typeInfoResolver.getSymbolInfo(mappedNode); + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccess) { + var symbol = typeInfoResolver.getSymbolInfo(node); // This is an alias, follow what it aliases if (symbol && symbol.flags & SymbolFlags.Import) { @@ -2531,19 +2554,19 @@ module ts { if (symbol && symbol.flags & SymbolFlags.HasExports) { // Extract module or enum members forEachValue(symbol.exports, symbol => { - if (typeInfoResolver.isValidPropertyAccess((mappedNode.parent), symbol.name)) { + if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); } } - var type = typeInfoResolver.getTypeOfNode(mappedNode); + var type = typeInfoResolver.getTypeOfNode(node); var apparentType = type && typeInfoResolver.getApparentType(type); if (apparentType) { // Filter private properties forEach(apparentType.getApparentProperties(), symbol => { - if (typeInfoResolver.isValidPropertyAccess((mappedNode.parent), symbol.name)) { + if (typeInfoResolver.isValidPropertyAccess((node.parent), symbol.name)) { symbols.push(symbol); } }); @@ -2552,17 +2575,13 @@ module ts { getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { - var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(sourceFile.getSyntaxTree().sourceUnit(), position); + var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(sourceFile, position); // Object literal expression, look up possible property names from contextual type if (containingObjectLiteral) { - var objectLiteral = (mappedNode.kind === SyntaxKind.ObjectLiteral ? mappedNode : getAncestor(mappedNode, SyntaxKind.ObjectLiteral)); - - Debug.assert(objectLiteral); - isMemberCompletion = true; - var contextualType = typeInfoResolver.getContextualType(objectLiteral); + var contextualType = typeInfoResolver.getContextualType(containingObjectLiteral); if (!contextualType) { return undefined; } @@ -2570,7 +2589,7 @@ module ts { var contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType); if (contextualTypeMembers && contextualTypeMembers.length > 0) { // Add filtered items to the completion list - var filteredMembers = filterContextualMembersList(contextualTypeMembers, objectLiteral.properties); + var filteredMembers = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties); getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession); } } @@ -2579,7 +2598,7 @@ module ts { isMemberCompletion = false; /// TODO filter meaning based on the current context var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Import; - var symbols = typeInfoResolver.getSymbolsInScope(mappedNode, symbolMeanings); + var symbols = typeInfoResolver.getSymbolsInScope(node, symbolMeanings); getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } @@ -2767,14 +2786,19 @@ module ts { var type = typeResolver.getTypeOfSymbol(symbol); if (type) { - if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { - // try get the call/construct signature from the type if it matches - var callExpression: CallExpression; + // try get the call/construct signature from the type if it matches + var callExpression: CallExpression; + if (location.kind === SyntaxKind.CallExpression || location.kind === SyntaxKind.NewExpression) { + callExpression = location; + } + else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { if (location.parent.kind === SyntaxKind.PropertyAccess && (location.parent).right === location) { location = location.parent; } callExpression = location.parent; + } + if (callExpression) { var candidateSignatures: Signature[] = []; signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures); if (!signature && candidateSignatures.length) { @@ -5016,17 +5040,7 @@ module ts { // OK, we have found a match in the file. This is only an acceptable match if // it is contained within a comment. - var token = getTokenAtPosition(sourceFile, matchPosition); - - if (token.getStart() <= matchPosition && matchPosition < token.getEnd()) { - // match was within the token itself. Not in the comment. Keep searching - // descriptor. - continue; - } - - // Looks to be within the trivia. See if we can find the comment containing it. - if (!getContainingComment(getTrailingCommentRanges(fileContents, token.getFullStart()), matchPosition) && - !getContainingComment(getLeadingCommentRanges(fileContents, token.getFullStart()), matchPosition)) { + if (!isInsideComment(sourceFile, matchPosition)) { continue; } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4ceb20fdcee..825c194bc73 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -95,11 +95,12 @@ module ts { var child = current.getChildAt(i); var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile); if (start <= position) { - if (position < child.getEnd()) { + var end = child.getEnd(); + if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { current = child; continue outer; } - else if (includeItemAtEndPosition && child.getEnd() === position) { + else if (includeItemAtEndPosition && end === position) { var previousToken = findPrecedingToken(position, sourceFile, child); if (previousToken && includeItemAtEndPosition(previousToken)) { return previousToken; @@ -180,7 +181,7 @@ module ts { for (var i = 0, len = children.length; i < len; ++i) { var child = children[i]; if (nodeHasTokens(child)) { - if (position < child.end) { + if (position <= child.end) { if (child.getStart(sourceFile) >= position) { // actual start of the node is past the position - previous token should be at the end of previous child var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i); diff --git a/tests/cases/fourslash/completionListAfterNumericLiteral.ts b/tests/cases/fourslash/completionListAfterNumericLiteral.ts index a8ea0335f70..549c048a635 100644 --- a/tests/cases/fourslash/completionListAfterNumericLiteral.ts +++ b/tests/cases/fourslash/completionListAfterNumericLiteral.ts @@ -25,10 +25,10 @@ goTo.marker("dotOnNumberExrpressions1"); verify.completionListIsEmpty(); goTo.marker("dotOnNumberExrpressions2"); -verify.completionListIsEmpty(); +verify.completionListContains("toExponential"); goTo.marker("dotOnNumberExrpressions3"); -verify.completionListIsEmpty(); +verify.completionListContains("toExponential"); goTo.marker("dotOnNumberExrpressions4"); verify.completionListIsEmpty(); diff --git a/tests/cases/fourslash/completionListAfterNumericLiteral1.ts b/tests/cases/fourslash/completionListAfterNumericLiteral1.ts index b2604531316..cf8b5d41e98 100644 --- a/tests/cases/fourslash/completionListAfterNumericLiteral1.ts +++ b/tests/cases/fourslash/completionListAfterNumericLiteral1.ts @@ -3,4 +3,4 @@ ////5../**/ goTo.marker(); -verify.completionListIsEmpty(); \ No newline at end of file +verify.completionListContains("toFixed"); \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInComments2.ts b/tests/cases/fourslash/completionListInComments2.ts new file mode 100644 index 00000000000..d9855306fcf --- /dev/null +++ b/tests/cases/fourslash/completionListInComments2.ts @@ -0,0 +1,7 @@ +/// + +//// // */{| "name" : "1" |} + +goTo.marker("1"); +// Completion list should not be available within comments +verify.completionListIsEmpty(); diff --git a/tests/cases/fourslash/completionListInComments3.ts b/tests/cases/fourslash/completionListInComments3.ts new file mode 100644 index 00000000000..3f57929c1f4 --- /dev/null +++ b/tests/cases/fourslash/completionListInComments3.ts @@ -0,0 +1,26 @@ +/// + +//// /*{| "name": "1" |} + +//// /* {| "name": "2" |} + +//// /* *{| "name": "3" |} + +//// /* */{| "name": "4" |} + +//// {| "name": "5" |}/* */ + +goTo.marker("1"); +verify.completionListIsEmpty(); + +goTo.marker("2"); +verify.completionListIsEmpty(); + +goTo.marker("3"); +verify.completionListIsEmpty(); + +goTo.marker("4"); +verify.not.completionListIsEmpty(); + +//goTo.marker("5"); +//verify.not.completionListIsEmpty(); diff --git a/tests/cases/fourslash/completionListPrivateMembers3.ts b/tests/cases/fourslash/completionListPrivateMembers3.ts new file mode 100644 index 00000000000..69f7456d7b5 --- /dev/null +++ b/tests/cases/fourslash/completionListPrivateMembers3.ts @@ -0,0 +1,31 @@ +/// + +////class Other { +//// public p; +//// protected p2 +//// private p3; +////} +//// +////class Self { +//// private other: Other; +//// +//// method() { +//// this.other./*1*/; +//// +//// this.other.p/*2*/; +//// +//// this.other.p/*3*/.toString(); +//// } +////} + +goTo.marker("1"); +verify.memberListContains("p"); +verify.memberListCount(1); + +goTo.marker("2"); +verify.memberListContains("p"); +verify.memberListCount(1); + +goTo.marker("2"); +verify.memberListContains("p"); +verify.memberListCount(1); diff --git a/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts b/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts index e49dd0dea5d..d01856a54fb 100644 --- a/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts +++ b/tests/cases/fourslash/completion_enum-members-with-invalid-identifiers-should-not-show-in-completion.ts @@ -10,6 +10,7 @@ //// //// e./**/ +goTo.marker(); verify.not.completionListContains('1'); verify.not.completionListContains('"1"'); verify.not.completionListContains('2'); From 68db15d960cc9de180305e28e8c3ff495cc7bffc Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Oct 2014 17:34:00 -0700 Subject: [PATCH 02/16] Split completionListAtIdentifierDefinitionLocation into multiple tests to ease debugging --- ...stAtIdentifierDefinitionLocations_catch.ts | 13 +++++++ ...AtIdentifierDefinitionLocations_classes.ts | 12 +++++++ ...entifierDefinitionLocations_enumMembers.ts | 11 ++++++ ...ntifierDefinitionLocations_enumMembers2.ts | 9 +++++ ...stAtIdentifierDefinitionLocations_enums.ts | 14 ++++++++ ...IdentifierDefinitionLocations_functions.ts | 13 +++++++ ...dentifierDefinitionLocations_interfaces.ts | 13 +++++++ ...AtIdentifierDefinitionLocations_modules.ts | 13 +++++++ ...entifierDefinitionLocations_parameters.ts} | 35 ++++++++----------- ...fierDefinitionLocations_varDeclarations.ts | 18 ++++++++++ 10 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_catch.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_classes.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers2.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enums.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_functions.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaces.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_modules.ts rename tests/cases/fourslash/{completionListAtIdentifierDefinitionLocations.ts => completionListAtIdentifierDefinitionLocations_parameters.ts} (54%) create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_catch.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_catch.ts new file mode 100644 index 00000000000..bdf13c1d97f --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_catch.ts @@ -0,0 +1,13 @@ +/// + +////var aa = 1; + +//// try {} catch(/*catchVariable1*/ + +//// try {} catch(a/*catchVariable2*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_classes.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_classes.ts new file mode 100644 index 00000000000..60a108cf1e6 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_classes.ts @@ -0,0 +1,12 @@ +/// + +////var aa = 1; + +////class /*className1*/ + +////class a/*className2*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers.ts new file mode 100644 index 00000000000..6c0472be546 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers.ts @@ -0,0 +1,11 @@ +/// + +////var aa = 1; + +////enum a { /*enumValueName1*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers2.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers2.ts new file mode 100644 index 00000000000..ee2f3e71032 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enumMembers2.ts @@ -0,0 +1,9 @@ +/// + +////var aa = 1; +////enum a { foo, /*enumValueName3*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enums.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enums.ts new file mode 100644 index 00000000000..183f8a22c63 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_enums.ts @@ -0,0 +1,14 @@ +/// + +////var aa = 1; + +////enum /*enumName1*/ + +////enum a/*enumName2*/ + +////var x = 0; enum /*enumName4*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_functions.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_functions.ts new file mode 100644 index 00000000000..24231174727 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_functions.ts @@ -0,0 +1,13 @@ +/// + +////var aa = 1; + +////function /*functionName1*/ + +////function a/*functionName2*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaces.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaces.ts new file mode 100644 index 00000000000..ec2732fe2fe --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaces.ts @@ -0,0 +1,13 @@ +/// + +////var aa = 1; + +////interface /*interfaceName1*/ + +////interface a/*interfaceName2*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_modules.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_modules.ts new file mode 100644 index 00000000000..4ebdf029a89 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_modules.ts @@ -0,0 +1,13 @@ +/// + +////var aa = 1; + +////module /*moduleName1*/ + +////module a/*moduleName2*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_parameters.ts similarity index 54% rename from tests/cases/fourslash/completionListAtIdentifierDefinitionLocations.ts rename to tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_parameters.ts index e36d69c82f2..0fd66e9d091 100644 --- a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations.ts +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_parameters.ts @@ -1,40 +1,33 @@ /// ////var aa = 1; -////class /*className1*/ -////class a/*className2*/ -////interface /*interfaceName1*/ -////interface a/*interfaceName2*/ -////module /*moduleName1*/ -////module a/*moduleName2*/ -////enum /*enumName1*/ -////enum a/*enumName2*/ -////// fourslash is saying completion list is not empty on this line but editor disagrees -//////enum a { /*enumValueName1*/ -////enum a { f/*enumValueName2*/ -////enum a { foo, /*enumValueName3*/ -////var x = 0; enum /*enumName4*/ -////function /*functionName1*/ -////function a/*functionName2*/ -////var /*varName1*/ -////var a/*varName2*/ -////var a2,/*varName3*/ -////var a2, a/*varName4*/ + ////function testFunction(/*parameterName1*/ + ////function testFunction(a/*parameterName2*/ + ////function testFunction(a, /*parameterName3*/ + ////function testFunction(a, b/*parameterName4*/ + ////class bar1{ constructor(/*constructorParamter1*/ + ////class bar2{ constructor(a/*constructorParamter2*/ + ////class bar3{ constructor(a, /*constructorParamter3*/ + ////class bar4{ constructor(a, b/*constructorParamter4*/ + ////class bar5{ constructor(public /*constructorParamter5*/ + ////class bar6{ constructor(public a/*constructorParamter6*/ + ////class bar7{ constructor(private a/*constructorParamter7*/ + ////class bar8{ constructor(.../*constructorParamter8*/ + ////class bar9{ constructor(...a/*constructorParamter9*/ -//// try {} catch(/*catchVariable1*/ -//// try {} catch(a/*catchVariable2*/ + test.markers().forEach((m) => { goTo.position(m.position, m.fileName); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts new file mode 100644 index 00000000000..50a112f4625 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_varDeclarations.ts @@ -0,0 +1,18 @@ +/// + +////var aa = 1; + + +////var /*varName1*/ + +////var a/*varName2*/ + +////var a2,/*varName3*/ + +////var a2, a/*varName4*/ + + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); From 463b2392b7d89eb3f88933d894a87fd8e77494d3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Wed, 22 Oct 2014 17:36:43 -0700 Subject: [PATCH 03/16] remove call to getSourceUnit --- src/services/services.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/services.ts b/src/services/services.ts index 66d59a5f0a3..018f322ac41 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2439,6 +2439,7 @@ module ts { case "module": case "function": case "var": + // TODO: add let and const return true; } } @@ -2503,7 +2504,6 @@ module ts { filename = TypeScript.switchToForwardSlashes(filename); var sourceFile = getSourceFile(filename); - var sourceUnit = sourceFile.getSourceUnit(); if (isCompletionListBlocker(sourceFile, position)) { host.log("Returning an empty list because completion was blocked."); From 3dc6072f583e80ddece8233774c1e0dcf05bd65f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 09:27:50 -0700 Subject: [PATCH 04/16] Disallow completion in interface declarations --- src/services/services.ts | 10 +++++++--- ...AtIdentifierDefinitionLocations_interfaceMembers.ts | 10 ++++++++++ ...tIdentifierDefinitionLocations_interfaceMembers2.ts | 10 ++++++++++ ...tIdentifierDefinitionLocations_interfaceMembers3.ts | 10 ++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers2.ts create mode 100644 tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers3.ts diff --git a/src/services/services.ts b/src/services/services.ts index 018f322ac41..82f19d1797c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2403,7 +2403,7 @@ module ts { case SyntaxKind.CommaToken: return containingNodeKind === SyntaxKind.VariableDeclaration || containingNodeKind === SyntaxKind.VariableStatement || - containingNodeKind === SyntaxKind.EnumDeclaration || // enum { foo, | + containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | isFunction(containingNodeKind); case SyntaxKind.OpenParenToken: @@ -2411,8 +2411,12 @@ module ts { isFunction(containingNodeKind); case SyntaxKind.OpenBraceToken: - return containingNodeKind === SyntaxKind.EnumDeclaration; // enum { | - // containingNodeKind === SyntaxKind.InterfaceDeclaration; + return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { | + containingNodeKind === SyntaxKind.InterfaceDeclaration; // interface a { | + + case SyntaxKind.SemicolonToken: + return containingNodeKind === SyntaxKind.Property && + previousToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration; // interface a { f; | case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers.ts new file mode 100644 index 00000000000..266b0b78c9c --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers.ts @@ -0,0 +1,10 @@ +/// + +////var aa = 1; + +////interface a { /*interfaceValue1*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers2.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers2.ts new file mode 100644 index 00000000000..82a30325948 --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers2.ts @@ -0,0 +1,10 @@ +/// + +////var aa = 1; + +////interface a { f/*interfaceValue2*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers3.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers3.ts new file mode 100644 index 00000000000..ed640dd3f1a --- /dev/null +++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_interfaceMembers3.ts @@ -0,0 +1,10 @@ +/// + +////var aa = 1; + +////interface a { f; /*interfaceValue3*/ + +test.markers().forEach((m) => { + goTo.position(m.position, m.fileName); + verify.completionListIsEmpty(); +}); From 161eea13e02c289defefc01fc37499fa7c7140f0 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 09:34:29 -0700 Subject: [PATCH 05/16] Add test for issue#903 --- tests/cases/fourslash/completionListAfterSlash.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/cases/fourslash/completionListAfterSlash.ts diff --git a/tests/cases/fourslash/completionListAfterSlash.ts b/tests/cases/fourslash/completionListAfterSlash.ts new file mode 100644 index 00000000000..f9a0b69afdf --- /dev/null +++ b/tests/cases/fourslash/completionListAfterSlash.ts @@ -0,0 +1,8 @@ +/// + +////var a = 0; +////a/./**/ + +goTo.marker(); +// should not crash +verify.completionListIsEmpty(); From 669044c495d4a7ad58347cd4f73a8b1516fac4c6 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 12:35:04 -0700 Subject: [PATCH 06/16] Fix issue #866, detect the current location correctelly in completion entry details --- src/services/services.ts | 20 +++++++++++++------ .../fourslash/commentsExternalModules.ts | 4 ++-- tests/cases/fourslash/commentsFunction.ts | 2 +- .../fourslash/commentsImportDeclaration.ts | 2 +- tests/cases/fourslash/commentsInheritance.ts | 20 +++++++++---------- tests/cases/fourslash/commentsInterface.ts | 2 +- tests/cases/fourslash/commentsModules.ts | 14 ++++++------- .../externalModuleWithExportAssignment.ts | 4 ++-- 8 files changed, 38 insertions(+), 30 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 82f19d1797c..77fa907956d 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1265,7 +1265,6 @@ module ts { position: number; // position in the file where the completion was requested entries: CompletionEntry[]; // entries for this completion symbols: Map; // symbols by entry name map - location: Node; // the node where the completion was requested typeChecker: TypeChecker; // the typeChecker used to generate this completion } @@ -2515,8 +2514,10 @@ module ts { } var node: Node; + var location: Node; var isRightOfDot: boolean; var token = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); + if (token && token.kind === SyntaxKind.DotToken && (token.parent.kind === SyntaxKind.PropertyAccess || token.parent.kind === SyntaxKind.QualifiedName)) { node = (token.parent).left; @@ -2538,7 +2539,6 @@ module ts { position: position, entries: [], symbols: {}, - location: node, typeChecker: typeInfoResolver }; @@ -2624,6 +2624,8 @@ module ts { // in the getCompletionsAtPosition earlier filename = TypeScript.switchToForwardSlashes(filename); + var sourceFile = getSourceFile(filename); + var session = activeCompletionSession; // Ensure that the current active completion session is still valid for this request @@ -2640,7 +2642,8 @@ module ts { // 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. - var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location, SemanticMeaning.All); + var location = getTouchingPropertyName(sourceFile, position); + var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), location, session.typeChecker, location, SemanticMeaning.All); return { name: entryName, kind: displayPartsDocumentationsAndSymbolKind.symbolKind, @@ -2790,15 +2793,20 @@ module ts { var type = typeResolver.getTypeOfSymbol(symbol); if (type) { + if (location.parent && location.parent.kind === SyntaxKind.PropertyAccess) { + var right = (location.parent).right; + // Either the location is on the right of a property access, or on the left and the right is missing + if (right === location || (right && right.kind === SyntaxKind.Missing)){ + location = location.parent; + } + } + // try get the call/construct signature from the type if it matches var callExpression: CallExpression; if (location.kind === SyntaxKind.CallExpression || location.kind === SyntaxKind.NewExpression) { callExpression = location; } else if (isCallExpressionTarget(location) || isNewExpressionTarget(location)) { - if (location.parent.kind === SyntaxKind.PropertyAccess && (location.parent).right === location) { - location = location.parent; - } callExpression = location.parent; } diff --git a/tests/cases/fourslash/commentsExternalModules.ts b/tests/cases/fourslash/commentsExternalModules.ts index 0eed08ca01e..154d87535c6 100644 --- a/tests/cases/fourslash/commentsExternalModules.ts +++ b/tests/cases/fourslash/commentsExternalModules.ts @@ -64,7 +64,7 @@ goTo.marker('7'); verify.quickInfoIs("(var) myvar: m1.m2.c", ""); goTo.marker('8'); -verify.memberListContains("c", "class m1.m2.c", "class comment;"); +verify.memberListContains("c", "(constructor) m1.m2.c(): m1.m2.c", ""); verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i"); goTo.file("commentsExternalModules_file1.ts"); @@ -91,5 +91,5 @@ goTo.marker('14'); verify.quickInfoIs("(var) newVar: extMod.m1.m2.c", ""); goTo.marker('15'); -verify.memberListContains("c", "class extMod.m1.m2.c", "class comment;"); +verify.memberListContains("c", "(constructor) extMod.m1.m2.c(): extMod.m1.m2.c", ""); verify.memberListContains("i", "(var) extMod.m1.m2.i: extMod.m1.m2.c", "i"); diff --git a/tests/cases/fourslash/commentsFunction.ts b/tests/cases/fourslash/commentsFunction.ts index 3a4e4e4dcc2..3af718fc967 100644 --- a/tests/cases/fourslash/commentsFunction.ts +++ b/tests/cases/fourslash/commentsFunction.ts @@ -74,7 +74,7 @@ goTo.marker('12'); verify.quickInfoIs("(var) lambddaNoVarComment: (a: number, b: number) => number", ""); goTo.marker('13'); -verify.completionListContains('lambdaFoo', '(var) lambdaFoo: (a: number, b: number) => number', 'lamdaFoo var comment'); +verify.completionListContains('lambdaFoo', '(var) lambdaFoo: (a: number, b: number) => number', ''); verify.completionListContains('lambddaNoVarComment', '(var) lambddaNoVarComment: (a: number, b: number) => number', ''); goTo.marker('14'); diff --git a/tests/cases/fourslash/commentsImportDeclaration.ts b/tests/cases/fourslash/commentsImportDeclaration.ts index 192cb2763ca..7b34d2fade2 100644 --- a/tests/cases/fourslash/commentsImportDeclaration.ts +++ b/tests/cases/fourslash/commentsImportDeclaration.ts @@ -47,5 +47,5 @@ goTo.marker('9'); verify.quickInfoIs("(var) newVar: extMod.m1.m2.c", ""); goTo.marker('10'); -verify.memberListContains("c", "class extMod.m1.m2.c", "class comment;"); +verify.memberListContains("c", "(constructor) extMod.m1.m2.c(): extMod.m1.m2.c", ""); verify.memberListContains("i", "(var) extMod.m1.m2.i: extMod.m1.m2.c", "i"); diff --git a/tests/cases/fourslash/commentsInheritance.ts b/tests/cases/fourslash/commentsInheritance.ts index eaca1d79ccb..e8c2084d38d 100644 --- a/tests/cases/fourslash/commentsInheritance.ts +++ b/tests/cases/fourslash/commentsInheritance.ts @@ -223,7 +223,7 @@ goTo.marker('1'); verify.memberListContains("i1_p1", "(property) i1.i1_p1: number", "i1_p1"); verify.memberListContains("i1_f1", "(method) i1.i1_f1(): void", "i1_f1"); -verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "i1_l1"); +verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", ""); verify.memberListContains("i1_nc_p1", "(property) i1.i1_nc_p1: number", ""); verify.memberListContains("i1_nc_f1", "(method) i1.i1_nc_f1(): void", ""); verify.memberListContains("i1_nc_l1", "(property) i1.i1_nc_l1: () => void", ""); @@ -278,10 +278,10 @@ verify.memberListContains("i1_nc_f1", "(method) c1.i1_nc_f1(): void", ""); verify.memberListContains("i1_nc_l1", "(property) c1.i1_nc_l1: () => void", ""); verify.memberListContains("p1", "(property) c1.p1: number", "c1_p1"); verify.memberListContains("f1", "(method) c1.f1(): void", "c1_f1"); -verify.memberListContains("l1", "(property) c1.l1: () => void", "c1_l1"); +verify.memberListContains("l1", "(property) c1.l1: () => void", ""); verify.memberListContains("nc_p1", "(property) c1.nc_p1: number", "c1_nc_p1"); verify.memberListContains("nc_f1", "(method) c1.nc_f1(): void", "c1_nc_f1"); -verify.memberListContains("nc_l1", "(property) c1.nc_l1: () => void", "c1_nc_l1"); +verify.memberListContains("nc_l1", "(property) c1.nc_l1: () => void", ""); goTo.marker('7'); verify.currentSignatureHelpDocCommentIs(""); goTo.marker('8'); @@ -321,7 +321,7 @@ verify.quickInfoIs("(property) c1.nc_l1: () => void", ""); goTo.marker('11'); verify.memberListContains("i1_p1", "(property) i1.i1_p1: number", "i1_p1"); verify.memberListContains("i1_f1", "(method) i1.i1_f1(): void", "i1_f1"); -verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", "i1_l1"); +verify.memberListContains("i1_l1", "(property) i1.i1_l1: () => void", ""); verify.memberListContains("i1_nc_p1", "(property) i1.i1_nc_p1: number", ""); verify.memberListContains("i1_nc_f1", "(method) i1.i1_nc_f1(): void", ""); verify.memberListContains("i1_nc_l1", "(property) i1.i1_nc_l1: () => void", ""); @@ -508,13 +508,13 @@ verify.completionListContains("c4_i", "(var) c4_i: c4", ""); goTo.marker('36'); verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1"); verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1"); -verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1"); +verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", ""); verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", ""); verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", ""); verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", ""); verify.memberListContains("p1", "(property) i2.p1: number", "i2 p1"); verify.memberListContains("f1", "(method) i2.f1(): void", "i2 f1"); -verify.memberListContains("l1", "(property) i2.l1: () => void", "i2 l1"); +verify.memberListContains("l1", "(property) i2.l1: () => void", ""); verify.memberListContains("nc_p1", "(property) i2.nc_p1: number", ""); verify.memberListContains("nc_f1", "(method) i2.nc_f1(): void", ""); verify.memberListContains("nc_l1", "(property) i2.nc_l1: () => void", ""); @@ -559,13 +559,13 @@ verify.quickInfoIs("(property) i2.nc_l1: () => void", ""); goTo.marker('41'); verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1"); verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1"); -verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1"); +verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", ""); verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", ""); verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", ""); verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", ""); verify.memberListContains("p1", "(property) i3.p1: number", "i3 p1"); verify.memberListContains("f1", "(method) i3.f1(): void", "i3 f1"); -verify.memberListContains("l1", "(property) i3.l1: () => void", "i3 l1"); +verify.memberListContains("l1", "(property) i3.l1: () => void", ""); verify.memberListContains("nc_p1", "(property) i3.nc_p1: number", ""); verify.memberListContains("nc_f1", "(method) i3.nc_f1(): void", ""); verify.memberListContains("nc_l1", "(property) i3.nc_l1: () => void", ""); @@ -606,13 +606,13 @@ verify.quickInfoIs("(property) i3.nc_l1: () => void", ""); goTo.marker('46'); verify.memberListContains("i2_p1", "(property) i2.i2_p1: number", "i2_p1"); verify.memberListContains("i2_f1", "(method) i2.i2_f1(): void", "i2_f1"); -verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", "i2_l1"); +verify.memberListContains("i2_l1", "(property) i2.i2_l1: () => void", ""); verify.memberListContains("i2_nc_p1", "(property) i2.i2_nc_p1: number", ""); verify.memberListContains("i2_nc_f1", "(method) i2.i2_nc_f1(): void", ""); verify.memberListContains("i2_nc_l1", "(property) i2.i2_nc_l1: () => void", ""); verify.memberListContains("p1", "(property) i2.p1: number", "i2 p1"); verify.memberListContains("f1", "(method) i2.f1(): void", "i2 f1"); -verify.memberListContains("l1", "(property) i2.l1: () => void", "i2 l1"); +verify.memberListContains("l1", "(property) i2.l1: () => void", ""); verify.memberListContains("nc_p1", "(property) i2.nc_p1: number", ""); verify.memberListContains("nc_f1", "(method) i2.nc_f1(): void", ""); verify.memberListContains("nc_l1", "(property) i2.nc_l1: () => void", ""); diff --git a/tests/cases/fourslash/commentsInterface.ts b/tests/cases/fourslash/commentsInterface.ts index 02856242cee..d4a3d2dd924 100644 --- a/tests/cases/fourslash/commentsInterface.ts +++ b/tests/cases/fourslash/commentsInterface.ts @@ -235,7 +235,7 @@ verify.completionListContains("i3_i", "(var) i3_i: i3", ""); goTo.marker('41'); verify.quickInfoIs("(method) i3.f(a: number): string", "Function i3 f"); verify.memberListContains("f", "(method) i3.f(a: number): string", "Function i3 f"); -verify.memberListContains("l", "(property) i3.l: (b: number) => string", "i3 l"); +verify.memberListContains("l", "(property) i3.l: (b: number) => string", ""); verify.memberListContains("x", "(property) i3.x: number", "Comment i3 x"); verify.memberListContains("nc_f", "(method) i3.nc_f(a: number): string", ""); verify.memberListContains("nc_l", "(property) i3.nc_l: (b: number) => string", ""); diff --git a/tests/cases/fourslash/commentsModules.ts b/tests/cases/fourslash/commentsModules.ts index 06b45afe89e..90257079569 100644 --- a/tests/cases/fourslash/commentsModules.ts +++ b/tests/cases/fourslash/commentsModules.ts @@ -125,7 +125,7 @@ verify.quickInfoIs("(var) myvar: m1.m2.c", ""); goTo.marker('8'); verify.quickInfoIs("(constructor) m1.m2.c(): m1.m2.c", ""); -verify.memberListContains("c", "class m1.m2.c", "class comment;"); +verify.memberListContains("c", "(constructor) m1.m2.c(): m1.m2.c", ""); verify.memberListContains("i", "(var) m1.m2.i: m1.m2.c", "i"); goTo.marker('9'); @@ -138,7 +138,7 @@ verify.quickInfoIs("module m2.m3", "module comment of m2.m3"); goTo.marker('11'); verify.quickInfoIs("(constructor) m2.m3.c(): m2.m3.c", ""); -verify.memberListContains("c", "class m2.m3.c", "Exported class comment"); +verify.memberListContains("c", "(constructor) m2.m3.c(): m2.m3.c", ""); goTo.marker('12'); verify.completionListContains("m3", "module m3", ""); @@ -153,8 +153,8 @@ verify.memberListContains("m5", "module m3.m4.m5"); verify.quickInfoIs("module m3.m4.m5", "module comment of m3.m4.m5"); goTo.marker('15'); -verify.memberListContains("c", "class m3.m4.m5.c", "Exported class comment"); verify.quickInfoIs("(constructor) m3.m4.m5.c(): m3.m4.m5.c", ""); +verify.memberListContains("c", "(constructor) m3.m4.m5.c(): m3.m4.m5.c", ""); goTo.marker('16'); verify.completionListContains("m4", "module m4", ""); @@ -173,7 +173,7 @@ verify.memberListContains("m7", "module m4.m5.m6.m7"); verify.quickInfoIs("module m4.m5.m6.m7", ""); goTo.marker('20'); -verify.memberListContains("c", "class m4.m5.m6.m7.c", "Exported class comment"); +verify.memberListContains("c", "(constructor) m4.m5.m6.m7.c(): m4.m5.m6.m7.c", ""); verify.quickInfoIs("(constructor) m4.m5.m6.m7.c(): m4.m5.m6.m7.c", ""); goTo.marker('21'); @@ -193,7 +193,7 @@ verify.memberListContains("m8", "module m5.m6.m7.m8"); verify.quickInfoIs("module m5.m6.m7.m8", "module m8 comment"); goTo.marker('25'); -verify.memberListContains("c", "class m5.m6.m7.m8.c", "Exported class comment"); +verify.memberListContains("c", "(constructor) m5.m6.m7.m8.c(): m5.m6.m7.m8.c", ""); verify.quickInfoIs("(constructor) m5.m6.m7.m8.c(): m5.m6.m7.m8.c", ""); goTo.marker('26'); @@ -209,7 +209,7 @@ verify.memberListContains("m8", "module m6.m7.m8"); verify.quickInfoIs("module m6.m7.m8", ""); goTo.marker('29'); -verify.memberListContains("c", "class m6.m7.m8.c", "Exported class comment"); +verify.memberListContains("c", "(constructor) m6.m7.m8.c(): m6.m7.m8.c", ""); verify.quickInfoIs("(constructor) m6.m7.m8.c(): m6.m7.m8.c", ""); goTo.marker('30'); @@ -225,7 +225,7 @@ verify.memberListContains("m9", "module m7.m8.m9"); verify.quickInfoIs("module m7.m8.m9", "module m9 comment"); goTo.marker('33'); -verify.memberListContains("c", "class m7.m8.m9.c", "Exported class comment"); +verify.memberListContains("c", "(constructor) m7.m8.m9.c(): m7.m8.m9.c", ""); verify.quickInfoIs("(constructor) m7.m8.m9.c(): m7.m8.m9.c", ""); goTo.marker('34'); diff --git a/tests/cases/fourslash/externalModuleWithExportAssignment.ts b/tests/cases/fourslash/externalModuleWithExportAssignment.ts index 952640f2c6c..1cbaf4f518c 100644 --- a/tests/cases/fourslash/externalModuleWithExportAssignment.ts +++ b/tests/cases/fourslash/externalModuleWithExportAssignment.ts @@ -37,7 +37,7 @@ verify.quickInfoIs("(var) a: {\n (): a1.connectExport;\n test1: a1.connect goTo.marker('3'); verify.quickInfoIs("(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined); -verify.completionListContains("test1", "(property) test1: a1.connectModule", undefined); +verify.completionListContains("test1", "(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined); verify.completionListContains("test2", "(method) test2(): a1.connectModule", undefined); verify.not.completionListContains("connectModule"); verify.not.completionListContains("connectExport"); @@ -59,7 +59,7 @@ verify.quickInfoIs("(var) r2: a1.connectExport", undefined); goTo.marker('9'); verify.quickInfoIs("(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined); -verify.completionListContains("test1", "(property) test1: a1.connectModule", undefined); +verify.completionListContains("test1", "(property) test1: a1.connectModule(res: any, req: any, next: any) => void", undefined); verify.completionListContains("test2", "(method) test2(): a1.connectModule", undefined); verify.completionListContains("connectModule"); verify.completionListContains("connectExport"); From d327873d7b3b9ec248c5d65e9874d89cc4661a46 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 12:52:42 -0700 Subject: [PATCH 07/16] Fix issue #764, select the correct scope node if not left of a dot --- src/services/services.ts | 3 ++- .../fourslash/completionListAfterFunction.ts | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/completionListAfterFunction.ts diff --git a/src/services/services.ts b/src/services/services.ts index 77fa907956d..9b98b1a0eb3 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2529,7 +2529,8 @@ module ts { // we are at the end of a container node, we do not want to be inside it, as that would affect our completion results // e.g. function f(a) {}| <- 'a' should not be visible here - if (token && token.kind === SyntaxKind.CloseBraceToken && position === token.end) { + if (token && position === token.end && (token.kind === SyntaxKind.CloseBraceToken || token.kind === SyntaxKind.SemicolonToken)) { + node = getTokenAtPosition(sourceFile, position); } } diff --git a/tests/cases/fourslash/completionListAfterFunction.ts b/tests/cases/fourslash/completionListAfterFunction.ts new file mode 100644 index 00000000000..140c5e2e363 --- /dev/null +++ b/tests/cases/fourslash/completionListAfterFunction.ts @@ -0,0 +1,25 @@ +/// + +////// Outside the function +////declare function f1(a: number);/*1*/ +//// +////// inside the function +////declare function f2(b: number, b2 = /*2*/ +//// +////// Outside the function +////function f3(c: number) { }/*3*/ +//// +////// inside the function +////function f4(d: number) { /*4*/} + +goTo.marker("1"); +verify.not.completionListContains("a"); + +goTo.marker("2"); +verify.completionListContains("b"); + +goTo.marker("3"); +verify.not.completionListContains("c"); + +goTo.marker("4"); +verify.completionListContains("d"); From 48404452b825551a950c650852a369182a825d3f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 13:42:56 -0700 Subject: [PATCH 08/16] Cleanup completion list logic: - Do not walk the tree multiple times for the same session, instead pass along the previous token - Use current token if the this is not after a dot to avoid running into scoping issues - Also, add some documentation about different steps --- src/services/services.ts | 120 ++++++++++----------- tests/cases/fourslash/commentsOverloads.ts | 6 +- 2 files changed, 56 insertions(+), 70 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 36561dd8f85..7ba2b11c48c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2003,8 +2003,8 @@ module ts { } /** Returns true if the position is within a comment */ - function isInsideComment(sourceFile: SourceFile, position: number): boolean { - var token = getTokenAtPosition(sourceFile, position); + function isInsideComment(token: Node, position: number): boolean { + var sourceFile = token.getSourceFile(); // The position has to be: 1. in the leading trivia (before tokek.getStart()), and 2. within a comment return position <= token.getStart() && @@ -2348,48 +2348,38 @@ module ts { }); } - function isCompletionListBlocker(sourceFile: SourceFile, position: number): boolean { - // We shouldn't be getting a position that is outside the file because - // isEntirelyInsideComment can't handle when the position is out of bounds, - // callers should be fixed, however we should be resilient to bad inputs - // so we return true (this position is a blocker for getting completions) - if (position < 0 || position > sourceFile.end) { - return true; - } - - // This method uses Fidelity completely. Some information can be reached using the AST, but not everything. - return isInsideComment(sourceFile, position) || - isEntirelyInStringOrRegularExpressionLiteral(sourceFile, position) || - isIdentifierDefinitionLocation(sourceFile, position) || - isRightOfIllegalDot(sourceFile, position); + function isCompletionListBlocker(previousToken: Node): boolean { + return isInStringOrRegularExpressionLiteral(previousToken) || + isIdentifierDefinitionLocation(previousToken) || + isRightOfIllegalDot(previousToken); } - function isEntirelyInStringOrRegularExpressionLiteral(sourceFile: SourceFile, position: number): boolean { - var token = getTouchingPropertyName(sourceFile, position); + function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean { + //var token = getTouchingPropertyName(sourceFile, position); // || token.kind === SyntaxKind.RegularExpressionLiteral - if (token.kind === SyntaxKind.StringLiteral) { + if (previousToken.kind === SyntaxKind.StringLiteral) { // The position has to be either: 1. entirely within the token text, or // 2. at the end position, and the string literal is not terminated - var start = token.getStart(); - var end = token.getEnd(); + var start = previousToken.getStart(); + var end = previousToken.getEnd(); if (start < position && position < end) { return true; } else if (position === end) { var width = end - start; - return width <= 1 || sourceFile.text.charCodeAt(start) !== sourceFile.text.charCodeAt(end - 1); + var text = previousToken.getSourceFile().text; + return width <= 1 || text.charCodeAt(start) !== text.charCodeAt(end - 1); } } - else if (token.kind === SyntaxKind.RegularExpressionLiteral) { - return token.getStart() < position && position < token.getEnd(); + else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) { + return previousToken.getStart() < position && position < previousToken.getEnd(); } return false; } - function getContainingObjectLiteralApplicableForCompletion(sourceFile: SourceFile, position: number): ObjectLiteral { + function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteral { // The locations in an object literal expression that are applicable for completion are property name definition locations. - var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); if (previousToken) { var parent = previousToken.parent; @@ -2424,8 +2414,7 @@ module ts { return false; } - function isIdentifierDefinitionLocation(sourceFile: SourceFile, position: number): boolean { - var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); + function isIdentifierDefinitionLocation(previousToken: Node): boolean { if (previousToken) { var containingNodeKind = previousToken.parent.kind; switch (previousToken.kind) { @@ -2480,20 +2469,7 @@ module ts { return false; } - function getNonIdentifierCompleteTokenOnLeft(sourceFile: SourceFile, position: number): Node { - var previousToken = findTokenOnLeftOfPosition(sourceFile, position); - - if (previousToken && position <= previousToken.end && previousToken.kind === SyntaxKind.Identifier) { - // The caret is at the end of an identifier, the decision to provide completion depends on the previous token - previousToken = findPrecedingToken(previousToken.pos, sourceFile); - } - - return previousToken; - } - - function isRightOfIllegalDot(sourceFile: SourceFile, position: number): boolean { - var previousToken = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); - + function isRightOfIllegalDot(previousToken: Node): boolean { if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) { var text = previousToken.getFullText(); return text.charAt(text.length - 1) === "."; @@ -2538,33 +2514,45 @@ module ts { var sourceFile = getSourceFile(filename); - if (isCompletionListBlocker(sourceFile, position)) { + var currentToken = getTokenAtPosition(sourceFile, position); + + // Completion not allowed inside comments, bail out if this is the case + if (isInsideComment(currentToken, position)) { host.log("Returning an empty list because completion was blocked."); - return null; + return undefined; } - var node: Node; - var location: Node; - var isRightOfDot: boolean; - var token = getNonIdentifierCompleteTokenOnLeft(sourceFile, position); + // The decision to provide completion depends on the previous token, so find it + // Note: previousToken can be undefined if we are the beginning of the file + var previousToken = findPrecedingToken(position, sourceFile); - if (token && token.kind === SyntaxKind.DotToken && - (token.parent.kind === SyntaxKind.PropertyAccess || token.parent.kind === SyntaxKind.QualifiedName)) { - node = (token.parent).left; + // The caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS| + // Skip this partial identifier to the previous token + if (previousToken && position <= previousToken.end && previousToken.kind === SyntaxKind.Identifier) { + previousToken = findPrecedingToken(previousToken.pos, sourceFile); + } + + // Check if this is a valid completion location + if (previousToken && isCompletionListBlocker(previousToken)) { + host.log("Returning an empty list because completion was blocked."); + return undefined; + } + + // Find the node where completion is requested on, in the case of a completion after a dot, it is the member access expression + // other wise, it is a request for all visible symbols in the scope, and the node is the current location + var node: Node; + var isRightOfDot: boolean; + if (previousToken && previousToken.kind === SyntaxKind.DotToken && + (previousToken.parent.kind === SyntaxKind.PropertyAccess || previousToken.parent.kind === SyntaxKind.QualifiedName)) { + node = (previousToken.parent).left; isRightOfDot = true; } else { - node = !token ? sourceFile : token.parent; + node = currentToken; isRightOfDot = false; - - // we are at the end of a container node, we do not want to be inside it, as that would affect our completion results - // e.g. function f(a) {}| <- 'a' should not be visible here - if (token && position === token.end && (token.kind === SyntaxKind.CloseBraceToken || token.kind === SyntaxKind.SemicolonToken)) { - node = getTokenAtPosition(sourceFile, position); - } } - // Get the completions + // Clear the current activeCompletionSession for this session activeCompletionSession = { filename: filename, position: position, @@ -2573,8 +2561,9 @@ module ts { typeChecker: typeInfoResolver }; - // Right of dot member completion list + // Populate the completion list if (isRightOfDot) { + // Right of dot member completion list var symbols: Symbol[] = []; isMemberCompletion = true; @@ -2609,10 +2598,9 @@ module ts { getCompletionEntriesFromSymbols(symbols, activeCompletionSession); } else { - var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(sourceFile, position); - - // Object literal expression, look up possible property names from contextual type + var containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(previousToken); if (containingObjectLiteral) { + // Object literal expression, look up possible property names from contextual type isMemberCompletion = true; var contextualType = typeInfoResolver.getContextualType(containingObjectLiteral); @@ -2627,9 +2615,10 @@ module ts { getCompletionEntriesFromSymbols(filteredMembers, activeCompletionSession); } } - // Get scope members else { + // Get scope members isMemberCompletion = false; + /// TODO filter meaning based on the current context var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Import; var symbols = typeInfoResolver.getSymbolsInScope(node, symbolMeanings); @@ -5150,7 +5139,8 @@ module ts { // OK, we have found a match in the file. This is only an acceptable match if // it is contained within a comment. - if (!isInsideComment(sourceFile, matchPosition)) { + var token = getTokenAtPosition(sourceFile, matchPosition); + if (!isInsideComment(token, matchPosition)) { continue; } diff --git a/tests/cases/fourslash/commentsOverloads.ts b/tests/cases/fourslash/commentsOverloads.ts index 3976fdeae4a..1e85346a17a 100644 --- a/tests/cases/fourslash/commentsOverloads.ts +++ b/tests/cases/fourslash/commentsOverloads.ts @@ -594,11 +594,7 @@ goTo.marker('64q'); verify.quickInfoIs("(constructor) c5(b: string): c5 (+1 overload)", "c5 2"); goTo.marker('65'); -//verify.completionListContains("c", "class c", ""); -// the below check is wrong and it should show it as class but currently we have a bug for adding the parameters of ambient function in the symbol list -// eg declare function foo2(x: number); -// completion list here -verify.completionListContains("c", "(parameter) c: boolean", ""); +verify.completionListContains("c", "class c", ""); verify.completionListContains("c1", "class c1", ""); verify.completionListContains("c2", "class c2", ""); verify.completionListContains("c3", "class c3", ""); From 3c32fcc8df4de513b4e3a387e539fca11c56a6d5 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 13:44:10 -0700 Subject: [PATCH 09/16] Move helpers to the bottom of the function --- src/services/services.ts | 340 +++++++++++++++++++-------------------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 7ba2b11c48c..cf04ba101b6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2338,176 +2338,6 @@ module ts { } function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) { - function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { - forEach(symbols, symbol => { - var entry = createCompletionEntry(symbol, session.typeChecker); - if (entry && !lookUp(session.symbols, entry.name)) { - session.entries.push(entry); - session.symbols[entry.name] = symbol; - } - }); - } - - function isCompletionListBlocker(previousToken: Node): boolean { - return isInStringOrRegularExpressionLiteral(previousToken) || - isIdentifierDefinitionLocation(previousToken) || - isRightOfIllegalDot(previousToken); - } - - function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean { - //var token = getTouchingPropertyName(sourceFile, position); - - // || token.kind === SyntaxKind.RegularExpressionLiteral - if (previousToken.kind === SyntaxKind.StringLiteral) { - // The position has to be either: 1. entirely within the token text, or - // 2. at the end position, and the string literal is not terminated - var start = previousToken.getStart(); - var end = previousToken.getEnd(); - if (start < position && position < end) { - return true; - } - else if (position === end) { - var width = end - start; - var text = previousToken.getSourceFile().text; - return width <= 1 || text.charCodeAt(start) !== text.charCodeAt(end - 1); - } - } - else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) { - return previousToken.getStart() < position && position < previousToken.getEnd(); - } - return false; - } - - function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteral { - // The locations in an object literal expression that are applicable for completion are property name definition locations. - - if (previousToken) { - var parent = previousToken.parent; - - switch (previousToken.kind) { - case SyntaxKind.OpenBraceToken: // var x = { | - case SyntaxKind.CommaToken: // var x = { a: 0, | - if (parent && parent.kind === SyntaxKind.ObjectLiteral) { - return parent; - } - break; - } - } - - return undefined; - } - - function isFunction(kind: SyntaxKind): boolean { - switch (kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.Method: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.CallSignature: - case SyntaxKind.ConstructSignature: - case SyntaxKind.IndexSignature: - return true; - } - return false; - } - - function isIdentifierDefinitionLocation(previousToken: Node): boolean { - if (previousToken) { - var containingNodeKind = previousToken.parent.kind; - switch (previousToken.kind) { - case SyntaxKind.CommaToken: - return containingNodeKind === SyntaxKind.VariableDeclaration || - containingNodeKind === SyntaxKind.VariableStatement || - containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | - isFunction(containingNodeKind); - - case SyntaxKind.OpenParenToken: - return containingNodeKind === SyntaxKind.CatchBlock || - isFunction(containingNodeKind); - - case SyntaxKind.OpenBraceToken: - return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { | - containingNodeKind === SyntaxKind.InterfaceDeclaration; // interface a { | - - case SyntaxKind.SemicolonToken: - return containingNodeKind === SyntaxKind.Property && - previousToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration; // interface a { f; | - - case SyntaxKind.PublicKeyword: - case SyntaxKind.PrivateKeyword: - case SyntaxKind.StaticKeyword: - case SyntaxKind.DotDotDotToken: - return containingNodeKind === SyntaxKind.Parameter; - - case SyntaxKind.ClassKeyword: - case SyntaxKind.ModuleKeyword: - case SyntaxKind.EnumKeyword: - case SyntaxKind.InterfaceKeyword: - case SyntaxKind.FunctionKeyword: - case SyntaxKind.VarKeyword: - case SyntaxKind.GetKeyword: - case SyntaxKind.SetKeyword: - return true; - } - - // Previous token may have been a keyword that was converted to an identifier. - switch (previousToken.getText()) { - case "class": - case "interface": - case "enum": - case "module": - case "function": - case "var": - // TODO: add let and const - return true; - } - } - - return false; - } - - function isRightOfIllegalDot(previousToken: Node): boolean { - if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) { - var text = previousToken.getFullText(); - return text.charAt(text.length - 1) === "."; - } - - return false; - } - - function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] { - if (!existingMembers || existingMembers.length === 0) { - return contextualMemberSymbols; - } - - var existingMemberNames: Map = {}; - forEach(existingMembers, m => { - if (m.kind !== SyntaxKind.PropertyAssignment) { - // Ignore omitted expressions for missing members in the object literal - return; - } - - if (m.getStart() <= position && position <= m.getEnd()) { - // If this is the current item we are editing right now, do not filter it out - return; - } - - existingMemberNames[m.name.text] = true; - }); - - var filteredMembers: Symbol[] = []; - forEach(contextualMemberSymbols, s => { - if (!existingMemberNames[s.name]) { - filteredMembers.push(s); - } - }); - - return filteredMembers; - } - synchronizeHostData(); filename = TypeScript.switchToForwardSlashes(filename); @@ -2636,6 +2466,176 @@ module ts { isMemberCompletion: isMemberCompletion, entries: activeCompletionSession.entries }; + + function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void { + forEach(symbols, symbol => { + var entry = createCompletionEntry(symbol, session.typeChecker); + if (entry && !lookUp(session.symbols, entry.name)) { + session.entries.push(entry); + session.symbols[entry.name] = symbol; + } + }); + } + + function isCompletionListBlocker(previousToken: Node): boolean { + return isInStringOrRegularExpressionLiteral(previousToken) || + isIdentifierDefinitionLocation(previousToken) || + isRightOfIllegalDot(previousToken); + } + + function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean { + //var token = getTouchingPropertyName(sourceFile, position); + + // || token.kind === SyntaxKind.RegularExpressionLiteral + if (previousToken.kind === SyntaxKind.StringLiteral) { + // The position has to be either: 1. entirely within the token text, or + // 2. at the end position, and the string literal is not terminated + var start = previousToken.getStart(); + var end = previousToken.getEnd(); + if (start < position && position < end) { + return true; + } + else if (position === end) { + var width = end - start; + var text = previousToken.getSourceFile().text; + return width <= 1 || text.charCodeAt(start) !== text.charCodeAt(end - 1); + } + } + else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) { + return previousToken.getStart() < position && position < previousToken.getEnd(); + } + return false; + } + + function getContainingObjectLiteralApplicableForCompletion(previousToken: Node): ObjectLiteral { + // The locations in an object literal expression that are applicable for completion are property name definition locations. + + if (previousToken) { + var parent = previousToken.parent; + + switch (previousToken.kind) { + case SyntaxKind.OpenBraceToken: // var x = { | + case SyntaxKind.CommaToken: // var x = { a: 0, | + if (parent && parent.kind === SyntaxKind.ObjectLiteral) { + return parent; + } + break; + } + } + + return undefined; + } + + function isFunction(kind: SyntaxKind): boolean { + switch (kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.CallSignature: + case SyntaxKind.ConstructSignature: + case SyntaxKind.IndexSignature: + return true; + } + return false; + } + + function isIdentifierDefinitionLocation(previousToken: Node): boolean { + if (previousToken) { + var containingNodeKind = previousToken.parent.kind; + switch (previousToken.kind) { + case SyntaxKind.CommaToken: + return containingNodeKind === SyntaxKind.VariableDeclaration || + containingNodeKind === SyntaxKind.VariableStatement || + containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, | + isFunction(containingNodeKind); + + case SyntaxKind.OpenParenToken: + return containingNodeKind === SyntaxKind.CatchBlock || + isFunction(containingNodeKind); + + case SyntaxKind.OpenBraceToken: + return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { | + containingNodeKind === SyntaxKind.InterfaceDeclaration; // interface a { | + + case SyntaxKind.SemicolonToken: + return containingNodeKind === SyntaxKind.Property && + previousToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration; // interface a { f; | + + case SyntaxKind.PublicKeyword: + case SyntaxKind.PrivateKeyword: + case SyntaxKind.StaticKeyword: + case SyntaxKind.DotDotDotToken: + return containingNodeKind === SyntaxKind.Parameter; + + case SyntaxKind.ClassKeyword: + case SyntaxKind.ModuleKeyword: + case SyntaxKind.EnumKeyword: + case SyntaxKind.InterfaceKeyword: + case SyntaxKind.FunctionKeyword: + case SyntaxKind.VarKeyword: + case SyntaxKind.GetKeyword: + case SyntaxKind.SetKeyword: + return true; + } + + // Previous token may have been a keyword that was converted to an identifier. + switch (previousToken.getText()) { + case "class": + case "interface": + case "enum": + case "module": + case "function": + case "var": + // TODO: add let and const + return true; + } + } + + return false; + } + + function isRightOfIllegalDot(previousToken: Node): boolean { + if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) { + var text = previousToken.getFullText(); + return text.charAt(text.length - 1) === "."; + } + + return false; + } + + function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] { + if (!existingMembers || existingMembers.length === 0) { + return contextualMemberSymbols; + } + + var existingMemberNames: Map = {}; + forEach(existingMembers, m => { + if (m.kind !== SyntaxKind.PropertyAssignment) { + // Ignore omitted expressions for missing members in the object literal + return; + } + + if (m.getStart() <= position && position <= m.getEnd()) { + // If this is the current item we are editing right now, do not filter it out + return; + } + + existingMemberNames[m.name.text] = true; + }); + + var filteredMembers: Symbol[] = []; + forEach(contextualMemberSymbols, s => { + if (!existingMemberNames[s.name]) { + filteredMembers.push(s); + } + }); + + return filteredMembers; + } } function getCompletionEntryDetails(filename: string, position: number, entryName: string): CompletionEntryDetails { From b6f4aa9da9052ee77091c5d07a8f87de2b0ebc4c Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Thu, 23 Oct 2014 14:08:04 -0700 Subject: [PATCH 10/16] Fix wrong condition for unterminated multi-line comments --- src/services/services.ts | 6 +++--- tests/cases/fourslash/completionListInComments3.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index cf04ba101b6..3584e016227 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2025,9 +2025,9 @@ module ts { return true; } else { - // is unterminated multiline comment - return text.charCodeAt(comment.end - 1) !== CharacterCodes.slash && - text.charCodeAt(comment.end - 2) !== CharacterCodes.asterisk; + // is unterminated multi-line comment + return !(text.charCodeAt(comment.end - 1) === CharacterCodes.slash && + text.charCodeAt(comment.end - 2) === CharacterCodes.asterisk); } } return false; diff --git a/tests/cases/fourslash/completionListInComments3.ts b/tests/cases/fourslash/completionListInComments3.ts index 3f57929c1f4..2f20a969ba1 100644 --- a/tests/cases/fourslash/completionListInComments3.ts +++ b/tests/cases/fourslash/completionListInComments3.ts @@ -10,6 +10,8 @@ //// {| "name": "5" |}/* */ +/////* {| "name": "6" |} + goTo.marker("1"); verify.completionListIsEmpty(); @@ -22,5 +24,8 @@ verify.completionListIsEmpty(); goTo.marker("4"); verify.not.completionListIsEmpty(); -//goTo.marker("5"); -//verify.not.completionListIsEmpty(); +goTo.marker("5"); +verify.not.completionListIsEmpty(); + +goTo.marker("6"); +verify.completionListIsEmpty(); From f3b1e94d6879f6ddb810aee53eb8007f9cc187f2 Mon Sep 17 00:00:00 2001 From: Jed Mao Date: Sat, 25 Oct 2014 01:27:02 -0500 Subject: [PATCH 11/16] Introduce .editorconfig file --- .editorconfig | 16 ++++++++++ package.json | 88 +++++++++++++++++++++++++-------------------------- 2 files changed, 60 insertions(+), 44 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..0879f3c6c7d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.json] +indent_size = 2 + +[*.yml] +indent_size = 2 diff --git a/package.json b/package.json index 00752302254..535a666a4f9 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,46 @@ { - "name": "typescript", - "author": "Microsoft Corp.", - "homepage": "http://typescriptlang.org/", - "version": "1.3.0", - "licenses": [ - { - "type": "Apache License 2.0", - "url": "https://github.com/Microsoft/TypeScript/blob/master/LICENSE.txt" - } - ], - "description": "TypeScript is a language for application scale JavaScript development", - "keywords": [ - "TypeScript", - "Microsoft", - "compiler", - "language", - "javascript" - ], - "bugs": { - "url" : "https://github.com/Microsoft/TypeScript/issues" - }, - "repository" : { - "type" : "git", - "url" : "https://github.com/Microsoft/TypeScript.git" - }, - "preferGlobal" : true, - "main" : "./bin/tsc.js", - "bin" : { - "tsc" : "./bin/tsc" - }, - "engines" : { - "node" : ">=0.8.0" - }, - "devDependencies": { - "jake" : "latest", - "mocha" : "latest", - "chai" : "latest", - "browserify" : "latest", - "istanbul": "latest", - "codeclimate-test-reporter": "latest" - }, - "scripts": { - "test": "jake generate-code-coverage" - } + "name": "typescript", + "author": "Microsoft Corp.", + "homepage": "http://typescriptlang.org/", + "version": "1.3.0", + "licenses": [ + { + "type": "Apache License 2.0", + "url": "https://github.com/Microsoft/TypeScript/blob/master/LICENSE.txt" + } + ], + "description": "TypeScript is a language for application scale JavaScript development", + "keywords": [ + "TypeScript", + "Microsoft", + "compiler", + "language", + "javascript" + ], + "bugs": { + "url": "https://github.com/Microsoft/TypeScript/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/Microsoft/TypeScript.git" + }, + "preferGlobal": true, + "main": "./bin/tsc.js", + "bin": { + "tsc": "./bin/tsc" + }, + "engines": { + "node": ">=0.8.0" + }, + "devDependencies": { + "browserify": "latest", + "chai": "latest", + "codeclimate-test-reporter": "latest", + "istanbul": "latest", + "jake": "latest", + "mocha": "latest" + }, + "scripts": { + "test": "jake generate-code-coverage" + } } From 218064d8b4a8d1ea4fad00ff339e13318c8ee627 Mon Sep 17 00:00:00 2001 From: Jed Mao Date: Sat, 25 Oct 2014 01:34:08 -0500 Subject: [PATCH 12/16] Introduce .gitattributes file --- .gitattributes | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..e186d4ff06b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain From 962c4de875640f0dd0716687f12b0aa59fbbbabb Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Mon, 27 Oct 2014 15:30:38 -0700 Subject: [PATCH 13/16] Address code review comments --- src/services/services.ts | 9 ++++----- .../cases/fourslash/completionListAfterFunction2.ts | 13 +++++++++++++ .../cases/fourslash/completionListAfterFunction3.ts | 12 ++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 tests/cases/fourslash/completionListAfterFunction2.ts create mode 100644 tests/cases/fourslash/completionListAfterFunction3.ts diff --git a/src/services/services.ts b/src/services/services.ts index 3584e016227..9270a3115dc 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2021,7 +2021,7 @@ module ts { var text = sourceFile.text; var width = comment.end - comment.pos; // is single line comment or just /* - if (width <=2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) { + if (width <= 2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) { return true; } else { @@ -2484,9 +2484,6 @@ module ts { } function isInStringOrRegularExpressionLiteral(previousToken: Node): boolean { - //var token = getTouchingPropertyName(sourceFile, position); - - // || token.kind === SyntaxKind.RegularExpressionLiteral if (previousToken.kind === SyntaxKind.StringLiteral) { // The position has to be either: 1. entirely within the token text, or // 2. at the end position, and the string literal is not terminated @@ -2498,7 +2495,9 @@ module ts { else if (position === end) { var width = end - start; var text = previousToken.getSourceFile().text; - return width <= 1 || text.charCodeAt(start) !== text.charCodeAt(end - 1); + return width <= 1 || + text.charCodeAt(start) !== text.charCodeAt(end - 1) || + text.charCodeAt(end - 2) === CharacterCodes.backslash; } } else if (previousToken.kind === SyntaxKind.RegularExpressionLiteral) { diff --git a/tests/cases/fourslash/completionListAfterFunction2.ts b/tests/cases/fourslash/completionListAfterFunction2.ts new file mode 100644 index 00000000000..c123e084972 --- /dev/null +++ b/tests/cases/fourslash/completionListAfterFunction2.ts @@ -0,0 +1,13 @@ +/// + +////// Outside the function expression +////declare var f1: (a: number) => void; /*1*/ +//// +////declare var f1: (b: number, b2: /*2*/) => void; + +goTo.marker("1"); +verify.not.completionListContains("a"); + +goTo.marker("2"); +verify.completionListContains("b"); + diff --git a/tests/cases/fourslash/completionListAfterFunction3.ts b/tests/cases/fourslash/completionListAfterFunction3.ts new file mode 100644 index 00000000000..575351ea648 --- /dev/null +++ b/tests/cases/fourslash/completionListAfterFunction3.ts @@ -0,0 +1,12 @@ +/// + +////// Outside the function expression +////var x1 = (a: number) => { }/*1*/; +//// +////var x2 = (b: number) => {/*2*/ }; + +goTo.marker("1"); +verify.not.completionListContains("a"); + +goTo.marker("2"); +verify.completionListContains("b"); From d6ac176be976d7869622002cf146454410ad3936 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 28 Oct 2014 09:09:46 -0700 Subject: [PATCH 14/16] Respond to code review comments --- src/services/services.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 19d602b55d7..7a6a810b305 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2019,17 +2019,15 @@ module ts { } /** Returns true if the position is within a comment */ - function isInsideComment(token: Node, position: number): boolean { - var sourceFile = token.getSourceFile(); - - // The position has to be: 1. in the leading trivia (before tokek.getStart()), and 2. within a comment - return position <= token.getStart() && + function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean { + // The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment + return position <= token.getStart(sourceFile) && (isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) || isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart()))); function isInsideCommentRange(comments: CommentRange[]): boolean { return forEach(comments, comment => { - // either we are 1. completely inside the comment, or 2. at the end of + // either we are 1. completely inside the comment, or 2. at the end of the comment if (comment.pos < position && position < comment.end) { return true; } @@ -2363,8 +2361,8 @@ module ts { var currentToken = getTokenAtPosition(sourceFile, position); // Completion not allowed inside comments, bail out if this is the case - if (isInsideComment(currentToken, position)) { - host.log("Returning an empty list because completion was blocked."); + if (isInsideComment(sourceFile, currentToken, position)) { + host.log("Returning an empty list because completion was inside a comment."); return undefined; } @@ -2380,7 +2378,7 @@ module ts { // Check if this is a valid completion location if (previousToken && isCompletionListBlocker(previousToken)) { - host.log("Returning an empty list because completion was blocked."); + host.log("Returning an empty list because completion was requested in an invalid position."); return undefined; } @@ -5157,7 +5155,7 @@ module ts { // OK, we have found a match in the file. This is only an acceptable match if // it is contained within a comment. var token = getTokenAtPosition(sourceFile, matchPosition); - if (!isInsideComment(token, matchPosition)) { + if (!isInsideComment(sourceFile, token, matchPosition)) { continue; } From f3526bd2c494c7e691594b88a01de3a1b93b0cc4 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 28 Oct 2014 12:11:52 -0700 Subject: [PATCH 15/16] Revert "Introduce .editorconfig file" This reverts commit f3b1e94d6879f6ddb810aee53eb8007f9cc187f2. --- .editorconfig | 16 ---------- package.json | 88 +++++++++++++++++++++++++-------------------------- 2 files changed, 44 insertions(+), 60 deletions(-) delete mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 0879f3c6c7d..00000000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -# http://editorconfig.org - -# top-most EditorConfig file -root = true - -[*] -indent_style = space -indent_size = 4 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.json] -indent_size = 2 - -[*.yml] -indent_size = 2 diff --git a/package.json b/package.json index 535a666a4f9..00752302254 100644 --- a/package.json +++ b/package.json @@ -1,46 +1,46 @@ { - "name": "typescript", - "author": "Microsoft Corp.", - "homepage": "http://typescriptlang.org/", - "version": "1.3.0", - "licenses": [ - { - "type": "Apache License 2.0", - "url": "https://github.com/Microsoft/TypeScript/blob/master/LICENSE.txt" - } - ], - "description": "TypeScript is a language for application scale JavaScript development", - "keywords": [ - "TypeScript", - "Microsoft", - "compiler", - "language", - "javascript" - ], - "bugs": { - "url": "https://github.com/Microsoft/TypeScript/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/Microsoft/TypeScript.git" - }, - "preferGlobal": true, - "main": "./bin/tsc.js", - "bin": { - "tsc": "./bin/tsc" - }, - "engines": { - "node": ">=0.8.0" - }, - "devDependencies": { - "browserify": "latest", - "chai": "latest", - "codeclimate-test-reporter": "latest", - "istanbul": "latest", - "jake": "latest", - "mocha": "latest" - }, - "scripts": { - "test": "jake generate-code-coverage" - } + "name": "typescript", + "author": "Microsoft Corp.", + "homepage": "http://typescriptlang.org/", + "version": "1.3.0", + "licenses": [ + { + "type": "Apache License 2.0", + "url": "https://github.com/Microsoft/TypeScript/blob/master/LICENSE.txt" + } + ], + "description": "TypeScript is a language for application scale JavaScript development", + "keywords": [ + "TypeScript", + "Microsoft", + "compiler", + "language", + "javascript" + ], + "bugs": { + "url" : "https://github.com/Microsoft/TypeScript/issues" + }, + "repository" : { + "type" : "git", + "url" : "https://github.com/Microsoft/TypeScript.git" + }, + "preferGlobal" : true, + "main" : "./bin/tsc.js", + "bin" : { + "tsc" : "./bin/tsc" + }, + "engines" : { + "node" : ">=0.8.0" + }, + "devDependencies": { + "jake" : "latest", + "mocha" : "latest", + "chai" : "latest", + "browserify" : "latest", + "istanbul": "latest", + "codeclimate-test-reporter": "latest" + }, + "scripts": { + "test": "jake generate-code-coverage" + } } From e179e0565cfb90c30dc219e49599547948bb2e10 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 28 Oct 2014 12:12:18 -0700 Subject: [PATCH 16/16] Revert "Introduce .gitattributes file" This reverts commit 218064d8b4a8d1ea4fad00ff339e13318c8ee627. --- .gitattributes | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index e186d4ff06b..00000000000 --- a/.gitattributes +++ /dev/null @@ -1,14 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto - -# Standard to msysgit -*.doc diff=astextplain -*.DOC diff=astextplain -*.docx diff=astextplain -*.DOCX diff=astextplain -*.dot diff=astextplain -*.DOT diff=astextplain -*.pdf diff=astextplain -*.PDF diff=astextplain -*.rtf diff=astextplain -*.RTF diff=astextplain