diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index c8f20746a074f..1f5807c12495c 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1570,6 +1570,28 @@ module FourSlash { this.currentCaretPosition = definition.textSpan.start; } + public goToTypeDefinition(definitionIndex: number) { + if (definitionIndex === 0) { + this.scenarioActions.push(''); + } + else { + this.taoInvalidReason = 'GoToTypeDefinition not supported for non-zero definition indices'; + } + + var definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); + if (!definitions || !definitions.length) { + this.raiseError('goToTypeDefinition failed - expected to at least one definition location but got 0'); + } + + if (definitionIndex >= definitions.length) { + this.raiseError('goToTypeDefinition failed - definitionIndex value (' + definitionIndex + ') exceeds definition list size (' + definitions.length + ')'); + } + + var definition = definitions[definitionIndex]; + this.openFile(definition.fileName); + this.currentCaretPosition = definition.textSpan.start; + } + public verifyDefinitionLocationExists(negative: boolean) { this.taoInvalidReason = 'verifyDefinitionLocationExists NYI'; @@ -1589,8 +1611,18 @@ module FourSlash { var assertFn = negative ? assert.notEqual : assert.equal; var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var actualCount = definitions && definitions.length || 0; + + assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Definitions Count")); + } + + public verifyTypeDefinitionsCount(negative: boolean, expectedCount: number) { + var assertFn = negative ? assert.notEqual : assert.equal; + + var definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var actualCount = definitions && definitions.length || 0; - assertFn(definitions.length, expectedCount, this.messageAtLastKnownMarker("Definitions Count")); + assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Type definitions Count")); } public verifyDefinitionsName(negative: boolean, expectedName: string, expectedContainerName: string) { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index f4f0c9d83912d..0e0b8d829183d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -342,6 +342,9 @@ module Harness.LanguageService { getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); } + getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[]{ + return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position)); + } getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] { return unwrapJSONCallResult(this.shim.getReferencesAtPosition(fileName, position)); } diff --git a/src/server/client.ts b/src/server/client.ts index eab42abd0e191..3582d508322c2 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -300,6 +300,32 @@ module ts.server { }); } + getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { + var lineOffset = this.positionToOneBasedLineOffset(fileName, position); + var args: protocol.FileLocationRequestArgs = { + file: fileName, + line: lineOffset.line, + offset: lineOffset.offset, + }; + + var request = this.processRequest(CommandNames.TypeDefinition, args); + var response = this.processResponse(request); + + return response.body.map(entry => { + var fileName = entry.file; + var start = this.lineOffsetToPosition(fileName, entry.start); + var end = this.lineOffsetToPosition(fileName, entry.end); + return { + containerKind: "", + containerName: "", + fileName: fileName, + textSpan: ts.createTextSpanFromBounds(start, end), + kind: "", + name: "" + }; + }); + } + findReferences(fileName: string, position: number): ReferencedSymbol[]{ // Not yet implemented. return []; diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index fc9f13a05330a..dbf3ff3e51c9f 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -773,7 +773,7 @@ module ts.server { findConfigFile(searchPath: string): string { while (true) { var fileName = ts.combinePaths(searchPath, "tsconfig.json"); - if (sys.fileExists(fileName)) { + if (this.host.fileExists(fileName)) { return fileName; } var parentPath = ts.getDirectoryPath(searchPath); @@ -923,7 +923,7 @@ module ts.server { var proj = this.createProject(configFilename, projectOptions); for (var i = 0, len = parsedCommandLine.fileNames.length; i < len; i++) { var rootFilename = parsedCommandLine.fileNames[i]; - if (ts.sys.fileExists(rootFilename)) { + if (this.host.fileExists(rootFilename)) { var info = this.openFile(rootFilename, clientFileName == rootFilename); proj.addRoot(info); } diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index 5bc1ffbe4dc07..b95d5e99864bb 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -125,6 +125,14 @@ declare module ts.server.protocol { export interface DefinitionRequest extends FileLocationRequest { } + /** + * Go to type request; value of command field is + * "typeDefinition". Return response giving the file locations that + * define the type for the symbol found in file at location line, col. + */ + export interface TypeDefinitionRequest extends FileLocationRequest { + } + /** * Location in source code expressed as (one-based) line and character offset. */ @@ -165,6 +173,13 @@ declare module ts.server.protocol { body?: FileSpan[]; } + /** + * Definition response message. Gives text range for definition. + */ + export interface TypeDefinitionResponse extends Response { + body?: FileSpan[]; + } + /** * Get occurrences request; value of command field is * "occurrences". Return response giving spans that are relevant diff --git a/src/server/session.ts b/src/server/session.ts index 18a47201366a7..baf0a085ad4a9 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -97,6 +97,7 @@ module ts.server { export var Rename = "rename"; export var Saveto = "saveto"; export var SignatureHelp = "signatureHelp"; + export var TypeDefinition = "typeDefinition"; export var Unknown = "unknown"; } @@ -285,7 +286,29 @@ module ts.server { })); } - getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[] { + getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { + var file = ts.normalizePath(fileName); + var project = this.projectService.getProjectForFile(file); + if (!project) { + throw Errors.NoProject; + } + + var compilerService = project.compilerService; + var position = compilerService.host.lineOffsetToPosition(file, line, offset); + + var definitions = compilerService.languageService.getTypeDefinitionAtPosition(file, position); + if (!definitions) { + return undefined; + } + + return definitions.map(def => ({ + file: def.fileName, + start: compilerService.host.positionToLineOffset(def.fileName, def.textSpan.start), + end: compilerService.host.positionToLineOffset(def.fileName, ts.textSpanEnd(def.textSpan)) + })); + } + + getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[]{ fileName = ts.normalizePath(fileName); let project = this.projectService.getProjectForFile(fileName); @@ -817,6 +840,11 @@ module ts.server { response = this.getDefinition(defArgs.line, defArgs.offset, defArgs.file); break; } + case CommandNames.TypeDefinition: { + var defArgs = request.arguments; + response = this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file); + break; + } case CommandNames.References: { var refArgs = request.arguments; response = this.getReferences(refArgs.line, refArgs.offset, refArgs.file); diff --git a/src/services/services.ts b/src/services/services.ts index d51a9233d452c..1333f2a13cb73 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1001,6 +1001,8 @@ module ts { findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; findReferences(fileName: string, position: number): ReferencedSymbol[]; getDocumentHighlights(fileName: string, position: number, filesToSearch: string[]): DocumentHighlights[]; @@ -3502,19 +3504,6 @@ module ts { return ScriptElementKind.unknown; } - function getTypeKind(type: Type): string { - let flags = type.getFlags(); - - if (flags & TypeFlags.Enum) return ScriptElementKind.enumElement; - if (flags & TypeFlags.Class) return ScriptElementKind.classElement; - if (flags & TypeFlags.Interface) return ScriptElementKind.interfaceElement; - if (flags & TypeFlags.TypeParameter) return ScriptElementKind.typeParameterElement; - if (flags & TypeFlags.Intrinsic) return ScriptElementKind.primitiveType; - if (flags & TypeFlags.StringLiteral) return ScriptElementKind.primitiveType; - - return ScriptElementKind.unknown; - } - function getSymbolModifiers(symbol: Symbol): string { return symbol && symbol.declarations && symbol.declarations.length > 0 ? getNodeModifiers(symbol.declarations[0]) @@ -3929,6 +3918,71 @@ module ts { }; } + function getDefinitionFromSymbol(symbol: Symbol, node: Node): DefinitionInfo[] { + let typeChecker = program.getTypeChecker(); + let result: DefinitionInfo[] = []; + let declarations = symbol.getDeclarations(); + let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol + let symbolKind = getSymbolKind(symbol, node); + let containerSymbol = symbol.parent; + let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; + + if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && + !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { + // Just add all the declarations. + forEach(declarations, declaration => { + result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); + }); + } + + return result; + + function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + // Applicable only if we are in a new expression, or we are on a constructor declaration + // and in either case the symbol has a construct signature definition, i.e. class + if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) { + if (symbol.flags & SymbolFlags.Class) { + let classDeclaration = symbol.getDeclarations()[0]; + Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration); + + return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result); + } + } + return false; + } + + function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { + return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result); + } + return false; + } + + function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { + let declarations: Declaration[] = []; + let definition: Declaration; + + forEach(signatureDeclarations, d => { + if ((selectConstructors && d.kind === SyntaxKind.Constructor) || + (!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) { + declarations.push(d); + if ((d).body) definition = d; + } + }); + + if (definition) { + result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName)); + return true; + } + else if (declarations.length) { + result.push(createDefinitionInfo(lastOrUndefined(declarations), symbolKind, symbolName, containerName)); + return true; + } + + return false; + } + } + /// Goto definition function getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { synchronizeHostData(); @@ -4003,67 +4057,47 @@ module ts { declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName)); } - let result: DefinitionInfo[] = []; - let declarations = symbol.getDeclarations(); - let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol - let symbolKind = getSymbolKind(symbol, node); - let containerSymbol = symbol.parent; - let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : ""; - - if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) && - !tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) { - // Just add all the declarations. - forEach(declarations, declaration => { - result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName)); - }); - } + return getDefinitionFromSymbol(symbol, node); + } - return result; + /// Goto type + function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { + synchronizeHostData(); - function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { - // Applicable only if we are in a new expression, or we are on a constructor declaration - // and in either case the symbol has a construct signature definition, i.e. class - if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) { - if (symbol.flags & SymbolFlags.Class) { - let classDeclaration = symbol.getDeclarations()[0]; - Debug.assert(classDeclaration && classDeclaration.kind === SyntaxKind.ClassDeclaration); + let sourceFile = getValidSourceFile(fileName); - return tryAddSignature(classDeclaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result); - } - } - return false; + let node = getTouchingPropertyName(sourceFile, position); + if (!node) { + return undefined; } - function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { - if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) { - return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result); - } - return false; + let typeChecker = program.getTypeChecker(); + + let symbol = typeChecker.getSymbolAtLocation(node); + if (!symbol) { + return undefined; } - function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) { - let declarations: Declaration[] = []; - let definition: Declaration; + let type = typeChecker.getTypeOfSymbolAtLocation(symbol, node); + if (!type) { + return undefined; + } - forEach(signatureDeclarations, d => { - if ((selectConstructors && d.kind === SyntaxKind.Constructor) || - (!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) { - declarations.push(d); - if ((d).body) definition = d; + if (type.flags & TypeFlags.Union) { + var result: DefinitionInfo[] = []; + forEach((type).types, t => { + if (t.symbol) { + result.push(...getDefinitionFromSymbol(t.symbol, node)); } }); + return result; + } - if (definition) { - result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName)); - return true; - } - else if (declarations.length) { - result.push(createDefinitionInfo(lastOrUndefined(declarations), symbolKind, symbolName, containerName)); - return true; - } - - return false; + if (!type.symbol) { + return undefined; } + + return getDefinitionFromSymbol(type.symbol, node); } function getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] { @@ -6496,6 +6530,7 @@ module ts { getSignatureHelpItems, getQuickInfoAtPosition, getDefinitionAtPosition, + getTypeDefinitionAtPosition, getReferencesAtPosition, findReferences, getOccurrencesAtPosition, diff --git a/src/services/shims.ts b/src/services/shims.ts index b5217852b8569..906b8b59d3cb4 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -132,6 +132,14 @@ module ts { */ getDefinitionAtPosition(fileName: string, position: number): string; + /** + * Returns a JSON-encoded value of the type: + * { fileName: string; textSpan: { start: number; length: number}; kind: string; name: string; containerKind: string; containerName: string } + * + * Or undefined value if no definition can be found. + */ + getTypeDefinitionAtPosition(fileName: string, position: number): string; + /** * Returns a JSON-encoded value of the type: * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[] @@ -589,6 +597,20 @@ module ts { }); } + /// GOTO Type + + /** + * Computes the definition location of the type of the symbol + * at the requested position. + */ + public getTypeDefinitionAtPosition(fileName: string, position: number): string { + return this.forwardJSONCall( + "getTypeDefinitionAtPosition('" + fileName + "', " + position + ")", + () => { + return this.languageService.getTypeDefinitionAtPosition(fileName, position); + }); + } + public getRenameInfo(fileName: string, position: number): string { return this.forwardJSONCall( "getRenameInfo('" + fileName + "', " + position + ")", diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 867f7b1664148..9c6fd814d9f09 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -119,6 +119,10 @@ module FourSlashInterface { FourSlash.currentTestState.goToDefinition(definitionIndex); } + public type(definitionIndex: number = 0) { + FourSlash.currentTestState.goToTypeDefinition(definitionIndex); + } + public position(position: number, fileIndex?: number); public position(position: number, fileName?: string); public position(position: number, fileNameOrIndex?: any) { @@ -234,6 +238,10 @@ module FourSlashInterface { FourSlash.currentTestState.verifyDefinitionsCount(this.negative, expectedCount); } + public typeDefinitionCountIs(expectedCount: number) { + FourSlash.currentTestState.verifyTypeDefinitionsCount(this.negative, expectedCount); + } + public definitionLocationExists() { FourSlash.currentTestState.verifyDefinitionLocationExists(this.negative); } diff --git a/tests/cases/fourslash/goToTypeDefinition.ts b/tests/cases/fourslash/goToTypeDefinition.ts new file mode 100644 index 0000000000000..6b34e7e48866c --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinition.ts @@ -0,0 +1,14 @@ +/// + +// @Filename: goToTypeDefinition_Definition.ts +/////*definition*/class C { +//// p; +////} +////var c: C; + +// @Filename: goToTypeDefinition_Consumption.ts +/////*reference*/c = undefined; + +goTo.marker('reference'); +goTo.type(); +verify.caretAtMarker('definition'); diff --git a/tests/cases/fourslash/goToTypeDefinition2.ts b/tests/cases/fourslash/goToTypeDefinition2.ts new file mode 100644 index 0000000000000..8c76655f4a832 --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinition2.ts @@ -0,0 +1,18 @@ +/// + +// @Filename: goToTypeDefinition2_Definition.ts +/////*definition*/interface I1 { +//// p; +////} +////type propertyType = I1; +////interface I2 { +//// property: propertyType; +////} + +// @Filename: goToTypeDefinition2_Consumption.ts +////var i2: I2; +////i2.prop/*reference*/erty; + +goTo.marker('reference'); +goTo.type(); +verify.caretAtMarker('definition'); diff --git a/tests/cases/fourslash/goToTypeDefinitionAliases.ts b/tests/cases/fourslash/goToTypeDefinitionAliases.ts new file mode 100644 index 0000000000000..19abc22ca30ef --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinitionAliases.ts @@ -0,0 +1,24 @@ +/// + +// @Filename: goToTypeDefinitioAliases_module1.ts +/////*definition*/interface I { +//// p; +////} +////export {I as I2}; + +// @Filename: goToTypeDefinitioAliases_module2.ts +////import {I2 as I3} from "goToTypeDefinitioAliases_module1"; +////var v1: I3; +////export {v1 as v2}; + +// @Filename: goToTypeDefinitioAliases_module3.ts +////import {/*reference1*/v2 as v3} from "goToTypeDefinitioAliases_module2"; +/////*reference2*/v3; + +goTo.marker('reference1'); +goTo.type(); +verify.caretAtMarker('definition'); + +goTo.marker('reference2'); +goTo.type(); +verify.caretAtMarker('definition'); diff --git a/tests/cases/fourslash/goToTypeDefinitionEnumMembers.ts b/tests/cases/fourslash/goToTypeDefinitionEnumMembers.ts new file mode 100644 index 0000000000000..4b5f151498cb3 --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinitionEnumMembers.ts @@ -0,0 +1,13 @@ +/// + +/////*definition*/enum E { +//// value1, +//// value2 +////} +////var x = E.value2; +//// +/////*reference*/x; + +goTo.marker('reference'); +goTo.type(); +verify.caretAtMarker('definition'); diff --git a/tests/cases/fourslash/goToTypeDefinitionModule.ts b/tests/cases/fourslash/goToTypeDefinitionModule.ts new file mode 100644 index 0000000000000..2afccab97c304 --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinitionModule.ts @@ -0,0 +1,19 @@ +/// + +// @Filename: goToTypeDefinitioAliases_module1.ts +/////*definition*/module M { +//// export var p; +////} +////var m: typeof M; + +// @Filename: goToTypeDefinitioAliases_module3.ts +/////*reference1*/M; +/////*reference2*/m; + +goTo.marker('reference1'); +goTo.type(); +verify.caretAtMarker('definition'); + +goTo.marker('reference2'); +goTo.type(); +verify.caretAtMarker('definition'); \ No newline at end of file diff --git a/tests/cases/fourslash/goToTypeDefinitionPrimitives.ts b/tests/cases/fourslash/goToTypeDefinitionPrimitives.ts new file mode 100644 index 0000000000000..d38a0c1634390 --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinitionPrimitives.ts @@ -0,0 +1,25 @@ +/// + +// @Filename: module1.ts +////var w: {a: number}; +////var x = "string"; +////var y: number | string; +////var z; // any + +// @Filename: module2.ts +////w./*reference1*/a; +/////*reference2*/x; +/////*reference3*/y; +/////*reference4*/y; + +goTo.marker('reference1'); +verify.typeDefinitionCountIs(0); + +goTo.marker('reference1'); +verify.typeDefinitionCountIs(0); + +goTo.marker('reference2'); +verify.typeDefinitionCountIs(0); + +goTo.marker('reference4'); +verify.typeDefinitionCountIs(0); diff --git a/tests/cases/fourslash/goToTypeDefinitionUnionType.ts b/tests/cases/fourslash/goToTypeDefinitionUnionType.ts new file mode 100644 index 0000000000000..0630ae3ebb932 --- /dev/null +++ b/tests/cases/fourslash/goToTypeDefinitionUnionType.ts @@ -0,0 +1,31 @@ +/// + +/////*definition0*/class C { +//// p; +////} +//// +/////*definition1*/interface I { +//// x; +////} +//// +////module M { +//// /*definition2*/export interface I { +//// y; +//// } +////} +//// +////var x: C | I | M.I; +//// +/////*reference*/x; + +goTo.marker('reference'); +goTo.type(0); +verify.caretAtMarker('definition0'); + +goTo.marker('reference'); +goTo.type(1); +verify.caretAtMarker('definition1'); + +goTo.marker('reference'); +goTo.type(2); +verify.caretAtMarker('definition2'); diff --git a/tests/cases/fourslash/server/typedefinition01.ts b/tests/cases/fourslash/server/typedefinition01.ts new file mode 100644 index 0000000000000..e7c37747abaad --- /dev/null +++ b/tests/cases/fourslash/server/typedefinition01.ts @@ -0,0 +1,12 @@ +/// + +// @Filename: b.ts +////import n = require('a'); +////var x/*1*/ = new n.Foo(); + +// @Filename: a.ts +//// /*2*/export class Foo {} + +goTo.marker('1'); +goTo.type(); +verify.caretAtMarker('2'); \ No newline at end of file diff --git a/tests/cases/fourslash/shims/goToTypeDefinition.ts b/tests/cases/fourslash/shims/goToTypeDefinition.ts new file mode 100644 index 0000000000000..6b34e7e48866c --- /dev/null +++ b/tests/cases/fourslash/shims/goToTypeDefinition.ts @@ -0,0 +1,14 @@ +/// + +// @Filename: goToTypeDefinition_Definition.ts +/////*definition*/class C { +//// p; +////} +////var c: C; + +// @Filename: goToTypeDefinition_Consumption.ts +/////*reference*/c = undefined; + +goTo.marker('reference'); +goTo.type(); +verify.caretAtMarker('definition');