diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index ea6ccd68fbc35..52ac86263fda3 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -997,18 +997,43 @@ namespace FourSlash { definition: string | { text: string, range: ts.TextSpan }; references: ts.ReferenceEntry[]; } + interface RangeMarkerData { + id?: string; + isWriteAccess?: boolean, + isDefinition?: boolean, + isInString?: true, + contextRangeIndex?: number, + contextRangeDelta?: number, + contextRangeId?: string + } const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition: typeof definition === "string" ? definition : { ...definition, range: ts.createTextSpanFromRange(definition.range) }, references: ranges.map(r => { - const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex } = (r.marker && r.marker.data || {}) as { isWriteAccess?: boolean, isDefinition?: boolean, isInString?: true, contextRangeIndex?: number }; + const { isWriteAccess = false, isDefinition = false, isInString, contextRangeIndex, contextRangeDelta, contextRangeId } = (r.marker && r.marker.data || {}) as RangeMarkerData; + let contextSpan: ts.TextSpan | undefined; + if (contextRangeDelta !== undefined) { + const allRanges = this.getRanges(); + const index = allRanges.indexOf(r); + if (index !== -1) { + contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]); + } + } + else if (contextRangeId !== undefined) { + const allRanges = this.getRanges(); + const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId); + if (contextRange) { + contextSpan = ts.createTextSpanFromRange(contextRange); + } + } + else if (contextRangeIndex !== undefined) { + contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]); + } return { - fileName: r.fileName, textSpan: ts.createTextSpanFromRange(r), + fileName: r.fileName, + ...(contextSpan ? { contextSpan } : undefined), isWriteAccess, isDefinition, - ...(contextRangeIndex !== undefined ? - { contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } : - undefined), ...(isInString ? { isInString: true } : undefined), }; }), @@ -1032,7 +1057,7 @@ namespace FourSlash { } public verifyNoReferences(markerNameOrRange?: string | Range) { - if (markerNameOrRange) this.goToMarkerOrRange(markerNameOrRange); + if (markerNameOrRange !== undefined) this.goToMarkerOrRange(markerNameOrRange); const refs = this.getReferencesAtCaret(); if (refs && refs.length) { this.raiseError(`Expected getReferences to fail, but saw references: ${stringify(refs)}`); @@ -1233,6 +1258,12 @@ namespace FourSlash { } public verifyRenameLocations(startRanges: ArrayOrSingle, options: FourSlashInterface.RenameLocationsOptions) { + interface RangeMarkerData { + id?: string; + contextRangeIndex?: number, + contextRangeDelta?: number + contextRangeId?: string; + } const { findInStrings = false, findInComments = false, ranges = this.getRanges(), providePrefixAndSuffixTextForRename = true } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options, providePrefixAndSuffixTextForRename: true } : options; const _startRanges = toArray(startRanges); @@ -1253,13 +1284,29 @@ namespace FourSlash { locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start); assert.deepEqual(sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => { const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions }; // eslint-disable-line no-in-operator - const { contextRangeIndex } = (range.marker && range.marker.data || {}) as { contextRangeIndex?: number; }; + const { contextRangeIndex, contextRangeDelta, contextRangeId } = (range.marker && range.marker.data || {}) as RangeMarkerData; + let contextSpan: ts.TextSpan | undefined; + if (contextRangeDelta !== undefined) { + const allRanges = this.getRanges(); + const index = allRanges.indexOf(range); + if (index !== -1) { + contextSpan = ts.createTextSpanFromRange(allRanges[index + contextRangeDelta]); + } + } + else if (contextRangeId !== undefined) { + const allRanges = this.getRanges(); + const contextRange = ts.find(allRanges, range => (range.marker?.data as RangeMarkerData)?.id === contextRangeId); + if (contextRange) { + contextSpan = ts.createTextSpanFromRange(contextRange); + } + } + else if (contextRangeIndex !== undefined) { + contextSpan = ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]); + } return { fileName: range.fileName, textSpan: ts.createTextSpanFromRange(range), - ...(contextRangeIndex !== undefined ? - { contextSpan: ts.createTextSpanFromRange(this.getRanges()[contextRangeIndex]) } : - undefined), + ...(contextSpan ? { contextSpan } : undefined), ...prefixSuffixText }; }))); @@ -3589,19 +3636,41 @@ namespace FourSlash { // Parse out the files and their metadata const testData = parseTestData(absoluteBasePath, content, absoluteFileName); const state = new TestState(absoluteFileName, absoluteBasePath, testType, testData); - const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } }); + const actualFileName = Harness.IO.resolvePath(fileName) || absoluteFileName; + const output = ts.transpileModule(content, { reportDiagnostics: true, fileName: actualFileName, compilerOptions: { target: ts.ScriptTarget.ES2015, inlineSourceMap: true } }); if (output.diagnostics!.length > 0) { throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`); } - runCode(output.outputText, state); + runCode(output.outputText, state, actualFileName); } - function runCode(code: string, state: TestState): void { + function runCode(code: string, state: TestState, fileName: string): void { // Compile and execute the test - const wrappedCode = - `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) { -${code} -})`; + const generatedFile = ts.changeExtension(fileName, ".js"); + const wrappedCode = `(function(test, goTo, plugins, verify, edit, debug, format, cancellation, classification, completion, verifyOperationIsCancelled) {${code}\n//# sourceURL=${generatedFile}\n})`; + + type SourceMapSupportModule = typeof import("source-map-support") & { + // TODO(rbuckton): This is missing from the DT definitions and needs to be added. + resetRetrieveHandlers(): void + }; + + // Provide the content of the current test to 'source-map-support' so that it can give us the correct source positions + // for test failures. + let sourceMapSupportModule: SourceMapSupportModule | undefined; + try { + sourceMapSupportModule = require("source-map-support"); + } + catch { + // do nothing + } + + sourceMapSupportModule?.install({ + retrieveFile: path => { + return path === generatedFile ? wrappedCode : + undefined!; + } + }); + try { const test = new FourSlashInterface.Test(state); const goTo = new FourSlashInterface.GoTo(state); @@ -3616,8 +3685,13 @@ ${code} f(test, goTo, plugins, verify, edit, debug, format, cancellation, FourSlashInterface.Classification, FourSlashInterface.Completion, verifyOperationIsCancelled); } catch (err) { + // ensure 'source-map-support' is triggered while we still have the handler attached by accessing `error.stack`. + err.stack?.toString(); throw err; } + finally { + sourceMapSupportModule?.resetRetrieveHandlers(); + } } function chompLeadingSpace(content: string) { diff --git a/src/services/callHierarchy.ts b/src/services/callHierarchy.ts index 838f9355d3dca..a924bc2809108 100644 --- a/src/services/callHierarchy.ts +++ b/src/services/callHierarchy.ts @@ -293,7 +293,7 @@ namespace ts.CallHierarchy { return []; } const location = getCallHierarchyDeclarationReferenceNode(declaration); - const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, /*options*/ undefined, convertEntryToCallSite), isDefined); + const calls = filter(FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, program.getSourceFiles(), location, /*position*/ 0, { use: FindAllReferences.FindReferencesUse.References }, convertEntryToCallSite), isDefined); return calls ? group(calls, getCallSiteGroupKey, entries => convertCallSiteGroupToIncomingCall(program, entries)) : []; } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index b4f1c19837dd1..920d2dcc573ea 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -171,14 +171,27 @@ namespace ts.FindAllReferences { undefined; } + export const enum FindReferencesUse { + /** + * When searching for references to a symbol, the location will not be adjusted (this is the default behavior when not specified). + */ + Other, + /** + * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword. + */ + References, + /** + * When searching for references to a symbol, the location will be adjusted if the cursor was on a keyword. + * Unlike `References`, the location will only be adjusted keyword belonged to a declaration with a valid name. + * If set, we will find fewer references -- if it is referenced by several different names, we still only find references for the original name. + */ + Rename, + } + export interface Options { readonly findInStrings?: boolean; readonly findInComments?: boolean; - /** - * True if we are renaming the symbol. - * If so, we will find fewer references -- if it is referenced by several different names, we still only find references for the original name. - */ - readonly isForRename?: boolean; + readonly use?: FindReferencesUse; /** True if we are searching for implementations. We will have a different method of adding references if so. */ readonly implementations?: boolean; /** @@ -191,7 +204,7 @@ namespace ts.FindAllReferences { export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: readonly SourceFile[], sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined { const node = getTouchingPropertyName(sourceFile, position); - const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken); + const referencedSymbols = Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, { use: FindReferencesUse.References }); const checker = program.getTypeChecker(); return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) => // Only include referenced symbols that have a valid definition. @@ -229,7 +242,7 @@ namespace ts.FindAllReferences { } else { // Perform "Find all References" and retrieve only those that are implementations - return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true }); + return getReferenceEntriesForNode(position, node, program, sourceFiles, cancellationToken, { implementations: true, use: FindReferencesUse.References }); } } @@ -502,6 +515,7 @@ namespace ts.FindAllReferences { case SyntaxKind.ModuleDeclaration: case SyntaxKind.NamespaceExportDeclaration: case SyntaxKind.NamespaceImport: + case SyntaxKind.NamespaceExport: case SyntaxKind.Parameter: case SyntaxKind.ShorthandPropertyAssignment: case SyntaxKind.TypeAliasDeclaration: @@ -539,6 +553,12 @@ namespace ts.FindAllReferences { export namespace Core { /** Core find-all-references algorithm. Handles special cases before delegating to `getReferencedSymbolsForSymbol`. */ export function getReferencedSymbolsForNode(position: number, node: Node, program: Program, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap = arrayToSet(sourceFiles, f => f.fileName)): readonly SymbolAndEntries[] | undefined { + if (options.use === FindReferencesUse.References) { + node = getAdjustedReferenceLocation(node); + } + else if (options.use === FindReferencesUse.Rename) { + node = getAdjustedRenameLocation(node); + } if (isSourceFile(node)) { const reference = GoToDefinition.getReferenceAtPosition(node, position, program); const moduleSymbol = reference && program.getTypeChecker().getMergedSymbol(reference.file.symbol); @@ -723,6 +743,11 @@ namespace ts.FindAllReferences { /** getReferencedSymbols for special node kinds. */ function getReferencedSymbolsSpecial(node: Node, sourceFiles: readonly SourceFile[], cancellationToken: CancellationToken): SymbolAndEntries[] | undefined { if (isTypeKeyword(node.kind)) { + // A void expression (i.e., `void foo()`) is not special, but the `void` type is. + if (node.kind === SyntaxKind.VoidKeyword && isVoidExpression(node.parent)) { + return undefined; + } + // A modifier readonly (like on a property declaration) is not special; // a readonly type keyword (like `readonly string[]`) is. if (node.kind === SyntaxKind.ReadonlyKeyword && !isReadonlyTypeOperator(node)) { @@ -779,7 +804,7 @@ namespace ts.FindAllReferences { searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state); } else { - const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, !!options.isForRename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] }); + const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, options.use === FindReferencesUse.Rename, !!options.providePrefixAndSuffixTextForRename, !!options.implementations) : [symbol] }); getReferencesInContainerOrFiles(symbol, state, search); } @@ -920,7 +945,7 @@ namespace ts.FindAllReferences { /** Gets every place to look for references of an exported symbols. See `ImportsResult` in `importTracker.ts` for more documentation. */ getImportSearches(exportSymbol: Symbol, exportInfo: ExportInfo): ImportsResult { if (!this.importTracker) this.importTracker = createImportTracker(this.sourceFiles, this.sourceFilesSet, this.checker, this.cancellationToken); - return this.importTracker(exportSymbol, exportInfo, !!this.options.isForRename); + return this.importTracker(exportSymbol, exportInfo, this.options.use === FindReferencesUse.Rename); } /** @param allSearchSymbols set of additional symbols for use by `includes`. */ @@ -1001,7 +1026,7 @@ namespace ts.FindAllReferences { break; case ExportKind.Default: // Search for a property access to '.default'. This can't be renamed. - indirectSearch = state.options.isForRename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" }); + indirectSearch = state.options.use === FindReferencesUse.Rename ? undefined : state.createSearch(exportLocation, exportSymbol, ImportExport.Export, { text: "default" }); break; case ExportKind.ExportEquals: break; @@ -1041,7 +1066,7 @@ namespace ts.FindAllReferences { function shouldAddSingleReference(singleRef: Identifier | StringLiteral, state: State): boolean { if (!hasMatchingMeaning(singleRef, state)) return false; - if (!state.options.isForRename) return true; + if (state.options.use !== FindReferencesUse.Rename) return true; // Don't rename an import type `import("./module-name")` when renaming `name` in `export = name;` if (!isIdentifier(singleRef)) return false; // At `default` in `import { default as x }` or `export { default as x }`, do add a reference, but do not rename. @@ -1373,7 +1398,7 @@ namespace ts.FindAllReferences { if (!propertyName) { // Don't rename at `export { default } from "m";`. (but do continue to search for imports of the re-export) - if (!(state.options.isForRename && (name.escapedText === InternalSymbolName.Default))) { + if (!(state.options.use === FindReferencesUse.Rename && (name.escapedText === InternalSymbolName.Default))) { addRef(); } } @@ -1384,7 +1409,7 @@ namespace ts.FindAllReferences { addRef(); } - if (addReferencesHere && !state.options.isForRename && state.markSeenReExportRHS(name)) { + if (addReferencesHere && state.options.use !== FindReferencesUse.Rename && state.markSeenReExportRHS(name)) { addReference(name, Debug.assertDefined(exportSpecifier.symbol), state); } } @@ -1503,7 +1528,7 @@ namespace ts.FindAllReferences { function addClassStaticThisReferences(referenceLocation: Node, search: Search, state: State): void { addReference(referenceLocation, search.symbol, state); const classLike = referenceLocation.parent; - if (state.options.isForRename || !isClassLike(classLike)) return; + if (state.options.use === FindReferencesUse.Rename || !isClassLike(classLike)) return; Debug.assert(classLike.name === referenceLocation); const addRef = state.referenceAdder(search.symbol); for (const member of classLike.members) { @@ -1961,7 +1986,7 @@ namespace ts.FindAllReferences { function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined { const { checker } = state; return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false, - /*onlyIncludeBindingElementAtReferenceLocation*/ !state.options.isForRename || !!state.options.providePrefixAndSuffixTextForRename, + /*onlyIncludeBindingElementAtReferenceLocation*/ state.options.use !== FindReferencesUse.Rename || !!state.options.providePrefixAndSuffixTextForRename, (sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => search.includes(baseSymbol || rootSymbol || sym) // For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol. ? { symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, kind } @@ -2054,7 +2079,7 @@ namespace ts.FindAllReferences { } function isForRenameWithPrefixAndSuffixText(options: Options) { - return options.isForRename && options.providePrefixAndSuffixTextForRename; + return options.use === FindReferencesUse.Rename && options.providePrefixAndSuffixTextForRename; } } } diff --git a/src/services/rename.ts b/src/services/rename.ts index 775051a8364c3..3251dee6cd4a8 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -1,11 +1,14 @@ /* @internal */ namespace ts.Rename { export function getRenameInfo(program: Program, sourceFile: SourceFile, position: number, options?: RenameInfoOptions): RenameInfo { - const node = getTouchingPropertyName(sourceFile, position); - const renameInfo = node && nodeIsEligibleForRename(node) - ? getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, declaration => program.isSourceFileDefaultLibrary(declaration.getSourceFile()), options) - : undefined; - return renameInfo || getRenameInfoError(Diagnostics.You_cannot_rename_this_element); + const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); + if (nodeIsEligibleForRename(node)) { + const renameInfo = getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, declaration => program.isSourceFileDefaultLibrary(declaration.getSourceFile()), options); + if (renameInfo) { + return renameInfo; + } + } + return getRenameInfoError(Diagnostics.You_cannot_rename_this_element); } function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean, options?: RenameInfoOptions): RenameInfo | undefined { diff --git a/src/services/services.ts b/src/services/services.ts index 1a3eae675e62c..0c45e3f2d6ba5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1608,7 +1608,7 @@ namespace ts { function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): RenameLocation[] | undefined { synchronizeHostData(); const sourceFile = getValidSourceFile(fileName); - const node = getTouchingPropertyName(sourceFile, position); + const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position)); if (isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) && isIntrinsicJsxName(node.escapedText)) { const { openingElement, closingElement } = node.parent.parent; return [openingElement, closingElement].map((node): RenameLocation => { @@ -1621,21 +1621,21 @@ namespace ts { }); } else { - return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, isForRename: true }, + return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, use: FindAllReferences.FindReferencesUse.Rename }, (entry, originalNode, checker) => FindAllReferences.toRenameLocation(entry, originalNode, checker, providePrefixAndSuffixTextForRename || false)); } } function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] | undefined { synchronizeHostData(); - return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, {}, FindAllReferences.toReferenceEntry); + return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { use: FindAllReferences.FindReferencesUse.References }, FindAllReferences.toReferenceEntry); } function getReferencesWorker(node: Node, position: number, options: FindAllReferences.Options, cb: FindAllReferences.ToReferenceOrRenameEntry): T[] | undefined { synchronizeHostData(); // Exclude default library when renaming as commonly user don't want to change that file. - const sourceFiles = options && options.isForRename + const sourceFiles = options && options.use === FindAllReferences.FindReferencesUse.Rename ? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile)) : program.getSourceFiles(); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 69010b4611fd1..356ea22dbaa1b 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -88,6 +88,7 @@ namespace ts { } export function getMeaningFromLocation(node: Node): SemanticMeaning { + node = getAdjustedReferenceLocation(node); if (node.kind === SyntaxKind.SourceFile) { return SemanticMeaning.Value; } @@ -720,6 +721,337 @@ namespace ts { return syntaxList; } + function isDefaultModifier(node: Node) { + return node.kind === SyntaxKind.DefaultKeyword; + } + + function isClassKeyword(node: Node) { + return node.kind === SyntaxKind.ClassKeyword; + } + + function isFunctionKeyword(node: Node) { + return node.kind === SyntaxKind.FunctionKeyword; + } + + function getAdjustedLocationForClass(node: ClassDeclaration | ClassExpression) { + if (isNamedDeclaration(node)) { + return node.name; + } + if (isClassDeclaration(node)) { + // for class and function declarations, use the `default` modifier + // when the declaration is unnamed. + const defaultModifier = find(node.modifiers!, isDefaultModifier); + if (defaultModifier) return defaultModifier; + } + if (isClassExpression(node)) { + // for class expressions, use the `class` keyword when the class is unnamed + const classKeyword = find(node.getChildren(), isClassKeyword); + if (classKeyword) return classKeyword; + } + } + + function getAdjustedLocationForFunction(node: FunctionDeclaration | FunctionExpression) { + if (isNamedDeclaration(node)) { + return node.name; + } + if (isFunctionDeclaration(node)) { + // for class and function declarations, use the `default` modifier + // when the declaration is unnamed. + const defaultModifier = find(node.modifiers!, isDefaultModifier); + if (defaultModifier) return defaultModifier; + } + if (isFunctionExpression(node)) { + // for function expressions, use the `function` keyword when the function is unnamed + const functionKeyword = find(node.getChildren(), isFunctionKeyword); + if (functionKeyword) return functionKeyword; + } + } + + function getAdjustedLocationForDeclaration(node: Node, forRename: boolean) { + if (!forRename) { + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + return getAdjustedLocationForClass(node as ClassDeclaration | ClassExpression); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + return getAdjustedLocationForFunction(node as FunctionDeclaration | FunctionExpression); + } + } + if (isNamedDeclaration(node)) { + return node.name; + } + } + + function getAdjustedLocationForImportDeclaration(node: ImportDeclaration, forRename: boolean) { + if (node.importClause) { + // /**/import [|name|] from ...; + // import /**/type [|name|] from ...; + if (node.importClause.name && !node.importClause.namedBindings) { + return node.importClause.name; + } + // /**/import { [|name|] } from ...; + // /**/import { propertyName as [|name|] } from ...; + // /**/import * as [|name|] from ...; + // import /**/type { [|name|] } from ...; + // import /**/type { propertyName as [|name|] } from ...; + // import /**/type * as [|name|] from ...; + if (!node.importClause.name && node.importClause.namedBindings) { + if (isNamedImports(node.importClause.namedBindings)) { + if (node.importClause.namedBindings.elements.length === 1) { + return node.importClause.namedBindings.elements[0].name; + } + } + else if (isNamespaceImport(node.importClause.namedBindings)) { + return node.importClause.namedBindings.name; + } + } + + } + if (!forRename) { + // /**/import "[|module|]"; + // /**/import ... from "[|module|]"; + // import /**/type ... from "[|module|]"; + return node.moduleSpecifier; + } + } + + function getAdjustedLocationForExportDeclaration(node: ExportDeclaration, forRename: boolean) { + if (node.exportClause) { + // /**/export { [|name|] } ... + // /**/export { propertyName as [|name|] } ... + // /**/export * as [|name|] ... + // export /**/type { [|name|] } from ... + // export /**/type { propertyName as [|name|] } from ... + // export /**/type * as [|name|] ... + if (isNamedExports(node.exportClause)) { + if (node.exportClause.elements.length === 1) { + return node.exportClause.elements[0].name; + } + } + else if (isNamespaceExport(node.exportClause)) { + return node.exportClause.name; + } + } + if (!forRename) { + // /**/export * from "[|module|]"; + // export /**/type * from "[|module|]"; + return node.moduleSpecifier; + } + } + + function getAdjustedLocationForHeritageClause(node: HeritageClause) { + // /**/extends [|name|] + // /**/implements [|name|] + if (node.types.length === 1) { + return node.types[0].expression; + } + + // /**/extends name1, name2 ... + // /**/implements name1, name2 ... + } + + function getAdjustedLocation(node: Node, forRename: boolean): Node { + const { parent } = node; + // /**/ [|name|] ... + // /**/ [|name|] ... + // /**/ [|name|] ... + // /**/import [|name|] = ... + // + // NOTE: If the node is a modifier, we don't adjust its location if it is the `default` modifier as that is handled + // specially by `getSymbolAtLocation`. + if (isModifier(node) && (forRename || node.kind !== SyntaxKind.DefaultKeyword) ? contains(parent.modifiers, node) : + node.kind === SyntaxKind.ClassKeyword ? isClassDeclaration(parent) || isClassExpression(node) : + node.kind === SyntaxKind.FunctionKeyword ? isFunctionDeclaration(parent) || isFunctionExpression(node) : + node.kind === SyntaxKind.InterfaceKeyword ? isInterfaceDeclaration(parent) : + node.kind === SyntaxKind.EnumKeyword ? isEnumDeclaration(parent) : + node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) : + node.kind === SyntaxKind.NamespaceKeyword || node.kind === SyntaxKind.ModuleKeyword ? isModuleDeclaration(parent) : + node.kind === SyntaxKind.ImportKeyword ? isImportEqualsDeclaration(parent) : + node.kind === SyntaxKind.GetKeyword ? isGetAccessorDeclaration(parent) : + node.kind === SyntaxKind.SetKeyword && isSetAccessorDeclaration(parent)) { + const location = getAdjustedLocationForDeclaration(parent, forRename); + if (location) { + return location; + } + } + // /**/ [|name|] ... + if ((node.kind === SyntaxKind.VarKeyword || node.kind === SyntaxKind.ConstKeyword || node.kind === SyntaxKind.LetKeyword) && + isVariableDeclarationList(parent) && parent.declarations.length === 1) { + const decl = parent.declarations[0]; + if (isIdentifier(decl.name)) { + return decl.name; + } + } + if (node.kind === SyntaxKind.TypeKeyword) { + // import /**/type [|name|] from ...; + // import /**/type { [|name|] } from ...; + // import /**/type { propertyName as [|name|] } from ...; + // import /**/type ... from "[|module|]"; + if (isImportClause(parent) && parent.isTypeOnly) { + const location = getAdjustedLocationForImportDeclaration(parent.parent, forRename); + if (location) { + return location; + } + } + // export /**/type { [|name|] } from ...; + // export /**/type { propertyName as [|name|] } from ...; + // export /**/type * from "[|module|]"; + // export /**/type * as ... from "[|module|]"; + if (isExportDeclaration(parent) && parent.isTypeOnly) { + const location = getAdjustedLocationForExportDeclaration(parent, forRename); + if (location) { + return location; + } + } + } + // import { propertyName /**/as [|name|] } ... + // import * /**/as [|name|] ... + // export { propertyName /**/as [|name|] } ... + // export * /**/as [|name|] ... + if (node.kind === SyntaxKind.AsKeyword) { + if (isImportSpecifier(parent) && parent.propertyName || + isExportSpecifier(parent) && parent.propertyName || + isNamespaceImport(parent) || + isNamespaceExport(parent)) { + return parent.name; + } + if (isExportDeclaration(parent) && parent.exportClause && isNamespaceExport(parent.exportClause)) { + return parent.exportClause.name; + } + } + // /**/import [|name|] from ...; + // /**/import { [|name|] } from ...; + // /**/import { propertyName as [|name|] } from ...; + // /**/import ... from "[|module|]"; + // /**/import "[|module|]"; + if (node.kind === SyntaxKind.ImportKeyword && isImportDeclaration(parent)) { + const location = getAdjustedLocationForImportDeclaration(parent, forRename); + if (location) { + return location; + } + } + if (node.kind === SyntaxKind.ExportKeyword) { + // /**/export { [|name|] } ...; + // /**/export { propertyName as [|name|] } ...; + // /**/export * from "[|module|]"; + // /**/export * as ... from "[|module|]"; + if (isExportDeclaration(parent)) { + const location = getAdjustedLocationForExportDeclaration(parent, forRename); + if (location) { + return location; + } + } + // NOTE: We don't adjust the location of the `default` keyword as that is handled specially by `getSymbolAtLocation`. + // /**/export default [|name|]; + // /**/export = [|name|]; + if (isExportAssignment(parent)) { + return skipOuterExpressions(parent.expression); + } + } + // import name = /**/require("[|module|]"); + if (node.kind === SyntaxKind.RequireKeyword && isExternalModuleReference(parent)) { + return parent.expression; + } + // import ... /**/from "[|module|]"; + // export ... /**/from "[|module|]"; + if (node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) && parent.moduleSpecifier) { + return parent.moduleSpecifier; + } + // class ... /**/extends [|name|] ... + // class ... /**/implements [|name|] ... + // class ... /**/implements name1, name2 ... + // interface ... /**/extends [|name|] ... + // interface ... /**/extends name1, name2 ... + if ((node.kind === SyntaxKind.ExtendsKeyword || node.kind === SyntaxKind.ImplementsKeyword) && isHeritageClause(parent) && parent.token === node.kind) { + const location = getAdjustedLocationForHeritageClause(parent); + if (location) { + return location; + } + } + if (node.kind === SyntaxKind.ExtendsKeyword) { + // ... ... + if (isTypeParameterDeclaration(parent) && parent.constraint && isTypeReferenceNode(parent.constraint)) { + return parent.constraint.typeName; + } + // ... T /**/extends [|U|] ? ... + if (isConditionalTypeNode(parent) && isTypeReferenceNode(parent.extendsType)) { + return parent.extendsType.typeName; + } + } + // ... T extends /**/infer [|U|] ? ... + if (node.kind === SyntaxKind.InferKeyword && isInferTypeNode(parent)) { + return parent.typeParameter.name; + } + // { [ [|K|] /**/in keyof T]: ... } + if (node.kind === SyntaxKind.InKeyword && isTypeParameterDeclaration(parent) && isMappedTypeNode(parent.parent)) { + return parent.name; + } + // /**/keyof [|T|] + if (node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.KeyOfKeyword && + isTypeReferenceNode(parent.type)) { + return parent.type.typeName; + } + // /**/readonly [|name|][] + if (node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.ReadonlyKeyword && + isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType)) { + return parent.type.elementType.typeName; + } + if (!forRename) { + // /**/new [|name|] + // /**/void [|name|] + // /**/void obj.[|name|] + // /**/typeof [|name|] + // /**/typeof obj.[|name|] + // /**/await [|name|] + // /**/await obj.[|name|] + // /**/yield [|name|] + // /**/yield obj.[|name|] + // /**/delete obj.[|name|] + if (node.kind === SyntaxKind.NewKeyword && isNewExpression(parent) || + node.kind === SyntaxKind.VoidKeyword && isVoidExpression(parent) || + node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) || + node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) || + node.kind === SyntaxKind.YieldKeyword && isYieldExpression(parent) || + node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent)) { + if (parent.expression) { + return skipOuterExpressions(parent.expression); + } + } + // left /**/in [|name|] + // left /**/instanceof [|name|] + if ((node.kind === SyntaxKind.InKeyword || node.kind === SyntaxKind.InstanceOfKeyword) && isBinaryExpression(parent) && parent.operatorToken === node) { + return skipOuterExpressions(parent.right); + } + // left /**/as [|name|] + if (node.kind === SyntaxKind.AsKeyword && isAsExpression(parent) && isTypeReferenceNode(parent.type)) { + return parent.type.typeName; + } + // for (... /**/in [|name|]) + // for (... /**/of [|name|]) + if (node.kind === SyntaxKind.InKeyword && isForInStatement(parent) || + node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent)) { + return skipOuterExpressions(parent.expression); + } + } + return node; + } + + /** + * Adjusts the location used for "find references" and "go to definition" when the cursor was not + * on a property name. + */ + export function getAdjustedReferenceLocation(node: Node): Node { + return getAdjustedLocation(node, /*forRename*/ false); + } + + /** + * Adjusts the location used for "rename" when the cursor was not on a property name. + */ + export function getAdjustedRenameLocation(node: Node): Node { + return getAdjustedLocation(node, /*forRename*/ true); + } + /** * Gets the token whose text has range [start, end) and * position >= start and (position < end or (position === end && token is literal or keyword or identifier)) diff --git a/tests/cases/fourslash/findAllRefsExportEquals.ts b/tests/cases/fourslash/findAllRefsExportEquals.ts index 647023b43ff60..f0fb88e5ab3d6 100644 --- a/tests/cases/fourslash/findAllRefsExportEquals.ts +++ b/tests/cases/fourslash/findAllRefsExportEquals.ts @@ -14,4 +14,4 @@ const b = { definition: '(alias) type T = number\nimport T = require("./a")', ra verify.referenceGroups([r0, r2], [a, b]); verify.referenceGroups(r3, [b, a]); verify.referenceGroups(r4, [mod, a, b]); -verify.referenceGroups(r1, [mod]); +verify.referenceGroups(r1, [a, b]); diff --git a/tests/cases/fourslash/findAllRefsInExport1.ts b/tests/cases/fourslash/findAllRefsInExport1.ts deleted file mode 100644 index 02ec901177f33..0000000000000 --- a/tests/cases/fourslash/findAllRefsInExport1.ts +++ /dev/null @@ -1,10 +0,0 @@ -/// - -//// class C {} -//// /*1*/export { C /*2*/as D }; - -goTo.marker("1"); -verify.noReferences(); - -goTo.marker("2"); -verify.noReferences(); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts index 61e66de94cac5..59967af0d9ce5 100644 --- a/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts +++ b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts @@ -19,7 +19,7 @@ verify.referenceGroups(r1, [{ definition: "namespace T", ranges: [r1, r2] }]); const t: FourSlashInterface.ReferenceGroup = { definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] }; verify.referenceGroups(r2, [t]); verify.referenceGroups([r3, r4], [{ definition: 'module "/a"', ranges: [r4, rExport] }, t]); -verify.referenceGroups(rExport, [{ definition: 'module "/a"', ranges: [r3, r4, rExport] }]); +verify.referenceGroups(rExport, [t]); verify.renameLocations(r0, [r0, r2]); verify.renameLocations(r1, [r1, r2]); diff --git a/tests/cases/fourslash/getRenameInfoTests2.ts b/tests/cases/fourslash/getRenameInfoTests2.ts index 93e8e451b4a16..880bca7378a62 100644 --- a/tests/cases/fourslash/getRenameInfoTests2.ts +++ b/tests/cases/fourslash/getRenameInfoTests2.ts @@ -1,6 +1,6 @@ /// -/////**/class C { +////class C /**/extends null { //// ////} diff --git a/tests/cases/fourslash/referencesForDeclarationKeywords.ts b/tests/cases/fourslash/referencesForDeclarationKeywords.ts new file mode 100644 index 0000000000000..aeb8870ee2388 --- /dev/null +++ b/tests/cases/fourslash/referencesForDeclarationKeywords.ts @@ -0,0 +1,89 @@ +/// +////[|{| "id": "baseDecl" |}class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "baseDecl" |}Base|] {}|] +////[|{| "id": "implemented1Decl" |}interface [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "implemented1Decl" |}Implemented1|] {}|] +////[|{| "id": "classDecl1" |}[|class|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "classDecl1" |}C1|] [|extends|] [|Base|] [|implements|] [|Implemented1|] { +//// [|{| "id": "getDecl" |}[|get|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "getDecl" |}e|]() { return 1; }|] +//// [|{| "id": "setDecl" |}[|set|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "setDecl" |}e|](v) {}|] +////}|] +////[|{| "id": "interfaceDecl1" |}[|interface|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "interfaceDecl1" |}I1|] [|extends|] [|Base|] { }|] +////[|{| "id": "typeDecl" |}[|type|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "typeDecl" |}T|] = { }|] +////[|{| "id": "enumDecl" |}[|enum|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "enumDecl" |}E|] { }|] +////[|{| "id": "namespaceDecl" |}[|namespace|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "namespaceDecl" |}N|] { }|] +////[|{| "id": "moduleDecl" |}[|module|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "moduleDecl" |}M|] { }|] +////[|{| "id": "functionDecl" |}[|function|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "functionDecl" |}fn|]() {}|] +////[|{| "id": "varDecl" |}[|var|] [|{| "isWriteAccess": false, "isDefinition": true, "contextRangeId": "varDecl" |}x|];|] +////[|{| "id": "letDecl" |}[|let|] [|{| "isWriteAccess": false, "isDefinition": true, "contextRangeId": "letDecl" |}y|];|] +////[|{| "id": "constDecl" |}[|const|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "constDecl" |}z|] = 1;|] +////interface Implemented2 {} +////interface Implemented3 {} +////class C2 [|implements|] Implemented2, Implemented3 {} +////interface I2 [|extends|] Implemented2, Implemented3 {} + +const [ + baseDecl, + baseDecl_name, + implemented1Decl, + implemented1Decl_name, + classDecl1, + classDecl1_classKeyword, + classDecl1_name, + classDecl1_extendsKeyword, + classDecl1_extendsName, + classDecl1_implementsKeyword, + classDecl1_implementsName, + getDecl, + getDecl_getKeyword, + getDecl_name, + setDecl, + setDecl_setKeyword, + setDecl_name, + interfaceDecl1, + interfaceDecl1_interfaceKeyword, + interfaceDecl1_name, + interfaceDecl1_extendsKeyword, + interfaceDecl1_extendsName, + typeDecl, + typeDecl_typeKeyword, + typeDecl_name, + enumDecl, + enumDecl_enumKeyword, + enumDecl_name, + namespaceDecl, + namespaceDecl_namespaceKeyword, + namespaceDecl_name, + moduleDecl, + moduleDecl_moduleKeyword, + moduleDecl_name, + functionDecl, + functionDecl_functionKeyword, + functionDecl_name, + varDecl, + varDecl_varKeyword, + varDecl_name, + letDecl, + letDecl_letKeyword, + letDecl_name, + constDecl, + constDecl_constKeyword, + constDecl_name, + classDecl2_implementsKeyword, + interfaceDecl2_extendsKeyword, +] = test.ranges(); +verify.referenceGroups(classDecl1_classKeyword, [{ definition: "class C1", ranges: [classDecl1_name] }]); +verify.referenceGroups(classDecl1_extendsKeyword, [{ definition: "class Base", ranges: [baseDecl_name, classDecl1_extendsName, interfaceDecl1_extendsName] }]); +verify.referenceGroups(classDecl1_implementsKeyword, [{ definition: "interface Implemented1", ranges: [implemented1Decl_name, classDecl1_implementsName] }]); +for (const keyword of [getDecl_getKeyword, setDecl_setKeyword]) { + verify.referenceGroups(keyword, [{ definition: "(property) C1.e: number", ranges: [getDecl_name, setDecl_name] }]); +} +verify.referenceGroups(interfaceDecl1_interfaceKeyword, [{ definition: "interface I1", ranges: [interfaceDecl1_name] }]); +verify.referenceGroups(interfaceDecl1_extendsKeyword, [{ definition: "class Base", ranges: [baseDecl_name, classDecl1_extendsName, interfaceDecl1_extendsName] }]); +verify.referenceGroups(typeDecl_typeKeyword, [{ definition: "type T = {}", ranges: [typeDecl_name] }]); +verify.referenceGroups(enumDecl_enumKeyword, [{ definition: "enum E", ranges: [enumDecl_name] }]); +verify.referenceGroups(namespaceDecl_namespaceKeyword, [{ definition: "namespace N", ranges: [namespaceDecl_name] }]); +verify.referenceGroups(moduleDecl_moduleKeyword, [{ definition: "namespace M", ranges: [moduleDecl_name] }]); +verify.referenceGroups(functionDecl_functionKeyword, [{ definition: "function fn(): void", ranges: [functionDecl_name] }]); +verify.referenceGroups(varDecl_varKeyword, [{ definition: "var x: any", ranges: [varDecl_name] }]); +verify.referenceGroups(letDecl_letKeyword, [{ definition: "let y: any", ranges: [letDecl_name] }]); +verify.referenceGroups(constDecl_constKeyword, [{ definition: "const z: 1", ranges: [constDecl_name] }]); +verify.noReferences(classDecl2_implementsKeyword); +verify.noReferences(interfaceDecl2_extendsKeyword); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForExpressionKeywords.ts b/tests/cases/fourslash/referencesForExpressionKeywords.ts new file mode 100644 index 0000000000000..c64919b765941 --- /dev/null +++ b/tests/cases/fourslash/referencesForExpressionKeywords.ts @@ -0,0 +1,44 @@ +/// + +////[|class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}C|] { +//// [|static [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}x|] = 1;|] +////}|] +////[|new|] [|C|](); +////[|void|] [|C|]; +////[|typeof|] [|C|]; +////[|delete|] [|C|].[|x|]; +////async function* f() { +//// [|yield|] [|C|]; +//// [|await|] [|C|]; +////} +////"x" [|in|] [|C|]; +////undefined [|instanceof|] [|C|]; +////undefined [|as|] [|C|]; + +const [ + classDecl, + classDecl_name, + fieldDecl, + fieldDecl_name, + newKeyword, + newC, + voidKeyword, + voidC, + typeofKeyword, + typeofC, + deleteKeyword, + deleteC, + deleteCx, + yieldKeyword, + yieldC, + awaitKeyword, + awaitC, + inKeyword, + inC, + instanceofKeyword, + instanceofC, + asKeyword, + asC, +] = test.ranges(); +verify.referenceGroups([newKeyword, voidKeyword, typeofKeyword, yieldKeyword, awaitKeyword, inKeyword, instanceofKeyword, asKeyword], [{ definition: "class C", ranges: [classDecl_name, newC, voidC, typeofC, deleteC, yieldC, awaitC, inC, instanceofC, asC] }]); +verify.referenceGroups(deleteKeyword, [{ definition: "(property) C.x: number", ranges: [fieldDecl_name, deleteCx] }]); \ No newline at end of file diff --git a/tests/cases/fourslash/referencesForModifiers.ts b/tests/cases/fourslash/referencesForModifiers.ts new file mode 100644 index 0000000000000..2cfa7eebce77b --- /dev/null +++ b/tests/cases/fourslash/referencesForModifiers.ts @@ -0,0 +1,27 @@ +/// + +////[|/*declareModifier*/declare /*abstractModifier*/abstract class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}C1|] { +//// [|/*staticModifier*/static [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}a|];|] +//// [|/*readonlyModifier*/readonly [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}b|];|] +//// [|/*publicModifier*/public [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}c|];|] +//// [|/*protectedModifier*/protected [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}d|];|] +//// [|/*privateModifier*/private [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}e|];|] +////}|] +////[|/*constModifier*/const enum [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}E|] { +////}|] +////[|/*asyncModifier*/async function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}fn|]() {}|] +////[|/*exportModifier*/export /*defaultModifier*/[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -1 |}default|] class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}C2|] {}|] + +const [, classDef1,, aDef,, bDef,, cDef,, dDef,, eDef,, enumDef,, functionDef,, classDef2Default, classDef2Name] = test.ranges(); +for (const modifier of ["declareModifier", "abstractModifier"]) { + verify.referenceGroups(modifier, [{ definition: "class C1", ranges: [classDef1] }]); +} +verify.referenceGroups("staticModifier", [{ definition: "(property) C1.a: any", ranges: [aDef] }]); +verify.referenceGroups("readonlyModifier", [{ definition: "(property) C1.b: any", ranges: [bDef] }]); +verify.referenceGroups("publicModifier", [{ definition: "(property) C1.c: any", ranges: [cDef] }]); +verify.referenceGroups("protectedModifier", [{ definition: "(property) C1.d: any", ranges: [dDef] }]); +verify.referenceGroups("privateModifier", [{ definition: "(property) C1.e: any", ranges: [eDef] }]); +verify.referenceGroups("constModifier", [{ definition: "const enum E", ranges: [enumDef] }]); +verify.referenceGroups("asyncModifier", [{ definition: "function fn(): Promise", ranges: [functionDef] }]); +verify.referenceGroups("exportModifier", [{ definition: "class C2", ranges: [classDef2Name] }]); +verify.referenceGroups("defaultModifier", [{ definition: "class C2", ranges: [classDef2Default] }]); diff --git a/tests/cases/fourslash/referencesForStatementKeywords.ts b/tests/cases/fourslash/referencesForStatementKeywords.ts new file mode 100644 index 0000000000000..bcd9aa0f48a3c --- /dev/null +++ b/tests/cases/fourslash/referencesForStatementKeywords.ts @@ -0,0 +1,267 @@ +/// + +// @filename: /main.ts +////// import ... = ... +////[|{| "id": "importEqualsDecl1" |}[|import|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importEqualsDecl1" |}A|] = [|require|]("[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importEqualsDecl1" |}./a|]");|] +////[|{| "id": "namespaceDecl1" |}namespace [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "namespaceDecl1" |}N|] { }|] +////[|{| "id": "importEqualsDecl2" |}[|import|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importEqualsDecl2" |}N2|] = [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importEqualsDecl2" |}N|];|] +//// +////// import ... from ... +////[|{| "id": "importDecl1" |}[|import|] [|type|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importDecl1" |}B|] [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importDecl1" |}./b|]";|] +////[|{| "id": "importDecl2" |}[|import|] [|type|] * [|as|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importDecl2" |}C|] [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importDecl2" |}./c|]";|] +////[|{| "id": "importDecl3" |}[|import|] [|type|] { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importDecl3" |}D|] } [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importDecl3" |}./d|]";|] +////[|{| "id": "importDecl4" |}[|import|] [|type|] { e1, e2 [|as|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "importDecl4" |}e3|] } [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importDecl4" |}./e|]";|] +//// +////// import "module" +////[|{| "id": "importDecl5" |}[|import|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "importDecl5" |}./f|]";|] +//// +////// export ... from ... +////[|{| "id": "exportDecl1" |}[|export|] [|type|] * [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportDecl1" |}./g|]";|] +////[|{| "id": "exportDecl2" |}[|export|] [|type|] * [|as|] [|{| "isWriteAccess": true, "isDefinition": true |}H|] [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportDecl2" |}./h|]";|] +////[|{| "id": "exportDecl3" |}[|export|] [|type|] { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "exportDecl3" |}I|] } [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportDecl3" |}./i|]";|] +////[|{| "id": "exportDecl4" |}[|export|] [|type|] { j1, j2 [|as|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "exportDecl4" |}j3|] } [|from|] "[|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportDecl4" |}./j|]";|] +////[|{| "id": "typeDecl1" |}type [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "typeDecl1" |}Z1|] = 1;|] +////[|{| "id": "exportDecl5" |}[|export|] [|type|] { [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "exportDecl5" |}Z1|] };|] +////type Z2 = 2; +////type Z3 = 3; +////[|{| "id": "exportDecl6" |}[|export|] [|type|] { z2, z3 [|as|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "exportDecl6" |}z4|] };|] + +// @filename: /main2.ts +////[|{| "id": "varDecl1" |}const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "varDecl1" |}x|] = {};|] +////[|{| "id": "exportAssignment1" |}[|export|] = [|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportAssignment1"|}x|];|] + +// @filename: /main3.ts +////[|{| "id": "varDecl3" |}const [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "varDecl3" |}y|] = {};|] +////[|{| "id": "exportAssignment2" |}[|export|] [|default|] [|{| "isWriteAccess": false, "isDefinition": false, "contextRangeId": "exportAssignment2"|}y|];|] + +// @filename: /a.ts +////export const a = 1; + +// @filename: /b.ts +////[|{| "id": "classDecl1" |}export default class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "classDecl1" |}B|] {}|] + +// @filename: /c.ts +////export const c = 1; + +// @filename: /d.ts +////[|{| "id": "classDecl2" |}export class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "classDecl2" |}D|] {}|] + +// @filename: /e.ts +////export const e1 = 1; +////export const e2 = 2; + +// @filename: /f.ts +////export const f = 1; + +// @filename: /g.ts +////export const g = 1; + +// @filename: /h.ts +////export const h = 1; + +// @filename: /i.ts +////[|{| "id": "classDecl3" |}export class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "classDecl3" |}I|] {}|] + +// @filename: /j.ts +////export const j1 = 1; +////export const j2 = 2; + +const [ + // main.ts + importEqualsDecl1, + importEqualsDecl1_importKeyword, + importEqualsDecl1_name, + importEqualsDecl1_requireKeyword, + importEqualsDecl1_module, + + namespaceDecl1, + namespaceDecl1_name, + + importEqualsDecl2, + importEqualsDecl2_importKeyword, + importEqualsDecl2_name, + importEqualsDecl2_reference, + + importDecl1, + importDecl1_importKeyword, + importDecl1_typeKeyword, + importDecl1_name, + importDecl1_fromKeyword, + importDecl1_module, + + importDecl2, + importDecl2_importKeyword, + importDecl2_typeKeyword, + importDecl2_asKeyword, + importDecl2_name, + importDecl2_fromKeyword, + importDecl2_module, + + importDecl3, + importDecl3_importKeyword, + importDecl3_typeKeyword, + importDecl3_name, + importDecl3_fromKeyword, + importDecl3_module, + + importDecl4, + importDecl4_importKeyword, + importDecl4_typeKeyword, + importDecl4_asKeyword, + importDecl4_name, + importDecl4_fromKeyword, + importDecl4_module, + + importDecl5, + importDecl5_importKeyword, + importDecl5_module, + + exportDecl1, + exportDecl1_exportKeyword, + exportDecl1_typeKeyword, + exportDecl1_fromKeyword, + exportDecl1_module, + + exportDecl2, + exportDecl2_exportKeyword, + exportDecl2_typeKeyword, + exportDecl2_asKeyword, + exportDecl2_name, + exportDecl2_fromKeyword, + exportDecl2_module, + + exportDecl3, + exportDecl3_exportKeyword, + exportDecl3_typeKeyword, + exportDecl3_name, + exportDecl3_fromKeyword, + exportDecl3_module, + + exportDecl4, + exportDecl4_exportKeyword, + exportDecl4_typeKeyword, + exportDecl4_asKeyword, + exportDecl4_name, + exportDecl4_fromKeyword, + exportDecl4_module, + + typeDecl1, + typeDecl1_name, + + exportDecl5, + exportDecl5_exportKeyword, + exportDecl5_typeKeyword, + exportDecl5_name, + + exportDecl6, + exportDecl6_exportKeyword, + exportDecl6_typeKeyword, + exportDecl6_asKeyword, + exportDecl6_name, + + // main2.ts + varDecl1, + varDecl1_name, + + exportAssignment1, + exportAssignment1_exportKeyword, + exportAssignment1_name, + + // main3.ts + varDecl2, + varDecl2_name, + + exportAssignment2, + exportAssignment2_exportKeyword, + exportAssignment2_defaultKeyword, + exportAssignment2_name, + + // a.ts + // b.ts + classDecl1, + classDecl1_name, + + // c.ts + // d.ts + classDecl2, + classDecl2_name, + + // e.ts + // f.ts + // g.ts + // h.ts + // i.ts + classDecl3, + classDecl3_name, + // j.ts + +] = test.ranges(); + + +// importEqualsDecl1: +verify.referenceGroups(importEqualsDecl1_importKeyword, [{ definition: "import A = require(\"./a\")", ranges: [importEqualsDecl1_name] }]); +verify.referenceGroups(importEqualsDecl1_requireKeyword, [{ definition: "module \"/a\"", ranges: [importEqualsDecl1_module] }]); + +// importEqualsDecl2: +verify.referenceGroups(importEqualsDecl2_importKeyword, [{ definition: "(alias) namespace N2\nimport N2 = N", ranges: [importEqualsDecl2_name] }]); + +// importDecl1: +verify.referenceGroups([importDecl1_importKeyword, importDecl1_typeKeyword], [ + { definition: "(alias) class B\nimport B", ranges: [importDecl1_name] }, + { definition: "class B", ranges: [classDecl1_name] } +]); +verify.referenceGroups(importDecl1_fromKeyword, [{ definition: "module \"/b\"", ranges: [importDecl1_module] }]); + +// importDecl2: +verify.referenceGroups([importDecl2_importKeyword, importDecl2_typeKeyword, importDecl2_asKeyword], [{ definition: "import C", ranges: [importDecl2_name] }]); +verify.referenceGroups([importDecl2_fromKeyword], [{ definition: "module \"/c\"", ranges: [importDecl2_module] }]); + +// importDecl3: +verify.referenceGroups([importDecl3_importKeyword, importDecl3_typeKeyword], [ + { definition: "(alias) class D\nimport D", ranges: [importDecl3_name] }, + { definition: "class D", ranges: [classDecl2_name] } +]); +verify.referenceGroups(importDecl3_fromKeyword, [{ definition: "module \"/d\"", ranges: [importDecl3_module] }]); + +// importDecl4: +verify.referenceGroups([importDecl4_importKeyword, importDecl4_typeKeyword, importDecl4_fromKeyword], [{ definition: "module \"/e\"", ranges: [importDecl4_module] }]); +verify.referenceGroups(importDecl4_asKeyword, [{ definition: "(alias) const e3: 2\nimport e3", ranges: [importDecl4_name] }]); + +// importDecl5 +verify.referenceGroups(importDecl5_importKeyword, [{ definition: "module \"/f\"", ranges: [importDecl5_module] }]); + +// exportDecl1: +verify.referenceGroups([exportDecl1_exportKeyword, exportDecl1_typeKeyword, exportDecl1_fromKeyword], [{ definition: "module \"/g\"", ranges: [exportDecl1_module] }]); + +// exportDecl2: +verify.referenceGroups([exportDecl2_exportKeyword, exportDecl2_typeKeyword, exportDecl2_asKeyword], [{ definition: "import H", ranges: [exportDecl2_name] }]); +verify.referenceGroups([exportDecl2_fromKeyword], [{ definition: "module \"/h\"", ranges: [exportDecl2_module] }]); + +// exportDecl3: +verify.referenceGroups([exportDecl3_exportKeyword, exportDecl3_typeKeyword], [ + { definition: "(alias) class I\nexport I", ranges: [exportDecl3_name] }, + { definition: "class I", ranges: [classDecl3_name] } +]); +verify.referenceGroups(exportDecl3_fromKeyword, [{ definition: "module \"/i\"", ranges: [exportDecl3_module] }]); + +// exportDecl4: +verify.referenceGroups([exportDecl4_exportKeyword, exportDecl4_typeKeyword, exportDecl4_fromKeyword], [{ definition: "module \"/j\"", ranges: [exportDecl4_module] }]); +verify.referenceGroups(exportDecl4_asKeyword, [{ definition: "(alias) const j3: 2\nexport j3", ranges: [exportDecl4_name] }]); + +// exportDecl5: +verify.referenceGroups([exportDecl5_exportKeyword, exportDecl5_typeKeyword], [{ definition: "type Z1 = 1", ranges: [typeDecl1_name, exportDecl5_name] }]); + +// exportDecl6: +verify.noReferences(exportDecl6_exportKeyword); +verify.noReferences(exportDecl6_typeKeyword); +verify.referenceGroups(exportDecl6_asKeyword, [{ definition: "export z4", ranges: [exportDecl6_name] }]); + +// exportAssignment1: +verify.referenceGroups(exportAssignment1_exportKeyword, [ + { definition: "const x: {}", ranges: [varDecl1_name, exportAssignment1_name] } +]); + +// exportAssignment2: +verify.referenceGroups(exportAssignment2_exportKeyword, [ + { definition: "const y: {}", ranges: [varDecl2_name, exportAssignment2_name] } +]); diff --git a/tests/cases/fourslash/referencesForTypeKeywords.ts b/tests/cases/fourslash/referencesForTypeKeywords.ts new file mode 100644 index 0000000000000..cfd37a43960c0 --- /dev/null +++ b/tests/cases/fourslash/referencesForTypeKeywords.ts @@ -0,0 +1,43 @@ +/// + +////[|{| "id": "interfaceDecl" |}interface [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "interfaceDecl" |}I|] {}|] +////function f() {} +////type A1 = T [|extends|] [|U|] ? 1 : 0; +////type A2 = T extends [|infer|] [|{| "isWriteAccess": true, "isDefinition": true |}U|] ? 1 : 0; +////type A3 = { [[|{| "id": "mappedType_param" |}[|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "mappedType_param" |}P|] [|in|] keyof T|]]: 1 }; +////type A4<[|{| "isWriteAccess": true, "isDefinition": true |}T|]> = [|keyof|] [|T|]; +////type A5<[|{| "isWriteAccess": true, "isDefinition": true |}T|]> = [|readonly|] [|T|][]; + +const [ + interfaceDecl, + interfaceDecl_name, + + typeParam_extendsKeyword, + typeParam_constraint, + + typeParamA1_name, + conditionalType_extendsKeyword, + conditionalType_extendsType, + + inferType_inferKeyword, + inferType_type, + + mappedType_param, + mappedType_name, + mappedType_inOperator, + + typeParamA4_name, + keyofOperator_keyofKeyword, + keyofOperator_type, + + typeParamA5_name, + readonlyOperator_readonlyKeyword, + readonlyOperator_elementType, +] = test.ranges(); + +verify.referenceGroups(typeParam_extendsKeyword, [{ definition: "interface I", ranges: [interfaceDecl_name, typeParam_constraint] }]); +verify.referenceGroups(conditionalType_extendsKeyword, [{ definition: "(type parameter) U in type A1", ranges: [typeParamA1_name, conditionalType_extendsType] }]); +verify.referenceGroups(inferType_inferKeyword, [{ definition: "(type parameter) U", ranges: [inferType_type] }]); +verify.referenceGroups(mappedType_inOperator, [{ definition: "(type parameter) P", ranges: [mappedType_name] }]); +verify.referenceGroups(keyofOperator_keyofKeyword, [{ definition: "(type parameter) T in type A4", ranges: [typeParamA4_name, keyofOperator_type] }]); +verify.referenceGroups(readonlyOperator_readonlyKeyword, [{ definition: "(type parameter) T in type A5", ranges: [typeParamA5_name, readonlyOperator_elementType] }]); \ No newline at end of file diff --git a/tests/cases/fourslash/renameDeclarationKeywords.ts b/tests/cases/fourslash/renameDeclarationKeywords.ts new file mode 100644 index 0000000000000..0a762150ff65a --- /dev/null +++ b/tests/cases/fourslash/renameDeclarationKeywords.ts @@ -0,0 +1,95 @@ +/// + +////[|{| "id": "baseDecl" |}class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "baseDecl" |}Base|] {}|] +////[|{| "id": "implemented1Decl" |}interface [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "implemented1Decl" |}Implemented1|] {}|] +////[|{| "id": "classDecl1" |}[|class|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "classDecl1" |}C1|] [|extends|] [|Base|] [|implements|] [|Implemented1|] { +//// [|{| "id": "getDecl" |}[|get|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "getDecl" |}e|]() { return 1; }|] +//// [|{| "id": "setDecl" |}[|set|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "setDecl" |}e|](v) {}|] +////}|] +////[|{| "id": "interfaceDecl1" |}[|interface|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "interfaceDecl1" |}I1|] [|extends|] [|Base|] { }|] +////[|{| "id": "typeDecl" |}[|type|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "typeDecl" |}T|] = { }|] +////[|{| "id": "enumDecl" |}[|enum|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "enumDecl" |}E|] { }|] +////[|{| "id": "namespaceDecl" |}[|namespace|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "namespaceDecl" |}N|] { }|] +////[|{| "id": "moduleDecl" |}[|module|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "moduleDecl" |}M|] { }|] +////[|{| "id": "functionDecl" |}[|function|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "functionDecl" |}fn|]() {}|] +////[|{| "id": "varDecl" |}[|var|] [|{| "isWriteAccess": false, "isDefinition": true, "contextRangeId": "varDecl" |}x|];|] +////[|{| "id": "letDecl" |}[|let|] [|{| "isWriteAccess": false, "isDefinition": true, "contextRangeId": "letDecl" |}y|];|] +////[|{| "id": "constDecl" |}[|const|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeId": "constDecl" |}z|] = 1;|] + +const [ + baseDecl, + baseDecl_name, + + implemented1Decl, + implemented1Decl_name, + + classDecl1, + classDecl1_classKeyword, + classDecl1_name, + classDecl1_extendsKeyword, + classDecl1_extendsName, + classDecl1_implementsKeyword, + classDecl1_implementsName, + + getDecl, + getDecl_getKeyword, + getDecl_name, + + setDecl, + setDecl_setKeyword, + setDecl_name, + + interfaceDecl1, + interfaceDecl1_interfaceKeyword, + interfaceDecl1_name, + interfaceDecl1_extendsKeyword, + interfaceDecl1_extendsName, + + typeDecl, + typeDecl_typeKeyword, + typeDecl_name, + + enumDecl, + enumDecl_enumKeyword, + enumDecl_name, + + namespaceDecl, + namespaceDecl_namespaceKeyword, + namespaceDecl_name, + + moduleDecl, + moduleDecl_moduleKeyword, + moduleDecl_name, + + functionDecl, + functionDecl_functionKeyword, + functionDecl_name, + + varDecl, + varDecl_varKeyword, + varDecl_name, + + letDecl, + letDecl_letKeyword, + letDecl_name, + + constDecl, + constDecl_constKeyword, + constDecl_name, +] = test.ranges(); +verify.renameLocations(classDecl1_classKeyword, [{ range: classDecl1_name }]); +verify.renameLocations(classDecl1_extendsKeyword, [{ range: baseDecl_name }, { range: classDecl1_extendsName }, { range: interfaceDecl1_extendsName }]); +verify.renameLocations(classDecl1_implementsKeyword, [{ range: implemented1Decl_name }, { range: classDecl1_implementsName }]); +for (const keyword of [getDecl_getKeyword, setDecl_setKeyword]) { + verify.renameLocations(keyword, [{ range: getDecl_name }, { range: setDecl_name }]); +} +verify.renameLocations(interfaceDecl1_interfaceKeyword, [{ range: interfaceDecl1_name }]); +verify.renameLocations(interfaceDecl1_extendsKeyword, [{ range: baseDecl_name }, { range: classDecl1_extendsName }, { range: interfaceDecl1_extendsName }]); +verify.renameLocations(typeDecl_typeKeyword, [{ range: typeDecl_name }]); +verify.renameLocations(enumDecl_enumKeyword, [{ range: enumDecl_name }]); +verify.renameLocations(namespaceDecl_namespaceKeyword, [{ range: namespaceDecl_name }]); +verify.renameLocations(moduleDecl_moduleKeyword, [{ range: moduleDecl_name }]); +verify.renameLocations(functionDecl_functionKeyword, [{ range: functionDecl_name }]); +verify.renameLocations(varDecl_varKeyword, [{ range: varDecl_name }]); +verify.renameLocations(letDecl_letKeyword, [{ range: letDecl_name }]); +verify.renameLocations(constDecl_constKeyword, [{ range: constDecl_name }]); \ No newline at end of file diff --git a/tests/cases/fourslash/renameModifiers.ts b/tests/cases/fourslash/renameModifiers.ts new file mode 100644 index 0000000000000..ab2258a1d08cf --- /dev/null +++ b/tests/cases/fourslash/renameModifiers.ts @@ -0,0 +1,34 @@ +/// + +////[|[|declare|] [|abstract|] class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -3 |}C1|] { +//// [|[|static|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}a|];|] +//// [|[|readonly|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}b|];|] +//// [|[|public|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}c|];|] +//// [|[|protected|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}d|];|] +//// [|[|private|] [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}e|];|] +////}|] +////[|[|const|] enum [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}E|] { +////}|] +////[|[|async|] function [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -2 |}fn|]() {}|] +////[|[|export|] [|default|] class [|{| "isWriteAccess": true, "isDefinition": true, "contextRangeDelta": -3 |}C2|] {}|] + +const [ + class1Def, declareKeyword, abstractKeyword, class1Name, + aDef, staticKeyword, aName, + bDef, readonlyKeyword, bName, + cDef, publicKeyword, cName, + dDef, protectedKeyword, dName, + eDef, privateKeyword, eName, + enumDef, constKeyword, enumName, + functionDef, asyncKeyword, functionName, + class2Def, exportKeyword, defaultKeyword, class2Name, +] = test.ranges(); +verify.renameLocations([declareKeyword, abstractKeyword], [{ range: class1Name }]); +verify.renameLocations([staticKeyword], [{ range: aName }]); +verify.renameLocations([readonlyKeyword], [{ range: bName }]); +verify.renameLocations([publicKeyword], [{ range: cName }]); +verify.renameLocations([protectedKeyword], [{ range: dName }]); +verify.renameLocations([privateKeyword], [{ range: eName }]); +verify.renameLocations([constKeyword], [{ range: enumName }]); +verify.renameLocations([asyncKeyword], [{ range: functionName }]); +verify.renameLocations([exportKeyword, defaultKeyword], [{ range: class2Name }]); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy