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..381ac186a4b 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..049f7e06fb3 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..5635c100a40 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)
@@ -575,10 +581,10 @@ For this switch statement, the compiler will generate the following code.
```TypeScript
switch (op) {
- case 0 /* Operator.ADD */ :
+ case 0 /* Operator.ADD */:
// execute add
break;
- case 1 /* Operator.DIV */ :
+ case 1 /* Operator.DIV */:
// execute div
break;
// ...
@@ -732,7 +738,7 @@ var M;
return s;
}
M.f = f;
-})(M||(M={}));
+})(M || (M = {}));
```
In this case, the compiler assumes that the module object resides in global variable ‘M’, which may or may not have been initialized to the desired module object.
@@ -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 [3.6.4](#3.6.4)) 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..834d85616f3 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -92,7 +92,9 @@ module ts {
getContextualType: getContextualType,
getFullyQualifiedName: getFullyQualifiedName,
getResolvedSignature: getResolvedSignature,
- getEnumMemberValue: getEnumMemberValue
+ getEnumMemberValue: getEnumMemberValue,
+ isValidPropertyAccess: isValidPropertyAccess,
+ getAliasedSymbol: resolveImport
};
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
@@ -4239,6 +4241,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);
@@ -4311,25 +4332,32 @@ module ts {
}
function signatureHasCorrectArity(node: CallExpression, signature: Signature): boolean {
- var args = node.arguments || emptyArray;
- var isCorrect = args.length >= signature.minArgumentCount &&
- (signature.hasRestParameter || args.length <= signature.parameters.length) &&
- (!node.typeArguments || signature.typeParameters && node.typeArguments.length === signature.typeParameters.length);
-
- // For error recovery, since we have parsed OmittedExpressions for any extra commas
- // in the argument list, if we see any OmittedExpressions, just return true.
- // The reason this is ok is because omitted expressions here are syntactically
- // illegal, and will cause a parse error.
- // Note: It may be worth keeping the upper bound check on arity, but removing
- // the lower bound check if there are omitted expressions.
- if (!isCorrect) {
- // Technically this type assertion is not safe because args could be initialized to emptyArray
- // above.
- if ((>args).hasTrailingComma || forEach(args, arg => arg.kind === SyntaxKind.OmittedExpression)) {
- return true;
- }
+ if (!node.arguments) {
+ // This only happens when we have something of the form:
+ // new C
+ //
+ return signature.minArgumentCount === 0;
}
- return isCorrect;
+
+ // For IDE scenarios, since we may have an incomplete call, we make two modifications
+ // to arity checking.
+ // 1. A trailing comma is tantamount to adding another argument
+ // 2. If the call is incomplete (no closing paren) allow fewer arguments than expected
+ var args = node.arguments;
+ var numberOfArgs = args.hasTrailingComma ? args.length + 1 : args.length;
+ var hasTooManyArguments = !signature.hasRestParameter && numberOfArgs > signature.parameters.length;
+ var hasRightNumberOfTypeArguments = !node.typeArguments ||
+ (signature.typeParameters && node.typeArguments.length === signature.typeParameters.length);
+
+ if (hasTooManyArguments || !hasRightNumberOfTypeArguments) {
+ return false;
+ }
+
+ // If we are missing the close paren, the call is incomplete, and we should skip
+ // the lower bound check.
+ var callIsIncomplete = args.end === node.end;
+ var hasEnoughArguments = numberOfArgs >= signature.minArgumentCount;
+ return callIsIncomplete || hasEnoughArguments;
}
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts
index ba6f742c4c1..e0b8099ef3c 100644
--- a/src/compiler/diagnosticInformationMap.generated.ts
+++ b/src/compiler/diagnosticInformationMap.generated.ts
@@ -5,6 +5,7 @@ module ts {
Unterminated_string_literal: { code: 1002, category: DiagnosticCategory.Error, key: "Unterminated string literal." },
Identifier_expected: { code: 1003, category: DiagnosticCategory.Error, key: "Identifier expected." },
_0_expected: { code: 1005, category: DiagnosticCategory.Error, key: "'{0}' expected." },
+ A_file_cannot_have_a_reference_to_itself: { code: 1006, category: DiagnosticCategory.Error, key: "A file cannot have a reference to itself." },
Trailing_comma_not_allowed: { code: 1009, category: DiagnosticCategory.Error, key: "Trailing comma not allowed." },
Asterisk_Slash_expected: { code: 1010, category: DiagnosticCategory.Error, key: "'*/' expected." },
Unexpected_token: { code: 1012, category: DiagnosticCategory.Error, key: "Unexpected token." },
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 0480cd3000c..1b89d2242c7 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -10,6 +10,10 @@
"'{0}' expected.": {
"category": "Error",
"code": 1005
+ },
+ "A file cannot have a reference to itself.": {
+ "category": "Error",
+ "code": 1006
},
"Trailing comma not allowed.": {
"category": "Error",
@@ -1355,6 +1359,7 @@
"category": "Error",
"code": 5001
},
+
"Cannot find the common subdirectory path for the input files.": {
"category": "Error",
"code": 5009
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index b06326f6925..6dd593c7fee 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1073,7 +1073,7 @@ module ts {
case ParsingContext.TypeParameters:
return isIdentifier();
case ParsingContext.ArgumentExpressions:
- return isExpression();
+ return token === SyntaxKind.CommaToken || isExpression();
case ParsingContext.ArrayLiteralMembers:
return token === SyntaxKind.CommaToken || isExpression();
case ParsingContext.Parameters:
@@ -1226,18 +1226,6 @@ module ts {
error(Diagnostics._0_expected, ",");
}
else if (isListTerminator(kind)) {
- // Check if the last token was a comma.
- if (commaStart >= 0) {
- if (!allowTrailingComma) {
- if (file.syntacticErrors.length === errorCountBeforeParsingList) {
- // Report a grammar error so we don't affect lookahead
- grammarErrorAtPos(commaStart, scanner.getStartPos() - commaStart, Diagnostics.Trailing_comma_not_allowed);
- }
- }
- // Always preserve a trailing comma by marking it on the NodeArray
- result.hasTrailingComma = true;
- }
-
break;
}
else {
@@ -1248,6 +1236,23 @@ module ts {
nextToken();
}
}
+
+ // Recording the trailing comma is deliberately done after the previous
+ // loop, and not just if we see a list terminator. This is because the list
+ // may have ended incorrectly, but it is still important to know if there
+ // was a trailing comma.
+ // Check if the last token was a comma.
+ if (commaStart >= 0) {
+ if (!allowTrailingComma) {
+ if (file.syntacticErrors.length === errorCountBeforeParsingList) {
+ // Report a grammar error so we don't affect lookahead
+ grammarErrorAtPos(commaStart, scanner.getStartPos() - commaStart, Diagnostics.Trailing_comma_not_allowed);
+ }
+ }
+ // Always preserve a trailing comma by marking it on the NodeArray
+ result.hasTrailingComma = true;
+ }
+
result.end = getNodeEnd();
parsingContext = saveParsingContext;
return result;
@@ -3826,15 +3831,17 @@ module ts {
}
else {
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
+ var start = range.pos;
+ var end = range.end;
+ var length = end - start;
+
if (!matchResult) {
- var start = range.pos;
- var length = range.end - start;
errorAtPos(start, length, Diagnostics.Invalid_reference_directive_syntax);
}
else {
referencedFiles.push({
- pos: range.pos,
- end: range.end,
+ pos: start,
+ end: end,
filename: matchResult[3]
});
}
@@ -3951,6 +3958,9 @@ module ts {
else if (!findSourceFile(filename, isDefaultLib, refFile, refPos, refEnd)) {
diagnostic = Diagnostics.File_0_not_found;
}
+ else if (refFile && host.getCanonicalFileName(filename) === host.getCanonicalFileName(refFile.filename)) {
+ diagnostic = Diagnostics.A_file_cannot_have_a_reference_to_itself;
+ }
}
else {
if (!(findSourceFile(filename + ".ts", isDefaultLib, refFile, refPos, refEnd) || findSourceFile(filename + ".d.ts", isDefaultLib, refFile, refPos, refEnd))) {
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index dcc42bf3358..da2cb9099c2 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -655,6 +655,9 @@ 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;
+ getAliasedSymbol(symbol: Symbol): Symbol;
}
export interface TextWriter {
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index a97319ff332..d33b5c0715d 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');
}
}
}
@@ -886,31 +891,38 @@ module FourSlash {
assert.equal(actual, expected);
}
+ public verifySignatureHelpArgumentCount(expected: number) {
+ this.taoInvalidReason = 'verifySignatureHelpArgumentCount NYI';
+ var signatureHelpItems = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
+ var actual = signatureHelpItems.argumentCount;
+ assert.equal(actual, expected);
+ }
+
public verifySignatureHelpPresent(shouldBePresent = true) {
this.taoInvalidReason = 'verifySignatureHelpPresent NYI';
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 +931,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,35 +945,22 @@ 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);
}
- //private getFormalParameter() {
- // var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
- // return help.formal;
- //}
-
private getActiveSignatureHelpItem() {
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
-
- // If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered),
- // 'activeFormal' will be -1 (even if there is only 1 signature). Signature help will show the
- // first signature in the signature group, so go with that
- var index = help.selectedItemIndex < 0 ? 0 : help.selectedItemIndex;
-
+ var index = help.selectedItemIndex;
return help.items[index];
}
private getActiveParameter(): ts.SignatureHelpParameter {
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
-
var item = help.items[help.selectedItemIndex];
-
- // Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed
- var currentParam = help.argumentIndex < 0 ? 0 : help.argumentIndex;
+ var currentParam = help.argumentIndex;
return item.parameters[currentParam];
}
@@ -1009,7 +1008,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 +1308,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 +1325,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 +1364,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 +1421,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 +1441,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 +1479,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 +1488,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 +1531,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 +1576,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 +1585,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 +1593,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 +1620,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 +1637,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 +1646,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 +1657,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 +1666,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 +1680,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 +1767,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 +1787,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 +1803,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 +1814,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 +1839,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 +1847,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 +1901,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 +1924,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 +2009,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 3e222450aa7..a35c1213956 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -256,7 +256,7 @@ module ts {
var declarations = this.getDeclarations();
if (declarations) {
for (var i = 0, n = declarations.length; i < n; i++) {
- this.processDocumentationCommentDeclaration(lines, declarations[0]);
+ this.processDocumentationCommentDeclaration(lines, declarations[i]);
}
}
@@ -274,7 +274,7 @@ module ts {
for (var i = 0, n = commentRanges.length; i < n; i++) {
this.processDocumentationCommentRange(
- lines, sourceFile, commentRanges[0]);
+ lines, sourceFile, commentRanges[i]);
}
}
}
@@ -1025,6 +1025,8 @@ module ts {
static primitiveType = "primitive type";
static label = "label";
+
+ static alias = "alias"
}
export class ScriptElementKindModifier {
@@ -2038,15 +2040,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;
@@ -2130,7 +2123,7 @@ module ts {
}
// TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node
- var mappedNode = getNodeAtPosition(sourceFile, TypeScript.end(node) - 1);
+ var mappedNode = getTouchingToken(sourceFile, TypeScript.end(node) - 1);
if (isPunctuation(mappedNode.kind)) {
mappedNode = mappedNode.parent;
}
@@ -2150,15 +2143,20 @@ 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) {
var symbol = typeInfoResolver.getSymbolInfo(mappedNode);
+
+ // This is an alias, follow what it aliases
+ if (symbol && symbol.flags & SymbolFlags.Import) {
+ symbol = typeInfoResolver.getAliasedSymbol(symbol);
+ }
+
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 +2168,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);
}
});
@@ -2205,7 +2203,7 @@ module ts {
else {
isMemberCompletion = false;
/// TODO filter meaning based on the current context
- var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace;
+ var symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Import;
var symbols = typeInfoResolver.getSymbolsInScope(mappedNode, symbolMeanings);
getCompletionEntriesFromSymbols(symbols, activeCompletionSession);
@@ -2303,6 +2301,7 @@ module ts {
if (flags & SymbolFlags.Constructor) return ScriptElementKind.constructorImplementationElement;
if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement;
+ if (flags & SymbolFlags.Import) return ScriptElementKind.alias;
return ScriptElementKind.unknown;
}
@@ -2368,7 +2367,7 @@ module ts {
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getSourceFile(fileName);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingPropertyName(sourceFile, position);
if (!node) {
return undefined;
}
@@ -2476,7 +2475,7 @@ module ts {
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getSourceFile(fileName);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
if (!node) {
return undefined;
}
@@ -2559,7 +2558,7 @@ module ts {
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingPropertyName(sourceFile, position);
if (!node) {
return undefined;
}
@@ -2623,7 +2622,7 @@ module ts {
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
if (!node) {
return undefined;
}
@@ -2645,6 +2644,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:
@@ -2685,6 +2689,11 @@ module ts {
return getConstructorOccurrences(node.parent);
}
break;
+ case SyntaxKind.GetKeyword:
+ case SyntaxKind.SetKeyword:
+ if (hasKind(node.parent, SyntaxKind.GetAccessor) || hasKind(node.parent, SyntaxKind.SetAccessor)) {
+ return getGetAndSetOccurrences(node.parent);
+ }
}
return undefined;
@@ -2762,12 +2771,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[] = [];
@@ -2919,6 +3024,23 @@ module ts {
return map(keywords, getReferenceEntryFromNode);
}
+ function getGetAndSetOccurrences(accessorDeclaration: AccessorDeclaration): ReferenceEntry[] {
+ var keywords: Node[] = [];
+
+ tryPushAccessorKeyword(accessorDeclaration.symbol, SyntaxKind.GetAccessor);
+ tryPushAccessorKeyword(accessorDeclaration.symbol, SyntaxKind.SetAccessor);
+
+ return map(keywords, getReferenceEntryFromNode);
+
+ function tryPushAccessorKeyword(accessorSymbol: Symbol, accessorKind: SyntaxKind): void {
+ var accessor = getDeclarationOfKind(accessorSymbol, accessorKind);
+
+ if (accessor) {
+ forEach(accessor.getChildren(), child => pushKeywordIf(keywords, child, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword));
+ }
+ }
+ }
+
// returns true if 'node' is defined and has a matching 'kind'.
function hasKind(node: Node, kind: SyntaxKind) {
return node !== undefined && node.kind === kind;
@@ -2945,7 +3067,7 @@ module ts {
filename = TypeScript.switchToForwardSlashes(filename);
var sourceFile = getSourceFile(filename);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingPropertyName(sourceFile, position);
if (!node) {
return undefined;
}
@@ -3128,7 +3250,7 @@ module ts {
forEach(possiblePositions, position => {
cancellationToken.throwIfCancellationRequested();
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
if (!node || node.getWidth() !== labelName.length) {
return;
}
@@ -3184,7 +3306,7 @@ module ts {
forEach(possiblePositions, position => {
cancellationToken.throwIfCancellationRequested();
- var referenceLocation = getNodeAtPosition(sourceFile, position);
+ var referenceLocation = getTouchingPropertyName(sourceFile, position);
if (!isValidReferencePosition(referenceLocation, searchText)) {
return;
}
@@ -3236,7 +3358,7 @@ module ts {
forEach(possiblePositions, position => {
cancellationToken.throwIfCancellationRequested();
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
return;
@@ -3302,7 +3424,7 @@ module ts {
forEach(possiblePositions, position => {
cancellationToken.throwIfCancellationRequested();
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
if (!node || node.kind !== SyntaxKind.ThisKeyword) {
return;
}
@@ -4116,7 +4238,7 @@ module ts {
var sourceFile = getCurrentSourceFile(filename);
var result: TypeScript.TextSpan[] = [];
- var token = getTokenAtPosition(sourceFile, position);
+ var token = getTouchingToken(sourceFile, position);
if (token.getStart(sourceFile) === position) {
var matchKind = getMatchingTokenKind(token);
@@ -4400,7 +4522,7 @@ module ts {
fileName = TypeScript.switchToForwardSlashes(fileName);
var sourceFile = getSourceFile(fileName);
- var node = getNodeAtPosition(sourceFile, position);
+ var node = getTouchingWord(sourceFile, position);
// Can only rename an identifier.
if (node && node.kind === SyntaxKind.Identifier) {
@@ -4486,26 +4608,58 @@ module ts {
/// If we consider every slash token to be a regex, we could be missing cases like "1/2/3", where
/// we have a series of divide operator. this list allows us to be more accurate by ruling out
/// locations where a regexp cannot exist.
- var noRegexTable: boolean[];
- if (!noRegexTable) {
- noRegexTable = [];
- noRegexTable[SyntaxKind.Identifier] = true;
- noRegexTable[SyntaxKind.StringLiteral] = true;
- noRegexTable[SyntaxKind.NumericLiteral] = true;
- noRegexTable[SyntaxKind.RegularExpressionLiteral] = true;
- noRegexTable[SyntaxKind.ThisKeyword] = true;
- noRegexTable[SyntaxKind.PlusPlusToken] = true;
- noRegexTable[SyntaxKind.MinusMinusToken] = true;
- noRegexTable[SyntaxKind.CloseParenToken] = true;
- noRegexTable[SyntaxKind.CloseBracketToken] = true;
- noRegexTable[SyntaxKind.CloseBraceToken] = true;
- noRegexTable[SyntaxKind.TrueKeyword] = true;
- noRegexTable[SyntaxKind.FalseKeyword] = true;
+ var noRegexTable: boolean[] = [];
+ noRegexTable[SyntaxKind.Identifier] = true;
+ noRegexTable[SyntaxKind.StringLiteral] = true;
+ noRegexTable[SyntaxKind.NumericLiteral] = true;
+ noRegexTable[SyntaxKind.RegularExpressionLiteral] = true;
+ noRegexTable[SyntaxKind.ThisKeyword] = true;
+ noRegexTable[SyntaxKind.PlusPlusToken] = true;
+ noRegexTable[SyntaxKind.MinusMinusToken] = true;
+ noRegexTable[SyntaxKind.CloseParenToken] = true;
+ noRegexTable[SyntaxKind.CloseBracketToken] = true;
+ noRegexTable[SyntaxKind.CloseBraceToken] = true;
+ noRegexTable[SyntaxKind.TrueKeyword] = true;
+ noRegexTable[SyntaxKind.FalseKeyword] = true;
+
+ function isAccessibilityModifier(kind: SyntaxKind) {
+ switch (kind) {
+ case SyntaxKind.PublicKeyword:
+ case SyntaxKind.PrivateKeyword:
+ case SyntaxKind.ProtectedKeyword:
+ return true;
+ }
+
+ return false;
+ }
+
+ /** Returns true if 'keyword2' can legally follow 'keyword1' in any language construct. */
+ function canFollow(keyword1: SyntaxKind, keyword2: SyntaxKind) {
+ if (isAccessibilityModifier(keyword1)) {
+ if (keyword2 === SyntaxKind.GetKeyword ||
+ keyword2 === SyntaxKind.SetKeyword ||
+ keyword2 === SyntaxKind.ConstructorKeyword ||
+ keyword2 === SyntaxKind.StaticKeyword) {
+
+ // Allow things like "public get", "public constructor" and "public static".
+ // These are all legal.
+ return true;
+ }
+
+ // Any other keyword following "public" is actually an identifier an not a real
+ // keyword.
+ return false;
+ }
+
+ // Assume any other keyword combination is legal. This can be refined in the future
+ // if there are more cases we want the classifier to be better at.
+ return true;
}
function getClassificationsForLine(text: string, lexState: EndOfLineState): ClassificationResult {
var offset = 0;
var lastTokenOrCommentEnd = 0;
+ var token = SyntaxKind.Unknown;
var lastNonTriviaToken = SyntaxKind.Unknown;
// If we're in a string literal, then prepend: "\
@@ -4535,8 +4689,6 @@ module ts {
entries: []
};
-
- var token = SyntaxKind.Unknown;
do {
token = scanner.scan();
@@ -4549,6 +4701,13 @@ module ts {
else if (lastNonTriviaToken === SyntaxKind.DotToken && isKeyword(token)) {
token = SyntaxKind.Identifier;
}
+ else if (isKeyword(lastNonTriviaToken) && isKeyword(token) && !canFollow(lastNonTriviaToken, token)) {
+ // We have two keywords in a row. Only treat the second as a keyword if
+ // it's a sequence that could legally occur in the language. Otherwise
+ // treat it as an identifier. This way, if someone writes "private var"
+ // we recognize that 'var' is actually an identifier here.
+ token = SyntaxKind.Identifier;
+ }
lastNonTriviaToken = token;
}
diff --git a/src/services/signatureHelp.ts b/src/services/signatureHelp.ts
index 796472c030e..080e4704b83 100644
--- a/src/services/signatureHelp.ts
+++ b/src/services/signatureHelp.ts
@@ -172,15 +172,15 @@ module ts.SignatureHelp {
return undefined;
}
- var argumentList = getContainingArgumentList(startingToken);
+ var argumentInfo = getContainingArgumentInfo(startingToken);
cancellationToken.throwIfCancellationRequested();
// Semantic filtering of signature help
- if (!argumentList) {
+ if (!argumentInfo) {
return undefined;
}
- var call = argumentList.parent;
+ var call = argumentInfo.list.parent;
var candidates = [];
var resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates);
cancellationToken.throwIfCancellationRequested();
@@ -189,13 +189,13 @@ module ts.SignatureHelp {
return undefined;
}
- return createSignatureHelpItems(candidates, resolvedSignature, argumentList);
+ return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo);
/**
* If node is an argument, returns its index in the argument list.
* If not, returns -1.
*/
- function getImmediatelyContainingArgumentList(node: Node): Node {
+ function getImmediatelyContainingArgumentInfo(node: Node): ListItemInfo {
if (node.parent.kind !== SyntaxKind.CallExpression && node.parent.kind !== SyntaxKind.NewExpression) {
return undefined;
}
@@ -216,10 +216,14 @@ module ts.SignatureHelp {
var parent = node.parent;
// Find out if 'node' is an argument, a type argument, or neither
if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
- // Find the list that starts right *after* the < or ( token
+ // Find the list that starts right *after* the < or ( token.
+ // If the user has just opened a list, consider this item 0.
var list = getChildListThatStartsWithOpenerToken(parent, node, sourceFile);
Debug.assert(list);
- return list;
+ return {
+ list: list,
+ listItemIndex: 0
+ };
}
if (node.kind === SyntaxKind.GreaterThanToken
@@ -228,18 +232,18 @@ module ts.SignatureHelp {
return undefined;
}
- return findContainingList(node);
+ return findListItemInfo(node);
}
- function getContainingArgumentList(node: Node): Node {
+ function getContainingArgumentInfo(node: Node): ListItemInfo {
for (var n = node; n.kind !== SyntaxKind.SourceFile; n = n.parent) {
if (n.kind === SyntaxKind.FunctionBlock) {
return undefined;
}
- var argumentList = getImmediatelyContainingArgumentList(n);
- if (argumentList) {
- return argumentList;
+ var argumentInfo = getImmediatelyContainingArgumentInfo(n);
+ if (argumentInfo) {
+ return argumentInfo;
}
@@ -248,7 +252,35 @@ module ts.SignatureHelp {
return undefined;
}
- function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentListOrTypeArgumentList: Node): SignatureHelpItems {
+ /**
+ * The selectedItemIndex could be negative for several reasons.
+ * 1. There are too many arguments for all of the overloads
+ * 2. None of the overloads were type compatible
+ * The solution here is to try to pick the best overload by picking
+ * either the first one that has an appropriate number of parameters,
+ * or the one with the most parameters.
+ */
+ function selectBestInvalidOverloadIndex(candidates: Signature[], argumentCount: number): number {
+ var maxParamsSignatureIndex = -1;
+ var maxParams = -1;
+ for (var i = 0; i < candidates.length; i++) {
+ var candidate = candidates[i];
+
+ if (candidate.hasRestParameter || candidate.parameters.length >= argumentCount) {
+ return i;
+ }
+
+ if (candidate.parameters.length > maxParams) {
+ maxParams = candidate.parameters.length;
+ maxParamsSignatureIndex = i;
+ }
+ }
+
+ return maxParamsSignatureIndex;
+ }
+
+ function createSignatureHelpItems(candidates: Signature[], bestSignature: Signature, argumentInfoOrTypeArgumentInfo: ListItemInfo): SignatureHelpItems {
+ var argumentListOrTypeArgumentList = argumentInfoOrTypeArgumentInfo.list;
var items: SignatureHelpItem[] = map(candidates, candidateSignature => {
var parameters = candidateSignature.parameters;
var parameterHelpItems: SignatureHelpParameter[] = parameters.length === 0 ? emptyArray : map(parameters, p => {
@@ -321,11 +353,6 @@ module ts.SignatureHelp {
};
});
- var selectedItemIndex = candidates.indexOf(bestSignature);
- if (selectedItemIndex < 0) {
- selectedItemIndex = 0;
- }
-
// We use full start and skip trivia on the end because we want to include trivia on
// both sides. For example,
//
@@ -338,63 +365,38 @@ module ts.SignatureHelp {
var applicableSpanEnd = skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false);
var applicableSpan = new TypeScript.TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
- var state = getSignatureHelpCurrentArgumentState(sourceFile, position, applicableSpanStart);
+ // The listItemIndex we got back includes commas. Our goal is to return the index of the proper
+ // item (not including commas). Here are some examples:
+ // 1. foo(a, b, c $) -> the listItemIndex is 4, we want to return 2
+ // 2. foo(a, b, $ c) -> listItemIndex is 3, we want to return 2
+ // 3. foo($a) -> listItemIndex is 0, we want to return 0
+ //
+ // In general, we want to subtract the number of commas before the current index.
+ // But if we are on a comma, we also want to pretend we are on the argument *following*
+ // the comma. That amounts to taking the ceiling of half the index.
+ var argumentIndex = (argumentInfoOrTypeArgumentInfo.listItemIndex + 1) >> 1;
+
+ // argumentCount is the number of commas plus one, unless the list is completely empty,
+ // in which case there are 0.
+ var argumentCount = argumentListOrTypeArgumentList.getChildCount() === 0
+ ? 0
+ : 1 + countWhere(argumentListOrTypeArgumentList.getChildren(), arg => arg.kind === SyntaxKind.CommaToken);
+
+ var selectedItemIndex = candidates.indexOf(bestSignature);
+ if (selectedItemIndex < 0) {
+ selectedItemIndex = selectBestInvalidOverloadIndex(candidates, argumentCount);
+ }
+
return {
items: items,
applicableSpan: applicableSpan,
selectedItemIndex: selectedItemIndex,
- argumentIndex: state.argumentIndex,
- argumentCount: state.argumentCount
+ argumentIndex: argumentIndex,
+ argumentCount: argumentCount
};
}
}
- function getSignatureHelpCurrentArgumentState(sourceFile: SourceFile, position: number, applicableSpanStart: number): { argumentIndex: number; argumentCount: number } {
- var tokenPrecedingSpanStart = findPrecedingToken(applicableSpanStart, sourceFile);
- if (!tokenPrecedingSpanStart) {
- return undefined;
- }
-
- if (tokenPrecedingSpanStart.kind !== SyntaxKind.OpenParenToken && tokenPrecedingSpanStart.kind !== SyntaxKind.LessThanToken) {
- // The span start must have moved backward in the file (for example if the open paren was backspaced)
- return undefined;
- }
-
- var tokenPrecedingCurrentPosition = findPrecedingToken(position, sourceFile);
- var call = tokenPrecedingSpanStart.parent;
- Debug.assert(call.kind === SyntaxKind.CallExpression || call.kind === SyntaxKind.NewExpression, "wrong call kind " + SyntaxKind[call.kind]);
- if (tokenPrecedingCurrentPosition.kind === SyntaxKind.CloseParenToken || tokenPrecedingCurrentPosition.kind === SyntaxKind.GreaterThanToken) {
- if (tokenPrecedingCurrentPosition.parent === call) {
- // This call expression is complete. Stop signature help.
- return undefined;
- }
- }
-
- var argumentListOrTypeArgumentList = getChildListThatStartsWithOpenerToken(call, tokenPrecedingSpanStart, sourceFile);
- // Debug.assert(argumentListOrTypeArgumentList.getChildCount() === 0 || argumentListOrTypeArgumentList.getChildCount() % 2 === 1, "Even number of children");
-
- // The call might be finished, but incorrectly. Check if we are still within the bounds of the call
- if (position > skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false)) {
- return undefined;
- }
-
- var numberOfCommas = countWhere(argumentListOrTypeArgumentList.getChildren(), arg => arg.kind === SyntaxKind.CommaToken);
- var argumentCount = numberOfCommas + 1;
- if (argumentCount <= 1) {
- return { argumentIndex: 0, argumentCount: argumentCount };
- }
-
- var indexOfNodeContainingPosition = findListItemIndexContainingPosition(argumentListOrTypeArgumentList, position);
-
- // indexOfNodeContainingPosition checks that position is between pos and end of each child, so it is
- // possible that we are to the right of all children. Assume that we are still within
- // the applicable span and that we are typing the last argument
- // Alternatively, we could be in range of one of the arguments, in which case we need to divide
- // by 2 to exclude commas. Use bit shifting in order to take the floor of the division.
- var argumentIndex = indexOfNodeContainingPosition < 0 ? argumentCount - 1 : indexOfNodeContainingPosition >> 1;
- return { argumentIndex: argumentIndex, argumentCount: argumentCount };
- }
-
function getChildListThatStartsWithOpenerToken(parent: Node, openerToken: Node, sourceFile: SourceFile): Node {
var children = parent.getChildren(sourceFile);
var indexOfOpenerToken = children.indexOf(openerToken);
diff --git a/src/services/utilities.ts b/src/services/utilities.ts
index 9e68ef1a7aa..caa324fcc7b 100644
--- a/src/services/utilities.ts
+++ b/src/services/utilities.ts
@@ -50,34 +50,54 @@ module ts {
return -1;
}
- /** Get a token that contains the position. This is guaranteed to return a token, the position can be in the
- * leading trivia or within the token text.
- */
- export function getTokenAtPosition(sourceFile: SourceFile, position: number) {
- var current: Node = sourceFile;
- outer: while (true) {
- // find the child that has this
- for (var i = 0, n = current.getChildCount(); i < n; i++) {
- var child = current.getChildAt(i);
- if (child.getFullStart() <= position && position < child.getEnd()) {
- current = child;
- continue outer;
- }
- }
- return current;
- }
+ /* Gets the token whose text has range [start, end) and
+ * position >= start and (position < end or (position === end && token is keyword or identifier))
+ */
+ export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
+ return getTouchingToken(sourceFile, position, isWord);
}
- /** Get the token whose text contains the position, or the containing node. */
- export function getNodeAtPosition(sourceFile: SourceFile, position: number) {
+ /* Gets the token whose text has range [start, end) and position >= start
+ * and (position < end or (position === end && token is keyword or identifier or numeric\string litera))
+ */
+ export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
+ return getTouchingToken(sourceFile, position, isPropertyName);
+ }
+
+ /** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
+ export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean): Node {
+ return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition);
+ }
+
+ /** Returns a token if position is in [start-of-leading-trivia, end) */
+ export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node {
+ return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined);
+ }
+
+ /** Get the token whose text contains the position */
+ function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean): Node {
var current: Node = sourceFile;
outer: while (true) {
- // find the child that has this
- for (var i = 0, n = current.getChildCount(); i < n; i++) {
+ if (isToken(current)) {
+ // exit early
+ return current;
+ }
+
+ // find the child that contains 'position'
+ for (var i = 0, n = current.getChildCount(sourceFile); i < n; i++) {
var child = current.getChildAt(i);
- if (child.getStart() <= position && position < child.getEnd()) {
- current = child;
- continue outer;
+ var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile);
+ if (start <= position) {
+ if (position < child.getEnd()) {
+ current = child;
+ continue outer;
+ }
+ else if (includeItemAtEndPosition && child.getEnd() === position) {
+ var previousToken = findPrecedingToken(position, sourceFile, child);
+ if (previousToken && includeItemAtEndPosition(previousToken)) {
+ return previousToken;
+ }
+ }
}
}
return current;
@@ -130,8 +150,8 @@ module ts {
}
}
- export function findPrecedingToken(position: number, sourceFile: SourceFile): Node {
- return find(sourceFile);
+ export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node): Node {
+ return find(startNode || sourceFile);
function findRightmostToken(n: Node): Node {
if (isToken(n)) {
@@ -167,7 +187,7 @@ module ts {
}
}
- Debug.assert(n.kind === SyntaxKind.SourceFile);
+ Debug.assert(startNode || n.kind === SyntaxKind.SourceFile);
// Here we know that none of child token nodes embrace the position,
// the only known case is when position is at the end of the file.
@@ -205,4 +225,16 @@ module ts {
function isToken(n: Node): boolean {
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
}
+
+ function isKeyword(n: Node): boolean {
+ return n.kind >= SyntaxKind.FirstKeyword && n.kind <= SyntaxKind.LastKeyword;
+ }
+
+ function isWord(n: Node): boolean {
+ return n.kind === SyntaxKind.Identifier || isKeyword(n);
+ }
+
+ function isPropertyName(n: Node): boolean {
+ return n.kind === SyntaxKind.StringLiteral || n.kind === SyntaxKind.NumericLiteral || isWord(n);
+ }
}
\ No newline at end of file
diff --git a/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/amd/visibilityOfTypeUsedAcrossModules2.errors.txt b/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/amd/visibilityOfTypeUsedAcrossModules2.errors.txt
index 9bdeb723415..d5c992fff66 100644
--- a/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/amd/visibilityOfTypeUsedAcrossModules2.errors.txt
+++ b/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/amd/visibilityOfTypeUsedAcrossModules2.errors.txt
@@ -1,9 +1,12 @@
+main.ts(1,1): error TS1006: A file cannot have a reference to itself.
main.ts(2,1): error TS6053: File 'nonExistingFile1.ts' not found.
main.ts(3,1): error TS6053: File 'nonExistingFile2.ts' not found.
-==== main.ts (2 errors) ====
+==== main.ts (3 errors) ====
///
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1006: A file cannot have a reference to itself.
///
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS6053: File 'nonExistingFile1.ts' not found.
diff --git a/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/node/visibilityOfTypeUsedAcrossModules2.errors.txt b/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/node/visibilityOfTypeUsedAcrossModules2.errors.txt
index 9bdeb723415..d5c992fff66 100644
--- a/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/node/visibilityOfTypeUsedAcrossModules2.errors.txt
+++ b/tests/baselines/reference/project/visibilityOfTypeUsedAcrossModules2/node/visibilityOfTypeUsedAcrossModules2.errors.txt
@@ -1,9 +1,12 @@
+main.ts(1,1): error TS1006: A file cannot have a reference to itself.
main.ts(2,1): error TS6053: File 'nonExistingFile1.ts' not found.
main.ts(3,1): error TS6053: File 'nonExistingFile2.ts' not found.
-==== main.ts (2 errors) ====
+==== main.ts (3 errors) ====
///
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1006: A file cannot have a reference to itself.
///
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS6053: File 'nonExistingFile1.ts' not found.
diff --git a/tests/baselines/reference/selfReferencingFile.errors.txt b/tests/baselines/reference/selfReferencingFile.errors.txt
new file mode 100644
index 00000000000..727be1ea0b2
--- /dev/null
+++ b/tests/baselines/reference/selfReferencingFile.errors.txt
@@ -0,0 +1,11 @@
+tests/cases/compiler/selfReferencingFile.ts(1,1): error TS1006: A file cannot have a reference to itself.
+
+
+==== tests/cases/compiler/selfReferencingFile.ts (1 errors) ====
+ ///
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1006: A file cannot have a reference to itself.
+
+ class selfReferencingFile {
+
+ }
\ No newline at end of file
diff --git a/tests/baselines/reference/selfReferencingFile2.errors.txt b/tests/baselines/reference/selfReferencingFile2.errors.txt
new file mode 100644
index 00000000000..5bd2d75723a
--- /dev/null
+++ b/tests/baselines/reference/selfReferencingFile2.errors.txt
@@ -0,0 +1,11 @@
+tests/cases/compiler/selfReferencingFile2.ts(1,1): error TS6053: File 'tests/cases/selfReferencingFile2.ts' not found.
+
+
+==== tests/cases/compiler/selfReferencingFile2.ts (1 errors) ====
+ ///
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS6053: File 'selfReferencingFile2.ts' not found.
+
+ class selfReferencingFile2 {
+
+ }
\ No newline at end of file
diff --git a/tests/baselines/reference/selfReferencingFile3.errors.txt b/tests/baselines/reference/selfReferencingFile3.errors.txt
new file mode 100644
index 00000000000..e6e8deb5d47
--- /dev/null
+++ b/tests/baselines/reference/selfReferencingFile3.errors.txt
@@ -0,0 +1,11 @@
+tests/cases/compiler/selfReferencingFile3.ts(1,1): error TS1006: A file cannot have a reference to itself.
+
+
+==== tests/cases/compiler/selfReferencingFile3.ts (1 errors) ====
+ ///
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+!!! error TS1006: A file cannot have a reference to itself.
+
+ class selfReferencingFile3 {
+
+ }
\ No newline at end of file
diff --git a/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt b/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt
index 3edeb834baa..986f2dedf6e 100644
--- a/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt
+++ b/tests/baselines/reference/trailingSeparatorInFunctionCall.errors.txt
@@ -1,18 +1,24 @@
tests/cases/compiler/trailingSeparatorInFunctionCall.ts(4,7): error TS1009: Trailing comma not allowed.
tests/cases/compiler/trailingSeparatorInFunctionCall.ts(9,8): error TS1009: Trailing comma not allowed.
+tests/cases/compiler/trailingSeparatorInFunctionCall.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
+tests/cases/compiler/trailingSeparatorInFunctionCall.ts(9,1): error TS2346: Supplied parameters do not match any signature of call target.
-==== tests/cases/compiler/trailingSeparatorInFunctionCall.ts (2 errors) ====
+==== tests/cases/compiler/trailingSeparatorInFunctionCall.ts (4 errors) ====
function f(x, y) {
}
f(1, 2, );
~
!!! error TS1009: Trailing comma not allowed.
+ ~~~~~~~~~
+!!! error TS2346: Supplied parameters do not match any signature of call target.
function f2(x: T, y: T) {
}
f2(1, 2, );
~
-!!! error TS1009: Trailing comma not allowed.
\ No newline at end of file
+!!! error TS1009: Trailing comma not allowed.
+ ~~~~~~~~~~
+!!! error TS2346: Supplied parameters do not match any signature of call target.
\ No newline at end of file
diff --git a/tests/cases/compiler/selfReferencingFile.ts b/tests/cases/compiler/selfReferencingFile.ts
new file mode 100644
index 00000000000..cac46da2369
--- /dev/null
+++ b/tests/cases/compiler/selfReferencingFile.ts
@@ -0,0 +1,5 @@
+///
+
+class selfReferencingFile {
+
+}
\ No newline at end of file
diff --git a/tests/cases/compiler/selfReferencingFile2.ts b/tests/cases/compiler/selfReferencingFile2.ts
new file mode 100644
index 00000000000..c98e7a07735
--- /dev/null
+++ b/tests/cases/compiler/selfReferencingFile2.ts
@@ -0,0 +1,5 @@
+///
+
+class selfReferencingFile2 {
+
+}
\ No newline at end of file
diff --git a/tests/cases/compiler/selfReferencingFile3.ts b/tests/cases/compiler/selfReferencingFile3.ts
new file mode 100644
index 00000000000..4242d0b3633
--- /dev/null
+++ b/tests/cases/compiler/selfReferencingFile3.ts
@@ -0,0 +1,5 @@
+///
+
+class selfReferencingFile3 {
+
+}
\ No newline at end of file
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/completionListOnAliases.ts b/tests/cases/fourslash/completionListOnAliases.ts
new file mode 100644
index 00000000000..785a65a76bd
--- /dev/null
+++ b/tests/cases/fourslash/completionListOnAliases.ts
@@ -0,0 +1,15 @@
+///
+
+////module M {
+//// export var value;
+////
+//// import x = M;
+//// /*1*/
+//// x./*2*/
+////}
+
+goTo.marker("1");
+verify.memberListContains("x", undefined, undefined, undefined ,/*kind: */ "alias");
+
+goTo.marker("2");
+verify.memberListContains("value");
diff --git a/tests/cases/fourslash/completionListOnAliases2.ts b/tests/cases/fourslash/completionListOnAliases2.ts
new file mode 100644
index 00000000000..6a74f3a525b
--- /dev/null
+++ b/tests/cases/fourslash/completionListOnAliases2.ts
@@ -0,0 +1,74 @@
+///
+
+////module M {
+//// export interface I { }
+//// export class C {
+//// static property;
+//// }
+//// export enum E {
+//// value = 0
+//// }
+//// export module N {
+//// export var v;
+//// }
+//// export var V = 0;
+//// export function F() { }
+//// export import A = M;
+////}
+////
+////import m = M;
+////import c = M.C;
+////import e = M.E;
+////import n = M.N;
+////import v = M.V;
+////import f = M.F;
+////import a = M.A;
+////
+////m./*1*/;
+////c./*2*/;
+////e./*3*/;
+////n./*4*/;
+////v./*5*/;
+////f./*6*/;
+////a./*7*/;
+
+
+// Module m
+goTo.marker("1");
+verify.memberListContains("I");
+verify.memberListContains("C");
+verify.memberListContains("E");
+verify.memberListContains("N");
+verify.memberListContains("V");
+verify.memberListContains("F");
+verify.memberListContains("A");
+
+// Class C
+goTo.marker("2");
+verify.memberListContains("property");
+
+// Enum E
+goTo.marker("3");
+verify.memberListContains("value");
+
+// Module N
+goTo.marker("4");
+verify.memberListContains("v");
+
+// var V
+goTo.marker("5");
+verify.memberListContains("toFixed");
+
+// function F
+goTo.marker("6");
+verify.memberListContains("call");
+
+// alias a
+goTo.marker("7");
+verify.memberListContains("I");
+verify.memberListContains("C");
+verify.memberListContains("E");
+verify.memberListContains("N");
+verify.memberListContains("V");
+verify.memberListContains("F");
+verify.memberListContains("A");
diff --git a/tests/cases/fourslash/completionListOnAliases3.ts b/tests/cases/fourslash/completionListOnAliases3.ts
new file mode 100644
index 00000000000..8c5194af968
--- /dev/null
+++ b/tests/cases/fourslash/completionListOnAliases3.ts
@@ -0,0 +1,13 @@
+///
+
+////declare module 'foobar' {
+//// interface Q { x: number; }
+////}
+////declare module 'thing' {
+//// import x = require('foobar');
+//// var m: x./*1*/;
+////}
+
+// Q does not show up in member list of x
+goTo.marker("1");
+verify.memberListContains("Q");
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/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index 35b6894b1ce..c204a98c4a4 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -294,6 +294,10 @@ module FourSlashInterface {
FourSlash.currentTestState.verifySignatureHelpCount(expected);
}
+ public signatureHelpArgumentCountIs(expected: number) {
+ FourSlash.currentTestState.verifySignatureHelpArgumentCount(expected);
+ }
+
public currentSignatureParamterCountIs(expected: number) {
FourSlash.currentTestState.verifyCurrentSignatureHelpParameterCount(expected);
}
diff --git a/tests/cases/fourslash/getOccurrencesIfElse5.ts b/tests/cases/fourslash/getOccurrencesIfElse5.ts
new file mode 100644
index 00000000000..b0519630b7b
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesIfElse5.ts
@@ -0,0 +1,42 @@
+///
+
+////if/*1*/ (true) {
+//// if/*2*/ (false) {
+//// }
+//// else/*3*/ {
+//// }
+//// if/*4*/ (true) {
+//// }
+//// else/*5*/ {
+//// if/*6*/ (false)
+//// if/*7*/ (true)
+//// var x = undefined;
+//// }
+////}
+////else/*8*/ if (null) {
+////}
+////else/*9*/ /* whar garbl */ if/*10*/ (undefined) {
+////}
+////else/*11*/
+////if/*12*/ (false) {
+////}
+////else/*13*/ { }
+
+function verifyOccurencesAtMarker(marker: string, count: number) {
+ goTo.marker(marker);
+ verify.occurrencesAtPositionCount(count);
+}
+
+verifyOccurencesAtMarker("1", 7);
+verifyOccurencesAtMarker("2", 2);
+verifyOccurencesAtMarker("3", 2);
+verifyOccurencesAtMarker("4", 2);
+verifyOccurencesAtMarker("5", 2);
+verifyOccurencesAtMarker("6", 1);
+verifyOccurencesAtMarker("7", 1);
+verifyOccurencesAtMarker("8", 7);
+verifyOccurencesAtMarker("9", 7);
+verifyOccurencesAtMarker("10", 7);
+verifyOccurencesAtMarker("11", 7);
+verifyOccurencesAtMarker("12", 7);
+verifyOccurencesAtMarker("13", 7);
diff --git a/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts b/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts
deleted file mode 100644
index 601eba63c64..00000000000
--- a/tests/cases/fourslash/getOccurrencesIfElseNegatives.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-///
-
-////if/*1*/ (true) {
-//// if/*2*/ (false) {
-//// }
-//// else/*3*/ {
-//// }
-//// if/*4*/ (true) {
-//// }
-//// else/*5*/ {
-//// if/*6*/ (false)
-//// if/*7*/ (true)
-//// var x = undefined;
-//// }
-////}
-////else/*8*/ if (null) {
-////}
-////else/*9*/ /* whar garbl */ if/*10*/ (undefined) {
-////}
-////else/*11*/
-////if/*12*/ (false) {
-////}
-////else/*13*/ { }
-
-
-test.markers().forEach(m => {
- goTo.position(m.position, m.fileName)
- verify.occurrencesAtPositionCount(0);
-});
diff --git a/tests/cases/fourslash/getOccurrencesLoopBreakContinue6.ts b/tests/cases/fourslash/getOccurrencesLoopBreakContinue6.ts
new file mode 100644
index 00000000000..0127245dd50
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesLoopBreakContinue6.ts
@@ -0,0 +1,70 @@
+///
+
+////var arr = [1, 2, 3, 4];
+////label1: for (var n in arr) {
+//// break;
+//// continue;
+//// break label1;
+//// continue label1;
+////
+//// label2: for (var i = 0; i < arr[n]; i++) {
+//// break label1;
+//// continue label1;
+////
+//// break;
+//// continue;
+//// break label2;
+//// continue label2;
+////
+//// function foo() {
+//// label3: while (true) {
+//// break;
+//// continue;
+//// break label3;
+//// continue label3;
+////
+//// // these cross function boundaries
+//// br/*1*/eak label1;
+//// cont/*2*/inue label1;
+//// bre/*3*/ak label2;
+//// c/*4*/ontinue label2;
+////
+//// label4: do {
+//// break;
+//// continue;
+//// break label4;
+//// continue label4;
+////
+//// break label3;
+//// continue label3;
+////
+//// switch (10) {
+//// case 1:
+//// case 2:
+//// break;
+//// break label4;
+//// default:
+//// continue;
+//// }
+////
+//// // these cross function boundaries
+//// br/*5*/eak label1;
+//// co/*6*/ntinue label1;
+//// br/*7*/eak label2;
+//// con/*8*/tinue label2;
+//// () => { b/*9*/reak; }
+//// } while (true)
+//// }
+//// }
+//// }
+////}
+////
+////label5: while (true) break label5;
+////
+////label7: while (true) co/*10*/ntinue label5;
+
+test.markers().forEach(m => {
+ goTo.position(m.position);
+
+ verify.occurrencesAtPositionCount(0);
+});
diff --git a/tests/cases/fourslash/getOccurrencesReturnNegatives.ts b/tests/cases/fourslash/getOccurrencesReturn4.ts
similarity index 52%
rename from tests/cases/fourslash/getOccurrencesReturnNegatives.ts
rename to tests/cases/fourslash/getOccurrencesReturn4.ts
index 79cb3c659c6..4e25162f80f 100644
--- a/tests/cases/fourslash/getOccurrencesReturnNegatives.ts
+++ b/tests/cases/fourslash/getOccurrencesReturn4.ts
@@ -19,7 +19,15 @@
//// return/*7*/ true;
////}
-test.markers().forEach(m => {
- goTo.position(m.position, m.fileName)
- verify.occurrencesAtPositionCount(0);
-});
\ No newline at end of file
+function verifyOccurencesAtMarker(marker: string, count: number) {
+ goTo.marker(marker);
+ verify.occurrencesAtPositionCount(count);
+}
+
+verifyOccurencesAtMarker("1", 4);
+verifyOccurencesAtMarker("2", 4);
+verifyOccurencesAtMarker("3", 4);
+verifyOccurencesAtMarker("4", 4);
+verifyOccurencesAtMarker("5", 1);
+verifyOccurencesAtMarker("6", 3);
+verifyOccurencesAtMarker("7", 3);
\ No newline at end of file
diff --git a/tests/cases/fourslash/getOccurrencesSetAndGet.ts b/tests/cases/fourslash/getOccurrencesSetAndGet.ts
new file mode 100644
index 00000000000..b1ab6f44c6b
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesSetAndGet.ts
@@ -0,0 +1,34 @@
+///
+
+////class Foo {
+//// [|set|] bar(b: any) {
+//// }
+////
+//// public [|get|] bar(): any {
+//// return undefined;
+//// }
+////
+//// public set set(s: any) {
+//// }
+////
+//// public get set(): any {
+//// return undefined;
+//// }
+////
+//// public set get(g: any) {
+//// }
+////
+//// public get get(): any {
+//// return undefined;
+//// }
+////}
+
+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/getOccurrencesSetAndGet2.ts b/tests/cases/fourslash/getOccurrencesSetAndGet2.ts
new file mode 100644
index 00000000000..1345394b8ee
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesSetAndGet2.ts
@@ -0,0 +1,34 @@
+///
+
+////class Foo {
+//// set bar(b: any) {
+//// }
+////
+//// public get bar(): any {
+//// return undefined;
+//// }
+////
+//// public [|set|] set(s: any) {
+//// }
+////
+//// public [|get|] set(): any {
+//// return undefined;
+//// }
+////
+//// public set get(g: any) {
+//// }
+////
+//// public get get(): any {
+//// return undefined;
+//// }
+////}
+
+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/getOccurrencesSetAndGet3.ts b/tests/cases/fourslash/getOccurrencesSetAndGet3.ts
new file mode 100644
index 00000000000..4105a407571
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesSetAndGet3.ts
@@ -0,0 +1,34 @@
+///
+
+////class Foo {
+//// set bar(b: any) {
+//// }
+////
+//// public get bar(): any {
+//// return undefined;
+//// }
+////
+//// public set set(s: any) {
+//// }
+////
+//// public get set(): any {
+//// return undefined;
+//// }
+////
+//// public [|set|] get(g: any) {
+//// }
+////
+//// public [|get|] get(): any {
+//// return undefined;
+//// }
+////}
+
+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/getOccurrencesSwitchCaseDefault5.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault5.ts
new file mode 100644
index 00000000000..162c2e1a94f
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesSwitchCaseDefault5.ts
@@ -0,0 +1,40 @@
+///
+
+////switch/*1*/ (10) {
+//// case/*2*/ 1:
+//// case/*3*/ 2:
+//// case/*4*/ 4:
+//// case/*5*/ 8:
+//// foo: switch/*6*/ (20) {
+//// case/*7*/ 1:
+//// case/*8*/ 2:
+//// break/*9*/;
+//// default/*10*/:
+//// break foo;
+//// }
+//// case/*11*/ 0xBEEF:
+//// default/*12*/:
+//// break/*13*/;
+//// case 16/*14*/:
+////}
+
+function verifyOccurencesAtMarker(marker: string, count: number) {
+ goTo.marker(marker);
+ verify.occurrencesAtPositionCount(count);
+}
+
+verifyOccurencesAtMarker("1", 9);
+verifyOccurencesAtMarker("2", 9);
+verifyOccurencesAtMarker("3", 9);
+verifyOccurencesAtMarker("4", 9);
+verifyOccurencesAtMarker("5", 9);
+verifyOccurencesAtMarker("6", 6);
+verifyOccurencesAtMarker("7", 6);
+verifyOccurencesAtMarker("8", 6);
+verifyOccurencesAtMarker("9", 6);
+verifyOccurencesAtMarker("10", 6);
+verifyOccurencesAtMarker("11", 9);
+verifyOccurencesAtMarker("12", 9);
+verifyOccurencesAtMarker("13", 9);
+verifyOccurencesAtMarker("14", 0);
+
diff --git a/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultNegatives.ts b/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultNegatives.ts
deleted file mode 100644
index cfb70b0c11a..00000000000
--- a/tests/cases/fourslash/getOccurrencesSwitchCaseDefaultNegatives.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-///
-
-////switch/*1*/ (10) {
-//// case/*2*/ 1:
-//// case/*3*/ 2:
-//// case/*4*/ 4:
-//// case/*5*/ 8:
-//// foo: switch/*6*/ (20) {
-//// case/*7*/ 1:
-//// case/*8*/ 2:
-//// break/*9*/;
-//// default/*10*/:
-//// break foo;
-//// }
-//// case/*11*/ 0xBEEF:
-//// default/*12*/:
-//// break/*13*/;
-//// case 16/*14*/:
-////}
-
-
-for (var i = 1; i <= test.markers().length; i++) {
- goTo.marker("" + i);
- verify.occurrencesAtPositionCount(0);
-}
diff --git a/tests/cases/fourslash/getOccurrencesThisNegatives.ts b/tests/cases/fourslash/getOccurrencesThis6.ts
similarity index 85%
rename from tests/cases/fourslash/getOccurrencesThisNegatives.ts
rename to tests/cases/fourslash/getOccurrencesThis6.ts
index 95c676e0add..6ff779c0b46 100644
--- a/tests/cases/fourslash/getOccurrencesThisNegatives.ts
+++ b/tests/cases/fourslash/getOccurrencesThis6.ts
@@ -142,8 +142,14 @@
////}
-test.markers().forEach(m => {
- goTo.position(m.position, m.fileName)
+function verifyOccurencesAtMarker(marker: string, count: number) {
+ goTo.marker(marker);
+ verify.occurrencesAtPositionCount(count);
+}
- verify.occurrencesAtPositionCount(0);
-});
\ No newline at end of file
+verifyOccurencesAtMarker("1", 2);
+verifyOccurencesAtMarker("2", 6);
+verifyOccurencesAtMarker("3", 1);
+verifyOccurencesAtMarker("4", 1);
+verifyOccurencesAtMarker("5", 1);
+verifyOccurencesAtMarker("6", 0);
\ No newline at end of file
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);
+});
+
diff --git a/tests/cases/fourslash/getOccurrencesTryCatchFinally4.ts b/tests/cases/fourslash/getOccurrencesTryCatchFinally4.ts
new file mode 100644
index 00000000000..dc6b0540312
--- /dev/null
+++ b/tests/cases/fourslash/getOccurrencesTryCatchFinally4.ts
@@ -0,0 +1,30 @@
+///
+
+////try/*1*/ {
+//// try/*2*/ {
+//// }
+//// catch/*3*/ (x) {
+//// }
+////
+//// try/*4*/ {
+//// }
+//// finally/*5*/ {/*8*/
+//// }
+////}
+////catch/*6*/ (e) {
+////}
+////finally/*7*/ {
+////}
+function verifyOccurencesAtMarker(marker: string, count: number) {
+ goTo.marker(marker);
+ verify.occurrencesAtPositionCount(count);
+}
+
+verifyOccurencesAtMarker("1", 3);
+verifyOccurencesAtMarker("2", 2);
+verifyOccurencesAtMarker("3", 2);
+verifyOccurencesAtMarker("4", 2);
+verifyOccurencesAtMarker("5", 2);
+verifyOccurencesAtMarker("6", 3);
+verifyOccurencesAtMarker("7", 3);
+verifyOccurencesAtMarker("8", 0);
\ No newline at end of file
diff --git a/tests/cases/fourslash/getOccurrencesTryCatchFinallyNegatives.ts b/tests/cases/fourslash/getOccurrencesTryCatchFinallyNegatives.ts
deleted file mode 100644
index d5889ff84e9..00000000000
--- a/tests/cases/fourslash/getOccurrencesTryCatchFinallyNegatives.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-///
-
-////try/*1*/ {
-//// try/*2*/ {
-//// }
-//// catch/*3*/ (x) {
-//// }
-////
-//// try/*4*/ {
-//// }
-//// finally/*5*/ {/*8*/
-//// }
-////}
-////catch/*6*/ (e) {
-////}
-////finally/*7*/ {
-////}
-
-
-for (var i = 1; i <= test.markers().length; i++) {
- goTo.marker("" + i);
- verify.occurrencesAtPositionCount(0);
-}
\ No newline at end of file
diff --git a/tests/cases/fourslash/goToDefinitionSimple.ts b/tests/cases/fourslash/goToDefinitionSimple.ts
index f931610aa2a..47c1909cf12 100644
--- a/tests/cases/fourslash/goToDefinitionSimple.ts
+++ b/tests/cases/fourslash/goToDefinitionSimple.ts
@@ -5,7 +5,12 @@
// @Filename: Consumption.ts
//// var n = new /*1*/c();
+//// var n = new c/*3*/();
goTo.marker('1');
goTo.definition();
verify.caretAtMarker('2');
+
+goTo.marker('3');
+goTo.definition();
+verify.caretAtMarker('2');
diff --git a/tests/cases/fourslash/signatureHelpOnOverloads.ts b/tests/cases/fourslash/signatureHelpOnOverloads.ts
index 83d7b75a4cf..9712c9dc301 100644
--- a/tests/cases/fourslash/signatureHelpOnOverloads.ts
+++ b/tests/cases/fourslash/signatureHelpOnOverloads.ts
@@ -13,6 +13,6 @@ verify.currentParameterSpanIs("x: string");
edit.insert("'',");
verify.signatureHelpCountIs(2);
-// verify.currentSignatureHelpIs("fn(x: string, y: number): any");
-// verify.currentParameterHelpArgumentNameIs("y");
-// verify.currentParameterSpanIs("y: number");
+verify.currentSignatureHelpIs("fn(x: string, y: number): any");
+verify.currentParameterHelpArgumentNameIs("y");
+verify.currentParameterSpanIs("y: number");
diff --git a/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts
new file mode 100644
index 00000000000..fe18f655ed4
--- /dev/null
+++ b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity.ts
@@ -0,0 +1,20 @@
+///
+
+////declare function f(s: string);
+////declare function f(n: number);
+////declare function f(s: string, b: boolean);
+////declare function f(n: number, b: boolean);
+////
+////f(1/**/
+
+goTo.marker();
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(n: number): any");
+verify.currentParameterHelpArgumentNameIs("n");
+verify.currentParameterSpanIs("n: number");
+
+edit.insert(", ");
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(n: number, b: boolean): any");
+verify.currentParameterHelpArgumentNameIs("b");
+verify.currentParameterSpanIs("b: boolean");
\ No newline at end of file
diff --git a/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity2.ts b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity2.ts
new file mode 100644
index 00000000000..1f87f3b9a0c
--- /dev/null
+++ b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity2.ts
@@ -0,0 +1,20 @@
+///
+
+////declare function f(s: string);
+////declare function f(n: number);
+////declare function f(s: string, b: boolean);
+////declare function f(n: number, b: boolean);
+////
+////f(1/**/ var
+
+goTo.marker();
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(n: number): any");
+verify.currentParameterHelpArgumentNameIs("n");
+verify.currentParameterSpanIs("n: number");
+
+edit.insert(", ");
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(n: number, b: boolean): any");
+verify.currentParameterHelpArgumentNameIs("b");
+verify.currentParameterSpanIs("b: boolean");
\ No newline at end of file
diff --git a/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity3.ts b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity3.ts
new file mode 100644
index 00000000000..c217a12ef58
--- /dev/null
+++ b/tests/cases/fourslash/signatureHelpOnOverloadsDifferentArity3.ts
@@ -0,0 +1,26 @@
+///
+
+////declare function f();
+////declare function f(s: string);
+////declare function f(s: string, b: boolean);
+////declare function f(n: number, b: boolean);
+////
+////f(/**/
+
+goTo.marker();
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(): any");
+verify.currentSignatureParamterCountIs(0);
+verify.signatureHelpArgumentCountIs(0);
+
+edit.insert(", ");
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(s: string, b: boolean): any");
+verify.currentSignatureParamterCountIs(2);
+verify.currentParameterHelpArgumentNameIs("b");
+verify.currentParameterSpanIs("b: boolean");
+
+edit.insert(", ");
+verify.signatureHelpCountIs(4);
+verify.currentSignatureHelpIs("f(s: string, b: boolean): any");
+verify.currentSignatureParamterCountIs(2);
\ No newline at end of file
diff --git a/tests/cases/unittests/services/colorization.ts b/tests/cases/unittests/services/colorization.ts
index d89cf702693..18b157f26b0 100644
--- a/tests/cases/unittests/services/colorization.ts
+++ b/tests/cases/unittests/services/colorization.ts
@@ -217,5 +217,19 @@ describe('Colorization', function () {
keyword("var"),
finalEndOfLineState(ts.EndOfLineState.Start));
});
+
+ it("classifies multiple keywords properly", function () {
+ test("public static",
+ ts.EndOfLineState.Start,
+ keyword("public"),
+ keyword("static"),
+ finalEndOfLineState(ts.EndOfLineState.Start));
+
+ test("public var",
+ ts.EndOfLineState.Start,
+ keyword("public"),
+ identifier("var"),
+ finalEndOfLineState(ts.EndOfLineState.Start));
+ });
});
});
\ No newline at end of file