fix(language-service): ignore hover of symbols not in the TypeScript program (#17969)
Fixes: #17965
This commit is contained in:
parent
cb16e9c747
commit
227dbbcfba
@ -322,7 +322,7 @@ export interface SymbolQuery {
|
|||||||
/**
|
/**
|
||||||
* Return the type symbol for the given static symbol.
|
* Return the type symbol for the given static symbol.
|
||||||
*/
|
*/
|
||||||
getTypeSymbol(type: StaticSymbol): Symbol;
|
getTypeSymbol(type: StaticSymbol): Symbol|undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the members that are in the context of a type's template reference.
|
* Return the members that are in the context of a type's template reference.
|
||||||
|
@ -159,10 +159,10 @@ class TypeScriptSymbolQuery implements SymbolQuery {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTypeSymbol(type: StaticSymbol): Symbol {
|
getTypeSymbol(type: StaticSymbol): Symbol|undefined {
|
||||||
const context: TypeContext = {node: this.source, program: this.program, checker: this.checker};
|
const context: TypeContext = {node: this.source, program: this.program, checker: this.checker};
|
||||||
const typeSymbol = findClassSymbolInContext(type, context) !;
|
const typeSymbol = findClassSymbolInContext(type, context);
|
||||||
return new SymbolWrapper(typeSymbol, context);
|
return typeSymbol && new SymbolWrapper(typeSymbol, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSymbolTable(symbols: SymbolDeclaration[]): SymbolTable {
|
createSymbolTable(symbols: SymbolDeclaration[]): SymbolTable {
|
||||||
|
108
packages/compiler-cli/test/diagnostics/symbol_query_spec.ts
Normal file
108
packages/compiler-cli/test/diagnostics/symbol_query_spec.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright Google Inc. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style license that can be
|
||||||
|
* found in the LICENSE file at https://angular.io/license
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {StaticSymbol} from '@angular/compiler';
|
||||||
|
import {AngularCompilerOptions, CompilerHost} from '@angular/compiler-cli';
|
||||||
|
import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockData, MockDirectory, MockMetadataBundlerHost, arrayToMockDir, arrayToMockMap, isSource, settings, setup, toMockFileArray} from '@angular/compiler/test/aot/test_util';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {Symbol, SymbolQuery, SymbolTable} from '../../src/diagnostics/symbols';
|
||||||
|
import {getSymbolQuery} from '../../src/diagnostics/typescript_symbols';
|
||||||
|
import {Directory} from '../mocks';
|
||||||
|
|
||||||
|
import {DiagnosticContext, MockLanguageServiceHost} from './mocks';
|
||||||
|
|
||||||
|
function emptyPipes(): SymbolTable {
|
||||||
|
return {
|
||||||
|
size: 0,
|
||||||
|
get(key: string) { return undefined; },
|
||||||
|
has(key: string) { return false; },
|
||||||
|
values(): Symbol[]{return [];}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('symbol query', () => {
|
||||||
|
let program: ts.Program;
|
||||||
|
let checker: ts.TypeChecker;
|
||||||
|
let sourceFile: ts.SourceFile;
|
||||||
|
let query: SymbolQuery;
|
||||||
|
let context: DiagnosticContext;
|
||||||
|
beforeEach(() => {
|
||||||
|
const registry = ts.createDocumentRegistry(false, '/src');
|
||||||
|
const host = new MockLanguageServiceHost(
|
||||||
|
['/quickstart/app/app.component.ts'], QUICKSTART, '/quickstart');
|
||||||
|
const service = ts.createLanguageService(host, registry);
|
||||||
|
program = service.getProgram();
|
||||||
|
checker = program.getTypeChecker();
|
||||||
|
sourceFile = program.getSourceFile('/quickstart/app/app.component.ts');
|
||||||
|
const options: AngularCompilerOptions = Object.create(host.getCompilationSettings());
|
||||||
|
options.genDir = '/dist';
|
||||||
|
options.basePath = '/quickstart';
|
||||||
|
const aotHost = new CompilerHost(program, options, host, {verboseInvalidExpression: true});
|
||||||
|
context = new DiagnosticContext(service, program, checker, aotHost);
|
||||||
|
query = getSymbolQuery(program, checker, sourceFile, emptyPipes)
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to get undefined for an unknown symbol', () => {
|
||||||
|
const unknownType = context.getStaticSymbol('/unkonwn/file.ts', 'UnknownType');
|
||||||
|
const symbol = query.getTypeSymbol(unknownType);
|
||||||
|
expect(symbol).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function appComponentSource(template: string): string {
|
||||||
|
return `
|
||||||
|
import {Component} from '@angular/core';
|
||||||
|
|
||||||
|
export interface Person {
|
||||||
|
name: string;
|
||||||
|
address: Address;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Address {
|
||||||
|
street: string;
|
||||||
|
city: string;
|
||||||
|
state: string;
|
||||||
|
zip: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
template: '${template}'
|
||||||
|
})
|
||||||
|
export class AppComponent {
|
||||||
|
name = 'Angular';
|
||||||
|
person: Person;
|
||||||
|
people: Person[];
|
||||||
|
maybePerson?: Person;
|
||||||
|
|
||||||
|
getName(): string { return this.name; }
|
||||||
|
getPerson(): Person { return this.person; }
|
||||||
|
getMaybePerson(): Person | undefined { this.maybePerson; }
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUICKSTART: Directory = {
|
||||||
|
quickstart: {
|
||||||
|
app: {
|
||||||
|
'app.component.ts': appComponentSource('<h1>Hello {{name}}</h1>'),
|
||||||
|
'app.module.ts': `
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { toString } from './utils';
|
||||||
|
|
||||||
|
import { AppComponent } from './app.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [ AppComponent ],
|
||||||
|
bootstrap: [ AppComponent ]
|
||||||
|
})
|
||||||
|
export class AppModule { }
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user