mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #14001 from Microsoft/refactor_findallrefs
Refactor findAllReferences. Now supports renamed exports and imports.
This commit is contained in:
@@ -41,6 +41,7 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
|
||||
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
|
||||
string: ["browser", "tests", "host", "reporter", "stackTraceLimit"],
|
||||
alias: {
|
||||
b: "browser",
|
||||
d: "debug",
|
||||
t: "tests",
|
||||
test: "tests",
|
||||
|
||||
+51
-41
@@ -81,6 +81,7 @@ namespace ts {
|
||||
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
|
||||
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
|
||||
isUnknownSymbol: symbol => symbol === unknownSymbol,
|
||||
getMergedSymbol,
|
||||
getDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
getTypeOfSymbolAtLocation: (symbol, location) => {
|
||||
@@ -172,6 +173,17 @@ namespace ts {
|
||||
node = getParseTreeNode(node, isFunctionLike);
|
||||
return node ? isImplementationOfOverload(node) : undefined;
|
||||
},
|
||||
getImmediateAliasedSymbol: symbol => {
|
||||
Debug.assert((symbol.flags & SymbolFlags.Alias) !== 0, "Should only get Alias here.");
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.immediateTarget) {
|
||||
const node = getDeclarationOfAliasSymbol(symbol);
|
||||
Debug.assert(!!node);
|
||||
links.immediateTarget = getTargetOfAliasDeclaration(node, /*dontRecursivelyResolve*/ true);
|
||||
}
|
||||
|
||||
return links.immediateTarget;
|
||||
},
|
||||
getAliasedSymbol: resolveAlias,
|
||||
getEmitResolver,
|
||||
getExportsOfModule: getExportsOfModuleAsArray,
|
||||
@@ -1272,14 +1284,14 @@ namespace ts {
|
||||
return find<Declaration>(symbol.declarations, isAliasSymbolDeclaration);
|
||||
}
|
||||
|
||||
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
|
||||
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration, dontResolveAlias: boolean): Symbol {
|
||||
if (node.moduleReference.kind === SyntaxKind.ExternalModuleReference) {
|
||||
return resolveExternalModuleSymbol(resolveExternalModuleName(node, getExternalModuleImportEqualsDeclarationExpression(node)));
|
||||
}
|
||||
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>node.moduleReference);
|
||||
return getSymbolOfPartOfRightHandSideOfImportEquals(<EntityName>node.moduleReference, dontResolveAlias);
|
||||
}
|
||||
|
||||
function getTargetOfImportClause(node: ImportClause): Symbol {
|
||||
function getTargetOfImportClause(node: ImportClause, dontResolveAlias: boolean): Symbol {
|
||||
const moduleSymbol = resolveExternalModuleName(node, (<ImportDeclaration>node.parent).moduleSpecifier);
|
||||
|
||||
if (moduleSymbol) {
|
||||
@@ -1291,22 +1303,22 @@ namespace ts {
|
||||
const exportValue = moduleSymbol.exports.get("export=");
|
||||
exportDefaultSymbol = exportValue
|
||||
? getPropertyOfType(getTypeOfSymbol(exportValue), "default")
|
||||
: resolveSymbol(moduleSymbol.exports.get("default"));
|
||||
: resolveSymbol(moduleSymbol.exports.get("default"), dontResolveAlias);
|
||||
}
|
||||
|
||||
if (!exportDefaultSymbol && !allowSyntheticDefaultImports) {
|
||||
error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol));
|
||||
}
|
||||
else if (!exportDefaultSymbol && allowSyntheticDefaultImports) {
|
||||
return resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
|
||||
return resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
|
||||
}
|
||||
return exportDefaultSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetOfNamespaceImport(node: NamespaceImport): Symbol {
|
||||
function getTargetOfNamespaceImport(node: NamespaceImport, dontResolveAlias: boolean): Symbol {
|
||||
const moduleSpecifier = (<ImportDeclaration>node.parent.parent).moduleSpecifier;
|
||||
return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier);
|
||||
return resolveESModuleSymbol(resolveExternalModuleName(node, moduleSpecifier), moduleSpecifier, dontResolveAlias);
|
||||
}
|
||||
|
||||
// This function creates a synthetic symbol that combines the value side of one symbol with the
|
||||
@@ -1340,12 +1352,9 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getExportOfModule(symbol: Symbol, name: string): Symbol {
|
||||
function getExportOfModule(symbol: Symbol, name: string, dontResolveAlias: boolean): Symbol {
|
||||
if (symbol.flags & SymbolFlags.Module) {
|
||||
const exportedSymbol = getExportsOfSymbol(symbol).get(name);
|
||||
if (exportedSymbol) {
|
||||
return resolveSymbol(exportedSymbol);
|
||||
}
|
||||
return resolveSymbol(getExportsOfSymbol(symbol).get(name), dontResolveAlias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1358,9 +1367,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier): Symbol {
|
||||
function getExternalModuleMember(node: ImportDeclaration | ExportDeclaration, specifier: ImportOrExportSpecifier, dontResolveAlias?: boolean): Symbol {
|
||||
const moduleSymbol = resolveExternalModuleName(node, node.moduleSpecifier);
|
||||
const targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier);
|
||||
const targetSymbol = resolveESModuleSymbol(moduleSymbol, node.moduleSpecifier, dontResolveAlias);
|
||||
if (targetSymbol) {
|
||||
const name = specifier.propertyName || specifier.name;
|
||||
if (name.text) {
|
||||
@@ -1377,11 +1386,11 @@ namespace ts {
|
||||
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text);
|
||||
}
|
||||
// if symbolFromVariable is export - get its final target
|
||||
symbolFromVariable = resolveSymbol(symbolFromVariable);
|
||||
let symbolFromModule = getExportOfModule(targetSymbol, name.text);
|
||||
symbolFromVariable = resolveSymbol(symbolFromVariable, dontResolveAlias);
|
||||
let symbolFromModule = getExportOfModule(targetSymbol, name.text, dontResolveAlias);
|
||||
// If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default
|
||||
if (!symbolFromModule && allowSyntheticDefaultImports && name.text === "default") {
|
||||
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
|
||||
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
|
||||
}
|
||||
const symbol = symbolFromModule && symbolFromVariable ?
|
||||
combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
|
||||
@@ -1394,45 +1403,46 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getTargetOfImportSpecifier(node: ImportSpecifier): Symbol {
|
||||
return getExternalModuleMember(<ImportDeclaration>node.parent.parent.parent, node);
|
||||
function getTargetOfImportSpecifier(node: ImportSpecifier, dontResolveAlias: boolean): Symbol {
|
||||
return getExternalModuleMember(<ImportDeclaration>node.parent.parent.parent, node, dontResolveAlias);
|
||||
}
|
||||
|
||||
function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration): Symbol {
|
||||
return resolveExternalModuleSymbol(node.parent.symbol);
|
||||
function getTargetOfNamespaceExportDeclaration(node: NamespaceExportDeclaration, dontResolveAlias: boolean): Symbol {
|
||||
return resolveExternalModuleSymbol(node.parent.symbol, dontResolveAlias);
|
||||
}
|
||||
|
||||
function getTargetOfExportSpecifier(node: ExportSpecifier): Symbol {
|
||||
function getTargetOfExportSpecifier(node: ExportSpecifier, dontResolveAlias?: boolean): Symbol {
|
||||
return (<ExportDeclaration>node.parent.parent).moduleSpecifier ?
|
||||
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node) :
|
||||
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
|
||||
getExternalModuleMember(<ExportDeclaration>node.parent.parent, node, dontResolveAlias) :
|
||||
resolveEntityName(node.propertyName || node.name, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
|
||||
}
|
||||
|
||||
function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
|
||||
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
|
||||
function getTargetOfExportAssignment(node: ExportAssignment, dontResolveAlias: boolean): Symbol {
|
||||
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace, /*ignoreErrors*/ false, dontResolveAlias);
|
||||
}
|
||||
|
||||
function getTargetOfAliasDeclaration(node: Declaration): Symbol {
|
||||
function getTargetOfAliasDeclaration(node: Declaration, dontRecursivelyResolve?: boolean): Symbol {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return getTargetOfImportEqualsDeclaration(<ImportEqualsDeclaration>node);
|
||||
return getTargetOfImportEqualsDeclaration(<ImportEqualsDeclaration>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.ImportClause:
|
||||
return getTargetOfImportClause(<ImportClause>node);
|
||||
return getTargetOfImportClause(<ImportClause>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return getTargetOfNamespaceImport(<NamespaceImport>node);
|
||||
return getTargetOfNamespaceImport(<NamespaceImport>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
return getTargetOfImportSpecifier(<ImportSpecifier>node);
|
||||
return getTargetOfImportSpecifier(<ImportSpecifier>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return getTargetOfExportSpecifier(<ExportSpecifier>node);
|
||||
return getTargetOfExportSpecifier(<ExportSpecifier>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return getTargetOfExportAssignment(<ExportAssignment>node);
|
||||
return getTargetOfExportAssignment(<ExportAssignment>node, dontRecursivelyResolve);
|
||||
case SyntaxKind.NamespaceExportDeclaration:
|
||||
return getTargetOfNamespaceExportDeclaration(<NamespaceExportDeclaration>node);
|
||||
return getTargetOfNamespaceExportDeclaration(<NamespaceExportDeclaration>node, dontRecursivelyResolve);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveSymbol(symbol: Symbol): Symbol {
|
||||
return symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)) ? resolveAlias(symbol) : symbol;
|
||||
function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol {
|
||||
const shouldResolve = !dontResolveAlias && symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace));
|
||||
return shouldResolve ? resolveAlias(symbol) : symbol;
|
||||
}
|
||||
|
||||
function resolveAlias(symbol: Symbol): Symbol {
|
||||
@@ -1672,16 +1682,16 @@ namespace ts {
|
||||
|
||||
// An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
|
||||
// and an external module with no 'export =' declaration resolves to the module itself.
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol): Symbol {
|
||||
return moduleSymbol && getMergedSymbol(resolveSymbol(moduleSymbol.exports.get("export="))) || moduleSymbol;
|
||||
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
|
||||
return moduleSymbol && getMergedSymbol(resolveSymbol(moduleSymbol.exports.get("export="), dontResolveAlias)) || moduleSymbol;
|
||||
}
|
||||
|
||||
// An external module with an 'export =' declaration may be referenced as an ES6 module provided the 'export ='
|
||||
// references a symbol that is at least declared as a module or a variable. The target of the 'export =' may
|
||||
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
|
||||
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression): Symbol {
|
||||
let symbol = resolveExternalModuleSymbol(moduleSymbol);
|
||||
if (symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
|
||||
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression, dontResolveAlias: boolean): Symbol {
|
||||
let symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias);
|
||||
if (!dontResolveAlias && symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
|
||||
error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
|
||||
symbol = undefined;
|
||||
}
|
||||
|
||||
@@ -887,10 +887,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Shims `Array.from`. */
|
||||
export function arrayFrom<T>(iterator: Iterator<T>): T[] {
|
||||
const result: T[] = [];
|
||||
export function arrayFrom<T, U>(iterator: Iterator<T>, map: (t: T) => U): U[];
|
||||
export function arrayFrom<T>(iterator: Iterator<T>): T[];
|
||||
export function arrayFrom(iterator: Iterator<any>, map?: (t: any) => any): any[] {
|
||||
const result: any[] = [];
|
||||
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
|
||||
result.push(value);
|
||||
result.push(map ? map(value) : value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -458,6 +458,7 @@ namespace ts {
|
||||
return Parser.parseIsolatedEntityName(text, languageVersion);
|
||||
}
|
||||
|
||||
// See also `isExternalOrCommonJsModule` in utilities.ts
|
||||
export function isExternalModule(file: SourceFile): boolean {
|
||||
return file.externalModuleIndicator !== undefined;
|
||||
}
|
||||
|
||||
@@ -1886,6 +1886,7 @@ namespace ts {
|
||||
kind: SyntaxKind.ImportDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
importClause?: ImportClause;
|
||||
/** If this is not a StringLiteral it will be a grammar error. */
|
||||
moduleSpecifier: Expression;
|
||||
}
|
||||
|
||||
@@ -1919,6 +1920,7 @@ namespace ts {
|
||||
kind: SyntaxKind.ExportDeclaration;
|
||||
parent?: SourceFile | ModuleBlock;
|
||||
exportClause?: NamedExports;
|
||||
/** If this is not a StringLiteral it will be a grammar error. */
|
||||
moduleSpecifier?: Expression;
|
||||
}
|
||||
|
||||
@@ -2305,8 +2307,8 @@ namespace ts {
|
||||
// Content of this field should never be used directly - use getResolvedModuleFileName/setResolvedModuleFileName functions instead
|
||||
/* @internal */ resolvedModules: Map<ResolvedModuleFull>;
|
||||
/* @internal */ resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
|
||||
/* @internal */ imports: LiteralExpression[];
|
||||
/* @internal */ moduleAugmentations: LiteralExpression[];
|
||||
/* @internal */ imports: StringLiteral[];
|
||||
/* @internal */ moduleAugmentations: StringLiteral[];
|
||||
/* @internal */ patternAmbientModules?: PatternAmbientModule[];
|
||||
/* @internal */ ambientModuleNames: string[];
|
||||
/* @internal */ checkJsDirective: CheckJsDirective | undefined;
|
||||
@@ -2522,10 +2524,14 @@ namespace ts {
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isUnknownSymbol(symbol: Symbol): boolean;
|
||||
/* @internal */ getMergedSymbol(symbol: Symbol): Symbol;
|
||||
|
||||
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
|
||||
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
|
||||
/** Follow all aliases to get the original symbol. */
|
||||
getAliasedSymbol(symbol: Symbol): Symbol;
|
||||
/** Follow a *single* alias to get the immediately aliased symbol. */
|
||||
/* @internal */ getImmediateAliasedSymbol(symbol: Symbol): Symbol;
|
||||
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
|
||||
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
|
||||
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
|
||||
@@ -2841,6 +2847,7 @@ namespace ts {
|
||||
|
||||
/* @internal */
|
||||
export interface SymbolLinks {
|
||||
immediateTarget?: Symbol; // Immediate target of an alias. May be another alias. Do not access directly, use `checker.getImmediateAliasedSymbol` instead.
|
||||
target?: Symbol; // Resolved (non-alias) target of an alias
|
||||
type?: Type; // Type of value symbol
|
||||
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
|
||||
|
||||
@@ -3134,7 +3134,7 @@ namespace ts {
|
||||
return isExportDefaultSymbol(symbol) ? symbol.valueDeclaration.localSymbol : undefined;
|
||||
}
|
||||
|
||||
export function isExportDefaultSymbol(symbol: Symbol): boolean {
|
||||
function isExportDefaultSymbol(symbol: Symbol): boolean {
|
||||
return symbol && symbol.valueDeclaration && hasModifier(symbol.valueDeclaration, ModifierFlags.Default);
|
||||
}
|
||||
|
||||
|
||||
+122
-22
@@ -549,10 +549,21 @@ namespace FourSlash {
|
||||
Harness.IO.log("Unexpected error(s) found. Error list is:");
|
||||
}
|
||||
|
||||
errors.forEach(function (error: ts.Diagnostic) {
|
||||
Harness.IO.log(" minChar: " + error.start +
|
||||
", limChar: " + (error.start + error.length) +
|
||||
", message: " + ts.flattenDiagnosticMessageText(error.messageText, Harness.IO.newLine()) + "\n");
|
||||
for (const { start, length, messageText } of errors) {
|
||||
Harness.IO.log(" minChar: " + start +
|
||||
", limChar: " + (start + length) +
|
||||
", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
public verifyNoErrors() {
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
const errors = this.getDiagnostics(fileName);
|
||||
if (errors.length) {
|
||||
this.printErrorLog(/*expectErrors*/ false, errors);
|
||||
const error = errors[0];
|
||||
this.raiseError(`Found an error: ${error.file.fileName}@${error.start}: ${error.messageText}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -882,7 +893,68 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyReferencesAre(expectedReferences: Range[]) {
|
||||
/** Use `getProgram` instead of accessing this directly. */
|
||||
private _program: ts.Program;
|
||||
/** Use `getChecker` instead of accessing this directly. */
|
||||
private _checker: ts.TypeChecker;
|
||||
|
||||
private getProgram(): ts.Program {
|
||||
return this._program || (this._program = this.languageService.getProgram());
|
||||
}
|
||||
|
||||
private getChecker() {
|
||||
return this._checker || (this._checker = this.getProgram().getTypeChecker());
|
||||
}
|
||||
|
||||
private getSourceFile(): ts.SourceFile {
|
||||
const { fileName } = this.activeFile;
|
||||
const result = this.getProgram().getSourceFile(fileName);
|
||||
if (!result) {
|
||||
throw new Error(`Could not get source file ${fileName}`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private getNode(): ts.Node {
|
||||
return ts.getTouchingPropertyName(this.getSourceFile(), this.currentCaretPosition);
|
||||
}
|
||||
|
||||
private goToAndGetNode(range: Range): ts.Node {
|
||||
this.goToRangeStart(range);
|
||||
const node = this.getNode();
|
||||
this.verifyRange("touching property name", range, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
private verifyRange(desc: string, expected: Range, actual: ts.Node) {
|
||||
const actualStart = actual.getStart();
|
||||
const actualEnd = actual.getEnd();
|
||||
if (actualStart !== expected.start || actualEnd !== expected.end) {
|
||||
this.raiseError(`${desc} should be ${expected.start}-${expected.end}, got ${actualStart}-${actualEnd}`);
|
||||
}
|
||||
}
|
||||
|
||||
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}`);
|
||||
}
|
||||
|
||||
ts.zipWith(declarations, declarationRanges, (decl, range) => {
|
||||
this.verifyRange("symbol declaration", range, decl);
|
||||
});
|
||||
}
|
||||
|
||||
public verifySymbolAtLocation(startRange: Range, declarationRanges: Range[]): void {
|
||||
const node = this.goToAndGetNode(startRange);
|
||||
const symbol = this.getChecker().getSymbolAtLocation(node);
|
||||
if (!symbol) {
|
||||
this.raiseError("Could not get symbol at location");
|
||||
}
|
||||
this.verifySymbol(symbol, declarationRanges);
|
||||
}
|
||||
|
||||
private verifyReferencesAre(expectedReferences: Range[]) {
|
||||
const actualReferences = this.getReferencesAtCaret() || [];
|
||||
|
||||
if (actualReferences.length > expectedReferences.length) {
|
||||
@@ -928,7 +1000,7 @@ namespace FourSlash {
|
||||
|
||||
for (const startRange of toArray(startRanges)) {
|
||||
this.goToRangeStart(startRange);
|
||||
const fullActual = this.findReferencesAtCaret().map<ReferenceJson>(({ definition, references }) => ({
|
||||
const fullActual = ts.map<ts.ReferencedSymbol, ReferenceJson>(this.findReferencesAtCaret(), ({ definition, references }) => ({
|
||||
definition: definition.displayParts.map(d => d.text).join(""),
|
||||
ranges: references
|
||||
}));
|
||||
@@ -1108,9 +1180,32 @@ namespace FourSlash {
|
||||
});
|
||||
}
|
||||
|
||||
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
|
||||
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
|
||||
if (renameInfo.canRename) {
|
||||
public verifyRangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }) {
|
||||
const ranges = ts.isArray(options) ? options : options && options.ranges || this.getRanges();
|
||||
this.verifyRenameLocations(ranges, { ranges, ...options });
|
||||
}
|
||||
|
||||
public verifyRenameLocations(startRanges: Range | Range[], options: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: Range[] }) {
|
||||
let findInStrings: boolean, findInComments: boolean, ranges: Range[];
|
||||
if (ts.isArray(options)) {
|
||||
findInStrings = findInComments = false;
|
||||
ranges = options;
|
||||
}
|
||||
else {
|
||||
findInStrings = !!options.findInStrings;
|
||||
findInComments = !!options.findInComments;
|
||||
ranges = options.ranges;
|
||||
}
|
||||
|
||||
for (const startRange of toArray(startRanges)) {
|
||||
this.goToRangeStart(startRange);
|
||||
|
||||
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
|
||||
if (!renameInfo.canRename) {
|
||||
this.raiseError("Expected rename to succeed, but it actually failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
let references = this.languageService.findRenameLocations(
|
||||
this.activeFile.fileName, this.currentCaretPosition, findInStrings, findInComments);
|
||||
|
||||
@@ -1132,13 +1227,10 @@ namespace FourSlash {
|
||||
|
||||
ts.zipWith(references, ranges, (reference, range) => {
|
||||
if (reference.textSpan.start !== range.start || ts.textSpanEnd(reference.textSpan) !== range.end) {
|
||||
this.raiseError("Rename location results do not match.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + JSON.stringify(references));
|
||||
this.raiseError("Rename location results do not match.\n\nExpected: " + stringify(ranges) + "\n\nActual:" + stringify(references));
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.raiseError("Expected rename to succeed, but it actually failed.");
|
||||
}
|
||||
}
|
||||
|
||||
public verifyQuickInfoExists(negative: boolean) {
|
||||
@@ -2551,8 +2643,8 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesAreRenameLocations(findInStrings: boolean, findInComments: boolean) {
|
||||
this.goToEachRange(() => this.verifyRenameLocations(findInStrings, findInComments));
|
||||
public verifyRangesWithSameTextAreRenameLocations() {
|
||||
this.rangesByText().forEach(ranges => this.verifyRangesAreRenameLocations(ranges));
|
||||
}
|
||||
|
||||
public verifyRangesWithSameTextAreDocumentHighlights() {
|
||||
@@ -2591,7 +2683,7 @@ namespace FourSlash {
|
||||
|
||||
ts.zipWith(expectedRangesInFile, spansInFile, (expectedRange, span) => {
|
||||
if (span.textSpan.start !== expectedRange.start || ts.textSpanEnd(span.textSpan) !== expectedRange.end) {
|
||||
this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${JSON.stringify(span.textSpan)}, expected: ${expectedRange.start}--${expectedRange.end}`);
|
||||
this.raiseError(`verifyDocumentHighlights failed - span does not match, actual: ${stringify(span.textSpan)}, expected: ${expectedRange.start}--${expectedRange.end}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -3495,8 +3587,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifyGetEmitOutputContentsForCurrentFile(expected);
|
||||
}
|
||||
|
||||
public referencesAre(ranges: FourSlash.Range[]) {
|
||||
this.state.verifyReferencesAre(ranges);
|
||||
public symbolAtLocation(startRange: FourSlash.Range, ...declarationRanges: FourSlash.Range[]) {
|
||||
this.state.verifySymbolAtLocation(startRange, declarationRanges);
|
||||
}
|
||||
|
||||
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
|
||||
@@ -3563,6 +3655,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifyCurrentSignatureHelpIs(expected);
|
||||
}
|
||||
|
||||
public noErrors() {
|
||||
this.state.verifyNoErrors();
|
||||
}
|
||||
|
||||
public numberOfErrorsInCurrentFile(expected: number) {
|
||||
this.state.verifyNumberOfErrorsInCurrentFile(expected);
|
||||
}
|
||||
@@ -3659,8 +3755,12 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRangesAreOccurrences(isWriteAccess);
|
||||
}
|
||||
|
||||
public rangesAreRenameLocations(findInStrings = false, findInComments = false) {
|
||||
this.state.verifyRangesAreRenameLocations(findInStrings, findInComments);
|
||||
public rangesWithSameTextAreRenameLocations() {
|
||||
this.state.verifyRangesWithSameTextAreRenameLocations();
|
||||
}
|
||||
|
||||
public rangesAreRenameLocations(options?: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: FourSlash.Range[] }) {
|
||||
this.state.verifyRangesAreRenameLocations(options);
|
||||
}
|
||||
|
||||
public rangesAreDocumentHighlights(ranges?: FourSlash.Range[]) {
|
||||
@@ -3697,8 +3797,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRenameInfoFailed(message);
|
||||
}
|
||||
|
||||
public renameLocations(findInStrings: boolean, findInComments: boolean, ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRenameLocations(findInStrings, findInComments, ranges);
|
||||
public renameLocations(startRanges: FourSlash.Range | FourSlash.Range[], options: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: FourSlash.Range[] }) {
|
||||
this.state.verifyRenameLocations(startRanges, options);
|
||||
}
|
||||
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
|
||||
|
||||
@@ -17,34 +17,22 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
|
||||
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
|
||||
const context = new FindAllReferences.DefaultFindReferencesContext(typeChecker, cancellationToken);
|
||||
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(context, node, sourceFilesToSearch);
|
||||
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
|
||||
const referenceEntries = FindAllReferences.getReferenceEntriesForNode(node, sourceFilesToSearch, typeChecker, cancellationToken);
|
||||
return referenceEntries && convertReferencedSymbols(referenceEntries);
|
||||
}
|
||||
|
||||
function convertReferencedSymbols(referencedSymbols: ReferencedSymbol[]): DocumentHighlights[] {
|
||||
const fileNameToDocumentHighlights = createMap<DocumentHighlights>();
|
||||
const result: DocumentHighlights[] = [];
|
||||
for (const referencedSymbol of referencedSymbols) {
|
||||
for (const referenceEntry of referencedSymbol.references) {
|
||||
const fileName = referenceEntry.fileName;
|
||||
let documentHighlights = fileNameToDocumentHighlights.get(fileName);
|
||||
if (!documentHighlights) {
|
||||
documentHighlights = { fileName, highlightSpans: [] };
|
||||
|
||||
fileNameToDocumentHighlights.set(fileName, documentHighlights);
|
||||
result.push(documentHighlights);
|
||||
}
|
||||
|
||||
documentHighlights.highlightSpans.push({
|
||||
textSpan: referenceEntry.textSpan,
|
||||
kind: referenceEntry.isWriteAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference,
|
||||
isInString: referenceEntry.isInString
|
||||
});
|
||||
function convertReferencedSymbols(referenceEntries: FindAllReferences.Entry[]): DocumentHighlights[] {
|
||||
const fileNameToDocumentHighlights = createMap<HighlightSpan[]>();
|
||||
for (const entry of referenceEntries) {
|
||||
const { fileName, span } = FindAllReferences.toHighlightSpan(entry);
|
||||
let highlightSpans = fileNameToDocumentHighlights.get(fileName);
|
||||
if (!highlightSpans) {
|
||||
fileNameToDocumentHighlights.set(fileName, highlightSpans = []);
|
||||
}
|
||||
highlightSpans.push(span);
|
||||
}
|
||||
|
||||
return result;
|
||||
return arrayFrom(fileNameToDocumentHighlights.entries(), ([fileName, highlightSpans ]) => ({ fileName, highlightSpans }));
|
||||
}
|
||||
|
||||
function getSyntacticDocumentHighlights(node: Node, sourceFile: SourceFile): DocumentHighlights[] {
|
||||
|
||||
+870
-654
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,567 @@
|
||||
/* Code for finding imports of an exported symbol. Used only by FindAllReferences. */
|
||||
/* @internal */
|
||||
namespace ts.FindAllReferences {
|
||||
export interface ImportsResult {
|
||||
/** For every import of the symbol, the location and local symbol for the import. */
|
||||
importSearches: Array<[Identifier, Symbol]>;
|
||||
/** For rename imports/exports `{ foo as bar }`, `foo` is not a local, so it may be added as a reference immediately without further searching. */
|
||||
singleReferences: Identifier[];
|
||||
/** List of source files that may (or may not) use the symbol via a namespace. (For UMD modules this is every file.) */
|
||||
indirectUsers: SourceFile[];
|
||||
}
|
||||
export type ImportTracker = (exportSymbol: Symbol, exportInfo: ExportInfo, isForRename: boolean) => ImportsResult;
|
||||
|
||||
/** Creates the imports map and returns an ImportTracker that uses it. Call this lazily to avoid calling `getDirectImportsMap` unnecessarily. */
|
||||
export function createImportTracker(sourceFiles: SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken): ImportTracker {
|
||||
const allDirectImports = getDirectImportsMap(sourceFiles, checker, cancellationToken);
|
||||
return (exportSymbol, exportInfo, isForRename) => {
|
||||
const { directImports, indirectUsers } = getImportersForExport(sourceFiles, allDirectImports, exportInfo, checker, cancellationToken);
|
||||
return { indirectUsers, ...getSearchesFromDirectImports(directImports, exportSymbol, exportInfo.exportKind, checker, isForRename) };
|
||||
};
|
||||
}
|
||||
|
||||
/** Info about an exported symbol to perform recursive search on. */
|
||||
export interface ExportInfo {
|
||||
exportingModuleSymbol: Symbol;
|
||||
exportKind: ExportKind;
|
||||
}
|
||||
|
||||
export const enum ExportKind { Named, Default, ExportEquals }
|
||||
|
||||
export const enum ImportExport { Import, Export }
|
||||
|
||||
interface AmbientModuleDeclaration extends ModuleDeclaration { body?: ModuleBlock; }
|
||||
type SourceFileLike = SourceFile | AmbientModuleDeclaration;
|
||||
// Identifier for the case of `const x = require("y")`.
|
||||
type Importer = AnyImportSyntax | Identifier | ExportDeclaration;
|
||||
type ImporterOrCallExpression = Importer | CallExpression;
|
||||
|
||||
/** Returns import statements that directly reference the exporting module, and a list of files that may access the module through a namespace. */
|
||||
function getImportersForExport(
|
||||
sourceFiles: SourceFile[],
|
||||
allDirectImports: Map<ImporterOrCallExpression[]>,
|
||||
{ exportingModuleSymbol, exportKind }: ExportInfo,
|
||||
checker: TypeChecker,
|
||||
cancellationToken: CancellationToken
|
||||
): { directImports: Importer[], indirectUsers: SourceFile[] } {
|
||||
const markSeenDirectImport = nodeSeenTracker<ImporterOrCallExpression>();
|
||||
const markSeenIndirectUser = nodeSeenTracker<SourceFileLike>();
|
||||
const directImports: Importer[] = [];
|
||||
const isAvailableThroughGlobal = !!exportingModuleSymbol.globalExports;
|
||||
const indirectUserDeclarations: SourceFileLike[] = isAvailableThroughGlobal ? undefined : [];
|
||||
|
||||
handleDirectImports(exportingModuleSymbol);
|
||||
|
||||
return { directImports, indirectUsers: getIndirectUsers() };
|
||||
|
||||
function getIndirectUsers(): SourceFile[] {
|
||||
if (isAvailableThroughGlobal) {
|
||||
// It has `export as namespace`, so anything could potentially use it.
|
||||
return sourceFiles;
|
||||
}
|
||||
|
||||
// Module augmentations may use this module's exports without importing it.
|
||||
for (const decl of exportingModuleSymbol.declarations) {
|
||||
if (isExternalModuleAugmentation(decl)) {
|
||||
addIndirectUser(decl as SourceFileLike);
|
||||
}
|
||||
}
|
||||
|
||||
// This may return duplicates (if there are multiple module declarations in a single source file, all importing the same thing as a namespace), but `State.markSearchedSymbol` will handle that.
|
||||
return indirectUserDeclarations.map(getSourceFileOfNode);
|
||||
}
|
||||
|
||||
function handleDirectImports(exportingModuleSymbol: Symbol): void {
|
||||
const theseDirectImports = getDirectImports(exportingModuleSymbol);
|
||||
if (theseDirectImports) for (const direct of theseDirectImports) {
|
||||
if (!markSeenDirectImport(direct)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
switch (direct.kind) {
|
||||
case SyntaxKind.CallExpression:
|
||||
if (!isAvailableThroughGlobal) {
|
||||
const parent = direct.parent!;
|
||||
if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
const { name } = parent as ts.VariableDeclaration;
|
||||
if (name.kind === SyntaxKind.Identifier) {
|
||||
directImports.push(name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't support re-exporting 'require()' calls, so just add a single indirect user.
|
||||
addIndirectUser(direct.getSourceFile());
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export));
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
const namedBindings = direct.importClause && direct.importClause.namedBindings;
|
||||
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
handleNamespaceImport(direct, namedBindings.name);
|
||||
}
|
||||
else {
|
||||
directImports.push(direct);
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
if (!direct.exportClause) {
|
||||
// This is `export * from "foo"`, so imports of this module may import the export too.
|
||||
handleDirectImports(getContainingModuleSymbol(direct, checker));
|
||||
}
|
||||
else {
|
||||
// This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports.
|
||||
directImports.push(direct);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleNamespaceImport(importDeclaration: ImportEqualsDeclaration | ImportDeclaration, name: Identifier, isReExport?: boolean): void {
|
||||
if (exportKind === ExportKind.ExportEquals) {
|
||||
// This is a direct import, not import-as-namespace.
|
||||
directImports.push(importDeclaration);
|
||||
}
|
||||
else if (!isAvailableThroughGlobal) {
|
||||
const sourceFileLike = getSourceFileLikeForImportDeclaration(importDeclaration);
|
||||
Debug.assert(sourceFileLike.kind === SyntaxKind.SourceFile || sourceFileLike.kind === SyntaxKind.ModuleDeclaration);
|
||||
if (isReExport || findNamespaceReExports(sourceFileLike, name, checker)) {
|
||||
addIndirectUsers(sourceFileLike);
|
||||
}
|
||||
else {
|
||||
addIndirectUser(sourceFileLike);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addIndirectUser(sourceFileLike: SourceFileLike): boolean {
|
||||
Debug.assert(!isAvailableThroughGlobal);
|
||||
const isNew = markSeenIndirectUser(sourceFileLike);
|
||||
if (isNew) {
|
||||
indirectUserDeclarations.push(sourceFileLike);
|
||||
}
|
||||
return isNew;
|
||||
}
|
||||
|
||||
/** Adds a module and all of its transitive dependencies as possible indirect users. */
|
||||
function addIndirectUsers(sourceFileLike: SourceFileLike): void {
|
||||
if (!addIndirectUser(sourceFileLike)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const moduleSymbol = checker.getMergedSymbol(sourceFileLike.symbol);
|
||||
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
|
||||
const directImports = getDirectImports(moduleSymbol);
|
||||
if (directImports) for (const directImport of directImports) {
|
||||
addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport));
|
||||
}
|
||||
}
|
||||
|
||||
function getDirectImports(moduleSymbol: Symbol): ImporterOrCallExpression[] | undefined {
|
||||
return allDirectImports.get(getSymbolId(moduleSymbol).toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the set of direct imports of a module, we need to find which ones import the particular exported symbol.
|
||||
* The returned `importSearches` will result in the entire source file being searched.
|
||||
* But re-exports will be placed in 'singleReferences' since they cannot be locally referenced.
|
||||
*/
|
||||
function getSearchesFromDirectImports(directImports: Importer[], exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker, isForRename: boolean): Pick<ImportsResult, "importSearches" | "singleReferences"> {
|
||||
const exportName = exportSymbol.name;
|
||||
const importSearches: Array<[Identifier, Symbol]> = [];
|
||||
const singleReferences: Identifier[] = [];
|
||||
function addSearch(location: Identifier, symbol: Symbol): void {
|
||||
importSearches.push([location, symbol]);
|
||||
}
|
||||
|
||||
if (directImports) for (const decl of directImports) {
|
||||
handleImport(decl);
|
||||
}
|
||||
|
||||
return { importSearches, singleReferences };
|
||||
|
||||
function handleImport(decl: Importer): void {
|
||||
if (decl.kind === SyntaxKind.ImportEqualsDeclaration) {
|
||||
if (isExternalModuleImportEquals(decl)) {
|
||||
handleNamespaceImportLike(decl.name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (decl.kind === ts.SyntaxKind.Identifier) {
|
||||
handleNamespaceImportLike(decl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore if there's a grammar error
|
||||
if (decl.moduleSpecifier.kind !== SyntaxKind.StringLiteral) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (decl.kind === SyntaxKind.ExportDeclaration) {
|
||||
searchForNamedImport(decl.exportClause);
|
||||
return;
|
||||
}
|
||||
|
||||
const { importClause } = decl;
|
||||
|
||||
const { namedBindings } = importClause;
|
||||
if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) {
|
||||
handleNamespaceImportLike(namedBindings.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (exportKind === ExportKind.Named) {
|
||||
searchForNamedImport(namedBindings as NamedImports | undefined);
|
||||
}
|
||||
else {
|
||||
// `export =` might be imported by a default import if `--allowSyntheticDefaultImports` is on, so this handles both ExportKind.Default and ExportKind.ExportEquals
|
||||
const { name } = importClause;
|
||||
// If a default import has the same name as the default export, allow to rename it.
|
||||
// Given `import f` and `export default function f`, we will rename both, but for `import g` we will rename just that.
|
||||
if (name && (!isForRename || name.text === symbolName(exportSymbol))) {
|
||||
const defaultImportAlias = checker.getSymbolAtLocation(name);
|
||||
addSearch(name, defaultImportAlias);
|
||||
}
|
||||
|
||||
// 'default' might be accessed as a named import `{ default as foo }`.
|
||||
if (!isForRename && exportKind === ExportKind.Default) {
|
||||
Debug.assert(exportName === "default");
|
||||
searchForNamedImport(namedBindings as NamedImports | undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `import x = require("./x") or `import * as x from "./x"`.
|
||||
* An `export =` may be imported by this syntax, so it may be a direct import.
|
||||
* If it's not a direct import, it will be in `indirectUsers`, so we don't have to do anything here.
|
||||
*/
|
||||
function handleNamespaceImportLike(importName: Identifier): void {
|
||||
// Don't rename an import that already has a different name than the export.
|
||||
if (exportKind === ExportKind.ExportEquals && (!isForRename || importName.text === exportName)) {
|
||||
addSearch(importName, checker.getSymbolAtLocation(importName));
|
||||
}
|
||||
}
|
||||
|
||||
function searchForNamedImport(namedBindings: NamedImportsOrExports | undefined): void {
|
||||
if (namedBindings) for (const element of namedBindings.elements) {
|
||||
const { name, propertyName } = element;
|
||||
if ((propertyName || name).text !== exportName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyName) {
|
||||
// This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference.
|
||||
singleReferences.push(propertyName);
|
||||
if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`.
|
||||
// Search locally for `bar`.
|
||||
addSearch(name, checker.getSymbolAtLocation(name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName
|
||||
? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol.
|
||||
: checker.getSymbolAtLocation(name);
|
||||
addSearch(name, localSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns 'true' is the namespace 'name' is re-exported from this module, and 'false' if it is only used locally. */
|
||||
function findNamespaceReExports(sourceFileLike: SourceFileLike, name: Identifier, checker: TypeChecker): boolean {
|
||||
const namespaceImportSymbol = checker.getSymbolAtLocation(name);
|
||||
|
||||
return forEachPossibleImportOrExportStatement(sourceFileLike, statement => {
|
||||
if (statement.kind !== SyntaxKind.ExportDeclaration) return;
|
||||
|
||||
const { exportClause, moduleSpecifier } = statement as ExportDeclaration;
|
||||
if (moduleSpecifier || !exportClause) return;
|
||||
|
||||
for (const element of exportClause.elements) {
|
||||
if (checker.getExportSpecifierLocalTargetSymbol(element) === namespaceImportSymbol) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Returns a map from a module symbol Id to all import statements that directly reference the module. */
|
||||
function getDirectImportsMap(sourceFiles: SourceFile[], checker: TypeChecker, cancellationToken: CancellationToken): Map<ImporterOrCallExpression[]> {
|
||||
const map = createMap<ImporterOrCallExpression[]>();
|
||||
|
||||
for (const sourceFile of sourceFiles) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
forEachImport(sourceFile, (importDecl, moduleSpecifier) => {
|
||||
const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier);
|
||||
if (moduleSymbol) {
|
||||
const id = getSymbolId(moduleSymbol).toString();
|
||||
let imports = map.get(id);
|
||||
if (!imports) {
|
||||
map.set(id, imports = []);
|
||||
}
|
||||
imports.push(importDecl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/** Iterates over all statements at the top level or in module declarations. Returns the first truthy result. */
|
||||
function forEachPossibleImportOrExportStatement<T>(sourceFileLike: SourceFileLike, action: (statement: Statement) => T): T {
|
||||
return forEach(sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body.statements, statement =>
|
||||
action(statement) || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action)));
|
||||
}
|
||||
|
||||
/** Calls `action` for each import, re-export, or require() in a file. */
|
||||
function forEachImport(sourceFile: SourceFile, action: (importStatement: ImporterOrCallExpression, imported: StringLiteral) => void): void {
|
||||
if (sourceFile.externalModuleIndicator) {
|
||||
for (const moduleSpecifier of sourceFile.imports) {
|
||||
action(importerFromModuleSpecifier(moduleSpecifier), moduleSpecifier);
|
||||
}
|
||||
}
|
||||
else {
|
||||
forEachPossibleImportOrExportStatement(sourceFile, statement => {
|
||||
switch (statement.kind) {
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
case SyntaxKind.ImportDeclaration: {
|
||||
const decl = statement as ImportDeclaration | ExportDeclaration;
|
||||
if (decl.moduleSpecifier && decl.moduleSpecifier.kind === SyntaxKind.StringLiteral) {
|
||||
action(decl, decl.moduleSpecifier as StringLiteral);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SyntaxKind.ImportEqualsDeclaration: {
|
||||
const decl = statement as ImportEqualsDeclaration;
|
||||
const { moduleReference } = decl;
|
||||
if (moduleReference.kind === SyntaxKind.ExternalModuleReference &&
|
||||
moduleReference.expression.kind === SyntaxKind.StringLiteral) {
|
||||
action(decl, moduleReference.expression as StringLiteral);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (sourceFile.flags & NodeFlags.JavaScriptFile) {
|
||||
// Find all 'require()' calls.
|
||||
sourceFile.forEachChild(function recur(node: Node): void {
|
||||
if (isRequireCall(node, /*checkArgumentIsStringLiteral*/ true)) {
|
||||
action(node, node.arguments[0] as StringLiteral);
|
||||
} else {
|
||||
node.forEachChild(recur);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function importerFromModuleSpecifier(moduleSpecifier: StringLiteral): Importer {
|
||||
const decl = moduleSpecifier.parent;
|
||||
if (decl.kind === SyntaxKind.ImportDeclaration || decl.kind === SyntaxKind.ExportDeclaration) {
|
||||
return decl as ImportDeclaration | ExportDeclaration;
|
||||
}
|
||||
Debug.assert(decl.kind === SyntaxKind.ExternalModuleReference);
|
||||
return (decl as ExternalModuleReference).parent;
|
||||
}
|
||||
|
||||
export interface ImportedSymbol {
|
||||
kind: ImportExport.Import;
|
||||
symbol: Symbol;
|
||||
isNamedImport: boolean;
|
||||
}
|
||||
export interface ExportedSymbol {
|
||||
kind: ImportExport.Export;
|
||||
symbol: Symbol;
|
||||
exportInfo: ExportInfo;
|
||||
}
|
||||
/**
|
||||
* Given a local reference, we might notice that it's an import/export and recursively search for references of that.
|
||||
* If at an import, look locally for the symbol it imports.
|
||||
* If an an export, look for all imports of it.
|
||||
* This doesn't handle export specifiers; that is done in `getReferencesAtExportSpecifier`.
|
||||
* @param comingFromExport If we are doing a search for all exports, don't bother looking backwards for the imported symbol, since that's the reason we're here.
|
||||
*/
|
||||
export function getImportOrExportSymbol(node: Node, symbol: Symbol, checker: TypeChecker, comingFromExport: boolean): ImportedSymbol | ExportedSymbol | undefined {
|
||||
return comingFromExport ? getExport() : getExport() || getImport();
|
||||
|
||||
function getExport(): ExportedSymbol | ImportedSymbol | undefined {
|
||||
const { parent } = node;
|
||||
if (symbol.flags & SymbolFlags.Export) {
|
||||
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use.
|
||||
// So check that we are at the declaration.
|
||||
return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression
|
||||
? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false)
|
||||
: undefined;
|
||||
}
|
||||
else {
|
||||
const { exportSymbol } = symbol;
|
||||
Debug.assert(!!exportSymbol);
|
||||
return exportInfo(exportSymbol, getExportKindForDeclaration(parent));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const exportNode = parent.kind === SyntaxKind.VariableDeclaration ? getAncestor(parent, SyntaxKind.VariableStatement) : parent;
|
||||
if (hasModifier(exportNode, ModifierFlags.Export)) {
|
||||
if (exportNode.kind === SyntaxKind.ImportEqualsDeclaration && (exportNode as ImportEqualsDeclaration).moduleReference === node) {
|
||||
// We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement.
|
||||
if (comingFromExport) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const lhsSymbol = checker.getSymbolAtLocation((exportNode as ImportEqualsDeclaration).name);
|
||||
return { kind: ImportExport.Import, symbol: lhsSymbol, isNamedImport: false };
|
||||
}
|
||||
else {
|
||||
return exportInfo(symbol, getExportKindForDeclaration(exportNode));
|
||||
}
|
||||
}
|
||||
else if (parent.kind === SyntaxKind.ExportAssignment) {
|
||||
// Get the symbol for the `export =` node; its parent is the module it's the export of.
|
||||
const exportingModuleSymbol = parent.symbol.parent;
|
||||
Debug.assert(!!exportingModuleSymbol);
|
||||
return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } };
|
||||
}
|
||||
else if (parent.kind === ts.SyntaxKind.BinaryExpression) {
|
||||
return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
|
||||
}
|
||||
else if (parent.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
|
||||
let kind: ExportKind;
|
||||
switch (getSpecialPropertyAssignmentKind(node)) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
kind = ExportKind.Named;
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
kind = ExportKind.ExportEquals;
|
||||
break;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const sym = useLhsSymbol ? checker.getSymbolAtLocation((node.left as ts.PropertyAccessExpression).name) : symbol;
|
||||
return sym && exportInfo(sym, kind);
|
||||
}
|
||||
}
|
||||
|
||||
function getImport(): ImportedSymbol | undefined {
|
||||
const isImport = isNodeImport(node);
|
||||
if (!isImport) return;
|
||||
|
||||
// A symbol being imported is always an alias. So get what that aliases to find the local symbol.
|
||||
let importedSymbol = checker.getImmediateAliasedSymbol(symbol);
|
||||
if (importedSymbol) {
|
||||
// Search on the local symbol in the exporting module, not the exported symbol.
|
||||
importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker);
|
||||
// Similarly, skip past the symbol for 'export ='
|
||||
if (importedSymbol.name === "export=") {
|
||||
importedSymbol = checker.getImmediateAliasedSymbol(importedSymbol);
|
||||
}
|
||||
|
||||
if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching.
|
||||
return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function exportInfo(symbol: Symbol, kind: ExportKind): ExportedSymbol {
|
||||
const exportInfo = getExportInfo(symbol, kind, checker);
|
||||
return exportInfo && { kind: ImportExport.Export, symbol, exportInfo };
|
||||
}
|
||||
|
||||
// Not meant for use with export specifiers or export assignment.
|
||||
function getExportKindForDeclaration(node: Node): ExportKind | undefined {
|
||||
return hasModifier(node, ModifierFlags.Default) ? ExportKind.Default : ExportKind.Named;
|
||||
}
|
||||
}
|
||||
|
||||
function isNodeImport(node: Node): { isNamedImport: boolean } | undefined {
|
||||
const { parent } = node;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return (parent as ImportEqualsDeclaration).name === node && isExternalModuleImportEquals(parent as ImportEqualsDeclaration)
|
||||
? { isNamedImport: false }
|
||||
: undefined;
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
// For a rename import `{ foo as bar }`, don't search for the imported symbol. Just find local uses of `bar`.
|
||||
return (parent as ImportSpecifier).propertyName ? undefined : { isNamedImport: true };
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.NamespaceImport:
|
||||
Debug.assert((parent as ImportClause | NamespaceImport).name === node);
|
||||
return { isNamedImport: false };
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function getExportInfo(exportSymbol: Symbol, exportKind: ExportKind, checker: TypeChecker): ExportInfo | undefined {
|
||||
const exportingModuleSymbol = checker.getMergedSymbol(exportSymbol.parent); // Need to get merged symbol in case there's an augmentation.
|
||||
// `export` may appear in a namespace. In that case, just rely on global search.
|
||||
return isExternalModuleSymbol(exportingModuleSymbol) ? { exportingModuleSymbol, exportKind } : undefined;
|
||||
}
|
||||
|
||||
function symbolName(symbol: Symbol): string {
|
||||
if (symbol.name !== "default") {
|
||||
return symbol.name;
|
||||
}
|
||||
|
||||
const name = forEach(symbol.declarations, ({ name }) => name && name.kind === SyntaxKind.Identifier && name.text);
|
||||
Debug.assert(!!name);
|
||||
return name;
|
||||
}
|
||||
|
||||
/** If at an export specifier, go to the symbol it refers to. */
|
||||
function skipExportSpecifierSymbol(symbol: Symbol, checker: TypeChecker): Symbol {
|
||||
// For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does.
|
||||
if (symbol.declarations) for (const declaration of symbol.declarations) {
|
||||
if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) {
|
||||
return checker.getExportSpecifierLocalTargetSymbol(declaration);
|
||||
}
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
function getContainingModuleSymbol(importer: Importer, checker: TypeChecker): Symbol {
|
||||
return checker.getMergedSymbol(getSourceFileLikeForImportDeclaration(importer).symbol);
|
||||
}
|
||||
|
||||
function getSourceFileLikeForImportDeclaration(node: ImporterOrCallExpression): SourceFileLike {
|
||||
if (node.kind === SyntaxKind.CallExpression) {
|
||||
return node.getSourceFile();
|
||||
}
|
||||
|
||||
const { parent } = node;
|
||||
|
||||
if (parent.kind === SyntaxKind.SourceFile) {
|
||||
return parent as SourceFile;
|
||||
}
|
||||
Debug.assert(parent.kind === SyntaxKind.ModuleBlock && isAmbientModuleDeclaration(parent.parent));
|
||||
return parent.parent as AmbientModuleDeclaration;
|
||||
}
|
||||
|
||||
function isAmbientModuleDeclaration(node: Node): node is AmbientModuleDeclaration {
|
||||
return node.kind === SyntaxKind.ModuleDeclaration && (node as ModuleDeclaration).name.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
function isExternalModuleImportEquals({ moduleReference }: ImportEqualsDeclaration): boolean {
|
||||
return moduleReference.kind === SyntaxKind.ExternalModuleReference && moduleReference.expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
}
|
||||
+15
-10
@@ -31,21 +31,25 @@ namespace ts.Rename {
|
||||
return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library);
|
||||
}
|
||||
|
||||
// Cannot rename `default` as in `import { default as foo } from "./someModule";
|
||||
if (node.kind === SyntaxKind.Identifier &&
|
||||
(node as Identifier).originalKeywordKind === SyntaxKind.DefaultKeyword &&
|
||||
symbol.parent.flags & ts.SymbolFlags.Module) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const displayName = stripQuotes(getDeclaredName(typeChecker, symbol, node));
|
||||
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
|
||||
return kind ? getRenameInfoSuccess(displayName, typeChecker.getFullyQualifiedName(symbol), kind, SymbolDisplay.getSymbolModifiers(symbol), node, sourceFile) : undefined;
|
||||
}
|
||||
}
|
||||
else if (node.kind === SyntaxKind.StringLiteral) {
|
||||
const type = getStringLiteralTypeForNode(<StringLiteral>node, typeChecker);
|
||||
if (type) {
|
||||
if (isDefinedInLibraryFile(node)) {
|
||||
return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library);
|
||||
}
|
||||
|
||||
const displayName = stripQuotes(type.text);
|
||||
return getRenameInfoSuccess(displayName, displayName, ScriptElementKind.variableElement, ScriptElementKindModifier.none, node, sourceFile);
|
||||
if (isDefinedInLibraryFile(node)) {
|
||||
return getRenameInfoError(Diagnostics.You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library);
|
||||
}
|
||||
|
||||
const displayName = stripQuotes((node as StringLiteral).text);
|
||||
return getRenameInfoSuccess(displayName, displayName, ScriptElementKind.variableElement, ScriptElementKindModifier.none, node, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +88,9 @@ namespace ts.Rename {
|
||||
return createTextSpan(start, width);
|
||||
}
|
||||
|
||||
function nodeIsEligibleForRename(node: Node) {
|
||||
return node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.StringLiteral ||
|
||||
function nodeIsEligibleForRename(node: Node): boolean {
|
||||
return node.kind === ts.SyntaxKind.Identifier ||
|
||||
node.kind === SyntaxKind.StringLiteral ||
|
||||
isLiteralNameOfPropertyDeclarationOrIndexAccess(node) ||
|
||||
isThis(node);
|
||||
}
|
||||
|
||||
+18
-24
@@ -10,7 +10,6 @@
|
||||
/// <reference path='documentRegistry.ts' />
|
||||
/// <reference path='findAllReferences.ts' />
|
||||
/// <reference path='goToDefinition.ts' />
|
||||
/// <reference path='goToImplementation.ts' />
|
||||
/// <reference path='jsDoc.ts' />
|
||||
/// <reference path='jsTyping.ts' />
|
||||
/// <reference path='navigateTo.ts' />
|
||||
@@ -502,8 +501,8 @@ namespace ts {
|
||||
public nameTable: Map<number>;
|
||||
public resolvedModules: Map<ResolvedModuleFull>;
|
||||
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
|
||||
public imports: LiteralExpression[];
|
||||
public moduleAugmentations: LiteralExpression[];
|
||||
public imports: StringLiteral[];
|
||||
public moduleAugmentations: StringLiteral[];
|
||||
private namedDeclarations: Map<Declaration[]>;
|
||||
public ambientModuleNames: string[];
|
||||
public checkJsDirective: CheckJsDirective | undefined;
|
||||
@@ -1410,18 +1409,18 @@ namespace ts {
|
||||
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
/// Goto implementation
|
||||
function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] {
|
||||
synchronizeHostData();
|
||||
return GoToImplementation.getImplementationAtPosition(program.getTypeChecker(), cancellationToken,
|
||||
program.getSourceFiles(), getTouchingPropertyName(getValidSourceFile(fileName), position));
|
||||
}
|
||||
|
||||
function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] {
|
||||
synchronizeHostData();
|
||||
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
/// Goto implementation
|
||||
function getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[] {
|
||||
synchronizeHostData();
|
||||
return FindAllReferences.getImplementationsAtPosition(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
/// References and Occurrences
|
||||
function getOccurrencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
|
||||
let results = getOccurrencesAtPositionCore(fileName, position);
|
||||
|
||||
@@ -1443,10 +1442,7 @@ namespace ts {
|
||||
return DocumentHighlights.getDocumentHighlights(program.getTypeChecker(), cancellationToken, sourceFile, position, sourceFilesToSearch);
|
||||
}
|
||||
|
||||
/// References and Occurrences
|
||||
function getOccurrencesAtPositionCore(fileName: string, position: number): ReferenceEntry[] {
|
||||
synchronizeHostData();
|
||||
|
||||
return convertDocumentHighlights(getDocumentHighlights(fileName, position, [fileName]));
|
||||
|
||||
function convertDocumentHighlights(documentHighlights: DocumentHighlights[]): ReferenceEntry[] {
|
||||
@@ -1472,24 +1468,21 @@ namespace ts {
|
||||
}
|
||||
|
||||
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
|
||||
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/ true);
|
||||
return FindAllReferences.convertReferences(referencedSymbols);
|
||||
return getReferences(fileName, position, { findInStrings, findInComments, isForRename: true });
|
||||
}
|
||||
|
||||
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
|
||||
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/ false);
|
||||
return FindAllReferences.convertReferences(referencedSymbols);
|
||||
return getReferences(fileName, position);
|
||||
}
|
||||
|
||||
function getReferences(fileName: string, position: number, options?: FindAllReferences.Options) {
|
||||
synchronizeHostData();
|
||||
return FindAllReferences.findReferencedEntries(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, options);
|
||||
}
|
||||
|
||||
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
|
||||
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/ false);
|
||||
// Only include referenced symbols that have a valid definition.
|
||||
return filter(referencedSymbols, rs => !!rs.definition);
|
||||
}
|
||||
|
||||
function findReferencedSymbols(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, isForRename: boolean): ReferencedSymbol[] {
|
||||
synchronizeHostData();
|
||||
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position, findInStrings, findInComments, isForRename);
|
||||
return FindAllReferences.findReferencedSymbols(program.getTypeChecker(), cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
|
||||
}
|
||||
|
||||
/// NavigateTo
|
||||
@@ -2013,6 +2006,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
/** Names in the name table are escaped, so an identifier `__foo` will have a name table entry `___foo`. */
|
||||
export function getNameTable(sourceFile: SourceFile): Map<number> {
|
||||
if (!sourceFile.nameTable) {
|
||||
initializeNameTable(sourceFile);
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
"documentHighlights.ts",
|
||||
"documentRegistry.ts",
|
||||
"findAllReferences.ts",
|
||||
"importTracker.ts",
|
||||
"goToDefinition.ts",
|
||||
"goToImplementation.ts",
|
||||
"jsDoc.ts",
|
||||
"jsTyping.ts",
|
||||
"navigateTo.ts",
|
||||
|
||||
@@ -483,12 +483,9 @@ namespace ts {
|
||||
displayParts: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
export interface ReferencedSymbolOf<T extends DocumentSpan> {
|
||||
export interface ReferencedSymbol {
|
||||
definition: ReferencedSymbolDefinitionInfo;
|
||||
references: T[];
|
||||
}
|
||||
|
||||
export interface ReferencedSymbol extends ReferencedSymbolOf<ReferenceEntry> {
|
||||
references: ReferenceEntry[];
|
||||
}
|
||||
|
||||
export enum SymbolDisplayPartKind {
|
||||
|
||||
+18
-19
@@ -364,15 +364,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getStringLiteralTypeForNode(node: StringLiteral | LiteralTypeNode, typeChecker: TypeChecker): LiteralType {
|
||||
const searchNode = node.parent.kind === SyntaxKind.LiteralType ? <LiteralTypeNode>node.parent : node;
|
||||
const type = typeChecker.getTypeAtLocation(searchNode);
|
||||
if (type && type.flags & TypeFlags.StringLiteral) {
|
||||
return <LiteralType>type;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isThis(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ThisKeyword:
|
||||
@@ -1132,6 +1123,21 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** True if the symbol is for an external module, as opposed to a namespace. */
|
||||
export function isExternalModuleSymbol(moduleSymbol: Symbol): boolean {
|
||||
Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module));
|
||||
return moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
/** Returns `true` the first time it encounters a node and `false` afterwards. */
|
||||
export function nodeSeenTracker<T extends Node>(): (node: T) => boolean {
|
||||
const seen: Array<true> = [];
|
||||
return node => {
|
||||
const id = getNodeId(node);
|
||||
return !seen[id] && (seen[id] = true);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
@@ -1300,21 +1306,14 @@ namespace ts {
|
||||
export function getDeclaredName(typeChecker: TypeChecker, symbol: Symbol, location: Node): string {
|
||||
// If this is an export or import specifier it could have been renamed using the 'as' syntax.
|
||||
// If so we want to search for whatever is under the cursor.
|
||||
if (isImportOrExportSpecifierName(location)) {
|
||||
return location.getText();
|
||||
}
|
||||
else if (isStringOrNumericLiteral(location) &&
|
||||
location.parent.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return (<LiteralExpression>location).text;
|
||||
if (isImportOrExportSpecifierName(location) || isStringOrNumericLiteral(location) && location.parent.kind === SyntaxKind.ComputedPropertyName) {
|
||||
return location.text;
|
||||
}
|
||||
|
||||
// Try to get the local symbol if we're dealing with an 'export default'
|
||||
// since that symbol has the "true" name.
|
||||
const localExportDefaultSymbol = getLocalSymbolForExportDefault(symbol);
|
||||
|
||||
const name = typeChecker.symbolToString(localExportDefaultSymbol || symbol);
|
||||
|
||||
return name;
|
||||
return typeChecker.symbolToString(localExportDefaultSymbol || symbol);
|
||||
}
|
||||
|
||||
export function isImportOrExportSpecifierName(location: Node): location is Identifier {
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.referenceGroups(r0, [
|
||||
{ definition: "import x", ranges: [r0] },
|
||||
{ definition: 'module "jquery"', ranges: [r1] }
|
||||
]);
|
||||
verify.referenceGroups(r1, [
|
||||
{ definition: 'module "jquery"', ranges: [r0] },
|
||||
{ definition: "import x", ranges: [r1] }
|
||||
]);
|
||||
// TODO: Want these to be in the same group, but that would require creating a symbol for `x`.
|
||||
verify.singleReferenceGroup("import x", [r0]);
|
||||
verify.singleReferenceGroup("import x", [r1]);
|
||||
@@ -7,4 +7,4 @@
|
||||
|
||||
goTo.eof();
|
||||
edit.insertLine('');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -42,4 +42,4 @@ verify.completionListContains('baz');
|
||||
verify.completionListContains('x');
|
||||
edit.insert('bar()');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -46,4 +46,4 @@ verify.completionListContains('baz');
|
||||
verify.completionListContains('x');
|
||||
edit.insert('bar()');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -30,4 +30,4 @@ edit.insert('x;');
|
||||
|
||||
verify.quickInfoAt("5", "(local var) r2: number");
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -10,4 +10,4 @@
|
||||
////}
|
||||
|
||||
verify.quickInfoAt("", "var M.C.C: typeof M.C");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -12,6 +12,6 @@
|
||||
////import {/*1*/} from './foo';
|
||||
|
||||
verify.completionsAt("1", ["prototype", "prop1", "prop2"]);
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('2');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -32,4 +32,4 @@ verify.not.completionListContains('bar');
|
||||
verify.not.completionListContains('baz');
|
||||
edit.insert('foo;');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -35,4 +35,4 @@ verify.not.completionListContains('bar');
|
||||
verify.not.completionListContains('baz');
|
||||
edit.insert('foo;');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -25,4 +25,4 @@
|
||||
////var result2 = r2.x;
|
||||
|
||||
verify.quickInfoAt("", "var r: CollectionItem");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
goTo.marker('1');
|
||||
edit.backspace(6);
|
||||
edit.insert('T');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
goTo.marker('2');
|
||||
edit.insertLine('');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -19,7 +19,7 @@
|
||||
// If we do not, an error will be raised claiming
|
||||
// that foo's return type is not assignable with
|
||||
// it's signature return type
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insert('D = C << 1,');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
+2
-3
@@ -10,7 +10,7 @@
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
// Edit and bind and resolve only var decl
|
||||
goTo.marker("1");
|
||||
@@ -18,5 +18,4 @@ edit.backspace(1);
|
||||
edit.insert(" ");
|
||||
verify.quickInfoIs("var M.C.C: typeof M.C");
|
||||
|
||||
// Verify there are no errors
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -21,4 +21,4 @@ verify.quickInfos({
|
||||
});
|
||||
goTo.marker('4');
|
||||
verify.completionListContains('foo');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -17,4 +17,4 @@ edit.insert("interface Array<T> { pop(def: T): T; }");
|
||||
|
||||
verify.not.errorExistsBetweenMarkers("1", "2");
|
||||
verify.quickInfoAt("y", "var y: number");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
////var /**/x = b.foo2().foo(5).foo(); // 'x' is of type 'void'
|
||||
|
||||
verify.quickInfoAt("", "var x: void");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
////y.length;
|
||||
|
||||
verify.quickInfoAt("", "var y: Date[]");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
////class d extends a.C { constructor() { [|super|](); }
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
verify.referenceGroups([r0, r2], [{ definition: "constructor C(n: number): C (+1 overload)", ranges }]);
|
||||
verify.referenceGroups(r1, [{ definition: "constructor C(): C (+1 overload)", ranges }]);
|
||||
const [a0, a1, a2, a3, a4, b0, c0, d0, d1] = ranges;
|
||||
verify.referenceGroups([a0, a2], defs("constructor C(n: number): C (+1 overload)"));
|
||||
verify.referenceGroups(a1, defs("constructor C(): C (+1 overload)"));
|
||||
|
||||
function defs(definition: string) {
|
||||
return [
|
||||
{ definition, ranges: [a0, a1, a2, a3, d0, d1, a4] },
|
||||
{ definition: "import C", ranges: [b0] },
|
||||
{ definition: "import C", ranges: [c0] }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export default function [|{| "isWriteAccess": true, "isDefinition": true |}f|]() {}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////export import a = require("./a");
|
||||
|
||||
// @Filename: /c.ts
|
||||
////import { a } from "./b";
|
||||
////a.[|default|]();
|
||||
////
|
||||
////declare const x: { [|{| "isWriteAccess": true, "isDefinition": true |}default|]: number };
|
||||
////x.[|default|];
|
||||
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
|
||||
verify.singleReferenceGroup("function f(): void", [r0, r1]);
|
||||
verify.singleReferenceGroup("(property) default: number", [r2, r3]);
|
||||
|
||||
verify.rangesAreRenameLocations([r0]);
|
||||
|
||||
// Can't rename a default import.
|
||||
goTo.rangeStart(r1);
|
||||
verify.renameInfoFailed();
|
||||
|
||||
// Can rename a default property.
|
||||
verify.rangesAreRenameLocations([r2, r3]);
|
||||
@@ -0,0 +1,24 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// `export as namespace` results in global search.
|
||||
|
||||
// @Filename: /node_modules/a/index.d.ts
|
||||
////export function [|{| "isWriteAccess": true, "isDefinition": true |}f|](): void;
|
||||
////export as namespace A;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}f|] } from "a";
|
||||
|
||||
// @Filename: /c.ts
|
||||
////A.[|f|]();
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
|
||||
const globals = { definition: "function f(): void", ranges: [r0, r2] };
|
||||
const imports = { definition: "import f", ranges: [r1] };
|
||||
|
||||
verify.referenceGroups([r0, r2], [globals, imports]);
|
||||
verify.referenceGroups(r1, [imports, globals]);
|
||||
@@ -10,5 +10,13 @@
|
||||
// @Filename: c.ts
|
||||
////import { f } from "./a";
|
||||
|
||||
verify.singleReferenceGroup("function f(): void");
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
verify.referenceGroups(r0, [
|
||||
{ definition: "function f(): void", ranges: [r0] },
|
||||
{ definition: "import g", ranges: [r1, r2] }
|
||||
]);
|
||||
verify.referenceGroups(r1, [{ definition: "import g", ranges: [r1, r2] }]);
|
||||
verify.referenceGroups(r2, [{ definition: "(alias) g(): void\nimport g", ranges: [r1, r2] }]);
|
||||
|
||||
verify.goToDefinition("ref", "def");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export {};
|
||||
////declare global {
|
||||
//// function [|{| "isWriteAccess": true, "isDefinition": true |}f|](): void;
|
||||
////}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////[|f|]();
|
||||
|
||||
verify.noErrors();
|
||||
verify.singleReferenceGroup("function f(): void");
|
||||
@@ -0,0 +1,60 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /node_modules/a/index.d.ts
|
||||
////declare function [|{| "isWriteAccess": true, "isDefinition": true |}a|](): void;
|
||||
////declare namespace [|{| "isWriteAccess": true, "isDefinition": true |}a|] {
|
||||
//// export const x: number;
|
||||
////}
|
||||
////export = [|a|];
|
||||
|
||||
// Import with different name and we find local refs
|
||||
// @Filename: /b.ts
|
||||
////import * as [|{| "isWriteAccess": true, "isDefinition": true |}b|] from "a";
|
||||
////[|b|]();
|
||||
////[|b|].x;
|
||||
|
||||
// Import with same name and we find all refs
|
||||
// @Filename: /c.ts
|
||||
////import * as [|{| "isWriteAccess": true, "isDefinition": true |}a|] from "a";
|
||||
////[|a|]();
|
||||
////[|a|].x;
|
||||
|
||||
verify.noErrors();
|
||||
const ranges = test.ranges();
|
||||
const [a0, a1, a2, b0, b1, b2, c0, c1, c2] = ranges;
|
||||
const aRanges = [a0, a1, a2];
|
||||
const bRanges = [b0, b1, b2];
|
||||
const cRanges = [c0, c1, c2];
|
||||
|
||||
verify.referenceGroups(a0, [
|
||||
{ definition: "function a(): void\nnamespace a", ranges: aRanges },
|
||||
{ definition: "import b", ranges: bRanges },
|
||||
{ definition: "import a", ranges: cRanges }
|
||||
]);
|
||||
verify.referenceGroups([a1, a2], [
|
||||
{ definition: "namespace a\nfunction a(): void", ranges: aRanges },
|
||||
{ definition: "import b", ranges: bRanges },
|
||||
{ definition: "import a", ranges: cRanges }
|
||||
]);
|
||||
|
||||
verify.referenceGroups([b0, b0], [
|
||||
{ definition: "import b", ranges: bRanges }
|
||||
]);
|
||||
verify.referenceGroups(b1, [
|
||||
{ definition: "(alias) b(): void\nimport b", ranges: bRanges }
|
||||
]);
|
||||
|
||||
verify.referenceGroups([c0, c2], [
|
||||
{ definition: "import a", ranges: cRanges },
|
||||
{ definition: "namespace a\nfunction a(): void", ranges: aRanges },
|
||||
{ definition: "import b", ranges: bRanges }
|
||||
]);
|
||||
verify.referenceGroups(c1, [
|
||||
{ definition: "(alias) a(): void\nimport a", ranges: cRanges },
|
||||
{ definition: "namespace a\nfunction a(): void", ranges: aRanges },
|
||||
{ definition: "import b", ranges: bRanges }
|
||||
]);
|
||||
|
||||
verify.renameLocations(aRanges, aRanges.concat(cRanges));
|
||||
verify.rangesAreRenameLocations(bRanges);
|
||||
verify.rangesAreRenameLocations(cRanges);
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: /node_modules/foo/index.d.ts
|
||||
////export type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
|
||||
// @Filename: /a.ts
|
||||
////import * as foo from "foo";
|
||||
////declare module "foo" {
|
||||
//// export const x: [|T|];
|
||||
////}
|
||||
|
||||
verify.noErrors();
|
||||
verify.singleReferenceGroup("type T = number");
|
||||
@@ -18,4 +18,3 @@ const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.referenceGroups(r0, [{ definition: "interface Test.start", ranges }]);
|
||||
verify.referenceGroups(r1, [{ definition: "interface Second.Test.start", ranges }]);
|
||||
|
||||
|
||||
@@ -14,5 +14,13 @@
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2, r3] = ranges;
|
||||
verify.referenceGroups([r0, r1, r3], [{ definition: "class Class", ranges }]);
|
||||
verify.referenceGroups(r2, [{ definition: "constructor Class(): Class", ranges }]);
|
||||
const classes = { definition: "class Class", ranges: [r0] };
|
||||
const imports = { definition: "import Class", ranges: [r1, r2] };
|
||||
const reExports = { definition: "import Class", ranges: [r3] };
|
||||
verify.referenceGroups(r0, [classes, imports, reExports]);
|
||||
verify.referenceGroups(r1, [imports, classes, reExports]);
|
||||
verify.referenceGroups(r2, [
|
||||
{ definition: "(alias) new Class(): Class\nimport Class", ranges: [r1, r2] },
|
||||
classes,
|
||||
reExports
|
||||
]);
|
||||
|
||||
@@ -13,11 +13,20 @@
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}Class|] as [|{| "isWriteAccess": true, "isDefinition": true |}C3|] } from "./a";
|
||||
|
||||
const ranges = test.rangesByText();
|
||||
verify.singleReferenceGroup("class Class", ranges.get("Class"));
|
||||
const classRanges = ranges.get("Class");
|
||||
const [class0, class1, class2] = classRanges;
|
||||
const c2Ranges = ranges.get("C2");
|
||||
const [c2_0, c2_1] = c2Ranges;
|
||||
const c3Ranges = ranges.get("C3");
|
||||
const classes = { definition: "class Class", ranges: classRanges };
|
||||
const c2s = { definition: "import C2", ranges: c2Ranges };
|
||||
const c3s = { definition: "import C3", ranges: c3Ranges };
|
||||
|
||||
const c2s = ranges.get("C2");
|
||||
const [c2_0, c2_1] = c2s;
|
||||
verify.referenceGroups(c2_0, [{ definition: "import C2", ranges: c2s }]);
|
||||
verify.referenceGroups(c2_1, [{ definition: "(alias) new C2(): C2\nimport C2", ranges: c2s }]);
|
||||
verify.referenceGroups(classRanges, [classes, c2s, c3s]);
|
||||
|
||||
verify.singleReferenceGroup("import C3", ranges.get("C3"));
|
||||
verify.referenceGroups(c2_0, [c2s])
|
||||
verify.referenceGroups(c2_1, [{ definition: "(alias) new C2(): C2\nimport C2", ranges: c2Ranges }]);
|
||||
|
||||
verify.referenceGroups(c3Ranges, [c3s]);
|
||||
|
||||
verify.rangesWithSameTextAreRenameLocations();
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @noLib: true
|
||||
|
||||
// @Filename: /a.ts
|
||||
////var [|{| "isWriteAccess": true, "isDefinition": true |}x|];
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}x|] };
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}x|] as [|{| "isWriteAccess": true, "isDefinition": true |}y|] };
|
||||
|
||||
// @Filename: /b.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}x|], [|{| "isWriteAccess": true, "isDefinition": true |}y|] } from "./a";
|
||||
////[|x|]; [|y|];
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
const [ax0, ax1, ax2, ay, bx0, by0, bx1, by1] = test.ranges();
|
||||
const axRanges = [ax0, ax1, ax2];
|
||||
const bxRanges = [bx0, bx1];
|
||||
const byRanges = [by0, by1];
|
||||
const axGroup = { definition: "var x: any", ranges: axRanges };
|
||||
const bxGroup = { definition: "import x", ranges: bxRanges };
|
||||
const ayGroup = { definition: "import y", ranges: [ay] }
|
||||
const byGroup = { definition: "import y", ranges: byRanges }
|
||||
|
||||
verify.referenceGroups(axRanges, [axGroup, bxGroup, ayGroup, byGroup]);
|
||||
verify.referenceGroups(bxRanges, [bxGroup, axGroup, ayGroup, byGroup]);
|
||||
verify.referenceGroups(ay, [ayGroup, byGroup]);
|
||||
verify.referenceGroups(byRanges, [byGroup, ayGroup]);
|
||||
|
||||
verify.rangesWithSameTextAreRenameLocations();
|
||||
@@ -0,0 +1,37 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
|
||||
|
||||
// @Filename: /b.ts
|
||||
////export const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
|
||||
|
||||
//@Filename: /c.ts
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } from "./b";
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } from "./a";
|
||||
////[|x|];
|
||||
|
||||
// @Filename: /d.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } from "./c";
|
||||
|
||||
verify.noErrors();
|
||||
const [a, b, cFromB, cFromA, cUse, d] = test.ranges();
|
||||
const cFromARanges = [cFromA, cUse];
|
||||
|
||||
const aGroup = { definition: "const x: 0", ranges: [a] };
|
||||
const cFromAGroup = { definition: "import x", ranges: cFromARanges };
|
||||
|
||||
verify.referenceGroups(a, [aGroup, cFromAGroup]);
|
||||
|
||||
const bGroup = { definition: "const x: 0", ranges: [b] };
|
||||
const cFromBGroup = { definition: "import x", ranges: [cFromB] };
|
||||
const dGroup = { definition: "import x", ranges: [d] };
|
||||
verify.referenceGroups(b, [bGroup, cFromBGroup, dGroup]);
|
||||
|
||||
verify.referenceGroups(cFromB, [cFromBGroup, dGroup, bGroup]);
|
||||
verify.referenceGroups(cFromARanges, [cFromAGroup, aGroup]);
|
||||
|
||||
verify.referenceGroups(d, [dGroup, cFromBGroup, bGroup]);
|
||||
|
||||
verify.rangesAreRenameLocations([a, cFromA, cUse]);
|
||||
verify.rangesAreRenameLocations([b, cFromB, d]);
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export function [|{| "isWriteAccess": true, "isDefinition": true |}foo|](): void {}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////export * from "./a";
|
||||
|
||||
// @Filename: /c.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}foo|] } from "./b";
|
||||
|
||||
verify.noErrors();
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
const a = { definition: "function foo(): void", ranges: [r0] };
|
||||
const c = { definition: "import foo", ranges: [r1] };
|
||||
verify.referenceGroups(r0, [a, c]);
|
||||
verify.referenceGroups(r1, [c, a]);
|
||||
@@ -0,0 +1,61 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export function [|{| "isWriteAccess": true, "isDefinition": true |}foo|](): void {}
|
||||
|
||||
// @Filename: /b.ts
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}foo|] as [|{| "isWriteAccess": true, "isDefinition": true |}bar|] } from "./a";
|
||||
|
||||
// @Filename: /c.ts
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}foo|] as [|{| "isWriteAccess": true, "isDefinition": true |}default|] } from "./a";
|
||||
|
||||
// @Filename: /d.ts
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}default|] } from "./c";
|
||||
|
||||
// @Filename: /e.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}bar|] } from "./b";
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}baz|] from "./c";
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}default|] as [|{| "isWriteAccess": true, "isDefinition": true |}bang|] } from "./c";
|
||||
////import [|{| "isWriteAccess": true, "isDefinition": true |}boom|] from "./d";
|
||||
////[|bar|](); [|baz|](); [|bang|](); [|boom|]();
|
||||
|
||||
verify.noErrors();
|
||||
const [foo0, foo1, bar0, foo2, defaultC, defaultD, bar1, baz0, defaultE, bang0, boom0, bar2, baz1, bang1, boom1] = test.ranges();
|
||||
const a = { definition: "function foo(): void", ranges: [foo0, foo1, foo2] };
|
||||
const b = { definition: "import bar", ranges: [bar0] };
|
||||
const c = { definition: "import default", ranges: [defaultC, defaultE] };
|
||||
const d = { definition: "import default", ranges: [defaultD] };
|
||||
const eBar = { definition: "import bar", ranges: [bar1, bar2] };
|
||||
const eBaz = { definition: "import baz", ranges: [baz0, baz1] };
|
||||
const eBang = { definition: "import bang", ranges: [bang0, bang1] };
|
||||
const eBoom = { definition: "import boom", ranges: [boom0, boom1] };
|
||||
|
||||
verify.referenceGroups([foo0, foo1, foo2], [a, b, eBar, c, d, eBoom, eBaz, eBang]);
|
||||
|
||||
verify.referenceGroups(bar0, [b, eBar]);
|
||||
verify.referenceGroups(bar1, [eBar, b]);
|
||||
verify.referenceGroups(bar2, [{ ...eBar, definition: "(alias) bar(): void\nimport bar" }, b]);
|
||||
|
||||
verify.referenceGroups([defaultC], [c, d, eBoom, eBaz, eBang]);
|
||||
verify.referenceGroups(defaultD, [d, eBoom, a, b, eBar,c, eBaz, eBang]);
|
||||
verify.referenceGroups(defaultE, [c, d, eBoom, eBaz, eBang]);
|
||||
verify.referenceGroups(baz0, [eBaz]);
|
||||
verify.referenceGroups(baz1, [{ ...eBaz, definition: "(alias) baz(): void\nimport baz" }]);
|
||||
|
||||
verify.referenceGroups(bang0, [eBang]);
|
||||
verify.referenceGroups(bang1, [{ ...eBang, definition: "(alias) bang(): void\nimport bang" }]);
|
||||
|
||||
verify.referenceGroups(boom0, [eBoom]);
|
||||
verify.referenceGroups(boom1, [{ ...eBoom, definition: "(alias) boom(): void\nimport boom" }]);
|
||||
|
||||
test.rangesByText().forEach((ranges, text) => {
|
||||
if (text === "default") {
|
||||
for (const range of ranges) {
|
||||
goTo.rangeStart(defaultC);
|
||||
verify.renameInfoFailed();
|
||||
}
|
||||
}
|
||||
else {
|
||||
verify.rangesAreRenameLocations(ranges);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: /a.ts
|
||||
////export const [|{| "isWriteAccess": true, "isDefinition": true |}x|] = 0;
|
||||
|
||||
//@Filename: /b.ts
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}x|] as [|{| "isWriteAccess": true, "isDefinition": true |}x|] } from "./a";
|
||||
////[|x|];
|
||||
|
||||
verify.noErrors();
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
const aRanges = [r0, r1];
|
||||
const bRanges = [r2, r3];
|
||||
const aGroup = { definition: "const x: 0", ranges: aRanges };
|
||||
const bGroup = { definition: "import x", ranges: bRanges };
|
||||
verify.referenceGroups(aRanges, [aGroup, bGroup]);
|
||||
verify.referenceGroups(bRanges, [bGroup]);
|
||||
|
||||
verify.rangesAreRenameLocations(aRanges);
|
||||
verify.rangesAreRenameLocations(aRanges);
|
||||
@@ -7,7 +7,7 @@
|
||||
//// obj.[|name|];
|
||||
|
||||
const [r0, r1, r2, r3, r4] = test.ranges();
|
||||
verify.referenceGroups([r0, r3], [{ definition: "var name: string", ranges: [r0, r1, r3] }]);
|
||||
verify.referenceGroups(r0, [{ definition: "var name: string", ranges: [r0, r1, r3] }]); //r3
|
||||
verify.referenceGroups(r1, [
|
||||
{ definition: "var name: string", ranges: [r0, r3] },
|
||||
{ definition: "(property) name: string", ranges: [r1, r4] }
|
||||
|
||||
@@ -13,4 +13,7 @@
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
verify.referenceGroups(ranges, [{ definition: "const SubmissionComp: (submission: any) => any", ranges: [r2, r0, r1] }]);
|
||||
const imports = { definition: "import SubmissionComp", ranges: [r0, r1] };
|
||||
const def = { definition: "const SubmissionComp: (submission: any) => any", ranges: [r2] };
|
||||
verify.referenceGroups([r0, r1], [imports, def]);
|
||||
verify.referenceGroups(r2, [def, imports]);
|
||||
|
||||
@@ -184,6 +184,7 @@ declare namespace FourSlashInterface {
|
||||
verifyGetEmitOutputForCurrentFile(expected: string): void;
|
||||
verifyGetEmitOutputContentsForCurrentFile(expected: ts.OutputFile[]): void;
|
||||
noReferences(markerNameOrRange?: string | Range): void;
|
||||
symbolAtLocation(startRange: Range, ...declarationRanges: Range[]): void;
|
||||
/**
|
||||
* @deprecated, prefer 'referenceGroups'
|
||||
* Like `referencesAre`, but goes to `start` first.
|
||||
@@ -197,7 +198,8 @@ declare namespace FourSlashInterface {
|
||||
referenceGroups(startRanges: Range | Range[], parts: Array<{ definition: string, ranges: Range[] }>): void;
|
||||
singleReferenceGroup(definition: string, ranges?: Range[]): void;
|
||||
rangesAreOccurrences(isWriteAccess?: boolean): void;
|
||||
rangesAreRenameLocations(findInStrings?: boolean, findInComments?: boolean): void;
|
||||
rangesWithSameTextAreRenameLocations(): void;
|
||||
rangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] });
|
||||
/**
|
||||
* Performs `referencesOf` for every range on the whole set.
|
||||
* If `ranges` is omitted, this is `test.ranges()`.
|
||||
@@ -215,6 +217,8 @@ declare namespace FourSlashInterface {
|
||||
currentSignatureParameterCountIs(expected: number): void;
|
||||
currentSignatureTypeParameterCountIs(expected: number): void;
|
||||
currentSignatureHelpIs(expected: string): void;
|
||||
// Checks that there are no compile errors.
|
||||
noErrors(): void;
|
||||
numberOfErrorsInCurrentFile(expected: number): void;
|
||||
baselineCurrentFileBreakpointLocations(): void;
|
||||
baselineCurrentFileNameOrDottedNameSpans(): void;
|
||||
@@ -256,7 +260,7 @@ declare namespace FourSlashInterface {
|
||||
}[]): void;
|
||||
renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string): void;
|
||||
renameInfoFailed(message?: string): void;
|
||||
renameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]): void;
|
||||
renameLocations(startRanges: Range | Range[], options: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: Range[] }): void;
|
||||
|
||||
/** Verify the quick info available at the current marker. */
|
||||
quickInfoIs(expectedText: string, expectedDocumentation?: string): void;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
////typeof C.k./*6*/caller === 'function';
|
||||
////l./*7*/prototype = Object.prototype;
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
for (var i = 1; i <= 7; i++) {
|
||||
goTo.marker('' + i);
|
||||
verify.completionListCount(8);
|
||||
|
||||
@@ -8,4 +8,4 @@
|
||||
////}
|
||||
|
||||
verify.quickInfoAt("", "var M.C.C: typeof M.C");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -20,7 +20,7 @@
|
||||
//// ofT: T;
|
||||
//// ofFooNum: Foo<number>;
|
||||
//// ofInterface: I;
|
||||
//// ofIG4: { x: number };
|
||||
//// ofIG4: { x: number };
|
||||
//// ofIG6: { x: T };
|
||||
//// ofC2: C<number>;
|
||||
//// ofC4: C<{ x: T }>
|
||||
@@ -35,33 +35,33 @@
|
||||
////// T is any
|
||||
////var f_/*a1*/r1 = f.prim1;
|
||||
////var f_/*a2*/r2 = f.prim2;
|
||||
////var f_/*a3*/r3 = f.ofT;
|
||||
////var f_/*a3*/r3 = f.ofT;
|
||||
////var f_/*a4*/r5 = f.ofFooNum;
|
||||
////var f_/*a5*/r8 = f.ofInterface;
|
||||
////var f_/*a6*/r12 = f.ofIG4;
|
||||
////var f_/*a7*/r14 = f.ofIG6;
|
||||
////var f_/*a7*/r14 = f.ofIG6;
|
||||
////var f_/*a8*/r18 = f.ofC2;
|
||||
////var f_/*a9*/r20 = f.ofC4;
|
||||
////var f_/*a9*/r20 = f.ofC4;
|
||||
////
|
||||
////// T is number
|
||||
////var f2_/*b1*/r1 = f2.prim1;
|
||||
////var f2_/*b2*/r2 = f2.prim2;
|
||||
////var f2_/*b3*/r3 = f2.ofT;
|
||||
////var f2_/*b4*/r5 = f2.ofFooNum;
|
||||
////var f2_/*b3*/r3 = f2.ofT;
|
||||
////var f2_/*b4*/r5 = f2.ofFooNum;
|
||||
////var f2_/*b5*/r8 = f2.ofInterface;
|
||||
////var f2_/*b6*/r12 = f2.ofIG4;
|
||||
////var f2_/*b7*/r14 = f2.ofIG6;
|
||||
////var f2_/*b7*/r14 = f2.ofIG6;
|
||||
////var f2_/*b8*/r18 = f2.ofC2;
|
||||
////var f2_/*b9*/r20 = f2.ofC4;
|
||||
////var f2_/*b9*/r20 = f2.ofC4;
|
||||
////
|
||||
////// T is I
|
||||
////var f3_/*c1*/r1 = f3.prim1;
|
||||
////var f3_/*c2*/r2 = f3.prim2;
|
||||
////var f3_/*c3*/r3 = f3.ofT;
|
||||
////var f3_/*c3*/r3 = f3.ofT;
|
||||
////var f3_/*c4*/r5 = f3.ofFooNum;
|
||||
////var f3_/*c5*/r8 = f3.ofInterface;
|
||||
////var f3_/*c6*/r12 = f3.ofIG4;
|
||||
////var f3_/*c7*/r14 = f3.ofIG6;
|
||||
////var f3_/*c7*/r14 = f3.ofIG6;
|
||||
////var f3_/*c8*/r18 = f3.ofC2;
|
||||
////var f3_/*c9*/r20 = f3.ofC4;
|
||||
////
|
||||
@@ -74,20 +74,20 @@
|
||||
////var f4_/*d6*/r12 = f4.ofIG4;
|
||||
////var f4_/*d7*/r14 = f4.ofIG6;
|
||||
////var f4_/*d8*/r18 = f4.ofC2;
|
||||
////var f4_/*d9*/r20 = f4.ofC4;
|
||||
////var f4_/*d9*/r20 = f4.ofC4;
|
||||
////
|
||||
////// T is Foo<number>
|
||||
////var f5_/*e1*/r1 = f5.prim1;
|
||||
////var f5_/*e2*/r2 = f5.prim2;
|
||||
////var f5_/*e3*/r3 = f5.ofT;
|
||||
////var f5_/*e3*/r3 = f5.ofT;
|
||||
////var f5_/*e4*/r5 = f5.ofFooNum;
|
||||
////var f5_/*e5*/r8 = f5.ofInterface;
|
||||
////var f5_/*e6*/r12 = f5.ofIG4;
|
||||
////var f5_/*e7*/r14 = f5.ofIG6;
|
||||
////var f5_/*e7*/r14 = f5.ofIG6;
|
||||
////var f5_/*e8*/r18 = f5.ofC2;
|
||||
////var f5_/*e9*/r20 = f5.ofC4;
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
verify.quickInfos({
|
||||
"a1": "var f_r1: number",
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
////var f_/*a1*/r4 = f.ofFooT;
|
||||
////var f_/*a2*/r7 = f.ofFooFooNum;
|
||||
////var f_/*a3*/r9 = f.ofIG;
|
||||
////var f_/*a5*/r13 = f.ofIG5;
|
||||
////var f_/*a5*/r13 = f.ofIG5;
|
||||
////var f_/*a7*/r17 = f.ofC1;
|
||||
////
|
||||
////// T is number
|
||||
@@ -60,10 +60,10 @@
|
||||
////var f5_/*e1*/r4 = f5.ofFooT;
|
||||
////var f5_/*e2*/r7 = f5.ofFooFooNum;
|
||||
////var f5_/*e3*/r9 = f5.ofIG;
|
||||
////var f5_/*e5*/r13 = f5.ofIG5;
|
||||
////var f5_/*e5*/r13 = f5.ofIG5;
|
||||
////var f5_/*e7*/r17 = f5.ofC1;
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
verify.quickInfos({
|
||||
a1: "var f_r4: Foo<any>",
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
//// value(): T;
|
||||
////}
|
||||
////interface ChainedArray<T> extends ChainedObject<Array<T>> {
|
||||
////
|
||||
////
|
||||
//// extend(...sources: any[]): ChainedArray<T>;
|
||||
////}
|
||||
//// /*1*/
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insert(' ');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -20,7 +20,7 @@
|
||||
////var c/*5*/cc = _(aaa).map(xx => xx.length); // Should not error, should be any[]
|
||||
////var d/*6*/dd = aaa.map(xx => xx.length); // should not error, should be any[]
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
verify.quickInfos({
|
||||
1: "var bb: number[]",
|
||||
2: "var cc: number[]",
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
//// }
|
||||
//// /*2*/
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insertLine("constructor(){}");
|
||||
edit.insertLine("foo(a: T) {");
|
||||
edit.insertLine(" return a;");
|
||||
edit.insertLine("}");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('2');
|
||||
edit.insertLine("var x = new C<number>();");
|
||||
edit.insertLine("var y: number = x.foo(5);");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
//// /*1*/
|
||||
|
||||
goTo.marker('1');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -63,13 +63,13 @@
|
||||
//// }
|
||||
//// /*1*/
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insertLine('');
|
||||
edit.insertLine('');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('2');
|
||||
edit.deleteAtCaret("Cookie".length);
|
||||
edit.insert("any");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
edit.insertLine('var narnia = new GenericPlanet2<Cookie, string>('); // shouldn't crash at this point
|
||||
@@ -30,4 +30,4 @@ verify.quickInfos({
|
||||
4: "var r4: any",
|
||||
41: "(method) Underscore.Static.all<any>(list: any[], iterator?: Underscore.Iterator<any, boolean>, context?: any): any"
|
||||
});
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -30,4 +30,4 @@ verify.quickInfos({
|
||||
4: "var r4: any",
|
||||
41: "(method) Underscore.Static.all<any>(list: any[], iterator?: Underscore.Iterator<any, boolean>, context?: any): any"
|
||||
});
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -5,4 +5,9 @@
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}x|] } from "./m";
|
||||
////const y = [|x|];
|
||||
|
||||
verify.singleReferenceGroup("var x: number");
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
const defs = { definition: "var x: number", ranges: [r0] };
|
||||
const imports = { definition: "import x", ranges: [r1, r2] };
|
||||
verify.referenceGroups(r0, [defs, imports]);
|
||||
verify.referenceGroups([r1, r2], [imports, defs]);
|
||||
|
||||
@@ -4,6 +4,4 @@
|
||||
// @Filename: File.d.ts
|
||||
//// declare var v: string;
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
//// interface privateInterface {}
|
||||
//// export class Bar implements /*1*/privateInterface/*2*/{ }
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
//// }
|
||||
|
||||
verify.allRangesAppearInImplementationList("function_call");
|
||||
verify.allRangesAppearInImplementationList("declaration");
|
||||
verify.allRangesAppearInImplementationList("declaration");
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
|
||||
goTo.marker('1');
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
edit.insert("//");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -7,16 +7,11 @@
|
||||
//// class Foo {
|
||||
//// constructor() {
|
||||
//// this.[|union|] = 'foo';
|
||||
//// this./*1*/[|union|] = 100;
|
||||
//// this.[|union|] = 100;
|
||||
//// }
|
||||
//// method() { return this./*2*/[|union|]; }
|
||||
//// method() { return this.[|union|]; }
|
||||
//// }
|
||||
//// var x = new Foo();
|
||||
//// x./*3*/[|union|];
|
||||
//// x.[|union|];
|
||||
|
||||
goTo.marker('1');
|
||||
verify.renameLocations(/*findInStrings*/false, /*findInComments*/false);
|
||||
goTo.marker('2');
|
||||
verify.renameLocations(/*findInStrings*/false, /*findInComments*/false);
|
||||
goTo.marker('3');
|
||||
verify.renameLocations(/*findInStrings*/false, /*findInComments*/false);
|
||||
verify.rangesAreRenameLocations();
|
||||
|
||||
@@ -29,4 +29,4 @@ verify.completionListContains("name");
|
||||
edit.insert("name;\nsausages.");
|
||||
verify.completionListContains("eggs");
|
||||
edit.insert("eggs;");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -7,5 +7,4 @@
|
||||
//// * @param {function (string):void} y */
|
||||
//// function fn(x, y) { }
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
|
||||
verify.noErrors();
|
||||
|
||||
@@ -18,6 +18,4 @@
|
||||
//// var x = <MyClass {...[|n/*src*/n|]}></MyClass>;
|
||||
|
||||
verify.goToDefinition("src", "dst");
|
||||
|
||||
goTo.marker('src');
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
verify.rangesAreRenameLocations();
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
//// return this.m(0);
|
||||
//// }
|
||||
//// }
|
||||
//// export class B extends A {
|
||||
//// export class B extends A {
|
||||
//// constructor(a: string) {
|
||||
//// super(a);
|
||||
//// }
|
||||
//// /*1*/
|
||||
//// /*1*/
|
||||
//// }
|
||||
//// var a = new A("s");
|
||||
//// var b = new B("s");
|
||||
//// }
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insert("public m(n: number) { return 0; }");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//// export class B extends A { /*1*/ }
|
||||
//// }
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
goTo.marker('1');
|
||||
edit.insert("public m(n: number) { return 0; }");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -17,7 +17,7 @@
|
||||
//// r4 = x; // 3
|
||||
////}
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
verify.eval("r1", undefined);
|
||||
verify.eval("r2", 2);
|
||||
verify.eval("r3", 2);
|
||||
|
||||
@@ -39,4 +39,4 @@ verify.completionListContains('x');
|
||||
verify.completionListContains('foo');
|
||||
verify.completionListContains('boo');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -30,4 +30,4 @@ verify.completionListContains('x');
|
||||
verify.completionListContains('foo');
|
||||
edit.insert('x;');
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
@@ -6,6 +6,6 @@
|
||||
////(y) => y;
|
||||
////x => x;
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
verify.not.errorExistsBeforeMarker();
|
||||
verify.not.errorExistsAfterMarker();
|
||||
@@ -18,7 +18,7 @@
|
||||
////const x = foo/*foo_value*/;
|
||||
////const i: foo/*foo_type*/ = { x: 1, y: 2 };
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
verify.navigationItemsListCount(2, "foo", "exact");
|
||||
verify.navigationItemsListContains("foo", "alias", "foo", "exact");
|
||||
@@ -49,7 +49,6 @@ verify.goToDefinitionIs("foo_type_declaration");
|
||||
////const x = bar/*bar_value*/;
|
||||
////const i: bar/*bar_type*/ = { x: 1, y: 2 };
|
||||
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.navigationItemsListCount(2, "bar", "exact");
|
||||
verify.navigationItemsListContains("bar", "alias", "bar", "exact");
|
||||
verify.navigationItemsListContains("bar", "interface", "bar", "exact");
|
||||
|
||||
@@ -23,4 +23,4 @@ edit.insert('a');
|
||||
verify.quickInfoIs("(property) B<string>.bar: string");
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs("var r4: string");
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
////}
|
||||
|
||||
verify.quickInfoAt("1", "(property) M2.A.foo: string", undefined);
|
||||
verify.numberOfErrorsInCurrentFile(0);
|
||||
verify.noErrors();
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: /defA.ts
|
||||
////declare module "a" {
|
||||
//// export type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
|
||||
////}
|
||||
|
||||
// @Filename: /defB.ts
|
||||
////declare module "b" {
|
||||
//// export import a = require("a");
|
||||
//// export const x: a.[|T|];
|
||||
////}
|
||||
|
||||
// @Filename: /defC.ts
|
||||
////declare module "c" {
|
||||
//// import b = require("b");
|
||||
//// const x: b.a.[|T|];
|
||||
////}
|
||||
|
||||
verify.noErrors();
|
||||
verify.singleReferenceGroup("type T = number");
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@Filename: a.ts
|
||||
////var /*1*/[|x|]: number;
|
||||
////var [|x|]: number;
|
||||
|
||||
//@Filename: b.ts
|
||||
/////// <reference path="a.ts" />
|
||||
@@ -11,7 +11,4 @@
|
||||
/////// <reference path="a.ts" />
|
||||
////[|x|]++;
|
||||
|
||||
goTo.file("a.ts");
|
||||
goTo.marker("1");
|
||||
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
||||
verify.rangesAreRenameLocations();
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
////export = [|SomeModule|];
|
||||
|
||||
// @Filename: b.ts
|
||||
////import M = require("./a");
|
||||
////import C = M.SomeClass;
|
||||
////import [|M|] = require("./a");
|
||||
////import C = [|M|].SomeClass;
|
||||
|
||||
verify.rangesAreRenameLocations();
|
||||
const [r0, r1, r2, r3] = test.ranges();
|
||||
verify.rangesAreRenameLocations([r0, r1]);
|
||||
verify.rangesAreRenameLocations([r2, r3]);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
///////<reference path="./Bar.ts" />
|
||||
///////<reference path="./Bar.ts" />
|
||||
|
||||
////function /**/[|Bar|]() {
|
||||
////function [|Bar|]() {
|
||||
//// // This is a reference to Bar in a comment.
|
||||
//// "this is a reference to Bar in a string"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations(/*findInStrings:*/ false, /*findInComments:*/ false);
|
||||
verify.rangesAreRenameLocations();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
///////<reference path="./Bar.ts" />
|
||||
///////<reference path="./Bar.ts" />
|
||||
|
||||
////function /**/[|Bar|]() {
|
||||
////function [|Bar|]() {
|
||||
//// // This is a reference to Bar in a comment.
|
||||
//// "this is a reference to [|Bar|] in a string"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations(/*findInStrings:*/ true, /*findInComments:*/ false);
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges[0], { findInStrings: true, ranges })
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
///////<reference path="./Bar.ts" />
|
||||
///////<reference path="./Bar.ts" />
|
||||
|
||||
////function /**/[|Bar|]() {
|
||||
////function [|Bar|]() {
|
||||
//// // This is a reference to [|Bar|] in a comment.
|
||||
//// "this is a reference to Bar in a string"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations(/*findInStrings:*/ false, /*findInComments:*/ true);
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges[0], { findInComments: true, ranges });
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
///////<reference path="./Bar.ts" />
|
||||
///////<reference path="./Bar.ts" />
|
||||
|
||||
////function /**/[|Bar|]() {
|
||||
//// // This is a reference to [|Bar|] in a comment.
|
||||
//// "this is a reference to [|Bar|] in a string"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations(/*findInStrings:*/ true, /*findInComments:*/ true);
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges[0], { findInStrings: true, findInComments: true, ranges });
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
// @Filename: b.ts
|
||||
////import { [|area|] } from './a';
|
||||
////var t = /**/[|area|](10);
|
||||
////var t = [|area|](10);
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
||||
verify.rangesAreRenameLocations()
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////exports./**/[|area|] = function (r) { return r * r; }
|
||||
|
||||
// @Filename: b.ts
|
||||
////import { [|area|] } from './a';
|
||||
////var t = [|area|](10);
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
||||
@@ -16,14 +16,15 @@ verify.occurrencesAtPositionCount(1);
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [C, B0, B1] = ranges;
|
||||
verify.referenceGroups([C, B0], [{ definition: "class B", ranges }]);
|
||||
verify.referenceGroups(B1, [{ definition: "constructor B(): B", ranges }]);
|
||||
|
||||
goTo.rangeStart(C);
|
||||
verify.renameLocations(false, false, [C, B0, B1]);
|
||||
const classes = { definition: "class B", ranges: [C] };
|
||||
const imports = { definition: "import B", ranges: [B0, B1] };
|
||||
verify.referenceGroups(C, [classes, imports]);
|
||||
verify.referenceGroups(B0, [imports, classes]);
|
||||
verify.referenceGroups(B1, [
|
||||
{ definition: "(alias) new B(): B\nimport B", ranges: [B0, B1] },
|
||||
classes
|
||||
]);
|
||||
|
||||
const rangesInB = [B0, B1];
|
||||
for (const r of rangesInB) {
|
||||
goTo.rangeStart(r);
|
||||
verify.renameLocations(false, false, rangesInB);
|
||||
}
|
||||
verify.renameLocations(C, ranges);
|
||||
verify.rangesAreRenameLocations([B0, B1]);
|
||||
|
||||
@@ -16,14 +16,12 @@ verify.occurrencesAtPositionCount(1);
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [C, B0, B1] = ranges;
|
||||
verify.referenceGroups([C, B0], [{ definition: "class C", ranges }]);
|
||||
verify.referenceGroups(B1, [{ definition: "constructor C(): B", ranges }]);
|
||||
const bRanges = [B0, B1];
|
||||
const classes = { definition: "class C", ranges: [C] };
|
||||
const imports = { definition: "import B", ranges: [B0, B1] };
|
||||
verify.referenceGroups(C, [classes, imports]);
|
||||
verify.referenceGroups(B0, [imports]);
|
||||
verify.referenceGroups(B1, [{ definition: "(alias) new B(): B\nimport B", ranges: bRanges }]);
|
||||
|
||||
goTo.rangeStart(C);
|
||||
verify.renameLocations(false, false, [C, B0, B1]);
|
||||
|
||||
const rangesInB = [B0, B1];
|
||||
for (const r of rangesInB) {
|
||||
goTo.rangeStart(r);
|
||||
verify.renameLocations(false, false, rangesInB);
|
||||
}
|
||||
verify.rangesAreRenameLocations([C]);
|
||||
verify.rangesAreRenameLocations(bRanges);
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I {
|
||||
//// /*1*/[|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////var elems: I[];
|
||||
////
|
||||
////var p2: number, property1: number;
|
||||
////for ({ [|property1|] } = elems[0]; p2 < 100; p2++) {
|
||||
//// p2 = property1++;
|
||||
////interface I {
|
||||
//// [|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////for ({ /*2*/[|property1|]: p2 } = elems[0]; p2 < 100; p2++) {
|
||||
////var elems: I[];
|
||||
////
|
||||
////var p2: number, property1: number;
|
||||
////for ({ [|property1|] } = elems[0]; p2 < 100; p2++) {
|
||||
//// p2 = property1++;
|
||||
////}
|
||||
////for ({ [|property1|]: p2 } = elems[0]; p2 < 100; p2++) {
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
const ranges = test.ranges();
|
||||
const [r0, , r2] = ranges;
|
||||
verify.renameLocations([r0, r2], ranges);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I {
|
||||
//// /*1*/[|property1|]: number;
|
||||
//// [|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////var elems: I[];
|
||||
@@ -9,12 +9,10 @@
|
||||
////var property1: number, p2: number;
|
||||
////for ({ [|property1|] } of elems) {
|
||||
//// property1++;
|
||||
////}
|
||||
////for ({ /*2*/[|property1|]: p2 } of elems) {
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
////}
|
||||
////for ({ [|property1|]: p2 } of elems) {
|
||||
////}
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, , r2] = ranges;
|
||||
verify.renameLocations([r0, r2], ranges);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface I {
|
||||
//// /*1*/[|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////var elems: I[], p1: number, property1: number;
|
||||
////[{ /*2*/[|property1|]: p1 }] = elems;
|
||||
////[{ [|property1|] }] = elems;
|
||||
////interface I {
|
||||
//// [|property1|]: number;
|
||||
//// property2: string;
|
||||
////}
|
||||
////var elems: I[], p1: number, property1: number;
|
||||
////[{ [|property1|]: p1 }] = elems;
|
||||
////[{ [|property1|] }] = elems;
|
||||
|
||||
goTo.marker("1");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.renameLocations([r0, r1], ranges);
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface MultiRobot {
|
||||
//// name: string;
|
||||
//// skills: {
|
||||
//// /*1*/[|primary|]: string;
|
||||
//// [|primary|]: string;
|
||||
//// secondary: string;
|
||||
//// };
|
||||
////}
|
||||
////let multiRobot: MultiRobot;
|
||||
////for ({ skills: { /*2*/[|primary|]: primaryA, secondary: secondaryA } } = multiRobot, i = 0; i < 1; i++) {
|
||||
////for ({ skills: { [|primary|]: primaryA, secondary: secondaryA } } = multiRobot, i = 0; i < 1; i++) {
|
||||
//// console.log(primaryA);
|
||||
////}
|
||||
////for ({ skills: { [|primary|], secondary } } = multiRobot, i = 0; i < 1; i++) {
|
||||
//// console.log(primary);
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.renameLocations([r0, r1], ranges);
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////interface MultiRobot {
|
||||
//// name: string;
|
||||
//// skills: {
|
||||
//// /*1*/[|primary|]: string;
|
||||
//// [|primary|]: string;
|
||||
//// secondary: string;
|
||||
//// };
|
||||
////}
|
||||
////let multiRobots: MultiRobot[];
|
||||
////for ({ skills: { /*2*/[|primary|]: primaryA, secondary: secondaryA } } of multiRobots) {
|
||||
////for ({ skills: { [|primary|]: primaryA, secondary: secondaryA } } of multiRobots) {
|
||||
//// console.log(primaryA);
|
||||
////}
|
||||
////for ({ skills: { [|primary|], secondary } } of multiRobots) {
|
||||
//// console.log(primary);
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ false);
|
||||
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1] = ranges;
|
||||
verify.renameLocations([r0, r1], ranges);
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////export default class /*1*/[|DefaultExportedClass|] {
|
||||
////export default class [|DefaultExportedClass|] {
|
||||
////}
|
||||
/////*
|
||||
//// * Commenting [|DefaultExportedClass|]
|
||||
//// * Commenting [|{| "inComment": true |}DefaultExportedClass|]
|
||||
//// */
|
||||
////
|
||||
////var x: /*2*/[|DefaultExportedClass|];
|
||||
////var x: [|DefaultExportedClass|];
|
||||
////
|
||||
////var y = new /*3*/[|DefaultExportedClass|];
|
||||
////var y = new [|DefaultExportedClass|];
|
||||
|
||||
goTo.eachMarker(() => verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true));
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges.filter(r => !(r.marker && r.marker.data.inComment)), { findInComments: true, ranges });
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
//// return /*2*/[|DefaultExportedFunction|]
|
||||
////}
|
||||
/////**
|
||||
//// * Commenting [|DefaultExportedFunction|]
|
||||
//// * Commenting [|{| "inComment": true |}DefaultExportedFunction|]
|
||||
//// */
|
||||
////
|
||||
////var x: typeof /*3*/[|DefaultExportedFunction|];
|
||||
////
|
||||
////var y = /*4*/[|DefaultExportedFunction|]();
|
||||
|
||||
goTo.eachMarker(() => verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true));
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges.filter(r => !(r.marker && r.marker.data.inComment)), { findInComments: true, ranges });
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
////var y = /*4*/[|f|]();
|
||||
////
|
||||
/////**
|
||||
//// * Commenting [|f|]
|
||||
//// * Commenting [|{| "inComment": true |}f|]
|
||||
//// */
|
||||
////namespace /*5*/[|f|] {
|
||||
//// var local = 100;
|
||||
////}
|
||||
|
||||
goTo.eachMarker(() => verify.renameLocations(/*findInStrings*/ false, /*findInComments*/ true));
|
||||
const ranges = test.ranges();
|
||||
verify.renameLocations(ranges.filter(r => !(r.marker && r.marker.data.inComment)), { findInComments: true, ranges });
|
||||
|
||||
@@ -7,4 +7,11 @@
|
||||
////import { [|{| "isWriteAccess": true, "isDefinition": true |}a|] } from './a';
|
||||
////export { [|{| "isWriteAccess": true, "isDefinition": true |}a|] };
|
||||
|
||||
verify.singleReferenceGroup("var a: any");
|
||||
const ranges = test.ranges();
|
||||
const [r0, r1, r2] = ranges;
|
||||
const vars = { definition: "var a: any", ranges: [r0] };
|
||||
const imports = { definition: "import a", ranges: [r1, r2] };
|
||||
verify.referenceGroups(r0, [vars, imports]);
|
||||
verify.referenceGroups(r1, [imports, vars]);
|
||||
verify.referenceGroups(r2, [imports, vars]);
|
||||
verify.rangesAreRenameLocations();
|
||||
|
||||
@@ -1,14 +1,35 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
////declare namespace N {
|
||||
//// export var x: number;
|
||||
////declare namespace [|{| "isWriteAccess": true, "isDefinition": true |}N|] {
|
||||
//// export var [|{| "isWriteAccess": true, "isDefinition": true |}x|]: number;
|
||||
////}
|
||||
////declare module "mod" {
|
||||
//// export = N;
|
||||
//// export = [|N|];
|
||||
////}
|
||||
////declare module "test" {
|
||||
//// import * as [|N|] from "mod";
|
||||
//// export { [|N|] }; // Renaming N here would rename
|
||||
////declare module "a" {
|
||||
//// import * as [|{| "isWriteAccess": true, "isDefinition": true |}N|] from "mod";
|
||||
//// export { [|{| "isWriteAccess": true, "isDefinition": true |}N|] }; // Renaming N here would rename
|
||||
////}
|
||||
////declare module "b" {
|
||||
//// import { [|{| "isWriteAccess": true, "isDefinition": true |}N|] } from "a";
|
||||
//// export const y: typeof [|N|].[|x|];
|
||||
////}
|
||||
|
||||
verify.rangesAreRenameLocations();
|
||||
const [N0, x0, N1, a0, a1, b0, b1, x1] = test.ranges();
|
||||
const nRanges = [N0, N1];
|
||||
const aRanges = [a0, a1];
|
||||
const bRanges = [b0, b1];
|
||||
const xRanges = [x0, x1];
|
||||
|
||||
const nGroup = { definition: "namespace N", ranges: nRanges };
|
||||
const aGroup = { definition: "import N", ranges: aRanges };
|
||||
const bGroup = { definition: "import N", ranges: [b0, b1] };
|
||||
|
||||
verify.referenceGroups(nRanges, [nGroup, aGroup, bGroup]);
|
||||
verify.referenceGroups([a0, a1], [aGroup, nGroup, bGroup]);
|
||||
verify.referenceGroups(bRanges, [bGroup, aGroup, nGroup]);
|
||||
verify.singleReferenceGroup("var N.x: number", xRanges);
|
||||
|
||||
verify.renameLocations(nRanges, nRanges.concat(aRanges, bRanges));
|
||||
verify.rangesAreRenameLocations(aRanges.concat(bRanges));
|
||||
verify.rangesAreRenameLocations(xRanges);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user