Ensure getRootSymbols always works recursively

This commit is contained in:
andy-ms 2017-12-10 16:58:17 -08:00
parent 9e51882d9c
commit b554a3691d
4 changed files with 38 additions and 31 deletions

View File

@ -24587,36 +24587,26 @@ namespace ts {
}
function getRootSymbols(symbol: Symbol): Symbol[] {
const roots = getImmediateRootSymbols(symbol);
return roots === undefined ? [symbol] : flatMap(roots, getRootSymbols);
}
function getImmediateRootSymbols(symbol: Symbol): ReadonlyArray<Symbol> | undefined {
if (getCheckFlags(symbol) & CheckFlags.Synthetic) {
const symbols: Symbol[] = [];
const name = symbol.escapedName;
forEach(getSymbolLinks(symbol).containingType.types, t => {
const symbol = getPropertyOfType(t, name);
if (symbol) {
symbols.push(symbol);
}
});
return symbols;
return mapDefined(getSymbolLinks(symbol).containingType.types, type => getPropertyOfType(type, symbol.escapedName));
}
else if (symbol.flags & SymbolFlags.Transient) {
const transient = symbol as TransientSymbol;
if (transient.leftSpread) {
return [...getRootSymbols(transient.leftSpread), ...getRootSymbols(transient.rightSpread)];
}
if (transient.syntheticOrigin) {
return getRootSymbols(transient.syntheticOrigin);
}
let target: Symbol;
let next = symbol;
while (next = getSymbolLinks(next).target) {
target = next;
}
if (target) {
return [target];
}
const { leftSpread, rightSpread, syntheticOrigin } = symbol as TransientSymbol;
return leftSpread ? [leftSpread, rightSpread] : syntheticOrigin ? [syntheticOrigin] : singleElementArray(tryGetAliasTarget(symbol));
}
return [symbol];
return undefined;
}
function tryGetAliasTarget(symbol: Symbol): Symbol | undefined {
let target: Symbol | undefined;
let next = symbol;
while (next = getSymbolLinks(next).target) {
target = next;
}
return target;
}
// Emitter support

View File

@ -1417,8 +1417,8 @@ namespace ts {
return Array.isArray ? Array.isArray(value) : value instanceof Array;
}
export function toArray<T>(value: T | ReadonlyArray<T>): ReadonlyArray<T>;
export function toArray<T>(value: T | T[]): T[];
export function toArray<T>(value: T | ReadonlyArray<T>): ReadonlyArray<T>;
export function toArray<T>(value: T | T[]): T[] {
return isArray(value) ? value : [value];
}
@ -3261,4 +3261,8 @@ namespace ts {
cachedReadDirectoryResult.clear();
}
}
export function singleElementArray<T>(t: T | undefined): T[] {
return t === undefined ? undefined : [t];
}
}

View File

@ -1110,10 +1110,6 @@ namespace ts {
return true;
}
export function singleElementArray<T>(t: T | undefined): T[] {
return t === undefined ? undefined : [t];
}
export function getFirstChildOfKind(node: Node, sourceFile: SourceFile, kind: SyntaxKind): Node | undefined {
return find(node.getChildren(sourceFile), c => c.kind === kind);
}

View File

@ -0,0 +1,17 @@
/// <reference path="fourslash.ts" />
////interface I { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: {}; }
////interface J { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: {}; }
////declare const o: (I | J) & { [|{| "isWriteAccess": true, "isDefinition": true |}x|]: string };
////o.[|x|];
const [r0, r1, r2, r3] = test.ranges();
verify.referenceGroups(r0, [{ definition: "(property) I.x: {}", ranges: [r0, r3] }]);
verify.referenceGroups(r1, [{ definition: "(property) J.x: {}", ranges: [r1, r3] }]);
verify.referenceGroups(r2, [{ definition: "(property) x: string", ranges: [r2, r3] }]);
verify.referenceGroups(r3, [
{ definition: "(property) I.x: {}", ranges: [r0] },
{ definition: "(property) J.x: {}", ranges: [r1] },
{ definition: "(property) x: string", ranges: [r2] },
{ definition: "(property) x: string & {}", ranges: [r3] },
]);