diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c96b2edc5b1..7a64733a88a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3468,29 +3468,6 @@ module ts { return getTypeOfSymbol(getExportSymbolOfValueSymbolIfExported(symbol)); } - function getThisContainer(node: Node): Node { - while (true) { - node = node.parent; - if (!node) { - return node; - } - switch (node.kind) { - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ModuleDeclaration: - case SyntaxKind.Property: - case SyntaxKind.Method: - case SyntaxKind.Constructor: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.SourceFile: - case SyntaxKind.ArrowFunction: - return node; - } - } - } - function captureLexicalThis(node: Node, container: Node): void { var classNode = container.parent && container.parent.kind === SyntaxKind.ClassDeclaration ? container.parent : undefined; getNodeLinks(node).flags |= NodeCheckFlags.LexicalThis; @@ -3503,11 +3480,14 @@ module ts { } function checkThisExpression(node: Node): Type { - var container = getThisContainer(node); + // Stop at the first arrow function so that we can + // tell whether 'this' needs to be captured. + var container = getThisContainer(node, /* includeArrowFunctions */ true); var needToCaptureLexicalThis = false; - // skip arrow functions - while (container.kind === SyntaxKind.ArrowFunction) { - container = getThisContainer(container); + + // Now skip arrow functions to get the "real" owner of 'this'. + if (container.kind === SyntaxKind.ArrowFunction) { + container = getThisContainer(container, /* includeArrowFunctions */ false); needToCaptureLexicalThis = true; } @@ -4407,37 +4387,6 @@ module ts { return voidType; } - // WARNING: This has the same semantics as the forEach family of functions, - // in that traversal terminates in the event that 'visitor' supplies a truthy value. - function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { - - return traverse(body); - - function traverse(node: Node): T { - switch (node.kind) { - case SyntaxKind.ReturnStatement: - return visitor(node); - case SyntaxKind.Block: - case SyntaxKind.FunctionBlock: - case SyntaxKind.IfStatement: - case SyntaxKind.DoStatement: - case SyntaxKind.WhileStatement: - case SyntaxKind.ForStatement: - case SyntaxKind.ForInStatement: - case SyntaxKind.WithStatement: - case SyntaxKind.SwitchStatement: - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - case SyntaxKind.LabelledStatement: - case SyntaxKind.TryStatement: - case SyntaxKind.TryBlock: - case SyntaxKind.CatchBlock: - case SyntaxKind.FinallyBlock: - return forEachChild(node, traverse); - } - } - } - /// Returns a set of types relating to every return expression relating to a function block. function checkAndAggregateReturnExpressionTypes(body: Block, contextualMapper?: TypeMapper): Type[] { var aggregatedTypes: Type[] = []; @@ -5856,17 +5805,6 @@ module ts { // TODO: Check that target label is valid } - function getContainingFunction(node: Node): SignatureDeclaration { - while (true) { - node = node.parent; - if (!node || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression || - node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.Method || node.kind === SyntaxKind.Constructor || - node.kind === SyntaxKind.GetAccessor || node.kind === SyntaxKind.SetAccessor) { - return node; - } - } - } - function checkReturnStatement(node: ReturnStatement) { if (node.expression && !(getNodeLinks(node.expression).flags & NodeCheckFlags.TypeChecked)) { var func = getContainingFunction(node); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index cfe27e7e7c3..dde11576817 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -350,6 +350,107 @@ module ts { } } + // Warning: This has the same semantics as the forEach family of functions, + // in that traversal terminates in the event that 'visitor' supplies a truthy value. + export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { + + return traverse(body); + + function traverse(node: Node): T { + switch (node.kind) { + case SyntaxKind.ReturnStatement: + return visitor(node); + case SyntaxKind.Block: + case SyntaxKind.FunctionBlock: + case SyntaxKind.IfStatement: + case SyntaxKind.DoStatement: + case SyntaxKind.WhileStatement: + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.WithStatement: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + case SyntaxKind.LabelledStatement: + case SyntaxKind.TryStatement: + case SyntaxKind.TryBlock: + case SyntaxKind.CatchBlock: + case SyntaxKind.FinallyBlock: + return forEachChild(node, traverse); + } + } + } + + export function isAnyFunction(node: Node): boolean { + if (node) { + switch (node.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ArrowFunction: + case SyntaxKind.Method: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + return true; + } + } + + return false; + } + + export function getContainingFunction(node: Node): SignatureDeclaration { + while (true) { + node = node.parent; + if (!node || isAnyFunction(node)) { + return node; + } + } + } + + export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.ArrowFunction: + if (!includeArrowFunctions) { + continue; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ModuleDeclaration: + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.SourceFile: + return node; + } + } + } + + export function getSuperContainer(node: Node): Node { + while (true) { + node = node.parent; + if (!node) { + return undefined; + } + switch (node.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + return node; + } + } + } + export function hasRestParameters(s: SignatureDeclaration): boolean { return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c13b47a066c..715d01926f0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -220,7 +220,7 @@ module ts { LastFutureReservedWord = YieldKeyword, FirstTypeNode = TypeReference, LastTypeNode = ArrayType, - FirstPunctuation= OpenBraceToken, + FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken } diff --git a/src/services/services.ts b/src/services/services.ts index 0069f53922d..d51eeee97c0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1312,20 +1312,6 @@ module ts { return node.parent.kind === SyntaxKind.NewExpression && (node.parent).func === node; } - function isAnyFunction(node: Node): boolean { - switch (node.kind) { - case SyntaxKind.FunctionExpression: - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.ArrowFunction: - case SyntaxKind.Method: - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.Constructor: - return true; - } - return false; - } - function isNameOfFunctionDeclaration(node: Node): boolean { return node.kind === SyntaxKind.Identifier && isAnyFunction(node.parent) && (node.parent).name === node; @@ -2148,7 +2134,6 @@ module ts { return result; } - /// Find references function getOccurrencesAtPosition(filename: string, position: number): ReferenceEntry[] { synchronizeHostData(); @@ -2160,11 +2145,23 @@ module ts { return undefined; } - if (node.kind === SyntaxKind.Identifier || isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { + if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || isNameOfExternalModuleImportOrDeclaration(node)) { return getReferencesForNode(node, [sourceFile]); } switch (node.kind) { + case SyntaxKind.IfKeyword: + case SyntaxKind.ElseKeyword: + if (hasKind(node.parent, SyntaxKind.IfStatement)) { + return getIfElseOccurrences(node.parent); + } + break; + case SyntaxKind.ReturnKeyword: + if (hasKind(node.parent, SyntaxKind.ReturnStatement)) { + return getReturnOccurrences(node.parent); + } + break; case SyntaxKind.TryKeyword: case SyntaxKind.CatchKeyword: case SyntaxKind.FinallyKeyword: @@ -2188,10 +2185,91 @@ module ts { return getBreakStatementOccurences(node.parent); } break; + case SyntaxKind.ConstructorKeyword: + if (hasKind(node.parent, SyntaxKind.Constructor)) { + return getConstructorOccurrences(node.parent); + } + break; } return undefined; + function getIfElseOccurrences(ifStatement: IfStatement): ReferenceEntry[] { + var keywords: Node[] = []; + + // Traverse upwards through all parent if-statements linked by their else-branches. + while (hasKind(ifStatement.parent, SyntaxKind.IfStatement) && (ifStatement.parent).elseStatement === ifStatement) { + ifStatement = ifStatement.parent; + } + + // Now traverse back down through the else branches, aggregating if/else keywords of if-statements. + while (ifStatement) { + var children = ifStatement.getChildren(); + pushKeywordIf(keywords, children[0], SyntaxKind.IfKeyword); + + // Generally the 'else' keyword is second-to-last, so we traverse backwards. + for (var i = children.length - 1; i >= 0; i--) { + if (pushKeywordIf(keywords, children[i], SyntaxKind.ElseKeyword)) { + break; + } + } + + if (!hasKind(ifStatement.elseStatement, SyntaxKind.IfStatement)) { + break + } + + ifStatement = ifStatement.elseStatement; + } + + var result: ReferenceEntry[] = []; + + // We'd like to highlight else/ifs together if they are only separated by whitespace + // (i.e. the keywords are separated by no comments, no newlines). + for (var i = 0; i < keywords.length; i++) { + if (keywords[i].kind === SyntaxKind.ElseKeyword && i < keywords.length - 1) { + var elseKeyword = keywords[i]; + var ifKeyword = keywords[i + 1]; // this *should* always be an 'if' keyword. + + var shouldHighlightNextKeyword = true; + + // Avoid recalculating getStart() by iterating backwards. + for (var j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) { + if (!isWhiteSpace(sourceFile.text.charCodeAt(j))) { + shouldHighlightNextKeyword = false; + break; + } + } + + if (shouldHighlightNextKeyword) { + result.push(new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(elseKeyword.getStart(), ifKeyword.end), /* isWriteAccess */ false)); + i++; // skip the next keyword + continue; + } + } + + // Ordinary case: just highlight the keyword. + result.push(getReferenceEntryFromNode(keywords[i])); + } + + return result; + } + + function getReturnOccurrences(returnStatement: ReturnStatement): ReferenceEntry[] { + var func = getContainingFunction(returnStatement); + + // If we didn't find a containing function with a block body, bail out. + if (!(func && hasKind(func.body, SyntaxKind.FunctionBlock))) { + return undefined; + } + + var keywords: Node[] = [] + forEachReturnStatement((func).body, returnStatement => { + pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword); + }); + + return map(keywords, getReferenceEntryFromNode); + } + function getTryCatchFinallyOccurrences(tryStatement: TryStatement): ReferenceEntry[] { var keywords: Node[] = []; @@ -2205,7 +2283,7 @@ module ts { pushKeywordIf(keywords, tryStatement.finallyBlock.getFirstToken(), SyntaxKind.FinallyKeyword); } - return keywordsToReferenceEntries(keywords); + return map(keywords, getReferenceEntryFromNode); } function getSwitchCaseDefaultOccurrences(switchStatement: SwitchStatement) { @@ -2241,10 +2319,10 @@ module ts { }); }); - return keywordsToReferenceEntries(keywords); + return map(keywords, getReferenceEntryFromNode); } - function getBreakStatementOccurences(breakStatement: BreakOrContinueStatement): ReferenceEntry[]{ + function getBreakStatementOccurences(breakStatement: BreakOrContinueStatement): ReferenceEntry[] { // TODO (drosen): Deal with labeled statements. if (breakStatement.label) { return undefined; @@ -2272,6 +2350,20 @@ module ts { return undefined; } + function getConstructorOccurrences(constructorDeclaration: ConstructorDeclaration): ReferenceEntry[] { + var declarations = constructorDeclaration.symbol.getDeclarations() + + var keywords: Node[] = []; + + forEach(declarations, declaration => { + forEach(declaration.getChildren(), token => { + return pushKeywordIf(keywords, token, SyntaxKind.ConstructorKeyword); + }); + }); + + return map(keywords, getReferenceEntryFromNode); + } + // returns true if 'node' is defined and has a matching 'kind'. function hasKind(node: Node, kind: SyntaxKind) { return !!(node && node.kind === kind); @@ -2282,20 +2374,13 @@ module ts { return node && node.parent; } - function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): void { - if (!token) { - return; - } - - if (contains(expected, token.kind)) { + function pushKeywordIf(keywordList: Node[], token: Node, ...expected: SyntaxKind[]): boolean { + if (token && contains(expected, token.kind)) { keywordList.push(token); + return true; } - } - function keywordsToReferenceEntries(keywords: Node[]): ReferenceEntry[]{ - return map(keywords, keyword => - new ReferenceEntry(filename, TypeScript.TextSpan.fromBounds(keyword.getStart(), keyword.end), /* isWriteAccess */ false) - ); + return false; } } @@ -2311,6 +2396,9 @@ module ts { } if (node.kind !== SyntaxKind.Identifier && + // TODO (drosen): This should be enabled in a later release - currently breaks rename. + //node.kind !== SyntaxKind.ThisKeyword && + //node.kind !== SyntaxKind.SuperKeyword && !isLiteralNameOfPropertyDeclarationOrIndexAccess(node) && !isNameOfExternalModuleImportOrDeclaration(node)) { return undefined; @@ -2326,7 +2414,7 @@ module ts { var labelDefinition = getTargetLabel((node.parent), (node).text); // if we have a label definition, look within its statement for references, if not, then // the label is undefined, just return a set of one for the current node. - return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntry(node)]; + return labelDefinition ? getLabelReferencesInNode(labelDefinition.parent, labelDefinition) : [getReferenceEntryFromNode(node)]; } else { // it is a label definition and not a target, search within the parent labeledStatement @@ -2334,13 +2422,21 @@ module ts { } } + if (node.kind === SyntaxKind.ThisKeyword) { + return getReferencesForThisKeyword(node, sourceFiles); + } + + if (node.kind === SyntaxKind.SuperKeyword) { + return getReferencesForSuperKeyword(node); + } + var symbol = typeInfoResolver.getSymbolInfo(node); // Could not find a symbol e.g. unknown identifier if (!symbol) { // Even if we did not find a symbol, we have an identifer, so there is at least - // one reference that we know of. return than instead of undefined. - return [getReferenceEntry(node)]; + // one reference that we know of. return that instead of undefined. + return [getReferenceEntryFromNode(node)]; } // the symbol was an internal symbol and does not have a declaration e.g.undefined symbol @@ -2484,7 +2580,7 @@ module ts { // Only pick labels that are either the target label, or have a target that is the target label if (node === targetLabel || (isJumpStatementTarget(node) && getTargetLabel(node, labelName) === targetLabel)) { - result.push(getReferenceEntry(node)); + result.push(getReferenceEntryFromNode(node)); } }); return result; @@ -2549,7 +2645,132 @@ module ts { } if (isRelatableToSearchSet(searchSymbols, referenceSymbol, referenceLocation)) { - result.push(getReferenceEntry(referenceLocation)); + result.push(getReferenceEntryFromNode(referenceLocation)); + } + }); + } + } + + function getReferencesForSuperKeyword(superKeyword: Node): ReferenceEntry[]{ + var searchSpaceNode = getSuperContainer(superKeyword); + if (!searchSpaceNode) { + return undefined; + } + // Whether 'super' occurs in a static context within a class. + var staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags; + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + default: + return undefined; + } + + var result: ReferenceEntry[] = []; + + var sourceFile = searchSpaceNode.getSourceFile(); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "super", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + var node = getNodeAtPosition(sourceFile, position); + + if (!node || node.kind !== SyntaxKind.SuperKeyword) { + return; + } + + var container = getSuperContainer(node); + + // If we have a 'super' container, we must have an enclosing class. + // Now make sure the owning class is the same as the search-space + // and has the same static qualifier as the original 'super's owner. + if (container && (NodeFlags.Static & container.flags) === staticFlag && container.parent.symbol === searchSpaceNode.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + }); + + return result; + } + + function getReferencesForThisKeyword(thisOrSuperKeyword: Node, sourceFiles: SourceFile[]): ReferenceEntry[] { + var searchSpaceNode = getThisContainer(thisOrSuperKeyword, /* includeArrowFunctions */ false); + + // Whether 'this' occurs in a static context within a class. + var staticFlag = NodeFlags.Static; + + switch (searchSpaceNode.kind) { + case SyntaxKind.Property: + case SyntaxKind.Method: + case SyntaxKind.Constructor: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + staticFlag &= searchSpaceNode.flags + searchSpaceNode = searchSpaceNode.parent; // re-assign to be the owning class + break; + case SyntaxKind.SourceFile: + if (isExternalModule(searchSpaceNode)) { + return undefined; + } + // Fall through + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + break; + default: + return undefined; + } + + var result: ReferenceEntry[] = []; + + if (searchSpaceNode.kind === SyntaxKind.SourceFile) { + forEach(sourceFiles, sourceFile => { + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", sourceFile.getStart(), sourceFile.getEnd()); + getThisReferencesInFile(sourceFile, sourceFile, possiblePositions, result); + }); + } + else { + var sourceFile = searchSpaceNode.getSourceFile(); + var possiblePositions = getPossibleSymbolReferencePositions(sourceFile, "this", searchSpaceNode.getStart(), searchSpaceNode.getEnd()); + getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, result); + } + + return result; + + function getThisReferencesInFile(sourceFile: SourceFile, searchSpaceNode: Node, possiblePositions: number[], result: ReferenceEntry[]): void { + forEach(possiblePositions, position => { + cancellationToken.throwIfCancellationRequested(); + + var node = getNodeAtPosition(sourceFile, position); + if (!node || node.kind !== SyntaxKind.ThisKeyword) { + return; + } + + var container = getThisContainer(node, /* includeArrowFunctions */ false); + + switch (searchSpaceNode.kind) { + case SyntaxKind.FunctionExpression: + case SyntaxKind.FunctionDeclaration: + if (searchSpaceNode.symbol === container.symbol) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.ClassDeclaration: + // Make sure the container belongs to the same class + // and has the appropriate static modifier from the original container. + if (container.parent && searchSpaceNode.symbol === container.parent.symbol && (container.flags & NodeFlags.Static) === staticFlag) { + result.push(getReferenceEntryFromNode(node)); + } + break; + case SyntaxKind.SourceFile: + if (container.kind === SyntaxKind.SourceFile && !isExternalModule(container)) { + result.push(getReferenceEntryFromNode(node)); + } + break; } }); } @@ -2651,18 +2872,6 @@ module ts { return undefined; } - function getReferenceEntry(node: Node): ReferenceEntry { - var start = node.getStart(); - var end = node.getEnd(); - - if (node.kind === SyntaxKind.StringLiteral) { - start += 1; - end -= 1; - } - - return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node)); - } - function getMeaningFromDeclaration(node: Declaration): SearchMeaning { switch (node.kind) { case SyntaxKind.Parameter: @@ -2799,40 +3008,38 @@ module ts { } return meaning; } + } - /// A node is considedered a writeAccess iff it is a name of a declaration or a target of an assignment - function isWriteAccess(node: Node): boolean { - if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { + function getReferenceEntryFromNode(node: Node): ReferenceEntry { + var start = node.getStart(); + var end = node.getEnd(); + + if (node.kind === SyntaxKind.StringLiteral) { + start += 1; + end -= 1; + } + + return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node)); + } + + /// A node is considedered a writeAccess iff it is a name of a declaration or a target of an assignment + function isWriteAccess(node: Node): boolean { + if (node.kind === SyntaxKind.Identifier && isDeclarationOrFunctionExpressionOrCatchVariableName(node)) { + return true; + } + + var parent = node.parent; + if (parent) { + if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) { return true; } - - var parent = node.parent; - if (parent) { - if (parent.kind === SyntaxKind.PostfixOperator || parent.kind === SyntaxKind.PrefixOperator) { - return true; - } - else if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { - var operator = (parent).operator; - switch (operator) { - case SyntaxKind.AsteriskEqualsToken: - case SyntaxKind.SlashEqualsToken: - case SyntaxKind.PercentEqualsToken: - case SyntaxKind.MinusEqualsToken: - case SyntaxKind.LessThanLessThanEqualsToken: - case SyntaxKind.GreaterThanGreaterThanEqualsToken: - case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: - case SyntaxKind.BarEqualsToken: - case SyntaxKind.CaretEqualsToken: - case SyntaxKind.AmpersandEqualsToken: - case SyntaxKind.PlusEqualsToken: - case SyntaxKind.EqualsToken: - return true; - } - } - - return false; + else if (parent.kind === SyntaxKind.BinaryExpression && (parent).left === node) { + var operator = (parent).operator; + return SyntaxKind.FirstAssignment <= operator && operator <= SyntaxKind.LastAssignment; } } + + return false; } /// Syntactic features diff --git a/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts b/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts new file mode 100644 index 00000000000..4b9f7a450ec --- /dev/null +++ b/tests/cases/fourslash/findAllRefsThisKeywordMultipleFiles.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: file1.ts +////this; this; + +// @Filename: file2.ts +////this; +////this; + +// @Filename: file3.ts +//// ((x = this, y) => t/**/his)(this, this); + +goTo.file("file1.ts"); +goTo.marker(); + +// TODO (drosen): The CURRENT behavior is that findAllRefs doesn't work on 'this' or 'super' keywords. +// This should change down the line. +verify.referencesCountIs(0); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesConstructor.ts b/tests/cases/fourslash/getOccurrencesConstructor.ts new file mode 100644 index 00000000000..0a6b84a5770 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesConstructor.ts @@ -0,0 +1,32 @@ +/// + +////class C { +//// [|const/**/ructor|](); +//// [|constructor|](x: number); +//// [|constructor|](y: string, x: number); +//// [|constructor|](a?: any, ...r: any[]) { +//// if (a === undefined && r.length === 0) { +//// return; +//// } +//// +//// return; +//// } +////} +//// +////class D { +//// constructor(public x: number, public y: number) { +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesConstructor2.ts b/tests/cases/fourslash/getOccurrencesConstructor2.ts new file mode 100644 index 00000000000..049c25b7f52 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesConstructor2.ts @@ -0,0 +1,32 @@ +/// + +////class C { +//// constructor(); +//// constructor(x: number); +//// constructor(y: string, x: number); +//// constructor(a?: any, ...r: any[]) { +//// if (a === undefined && r.length === 0) { +//// return; +//// } +//// +//// return; +//// } +////} +//// +////class D { +//// [|con/**/structor|](public x: number, public y: number) { +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse.ts b/tests/cases/fourslash/getOccurrencesIfElse.ts new file mode 100644 index 00000000000..96c70d404ab --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse.ts @@ -0,0 +1,36 @@ +/// + +////[|if|] (true) { +//// if (false) { +//// } +//// else { +//// } +//// if (true) { +//// } +//// else { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////[|else i/**/f|] (null) { +////} +////[|else|] /* whar garbl */ [|if|] (undefined) { +////} +////[|else|] +////[|if|] (false) { +////} +////[|else|] { } + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse2.ts b/tests/cases/fourslash/getOccurrencesIfElse2.ts new file mode 100644 index 00000000000..012e7a96efd --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse2.ts @@ -0,0 +1,32 @@ +/// + +////if (true) { +//// [|if|] (false) { +//// } +//// [|else|]{ +//// } +//// if (true) { +//// } +//// else { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse3.ts b/tests/cases/fourslash/getOccurrencesIfElse3.ts new file mode 100644 index 00000000000..b0ca3615648 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse3.ts @@ -0,0 +1,32 @@ +/// + +////if (true) { +//// if (false) { +//// } +//// else { +//// } +//// [|if|] (true) { +//// } +//// [|else|] { +//// if (false) +//// if (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElse4.ts b/tests/cases/fourslash/getOccurrencesIfElse4.ts new file mode 100644 index 00000000000..66746252741 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElse4.ts @@ -0,0 +1,30 @@ +/// + +////if (true) { +//// if (false) { +//// } +//// else { +//// } +//// if (true) { +//// } +//// else { +//// /*1*/if (false) +//// /*2*/i/*3*/f (true) +//// var x = undefined; +//// } +////} +////else if (null) { +////} +////else /* whar garbl */ if (undefined) { +////} +////else +////if (false) { +////} +////else { } + + +for (var i = 1; i <= test.markers().length; i++) { + goTo.marker("" + i); + + verify.occurrencesAtPositionCount(1); +} \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElseBroken.ts b/tests/cases/fourslash/getOccurrencesIfElseBroken.ts new file mode 100644 index 00000000000..a9e1e94f42d --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElseBroken.ts @@ -0,0 +1,24 @@ +/// + + +////[|if|] (true) { +//// var x = 1; +////} +////[|else if|] () +////[|else if|] +////[|else|] /* whar garbl */ [|if|] (i/**/f (true) { } else { }) +////else + +// It would be nice if in the future, +// We could include that last 'else'. + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +verify.occurrencesAtPositionCount(2); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts b/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts new file mode 100644 index 00000000000..601eba63c64 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts @@ -0,0 +1,29 @@ +/// + +////if/*1*/ (true) { +//// if/*2*/ (false) { +//// } +//// else/*3*/ { +//// } +//// if/*4*/ (true) { +//// } +//// else/*5*/ { +//// if/*6*/ (false) +//// if/*7*/ (true) +//// var x = undefined; +//// } +////} +////else/*8*/ if (null) { +////} +////else/*9*/ /* whar garbl */ if/*10*/ (undefined) { +////} +////else/*11*/ +////if/*12*/ (false) { +////} +////else/*13*/ { } + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(0); +}); diff --git a/tests/cases/fourslash/getOccurrencesReturn.ts b/tests/cases/fourslash/getOccurrencesReturn.ts new file mode 100644 index 00000000000..613e1645fb5 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn.ts @@ -0,0 +1,33 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// [|ret/**/urn|] (function () { +//// return; +//// return; +//// return; +//// +//// if (false) { +//// return true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// [|return|]; +//// [|return|] true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturn2.ts b/tests/cases/fourslash/getOccurrencesReturn2.ts new file mode 100644 index 00000000000..15a062433fe --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn2.ts @@ -0,0 +1,33 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// [|return|]; +//// [|ret/**/urn|]; +//// [|return|]; +//// +//// while (false) { +//// [|return|] true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// return; +//// return true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturn3.ts b/tests/cases/fourslash/getOccurrencesReturn3.ts new file mode 100644 index 00000000000..030d700ef6e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturn3.ts @@ -0,0 +1,28 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// return; +//// return; +//// return; +//// +//// if (false) { +//// return true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { [|return|] 4 }) +//// +//// return; +//// return true; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturnBroken.ts b/tests/cases/fourslash/getOccurrencesReturnBroken.ts new file mode 100644 index 00000000000..e740e7f2bb3 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturnBroken.ts @@ -0,0 +1,54 @@ +/// + +////ret/*1*/urn; +////retu/*2*/rn; +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// () => [|return|]; +//// [|return|]; +//// [|return|]; +//// +//// if (false) { +//// [|return|] true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return 4 }) +//// +//// return; +//// return true; +////} +//// +////class A { +//// ret/*3*/urn; +//// r/*4*/eturn 8675309; +////} + +// Note: For this test, these 'return's get highlighted as a result of a parse recovery +// where if an arrow function starts with a statement, we try to parse a body +// as if it was missing curly braces. If the behavior changes in the future, +// a change to this test is very much welcome. +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +for (var i = 1; i <= test.markers().length; i++) { + goTo.marker("" + i); + + switch (i) { + case 0: + case 1: + case 4: + verify.occurrencesAtPositionCount(0); + break; + case 3: + verify.occurrencesAtPositionCount(1); // 'return' is an instance member + break; + } +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesReturnNegatives.ts b/tests/cases/fourslash/getOccurrencesReturnNegatives.ts new file mode 100644 index 00000000000..79cb3c659c6 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesReturnNegatives.ts @@ -0,0 +1,25 @@ +/// + +////function f(a: number) { +//// if (a > 0) { +//// return (function () { +//// return/*1*/; +//// return/*2*/; +//// return/*3*/; +//// +//// if (false) { +//// return/*4*/ true; +//// } +//// })() || true; +//// } +//// +//// var unusued = [1, 2, 3, 4].map(x => { return/*5*/ 4 }) +//// +//// return/*6*/; +//// return/*7*/ true; +////} + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(0); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuper.ts b/tests/cases/fourslash/getOccurrencesSuper.ts new file mode 100644 index 00000000000..f53d9aca62e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuper.ts @@ -0,0 +1,64 @@ +/// + +////class SuperType { +//// superMethod() { +//// } +//// +//// static superStaticMethod() { +//// return 10; +//// } +////} +//// +////class SubType extends SuperType { +//// public prop1 = [|s/**/uper|].superMethod; +//// private prop2 = [|super|].superMethod; +//// +//// constructor() { +//// [|super|](); +//// } +//// +//// public method1() { +//// return [|super|].superMethod(); +//// } +//// +//// private method2() { +//// return [|super|].superMethod(); +//// } +//// +//// public method3() { +//// var x = () => [|super|].superMethod(); +//// +//// // Bad but still gets highlighted +//// function f() { +//// [|super|].superMethod(); +//// } +//// } +//// +//// // Bad but still gets highlighted. +//// public static statProp1 = super.superStaticMethod; +//// +//// public static staticMethod1() { +//// return super.superStaticMethod(); +//// } +//// +//// private static staticMethod2() { +//// return super.superStaticMethod(); +//// } +//// +//// // Are not actually 'super' keywords. +//// super = 10; +//// static super = 20; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuper2.ts b/tests/cases/fourslash/getOccurrencesSuper2.ts new file mode 100644 index 00000000000..1392170ae18 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuper2.ts @@ -0,0 +1,64 @@ +/// + +////class SuperType { +//// superMethod() { +//// } +//// +//// static superStaticMethod() { +//// return 10; +//// } +////} +//// +////class SubType extends SuperType { +//// public prop1 = super.superMethod; +//// private prop2 = super.superMethod; +//// +//// constructor() { +//// super(); +//// } +//// +//// public method1() { +//// return super.superMethod(); +//// } +//// +//// private method2() { +//// return super.superMethod(); +//// } +//// +//// public method3() { +//// var x = () => super.superMethod(); +//// +//// // Bad but still gets highlighted +//// function f() { +//// super.superMethod(); +//// } +//// } +//// +//// // Bad but still gets highlighted. +//// public static statProp1 = [|super|].superStaticMethod; +//// +//// public static staticMethod1() { +//// return [|super|].superStaticMethod(); +//// } +//// +//// private static staticMethod2() { +//// return [|supe/**/r|].superStaticMethod(); +//// } +//// +//// // Are not actually 'super' keywords. +//// super = 10; +//// static super = 20; +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesSuperNegatives.ts b/tests/cases/fourslash/getOccurrencesSuperNegatives.ts new file mode 100644 index 00000000000..8c76da33c12 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesSuperNegatives.ts @@ -0,0 +1,27 @@ +/// + +////function f(x = [|super|]) { +//// [|super|]; +////} +//// +////module M { +//// [|super|]; +//// function f(x = [|super|]) { +//// [|super|]; +//// } +//// +//// class A { +//// } +//// +//// class B extends A { +//// constructor() { +//// super(); +//// } +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + verify.occurrencesAtPositionCount(0); +}); diff --git a/tests/cases/fourslash/getOccurrencesThis.ts b/tests/cases/fourslash/getOccurrencesThis.ts new file mode 100644 index 00000000000..e4b059b9cf9 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis.ts @@ -0,0 +1,154 @@ +/// + +////[|this|]; +////[|th/**/is|]; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis2.ts b/tests/cases/fourslash/getOccurrencesThis2.ts new file mode 100644 index 00000000000..3df30369e3e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis2.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|t/**/his|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis3.ts b/tests/cases/fourslash/getOccurrencesThis3.ts new file mode 100644 index 00000000000..7ee18a31286 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis3.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// [|t/**/his|]; +//// (function (_) { +//// this; +//// })([|this|]); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis4.ts b/tests/cases/fourslash/getOccurrencesThis4.ts new file mode 100644 index 00000000000..75a9383f88e --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis4.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = [|this|].method1; +//// +//// public method1() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// [|this|]; +//// [|this|]; +//// () => [|t/**/his|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThis5.ts b/tests/cases/fourslash/getOccurrencesThis5.ts new file mode 100644 index 00000000000..86ce16b16be --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThis5.ts @@ -0,0 +1,154 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = [|this|].staticMethod1; +//// +//// public static staticMethod1() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|this|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// [|this|]; +//// [|this|]; +//// () => [|this|]; +//// () => { +//// if ([|this|]) { +//// [|this|]; +//// } +//// else { +//// [|t/**/his|].this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + +test.ranges().forEach(r => { + goTo.position(r.start); + + test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); + }); +}); + +goTo.marker(); +test.ranges().forEach(range => { + verify.occurrencesAtPositionContains(range, false); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives.ts b/tests/cases/fourslash/getOccurrencesThisNegatives.ts new file mode 100644 index 00000000000..95c676e0add --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThisNegatives.ts @@ -0,0 +1,149 @@ +/// + +////this/*1*/; +////this; +//// +////function f() { +//// this/*2*/; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// var x = th/*6*/is; +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this/*3*/; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this/*4*/; +//// }, +//// g() { +//// this/*5*/; +//// } +////} + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + + verify.occurrencesAtPositionCount(0); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives2.ts b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts new file mode 100644 index 00000000000..65fb37d09b4 --- /dev/null +++ b/tests/cases/fourslash/getOccurrencesThisNegatives2.ts @@ -0,0 +1,147 @@ +/// + +////this; +////this; +//// +////function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.t/*1*/his; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +////} +//// +////module m { +//// function f() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this./*2*/this; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////class A { +//// public b = this.method1; +//// +//// public method1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.thi/*3*/s; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private method2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.t/*4*/his; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// public static staticB = this.staticMethod1; +//// +//// public static staticMethod1() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.th/*5*/is; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +//// +//// private static staticMethod2() { +//// this; +//// this; +//// () => this; +//// () => { +//// if (this) { +//// this; +//// } +//// else { +//// this.th/*6*/is; +//// } +//// } +//// function inside() { +//// this; +//// (function (_) { +//// this; +//// })(this); +//// } +//// } +////} +//// +////var x = { +//// f() { +//// this; +//// }, +//// g() { +//// this; +//// } +////} + + +test.markers().forEach(m => { + goTo.position(m.position, m.fileName) + verify.occurrencesAtPositionCount(1); +});