diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index df515e7a8c8..f1458091df5 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -65,7 +65,8 @@ module ts {
symbolToString: symbolToString,
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
getRootSymbol: getRootSymbol,
- getContextualType: getContextualType
+ getContextualType: getContextualType,
+ getFullyQualifiedName: getFullyQualifiedName
};
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index c7893f8d997..82fac6b8913 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -634,6 +634,7 @@ module ts {
getApparentType(type: Type): ApparentType;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
+ getFullyQualifiedName(symbol: Symbol): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
getRootSymbol(symbol: Symbol): Symbol;
getContextualType(node: Node): Type;
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 360dc3df51e..ed6dc1a71f7 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -898,6 +898,44 @@ module FourSlash {
}
}
+ private validate(name: string, expected: string, actual: string) {
+ if (expected && expected !== actual) {
+ throw new Error("Expected " + name + " '" + expected + "'. Got '" + actual + "' instead.");
+ }
+ }
+
+ public verifyRenameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
+ var renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
+ if (!renameInfo.canRename) {
+ throw new Error("Rename did not succeed");
+ }
+
+ this.validate("displayName", displayName, renameInfo.displayName);
+ this.validate("fullDisplayName", fullDisplayName, renameInfo.fullDisplayName);
+ this.validate("kind", kind, renameInfo.kind);
+ this.validate("kindModifiers", kindModifiers, renameInfo.kindModifiers);
+
+ if (this.getRanges().length !== 1) {
+ throw new Error("Expected a single range to be selected in the test file.");
+ }
+
+ var expectedRange = this.getRanges()[0];
+ if (renameInfo.triggerSpan.start() !== expectedRange.start ||
+ renameInfo.triggerSpan.end() !== expectedRange.end) {
+ throw new Error("Expected triggerSpan [" + expectedRange.start + "," + expectedRange.end + "). Got [" +
+ renameInfo.triggerSpan.start() + "," + renameInfo.triggerSpan.end() + ") instead.");
+ }
+ }
+
+ public verifyRenameInfoFailed(message?: string) {
+ var renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
+ if (renameInfo.canRename) {
+ throw new Error("Rename was expected to fail");
+ }
+
+ this.validate("error", message, renameInfo.localizedErrorMessage);
+ }
+
//private getFormalParameter() {
// var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
// return help.formal;
diff --git a/src/services/services.ts b/src/services/services.ts
index 6742e86dc38..94fae880d25 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -3896,6 +3896,32 @@ module ts {
return null;
}
+ function getRenameInfo(fileName: string, position: number): RenameInfo {
+ synchronizeHostData();
+
+ fileName = TypeScript.switchToForwardSlashes(fileName);
+ var sourceFile = getSourceFile(fileName);
+
+ var node = getNodeAtPosition(sourceFile, position);
+
+ // Can only rename an identifier.
+ if (node && node.kind === SyntaxKind.Identifier) {
+ var symbol = typeInfoResolver.getSymbolInfo(node);
+
+ // Only allow a symbol to be renamed if it actually has at least one declaration.
+ if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) {
+ var kind = getSymbolKind(symbol);
+ if (kind) {
+ return RenameInfo.Create(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
+ getNodeModifiers(symbol.getDeclarations()[0]),
+ new TypeScript.TextSpan(node.getStart(), node.getWidth()));
+ }
+ }
+ }
+
+ return RenameInfo.CreateError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element.key));
+ }
+
return {
dispose: dispose,
cleanupSemanticCache: cleanupSemanticCache,
@@ -3916,7 +3942,7 @@ module ts {
getNameOrDottedNameSpan: getNameOrDottedNameSpan,
getBreakpointStatementAtPosition: getBreakpointStatementAtPosition,
getNavigateToItems: getNavigateToItems,
- getRenameInfo: (fileName, position): RenameInfo => RenameInfo.CreateError(getLocaleSpecificMessage(Diagnostics.You_cannot_rename_this_element.key)),
+ getRenameInfo: getRenameInfo,
getNavigationBarItems: getNavigationBarItems,
getOutliningSpans: getOutliningSpans,
getTodoComments: getTodoComments,
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index ccbaa34b900..f9476ee4d92 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -404,6 +404,14 @@ module FourSlashInterface {
public semanticClassificationsAre(...classifications: { classificationType: string; text: string }[]) {
FourSlash.currentTestState.verifySemanticClassifications(classifications);
}
+
+ public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
+ FourSlash.currentTestState.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers)
+ }
+
+ public renameInfoFailed(message?: string) {
+ FourSlash.currentTestState.verifyRenameInfoFailed(message)
+ }
}
export class edit {
diff --git a/tests/cases/fourslash/getRenameInfoTests1.ts b/tests/cases/fourslash/getRenameInfoTests1.ts
new file mode 100644
index 00000000000..6f4300282d6
--- /dev/null
+++ b/tests/cases/fourslash/getRenameInfoTests1.ts
@@ -0,0 +1,8 @@
+///
+
+////class [|/**/C|] {
+////
+////}
+
+goTo.marker("");
+verify.renameInfoSucceeded("C");
\ No newline at end of file
diff --git a/tests/cases/fourslash/getRenameInfoTests2.ts b/tests/cases/fourslash/getRenameInfoTests2.ts
new file mode 100644
index 00000000000..93e8e451b4a
--- /dev/null
+++ b/tests/cases/fourslash/getRenameInfoTests2.ts
@@ -0,0 +1,8 @@
+///
+
+/////**/class C {
+////
+////}
+
+goTo.marker("");
+verify.renameInfoFailed();
\ No newline at end of file