mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-16 15:44:16 -06:00
Also check inheritance for union and intersection types
This commit is contained in:
parent
051c7b0217
commit
115141cb50
@ -1844,6 +1844,13 @@ namespace ts {
|
||||
owners: string[];
|
||||
}
|
||||
|
||||
// Internal interface used for tracking state in find all references when checking
|
||||
// the inheritance hierarchy of property access expressions
|
||||
interface SymbolInheritanceState {
|
||||
symbol: Symbol;
|
||||
cachedInheritanceResults: Map<boolean>;
|
||||
}
|
||||
|
||||
export interface DisplayPartsSymbolWriter extends SymbolWriter {
|
||||
displayParts(): SymbolDisplayPart[];
|
||||
}
|
||||
@ -6546,13 +6553,17 @@ namespace ts {
|
||||
// symbol of the local type of the symbol the property is being accessed on. This is because our search
|
||||
// symbol may have a different parent symbol if the local type's symbol does not declare the property
|
||||
// being accessed (i.e. it is declared in some parent class or interface)
|
||||
let parentSymbol: Symbol = undefined;
|
||||
let inheritanceCache: Map<boolean> = undefined;
|
||||
if (implementations && searchLocation.parent && searchLocation.parent.kind === SyntaxKind.PropertyAccessExpression && searchLocation === (<PropertyAccessExpression>searchLocation.parent).name) {
|
||||
let parentSymbols: SymbolInheritanceState[] = undefined;
|
||||
|
||||
if (implementations && isRightSideOfPropertyAccess(searchLocation)) {
|
||||
const localParentType = typeChecker.getTypeAtLocation((<PropertyAccessExpression>searchLocation.parent).expression);
|
||||
if (localParentType && localParentType.symbol && localParentType.symbol.getFlags() & (SymbolFlags.Interface | SymbolFlags.Class) && localParentType.symbol.parent !== searchSymbol.parent) {
|
||||
parentSymbol = localParentType.symbol;
|
||||
inheritanceCache = createMap<boolean>();
|
||||
if (localParentType) {
|
||||
if (localParentType.symbol && isClassOrInterfaceReference(localParentType.symbol) && localParentType.symbol.parent !== searchSymbol.parent) {
|
||||
parentSymbols = [createSymbolInheritanceState(localParentType.symbol)];
|
||||
}
|
||||
else if (localParentType.getFlags() & TypeFlags.UnionOrIntersection) {
|
||||
parentSymbols = map(getSymbolsForComponentTypes(<UnionOrIntersectionType>localParentType), createSymbolInheritanceState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6596,7 +6607,7 @@ namespace ts {
|
||||
if (referenceSymbol) {
|
||||
const referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
|
||||
const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
|
||||
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation, parentSymbol, inheritanceCache);
|
||||
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation, parentSymbols);
|
||||
|
||||
if (relatedSymbol) {
|
||||
const referenceEntry = implementations ? getImplementationReferenceEntryForNode(referenceLocation) : getReferenceEntryFromNode(referenceLocation);
|
||||
@ -6691,6 +6702,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getSymbolsForComponentTypes(type: UnionOrIntersectionType, result: Symbol[] = []): Symbol[] {
|
||||
for (const componentType of type.types) {
|
||||
if (componentType.symbol && componentType.symbol.getFlags() & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
||||
result.push(componentType.symbol);
|
||||
}
|
||||
if (componentType.getFlags() & TypeFlags.UnionOrIntersection) {
|
||||
getSymbolsForComponentTypes(<UnionOrIntersectionType>componentType, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getContainingTypeReference(node: Node): Node {
|
||||
if (node) {
|
||||
if (node.kind === SyntaxKind.TypeReference) {
|
||||
@ -6786,7 +6809,7 @@ namespace ts {
|
||||
return inherits;
|
||||
}
|
||||
|
||||
function searchTypeReference(typeReference: ExpressionWithTypeArguments, cachedResults: Map<boolean>) {
|
||||
function searchTypeReference(typeReference: ExpressionWithTypeArguments, cachedResults: Map<boolean>): boolean {
|
||||
if (typeReference) {
|
||||
const type = typeChecker.getTypeAtLocation(typeReference);
|
||||
if (type && type.symbol) {
|
||||
@ -6797,6 +6820,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createSymbolInheritanceState(symbol: Symbol): SymbolInheritanceState {
|
||||
return {
|
||||
symbol,
|
||||
cachedInheritanceResults: createMap<boolean>()
|
||||
};
|
||||
}
|
||||
|
||||
function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] {
|
||||
let searchSpaceNode = getSuperContainer(superKeyword, /*stopOnFunctions*/ false);
|
||||
if (!searchSpaceNode) {
|
||||
@ -7144,7 +7174,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, parentSymbol: Symbol, inheritanceCache: Map<boolean>): Symbol {
|
||||
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, parentSymbols: SymbolInheritanceState[]): Symbol {
|
||||
if (searchSymbols.indexOf(referenceSymbol) >= 0) {
|
||||
return referenceSymbol;
|
||||
}
|
||||
@ -7153,7 +7183,7 @@ namespace ts {
|
||||
// symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness.
|
||||
const aliasSymbol = getAliasSymbolForPropertyNameSymbol(referenceSymbol, referenceLocation);
|
||||
if (aliasSymbol) {
|
||||
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, parentSymbol, inheritanceCache);
|
||||
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, parentSymbols);
|
||||
}
|
||||
|
||||
// If the reference location is in an object literal, try to get the contextual type for the
|
||||
@ -7198,7 +7228,13 @@ namespace ts {
|
||||
// Finally, try all properties with the same name in any type the containing type extended or implemented, and
|
||||
// see if any is in the list. If we were passed a parent symbol, only include types that are subtypes of the
|
||||
// parent symbol
|
||||
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) && (!parentSymbol || inheritsFrom(rootSymbol.parent, parentSymbol, inheritanceCache))) {
|
||||
if (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
||||
if (parentSymbols) {
|
||||
if (!forEach(parentSymbols, ({symbol, cachedInheritanceResults}) => inheritsFrom(rootSymbol.parent, symbol, cachedInheritanceResults))) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const result: Symbol[] = [];
|
||||
getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.getName(), result, /*previousIterationSymbolsCache*/ createMap<Symbol>());
|
||||
return forEach(result, s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// Should handle intersection types
|
||||
// Should handle union and intersection types
|
||||
|
||||
//// interface Foo {
|
||||
//// interface BaseFoo {
|
||||
//// hello(): void;
|
||||
//// }
|
||||
////
|
||||
//// interface Foo extends BaseFoo {
|
||||
//// aloha(): void;
|
||||
//// }
|
||||
////
|
||||
@ -13,12 +16,16 @@
|
||||
//// }
|
||||
////
|
||||
//// class FooImpl implements Foo {
|
||||
//// hello() {/**FooImpl*/}
|
||||
//// [|hello() {/**FooImpl*/}|]
|
||||
//// aloha() {}
|
||||
//// }
|
||||
////
|
||||
//// class BaseFooImpl implements BaseFoo {
|
||||
//// hello() {/**BaseFooImpl*/} // Should not show up
|
||||
//// }
|
||||
////
|
||||
//// class BarImpl implements Bar {
|
||||
//// hello() {/**BarImpl*/}
|
||||
//// [|hello() {/**BarImpl*/}|]
|
||||
//// goodbye() {}
|
||||
//// }
|
||||
////
|
||||
@ -28,9 +35,15 @@
|
||||
//// goodbye() {}
|
||||
//// }
|
||||
////
|
||||
//// function someFunction(x: Foo & Bar) {
|
||||
//// x.he/*function_call*/llo();
|
||||
//// function someFunction(x: Foo | Bar) {
|
||||
//// x.he/*function_call0*/llo();
|
||||
//// }
|
||||
////
|
||||
//// function anotherFunction(x: Foo & Bar) {
|
||||
//// x.he/*function_call1*/llo();
|
||||
//// }
|
||||
|
||||
goTo.marker("function_call");
|
||||
verify.allRangesAppearInImplementationList();
|
||||
for (var i = 0; i < 2; i++) {
|
||||
goTo.marker("function_call" + i);
|
||||
verify.allRangesAppearInImplementationList();
|
||||
}
|
||||
|
||||
@ -1,36 +1,12 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// Should handle union types
|
||||
|
||||
//// interface Foo {
|
||||
//// hello(): void;
|
||||
//// aloha(): void;
|
||||
//// }
|
||||
////
|
||||
//// interface Bar {
|
||||
//// hello(): void;
|
||||
//// goodbye(): void;
|
||||
//// }
|
||||
////
|
||||
//// class FooImpl implements Foo {
|
||||
//// [|hello() {/**FooImpl*/}|]
|
||||
//// aloha() {}
|
||||
//// }
|
||||
////
|
||||
//// class BarImpl implements Bar {
|
||||
//// [|hello() {/**BarImpl*/}|]
|
||||
//// goodbye() {}
|
||||
//// }
|
||||
////
|
||||
//// class FooAndBarImpl implements Foo, Bar {
|
||||
//// [|hello() {/**FooAndBarImpl*/}|]
|
||||
//// aloha() {}
|
||||
//// goodbye() {}
|
||||
//// }
|
||||
////
|
||||
//// function someFunction(x: Foo | Bar) {
|
||||
//// x.he/*function_call*/llo();
|
||||
//// }
|
||||
|
||||
goTo.marker("function_call");
|
||||
verify.allRangesAppearInImplementationList();
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// Should handle members of object literals in type assertion expressions
|
||||
|
||||
//// interface Foo {
|
||||
//// hel/*reference*/lo(): void;
|
||||
//// }
|
||||
////
|
||||
//// var x = <Foo> { [|hello: () => {}|] };
|
||||
//// var y = <Foo> (((({ [|hello: () => {}|] }))));
|
||||
goTo.marker("reference");
|
||||
verify.allRangesAppearInImplementationList();
|
||||
@ -1,12 +0,0 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// Should handle members of object literals in type assertion expressions
|
||||
|
||||
//// interface Foo {
|
||||
//// hel/*reference*/lo(): void;
|
||||
//// }
|
||||
////
|
||||
//// var x = <Foo> { [|hello: () => {}|] };
|
||||
//// var y = <Foo> (((({ [|hello: () => {}|] }))));
|
||||
goTo.marker("reference");
|
||||
verify.allRangesAppearInImplementationList();
|
||||
Loading…
x
Reference in New Issue
Block a user