Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ module ts {
symbolToString: symbolToString,
symbolToDisplayParts: symbolToDisplayParts,
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
getRootSymbol: getRootSymbol,
getRootSymbols: getRootSymbols,
getContextualType: getContextualType,
getFullyQualifiedName: getFullyQualifiedName,
getResolvedSignature: getResolvedSignature,
Expand Down Expand Up @@ -2144,6 +2144,14 @@ module ts {
}
var symbol = <TransientSymbol>createSymbol(SymbolFlags.UnionProperty | SymbolFlags.Transient, prop.name);
symbol.unionType = type;

symbol.declarations = [];
for (var i = 0; i < types.length; i++) {
var s = getPropertyOfType(types[i], prop.name);
if (s.declarations)
symbol.declarations.push.apply(symbol.declarations, s.declarations);
}

members[prop.name] = symbol;
});
var callSignatures = getUnionSignatures(types, SignatureKind.Call);
Expand Down Expand Up @@ -3635,7 +3643,8 @@ module ts {
}

function getBestCommonType(types: Type[], contextualType: Type): Type {
return contextualType && isSupertypeOfEach(contextualType, types) ? contextualType : getUnionType(types); }
return contextualType && isSupertypeOfEach(contextualType, types) ? contextualType : getUnionType(types);
}

function isTypeOfObjectLiteral(type: Type): boolean {
return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
Expand Down Expand Up @@ -7928,8 +7937,22 @@ module ts {
}
}

function getRootSymbol(symbol: Symbol) {
return ((symbol.flags & SymbolFlags.Transient) && getSymbolLinks(symbol).target) || symbol;
function getRootSymbols(symbol: Symbol): Symbol[] {
if (symbol.flags & SymbolFlags.UnionProperty) {
var symbols: Symbol[] = [];
var name = symbol.name;
forEach(getSymbolLinks(symbol).unionType.types, t => {
symbols.push(getPropertyOfType(getApparentType(t), name));
});
return symbols;
}
else if (symbol.flags & SymbolFlags.Transient) {
var target = getSymbolLinks(symbol).target;
if (target) {
return [target];
}
}
return [symbol];
}

// Emitter support
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ module ts {
symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[];
getFullyQualifiedName(symbol: Symbol): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
getRootSymbol(symbol: Symbol): Symbol;
getRootSymbols(symbol: Symbol): Symbol[];
getContextualType(node: Node): Type;
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;

Expand Down
219 changes: 128 additions & 91 deletions src/services/services.ts

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions tests/cases/fourslash/completionEntryForUnionProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
///<reference path="fourslash.ts" />

////interface One {
//// commonProperty: number;
//// commonFunction(): number;
////}
////
////interface Two {
//// commonProperty: string
//// commonFunction(): number;
////}
////
////var x : One | Two;
////
////x./**/

goTo.marker();
verify.memberListContains("commonProperty", "string | number", undefined, undefined, "property");
verify.memberListContains("commonFunction", "() => number", undefined, undefined, "method");
verify.memberListCount(2);
19 changes: 19 additions & 0 deletions tests/cases/fourslash/completionEntryForUnionProperty2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
///<reference path="fourslash.ts" />

////interface One {
//// commonProperty: number;
//// commonFunction(): number;
////}
////
////interface Two {
//// commonProperty: string
//// commonFunction(): number;
////}
////
////var x : One | Two;
////
////x.commonProperty./**/

goTo.marker();
verify.memberListContains("toString", "() => string", undefined, undefined, "method");
verify.memberListCount(1);
24 changes: 24 additions & 0 deletions tests/cases/fourslash/goToDefinitionUnionTypeProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/// <reference path='fourslash.ts' />

////interface One {
//// /*propertyDefinition1*/commonProperty: number;
//// commonFunction(): number;
////}
////
////interface Two {
//// /*propertyDefinition2*/commonProperty: string
//// commonFunction(): number;
////}
////
////var x : One | Two;
////
////x./*propertyReference*/commonProperty;
////x./*3*/commonFunction;

goTo.marker("propertyReference");
goTo.definition(0);
verify.caretAtMarker("propertyDefinition1");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition2");
25 changes: 25 additions & 0 deletions tests/cases/fourslash/goToDefinitionUnionTypeProperty2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/// <reference path='fourslash.ts' />
////interface HasAOrB {
//// /*propertyDefinition1*/a: string;
//// b: string;
////}
////
////interface One {
//// common: { /*propertyDefinition2*/a : number; };
////}
////
////interface Two {
//// common: HasAOrB;
////}
////
////var x : One | Two;
////
////x.common./*propertyReference*/a;

goTo.marker("propertyReference");
goTo.definition(0);
verify.caretAtMarker("propertyDefinition1");

goTo.marker("propertyReference");
goTo.definition(1);
verify.caretAtMarker("propertyDefinition2");
27 changes: 27 additions & 0 deletions tests/cases/fourslash/quickinfoForUnionProperty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/// <reference path="fourslash.ts"/>

////interface One {
//// commonProperty: number;
//// commonFunction(): number;
////}
////
////interface Two {
//// commonProperty: string
//// commonFunction(): number;
////}
////
////var /*1*/x : One | Two;
////
////x./*2*/commonProperty;
////x./*3*/commonFunction;


goTo.marker("1");
verify.quickInfoIs("One | Two", "", "x", "var");


goTo.marker("2");
verify.quickInfoIs("string | number", "", "commonProperty", "property");

goTo.marker("3");
verify.quickInfoIs("() => number", "", "commonFunction", "method");
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// <reference path='fourslash.ts'/>

/// <reference path='fourslash.ts'/>
////interface IFoo { /*1*/xy: number; }
////
////// Assignment
Expand All @@ -23,10 +23,10 @@
////var w: IFoo = { /*4*/xy: undefined };
////
////// Untped -- should not be included
////var u = { xy: 0 };


test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.referencesCountIs(9);
});
////var u = { xy: 0 };
test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.referencesCountIs(9);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// <reference path='fourslash.ts'/>

