Skip to content

Commit e1be0bc

Browse files
author
Kanchalai Tanglertsampan
committed
Merge branch 'master' into mergeMaster_09/01
2 parents 6dead9b + 4a643e5 commit e1be0bc

File tree

108 files changed

+6658
-1507
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+6658
-1507
lines changed

Jakefile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ var servicesSources = [
128128
"services.ts",
129129
"shims.ts",
130130
"signatureHelp.ts",
131+
"types.ts",
131132
"utilities.ts",
132133
"formatting/formatting.ts",
133134
"formatting/formattingContext.ts",

src/compiler/checker.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ namespace ts {
143143

144144
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
145145
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
146+
const resolvingSignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
146147

147148
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
148149

@@ -12264,10 +12265,10 @@ namespace ts {
1226412265
// or that a different candidatesOutArray was passed in. Therefore, we need to redo the work
1226512266
// to correctly fill the candidatesOutArray.
1226612267
const cached = links.resolvedSignature;
12267-
if (cached && cached !== anySignature && !candidatesOutArray) {
12268+
if (cached && cached !== resolvingSignature && !candidatesOutArray) {
1226812269
return cached;
1226912270
}
12270-
links.resolvedSignature = anySignature;
12271+
links.resolvedSignature = resolvingSignature;
1227112272
const result = resolveSignature(node, candidatesOutArray);
1227212273
// If signature resolution originated in control flow type analysis (for example to compute the
1227312274
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
@@ -12279,7 +12280,7 @@ namespace ts {
1227912280
function getResolvedOrAnySignature(node: CallLikeExpression) {
1228012281
// If we're already in the process of resolving the given signature, don't resolve again as
1228112282
// that could cause infinite recursion. Instead, return anySignature.
12282-
return getNodeLinks(node).resolvedSignature === anySignature ? anySignature : getResolvedSignature(node);
12283+
return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node);
1228312284
}
1228412285

1228512286
function getInferredClassType(symbol: Symbol) {

src/compiler/core.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,36 @@ namespace ts {
750750
return result;
751751
}
752752

753+
/**
754+
* Adds the value to an array of values associated with the key, and returns the array.
755+
* Creates the array if it does not already exist.
756+
*/
757+
export function multiMapAdd<V>(map: Map<V[]>, key: string, value: V): V[] {
758+
const values = map[key];
759+
if (values) {
760+
values.push(value);
761+
return values;
762+
}
763+
else {
764+
return map[key] = [value];
765+
}
766+
}
767+
768+
/**
769+
* Removes a value from an array of values associated with the key.
770+
* Does not preserve the order of those values.
771+
* Does nothing if `key` is not in `map`, or `value` is not in `map[key]`.
772+
*/
773+
export function multiMapRemove<V>(map: Map<V[]>, key: string, value: V): void {
774+
const values = map[key];
775+
if (values) {
776+
unorderedRemoveItem(values, value);
777+
if (!values.length) {
778+
delete map[key];
779+
}
780+
}
781+
}
782+
753783
/**
754784
* Tests whether a value is an array.
755785
*/

src/compiler/program.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ namespace ts {
88

99
const emptyArray: any[] = [];
1010

11-
const defaultTypeRoots = ["node_modules/@types"];
12-
1311
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
1412
while (true) {
1513
const fileName = combinePaths(searchPath, "tsconfig.json");
@@ -168,7 +166,7 @@ namespace ts {
168166

169167
const typeReferenceExtensions = [".d.ts"];
170168

171-
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
169+
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost): string[] | undefined {
172170
if (options.typeRoots) {
173171
return options.typeRoots;
174172
}
@@ -181,11 +179,37 @@ namespace ts {
181179
currentDirectory = host.getCurrentDirectory();
182180
}
183181

184-
if (!currentDirectory) {
185-
return undefined;
182+
return currentDirectory && getDefaultTypeRoots(currentDirectory, host);
183+
}
184+
185+
/**
186+
* Returns the path to every node_modules/@types directory from some ancestor directory.
187+
* Returns undefined if there are none.
188+
*/
189+
function getDefaultTypeRoots(currentDirectory: string, host: ModuleResolutionHost): string[] | undefined {
190+
if (!host.directoryExists) {
191+
return [combinePaths(currentDirectory, nodeModulesAtTypes)];
192+
// And if it doesn't exist, tough.
186193
}
187-
return map(defaultTypeRoots, d => combinePaths(currentDirectory, d));
194+
195+
let typeRoots: string[];
196+
197+
while (true) {
198+
const atTypes = combinePaths(currentDirectory, nodeModulesAtTypes);
199+
if (host.directoryExists(atTypes)) {
200+
(typeRoots || (typeRoots = [])).push(atTypes);
201+
}
202+
203+
const parent = getDirectoryPath(currentDirectory);
204+
if (parent === currentDirectory) {
205+
break;
206+
}
207+
currentDirectory = parent;
208+
}
209+
210+
return typeRoots;
188211
}
212+
const nodeModulesAtTypes = combinePaths("node_modules", "@types");
189213

190214
/**
191215
* @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown.

src/compiler/sys.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ namespace ts {
273273
}
274274

275275
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
276-
(fileWatcherCallbacks[filePath] || (fileWatcherCallbacks[filePath] = [])).push(callback);
276+
multiMapAdd(fileWatcherCallbacks, filePath, callback);
277277
}
278278

279279
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
@@ -289,13 +289,7 @@ namespace ts {
289289
}
290290

291291
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
292-
const callbacks = fileWatcherCallbacks[filePath];
293-
if (callbacks) {
294-
unorderedRemoveItem(callbacks, callback);
295-
if (callbacks.length === 0) {
296-
delete fileWatcherCallbacks[filePath];
297-
}
298-
}
292+
multiMapRemove(fileWatcherCallbacks, filePath, callback);
299293
}
300294

301295
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {

src/harness/fourslash.ts

Lines changed: 92 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,67 @@ namespace FourSlash {
525525
}
526526
}
527527

528+
public verifyGoToDefinitionIs(endMarker: string | string[]) {
529+
this.verifyGoToDefinitionWorker(endMarker instanceof Array ? endMarker : [endMarker]);
530+
}
531+
532+
public verifyGoToDefinition(arg0: any, endMarkerNames?: string | string[]) {
533+
if (endMarkerNames) {
534+
this.verifyGoToDefinitionPlain(arg0, endMarkerNames);
535+
}
536+
else if (arg0 instanceof Array) {
537+
const pairs: [string | string[], string | string[]][] = arg0;
538+
for (const [start, end] of pairs) {
539+
this.verifyGoToDefinitionPlain(start, end);
540+
}
541+
}
542+
else {
543+
const obj: { [startMarkerName: string]: string | string[] } = arg0;
544+
for (const startMarkerName in obj) {
545+
if (ts.hasProperty(obj, startMarkerName)) {
546+
this.verifyGoToDefinitionPlain(startMarkerName, obj[startMarkerName]);
547+
}
548+
}
549+
}
550+
}
551+
552+
private verifyGoToDefinitionPlain(startMarkerNames: string | string[], endMarkerNames: string | string[]) {
553+
if (startMarkerNames instanceof Array) {
554+
for (const start of startMarkerNames) {
555+
this.verifyGoToDefinitionSingle(start, endMarkerNames);
556+
}
557+
}
558+
else {
559+
this.verifyGoToDefinitionSingle(startMarkerNames, endMarkerNames);
560+
}
561+
}
562+
563+
public verifyGoToDefinitionForMarkers(markerNames: string[]) {
564+
for (const markerName of markerNames) {
565+
this.verifyGoToDefinitionSingle(`${markerName}Reference`, `${markerName}Definition`);
566+
}
567+
}
568+
569+
private verifyGoToDefinitionSingle(startMarkerName: string, endMarkerNames: string | string[]) {
570+
this.goToMarker(startMarkerName);
571+
this.verifyGoToDefinitionWorker(endMarkerNames instanceof Array ? endMarkerNames : [endMarkerNames]);
572+
}
573+
574+
private verifyGoToDefinitionWorker(endMarkers: string[]) {
575+
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition) || [];
576+
577+
if (endMarkers.length !== definitions.length) {
578+
this.raiseError(`goToDefinitions failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`);
579+
}
580+
581+
for (let i = 0; i < endMarkers.length; i++) {
582+
const marker = this.getMarkerByName(endMarkers[i]), definition = definitions[i];
583+
if (marker.fileName !== definition.fileName || marker.position !== definition.textSpan.start) {
584+
this.raiseError(`goToDefinition failed for definition ${i}: expected ${marker.fileName} at ${marker.position}, got ${definition.fileName} at ${definition.textSpan.start}`);
585+
}
586+
}
587+
}
588+
528589
public verifyGetEmitOutputForCurrentFile(expected: string): void {
529590
const emit = this.languageService.getEmitOutput(this.activeFile.fileName);
530591
if (emit.outputFiles.length !== 1) {
@@ -1561,21 +1622,6 @@ namespace FourSlash {
15611622
this.goToPosition(len);
15621623
}
15631624

1564-
public goToDefinition(definitionIndex: number) {
1565-
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1566-
if (!definitions || !definitions.length) {
1567-
this.raiseError("goToDefinition failed - expected to find at least one definition location but got 0");
1568-
}
1569-
1570-
if (definitionIndex >= definitions.length) {
1571-
this.raiseError(`goToDefinition failed - definitionIndex value (${definitionIndex}) exceeds definition list size (${definitions.length})`);
1572-
}
1573-
1574-
const definition = definitions[definitionIndex];
1575-
this.openFile(definition.fileName);
1576-
this.currentCaretPosition = definition.textSpan.start;
1577-
}
1578-
15791625
public goToTypeDefinition(definitionIndex: number) {
15801626
const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
15811627
if (!definitions || !definitions.length) {
@@ -1591,28 +1637,6 @@ namespace FourSlash {
15911637
this.currentCaretPosition = definition.textSpan.start;
15921638
}
15931639

1594-
public verifyDefinitionLocationExists(negative: boolean) {
1595-
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1596-
1597-
const foundDefinitions = definitions && definitions.length;
1598-
1599-
if (foundDefinitions && negative) {
1600-
this.raiseError(`goToDefinition - expected to 0 definition locations but got ${definitions.length}`);
1601-
}
1602-
else if (!foundDefinitions && !negative) {
1603-
this.raiseError("goToDefinition - expected to find at least one definition location but got 0");
1604-
}
1605-
}
1606-
1607-
public verifyDefinitionsCount(negative: boolean, expectedCount: number) {
1608-
const assertFn = negative ? assert.notEqual : assert.equal;
1609-
1610-
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
1611-
const actualCount = definitions && definitions.length || 0;
1612-
1613-
assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Definitions Count"));
1614-
}
1615-
16161640
public verifyTypeDefinitionsCount(negative: boolean, expectedCount: number) {
16171641
const assertFn = negative ? assert.notEqual : assert.equal;
16181642

@@ -1622,25 +1646,23 @@ namespace FourSlash {
16221646
assertFn(actualCount, expectedCount, this.messageAtLastKnownMarker("Type definitions Count"));
16231647
}
16241648

1625-
public verifyDefinitionsName(negative: boolean, expectedName: string, expectedContainerName: string) {
1649+
public verifyGoToDefinitionName(expectedName: string, expectedContainerName: string) {
16261650
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
16271651
const actualDefinitionName = definitions && definitions.length ? definitions[0].name : "";
16281652
const actualDefinitionContainerName = definitions && definitions.length ? definitions[0].containerName : "";
1629-
if (negative) {
1630-
assert.notEqual(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name"));
1631-
assert.notEqual(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
1632-
}
1633-
else {
1634-
assert.equal(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name"));
1635-
assert.equal(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
1636-
}
1653+
assert.equal(actualDefinitionName, expectedName, this.messageAtLastKnownMarker("Definition Info Name"));
1654+
assert.equal(actualDefinitionContainerName, expectedContainerName, this.messageAtLastKnownMarker("Definition Info Container Name"));
16371655
}
16381656

16391657
public getMarkers(): Marker[] {
16401658
// Return a copy of the list
16411659
return this.testData.markers.slice(0);
16421660
}
16431661

1662+
public getMarkerNames(): string[] {
1663+
return Object.keys(this.testData.markerPositions);
1664+
}
1665+
16441666
public getRanges(): Range[] {
16451667
return this.testData.ranges;
16461668
}
@@ -1649,8 +1671,7 @@ namespace FourSlash {
16491671
const result = ts.createMap<Range[]>();
16501672
for (const range of this.getRanges()) {
16511673
const text = this.rangeText(range);
1652-
const ranges = result[text] || (result[text] = []);
1653-
ranges.push(range);
1674+
ts.multiMapAdd(result, text, range);
16541675
}
16551676
return result;
16561677
}
@@ -2743,6 +2764,10 @@ namespace FourSlashInterface {
27432764
return this.state.getMarkers();
27442765
}
27452766

2767+
public markerNames(): string[] {
2768+
return this.state.getMarkerNames();
2769+
}
2770+
27462771
public marker(name?: string): FourSlash.Marker {
27472772
return this.state.getMarkerByName(name);
27482773
}
@@ -2778,10 +2803,6 @@ namespace FourSlashInterface {
27782803
this.state.goToEOF();
27792804
}
27802805

2781-
public definition(definitionIndex = 0) {
2782-
this.state.goToDefinition(definitionIndex);
2783-
}
2784-
27852806
public type(definitionIndex = 0) {
27862807
this.state.goToTypeDefinition(definitionIndex);
27872808
}
@@ -2886,22 +2907,10 @@ namespace FourSlashInterface {
28862907
this.state.verifyQuickInfoExists(this.negative);
28872908
}
28882909

2889-
public definitionCountIs(expectedCount: number) {
2890-
this.state.verifyDefinitionsCount(this.negative, expectedCount);
2891-
}
2892-
28932910
public typeDefinitionCountIs(expectedCount: number) {
28942911
this.state.verifyTypeDefinitionsCount(this.negative, expectedCount);
28952912
}
28962913

2897-
public definitionLocationExists() {
2898-
this.state.verifyDefinitionLocationExists(this.negative);
2899-
}
2900-
2901-
public verifyDefinitionsName(name: string, containerName: string) {
2902-
this.state.verifyDefinitionsName(this.negative, name, containerName);
2903-
}
2904-
29052914
public isValidBraceCompletionAtPosition(openingBrace: string) {
29062915
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
29072916
}
@@ -2945,6 +2954,25 @@ namespace FourSlashInterface {
29452954
this.state.verifyCurrentFileContent(text);
29462955
}
29472956

2957+
public goToDefinitionIs(endMarkers: string | string[]) {
2958+
this.state.verifyGoToDefinitionIs(endMarkers);
2959+
}
2960+
2961+
public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[]): void;
2962+
public goToDefinition(startsAndEnds: [string | string[], string | string[]][]): void;
2963+
public goToDefinition(startsAndEnds: { [startMarkerName: string]: string | string[] }): void;
2964+
public goToDefinition(arg0: any, endMarkerName?: string | string[]) {
2965+
this.state.verifyGoToDefinition(arg0, endMarkerName);
2966+
}
2967+
2968+
public goToDefinitionForMarkers(...markerNames: string[]) {
2969+
this.state.verifyGoToDefinitionForMarkers(markerNames);
2970+
}
2971+
2972+
public goToDefinitionName(name: string, containerName: string) {
2973+
this.state.verifyGoToDefinitionName(name, containerName);
2974+
}
2975+
29482976
public verifyGetEmitOutputForCurrentFile(expected: string): void {
29492977
this.state.verifyGetEmitOutputForCurrentFile(expected);
29502978
}

0 commit comments

Comments
 (0)