diff --git a/doc/TypeScript Language Specification (Change Markup).docx b/doc/TypeScript Language Specification (Change Markup).docx
index a2b2cf2ca5a..5bc24af5ec8 100644
Binary files a/doc/TypeScript Language Specification (Change Markup).docx and b/doc/TypeScript Language Specification (Change Markup).docx differ
diff --git a/doc/TypeScript Language Specification (Change Markup).pdf b/doc/TypeScript Language Specification (Change Markup).pdf
index 85478fa19ca..52998e9ec79 100644
Binary files a/doc/TypeScript Language Specification (Change Markup).pdf and b/doc/TypeScript Language Specification (Change Markup).pdf differ
diff --git a/doc/TypeScript Language Specification.docx b/doc/TypeScript Language Specification.docx
index d3a189853c5..740dd2c6034 100644
Binary files a/doc/TypeScript Language Specification.docx and b/doc/TypeScript Language Specification.docx differ
diff --git a/doc/TypeScript Language Specification.pdf b/doc/TypeScript Language Specification.pdf
index bebf6c6f046..4263dd72dc1 100644
Binary files a/doc/TypeScript Language Specification.pdf and b/doc/TypeScript Language Specification.pdf differ
diff --git a/doc/spec.md b/doc/spec.md
index aff7e06f469..e49132c61fc 100644
--- a/doc/spec.md
+++ b/doc/spec.md
@@ -44,8 +44,10 @@ TypeScript is a trademark of Microsoft Corporation.
* [3.3 Object Types](#3.3)
* [3.3.1 Named Type References](#3.3.1)
* [3.3.2 Array Types](#3.3.2)
- * [3.3.3 Anonymous Types](#3.3.3)
- * [3.3.4 Members](#3.3.4)
+ * [3.3.3 Tuple Types](#3.3.3)
+ * [3.3.4 Function Types](#3.3.4)
+ * [3.3.5 Constructor Types](#3.3.5)
+ * [3.3.6 Members](#3.3.6)
* [3.4 Type Parameters](#3.4)
* [3.4.1 Type Parameter Lists](#3.4.1)
* [3.4.2 Type Argument Lists](#3.4.2)
@@ -54,9 +56,13 @@ TypeScript is a trademark of Microsoft Corporation.
* [3.6 Specifying Types](#3.6)
* [3.6.1 Predefined Types](#3.6.1)
* [3.6.2 Type References](#3.6.2)
- * [3.6.3 Type Queries](#3.6.3)
- * [3.6.4 Type Literals](#3.6.4)
- * [3.7 Object Type Literals](#3.7)
+ * [3.6.3 Object Type Literals](#3.6.3)
+ * [3.6.4 Array Type Literals](#3.6.4)
+ * [3.6.5 Tuple Type Literals](#3.6.5)
+ * [3.6.6 Function Type Literals](#3.6.6)
+ * [3.6.7 Constructor Type Literals](#3.6.7)
+ * [3.6.8 Type Queries](#3.6.8)
+ * [3.7 Specifying Members](#3.7)
* [3.7.1 Property Signatures](#3.7.1)
* [3.7.2 Call Signatures](#3.7.2)
* [3.7.3 Construct Signatures](#3.7.3)
@@ -1041,7 +1047,20 @@ All string literal types are subtypes of the String primitive type.
## 3.3 Object Types
-The object types include references to class and interface types as well as anonymous object types created by a number of constructs such as object literals, function declarations, and module declarations. Object types are composed from properties, call signatures, construct signatures, and index signatures, collectively called members.
+Object types are composed from properties, call signatures, construct signatures, and index signatures, collectively called members.
+
+Class and interface type references, array types, tuple types, function types, and constructor types are all classified as object types. Multiple constructs in the TypeScript language create object types, including:
+
+* Object type literals (section [3.6.3](#3.6.3)).
+* Array type literals (section [3.6.4](#3.6.4)).
+* Tuple type literals (section [3.6.5](#3.6.5)).
+* Function type literals (section [3.6.6](#3.6.6)).
+* Constructor type literals (section [3.6.7](#3.6.7)).
+* Object literals (section [4.5](#4.5)).
+* Array literals (section [4.6](#4.6)).
+* Function expressions (section [4.9](#4.9)) and function declarations ([6.1](#6.1)).
+* Constructor function types created by class declarations (section [8.2.5](#8.2.5)).
+* Module instance types created by module declarations (section [10.3](#10.3)).
### 3.3.1 Named Type References
@@ -1049,22 +1068,60 @@ Type references (section [3.6.2](#3.6.2)) to class and interface types are class
### 3.3.2 Array Types
-Array types represent JavaScript arrays. Array types are type references (section [3.6.2](#3.6.2)) created from the generic interface type ‘Array’ in the global module. Array type literals (section [3.6.4](#3.6.4)) provide a shorthand notation for creating such references.
+***Array types*** represent JavaScript arrays with a common element type. Array types are named type references created from the generic interface type ‘Array’ in the global module with the array element type as a type argument. Array type literals (section [Error! Reference source not found.](#Error! Reference source not found.)) provide a shorthand notation for creating such references.
-Array literals (section [4.6](#4.6)) may be used to create values of array types.
+The declaration of the ‘Array’ interface includes a property ‘length’ and a numeric index signature for the element type, along with other members:
-### 3.3.3 Anonymous Types
+```TypeScript
+interface Array {
+ length: number;
+ [x: number]: T;
+ // Other members
+}
+```
-Several constructs in the TypeScript language introduce new anonymous object types:
+Array literals (section [4.6](#4.6)) may be used to create values of array types. For example
-* Function and constructor type literals (section [3.6.4](#3.6.4)).
-* Object type literals (section [3.7](#3.7)).
-* Object literals (section [4.5](#4.5)).
-* Function expressions (section [4.9](#4.9)) and function declarations ([6.1](#6.1)).
-* Constructor function types created by class declarations (section [8.2.5](#8.2.5)).
-* Module instance types created by module declarations (section [10.3](#10.3)).
+```TypeScript
+var a: string[] = ["hello", "world"];
+```
-### 3.3.4 Members
+### 3.3.3 Tuple Types
+
+***Tuple types*** represent JavaScript arrays with individually tracked element types. Tuple types are written using tuple type literals (section [3.6.5](#3.6.5)). A tuple type combines a set of numerically named properties with the members of an array type. Specifically, a tuple type
+
+```TypeScript
+[ T0, T1, ..., Tn ]
+```
+
+combines the set of properties
+
+```TypeScript
+{
+ 0: T0;
+ 1: T1;
+ ...
+ n: Tn;
+}
+```
+
+with the members of an array type whose element type is the best common type (section [3.10](#3.10)) of the tuple element types.
+
+Array literals (section [4.6](#4.6)) may be used to create values of tuple types. For example
+
+```TypeScript
+var t: [number, string] = [1, "one"];
+```
+
+### 3.3.4 Function Types
+
+An object type containing one or more call signatures is said to be a ***function type***. Function types may be written using function type literals (section [3.6.6](#3.6.6)) or by including call signatures in object type literals.
+
+### 3.3.5 Constructor Types
+
+An object type containing one or more construct signatures is said to be a ***constructor type***. Constructor types may be written using constructor type literals (section [3.6.7](#3.6.7)) or by including construct signatures in object type literals.
+
+### 3.3.6 Members
Every object type is composed from zero or more of the following kinds of members:
@@ -1198,13 +1255,19 @@ class G { // Introduce type parameter T
## 3.6 Specifying Types
-Types are specified either by referencing their keyword or name, by querying expression types, or by writing type literals which compose other types into new types.
+Types are specified either by referencing their keyword or name, or by writing object type literals, array type literals, tuple type literals, function type literals, constructor type literals, or type queries.
*Type:*
*PredefinedType*
*TypeReference*
- *TypeQuery*
- *TypeLiteral*
+ *ObjectType*
+ *ArrayType*
+ *TupleType*
+ *FunctionType*
+ *ConstructorType*
+ *TypeQuery*
+
+The different forms of type notations are described in the following sections.
### 3.6.1 Predefined Types
@@ -1278,7 +1341,123 @@ var v1: {
};
```
-### 3.6.3 Type Queries
+### 3.6.3 Object Type Literals
+
+An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous.
+
+ *ObjectType:*
+ `{` *TypeBodyopt* `}`
+
+ *TypeBody:*
+ *TypeMemberList* `;`*opt*
+
+ *TypeMemberList:*
+ *TypeMember*
+ *TypeMemberList* `;` *TypeMember*
+
+ *TypeMember:*
+ *PropertySignature*
+ *CallSignature*
+ *ConstructSignature*
+ *IndexSignature*
+ *MethodSignature*
+
+The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. Object type members are described in section [3.7](#3.7).
+
+### 3.6.4 Array Type Literals
+
+An array type literal is written as an element type followed by an open and close square bracket.
+
+ *ArrayType:*
+ *ElementType* *[no LineTerminator here]* `[` `]`
+
+ *ElementType:*
+ *PredefinedType*
+ *TypeReference*
+ *ObjectType*
+ *ArrayType*
+ *TupleType*
+ *TypeQuery*
+
+An array type literal references an array type (section [3.3.2](#3.3.2)) with the given element type. An array type literal is simply shorthand notation for a reference to the generic interface type ‘Array’ in the global module with the element type as a type argument.
+
+In order to avoid grammar ambiguities, array type literals permit only a restricted set of notations for the element type. Specifically, an *ArrayType* cannot start with a *FunctionType* or *ConstructorType*. To use one of those forms for the element type, an array type must be written using the ‘Array<T>’ notation. For example, the type
+
+```TypeScript
+() => string[]
+```
+
+denotes a function returning a string array, not an array of functions returning string. The latter can be expressed using ‘Array<T>’ notation
+
+```TypeScript
+Array<() => string>
+```
+
+or by writing the element type as an object type literal
+
+```TypeScript
+{ (): string }[]
+```
+
+### 3.6.5 Tuple Type Literals
+
+A tuple type literal is written as a sequence of element types, separated by commas and enclosed in square brackets.
+
+ *TupleType:*
+ `[` *TupleElementTypes* `]`
+
+ *TupleElementTypes:*
+ *TupleElementType*
+ *TupleElementTypes* `,` *TupleElementType*
+
+ *TupleElementType:*
+ *Type*
+
+A tuple type literal references a tuple type (section [3.3.3](#3.3.3)).
+
+### 3.6.6 Function Type Literals
+
+A function type literal specifies the type parameters, regular parameters, and return type of a call signature.
+
+ *FunctionType:*
+ *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
+
+A function type literal is shorthand for an object type containing a single call signature. Specifically, a function type literal of the form
+
+```TypeScript
+< T1, T2, ... > ( p1, p2, ... ) => R
+```
+
+is exactly equivalent to the object type literal
+
+```TypeScript
+{ < T1, T2, ... > ( p1, p2, ... ) : R }
+```
+
+Note that function types with multiple call or construct signatures cannot be written as function type literals but must instead be written as object type literals.
+
+### 3.6.7 Constructor Type Literals
+
+A constructor type literal specifies the type parameters, regular parameters, and return type of a construct signature.
+
+ *ConstructorType:*
+ `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
+
+A constructor type literal is shorthand for an object type containing a single construct signature. Specifically, a constructor type literal of the form
+
+```TypeScript
+new < T1, T2, ... > ( p1, p2, ... ) => R
+```
+
+is exactly equivalent to the object type literal
+
+```TypeScript
+{ new < T1, T2, ... > ( p1, p2, ... ) : R }
+```
+
+Note that constructor types with multiple construct signatures cannot be written as constructor type literals but must instead be written as object type literals.
+
+### 3.6.8 Type Queries
A type query obtains the type of an expression.
@@ -1318,82 +1497,9 @@ var h: () => typeof h;
Here, ‘g’ and ‘g.x’ have the same recursive type, and likewise ‘h’ and ‘h()’ have the same recursive type.
-### 3.6.4 Type Literals
+## 3.7 Specifying Members
-Type literals compose other types into new anonymous types.
-
- *TypeLiteral:*
- *ObjectType*
- *ArrayType*
- *FunctionType*
- *ConstructorType*
-
- *ArrayType:*
- *ElementType* *[no LineTerminator here]* `[` `]`
-
- *ElementType:*
- *PredefinedType*
- *TypeReference*
- *TypeQuery*
- *ObjectType*
- *ArrayType*
-
- *FunctionType:*
- *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
-
- *ConstructorType:*
- `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
-
-Object type literals are the primary form of type literals and are described in section [3.7](#3.7). Array, function, and constructor type literals are simply shorthand notations for other types:
-
-|Type literal|Equivalent form|
-|---|---|
-|`T [ ]`|`Array < T >`|
-|`< ... > ( ... ) => T`|`{ < ... > ( ... ) : T }`|
-|`new < ... > ( ... ) => T`|`{ new < ... > ( ... ) : T }`|
-
-As the table above illustrates, an array type literal is shorthand for a reference to the generic interface type ‘Array’ in the global module, a function type literal is shorthand for an object type containing a single call signature, and a constructor type literal is shorthand for an object type containing a single construct signature. Note that function and constructor types with multiple call or construct signatures cannot be written as function or constructor type literals but must instead be written as object type literals.
-
-In order to avoid grammar ambiguities, array type literals permit only a restricted set of notations for the element type. Specifically, an *ArrayType* cannot start with a *FunctionType* or *ConstructorType*. To use one of those forms for the element type, an array type must be written using the ‘Array<T>’ notation. For example, the type
-
-```TypeScript
-() => string[]
-```
-
-denotes a function returning a string array, not an array of functions returning string. The latter can be expressed using ‘Array<T>’ notation
-
-```TypeScript
-Array<() => string>
-```
-
-or by writing the element type as an object type literal
-
-```TypeScript
-{ (): string }[]
-```
-
-## 3.7 Object Type Literals
-
-An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous.
-
- *ObjectType:*
- `{` *TypeBodyopt* `}`
-
- *TypeBody:*
- *TypeMemberList* `;`*opt*
-
- *TypeMemberList:*
- *TypeMember*
- *TypeMemberList* `;` *TypeMember*
-
- *TypeMember:*
- *PropertySignature*
- *CallSignature*
- *ConstructSignature*
- *IndexSignature*
- *MethodSignature*
-
-The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. The signatures are separated by semicolons and enclosed in curly braces.
+The members of an object type literal (section [3.6.3](#3.6.3)) are specified as a combination of property, call, construct, index, and method signatures.
### 3.7.1 Property Signatures
@@ -1422,9 +1528,9 @@ A call signature defines the type parameters, parameter list, and return type as
A call signature that includes *TypeParameters* (section [3.4.1](#3.4.1)) is called a ***generic call signature***. Conversely, a call signature with no *TypeParameters* is called a non-generic call signature.
-As well as being members of object type literals, call signatures occur in method signatures (section [3.7.5](#3.7.5)), function expressions (section [4.9](#4.9)), and function declarations (section [6.1](#6.1)).
+As well as being members of object type literals, call signatures occur in method signatures (section [3.7.5](#3.7.5)), function expressions (section [4.9](#4.9)), and function declarations (section [6.1](#6.1)).
-An object type containing call signatures is said to be a ***function type***.
+An object type containing call signatures is said to be a ***function type***.
#### 3.7.2.1 Type Parameters
@@ -1548,7 +1654,7 @@ The type parameters, parameter list, and return type of a construct signature ar
A type containing construct signatures is said to be a ***constructor type***.
-### 3.7.4 Index Signatures
+### 3.7.4 Index Signatures
An index signature defines a type constraint for properties in the containing type.
@@ -1980,9 +2086,38 @@ When an object literal is contextually typed by a type that includes a string in
## 4.6 Array Literals
-In the absence of a contextual type, the type of an array literal is *C*`[]`, where *C* is the Undefined type (section [3.2.6](#3.2.6)) if the array literal is empty, or the best common type of the element expressions if the array literal is not empty.
+An array literal
-When an array literal is contextually typed (section [4.19](#4.19)) by an object type containing a numeric index signature of type *T*, each element expression is contextually typed by *T* and the type of the array literal is the best common type of the contextual type *T* and the types of the element expressions.
+```TypeScript
+[expr1, expr2, ..., exprN]
+```
+
+denotes a value of an array type (section [3.3.2](#3.3.2)) or a tuple type (section [3.3.3](#3.3.3)) depending on context.
+
+Each element expression in a non-empty array literal is processed as follows:
+
+* If the array literal is contextually typed (section [4.19](#4.19)) by a type *T* and *T* has a property with the numeric name *N*, where *N* is the index of the element expression in the array literal, the element expression is contextually typed by the type of that property.
+* Otherwise, if the array literal is contextually typed by a type *T* with a numeric index signature, the element expression is contextually typed by the type of the numeric index signature.
+* Otherwise, the element expression is not contextually typed.
+
+The resulting type of a non-empty array literal expression is determined as follows:
+
+* If the array literal is contextually typed by a type *T* and *T* has at least one property with a numeric name that matches the index of an element expression in the array literal, the resulting type is a tuple type constructed from the types of the element expressions.
+* Otherwise, if the array literal is contextually typed by a type T with a numeric index signature of type *S*, the resulting type is an array type where the element type is the best common type of the contextual type *S* and the types of the element expressions.
+* Otherwise, if the array literal is not contextually typed, the resulting type is an array type where the element type is the best common type of the types of the element expressions.
+
+The resulting type of an empty array literal expression is determined as follows:
+
+* If the array literal is contextually typed by a type *T* with a numeric index signature of type *S*, the resulting type is an array type with element type *S*.
+* Otherwise, the resulting type is an array type with the element type Undefined.
+
+The rules above mean that an array literal is always of an array type, unless it is contextually typed by a type with numerically named properties (such as a tuple type). For example
+
+```TypeScript
+var a = [1, 2]; // number[]
+var b = ["hello", true]; // {}[]
+var c: [number, string] = [3, "three"]; // [number, string]
+```
## 4.7 Parentheses
@@ -2181,6 +2316,26 @@ where *object* and *index* are expressions, is used to access the property with
* Otherwise, if *index* is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any.
* Otherwise, the property access is invalid and a compile-time error occurs.
+The rules above mean that properties are strongly typed when accessed using bracket notation with the literal representation of their name. For example:
+
+```TypeScript
+var type = {
+ name: "boolean",
+ primitive: true
+};
+
+var s = type["name"]; // string
+var b = type["primitive"]; // boolean
+```
+
+Tuple types assign numeric names to each of their elements and elements are therefore strongly typed when accessed using bracket notation with a numeric literal:
+
+```TypeScript
+var data: [string, number] = ["five", 5];
+var s = data[0]; // string
+var n = data[1]; // number
+```
+
## 4.11 The new Operator
A `new` operation has one of the following forms:
@@ -2435,7 +2590,7 @@ The
### 4.14.6 The typeof Operator
-The ‘typeof’ operator takes an operand of any type and produces a value of the String primitive type. In positions where a type is expected, ‘typeof’ can also be used in a type query (section [3.6.3](#3.6.3)) to produce the type of an expression.
+The ‘typeof’ operator takes an operand of any type and produces a value of the String primitive type. In positions where a type is expected, ‘typeof’ can also be used in a type query (section [3.6.8](#3.6.8)) to produce the type of an expression.
```TypeScript
var x = 5;
@@ -2451,7 +2606,7 @@ The subsections that follow specify the compile-time processing rules of the bin
### 4.15.1 The *, /, %, –, <<, >>, >>>, &, ^, and | operators
-These operators require their operands to be of type Any, the Number primitive type, or an enum type. Operands of an enum type are treated as having the primitive type Number. If one operand is the `null` or `undefine``d` value, it is treated as having the type of the other operand. The result is always of the Number primitive type.
+These operators require their operands to be of type Any, the Number primitive type, or an enum type. Operands of an enum type are treated as having the primitive type Number. If one operand is the `null` or `undefined` value, it is treated as having the type of the other operand. The result is always of the Number primitive type.
||Any|Boolean|Number|String|Object|
|:---:|:---:|:---:|:---:|:---:|:---:|
@@ -4803,8 +4958,12 @@ This appendix contains a summary of the grammar found in the main document. As d
*Type:*
*PredefinedType*
*TypeReference*
- *TypeQuery*
- *TypeLiteral*
+ *ObjectType*
+ *ArrayType*
+ *TupleType*
+ *FunctionType*
+ *ConstructorType*
+ *TypeQuery*
*PredefinedType:*
`any`
@@ -4824,35 +4983,6 @@ This appendix contains a summary of the grammar found in the main document. As d
*Identifier*
*ModuleName* `.` *Identifier*
- *TypeQuery:*
- `typeof` *TypeQueryExpression*
-
- *TypeQueryExpression:*
- *Identifier*
- *TypeQueryExpression* `.` *IdentifierName*
-
- *TypeLiteral:*
- *ObjectType*
- *ArrayType*
- *FunctionType*
- *ConstructorType*
-
- *ArrayType:*
- *ElementType* *[no LineTerminator here]* `[` `]`
-
- *ElementType:*
- *PredefinedType*
- *TypeReference*
- *TypeQuery*
- *ObjectType*
- *ArrayType*
-
- *FunctionType:*
- *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
-
- *ConstructorType:*
- `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
-
*ObjectType:*
`{` *TypeBodyopt* `}`
@@ -4870,6 +5000,40 @@ This appendix contains a summary of the grammar found in the main document. As d
*IndexSignature*
*MethodSignature*
+ *ArrayType:*
+ *ElementType* *[no LineTerminator here]* `[` `]`
+
+ *ElementType:*
+ *PredefinedType*
+ *TypeReference*
+ *ObjectType*
+ *ArrayType*
+ *TupleType*
+ *TypeQuery*
+
+ *TupleType:*
+ `[` *TupleElementTypes* `]`
+
+ *TupleElementTypes:*
+ *TupleElementType*
+ *TupleElementTypes* `,` *TupleElementType*
+
+ *TupleElementType:*
+ *Type*
+
+ *FunctionType:*
+ *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
+
+ *ConstructorType:*
+ `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type*
+
+ *TypeQuery:*
+ `typeof` *TypeQueryExpression*
+
+ *TypeQueryExpression:*
+ *Identifier*
+ *TypeQueryExpression* `.` *IdentifierName*
+
*PropertySignature:*
*PropertyName* `?`*opt* *TypeAnnotationopt*
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index cf35c1c02f5..99b387dd18c 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -92,7 +92,8 @@ module ts {
getContextualType: getContextualType,
getFullyQualifiedName: getFullyQualifiedName,
getResolvedSignature: getResolvedSignature,
- getEnumMemberValue: getEnumMemberValue
+ getEnumMemberValue: getEnumMemberValue,
+ isValidPropertyAccess: isValidPropertyAccess
};
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@@ -4239,6 +4240,25 @@ module ts {
return anyType;
}
+ function isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean {
+ var type = checkExpression(node.left);
+ if (type !== unknownType && type !== anyType) {
+ var apparentType = getApparentType(getWidenedType(type));
+ var prop = getPropertyOfApparentType(apparentType, propertyName);
+ if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) {
+ if (node.left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.Method) {
+ return false;
+ }
+ else {
+ var diagnosticsCount = diagnostics.length;
+ checkClassPropertyAccess(node, type, prop);
+ return diagnostics.length === diagnosticsCount
+ }
+ }
+ }
+ return true;
+ }
+
function checkIndexedAccess(node: IndexedAccess): Type {
var objectType = checkExpression(node.object);
var indexType = checkExpression(node.index);
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index dcc42bf3358..b564dba560b 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -655,6 +655,8 @@ module ts {
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
// computed value.
getEnumMemberValue(node: EnumMember): number;
+
+ isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean;
}
export interface TextWriter {
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index a97319ff332..c264c59348f 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -412,6 +412,11 @@ module FourSlash {
}
}
+ private raiseError(message: string) {
+ message = "Marker: " + currentTestState.lastKnownMarker + "\n" + message;
+ throw new Error(message);
+ }
+
private getDiagnostics(fileName: string): ts.Diagnostic[] {
var syntacticErrors = this.languageService.getSyntacticDiagnostics(fileName);
var semanticErrors = this.languageService.getSemanticDiagnostics(fileName);
@@ -500,7 +505,7 @@ module FourSlash {
this.printErrorLog(false, errors);
var errorMsg = "Actual number of errors (" + actual + ") does not match expected number (" + expected + ")";
Harness.IO.log(errorMsg);
- throw new Error(errorMsg);
+ this.raiseError(errorMsg);
}
}
@@ -514,7 +519,7 @@ module FourSlash {
var evaluation = new Function(emit.outputFiles[0].text + ';\r\nreturn (' + expr + ');')();
if (evaluation !== value) {
- throw new Error('Expected evaluation of expression "' + expr + '" to equal "' + value + '", but got "' + evaluation + '"');
+ this.raiseError('Expected evaluation of expression "' + expr + '" to equal "' + value + '", but got "' + evaluation + '"');
}
}
@@ -531,7 +536,7 @@ module FourSlash {
this.assertItemInCompletionList(members.entries, symbol, type, docComment, fullSymbolName, kind);
}
else {
- throw new Error("Expected a member list, but none was provided");
+ this.raiseError("Expected a member list, but none was provided");
}
}
@@ -554,11 +559,11 @@ module FourSlash {
var match = members.entries.length === expectedCount;
if ((!match && !negative) || (match && negative)) {
- throw new Error("Member list count was " + members.entries.length + ". Expected " + expectedCount);
+ this.raiseError("Member list count was " + members.entries.length + ". Expected " + expectedCount);
}
}
else if (expectedCount) {
- throw new Error("Member list count was 0. Expected " + expectedCount);
+ this.raiseError("Member list count was 0. Expected " + expectedCount);
}
}
@@ -568,7 +573,7 @@ module FourSlash {
var members = this.getMemberListAtCaret();
if (members.entries.filter(e => e.name === symbol).length !== 0) {
- throw new Error('Member list did contain ' + symbol);
+ this.raiseError('Member list did contain ' + symbol);
}
}
@@ -579,7 +584,7 @@ module FourSlash {
var itemsCount = completions.entries.length;
if (itemsCount <= count) {
- throw new Error('Expected completion list items count to be greater than ' + count + ', but is actually ' + itemsCount);
+ this.raiseError('Expected completion list items count to be greater than ' + count + ', but is actually ' + itemsCount);
}
}
@@ -592,7 +597,7 @@ module FourSlash {
var members = this.getMemberListAtCaret();
if ((!members || members.entries.length === 0) && negative) {
- throw new Error("Member list is empty at Caret");
+ this.raiseError("Member list is empty at Caret");
} else if ((members && members.entries.length !== 0) && !negative) {
var errorMsg = "\n" + "Member List contains: [" + members.entries[0].name;
@@ -602,7 +607,7 @@ module FourSlash {
errorMsg += "]\n";
Harness.IO.log(errorMsg);
- throw new Error("Member list is not empty at Caret");
+ this.raiseError("Member list is not empty at Caret");
}
}
@@ -612,7 +617,7 @@ module FourSlash {
var completions = this.getCompletionListAtCaret();
if ((!completions || completions.entries.length === 0) && negative) {
- throw new Error("Completion list is empty at Caret");
+ this.raiseError("Completion list is empty at Caret");
} else if ((completions && completions.entries.length !== 0) && !negative) {
var errorMsg = "\n" + "Completion List contains: [" + completions.entries[0].name;
@@ -622,7 +627,7 @@ module FourSlash {
errorMsg += "]\n";
Harness.IO.log(errorMsg);
- throw new Error("Completion list is not empty at Caret");
+ this.raiseError("Completion list is not empty at Caret");
}
}
@@ -638,7 +643,7 @@ module FourSlash {
var completions = this.getCompletionListAtCaret();
if (completions && completions.entries && completions.entries.filter(e => e.name === symbol).length !== 0) {
- throw new Error('Completion list did contain ' + symbol);
+ this.raiseError('Completion list did contain ' + symbol);
}
}
@@ -668,21 +673,21 @@ module FourSlash {
var references = this.getReferencesAtCaret();
if (!references || references.length === 0) {
- throw new Error('verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.');
+ this.raiseError('verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.');
}
for (var i = 0; i < references.length; i++) {
var reference = references[i];
if (reference && reference.fileName === fileName && reference.textSpan.start() === start && reference.textSpan.end() === end) {
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
- throw new Error('verifyReferencesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + reference.isWriteAccess + ', expected: ' + isWriteAccess + '.');
+ this.raiseError('verifyReferencesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + reference.isWriteAccess + ', expected: ' + isWriteAccess + '.');
}
return;
}
}
var missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
- throw new Error('verifyReferencesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(references) + ')');
+ this.raiseError('verifyReferencesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(references) + ')');
}
public verifyReferencesCountIs(count: number, localFilesOnly: boolean = true) {
@@ -706,7 +711,7 @@ module FourSlash {
if (referencesCount !== count) {
var condition = localFilesOnly ? "excluding libs" : "including libs";
- throw new Error("Expected references count (" + condition + ") to be " + count + ", but is actually " + referencesCount);
+ this.raiseError("Expected references count (" + condition + ") to be " + count + ", but is actually " + referencesCount);
}
}
@@ -729,7 +734,7 @@ module FourSlash {
if (implementorsCount !== count) {
var condition = localFilesOnly ? "excluding libs" : "including libs";
- throw new Error("Expected implementors count (" + condition + ") to be " + count + ", but is actually " + implementors.length);
+ this.raiseError("Expected implementors count (" + condition + ") to be " + count + ", but is actually " + implementors.length);
}
}
@@ -806,12 +811,12 @@ module FourSlash {
var actualQuickInfo = this.languageService.getTypeAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (negative) {
if (actualQuickInfo) {
- throw new Error('verifyQuickInfoExists failed. Expected quick info NOT to exist');
+ this.raiseError('verifyQuickInfoExists failed. Expected quick info NOT to exist');
}
}
else {
if (!actualQuickInfo) {
- throw new Error('verifyQuickInfoExists failed. Expected quick info to exist');
+ this.raiseError('verifyQuickInfoExists failed. Expected quick info to exist');
}
}
}
@@ -892,25 +897,25 @@ module FourSlash {
var actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
if (shouldBePresent) {
if (!actual) {
- throw new Error("Expected signature help to be present, but it wasn't");
+ this.raiseError("Expected signature help to be present, but it wasn't");
}
} else {
if (actual) {
- throw new Error("Expected no signature help, but got '" + JSON.stringify(actual) + "'");
+ this.raiseError("Expected no signature help, but got '" + JSON.stringify(actual) + "'");
}
}
}
private validate(name: string, expected: string, actual: string) {
if (expected && expected !== actual) {
- throw new Error("Expected " + name + " '" + expected + "'. Got '" + actual + "' instead.");
+ this.raiseError("Expected " + name + " '" + expected + "'. Got '" + actual + "' instead.");
}
}
public verifyRenameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
var renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
if (!renameInfo.canRename) {
- throw new Error("Rename did not succeed");
+ this.raiseError("Rename did not succeed");
}
this.validate("displayName", displayName, renameInfo.displayName);
@@ -919,13 +924,13 @@ module FourSlash {
this.validate("kindModifiers", kindModifiers, renameInfo.kindModifiers);
if (this.getRanges().length !== 1) {
- throw new Error("Expected a single range to be selected in the test file.");
+ this.raiseError("Expected a single range to be selected in the test file.");
}
var expectedRange = this.getRanges()[0];
if (renameInfo.triggerSpan.start() !== expectedRange.start ||
renameInfo.triggerSpan.end() !== expectedRange.end) {
- throw new Error("Expected triggerSpan [" + expectedRange.start + "," + expectedRange.end + "). Got [" +
+ this.raiseError("Expected triggerSpan [" + expectedRange.start + "," + expectedRange.end + "). Got [" +
renameInfo.triggerSpan.start() + "," + renameInfo.triggerSpan.end() + ") instead.");
}
}
@@ -933,7 +938,7 @@ module FourSlash {
public verifyRenameInfoFailed(message?: string) {
var renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
if (renameInfo.canRename) {
- throw new Error("Rename was expected to fail");
+ this.raiseError("Rename was expected to fail");
}
this.validate("error", message, renameInfo.localizedErrorMessage);
@@ -1009,7 +1014,7 @@ module FourSlash {
// If there is not emiThisFile flag specified in the test file, throw an error
if (emitFiles.length === 0) {
- throw new Error("No emitThisFile is specified in the test file");
+ this.raiseError("No emitThisFile is specified in the test file");
}
Harness.Baseline.runBaseline(
@@ -1309,7 +1314,7 @@ module FourSlash {
//var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics());
//if (incrSyntaxErrs !== fullSyntaxErrs) {
- // throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs);
+ // this.raiseError('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs);
//}
// if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) {
@@ -1326,7 +1331,7 @@ module FourSlash {
// var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName));
// if (incrSemanticErrs !== refSemanticErrs) {
- // throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs);
+ // this.raiseError('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs);
// }
// }
// }
@@ -1365,7 +1370,7 @@ module FourSlash {
var newContent = snapshot.getText(0, snapshot.getLength());
if (newContent.replace(/\s/g, '') !== oldContent.replace(/\s/g, '')) {
- throw new Error('Formatting operation destroyed non-whitespace content');
+ this.raiseError('Formatting operation destroyed non-whitespace content');
}
}
return runningOffset;
@@ -1422,11 +1427,11 @@ module FourSlash {
var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!definitions || !definitions.length) {
- throw new Error('goToDefinition failed - expected to at least one definition location but got 0');
+ this.raiseError('goToDefinition failed - expected to at least one definition location but got 0');
}
if (definitionIndex >= definitions.length) {
- throw new Error('goToDefinition failed - definitionIndex value (' + definitionIndex + ') exceeds definition list size (' + definitions.length + ')');
+ this.raiseError('goToDefinition failed - definitionIndex value (' + definitionIndex + ') exceeds definition list size (' + definitions.length + ')');
}
var definition = definitions[definitionIndex];
@@ -1442,10 +1447,10 @@ module FourSlash {
var foundDefinitions = definitions && definitions.length;
if (foundDefinitions && negative) {
- throw new Error('goToDefinition - expected to 0 definition locations but got ' + definitions.length);
+ this.raiseError('goToDefinition - expected to 0 definition locations but got ' + definitions.length);
}
else if (!foundDefinitions && !negative) {
- throw new Error('goToDefinition - expected to at least one definition location but got 0');
+ this.raiseError('goToDefinition - expected to at least one definition location but got 0');
}
}
@@ -1480,7 +1485,7 @@ module FourSlash {
var actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition);
if (actual != numberOfSpaces) {
- throw new Error('verifyIndentationAtCurrentPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
+ this.raiseError('verifyIndentationAtCurrentPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
}
}
@@ -1489,7 +1494,7 @@ module FourSlash {
var actual = this.getIndentation(fileName, position);
if (actual !== numberOfSpaces) {
- throw new Error('verifyIndentationAtPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
+ this.raiseError('verifyIndentationAtPosition failed - expected: ' + numberOfSpaces + ', actual: ' + actual);
}
}
@@ -1532,14 +1537,14 @@ module FourSlash {
var span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition);
if (span === null) {
- throw new Error('verifyCurrentNameOrDottedNameSpanText\n' +
+ this.raiseError('verifyCurrentNameOrDottedNameSpanText\n' +
'\tExpected: "' + text + '"\n' +
'\t Actual: null');
}
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end());
if (actual !== text) {
- throw new Error('verifyCurrentNameOrDottedNameSpanText\n' +
+ this.raiseError('verifyCurrentNameOrDottedNameSpanText\n' +
'\tExpected: "' + text + '"\n' +
'\t Actual: "' + actual + '"');
}
@@ -1577,7 +1582,7 @@ module FourSlash {
private verifyClassifications(expected: { classificationType: string; text: string }[], actual: ts.ClassifiedSpan[]) {
if (actual.length !== expected.length) {
- throw new Error('verifySyntacticClassification failed - expected total classifications to be ' + expected.length + ', but was ' + actual.length);
+ this.raiseError('verifySyntacticClassification failed - expected total classifications to be ' + expected.length + ', but was ' + actual.length);
}
for (var i = 0; i < expected.length; i++) {
@@ -1586,7 +1591,7 @@ module FourSlash {
var expectedType: string = (ts.ClassificationTypeNames)[expectedClassification.classificationType];
if (expectedType !== actualClassification.classificationType) {
- throw new Error('verifySyntacticClassification failed - expected classifications type to be ' +
+ this.raiseError('verifySyntacticClassification failed - expected classifications type to be ' +
expectedType + ', but was ' +
actualClassification.classificationType);
}
@@ -1594,7 +1599,7 @@ module FourSlash {
var actualSpan = actualClassification.textSpan;
var actualText = this.activeFile.content.substr(actualSpan.start(), actualSpan.length());
if (expectedClassification.text !== actualText) {
- throw new Error('verifySyntacticClassification failed - expected classificatied text to be ' +
+ this.raiseError('verifySyntacticClassification failed - expected classificatied text to be ' +
expectedClassification.text + ', but was ' +
actualText);
}
@@ -1621,14 +1626,14 @@ module FourSlash {
var actual = this.languageService.getOutliningSpans(this.activeFile.fileName);
if (actual.length !== spans.length) {
- throw new Error('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
+ this.raiseError('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
}
for (var i = 0; i < spans.length; i++) {
var expectedSpan = spans[i];
var actualSpan = actual[i];
if (expectedSpan.start !== actualSpan.textSpan.start() || expectedSpan.end !== actualSpan.textSpan.end()) {
- throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')');
+ this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')');
}
}
}
@@ -1638,7 +1643,7 @@ module FourSlash {
descriptors.map(d => { return { text: d, priority: 0 }; }));
if (actual.length !== spans.length) {
- throw new Error('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
+ this.raiseError('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
}
for (var i = 0; i < spans.length; i++) {
@@ -1647,7 +1652,7 @@ module FourSlash {
var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length);
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
- throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
+ this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
}
}
}
@@ -1658,7 +1663,7 @@ module FourSlash {
var actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
if (actual.length !== 2) {
- throw new Error('verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ' + actual.length);
+ this.raiseError('verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ' + actual.length);
}
var actualMatchPosition = -1;
@@ -1667,11 +1672,11 @@ module FourSlash {
} else if (bracePosition === actual[1].start()) {
actualMatchPosition = actual[0].start();
} else {
- throw new Error('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')');
+ this.raiseError('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')');
}
if (actualMatchPosition !== expectedMatchPosition) {
- throw new Error('verifyMatchingBracePosition failed - expected: ' + actualMatchPosition + ', actual: ' + expectedMatchPosition);
+ this.raiseError('verifyMatchingBracePosition failed - expected: ' + actualMatchPosition + ', actual: ' + expectedMatchPosition);
}
}
@@ -1681,7 +1686,7 @@ module FourSlash {
var actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
if (actual.length !== 0) {
- throw new Error('verifyNoMatchingBracePosition failed - expected: 0 spans, actual: ' + actual.length);
+ this.raiseError('verifyNoMatchingBracePosition failed - expected: 0 spans, actual: ' + actual.length);
}
}
@@ -1768,7 +1773,7 @@ module FourSlash {
}
if (expected != actual) {
- throw new Error('verifyNavigationItemsCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
+ this.raiseError('verifyNavigationItemsCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
}
}
@@ -1788,7 +1793,7 @@ module FourSlash {
var items = this.languageService.getNavigateToItems(searchValue);
if (!items || items.length === 0) {
- throw new Error('verifyNavigationItemsListContains failed - found 0 navigation items, expected at least one.');
+ this.raiseError('verifyNavigationItemsListContains failed - found 0 navigation items, expected at least one.');
}
for (var i = 0; i < items.length; i++) {
@@ -1804,7 +1809,7 @@ module FourSlash {
// if there was an explicit match kind specified, then it should be validated.
if (matchKind !== undefined) {
var missingItem = { name: name, kind: kind, searchValue: searchValue, matchKind: matchKind, fileName: fileName, parentName: parentName };
- throw new Error('verifyNavigationItemsListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
+ this.raiseError('verifyNavigationItemsListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
}
}
@@ -1815,7 +1820,7 @@ module FourSlash {
var actual = this.getNavigationBarItemsCount(items);
if (expected != actual) {
- throw new Error('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
+ this.raiseError('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
}
}
@@ -1840,7 +1845,7 @@ module FourSlash {
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
if (!items || items.length === 0) {
- throw new Error('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.');
+ this.raiseError('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.');
}
if (this.navigationBarItemsContains(items, name, kind)) {
@@ -1848,7 +1853,7 @@ module FourSlash {
}
var missingItem = { name: name, kind: kind };
- throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
+ this.raiseError('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
}
private navigationBarItemsContains(items: ts.NavigationBarItem[], name: string, kind: string) {
@@ -1902,21 +1907,21 @@ module FourSlash {
var occurances = this.getOccurancesAtCurrentPosition();
if (!occurances || occurances.length === 0) {
- throw new Error('verifyOccurancesAtPositionListContains failed - found 0 references, expected at least one.');
+ this.raiseError('verifyOccurancesAtPositionListContains failed - found 0 references, expected at least one.');
}
for (var i = 0; i < occurances.length; i++) {
var occurance = occurances[i];
if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) {
if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) {
- throw new Error('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.');
+ this.raiseError('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.');
}
return;
}
}
var missingItem = { fileName: fileName, start: start, end: end, isWriteAccess: isWriteAccess };
- throw new Error('verifyOccurancesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(occurances) + ')');
+ this.raiseError('verifyOccurancesAtPositionListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(occurances) + ')');
}
public verifyOccurrencesAtPositionListCount(expectedCount: number) {
@@ -1925,7 +1930,7 @@ module FourSlash {
var occurances = this.getOccurancesAtCurrentPosition();
var actualCount = occurances ? occurances.length : 0;
if (expectedCount !== actualCount) {
- throw new Error('verifyOccurrencesAtPositionListCount failed - actual: ' + actualCount + ', expected:' + expectedCount);
+ this.raiseError('verifyOccurrencesAtPositionListCount failed - actual: ' + actualCount + ', expected:' + expectedCount);
}
}
@@ -2010,7 +2015,7 @@ module FourSlash {
var itemsString = items.map((item) => JSON.stringify({ name: item.name, kind: item.kind })).join(",\n");
- throw new Error("Marker: " + currentTestState.lastKnownMarker + "\n" + 'Expected "' + JSON.stringify({ name: name, type: type, docComment: docComment, fullSymbolName: fullSymbolName, kind: kind }) + '" to be in list [' + itemsString + ']');
+ this.raiseError('Expected "' + JSON.stringify({ name: name, type: type, docComment: docComment, fullSymbolName: fullSymbolName, kind: kind }) + '" to be in list [' + itemsString + ']');
}
private findFile(indexOrName: any) {
diff --git a/src/services/services.ts b/src/services/services.ts
index f677f215641..6d58b18ad38 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -2038,15 +2038,6 @@ module ts {
return (SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation);
}
- function isVisibleWithinClassDeclaration(symbol: Symbol, containingClass: Declaration): boolean {
- var declaration = symbol.declarations && symbol.declarations[0];
- if (declaration && (declaration.flags & NodeFlags.Private)) {
- var declarationClass = getAncestor(declaration, SyntaxKind.ClassDeclaration);
- return containingClass === declarationClass;
- }
- return true;
- }
-
function filterContextualMembersList(contextualMemberSymbols: Symbol[], existingMembers: Declaration[]): Symbol[] {
if (!existingMembers || existingMembers.length === 0) {
return contextualMemberSymbols;
@@ -2150,7 +2141,6 @@ module ts {
// Right of dot member completion list
if (isRightOfDot) {
var symbols: Symbol[] = [];
- var containingClass = getAncestor(mappedNode, SyntaxKind.ClassDeclaration);
isMemberCompletion = true;
if (mappedNode.kind === SyntaxKind.Identifier || mappedNode.kind === SyntaxKind.QualifiedName || mappedNode.kind === SyntaxKind.PropertyAccess) {
@@ -2158,7 +2148,7 @@ module ts {
if (symbol && symbol.flags & SymbolFlags.HasExports) {
// Extract module or enum members
forEachValue(symbol.exports, symbol => {
- if (isVisibleWithinClassDeclaration(symbol, containingClass)) {
+ if (typeInfoResolver.isValidPropertyAccess((mappedNode.parent), symbol.name)) {
symbols.push(symbol);
}
});
@@ -2170,7 +2160,7 @@ module ts {
if (apparentType) {
// Filter private properties
forEach(apparentType.getApparentProperties(), symbol => {
- if (isVisibleWithinClassDeclaration(symbol, containingClass)) {
+ if (typeInfoResolver.isValidPropertyAccess((mappedNode.parent), symbol.name)) {
symbols.push(symbol);
}
});
@@ -2645,6 +2635,11 @@ module ts {
return getReturnOccurrences(node.parent);
}
break;
+ case SyntaxKind.ThrowKeyword:
+ if (hasKind(node.parent, SyntaxKind.ThrowStatement)) {
+ return getThrowOccurrences(node.parent);
+ }
+ break;
case SyntaxKind.TryKeyword:
case SyntaxKind.CatchKeyword:
case SyntaxKind.FinallyKeyword:
@@ -2762,12 +2757,108 @@ module ts {
}
var keywords: Node[] = []
- forEachReturnStatement((func).body, returnStatement => {
+ forEachReturnStatement(func.body, returnStatement => {
pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword);
});
+ // Include 'throw' statements that do not occur within a try block.
+ forEach(aggregateOwnedThrowStatements(func.body), throwStatement => {
+ pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword);
+ });
+
return map(keywords, getReferenceEntryFromNode);
}
+
+ function getThrowOccurrences(throwStatement: ThrowStatement) {
+ var owner = getThrowStatementOwner(throwStatement);
+
+ if (!owner) {
+ return undefined;
+ }
+
+ var keywords: Node[] = [];
+
+ forEach(aggregateOwnedThrowStatements(owner), throwStatement => {
+ pushKeywordIf(keywords, throwStatement.getFirstToken(), SyntaxKind.ThrowKeyword);
+ });
+
+ // If the "owner" is a function, then we equate 'return' and 'throw' statements in their
+ // ability to "jump out" of the function, and include occurrences for both.
+ if (owner.kind === SyntaxKind.FunctionBlock) {
+ forEachReturnStatement(owner, returnStatement => {
+ pushKeywordIf(keywords, returnStatement.getFirstToken(), SyntaxKind.ReturnKeyword);
+ });
+ }
+
+ return map(keywords, getReferenceEntryFromNode);
+ }
+
+ /**
+ * Aggregates all throw-statements within this node *without* crossing
+ * into function boundaries and try-blocks with catch-clauses.
+ */
+ function aggregateOwnedThrowStatements(node: Node): ThrowStatement[] {
+ var statementAccumulator: ThrowStatement[] = []
+ aggregate(node);
+ return statementAccumulator;
+
+ function aggregate(node: Node): void {
+ if (node.kind === SyntaxKind.ThrowStatement) {
+ statementAccumulator.push(node);
+ }
+ else if (node.kind === SyntaxKind.TryStatement) {
+ var tryStatement = node;
+
+ if (tryStatement.catchBlock) {
+ aggregate(tryStatement.catchBlock);
+ }
+ else {
+ // Exceptions thrown within a try block lacking a catch clause
+ // are "owned" in the current context.
+ aggregate(tryStatement.tryBlock);
+ }
+
+ if (tryStatement.finallyBlock) {
+ aggregate(tryStatement.finallyBlock);
+ }
+ }
+ // Do not cross function boundaries.
+ else if (!isAnyFunction(node)) {
+ forEachChild(node, aggregate);
+ }
+ };
+ }
+
+ /**
+ * For lack of a better name, this function takes a throw statement and returns the
+ * nearest ancestor that is a try-block (whose try statement has a catch clause),
+ * function-block, or source file.
+ */
+ function getThrowStatementOwner(throwStatement: ThrowStatement): Node {
+ var child: Node = throwStatement;
+
+ while (child.parent) {
+ var parent = child.parent;
+
+ if (parent.kind === SyntaxKind.FunctionBlock || parent.kind === SyntaxKind.SourceFile) {
+ return parent;
+ }
+
+ // A throw-statement is only owned by a try-statement if the try-statement has
+ // a catch clause, and if the throw-statement occurs within the try block.
+ if (parent.kind === SyntaxKind.TryStatement) {
+ var tryStatement = parent;
+
+ if (tryStatement.tryBlock === child && tryStatement.catchBlock) {
+ return child;
+ }
+ }
+
+ child = parent;
+ }
+
+ return undefined;
+ }
function getTryCatchFinallyOccurrences(tryStatement: TryStatement): ReferenceEntry[] {
var keywords: Node[] = [];
diff --git a/tests/cases/fourslash/completionListInstanceProtectedMembers.ts b/tests/cases/fourslash/completionListInstanceProtectedMembers.ts
new file mode 100644
index 00000000000..de09f059680
--- /dev/null
+++ b/tests/cases/fourslash/completionListInstanceProtectedMembers.ts
@@ -0,0 +1,63 @@
+///
+
+////class Base {
+//// private privateMethod() { }
+//// private privateProperty;
+////
+//// protected protectedMethod() { }
+//// protected protectedProperty;
+////
+//// public publicMethod() { }
+//// public publicProperty;
+////
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////
+//// test() {
+//// this./*1*/;
+////
+//// var b: Base;
+//// var c: C1;
+////
+//// b./*2*/;
+//// c./*3*/;
+//// }
+////}
+////
+////class C1 extends Base {
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////}
+
+
+// Same class, everything is visible
+goTo.marker("1");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("2");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+// Can not access protected properties overridden in subclass
+goTo.marker("3");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionListInstanceProtectedMembers2.ts b/tests/cases/fourslash/completionListInstanceProtectedMembers2.ts
new file mode 100644
index 00000000000..72b6f3a1f7b
--- /dev/null
+++ b/tests/cases/fourslash/completionListInstanceProtectedMembers2.ts
@@ -0,0 +1,76 @@
+///
+
+////class Base {
+//// private privateMethod() { }
+//// private privateProperty;
+////
+//// protected protectedMethod() { }
+//// protected protectedProperty;
+////
+//// public publicMethod() { }
+//// public publicProperty;
+////
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////}
+////
+////class C1 extends Base {
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////
+//// test() {
+//// this./*1*/;
+//// super./*2*/;
+////
+//// var b: Base;
+//// var c: C1;
+////
+//// b./*3*/;
+//// c./*4*/;
+//// }
+////}
+
+
+// Same class, everything is visible
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+// Can not access properties on super
+goTo.marker("2");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.not.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
+
+// Can not access protected properties through base class
+goTo.marker("3");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
+
+// Same class, everything is visible
+goTo.marker("4");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
diff --git a/tests/cases/fourslash/completionListInstanceProtectedMembers3.ts b/tests/cases/fourslash/completionListInstanceProtectedMembers3.ts
new file mode 100644
index 00000000000..2b3bf2ac2d9
--- /dev/null
+++ b/tests/cases/fourslash/completionListInstanceProtectedMembers3.ts
@@ -0,0 +1,46 @@
+///
+
+////class Base {
+//// private privateMethod() { }
+//// private privateProperty;
+////
+//// protected protectedMethod() { }
+//// protected protectedProperty;
+////
+//// public publicMethod() { }
+//// public publicProperty;
+////
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////}
+////
+////class C1 extends Base {
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////}
+////
+//// var b: Base;
+//// var c: C1;
+//// b./*1*/;
+//// c./*2*/;
+
+// Only public properties are visible outside the class
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("2");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
diff --git a/tests/cases/fourslash/completionListInstanceProtectedMembers4.ts b/tests/cases/fourslash/completionListInstanceProtectedMembers4.ts
new file mode 100644
index 00000000000..27f9bb5a1cf
--- /dev/null
+++ b/tests/cases/fourslash/completionListInstanceProtectedMembers4.ts
@@ -0,0 +1,34 @@
+///
+
+////class Base {
+//// private privateMethod() { }
+//// private privateProperty;
+////
+//// protected protectedMethod() { }
+//// protected protectedProperty;
+////
+//// public publicMethod() { }
+//// public publicProperty;
+////
+//// protected protectedOverriddenMethod() { }
+//// protected protectedOverriddenProperty;
+////}
+////
+////class C1 extends Base {
+//// public protectedOverriddenMethod() { }
+//// public protectedOverriddenProperty;
+////}
+////
+//// var c: C1;
+//// c./*1*/
+
+
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
diff --git a/tests/cases/fourslash/completionListProtectedMembers.ts b/tests/cases/fourslash/completionListProtectedMembers.ts
new file mode 100644
index 00000000000..4715a9fb714
--- /dev/null
+++ b/tests/cases/fourslash/completionListProtectedMembers.ts
@@ -0,0 +1,44 @@
+///
+
+////class Base {
+//// protected y;
+//// constructor(protected x) {}
+//// method() { this./*1*/; }
+////}
+////class D1 extends Base {
+//// protected z;
+//// method1() { this./*2*/; }
+////}
+////class D2 extends Base {
+//// method2() { this./*3*/; }
+////}
+////class D3 extends D1 {
+//// method2() { this./*4*/; }
+////}
+////var b: Base;
+////f./*5*/
+
+goTo.marker("1");
+verify.memberListContains("y");
+verify.memberListContains("x");
+verify.not.memberListContains("z");
+
+goTo.marker("2");
+verify.memberListContains("y");
+verify.memberListContains("x");
+verify.memberListContains("z");
+
+goTo.marker("3");
+verify.memberListContains("y");
+verify.memberListContains("x");
+verify.not.memberListContains("z");
+
+goTo.marker("4");
+verify.memberListContains("y");
+verify.memberListContains("x");
+verify.memberListContains("z");
+
+goTo.marker("5");
+verify.not.memberListContains("x");
+verify.not.memberListContains("y");
+verify.not.memberListContains("z");
diff --git a/tests/cases/fourslash/completionListStaticProtectedMembers.ts b/tests/cases/fourslash/completionListStaticProtectedMembers.ts
new file mode 100644
index 00000000000..af56f28ef06
--- /dev/null
+++ b/tests/cases/fourslash/completionListStaticProtectedMembers.ts
@@ -0,0 +1,59 @@
+///
+
+////class Base {
+//// private static privateMethod() { }
+//// private static privateProperty;
+////
+//// protected static protectedMethod() { }
+//// protected static protectedProperty;
+////
+//// public static publicMethod() { }
+//// public static publicProperty;
+////
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////
+//// static test() {
+//// Base./*1*/;
+//// this./*2*/;
+//// C1./*3*/;
+//// }
+////}
+////
+////class C1 extends Base {
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////}
+
+
+// Same class, everything is visible
+goTo.marker("1");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("2");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+// Can not access protected properties overridden in subclass
+goTo.marker("3");
+verify.memberListContains('privateMethod');
+verify.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionListStaticProtectedMembers2.ts b/tests/cases/fourslash/completionListStaticProtectedMembers2.ts
new file mode 100644
index 00000000000..9964a91d21b
--- /dev/null
+++ b/tests/cases/fourslash/completionListStaticProtectedMembers2.ts
@@ -0,0 +1,70 @@
+///
+
+////class Base {
+//// private static privateMethod() { }
+//// private static privateProperty;
+////
+//// protected static protectedMethod() { }
+//// protected static protectedProperty;
+////
+//// public static publicMethod() { }
+//// public static publicProperty;
+////
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////}
+////
+////class C2 extends Base {
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////
+//// static test() {
+//// Base./*1*/;
+//// C2./*2*/;
+//// this./*3*/;
+//// super./*4*/;
+//// }
+////}
+
+
+// Same class, everything is visible
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("2");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("3");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+// only public and protected methods of the base class are accessible through super
+goTo.marker("4");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.not.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionListStaticProtectedMembers3.ts b/tests/cases/fourslash/completionListStaticProtectedMembers3.ts
new file mode 100644
index 00000000000..f80186c93c0
--- /dev/null
+++ b/tests/cases/fourslash/completionListStaticProtectedMembers3.ts
@@ -0,0 +1,45 @@
+///
+
+////class Base {
+//// private static privateMethod() { }
+//// private static privateProperty;
+////
+//// protected static protectedMethod() { }
+//// protected static protectedProperty;
+////
+//// public static publicMethod() { }
+//// public static publicProperty;
+////
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////}
+////
+////class C3 extends Base {
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////}
+////
+////Base./*1*/;
+////C3./*2*/;
+
+
+// Only public properties are visible outside the class
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
+
+goTo.marker("2");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.not.memberListContains('protectedOverriddenMethod');
+verify.not.memberListContains('protectedOverriddenProperty');
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionListStaticProtectedMembers4.ts b/tests/cases/fourslash/completionListStaticProtectedMembers4.ts
new file mode 100644
index 00000000000..72cc081f2fc
--- /dev/null
+++ b/tests/cases/fourslash/completionListStaticProtectedMembers4.ts
@@ -0,0 +1,49 @@
+///
+
+////class Base {
+//// private static privateMethod() { }
+//// private static privateProperty;
+////
+//// protected static protectedMethod() { }
+//// protected static protectedProperty;
+////
+//// public static publicMethod() { }
+//// public static publicProperty;
+////
+//// protected static protectedOverriddenMethod() { }
+//// protected static protectedOverriddenProperty;
+////}
+////
+/////// Make the protected members public
+////class C4 extends Base {
+//// public static protectedOverriddenMethod() { }
+//// public static protectedOverriddenProperty;
+////}
+////class Derived extends C4 {
+//// test() {
+//// Derived./*1*/
+//// }
+////}
+//// Derived./*2*/
+
+// Sub class, everything but private is visible
+goTo.marker("1");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.memberListContains('protectedMethod');
+verify.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
+
+// Can see protected methods elevated to public
+goTo.marker("2");
+verify.not.memberListContains('privateMethod');
+verify.not.memberListContains('privateProperty');
+verify.not.memberListContains('protectedMethod');
+verify.not.memberListContains('protectedProperty');
+verify.memberListContains('publicMethod');
+verify.memberListContains('publicProperty');
+verify.memberListContains('protectedOverriddenMethod');
+verify.memberListContains('protectedOverriddenProperty');
diff --git a/tests/cases/fourslash/completionListSuperMembers.ts b/tests/cases/fourslash/completionListSuperMembers.ts
index c203a8774fb..6c7ddd5c7b3 100644
--- a/tests/cases/fourslash/completionListSuperMembers.ts
+++ b/tests/cases/fourslash/completionListSuperMembers.ts
@@ -25,7 +25,7 @@
goTo.marker();
-verify.memberListContains("publicProperty");
+verify.not.memberListContains("publicProperty");
verify.memberListContains("publicInstanceMethod");
// No statics
verify.not.memberListContains("publicStaticProperty");
diff --git a/tests/cases/fourslash/getOccurrencesThrow.ts b/tests/cases/fourslash/getOccurrencesThrow.ts
new file mode 100644
index 00000000000..c25551db92e
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow.ts
@@ -0,0 +1,58 @@
+///
+
+////function f(a: number) {
+//// try {
+//// throw "Hello";
+////
+//// try {
+//// throw 10;
+//// }
+//// catch (x) {
+//// [|return|] 100;
+//// }
+//// finally {
+//// throw 10;
+//// }
+//// }
+//// catch (x) {
+//// [|throw|] "Something";
+//// }
+//// finally {
+//// [|throw|] "Also something";
+//// }
+//// if (a > 0) {
+//// [|return|] (function () {
+//// return;
+//// return;
+//// return;
+////
+//// if (false) {
+//// return true;
+//// }
+//// throw "Hello!";
+//// })() || true;
+//// }
+////
+//// [|th/**/row|] 10;
+////
+//// var unusued = [1, 2, 3, 4].map(x => { throw 4 })
+////
+//// [|return|];
+//// [|return|] true;
+//// [|throw|] false;
+////}
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
+goTo.marker();
+test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+});
diff --git a/tests/cases/fourslash/getOccurrencesThrow2.ts b/tests/cases/fourslash/getOccurrencesThrow2.ts
new file mode 100644
index 00000000000..99e18020396
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow2.ts
@@ -0,0 +1,58 @@
+///
+
+////function f(a: number) {
+//// try {
+//// throw "Hello";
+////
+//// try {
+//// [|t/**/hrow|] 10;
+//// }
+//// catch (x) {
+//// return 100;
+//// }
+//// finally {
+//// throw 10;
+//// }
+//// }
+//// catch (x) {
+//// throw "Something";
+//// }
+//// finally {
+//// throw "Also something";
+//// }
+//// if (a > 0) {
+//// return (function () {
+//// return;
+//// return;
+//// return;
+////
+//// if (false) {
+//// return true;
+//// }
+//// throw "Hello!";
+//// })() || true;
+//// }
+////
+//// throw 10;
+////
+//// var unusued = [1, 2, 3, 4].map(x => { throw 4 })
+////
+//// return;
+//// return true;
+//// throw false;
+////}
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
+goTo.marker();
+test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+});
diff --git a/tests/cases/fourslash/getOccurrencesThrow3.ts b/tests/cases/fourslash/getOccurrencesThrow3.ts
new file mode 100644
index 00000000000..313d04b8e38
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow3.ts
@@ -0,0 +1,58 @@
+///
+
+////function f(a: number) {
+//// try {
+//// [|throw|] "Hello";
+////
+//// try {
+//// throw 10;
+//// }
+//// catch (x) {
+//// return 100;
+//// }
+//// finally {
+//// [|thr/**/ow|] 10;
+//// }
+//// }
+//// catch (x) {
+//// throw "Something";
+//// }
+//// finally {
+//// throw "Also something";
+//// }
+//// if (a > 0) {
+//// return (function () {
+//// return;
+//// return;
+//// return;
+////
+//// if (false) {
+//// return true;
+//// }
+//// throw "Hello!";
+//// })() || true;
+//// }
+////
+//// throw 10;
+////
+//// var unusued = [1, 2, 3, 4].map(x => { throw 4 })
+////
+//// return;
+//// return true;
+//// throw false;
+////}
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
+goTo.marker();
+test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+});
diff --git a/tests/cases/fourslash/getOccurrencesThrow4.ts b/tests/cases/fourslash/getOccurrencesThrow4.ts
new file mode 100644
index 00000000000..adf321526af
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow4.ts
@@ -0,0 +1,58 @@
+///
+
+////function f(a: number) {
+//// try {
+//// throw "Hello";
+////
+//// try {
+//// throw 10;
+//// }
+//// catch (x) {
+//// return 100;
+//// }
+//// finally {
+//// throw 10;
+//// }
+//// }
+//// catch (x) {
+//// throw "Something";
+//// }
+//// finally {
+//// throw "Also something";
+//// }
+//// if (a > 0) {
+//// return (function () {
+//// [|return|];
+//// [|return|];
+//// [|return|];
+////
+//// if (false) {
+//// [|return|] true;
+//// }
+//// [|th/**/row|] "Hello!";
+//// })() || true;
+//// }
+////
+//// throw 10;
+////
+//// var unusued = [1, 2, 3, 4].map(x => { throw 4 })
+////
+//// return;
+//// return true;
+//// throw false;
+////}
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
+goTo.marker();
+test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+});
diff --git a/tests/cases/fourslash/getOccurrencesThrow5.ts b/tests/cases/fourslash/getOccurrencesThrow5.ts
new file mode 100644
index 00000000000..3e5ba4bca13
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow5.ts
@@ -0,0 +1,58 @@
+///
+
+////function f(a: number) {
+//// try {
+//// throw "Hello";
+////
+//// try {
+//// throw 10;
+//// }
+//// catch (x) {
+//// return 100;
+//// }
+//// finally {
+//// throw 10;
+//// }
+//// }
+//// catch (x) {
+//// throw "Something";
+//// }
+//// finally {
+//// throw "Also something";
+//// }
+//// if (a > 0) {
+//// return (function () {
+//// return;
+//// return;
+//// return;
+////
+//// if (false) {
+//// return true;
+//// }
+//// throw "Hello!";
+//// })() || true;
+//// }
+////
+//// throw 10;
+////
+//// var unusued = [1, 2, 3, 4].map(x => { [|thr/**/ow|] 4 })
+////
+//// return;
+//// return true;
+//// throw false;
+////}
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
+goTo.marker();
+test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+});
diff --git a/tests/cases/fourslash/getOccurrencesThrow6.ts b/tests/cases/fourslash/getOccurrencesThrow6.ts
new file mode 100644
index 00000000000..2769c9933db
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow6.ts
@@ -0,0 +1,28 @@
+///
+
+////[|throw|] 100;
+////
+////try {
+//// throw 0;
+//// var x = () => { throw 0; };
+////}
+////catch (y) {
+//// var x = () => { throw 0; };
+//// [|throw|] 200;
+////}
+////finally {
+//// [|throw|] 300;
+////}
+
+
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
diff --git a/tests/cases/fourslash/getOccurrencesThrow7.ts b/tests/cases/fourslash/getOccurrencesThrow7.ts
new file mode 100644
index 00000000000..46e899a891b
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow7.ts
@@ -0,0 +1,31 @@
+///
+
+////try {
+//// [|throw|] 10;
+////
+//// try {
+//// throw 10;
+//// }
+//// catch (x) {
+//// [|throw|] 10;
+//// }
+//// finally {
+//// [|throw|] 10;
+//// }
+////}
+////finally {
+//// [|throw|] 10;
+////}
+////
+////[|throw|] 10;
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+
diff --git a/tests/cases/fourslash/getOccurrencesThrow8.ts b/tests/cases/fourslash/getOccurrencesThrow8.ts
new file mode 100644
index 00000000000..679e13c8d5a
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesThrow8.ts
@@ -0,0 +1,31 @@
+///
+
+////try {
+//// throw 10;
+////
+//// try {
+//// [|throw|] 10;
+//// }
+//// catch (x) {
+//// throw 10;
+//// }
+//// finally {
+//// throw 10;
+//// }
+////}
+////finally {
+//// throw 10;
+////}
+////
+////throw 10;
+
+test.ranges().forEach(r => {
+ goTo.position(r.start);
+
+ test.ranges().forEach(range => {
+ verify.occurrencesAtPositionContains(range, false);
+ });
+
+ verify.occurrencesAtPositionCount(test.ranges().length);
+});
+