Skip to content

Commit 681c7fe

Browse files
Merge branch 'master' into docComments
2 parents f5e9c03 + 8714673 commit 681c7fe

27 files changed

Lines changed: 1347 additions & 199 deletions
-14.2 KB
Binary file not shown.
-128 KB
Binary file not shown.
-6.31 KB
Binary file not shown.
88.7 KB
Binary file not shown.

doc/spec.md

Lines changed: 288 additions & 124 deletions
Large diffs are not rendered by default.

src/compiler/checker.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ module ts {
9292
getContextualType: getContextualType,
9393
getFullyQualifiedName: getFullyQualifiedName,
9494
getResolvedSignature: getResolvedSignature,
95-
getEnumMemberValue: getEnumMemberValue
95+
getEnumMemberValue: getEnumMemberValue,
96+
isValidPropertyAccess: isValidPropertyAccess
9697
};
9798

9899
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@@ -4239,6 +4240,25 @@ module ts {
42394240
return anyType;
42404241
}
42414242

4243+
function isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean {
4244+
var type = checkExpression(node.left);
4245+
if (type !== unknownType && type !== anyType) {
4246+
var apparentType = getApparentType(getWidenedType(type));
4247+
var prop = getPropertyOfApparentType(apparentType, propertyName);
4248+
if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) {
4249+
if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) {
4250+
return false;
4251+
}
4252+
else {
4253+
var diagnosticsCount = diagnostics.length;
4254+
checkClassPropertyAccess(node, type, prop);
4255+
return diagnostics.length === diagnosticsCount
4256+
}
4257+
}
4258+
}
4259+
return true;
4260+
}
4261+
42424262
function checkIndexedAccess(node: IndexedAccess): Type {
42434263
var objectType = checkExpression(node.object);
42444264
var indexType = checkExpression(node.index);

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,8 @@ module ts {
655655
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
656656
// computed value.
657657
getEnumMemberValue(node: EnumMember): number;
658+
659+
isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean;
658660
}
659661

660662
export interface TextWriter {

src/harness/fourslash.ts

Lines changed: 65 additions & 60 deletions
Large diffs are not rendered by default.

src/services/services.ts

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,15 +2038,6 @@ module ts {
20382038
return (SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation);
20392039
}
20402040

2041-
function isVisibleWithinClassDeclaration(symbol: Symbol, containingClass: Declaration): boolean {
2042-
var declaration = symbol.declarations && symbol.declarations[0];
2043-
if (declaration && (declaration.flags & NodeFlags.Private)) {
2044-
var declarationClass = getAncestor(declaration, SyntaxKind.ClassDeclaration);
2045-
return containingClass === declarationClass;
2046-
}
2047-
return true;
2048-
}
2049-
20502041
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
20512042
if (!existingMembers || existingMembers.length === 0) {
20522043
return contextualMemberSymbols;
@@ -2150,15 +2141,14 @@ module ts {
21502141
// Right of dot member completion list
21512142
if (isRightOfDot) {
21522143
var symbols: Symbol[] = [];
2153-
var containingClass = getAncestor(mappedNode, SyntaxKind.ClassDeclaration);
21542144
isMemberCompletion = true;
21552145

21562146
if (mappedNode.kind === SyntaxKind.Identifier || mappedNode.kind === SyntaxKind.QualifiedName || mappedNode.kind === SyntaxKind.PropertyAccess) {
21572147
var symbol = typeInfoResolver.getSymbolInfo(mappedNode);
21582148
if (symbol && symbol.flags & SymbolFlags.HasExports) {
21592149
// Extract module or enum members
21602150
forEachValue(symbol.exports, symbol => {
2161-
if (isVisibleWithinClassDeclaration(symbol, containingClass)) {
2151+
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(mappedNode.parent), symbol.name)) {
21622152
symbols.push(symbol);
21632153
}
21642154
});
@@ -2170,7 +2160,7 @@ module ts {
21702160
if (apparentType) {
21712161
// Filter private properties
21722162
forEach(apparentType.getApparentProperties(), symbol => {
2173-
if (isVisibleWithinClassDeclaration(symbol, containingClass)) {
2163+
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccess>(mappedNode.parent), symbol.name)) {
21742164
symbols.push(symbol);
21752165
}
21762166
});
@@ -2645,6 +2635,11 @@ module ts {
26452635
return getReturnOccurrences(<ReturnStatement>node.parent);
26462636
}
26472637
break;
2638+
case SyntaxKind.ThrowKeyword:
2639+
if (hasKind(node.parent, SyntaxKind.ThrowStatement)) {
2640+
return getThrowOccurrences(<ThrowStatement>node.parent);
2641+
}
2642+
break;
26482643
case SyntaxKind.TryKeyword:
26492644
case SyntaxKind.CatchKeyword:
26502645
case SyntaxKind.FinallyKeyword:
@@ -2762,12 +2757,108 @@ module ts {
27622757
}
27632758

27642759
var keywords: Node[] = []
2765-
forEachReturnStatement(<Block>(<FunctionDeclaration>func).body, returnStatement => {
2760+
forEachReturnStatement(<Block>func.body, returnStatement => {
27662761
pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword);
27672762
});
27682763

2764+
// Include 'throw' statements that do not occur within a try block.
2765+
forEach(aggregateOwnedThrowStatements(func.body), throwStatement => {
2766+
pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword);
2767+
});
2768+
27692769
return map(keywords, getReferenceEntryFromNode);
27702770
}
2771+
2772+
function getThrowOccurrences(throwStatement: ThrowStatement) {
2773+
var owner = getThrowStatementOwner(throwStatement);
2774+
2775+
if (!owner) {
2776+
return undefined;
2777+
}
2778+
2779+
var keywords: Node[] = [];
2780+
2781+
forEach(aggregateOwnedThrowStatements(owner), throwStatement => {
2782+
pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword);
2783+
});
2784+
2785+
// If the "owner" is a function, then we equate 'return' and 'throw' statements in their
2786+
// ability to "jump out" of the function, and include occurrences for both.
2787+
if (owner.kind === SyntaxKind.FunctionBlock) {
2788+
forEachReturnStatement(<Block>owner, returnStatement => {
2789+
pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword);
2790+
});
2791+
}
2792+
2793+
return map(keywords, getReferenceEntryFromNode);
2794+
}
2795+
2796+
/**
2797+
* Aggregates all throw-statements within this node *without* crossing
2798+
* into function boundaries and try-blocks with catch-clauses.
2799+
*/
2800+
function aggregateOwnedThrowStatements(node: Node): ThrowStatement[] {
2801+
var statementAccumulator: ThrowStatement[] = []
2802+
aggregate(node);
2803+
return statementAccumulator;
2804+
2805+
function aggregate(node: Node): void {
2806+
if (node.kind === SyntaxKind.ThrowStatement) {
2807+
statementAccumulator.push(<ThrowStatement>node);
2808+
}
2809+
else if (node.kind === SyntaxKind.TryStatement) {
2810+
var tryStatement = <TryStatement>node;
2811+
2812+
if (tryStatement.catchBlock) {
2813+
aggregate(tryStatement.catchBlock);
2814+
}
2815+
else {
2816+
// Exceptions thrown within a try block lacking a catch clause
2817+
// are "owned" in the current context.
2818+
aggregate(tryStatement.tryBlock);
2819+
}
2820+
2821+
if (tryStatement.finallyBlock) {
2822+
aggregate(tryStatement.finallyBlock);
2823+
}
2824+
}
2825+
// Do not cross function boundaries.
2826+
else if (!isAnyFunction(node)) {
2827+
forEachChild(node, aggregate);
2828+
}
2829+
};
2830+
}
2831+
2832+
/**
2833+
* For lack of a better name, this function takes a throw statement and returns the
2834+
* nearest ancestor that is a try-block (whose try statement has a catch clause),
2835+
* function-block, or source file.
2836+
*/
2837+
function getThrowStatementOwner(throwStatement: ThrowStatement): Node {
2838+
var child: Node = throwStatement;
2839+
2840+
while (child.parent) {
2841+
var parent = child.parent;
2842+
2843+
if (parent.kind === SyntaxKind.FunctionBlock || parent.kind === SyntaxKind.SourceFile) {
2844+
return parent;
2845+
}
2846+
2847+
// A throw-statement is only owned by a try-statement if the try-statement has
2848+
// a catch clause, and if the throw-statement occurs within the try block.
2849+
if (parent.kind === SyntaxKind.TryStatement) {
2850+
var tryStatement = <TryStatement>parent;
2851+
2852+
if (tryStatement.tryBlock === child && tryStatement.catchBlock) {
2853+
return child;
2854+
}
2855+
}
2856+
2857+
child = parent;
2858+
}
2859+
2860+
return undefined;
2861+
}
27712862

27722863
function getTryCatchFinallyOccurrences(tryStatement: TryStatement): ReferenceEntry[] {
27732864
var keywords: Node[] = [];
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////class Base {
4+
//// private privateMethod() { }
5+
//// private privateProperty;
6+
////
7+
//// protected protectedMethod() { }
8+
//// protected protectedProperty;
9+
////
10+
//// public publicMethod() { }
11+
//// public publicProperty;
12+
////
13+
//// protected protectedOverriddenMethod() { }
14+
//// protected protectedOverriddenProperty;
15+
////
16+
//// test() {
17+
//// this./*1*/;
18+
////
19+
//// var b: Base;
20+
//// var c: C1;
21+
////
22+
//// b./*2*/;
23+
//// c./*3*/;
24+
//// }
25+
////}
26+
////
27+
////class C1 extends Base {
28+
//// protected protectedOverriddenMethod() { }
29+
//// protected protectedOverriddenProperty;
30+
////}
31+
32+
33+
// Same class, everything is visible
34+
goTo.marker("1");
35+
verify.memberListContains('privateMethod');
36+
verify.memberListContains('privateProperty');
37+
verify.memberListContains('protectedMethod');
38+
verify.memberListContains('protectedProperty');
39+
verify.memberListContains('publicMethod');
40+
verify.memberListContains('publicProperty');
41+
verify.memberListContains('protectedOverriddenMethod');
42+
verify.memberListContains('protectedOverriddenProperty');
43+
44+
goTo.marker("2");
45+
verify.memberListContains('privateMethod');
46+
verify.memberListContains('privateProperty');
47+
verify.memberListContains('protectedMethod');
48+
verify.memberListContains('protectedProperty');
49+
verify.memberListContains('publicMethod');
50+
verify.memberListContains('publicProperty');
51+
verify.memberListContains('protectedOverriddenMethod');
52+
verify.memberListContains('protectedOverriddenProperty');
53+
54+
// Can not access protected properties overridden in subclass
55+
goTo.marker("3");
56+
verify.memberListContains('privateMethod');
57+
verify.memberListContains('privateProperty');
58+
verify.memberListContains('protectedMethod');
59+
verify.memberListContains('protectedProperty');
60+
verify.memberListContains('publicMethod');
61+
verify.memberListContains('publicProperty');
62+
verify.not.memberListContains('protectedOverriddenMethod');
63+
verify.not.memberListContains('protectedOverriddenProperty');

0 commit comments

Comments
 (0)