From 2a8b9ef21f4605c68a7d2e64a4932efa8f3e6f26 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 3 Oct 2014 14:53:50 -0700 Subject: [PATCH] Support rename in comments and strings. --- src/compiler/checker.ts | 4 +- src/compiler/parser.ts | 8 +-- src/harness/typeWriter.ts | 2 +- src/services/services.ts | 103 ++++++++++++++++++++++++++++++++++++-- src/services/shims.ts | 14 ++++++ src/services/utilities.ts | 2 +- 6 files changed, 121 insertions(+), 12 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a0e55520237..c2df5760e4e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2575,7 +2575,7 @@ module ts { function getStringLiteralType(node: StringLiteralTypeNode): StringLiteralType { if (hasProperty(stringLiteralTypes, node.text)) return stringLiteralTypes[node.text]; var type = stringLiteralTypes[node.text] = createType(TypeFlags.StringLiteral); - type.text = getSourceTextOfNode(node); + type.text = getTextOfNode(node); return type; } @@ -7430,7 +7430,7 @@ module ts { while (!isUniqueLocalName(escapeIdentifier(prefix + name), container)) { prefix += "_"; } - links.localModuleName = prefix + getSourceTextOfNode(container.name); + links.localModuleName = prefix + getTextOfNode(container.name); } return links.localModuleName; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5318e679c4e..13fe69cf1ba 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -54,11 +54,11 @@ module ts { return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); } - export function getSourceTextOfNodeFromSourceText(sourceText: string, node: Node): string { + export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string { return sourceText.substring(skipTrivia(sourceText, node.pos), node.end); } - export function getSourceTextOfNode(node: Node): string { + export function getTextOfNode(node: Node): string { var text = getSourceFileOfNode(node).text; return text.substring(skipTrivia(text, node.pos), node.end); } @@ -75,7 +75,7 @@ module ts { // Return display name of an identifier export function identifierToString(identifier: Identifier) { - return identifier.kind === SyntaxKind.Missing ? "(Missing)" : getSourceTextOfNode(identifier); + return identifier.kind === SyntaxKind.Missing ? "(Missing)" : getTextOfNode(identifier); } export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic { @@ -3045,7 +3045,7 @@ module ts { parseExpected(SyntaxKind.ColonToken); if (labelledStatementInfo.nodeIsNestedInLabel(node.label, /*requireIterationStatement*/ false, /*stopAtFunctionBoundary*/ true)) { - grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getSourceTextOfNodeFromSourceText(sourceText, node.label)); + grammarErrorOnNode(node.label, Diagnostics.Duplicate_label_0, getTextOfNodeFromSourceText(sourceText, node.label)); } labelledStatementInfo.addLabel(node.label); diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index 3b5d8cd3fff..8169531c27e 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -76,7 +76,7 @@ class TypeWriterWalker { private log(node: ts.Node, type: ts.Type): void { var actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos); var lineAndCharacter = this.currentSourceFile.getLineAndCharacterFromPosition(actualPos); - var sourceText = ts.getSourceTextOfNodeFromSourceText(this.currentSourceFile.text, node); + var sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node); // If we got an unknown type, we temporarily want to fall back to just pretending the name // (source text) of the node is the type. This is to align with the old typeWriter to make diff --git a/src/services/services.ts b/src/services/services.ts index 88efbaf2a2a..16d2bd9dffd 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -666,6 +666,8 @@ module ts { getSignatureAtPosition(fileName: string, position: number): SignatureInfo; getRenameInfo(fileName: string, position: number): RenameInfo; + findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; + getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[]; @@ -757,6 +759,11 @@ module ts { newText: string; } + export interface RenameLocation { + textSpan: TypeScript.TextSpan; + fileName: string; + } + export interface ReferenceEntry { textSpan: TypeScript.TextSpan; fileName: string; @@ -3062,11 +3069,19 @@ module ts { } } - function getReferencesAtPosition(filename: string, position: number): ReferenceEntry[] { + function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] { + return findReferences(fileName, position, findInStrings, findInComments); + } + + function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] { + return findReferences(fileName, position, /*findInStrings:*/ false, /*findInComments:*/ false); + } + + function findReferences(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReferenceEntry[] { synchronizeHostData(); - filename = TypeScript.switchToForwardSlashes(filename); - var sourceFile = getSourceFile(filename); + fileName = TypeScript.switchToForwardSlashes(fileName); + var sourceFile = getSourceFile(fileName); var node = getTouchingPropertyName(sourceFile, position); if (!node) { @@ -3082,7 +3097,86 @@ module ts { return undefined; } - return getReferencesForNode(node, program.getSourceFiles()); + Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral); + var references = getReferencesForNode(node, program.getSourceFiles()); + + var name = (node).text; + var tripleSlashDirectivePrefixRegex = /^\/\/\/\s*= 0) { + // Only consider it a match if there isn't a letter/number before or after + // the match. + var indexInSourceText = rawTextPositionInSourceText + matchIndex; + + if (indexInSourceText === 0 || !isIdentifierPart(sourceText.charCodeAt(indexInSourceText - 1), ScriptTarget.ES5)) { + var matchEnd = indexInSourceText + name.length; + if (matchEnd >= sourceText.length || !isIdentifierPart(sourceText.charCodeAt(matchEnd), ScriptTarget.ES5)) { + + references.push({ + fileName: sourceFile.filename, + textSpan: new TypeScript.TextSpan(indexInSourceText, name.length), + isWriteAccess: false + }); + } + } + + matchIndex++; + } + } + + function addCommentReferences(sourceFile: SourceFile) { + var sourceText = sourceFile.text; + forEachChild(sourceFile, addCommentReferencesInNode); + + function addCommentReferencesInNode(node: Node) { + if (isToken(node)) { + // Found a token, walk its comments (if it has any) for matches). + forEach(getLeadingCommentRanges(sourceText, node.pos), addReferencesInCommentRange); + } + else { + forEach(node.getChildren(), addCommentReferencesInNode); + } + } + + function addReferencesInCommentRange(range: CommentRange) { + var commentText = sourceText.substring(range.pos, range.end); + + // Don't add matches in /// { + return this.languageService.findRenameLocations(fileName, position, findInStrings, findInComments); + }); + } + /// GET BRACE MATCHING public getBraceMatchingAtPosition(fileName: string, position: number): string { return this.forwardJSONCall( diff --git a/src/services/utilities.ts b/src/services/utilities.ts index caa324fcc7b..af320ea0a0c 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -222,7 +222,7 @@ module ts { return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; } - function isToken(n: Node): boolean { + export function isToken(n: Node): boolean { return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; }