diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index c05fca5bb472a..d852a0b84f3a6 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -728,7 +728,7 @@ namespace FourSlash {
}
}
- public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) {
+ public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
const references = this.getReferencesAtCaret();
if (!references || references.length === 0) {
@@ -741,11 +741,14 @@ namespace FourSlash {
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
}
+ if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
+ this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
+ }
return;
}
}
- const missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
+ const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
}
@@ -2835,8 +2838,8 @@ namespace FourSlashInterface {
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
}
- public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean) {
- this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess);
+ public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean, isDefinition?: boolean) {
+ this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess, isDefinition);
}
public signatureHelpPresent() {
diff --git a/src/server/client.ts b/src/server/client.ts
index b0a1a8ec9e913..864dac9fdaaa1 100644
--- a/src/server/client.ts
+++ b/src/server/client.ts
@@ -376,6 +376,7 @@ namespace ts.server {
fileName: fileName,
textSpan: ts.createTextSpanFromBounds(start, end),
isWriteAccess: entry.isWriteAccess,
+ isDefinition: entry.isDefinition,
};
});
}
@@ -536,6 +537,7 @@ namespace ts.server {
fileName,
textSpan: ts.createTextSpanFromBounds(start, end),
isWriteAccess: entry.isWriteAccess,
+ isDefinition: false
};
});
}
diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts
index d2c15b308ec4f..b62d89ae52001 100644
--- a/src/server/protocol.d.ts
+++ b/src/server/protocol.d.ts
@@ -304,6 +304,11 @@ declare namespace ts.server.protocol {
* True if reference is a write location, false otherwise.
*/
isWriteAccess: boolean;
+
+ /**
+ * True if reference is a definition, false otherwise.
+ */
+ isDefinition: boolean;
}
/**
diff --git a/src/server/session.ts b/src/server/session.ts
index 0ec3d87e58c9a..2964dc66505f3 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -379,7 +379,7 @@ namespace ts.server {
start,
end,
file: fileName,
- isWriteAccess
+ isWriteAccess,
};
});
}
@@ -555,7 +555,8 @@ namespace ts.server {
start: start,
lineText: lineText,
end: compilerService.host.positionToLineOffset(ref.fileName, ts.textSpanEnd(ref.textSpan)),
- isWriteAccess: ref.isWriteAccess
+ isWriteAccess: ref.isWriteAccess,
+ isDefinition: ref.isDefinition
};
});
},
diff --git a/src/services/services.ts b/src/services/services.ts
index 13df3a54a30be..07094df7d2b2e 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1208,6 +1208,7 @@ namespace ts {
textSpan: TextSpan;
fileName: string;
isWriteAccess: boolean;
+ isDefinition: boolean;
}
export interface DocumentHighlights {
@@ -5749,7 +5750,8 @@ namespace ts {
result.push({
fileName: entry.fileName,
textSpan: highlightSpan.textSpan,
- isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference
+ isWriteAccess: highlightSpan.kind === HighlightSpanKind.writtenReference,
+ isDefinition: false
});
}
}
@@ -6183,7 +6185,8 @@ namespace ts {
references: [{
fileName: sourceFile.fileName,
textSpan: createTextSpan(position, searchText.length),
- isWriteAccess: false
+ isWriteAccess: false,
+ isDefinition: false
}]
});
}
@@ -6737,7 +6740,8 @@ namespace ts {
return {
fileName: node.getSourceFile().fileName,
textSpan: createTextSpanFromBounds(start, end),
- isWriteAccess: isWriteAccess(node)
+ isWriteAccess: isWriteAccess(node),
+ isDefinition: isDeclarationName(node) || isLiteralComputedPropertyDeclarationName(node)
};
}
diff --git a/src/services/shims.ts b/src/services/shims.ts
index 94ff3367e3c68..96392ca42bebd 100644
--- a/src/services/shims.ts
+++ b/src/services/shims.ts
@@ -164,7 +164,7 @@ namespace ts {
/**
* Returns a JSON-encoded value of the type:
- * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[]
+ * { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean, isDefinition?: boolean }[]
*/
getReferencesAtPosition(fileName: string, position: number): string;
@@ -1141,4 +1141,4 @@ namespace TypeScript.Services {
/* @internal */
const toolsVersion = "1.9";
-/* tslint:enable:no-unused-variable */
\ No newline at end of file
+/* tslint:enable:no-unused-variable */
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 540a650313845..78de5b02358b4 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -125,7 +125,7 @@ declare namespace FourSlashInterface {
completionListAllowsNewIdentifier(): void;
memberListIsEmpty(): void;
referencesCountIs(count: number): void;
- referencesAtPositionContains(range: Range, isWriteAccess?: boolean): void;
+ referencesAtPositionContains(range: Range, isWriteAccess?: boolean, isDefinition?: boolean): void;
signatureHelpPresent(): void;
errorExistsBetweenMarkers(startMarker: string, endMarker: string): void;
errorExistsAfterMarker(markerName?: string): void;
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfArrowFunction.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfArrowFunction.ts
new file mode 100644
index 0000000000000..eb9980c946d30
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfArrowFunction.ts
@@ -0,0 +1,8 @@
+///
+////var [|{| "isDefinition": true |}f|] = x => x + 1;
+////[|{| "isDefinition": false |}f|](12);
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts
new file mode 100644
index 0000000000000..9a30687c59e45
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfBindingPattern.ts
@@ -0,0 +1,8 @@
+///
+////const { [|{| "isDefinition": true |}x|], y } = { x: 1, y: 2 };
+////const z = [|{| "isDefinition": false |}x|];
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfClass.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfClass.ts
new file mode 100644
index 0000000000000..04b1f90681a24
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfClass.ts
@@ -0,0 +1,13 @@
+///
+////class [|{| "isDefinition": true |}C|] {
+//// n: number;
+//// constructor() {
+//// this.n = 12;
+//// }
+////}
+////let c = new [|{| "isDefinition": false |}C|]();
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfComputedProperty.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfComputedProperty.ts
new file mode 100644
index 0000000000000..8896694db50b4
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfComputedProperty.ts
@@ -0,0 +1,9 @@
+///
+////let o = { ["[|{| "isDefinition": true |}foo|]"]: 12 };
+////let y = o.[|{| "isDefinition": false |}foo|];
+////let z = o['[|{| "isDefinition": false |}foo|]'];
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfEnum.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfEnum.ts
new file mode 100644
index 0000000000000..a5764206bce23
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfEnum.ts
@@ -0,0 +1,11 @@
+///
+////enum [|{| "isDefinition": true |}E|] {
+//// First,
+//// Second
+////}
+////let first = [|{| "isDefinition": false |}E|].First;
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfExport.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfExport.ts
new file mode 100644
index 0000000000000..f863af9184fc1
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfExport.ts
@@ -0,0 +1,11 @@
+///
+// @Filename: m.ts
+////export var [|{| "isDefinition": true |}x|] = 12;
+// @Filename: main.ts
+////import { [|{| "isDefinition": true |}x|] } from "./m";
+////const y = [|{| "isDefinition": false |}x|];
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfFunction.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfFunction.ts
new file mode 100644
index 0000000000000..456d953092dca
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfFunction.ts
@@ -0,0 +1,9 @@
+///
+////function [|{| "isDefinition": true |}func|](x: number) {
+////}
+////[|{| "isDefinition": false |}func|](x)
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterface.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterface.ts
new file mode 100644
index 0000000000000..51d1e858185be
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterface.ts
@@ -0,0 +1,10 @@
+///
+////interface [|{| "isDefinition": true |}I|] {
+//// p: number;
+////}
+////let i: [|{| "isDefinition": false |}I|] = { p: 12 };
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterfaceClassMerge.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterfaceClassMerge.ts
new file mode 100644
index 0000000000000..7efefa17a4b02
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfInterfaceClassMerge.ts
@@ -0,0 +1,19 @@
+///
+////interface [|{| "isDefinition": true |}Numbers|] {
+//// p: number;
+////}
+////interface [|{| "isDefinition": true |}Numbers|] {
+//// m: number;
+////}
+////class [|{| "isDefinition": true |}Numbers|] {
+//// f(n: number) {
+//// return this.p + this.m + n;
+//// }
+////}
+////let i: [|{| "isDefinition": false |}Numbers|] = new [|{| "isDefinition": false |}Numbers|]();
+////let x = i.f(i.p + i.m);
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfNamespace.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfNamespace.ts
new file mode 100644
index 0000000000000..86b92ec9ce729
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfNamespace.ts
@@ -0,0 +1,10 @@
+///
+////namespace [|{| "isDefinition": true |}Numbers|] {
+//// export var n = 12;
+////}
+////let x = [|{| "isDefinition": false |}Numbers|].n + 1;
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfNumberNamedProperty.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfNumberNamedProperty.ts
new file mode 100644
index 0000000000000..7e3e084948f4c
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfNumberNamedProperty.ts
@@ -0,0 +1,8 @@
+///
+////let o = { [|{| "isDefinition": true |}1|]: 12 };
+////let y = o[[|{| "isDefinition": false |}1|]];
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfParameter.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfParameter.ts
new file mode 100644
index 0000000000000..cdb0e281d53fe
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfParameter.ts
@@ -0,0 +1,9 @@
+///
+////function f([|{| "isDefinition": true |}x|]: number) {
+//// return [|{| "isDefinition": false |}x|] + 1
+////}
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfStringNamedProperty.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfStringNamedProperty.ts
new file mode 100644
index 0000000000000..291aec90dda1c
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfStringNamedProperty.ts
@@ -0,0 +1,8 @@
+///
+////let o = { "[|{| "isDefinition": true |}x|]": 12 };
+////let y = o.[|{| "isDefinition": false |}x|];
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfTypeAlias.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfTypeAlias.ts
new file mode 100644
index 0000000000000..44a7c64a93a2e
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfTypeAlias.ts
@@ -0,0 +1,8 @@
+///
+////type [|{| "isDefinition": true |}Alias|]= number;
+////let n: [|{| "isDefinition": false |}Alias|] = 12;
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});
diff --git a/tests/cases/fourslash/getOccurrencesIsDefinitionOfVariable.ts b/tests/cases/fourslash/getOccurrencesIsDefinitionOfVariable.ts
new file mode 100644
index 0000000000000..8d046c67e3a89
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIsDefinitionOfVariable.ts
@@ -0,0 +1,23 @@
+///
+////var [|{| "isDefinition": true |}x|] = 0;
+////var assignmentRightHandSide = [|{| "isDefinition": false |}x|];
+////var assignmentRightHandSide2 = 1 + [|{| "isDefinition": false |}x|];
+////
+////[|{| "isDefinition": false |}x|] = 1;
+////[|{| "isDefinition": false |}x|] = [|{| "isDefinition": false |}x|] + [|{| "isDefinition": false |}x|];
+////
+////[|{| "isDefinition": false |}x|] == 1;
+////[|{| "isDefinition": false |}x|] <= 1;
+////
+////var preIncrement = ++[|{| "isDefinition": false |}x|];
+////var postIncrement = [|{| "isDefinition": false |}x|]++;
+////var preDecrement = --[|{| "isDefinition": false |}x|];
+////var postDecrement = [|{| "isDefinition": false |}x|]--;
+////
+////[|{| "isDefinition": false |}x|] += 1;
+////[|{| "isDefinition": false |}x|] <<= 1;
+var firstRange = test.ranges()[0];
+goTo.position(firstRange.start, firstRange.fileName);
+test.ranges().forEach(range => {
+ verify.referencesAtPositionContains(range, undefined, range.marker.data.isDefinition);
+});