diff --git a/packages/language-service/ivy/references.ts b/packages/language-service/ivy/references.ts index 204d4185cc..964297d3d7 100644 --- a/packages/language-service/ivy/references.ts +++ b/packages/language-service/ivy/references.ts @@ -392,6 +392,11 @@ export class ReferencesAndRenameBuilder { ...shimDocumentSpan, fileName: templateUrl, textSpan: toTextSpan(span), + // Specifically clear other text span values because we do not have enough knowledge to + // convert these to spans in the template. + contextSpan: undefined, + originalContextSpan: undefined, + originalTextSpan: undefined, }; } } diff --git a/packages/language-service/ivy/test/references_spec.ts b/packages/language-service/ivy/test/references_spec.ts index d2f08df74e..70295cac80 100644 --- a/packages/language-service/ivy/test/references_spec.ts +++ b/packages/language-service/ivy/test/references_spec.ts @@ -6,14 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {absoluteFrom, absoluteFrom as _} from '@angular/compiler-cli/src/ngtsc/file_system'; -import {initMockFileSystem, TestFile} from '@angular/compiler-cli/src/ngtsc/file_system/testing'; +import {initMockFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing'; -import {extractCursorInfo, LanguageServiceTestEnvironment} from './env'; -import {assertFileNames, assertTextSpans, createModuleWithDeclarations, humanizeDocumentSpanLike} from './test_utils'; +import {assertFileNames, assertTextSpans, createModuleAndProjectWithDeclarations, humanizeDocumentSpanLike, LanguageServiceTestEnv, OpenBuffer} from '../testing'; describe('find references and rename locations', () => { - let env: LanguageServiceTestEnvironment; + let env: LanguageServiceTestEnv; beforeEach(() => { initMockFileSystem('Native'); @@ -25,31 +23,33 @@ describe('find references and rename locations', () => { }); describe('cursor is on binding in component class', () => { - let cursor: number; + let appFile: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` - import {Component} from '@angular/core'; + const files = { + 'app.ts': `import {Component} from '@angular/core'; @Component({templateUrl: './app.html'}) export class AppCmp { - myP¦rop!: string; - }`); - cursor = cursorInfo.cursor; - const appFile = {name: _('/app.ts'), contents: cursorInfo.text}; - const templateFile = {name: _('/app.html'), contents: '{{myProp}}'}; - env = createModuleWithDeclarations([appFile], [templateFile]); + myProp!: string; + }`, + 'app.html': '{{myProp}}' + }; + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + appFile = project.openFile('app.ts'); + appFile.moveCursorToText('myP¦rop'); }); it('gets component member references from TS file and external template', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(appFile)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.html', 'app.ts']); assertTextSpans(refs, ['myProp']); }); it('gets rename locations from TS file and external template', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(appFile)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.html', 'app.ts']); assertTextSpans(renameLocations, ['myProp']); @@ -57,34 +57,34 @@ describe('find references and rename locations', () => { }); describe('when cursor is on binding in an external template', () => { - let cursor: number; + let templateFile: OpenBuffer; beforeEach(() => { - const appFile = { - name: _('/app.ts'), - contents: ` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({templateUrl: './app.html'}) export class AppCmp { myProp = ''; }`, + 'app.html': '{{myProp}}' }; - const cursorInfo = extractCursorInfo('{{myP¦rop}}'); - cursor = cursorInfo.cursor; - const templateFile = {name: _('/app.html'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile], [templateFile]); + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + templateFile = project.openFile('app.html'); + templateFile.moveCursorToText('myP¦rop'); }); it('gets references', () => { - const refs = getReferencesAtPosition(_('/app.html'), cursor)!; + const refs = getReferencesAtPosition(templateFile)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.html', 'app.ts']); assertTextSpans(refs, ['myProp']); }); it('gets rename locations', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.html'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(templateFile)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.html', 'app.ts']); assertTextSpans(renameLocations, ['myProp']); @@ -92,23 +92,26 @@ describe('find references and rename locations', () => { }); describe('when cursor is on function call in external template', () => { - let cursor: number; + let appFile: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: '
'}) + @Component({template: ''}) export class AppCmp { setTitle(s: number) {} - }`); - cursor = cursorInfo.cursor; - const appFile = {name: _('/app.ts'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile]); + }` + }; + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + appFile = project.openFile('app.ts'); + appFile.moveCursorToText('setTi¦tle(2)'); }); it('gets component member reference in ts file', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(appFile)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.ts']); @@ -116,7 +119,7 @@ describe('find references and rename locations', () => { }); it('gets rename location in ts file', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(appFile)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.ts']); @@ -125,31 +128,34 @@ describe('find references and rename locations', () => { }); describe('when cursor in on argument to a function call in an external template', () => { - let cursor: number; + let appFile: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: ''}) + @Component({template: ''}) export class AppCmp { title = ''; setTitle(s: string) {} - }`); - cursor = cursorInfo.cursor; - const appFile = {name: _('/app.ts'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile]); + }` + }; + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + appFile = project.openFile('app.ts'); + appFile.moveCursorToText('(ti¦tle)'); }); it('gets member reference in ts file', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(appFile)!; expect(refs.length).toBe(2); assertTextSpans(refs, ['title']); }); it('finds rename location in ts file', () => { - const refs = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const refs = getRenameLocationsAtPosition(appFile)!; expect(refs.length).toBe(2); assertTextSpans(refs, ['title']); @@ -157,56 +163,58 @@ describe('find references and rename locations', () => { }); describe('when cursor is on $event in method call arguments', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: ''}) + @Component({template: ''}) export class AppCmp { setTitle(s: any) {} - }`); - cursor = cursorInfo.cursor; - const appFile = {name: _('/app.ts'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile]); + }` + }; + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.ts'); + file.moveCursorToText('($even¦t)'); }); it('find references', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(file)!; expect(refs.length).toBe(1); assertTextSpans(refs, ['$event']); }); it('gets no rename locations', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations).toBeUndefined(); }); }); describe('when cursor in on LHS of property write in external template', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const appFile = { - name: _('/app.ts'), - contents: ` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({templateUrl: './app.html' }) export class AppCmp { title = ''; }`, + 'app.html': `` }; - const templateFileWithCursor = ``; - const cursorInfo = extractCursorInfo(templateFileWithCursor); - cursor = cursorInfo.cursor; - const templateFile = {name: _('/app.html'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile], [templateFile]); + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.html'); + file.moveCursorToText('ti¦tle = '); }); it('gets member reference in ts file', () => { - const refs = getReferencesAtPosition(_('/app.html'), cursor)!; + const refs = getReferencesAtPosition(file)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.ts', 'app.html']); @@ -214,7 +222,7 @@ describe('find references and rename locations', () => { }); it('gets rename location in ts file', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.html'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.ts', 'app.html']); @@ -223,27 +231,28 @@ describe('find references and rename locations', () => { }); describe('when cursor in on RHS of property write in external template', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: '' }) + @Component({template: '' }) export class AppCmp { title = ''; otherTitle = ''; - }`); - cursor = cursorInfo.cursor; - const appFile = { - name: _('/app.ts'), - contents: cursorInfo.text, + }` }; - env = createModuleWithDeclarations([appFile]); + + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.ts'); + file.moveCursorToText('= otherT¦itle">'); }); it('get reference to member in ts file', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(file)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.ts']); @@ -251,7 +260,7 @@ describe('find references and rename locations', () => { }); it('finds rename location in ts file', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.ts']); @@ -260,26 +269,26 @@ describe('find references and rename locations', () => { }); describe('when cursor in on a keyed read', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: '{{hero["na¦me"]}}' }) + @Component({template: '{{hero["name"]}}' }) export class AppCmp { hero: {name: string} = {name: 'Superman'}; - }`); - cursor = cursorInfo.cursor; - const appFile = { - name: _('/app.ts'), - contents: cursorInfo.text, + }` }; - env = createModuleWithDeclarations([appFile]); + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.ts'); + file.moveCursorToText('{{hero["na¦me"]}}'); }); it('gets reference to member type definition and initialization in component class', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(file)!; // 3 references: the type definition, the value assignment, and the read in the template expect(refs.length).toBe(3); @@ -293,7 +302,7 @@ describe('find references and rename locations', () => { }); it('gets rename locations in component class', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations).toBeUndefined(); // TODO(atscott): We should handle this case. The fix requires us to fix the result span as @@ -307,12 +316,11 @@ describe('find references and rename locations', () => { }); describe('when cursor in on RHS of keyed write in a template', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const appFile = { - name: _('/app.ts'), - contents: ` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; @Component({templateUrl: './app.html' }) @@ -320,16 +328,16 @@ describe('find references and rename locations', () => { hero: {name: string} = {name: 'Superman'}; batman = 'batman'; }`, + 'app.html': `` }; - const templateFileWithCursor = ``; - const cursorInfo = extractCursorInfo(templateFileWithCursor); - cursor = cursorInfo.cursor; - const templateFile = {name: _('/app.html'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile], [templateFile]); + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.html'); + file.moveCursorToText('bat¦man'); }); it('get references in ts file', () => { - const refs = getReferencesAtPosition(_('/app.html'), cursor)!; + const refs = getReferencesAtPosition(file)!; expect(refs.length).toBe(2); assertFileNames(refs, ['app.ts', 'app.html']); @@ -337,7 +345,7 @@ describe('find references and rename locations', () => { }); it('finds rename location in ts file', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.html'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations.length).toBe(2); assertFileNames(renameLocations, ['app.ts', 'app.html']); @@ -346,23 +354,26 @@ describe('find references and rename locations', () => { }); describe('when cursor in on an element reference', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const cursorInfo = extractCursorInfo(` + const files = { + 'app.ts': ` import {Component} from '@angular/core'; - @Component({template: ' {{ myIn¦put.value }}'}) + @Component({template: ' {{ myInput.value }}'}) export class AppCmp { title = ''; - }`); - cursor = cursorInfo.cursor; - const appFile = {name: _('/app.ts'), contents: cursorInfo.text}; - env = createModuleWithDeclarations([appFile]); + }` + }; + env = LanguageServiceTestEnv.setup(); + const project = createModuleAndProjectWithDeclarations(env, 'test', files); + file = project.openFile('app.ts'); + file.moveCursorToText('myInp¦ut.value'); }); it('get reference to declaration in template', () => { - const refs = getReferencesAtPosition(_('/app.ts'), cursor)!; + const refs = getReferencesAtPosition(file)!; expect(refs.length).toBe(2); assertTextSpans(refs, ['myInput']); @@ -373,7 +384,7 @@ describe('find references and rename locations', () => { }); it('finds rename location in template', () => { - const renameLocations = getRenameLocationsAtPosition(_('/app.ts'), cursor)!; + const renameLocations = getRenameLocationsAtPosition(file)!; expect(renameLocations.length).toBe(2); assertTextSpans(renameLocations, ['myInput']); @@ -381,30 +392,29 @@ describe('find references and rename locations', () => { }); describe('when cursor in on a template reference', () => { - let cursor: number; + let file: OpenBuffer; beforeEach(() => { - const templateWithCursor = ` -