From 69b0b5600dbb1da9af38656a50e38ca2c7e61864 Mon Sep 17 00:00:00 2001 From: Andy Hanson Date: Wed, 7 Sep 2016 12:00:44 -0700 Subject: [PATCH] Factor out getRenameInfo --- src/services/findAllReferences.ts | 8 +++ src/services/rename.ts | 98 ++++++++++++++++++++++++++++++ src/services/services.ts | 99 +------------------------------ src/services/tsconfig.json | 1 + src/services/utilities.ts | 8 --- 5 files changed, 109 insertions(+), 105 deletions(-) create mode 100644 src/services/rename.ts diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index bba70c47bc8..f2e2a8c9595 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -1114,4 +1114,12 @@ namespace ts.FindAllReferences { function tryGetClassByExtendingIdentifier(node: Node): ClassLikeDeclaration | undefined { return tryGetClassExtendingExpressionWithTypeArguments(climbPastPropertyAccess(node).parent); } + + function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { + if (node.kind === SyntaxKind.StringLiteral) { + return isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node); + } + + return false; + } } diff --git a/src/services/rename.ts b/src/services/rename.ts new file mode 100644 index 00000000000..6f28e505f79 --- /dev/null +++ b/src/services/rename.ts @@ -0,0 +1,98 @@ +/* @internal */ +namespace ts.Rename { + export function getRenameInfo(typeChecker: TypeChecker, defaultLibFileName: string, getCanonicalFileName: (fileName: string) => string, sourceFile: SourceFile, position: number): RenameInfo { + const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName)); + + const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true); + + if (node) { + if (node.kind === SyntaxKind.Identifier || + node.kind === SyntaxKind.StringLiteral || + isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || + isThis(node)) { + const symbol = typeChecker.getSymbolAtLocation(node); + + // Only allow a symbol to be renamed if it actually has at least one declaration. + if (symbol) { + const declarations = symbol.getDeclarations(); + if (declarations && declarations.length > 0) { + // Disallow rename for elements that are defined in the standard TypeScript library. + if (forEach(declarations, isDefinedInLibraryFile)) { + return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); + } + + const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); + const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); + if (kind) { + return { + canRename: true, + kind, + displayName, + localizedErrorMessage: undefined, + fullDisplayName: typeChecker.getFullyQualifiedName(symbol), + kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), + triggerSpan: createTriggerSpanForNode(node, sourceFile) + }; + } + } + } + else if (node.kind === SyntaxKind.StringLiteral) { + const type = getStringLiteralTypeForNode(node, typeChecker); + if (type) { + if (isDefinedInLibraryFile(node)) { + return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); + } + else { + const displayName = stripQuotes(type.text); + return { + canRename: true, + kind: ScriptElementKind.variableElement, + displayName, + localizedErrorMessage: undefined, + fullDisplayName: displayName, + kindModifiers: ScriptElementKindModifier.none, + triggerSpan: createTriggerSpanForNode(node, sourceFile) + }; + } + } + } + } + } + + return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element)); + + function getRenameInfoError(localizedErrorMessage: string): RenameInfo { + return { + canRename: false, + localizedErrorMessage: localizedErrorMessage, + displayName: undefined, + fullDisplayName: undefined, + kind: undefined, + kindModifiers: undefined, + triggerSpan: undefined + }; + } + + function isDefinedInLibraryFile(declaration: Node) { + if (defaultLibFileName) { + const sourceFile = declaration.getSourceFile(); + const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName)); + if (canonicalName === canonicalDefaultLibName) { + return true; + } + } + return false; + } + + function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { + let start = node.getStart(sourceFile); + let width = node.getWidth(sourceFile); + if (node.kind === SyntaxKind.StringLiteral) { + // Exclude the quotes + start += 1; + width -= 2; + } + return createTextSpan(start, width); + } + } +} diff --git a/src/services/services.ts b/src/services/services.ts index 51976cfdc61..1a59acf10d4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -18,6 +18,7 @@ /// /// /// +/// /// /// /// @@ -1419,104 +1420,8 @@ namespace ts { function getRenameInfo(fileName: string, position: number): RenameInfo { synchronizeHostData(); - - const sourceFile = getValidSourceFile(fileName); - const typeChecker = program.getTypeChecker(); - const defaultLibFileName = host.getDefaultLibFileName(host.getCompilationSettings()); - const canonicalDefaultLibName = getCanonicalFileName(ts.normalizePath(defaultLibFileName)); - - const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true); - - if (node) { - if (node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.StringLiteral || - isLiteralNameOfPropertyDeclarationOrIndexAccess(node) || - isThis(node)) { - const symbol = typeChecker.getSymbolAtLocation(node); - - // Only allow a symbol to be renamed if it actually has at least one declaration. - if (symbol) { - const declarations = symbol.getDeclarations(); - if (declarations && declarations.length > 0) { - // Disallow rename for elements that are defined in the standard TypeScript library. - if (forEach(declarations, isDefinedInLibraryFile)) { - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); - } - - const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node)); - const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node); - if (kind) { - return { - canRename: true, - kind, - displayName, - localizedErrorMessage: undefined, - fullDisplayName: typeChecker.getFullyQualifiedName(symbol), - kindModifiers: SymbolDisplay.getSymbolModifiers(symbol), - triggerSpan: createTriggerSpanForNode(node, sourceFile) - }; - } - } - } - else if (node.kind === SyntaxKind.StringLiteral) { - const type = getStringLiteralTypeForNode(node, typeChecker); - if (type) { - if (isDefinedInLibraryFile(node)) { - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library)); - } - else { - const displayName = stripQuotes(type.text); - return { - canRename: true, - kind: ScriptElementKind.variableElement, - displayName, - localizedErrorMessage: undefined, - fullDisplayName: displayName, - kindModifiers: ScriptElementKindModifier.none, - triggerSpan: createTriggerSpanForNode(node, sourceFile) - }; - } - } - } - } - } - - return getRenameInfoError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element)); - - function getRenameInfoError(localizedErrorMessage: string): RenameInfo { - return { - canRename: false, - localizedErrorMessage: localizedErrorMessage, - displayName: undefined, - fullDisplayName: undefined, - kind: undefined, - kindModifiers: undefined, - triggerSpan: undefined - }; - } - - function isDefinedInLibraryFile(declaration: Node) { - if (defaultLibFileName) { - const sourceFile = declaration.getSourceFile(); - const canonicalName = getCanonicalFileName(ts.normalizePath(sourceFile.fileName)); - if (canonicalName === canonicalDefaultLibName) { - return true; - } - } - return false; - } - - function createTriggerSpanForNode(node: Node, sourceFile: SourceFile) { - let start = node.getStart(sourceFile); - let width = node.getWidth(sourceFile); - if (node.kind === SyntaxKind.StringLiteral) { - // Exclude the quotes - start += 1; - width -= 2; - } - return createTextSpan(start, width); - } + return Rename.getRenameInfo(program.getTypeChecker(), defaultLibFileName, getCanonicalFileName, getValidSourceFile(fileName), position); } return { diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 47d3294a65c..2affec6fc74 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -56,6 +56,7 @@ "outliningElementsCollector.ts", "patternMatcher.ts", "preProcess.ts", + "rename.ts", "services.ts", "shims.ts", "signatureHelp.ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 8324c03a2c9..9e198a88194 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -87,14 +87,6 @@ namespace ts { return false; } - export function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean { - if (node.kind === SyntaxKind.StringLiteral) { - return isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node); - } - - return false; - } - export function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) { return isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node;