////interface A {
//// a: number;
//// common: string;
////}
////
////interface B {
//// b: number;
//// common: number;
////}
////
////// Assignment
////var v1: A | B = { a: 0, /*1*/common: "" };
////var v2: A | B = { b: 0, /*2*/common: 3 };
////
////// Function call
////function consumer(f: A | B) { }
////consumer({ a: 0, b: 0, /*3*/common: 1 });
////
////// Type cast
////var c = <A | B> { /*4*/common: 0, b: 0 };
////
////// Array literal
////var ar: Array<A|B> = [{ a: 0, /*5*/common: "" }, { b: 0, /*6*/common: 0 }];
////
////// Nested object literal
////var ob: { aorb: A|B } = { aorb: { b: 0, /*7*/common: 0 } };
////
////// Widened type
////var w: A|B = { a:0, /*8*/common: undefined };
////
////// Untped -- should not be included
////var u1 = { a: 0, b: 0, common: "" };
////var u2 = { b: 0, common: 0 };

test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.referencesCountIs(10); // 8 contextually typed common, and 2 in definition (A.common, B.common)
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/// <reference path='fourslash.ts'/>

////interface A {
//// a: number;
//// common: string;
////}
////
////interface B {
//// /*1*/b: number;
//// common: number;
////}
////
////// Assignment
////var v1: A | B = { a: 0, common: "" };
////var v2: A | B = { /*2*/b: 0, common: 3 };
////
////// Function call
////function consumer(f: A | B) { }
////consumer({ a: 0, /*3*/b: 0, common: 1 });
////
////// Type cast
////var c = <A | B> { common: 0, /*4*/b: 0 };
////
////// Array literal
////var ar: Array<A|B> = [{ a: 0, common: "" }, { /*5*/b: 0, common: 0 }];
////
////// Nested object literal
////var ob: { aorb: A|B } = { aorb: { /*6*/b: 0, common: 0 } };
////
////// Widened type
////var w: A|B = { /*7*/b:undefined, common: undefined };
////
////// Untped -- should not be included
////var u1 = { a: 0, b: 0, common: "" };
////var u2 = { b: 0, common: 0 };

test.markers().forEach((m) => {
goTo.position(m.position, m.fileName);
verify.referencesCountIs(7);
});
35 changes: 35 additions & 0 deletions tests/cases/fourslash/referencesForUnionProperties.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/// <reference path='fourslash.ts'/>

////interface One {
//// common: { /*1*/a: number; };
////}
////
////interface Base {
//// /*2*/a: string;
//// b: string;
////}
////
////interface HasAOrB extends Base {
//// /*3*/a: string;
//// b: string;
////}
////
////interface Two {
//// common: HasAOrB;
////}
////
////var x : One | Two;
////
////x.common./*4*/a;

goTo.marker("1");
verify.referencesCountIs(2); // One.common.a, x.common.a

goTo.marker("2");
verify.referencesCountIs(3); // Base.a, HasAOrB.a, x.common.a

goTo.marker("3");
verify.referencesCountIs(3); // Base.a, HasAOrB.a, x.common.a

goTo.marker("4");
verify.referencesCountIs(4); // One.common.a, Base.a, HasAOrB.a, x.common.a