Skip to content

Commit

Permalink
Merge branch 'master' into bug/42785
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbranch committed Mar 1, 2021
2 parents a687bae + aa67b16 commit 7597f52
Show file tree
Hide file tree
Showing 42 changed files with 723 additions and 389 deletions.
22 changes: 11 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3266,7 +3266,7 @@ namespace ts {
if (node.name) {
setParent(node.name, node);
}
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations[0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
file.bindDiagnostics.push(createDiagnosticForNode(symbolExport.declarations![0], Diagnostics.Duplicate_identifier_0, symbolName(prototypeSymbol)));
}
symbol.exports!.set(prototypeSymbol.escapedName, prototypeSymbol);
prototypeSymbol.parent = symbol;
Expand Down
5 changes: 4 additions & 1 deletion src/compiler/builderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,17 @@ namespace ts {

// From ambient modules
for (const ambientModule of program.getTypeChecker().getAmbientModules()) {
if (ambientModule.declarations.length > 1) {
if (ambientModule.declarations && ambientModule.declarations.length > 1) {
addReferenceFromAmbientModule(ambientModule);
}
}

return referencedFiles;

function addReferenceFromAmbientModule(symbol: Symbol) {
if (!symbol.declarations) {
return;
}
// Add any file other than our own as reference
for (const declaration of symbol.declarations) {
const declarationSourceFile = getSourceFileOfNode(declaration);
Expand Down
544 changes: 294 additions & 250 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ namespace ts {
return -1;
}

export function countWhere<T>(array: readonly T[], predicate: (x: T, i: number) => boolean): number {
export function countWhere<T>(array: readonly T[] | undefined, predicate: (x: T, i: number) => boolean): number {
let count = 0;
if (array) {
for (let i = 0; i < array.length; i++) {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/moduleSpecifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ namespace ts.moduleSpecifiers {
}

function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol, checker: TypeChecker): string | undefined {
const decl = find(moduleSymbol.declarations,
const decl = moduleSymbol.declarations?.find(
d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name)))
) as (ModuleDeclaration & { name: StringLiteral }) | undefined;
if (decl) {
Expand Down
14 changes: 8 additions & 6 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,13 +206,15 @@ namespace ts {
}

function reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, symbol: Symbol) {
const primaryDeclaration = find(parentSymbol.declarations, d => getSourceFileOfNode(d) === containingFile)!;
const primaryDeclaration = parentSymbol.declarations?.find(d => getSourceFileOfNode(d) === containingFile)!;
const augmentingDeclarations = filter(symbol.declarations, d => getSourceFileOfNode(d) !== containingFile);
for (const augmentations of augmentingDeclarations) {
context.addDiagnostic(addRelatedInfo(
createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized),
createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file)
));
if (augmentingDeclarations) {
for (const augmentations of augmentingDeclarations) {
context.addDiagnostic(addRelatedInfo(
createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized),
createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file)
));
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4165,6 +4165,7 @@ namespace ts {
/* @internal */ createSymbol(flags: SymbolFlags, name: __String): TransientSymbol;
/* @internal */ createIndexInfo(type: Type, isReadonly: boolean, declaration?: SignatureDeclaration): IndexInfo;
/* @internal */ isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult;
/* @internal */ tryFindAmbientModule(moduleName: string): Symbol | undefined;
/* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol | undefined;

/* @internal */ getSymbolWalker(accept?: (symbol: Symbol) => boolean): SymbolWalker;
Expand Down Expand Up @@ -4713,7 +4714,7 @@ namespace ts {
export interface Symbol {
flags: SymbolFlags; // Symbol flags
escapedName: __String; // Name of symbol
declarations: Declaration[]; // Declarations associated with this symbol
declarations?: Declaration[]; // Declarations associated with this symbol
valueDeclaration: Declaration; // First value declaration of the symbol
members?: SymbolTable; // Class, interface or object literal instance members
exports?: SymbolTable; // Module exports
Expand Down
8 changes: 4 additions & 4 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ namespace ts {
}

export function getNonAugmentationDeclaration(symbol: Symbol) {
return find(symbol.declarations, d => !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d)));
return symbol.declarations?.find(d => !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d)));
}

export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) {
Expand Down Expand Up @@ -4888,15 +4888,15 @@ namespace ts {
}

export function getLocalSymbolForExportDefault(symbol: Symbol) {
if (!isExportDefaultSymbol(symbol)) return undefined;
if (!isExportDefaultSymbol(symbol) || !symbol.declarations) return undefined;
for (const decl of symbol.declarations) {
if (decl.localSymbol) return decl.localSymbol;
}
return undefined;
}

function isExportDefaultSymbol(symbol: Symbol): boolean {
return symbol && length(symbol.declarations) > 0 && hasSyntacticModifier(symbol.declarations[0], ModifierFlags.Default);
return symbol && length(symbol.declarations) > 0 && hasSyntacticModifier(symbol.declarations![0], ModifierFlags.Default);
}

/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
Expand Down Expand Up @@ -5445,7 +5445,7 @@ namespace ts {
}

export function getClassLikeDeclarationOfSymbol(symbol: Symbol): ClassLikeDeclaration | undefined {
return find(symbol.declarations, isClassLike);
return symbol.declarations?.find(isClassLike);
}

export function getObjectFlags(type: Type): ObjectFlags {
Expand Down
17 changes: 8 additions & 9 deletions src/harness/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,9 @@ namespace ts.server {
isNewIdentifierLocation: false,
entries: response.body!.map<CompletionEntry>(entry => { // TODO: GH#18217
if (entry.replacementSpan !== undefined) {
const { name, kind, kindModifiers, sortText, replacementSpan, hasAction, source, isRecommended } = entry;
const { name, kind, kindModifiers, sortText, replacementSpan, hasAction, source, data, isRecommended } = entry;
// TODO: GH#241
const res: CompletionEntry = { name, kind, kindModifiers, sortText, replacementSpan: this.decodeSpan(replacementSpan, fileName), hasAction, source, isRecommended };
const res: CompletionEntry = { name, kind, kindModifiers, sortText, replacementSpan: this.decodeSpan(replacementSpan, fileName), hasAction, source, data: data as any, isRecommended };
return res;
}

Expand All @@ -216,14 +216,13 @@ namespace ts.server {
};
}

getCompletionEntryDetails(fileName: string, position: number, entryName: string, _options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined): CompletionEntryDetails {
const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [{ name: entryName, source }] };
getCompletionEntryDetails(fileName: string, position: number, entryName: string, _options: FormatCodeOptions | FormatCodeSettings | undefined, source: string | undefined, _preferences: UserPreferences | undefined, data: unknown): CompletionEntryDetails {
const args: protocol.CompletionDetailsRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), entryNames: [{ name: entryName, source, data }] };

const request = this.processRequest<protocol.CompletionDetailsRequest>(CommandNames.CompletionDetails, args);
const response = this.processResponse<protocol.CompletionDetailsResponse>(request);
Debug.assert(response.body!.length === 1, "Unexpected length of completion details response body.");
const convertedCodeActions = map(response.body![0].codeActions, ({ description, changes }) => ({ description, changes: this.convertChanges(changes, fileName) }));
return { ...response.body![0], codeActions: convertedCodeActions };
const request = this.processRequest<protocol.CompletionDetailsRequest>(CommandNames.CompletionDetailsFull, args);
const response = this.processResponse<protocol.Response>(request);
Debug.assert(response.body.length === 1, "Unexpected length of completion details response body.");
return response.body[0];
}

getCompletionEntrySymbol(_fileName: string, _position: number, _entryName: string): Symbol {
Expand Down
32 changes: 21 additions & 11 deletions src/harness/fourslashImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ namespace FourSlash {
}
const memo = Utils.memoize(
(_version: number, _active: string, _caret: number, _selectEnd: number, _marker: string, ...args: any[]) => (ls[key] as Function)(...args),
(...args) => args.join("|,|")
(...args) => args.map(a => a && typeof a === "object" ? JSON.stringify(a) : a).join("|,|")
);
proxy[key] = (...args: any[]) => memo(
target.languageServiceAdapterHost.getScriptInfo(target.activeFile.fileName)!.version,
Expand Down Expand Up @@ -867,7 +867,7 @@ namespace FourSlash {
nameToEntries.set(entry.name, [entry]);
}
else {
if (entries.some(e => e.source === entry.source)) {
if (entries.some(e => e.source === entry.source && this.deepEqual(e.data, entry.data))) {
this.raiseError(`Duplicate completions for ${entry.name}`);
}
entries.push(entry);
Expand All @@ -885,8 +885,8 @@ namespace FourSlash {
const name = typeof include === "string" ? include : include.name;
const found = nameToEntries.get(name);
if (!found) throw this.raiseError(`Includes: completion '${name}' not found.`);
assert(found.length === 1, `Must use 'exact' for multiple completions with same name: '${name}'`);
this.verifyCompletionEntry(ts.first(found), include);
if (!found.length) throw this.raiseError(`Includes: no completions with name '${name}' remain unmatched.`);
this.verifyCompletionEntry(found.shift()!, include);
}
}
if (options.excludes) {
Expand Down Expand Up @@ -933,7 +933,7 @@ namespace FourSlash {
assert.equal(actual.sortText, expected.sortText || ts.Completions.SortText.LocationPriority, this.messageAtLastKnownMarker(`Actual entry: ${JSON.stringify(actual)}`));

if (expected.text !== undefined) {
const actualDetails = ts.Debug.checkDefined(this.getCompletionEntryDetails(actual.name, actual.source), `No completion details available for name '${actual.name}' and source '${actual.source}'`);
const actualDetails = ts.Debug.checkDefined(this.getCompletionEntryDetails(actual.name, actual.source, actual.data), `No completion details available for name '${actual.name}' and source '${actual.source}'`);
assert.equal(ts.displayPartsToString(actualDetails.displayParts), expected.text, "Expected 'text' property to match 'displayParts' string");
assert.equal(ts.displayPartsToString(actualDetails.documentation), expected.documentation || "", "Expected 'documentation' property to match 'documentation' display parts string");
// TODO: GH#23587
Expand Down Expand Up @@ -1003,8 +1003,8 @@ namespace FourSlash {

private verifySymbol(symbol: ts.Symbol, declarationRanges: Range[]) {
const { declarations } = symbol;
if (declarations.length !== declarationRanges.length) {
this.raiseError(`Expected to get ${declarationRanges.length} declarations, got ${declarations.length}`);
if (declarations?.length !== declarationRanges.length) {
this.raiseError(`Expected to get ${declarationRanges.length} declarations, got ${declarations?.length}`);
}

ts.zipWith(declarations, declarationRanges, (decl, range) => {
Expand Down Expand Up @@ -1254,6 +1254,16 @@ namespace FourSlash {

}

private deepEqual(a: unknown, b: unknown) {
try {
this.assertObjectsEqual(a, b);
return true;
}
catch {
return false;
}
}

public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
const referencedSymbols = this.findReferencesAtCaret()!;

Expand Down Expand Up @@ -1281,11 +1291,11 @@ namespace FourSlash {
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, options);
}

private getCompletionEntryDetails(entryName: string, source?: string, preferences?: ts.UserPreferences): ts.CompletionEntryDetails | undefined {
private getCompletionEntryDetails(entryName: string, source: string | undefined, data: ts.CompletionEntryData | undefined, preferences?: ts.UserPreferences): ts.CompletionEntryDetails | undefined {
if (preferences) {
this.configure(preferences);
}
return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source, preferences);
return this.languageService.getCompletionEntryDetails(this.activeFile.fileName, this.currentCaretPosition, entryName, this.formatCodeSettings, source, preferences, data);
}

private getReferencesAtCaret() {
Expand Down Expand Up @@ -2796,14 +2806,14 @@ namespace FourSlash {
public applyCodeActionFromCompletion(markerName: string, options: FourSlashInterface.VerifyCompletionActionOptions) {
this.goToMarker(markerName);

const details = this.getCompletionEntryDetails(options.name, options.source, options.preferences);
const details = this.getCompletionEntryDetails(options.name, options.source, options.data, options.preferences);
if (!details) {
const completions = this.getCompletionListAtCaret(options.preferences)?.entries;
const matchingName = completions?.filter(e => e.name === options.name);
const detailMessage = matchingName?.length
? `\n Found ${matchingName.length} with name '${options.name}' from source(s) ${matchingName.map(e => `'${e.source}'`).join(", ")}.`
: ` (In fact, there were no completions with name '${options.name}' at all.)`;
return this.raiseError(`No completions were found for the given name, source, and preferences.` + detailMessage);
return this.raiseError(`No completions were found for the given name, source/data, and preferences.` + detailMessage);
}
const codeActions = details.codeActions;
if (codeActions?.length !== 1) {
Expand Down
1 change: 1 addition & 0 deletions src/harness/fourslashInterfaceImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,7 @@ namespace FourSlashInterface {
export interface VerifyCompletionActionOptions extends NewContentOptions {
name: string;
source?: string;
data?: ts.CompletionEntryData;
description: string;
preferences?: ts.UserPreferences;
}
Expand Down
Loading

0 comments on commit 7597f52

Please sign in to comment.