Merge branch 'master' into singletonScanner

This commit is contained in:
Cyrus Najmabadi
2015-04-15 15:48:59 -07:00
2532 changed files with 98572 additions and 88395 deletions
+40 -23
View File
@@ -2904,16 +2904,17 @@ module ts {
}
function getPropertiesOfType(type: Type): Symbol[] {
if (type.flags & TypeFlags.Union) {
return getPropertiesOfUnionType(<UnionType>type);
}
return getPropertiesOfObjectType(getApparentType(type));
type = getApparentType(type);
return type.flags & TypeFlags.Union ? getPropertiesOfUnionType(<UnionType>type) : getPropertiesOfObjectType(type);
}
// For a type parameter, return the base constraint of the type parameter. For the string, number,
// boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
// type itself. Note that the apparent type of a union type is the union type itself.
function getApparentType(type: Type): Type {
if (type.flags & TypeFlags.Union) {
type = getReducedTypeOfUnionType(<UnionType>type);
}
if (type.flags & TypeFlags.TypeParameter) {
do {
type = getConstraintOfTypeParameter(<TypeParameter>type);
@@ -2986,27 +2987,27 @@ module ts {
// necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
// Object and Function as appropriate.
function getPropertyOfType(type: Type, name: string): Symbol {
type = getApparentType(type);
if (type.flags & TypeFlags.ObjectType) {
let resolved = resolveObjectOrUnionTypeMembers(type);
if (hasProperty(resolved.members, name)) {
let symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
}
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
let symbol = getPropertyOfObjectType(globalFunctionType, name);
if (symbol) {
return symbol;
}
}
return getPropertyOfObjectType(globalObjectType, name);
}
if (type.flags & TypeFlags.Union) {
return getPropertyOfUnionType(<UnionType>type, name);
}
if (!(type.flags & TypeFlags.ObjectType)) {
type = getApparentType(type);
if (!(type.flags & TypeFlags.ObjectType)) {
return undefined;
}
}
let resolved = resolveObjectOrUnionTypeMembers(type);
if (hasProperty(resolved.members, name)) {
let symbol = resolved.members[name];
if (symbolIsValue(symbol)) {
return symbol;
}
}
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
let symbol = getPropertyOfObjectType(globalFunctionType, name);
if (symbol) return symbol;
}
return getPropertyOfObjectType(globalObjectType, name);
return undefined;
}
function getSignaturesOfObjectOrUnionType(type: Type, kind: SignatureKind): Signature[] {
@@ -3581,6 +3582,10 @@ module ts {
}
}
// The noSubtypeReduction flag is there because it isn't possible to always do subtype reduction. The flag
// is true when creating a union type from a type node and when instantiating a union type. In both of those
// cases subtype reduction has to be deferred to properly support recursive union types. For example, a
// type alias of the form "type Item = string | (() => Item)" cannot be reduced during its declaration.
function getUnionType(types: Type[], noSubtypeReduction?: boolean): Type {
if (types.length === 0) {
return emptyObjectType;
@@ -3605,10 +3610,19 @@ module ts {
if (!type) {
type = unionTypes[id] = <UnionType>createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
type.types = sortedTypes;
type.reducedType = noSubtypeReduction ? undefined : type;
}
return type;
}
function getReducedTypeOfUnionType(type: UnionType): Type {
// If union type was created without subtype reduction, perform the deferred reduction now
if (!type.reducedType) {
type.reducedType = getUnionType(type.types, /*noSubtypeReduction*/ false);
}
return type.reducedType;
}
function getTypeFromUnionTypeNode(node: UnionTypeNode): Type {
let links = getNodeLinks(node);
if (!links.resolvedType) {
@@ -9412,7 +9426,10 @@ module ts {
}
if (isArrayLikeType(inputType)) {
return getIndexTypeOfType(inputType, IndexKind.Number);
let indexType = getIndexTypeOfType(inputType, IndexKind.Number);
if (indexType) {
return indexType;
}
}
error(errorNode, Diagnostics.Type_0_is_not_an_array_type, typeToString(inputType));
-4
View File
@@ -659,10 +659,6 @@ module ts {
"\u0085": "\\u0085" // nextLine
};
export function getDefaultLibFileName(options: CompilerOptions): string {
return options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts";
}
export interface ObjectAllocator {
getNodeConstructor(kind: SyntaxKind): new () => Node;
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
+4 -4
View File
@@ -2043,19 +2043,19 @@
},
"'import ... =' can only be used in a .ts file.": {
"category": "Error",
"code": 8002
"code": 8002
},
"'export=' can only be used in a .ts file.": {
"category": "Error",
"code": 8003
"code": 8003
},
"'type parameter declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8004
"code": 8004
},
"'implements clauses' can only be used in a .ts file.": {
"category": "Error",
"code": 8005
"code": 8005
},
"'interface declarations' can only be used in a .ts file.": {
"category": "Error",
+3 -1
View File
@@ -121,7 +121,6 @@ module ts {
WhileKeyword,
WithKeyword,
// Strict mode reserved words
AsKeyword,
ImplementsKeyword,
InterfaceKeyword,
LetKeyword,
@@ -132,6 +131,7 @@ module ts {
StaticKeyword,
YieldKeyword,
// Contextual keywords
AsKeyword,
AnyKeyword,
BooleanKeyword,
ConstructorKeyword,
@@ -1512,6 +1512,8 @@ module ts {
export interface UnionType extends Type {
types: Type[]; // Constituent types
/* @internal */
reducedType: Type; // Reduced union type (all subtypes removed)
/* @internal */
resolvedProperties: SymbolTable; // Cache of resolved properties
}
+218 -216
View File
@@ -271,7 +271,6 @@ module ts {
};
}
/* @internal */
export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan {
let scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.text);
scanner.setTextPos(pos);
@@ -408,7 +407,6 @@ module ts {
export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
// Warning: This has the same semantics as the forEach family of functions,
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
export function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
@@ -439,7 +437,6 @@ module ts {
}
}
/* @internal */
export function isVariableLike(node: Node): boolean {
if (node) {
switch (node.kind) {
@@ -1151,218 +1148,7 @@ module ts {
}
return false;
}
export function textSpanEnd(span: TextSpan) {
return span.start + span.length
}
export function textSpanIsEmpty(span: TextSpan) {
return span.length === 0
}
export function textSpanContainsPosition(span: TextSpan, position: number) {
return position >= span.start && position < textSpanEnd(span);
}
// Returns true if 'span' contains 'other'.
export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) {
return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span);
}
export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) {
let overlapStart = Math.max(span.start, other.start);
let overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other));
return overlapStart < overlapEnd;
}
export function textSpanOverlap(span1: TextSpan, span2: TextSpan) {
let overlapStart = Math.max(span1.start, span2.start);
let overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (overlapStart < overlapEnd) {
return createTextSpanFromBounds(overlapStart, overlapEnd);
}
return undefined;
}
export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) {
return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start
}
export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) {
let end = start + length;
return start <= textSpanEnd(span) && end >= span.start;
}
export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
return position <= textSpanEnd(span) && position >= span.start;
}
export function textSpanIntersection(span1: TextSpan, span2: TextSpan) {
let intersectStart = Math.max(span1.start, span2.start);
let intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (intersectStart <= intersectEnd) {
return createTextSpanFromBounds(intersectStart, intersectEnd);
}
return undefined;
}
export function createTextSpan(start: number, length: number): TextSpan {
if (start < 0) {
throw new Error("start < 0");
}
if (length < 0) {
throw new Error("length < 0");
}
return { start, length };
}
export function createTextSpanFromBounds(start: number, end: number) {
return createTextSpan(start, end - start);
}
export function textChangeRangeNewSpan(range: TextChangeRange) {
return createTextSpan(range.span.start, range.newLength);
}
export function textChangeRangeIsUnchanged(range: TextChangeRange) {
return textSpanIsEmpty(range.span) && range.newLength === 0;
}
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
if (newLength < 0) {
throw new Error("newLength < 0");
}
return { span, newLength };
}
export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
/**
* Called to merge all the changes that occurred across several versions of a script snapshot
* into a single change. i.e. if a user keeps making successive edits to a script we will
* have a text change from V1 to V2, V2 to V3, ..., Vn.
*
* This function will then merge those changes into a single change range valid between V1 and
* Vn.
*/
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
if (changes.length === 0) {
return unchangedTextChangeRange;
}
if (changes.length === 1) {
return changes[0];
}
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
// as it makes things much easier to reason about.
let change0 = changes[0];
let oldStartN = change0.span.start;
let oldEndN = textSpanEnd(change0.span);
let newEndN = oldStartN + change0.newLength;
for (let i = 1; i < changes.length; i++) {
let nextChange = changes[i];
// Consider the following case:
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
// i.e. the span starting at 30 with length 30 is increased to length 40.
//
// 0 10 20 30 40 50 60 70 80 90 100
// -------------------------------------------------------------------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// -------------------------------------------------------------------------------------------------------
// | \
// | \
// T2 | \
// | \
// | \
// -------------------------------------------------------------------------------------------------------
//
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
// it's just the min of the old and new starts. i.e.:
//
// 0 10 20 30 40 50 60 70 80 90 100
// ------------------------------------------------------------*------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ----------------------------------------$-------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// (Note the dots represent the newly inferrred start.
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
// means:
//
// 0 10 20 30 40 50 60 70 80 90 100
// --------------------------------------------------------------------------------*----------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ------------------------------------------------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
// that's the same as if we started at char 80 instead of 60.
//
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
// first.
//
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
// semantics: { { start: 10, length: 70 }, newLength: 60 }
//
// The math then works out as follows.
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
// final result like so:
//
// {
// oldStart3: Min(oldStart1, oldStart2),
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
// }
let oldStart1 = oldStartN;
let oldEnd1 = oldEndN;
let newEnd1 = newEndN;
let oldStart2 = nextChange.span.start;
let oldEnd2 = textSpanEnd(nextChange.span);
let newEnd2 = oldStart2 + nextChange.newLength;
oldStartN = Math.min(oldStart1, oldStart2);
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
}
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN);
}
export function nodeStartsNewLexicalEnvironment(n: Node): boolean {
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
}
@@ -1379,7 +1165,6 @@ module ts {
return node;
}
/* @internal */
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
let fileDiagnostics: Map<Diagnostic[]> = {};
@@ -1854,3 +1639,220 @@ module ts {
return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined;
}
}
module ts {
export function getDefaultLibFileName(options: CompilerOptions): string {
return options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts";
}
export function textSpanEnd(span: TextSpan) {
return span.start + span.length
}
export function textSpanIsEmpty(span: TextSpan) {
return span.length === 0
}
export function textSpanContainsPosition(span: TextSpan, position: number) {
return position >= span.start && position < textSpanEnd(span);
}
// Returns true if 'span' contains 'other'.
export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) {
return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span);
}
export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) {
let overlapStart = Math.max(span.start, other.start);
let overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other));
return overlapStart < overlapEnd;
}
export function textSpanOverlap(span1: TextSpan, span2: TextSpan) {
let overlapStart = Math.max(span1.start, span2.start);
let overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (overlapStart < overlapEnd) {
return createTextSpanFromBounds(overlapStart, overlapEnd);
}
return undefined;
}
export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) {
return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start
}
export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) {
let end = start + length;
return start <= textSpanEnd(span) && end >= span.start;
}
export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
return position <= textSpanEnd(span) && position >= span.start;
}
export function textSpanIntersection(span1: TextSpan, span2: TextSpan) {
let intersectStart = Math.max(span1.start, span2.start);
let intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (intersectStart <= intersectEnd) {
return createTextSpanFromBounds(intersectStart, intersectEnd);
}
return undefined;
}
export function createTextSpan(start: number, length: number): TextSpan {
if (start < 0) {
throw new Error("start < 0");
}
if (length < 0) {
throw new Error("length < 0");
}
return { start, length };
}
export function createTextSpanFromBounds(start: number, end: number) {
return createTextSpan(start, end - start);
}
export function textChangeRangeNewSpan(range: TextChangeRange) {
return createTextSpan(range.span.start, range.newLength);
}
export function textChangeRangeIsUnchanged(range: TextChangeRange) {
return textSpanIsEmpty(range.span) && range.newLength === 0;
}
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
if (newLength < 0) {
throw new Error("newLength < 0");
}
return { span, newLength };
}
export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
/**
* Called to merge all the changes that occurred across several versions of a script snapshot
* into a single change. i.e. if a user keeps making successive edits to a script we will
* have a text change from V1 to V2, V2 to V3, ..., Vn.
*
* This function will then merge those changes into a single change range valid between V1 and
* Vn.
*/
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
if (changes.length === 0) {
return unchangedTextChangeRange;
}
if (changes.length === 1) {
return changes[0];
}
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
// as it makes things much easier to reason about.
let change0 = changes[0];
let oldStartN = change0.span.start;
let oldEndN = textSpanEnd(change0.span);
let newEndN = oldStartN + change0.newLength;
for (let i = 1; i < changes.length; i++) {
let nextChange = changes[i];
// Consider the following case:
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
// i.e. the span starting at 30 with length 30 is increased to length 40.
//
// 0 10 20 30 40 50 60 70 80 90 100
// -------------------------------------------------------------------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// -------------------------------------------------------------------------------------------------------
// | \
// | \
// T2 | \
// | \
// | \
// -------------------------------------------------------------------------------------------------------
//
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
// it's just the min of the old and new starts. i.e.:
//
// 0 10 20 30 40 50 60 70 80 90 100
// ------------------------------------------------------------*------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ----------------------------------------$-------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// (Note the dots represent the newly inferrred start.
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
// means:
//
// 0 10 20 30 40 50 60 70 80 90 100
// --------------------------------------------------------------------------------*----------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ------------------------------------------------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
// that's the same as if we started at char 80 instead of 60.
//
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
// first.
//
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
// semantics: { { start: 10, length: 70 }, newLength: 60 }
//
// The math then works out as follows.
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
// final result like so:
//
// {
// oldStart3: Min(oldStart1, oldStart2),
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
// }
let oldStart1 = oldStartN;
let oldEnd1 = oldEndN;
let newEnd1 = newEndN;
let oldStart2 = nextChange.span.start;
let oldEnd2 = textSpanEnd(nextChange.span);
let newEnd2 = oldStart2 + nextChange.newLength;
oldStartN = Math.min(oldStart1, oldStart2);
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
}
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN);
}
}
+27 -75
View File
@@ -1,6 +1,5 @@
interface TypeWriterResult {
line: number;
column: number;
syntaxKind: number;
sourceText: string;
type: string;
@@ -29,90 +28,43 @@ class TypeWriterWalker {
}
private visitNode(node: ts.Node): void {
switch (node.kind) {
// Should always log expressions that are not tokens
// Also, always log the "this" keyword
// TODO: Ideally we should log all expressions, but to compare to the
// old typeWriter baselines, suppress tokens
case ts.SyntaxKind.ThisKeyword:
case ts.SyntaxKind.SuperKeyword:
case ts.SyntaxKind.ArrayLiteralExpression:
case ts.SyntaxKind.ObjectLiteralExpression:
case ts.SyntaxKind.ElementAccessExpression:
case ts.SyntaxKind.CallExpression:
case ts.SyntaxKind.NewExpression:
case ts.SyntaxKind.TypeAssertionExpression:
case ts.SyntaxKind.ParenthesizedExpression:
case ts.SyntaxKind.FunctionExpression:
case ts.SyntaxKind.ArrowFunction:
case ts.SyntaxKind.TypeOfExpression:
case ts.SyntaxKind.VoidExpression:
case ts.SyntaxKind.DeleteExpression:
case ts.SyntaxKind.PrefixUnaryExpression:
case ts.SyntaxKind.PostfixUnaryExpression:
case ts.SyntaxKind.BinaryExpression:
case ts.SyntaxKind.ConditionalExpression:
case ts.SyntaxKind.SpreadElementExpression:
this.log(node, this.getTypeOfNode(node));
break;
case ts.SyntaxKind.PropertyAccessExpression:
for (var current = node; current.kind === ts.SyntaxKind.PropertyAccessExpression; current = current.parent) {
}
if (current.kind !== ts.SyntaxKind.HeritageClauseElement) {
this.log(node, this.getTypeOfNode(node));
}
break;
// Should not change expression status (maybe expressions)
// TODO: Again, ideally should log number and string literals too,
// but to be consistent with the old typeWriter, just log identifiers
case ts.SyntaxKind.Identifier:
var identifier = <ts.Identifier>node;
if (!this.isLabel(identifier)) {
var type = this.getTypeOfNode(identifier);
this.log(node, type);
}
break;
if (ts.isExpression(node) || node.kind === ts.SyntaxKind.Identifier) {
this.logTypeAndSymbol(node);
}
ts.forEachChild(node, child => this.visitNode(child));
}
private isLabel(identifier: ts.Identifier): boolean {
var parent = identifier.parent;
switch (parent.kind) {
case ts.SyntaxKind.ContinueStatement:
case ts.SyntaxKind.BreakStatement:
return (<ts.BreakOrContinueStatement>parent).label === identifier;
case ts.SyntaxKind.LabeledStatement:
return (<ts.LabeledStatement>parent).label === identifier;
}
return false;
}
private log(node: ts.Node, type: ts.Type): void {
private logTypeAndSymbol(node: ts.Node): void {
var actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
var lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
var sourceText = ts.getTextOfNodeFromSourceText(this.currentSourceFile.text, node);
// If we got an unknown type, we temporarily want to fall back to just pretending the name
// (source text) of the node is the type. This is to align with the old typeWriter to make
// baseline comparisons easier. In the long term, we will want to just call typeToString
this.results.push({
line: lineAndCharacter.line,
// todo(cyrusn): Not sure why column is one-based for type-writer. But I'm preserving
// that behavior to prevent having a lot of baselines to fix up.
column: lineAndCharacter.character + 1,
syntaxKind: node.kind,
sourceText: sourceText,
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.WriteOwnNameForAnyLike)
});
}
private getTypeOfNode(node: ts.Node): ts.Type {
var type = this.checker.getTypeAtLocation(node);
ts.Debug.assert(type !== undefined, "type doesn't exist");
return type;
var symbol = this.checker.getSymbolAtLocation(node);
var typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation);
if (symbol) {
var symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
if (symbol.declarations) {
for (let declaration of symbol.declarations) {
symbolString += ", ";
let declSourceFile = declaration.getSourceFile();
let declLineAndCharacter = declSourceFile.getLineAndCharacterOfPosition(declaration.pos);
symbolString += `Decl(${ ts.getBaseFileName(declSourceFile.fileName) }, ${ declLineAndCharacter.line }, ${ declLineAndCharacter.character })`
}
}
symbolString += ")";
typeString += ", " + symbolString;
}
this.results.push({
line: lineAndCharacter.line,
syntaxKind: node.kind,
sourceText: sourceText,
type: typeString
});
}
}
+69 -45
View File
@@ -118,7 +118,7 @@ module ts.server {
constructor(private host: ServerHost, private logger: Logger) {
this.projectService =
new ProjectService(host, logger, (eventName, project, fileName) => {
new ProjectService(host, logger, (eventName,project,fileName) => {
this.handleEvent(eventName, project, fileName);
});
}
@@ -263,7 +263,7 @@ module ts.server {
}
}
getDefinition({ line, offset, file: fileName }: protocol.FileLocationRequestArgs): protocol.FileSpan[] {
getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -285,7 +285,7 @@ module ts.server {
}));
}
getOccurrences({ line, offset, file: fileName }: protocol.FileLocationRequestArgs): protocol.OccurrencesResponseItem[] {
getOccurrences(line: number, offset: number, fileName: string): protocol.OccurrencesResponseItem[] {
fileName = ts.normalizePath(fileName);
let project = this.projectService.getProjectForFile(fileName);
@@ -315,7 +315,7 @@ module ts.server {
});
}
getRenameLocations({line, offset, file: fileName, findInComments, findInStrings }: protocol.RenameRequestArgs): protocol.RenameResponseBody {
getRenameLocations(line: number, offset: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -383,7 +383,7 @@ module ts.server {
return { info: renameInfo, locs: bakedRenameLocs };
}
getReferences({ line, offset, file: fileName }: protocol.FileLocationRequestArgs): protocol.ReferencesResponseBody {
getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody {
// TODO: get all projects for this file; report refs for all projects deleting duplicates
// can avoid duplicates by eliminating same ref file from subsequent projects
var file = ts.normalizePath(fileName);
@@ -430,12 +430,12 @@ module ts.server {
};
}
openClientFile({ file: fileName }: protocol.OpenRequestArgs) {
openClientFile(fileName: string) {
var file = ts.normalizePath(fileName);
this.projectService.openClientFile(file);
}
getQuickInfo({ line, offset, file: fileName }: protocol.FileLocationRequestArgs): protocol.QuickInfoResponseBody {
getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -461,7 +461,7 @@ module ts.server {
};
}
getFormattingEditsForRange({line, offset, endLine, endOffset, file: fileName}: protocol.FormatRequestArgs): protocol.CodeEdit[] {
getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -488,7 +488,7 @@ module ts.server {
});
}
getFormattingEditsAfterKeystroke({line, offset, key, file: fileName}: protocol.FormatOnKeyRequestArgs): protocol.CodeEdit[] {
getFormattingEditsAfterKeystroke(line: number, offset: number, key: string, fileName: string): protocol.CodeEdit[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
@@ -561,7 +561,7 @@ module ts.server {
});
}
getCompletions({ line, offset, prefix, file: fileName}: protocol.CompletionsRequestArgs): protocol.CompletionEntry[] {
getCompletions(line: number, offset: number, prefix: string, fileName: string): protocol.CompletionEntry[] {
if (!prefix) {
prefix = "";
}
@@ -587,7 +587,8 @@ module ts.server {
}, []).sort((a, b) => a.name.localeCompare(b.name));
}
getCompletionEntryDetails({ line, offset, entryNames, file: fileName}: protocol.CompletionDetailsRequestArgs): protocol.CompletionEntryDetails[] {
getCompletionEntryDetails(line: number, offset: number,
entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -606,20 +607,20 @@ module ts.server {
}, []);
}
getSignatureHelpItems({ line, offset, file: fileName }: protocol.SignatureHelpRequestArgs): protocol.SignatureHelpItems {
getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
throw Errors.NoProject;
}
var compilerService = project.compilerService;
var position = compilerService.host.lineOffsetToPosition(file, line, offset);
var helpItems = compilerService.languageService.getSignatureHelpItems(file, position);
if (!helpItems) {
return undefined;
}
var span = helpItems.applicableSpan;
var result: protocol.SignatureHelpItems = {
items: helpItems.items,
@@ -631,11 +632,11 @@ module ts.server {
argumentIndex: helpItems.argumentIndex,
argumentCount: helpItems.argumentCount,
}
return result;
}
getDiagnostics({ delay, files: fileNames }: protocol.GeterrRequestArgs): void {
getDiagnostics(delay: number, fileNames: string[]) {
var checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => {
fileName = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(fileName);
@@ -646,11 +647,11 @@ module ts.server {
}, []);
if (checkList.length > 0) {
this.updateErrorCheck(checkList, this.changeSeq, (n) => n == this.changeSeq, delay)
this.updateErrorCheck(checkList, this.changeSeq,(n) => n == this.changeSeq, delay)
}
}
change({ line, offset, endLine, endOffset, insertString, file: fileName }: protocol.ChangeRequestArgs): void {
change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (project) {
@@ -665,7 +666,7 @@ module ts.server {
}
}
reload({ file: fileName, tmpfile: tempFileName }: protocol.ReloadRequestArgs, reqSeq = 0): void {
reload(fileName: string, tempFileName: string, reqSeq = 0) {
var file = ts.normalizePath(fileName);
var tmpfile = ts.normalizePath(tempFileName);
var project = this.projectService.getProjectForFile(file);
@@ -678,7 +679,7 @@ module ts.server {
}
}
saveToTmp({ file: fileName, tmpfile: tempFileName }: protocol.SavetoRequestArgs): void {
saveToTmp(fileName: string, tempFileName: string) {
var file = ts.normalizePath(fileName);
var tmpfile = ts.normalizePath(tempFileName);
@@ -688,7 +689,7 @@ module ts.server {
}
}
closeClientFile({ file: fileName }: protocol.FileRequestArgs) {
closeClientFile(fileName: string) {
var file = ts.normalizePath(fileName);
this.projectService.closeClientFile(file);
}
@@ -712,7 +713,7 @@ module ts.server {
}));
}
getNavigationBarItems({ file: fileName }: protocol.FileRequestArgs): protocol.NavigationBarItem[]{
getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -728,7 +729,7 @@ module ts.server {
return this.decorateNavigationBarItem(project, fileName, items);
}
getNavigateToItems({ searchValue, file: fileName, maxResultCount }: protocol.NavtoRequestArgs): protocol.NavtoItem[]{
getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
if (!project) {
@@ -767,7 +768,7 @@ module ts.server {
});
}
getBraceMatching({ line, offset, file: fileName }: protocol.FileLocationRequestArgs): protocol.TextSpan[]{
getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] {
var file = ts.normalizePath(fileName);
var project = this.projectService.getProjectForFile(file);
@@ -809,91 +810,114 @@ module ts.server {
break;
}
case CommandNames.Definition: {
response = this.getDefinition(<protocol.FileLocationRequestArgs>request.arguments);
var defArgs = <protocol.FileLocationRequestArgs>request.arguments;
response = this.getDefinition(defArgs.line, defArgs.offset, defArgs.file);
break;
}
case CommandNames.References: {
response = this.getReferences(<protocol.FileLocationRequestArgs>request.arguments);
var refArgs = <protocol.FileLocationRequestArgs>request.arguments;
response = this.getReferences(refArgs.line, refArgs.offset, refArgs.file);
break;
}
case CommandNames.Rename: {
response = this.getRenameLocations(<protocol.RenameRequestArgs>request.arguments);
var renameArgs = <protocol.RenameRequestArgs>request.arguments;
response = this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings);
break;
}
case CommandNames.Open: {
this.openClientFile(<protocol.OpenRequestArgs>request.arguments);
var openArgs = <protocol.OpenRequestArgs>request.arguments;
this.openClientFile(openArgs.file);
responseRequired = false;
break;
}
case CommandNames.Quickinfo: {
response = this.getQuickInfo(<protocol.FileLocationRequestArgs>request.arguments);
var quickinfoArgs = <protocol.FileLocationRequestArgs>request.arguments;
response = this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file);
break;
}
case CommandNames.Format: {
response = this.getFormattingEditsForRange(<protocol.FormatRequestArgs>request.arguments);
var formatArgs = <protocol.FormatRequestArgs>request.arguments;
response = this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file);
break;
}
case CommandNames.Formatonkey: {
response = this.getFormattingEditsAfterKeystroke(<protocol.FormatOnKeyRequestArgs>request.arguments);
var formatOnKeyArgs = <protocol.FormatOnKeyRequestArgs>request.arguments;
response = this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file);
break;
}
case CommandNames.Completions: {
response = this.getCompletions(<protocol.CompletionsRequestArgs>request.arguments);
var completionsArgs = <protocol.CompletionsRequestArgs>request.arguments;
response = this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file);
break;
}
case CommandNames.CompletionDetails: {
response = this.getCompletionEntryDetails(<protocol.CompletionDetailsRequestArgs>request.arguments);
var completionDetailsArgs = <protocol.CompletionDetailsRequestArgs>request.arguments;
response =
this.getCompletionEntryDetails(completionDetailsArgs.line,completionDetailsArgs.offset,
completionDetailsArgs.entryNames,completionDetailsArgs.file);
break;
}
case CommandNames.SignatureHelp: {
response = this.getSignatureHelpItems(<protocol.SignatureHelpRequestArgs>request.arguments);
var signatureHelpArgs = <protocol.SignatureHelpRequestArgs>request.arguments;
response = this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file);
break;
}
case CommandNames.Geterr: {
this.getDiagnostics(<protocol.GeterrRequestArgs>request.arguments);
var geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
response = this.getDiagnostics(geterrArgs.delay, geterrArgs.files);
responseRequired = false;
break;
}
case CommandNames.Change: {
this.change(<protocol.ChangeRequestArgs>request.arguments);
var changeArgs = <protocol.ChangeRequestArgs>request.arguments;
this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset,
changeArgs.insertString, changeArgs.file);
responseRequired = false;
break;
}
case CommandNames.Configure: {
this.projectService.setHostConfiguration(<protocol.ConfigureRequestArguments>request.arguments);
var configureArgs = <protocol.ConfigureRequestArguments>request.arguments;
this.projectService.setHostConfiguration(configureArgs);
this.output(undefined, CommandNames.Configure, request.seq);
responseRequired = false;
break;
}
case CommandNames.Reload: {
this.reload(<protocol.ReloadRequestArgs>request.arguments);
var reloadArgs = <protocol.ReloadRequestArgs>request.arguments;
this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq);
responseRequired = false;
break;
}
case CommandNames.Saveto: {
this.saveToTmp(<protocol.SavetoRequestArgs>request.arguments);
var savetoArgs = <protocol.SavetoRequestArgs>request.arguments;
this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile);
responseRequired = false;
break;
}
case CommandNames.Close: {
this.closeClientFile(<protocol.FileRequestArgs>request.arguments);
var closeArgs = <protocol.FileRequestArgs>request.arguments;
this.closeClientFile(closeArgs.file);
responseRequired = false;
break;
}
case CommandNames.Navto: {
response = this.getNavigateToItems(<protocol.NavtoRequestArgs>request.arguments);
var navtoArgs = <protocol.NavtoRequestArgs>request.arguments;
response = this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount);
break;
}
case CommandNames.Brace: {
response = this.getBraceMatching(<protocol.FileLocationRequestArgs>request.arguments);
var braceArguments = <protocol.FileLocationRequestArgs>request.arguments;
response = this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file);
break;
}
case CommandNames.NavBar: {
response = this.getNavigationBarItems(<protocol.FileRequestArgs>request.arguments);
var navBarArgs = <protocol.FileRequestArgs>request.arguments;
response = this.getNavigationBarItems(navBarArgs.file);
break;
}
case CommandNames.Occurrences: {
response = this.getOccurrences(<protocol.FileLocationRequestArgs>request.arguments);
var { line, offset, file: fileName } = <protocol.FileLocationRequestArgs>request.arguments;
response = this.getOccurrences(line, offset, fileName);
break;
}
default: {
+27 -42
View File
@@ -10,11 +10,10 @@ module ts.NavigateTo {
forEach(program.getSourceFiles(), sourceFile => {
cancellationToken.throwIfCancellationRequested();
let declarations = sourceFile.getNamedDeclarations();
for (let declaration of declarations) {
var name = getDeclarationName(declaration);
if (name !== undefined) {
let nameToDeclarations = sourceFile.getNamedDeclarations();
for (let name in nameToDeclarations) {
let declarations = getProperty(nameToDeclarations, name);
if (declarations) {
// First do a quick check to see if the name of the declaration matches the
// last portion of the (possibly) dotted name they're searching for.
let matches = patternMatcher.getMatchesForLastSegmentOfPattern(name);
@@ -23,24 +22,26 @@ module ts.NavigateTo {
continue;
}
// It was a match! If the pattern has dots in it, then also see if the
// declaration container matches as well.
if (patternMatcher.patternContainsDots) {
let containers = getContainers(declaration);
if (!containers) {
return undefined;
for (let declaration of declarations) {
// It was a match! If the pattern has dots in it, then also see if the
// declaration container matches as well.
if (patternMatcher.patternContainsDots) {
let containers = getContainers(declaration);
if (!containers) {
return undefined;
}
matches = patternMatcher.getMatches(containers, name);
if (!matches) {
continue;
}
}
matches = patternMatcher.getMatches(containers, name);
if (!matches) {
continue;
}
let fileName = sourceFile.fileName;
let matchKind = bestMatchKind(matches);
rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration });
}
let fileName = sourceFile.fileName;
let matchKind = bestMatchKind(matches);
rawItems.push({ name, fileName, matchKind, isCaseSensitive: allMatchesAreCaseSensitive(matches), declaration });
}
}
});
@@ -67,30 +68,14 @@ module ts.NavigateTo {
return true;
}
function getDeclarationName(declaration: Declaration): string {
let result = getTextOfIdentifierOrLiteral(declaration.name);
if (result !== undefined) {
return result;
}
if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
let expr = (<ComputedPropertyName>declaration.name).expression;
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
return (<PropertyAccessExpression>expr).name.text;
}
return getTextOfIdentifierOrLiteral(expr);
}
return undefined;
}
function getTextOfIdentifierOrLiteral(node: Node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
if (node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
return (<Identifier | LiteralExpression>node).text;
return (<Identifier | LiteralExpression>node).text;
}
}
return undefined;
+179 -179
View File
@@ -1,180 +1,180 @@
/* @internal */
module ts {
export module OutliningElementsCollector {
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
let elements: OutliningSpan[] = [];
let collapseText = "...";
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
if (hintSpanNode && startElement && endElement) {
let span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end),
bannerText: collapseText,
autoCollapse: autoCollapse
};
elements.push(span);
}
}
function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) {
if (commentSpan) {
let span: OutliningSpan = {
textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
bannerText: collapseText,
autoCollapse: autoCollapse
};
elements.push(span);
}
}
function addOutliningForLeadingCommentsForNode(n: Node) {
let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile);
if (comments) {
let firstSingleLineCommentStart = -1;
let lastSingleLineCommentEnd = -1;
let isFirstSingleLineComment = true;
let singleLineCommentCount = 0;
for (let currentComment of comments) {
// For single line comments, combine consecutive ones (2 or more) into
// a single span from the start of the first till the end of the last
if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) {
if (isFirstSingleLineComment) {
firstSingleLineCommentStart = currentComment.pos;
}
isFirstSingleLineComment = false;
lastSingleLineCommentEnd = currentComment.end;
singleLineCommentCount++;
}
else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) {
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
addOutliningSpanComments(currentComment, /*autoCollapse*/ false);
singleLineCommentCount = 0;
lastSingleLineCommentEnd = -1;
isFirstSingleLineComment = true;
}
}
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
}
}
function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) {
// Only outline spans of two or more consecutive single line comments
if (count > 1) {
let multipleSingleLineComments = {
pos: start,
end: end,
kind: SyntaxKind.SingleLineCommentTrivia
}
addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false);
}
}
function autoCollapse(node: Node) {
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
}
let depth = 0;
let maxDepth = 20;
function walk(n: Node): void {
if (depth > maxDepth) {
return;
}
if (isDeclaration(n)) {
addOutliningForLeadingCommentsForNode(n);
}
switch (n.kind) {
case SyntaxKind.Block:
if (!isFunctionBlock(n)) {
let parent = n.parent;
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
// Check if the block is standalone, or 'attached' to some parent statement.
// If the latter, we want to collaps the block, but consider its hint span
// to be the entire span of the parent.
if (parent.kind === SyntaxKind.DoStatement ||
parent.kind === SyntaxKind.ForInStatement ||
parent.kind === SyntaxKind.ForOfStatement ||
parent.kind === SyntaxKind.ForStatement ||
parent.kind === SyntaxKind.IfStatement ||
parent.kind === SyntaxKind.WhileStatement ||
parent.kind === SyntaxKind.WithStatement ||
parent.kind === SyntaxKind.CatchClause) {
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
break;
}
if (parent.kind === SyntaxKind.TryStatement) {
// Could be the try-block, or the finally-block.
let tryStatement = <TryStatement>parent;
if (tryStatement.tryBlock === n) {
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
break;
}
else if (tryStatement.finallyBlock === n) {
let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
if (finallyKeyword) {
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n));
break;
}
}
// fall through.
}
// Block was a standalone block. In this case we want to only collapse
// the span of the block, independent of any parent span.
let span = createTextSpanFromBounds(n.getStart(), n.end);
elements.push({
textSpan: span,
hintSpan: span,
bannerText: collapseText,
autoCollapse: autoCollapse(n)
});
break;
}
// Fallthrough.
case SyntaxKind.ModuleBlock: {
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n));
break;
}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.CaseBlock: {
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n));
break;
}
case SyntaxKind.ArrayLiteralExpression:
let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile);
let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n));
break;
}
depth++;
forEachChild(n, walk);
depth--;
}
walk(sourceFile);
return elements;
}
}
/* @internal */
module ts {
export module OutliningElementsCollector {
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
let elements: OutliningSpan[] = [];
let collapseText = "...";
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
if (hintSpanNode && startElement && endElement) {
let span: OutliningSpan = {
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end),
bannerText: collapseText,
autoCollapse: autoCollapse
};
elements.push(span);
}
}
function addOutliningSpanComments(commentSpan: CommentRange, autoCollapse: boolean) {
if (commentSpan) {
let span: OutliningSpan = {
textSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
hintSpan: createTextSpanFromBounds(commentSpan.pos, commentSpan.end),
bannerText: collapseText,
autoCollapse: autoCollapse
};
elements.push(span);
}
}
function addOutliningForLeadingCommentsForNode(n: Node) {
let comments = ts.getLeadingCommentRangesOfNode(n, sourceFile);
if (comments) {
let firstSingleLineCommentStart = -1;
let lastSingleLineCommentEnd = -1;
let isFirstSingleLineComment = true;
let singleLineCommentCount = 0;
for (let currentComment of comments) {
// For single line comments, combine consecutive ones (2 or more) into
// a single span from the start of the first till the end of the last
if (currentComment.kind === SyntaxKind.SingleLineCommentTrivia) {
if (isFirstSingleLineComment) {
firstSingleLineCommentStart = currentComment.pos;
}
isFirstSingleLineComment = false;
lastSingleLineCommentEnd = currentComment.end;
singleLineCommentCount++;
}
else if (currentComment.kind === SyntaxKind.MultiLineCommentTrivia) {
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
addOutliningSpanComments(currentComment, /*autoCollapse*/ false);
singleLineCommentCount = 0;
lastSingleLineCommentEnd = -1;
isFirstSingleLineComment = true;
}
}
combineAndAddMultipleSingleLineComments(singleLineCommentCount, firstSingleLineCommentStart, lastSingleLineCommentEnd);
}
}
function combineAndAddMultipleSingleLineComments(count: number, start: number, end: number) {
// Only outline spans of two or more consecutive single line comments
if (count > 1) {
let multipleSingleLineComments = {
pos: start,
end: end,
kind: SyntaxKind.SingleLineCommentTrivia
}
addOutliningSpanComments(multipleSingleLineComments, /*autoCollapse*/ false);
}
}
function autoCollapse(node: Node) {
return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction;
}
let depth = 0;
let maxDepth = 20;
function walk(n: Node): void {
if (depth > maxDepth) {
return;
}
if (isDeclaration(n)) {
addOutliningForLeadingCommentsForNode(n);
}
switch (n.kind) {
case SyntaxKind.Block:
if (!isFunctionBlock(n)) {
let parent = n.parent;
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
// Check if the block is standalone, or 'attached' to some parent statement.
// If the latter, we want to collaps the block, but consider its hint span
// to be the entire span of the parent.
if (parent.kind === SyntaxKind.DoStatement ||
parent.kind === SyntaxKind.ForInStatement ||
parent.kind === SyntaxKind.ForOfStatement ||
parent.kind === SyntaxKind.ForStatement ||
parent.kind === SyntaxKind.IfStatement ||
parent.kind === SyntaxKind.WhileStatement ||
parent.kind === SyntaxKind.WithStatement ||
parent.kind === SyntaxKind.CatchClause) {
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
break;
}
if (parent.kind === SyntaxKind.TryStatement) {
// Could be the try-block, or the finally-block.
let tryStatement = <TryStatement>parent;
if (tryStatement.tryBlock === n) {
addOutliningSpan(parent, openBrace, closeBrace, autoCollapse(n));
break;
}
else if (tryStatement.finallyBlock === n) {
let finallyKeyword = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
if (finallyKeyword) {
addOutliningSpan(finallyKeyword, openBrace, closeBrace, autoCollapse(n));
break;
}
}
// fall through.
}
// Block was a standalone block. In this case we want to only collapse
// the span of the block, independent of any parent span.
let span = createTextSpanFromBounds(n.getStart(), n.end);
elements.push({
textSpan: span,
hintSpan: span,
bannerText: collapseText,
autoCollapse: autoCollapse(n)
});
break;
}
// Fallthrough.
case SyntaxKind.ModuleBlock: {
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n.parent, openBrace, closeBrace, autoCollapse(n));
break;
}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.CaseBlock: {
let openBrace = findChildOfKind(n, SyntaxKind.OpenBraceToken, sourceFile);
let closeBrace = findChildOfKind(n, SyntaxKind.CloseBraceToken, sourceFile);
addOutliningSpan(n, openBrace, closeBrace, autoCollapse(n));
break;
}
case SyntaxKind.ArrayLiteralExpression:
let openBracket = findChildOfKind(n, SyntaxKind.OpenBracketToken, sourceFile);
let closeBracket = findChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
addOutliningSpan(n, openBracket, closeBracket, autoCollapse(n));
break;
}
depth++;
forEachChild(n, walk);
depth--;
}
walk(sourceFile);
return elements;
}
}
}
+186 -136
View File
@@ -63,7 +63,8 @@ module ts {
/* @internal */ scriptSnapshot: IScriptSnapshot;
/* @internal */ nameTable: Map<string>;
getNamedDeclarations(): Declaration[];
/* @internal */ getNamedDeclarations(): Map<Declaration[]>;
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
getLineStarts(): number[];
getPositionOfLineAndCharacter(line: number, character: number): number;
@@ -749,7 +750,7 @@ module ts {
public identifiers: Map<string>;
public nameTable: Map<string>;
private namedDeclarations: Declaration[];
private namedDeclarations: Map<Declaration[]>;
public update(newText: string, textChangeRange: TextChangeRange): SourceFile {
return updateSourceFile(this, newText, textChangeRange);
@@ -767,7 +768,7 @@ module ts {
return ts.getPositionOfLineAndCharacter(this, line, character);
}
public getNamedDeclarations() {
public getNamedDeclarations(): Map<Declaration[]> {
if (!this.namedDeclarations) {
this.namedDeclarations = this.computeNamedDeclarations();
}
@@ -775,12 +776,57 @@ module ts {
return this.namedDeclarations;
}
private computeNamedDeclarations() {
let namedDeclarations: Declaration[] = [];
private computeNamedDeclarations(): Map<Declaration[]> {
let result: Map<Declaration[]> = {};
forEachChild(this, visit);
return namedDeclarations;
return result;
function addDeclaration(declaration: Declaration) {
let name = getDeclarationName(declaration);
if (name) {
let declarations = getDeclarations(name);
declarations.push(declaration);
}
}
function getDeclarations(name: string) {
return getProperty(result, name) || (result[name] = []);
}
function getDeclarationName(declaration: Declaration) {
if (declaration.name) {
let result = getTextOfIdentifierOrLiteral(declaration.name);
if (result !== undefined) {
return result;
}
if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
let expr = (<ComputedPropertyName>declaration.name).expression;
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
return (<PropertyAccessExpression>expr).name.text;
}
return getTextOfIdentifierOrLiteral(expr);
}
}
return undefined;
}
function getTextOfIdentifierOrLiteral(node: Node) {
if (node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
return (<Identifier | LiteralExpression>node).text;
}
}
return undefined;
}
function visit(node: Node): void {
switch (node.kind) {
@@ -788,22 +834,22 @@ module ts {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
let functionDeclaration = <FunctionLikeDeclaration>node;
let declarationName = getDeclarationName(functionDeclaration);
if (functionDeclaration.name && functionDeclaration.name.getFullWidth() > 0) {
let lastDeclaration = namedDeclarations.length > 0 ?
namedDeclarations[namedDeclarations.length - 1] :
undefined;
if (declarationName) {
let declarations = getDeclarations(declarationName);
let lastDeclaration = lastOrUndefined(declarations);
// Check whether this declaration belongs to an "overload group".
if (lastDeclaration && functionDeclaration.symbol === lastDeclaration.symbol) {
if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) {
// Overwrite the last declaration if it was an overload
// and this one is an implementation.
if (functionDeclaration.body && !(<FunctionLikeDeclaration>lastDeclaration).body) {
namedDeclarations[namedDeclarations.length - 1] = functionDeclaration;
declarations[declarations.length - 1] = functionDeclaration;
}
}
else {
namedDeclarations.push(functionDeclaration);
declarations.push(functionDeclaration);
}
forEachChild(node, visit);
@@ -824,10 +870,8 @@ module ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.TypeLiteral:
if ((<Declaration>node).name) {
namedDeclarations.push(<Declaration>node);
}
// fall through
addDeclaration(<Declaration>node);
// fall through
case SyntaxKind.Constructor:
case SyntaxKind.VariableStatement:
case SyntaxKind.VariableDeclarationList:
@@ -858,7 +902,7 @@ module ts {
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
namedDeclarations.push(<Declaration>node);
addDeclaration(<Declaration>node);
break;
case SyntaxKind.ExportDeclaration:
@@ -875,7 +919,7 @@ module ts {
// Handle default import case e.g.:
// import d from "mod";
if (importClause.name) {
namedDeclarations.push(importClause);
addDeclaration(importClause);
}
// Handle named bindings in imports e.g.:
@@ -883,7 +927,7 @@ module ts {
// import {a, b as B} from "mod";
if (importClause.namedBindings) {
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
namedDeclarations.push(<NamespaceImport>importClause.namedBindings);
addDeclaration(<NamespaceImport>importClause.namedBindings);
}
else {
forEach((<NamedImports>importClause.namedBindings).elements, visit);
@@ -2260,8 +2304,6 @@ module ts {
let ruleProvider: formatting.RulesProvider;
let program: Program;
// this checker is used to answer all LS questions except errors
let typeInfoResolver: TypeChecker;
let useCaseSensitivefileNames = false;
let cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
@@ -2343,8 +2385,10 @@ module ts {
}
program = newProgram;
typeInfoResolver = program.getTypeChecker();
// Make sure all the nodes in the program are both bound, and have their parent
// pointers set property.
program.getTypeChecker();
return;
function getOrCreateSourceFile(fileName: string): SourceFile {
@@ -2428,15 +2472,8 @@ module ts {
return program;
}
/**
* Clean up any semantic caches that are not needed.
* The host can call this method if it wants to jettison unused memory.
* We will just dump the typeChecker and recreate a new one. this should have the effect of destroying all the semantic caches.
*/
function cleanupSemanticCache(): void {
if (program) {
typeInfoResolver = program.getTypeChecker();
}
// TODO: Should we jettison the program (or it's type checker) here?
}
function dispose(): void {
@@ -2453,10 +2490,6 @@ module ts {
return program.getSyntacticDiagnostics(getValidSourceFile(fileName));
}
function isJavaScript(fileName: string) {
return fileExtensionIs(fileName, ".js");
}
/**
* getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors
* If '-d' enabled, report both semantic and emitter errors
@@ -2704,32 +2737,8 @@ module ts {
return unescapeIdentifier(displayName);
}
function createCompletionEntry(symbol: Symbol, typeChecker: TypeChecker, location: Node): CompletionEntry {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true);
if (!displayName) {
return undefined;
}
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
// 'getSymbolKind' which is permissible given that it is backwards compatible; but
// really we should consider passing the meaning for the node so that we don't report
// that a suggestion for a value is an interface. We COULD also just do what
// 'getSymbolModifiers' does, which is to use the first declaration.
// Use a 'sortText' of 0' so that all symbol completion entries come before any other
// entries (like JavaScript identifier entries).
return {
name: displayName,
kind: getSymbolKind(symbol, typeChecker, location),
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
function getCompletionData(fileName: string, position: number) {
let typeChecker = program.getTypeChecker();
let syntacticStart = new Date().getTime();
let sourceFile = getValidSourceFile(fileName);
@@ -2813,29 +2822,29 @@ module ts {
isNewIdentifierLocation = false;
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) {
let symbol = typeInfoResolver.getSymbolAtLocation(node);
let symbol = typeChecker.getSymbolAtLocation(node);
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Alias) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
symbol = typeChecker.getAliasedSymbol(symbol);
}
if (symbol && symbol.flags & SymbolFlags.HasExports) {
// Extract module or enum members
let exportedSymbols = typeInfoResolver.getExportsOfModule(symbol);
let exportedSymbols = typeChecker.getExportsOfModule(symbol);
forEach(exportedSymbols, symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name)) {
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name)) {
symbols.push(symbol);
}
});
}
}
let type = typeInfoResolver.getTypeAtLocation(node);
let type = typeChecker.getTypeAtLocation(node);
if (type) {
// Filter private properties
forEach(type.getApparentProperties(), symbol => {
if (typeInfoResolver.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name)) {
if (typeChecker.isValidPropertyAccess(<PropertyAccessExpression>(node.parent), symbol.name)) {
symbols.push(symbol);
}
});
@@ -2849,12 +2858,12 @@ module ts {
isMemberCompletion = true;
isNewIdentifierLocation = true;
let contextualType = typeInfoResolver.getContextualType(containingObjectLiteral);
let contextualType = typeChecker.getContextualType(containingObjectLiteral);
if (!contextualType) {
return false;
}
let contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType);
let contextualTypeMembers = typeChecker.getPropertiesOfType(contextualType);
if (contextualTypeMembers && contextualTypeMembers.length > 0) {
// Add filtered items to the completion list
symbols = filterContextualMembersList(contextualTypeMembers, containingObjectLiteral.properties);
@@ -2871,9 +2880,9 @@ module ts {
let exports: Symbol[];
if (importDeclaration.moduleSpecifier) {
let moduleSpecifierSymbol = typeInfoResolver.getSymbolAtLocation(importDeclaration.moduleSpecifier);
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
if (moduleSpecifierSymbol) {
exports = typeInfoResolver.getExportsOfModule(moduleSpecifierSymbol);
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
}
}
@@ -2922,7 +2931,7 @@ module ts {
/// TODO filter meaning based on the current context
let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings);
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
}
return true;
@@ -3109,6 +3118,7 @@ module ts {
case SyntaxKind.SemicolonToken:
return containingNodeKind === SyntaxKind.PropertySignature &&
previousToken.parent && previousToken.parent.parent &&
(previousToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration || // interface a { f; |
previousToken.parent.parent.kind === SyntaxKind.TypeLiteral); // let x : { a; |
@@ -3124,7 +3134,8 @@ module ts {
case SyntaxKind.DotDotDotToken:
return containingNodeKind === SyntaxKind.Parameter ||
containingNodeKind === SyntaxKind.Constructor ||
(previousToken.parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [ ...z|
(previousToken.parent && previousToken.parent.parent &&
previousToken.parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [ ...z|
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
@@ -3283,6 +3294,31 @@ module ts {
return entries;
}
function createCompletionEntry(symbol: Symbol, location: Node): CompletionEntry {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true);
if (!displayName) {
return undefined;
}
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
// 'getSymbolKind' which is permissible given that it is backwards compatible; but
// really we should consider passing the meaning for the node so that we don't report
// that a suggestion for a value is an interface. We COULD also just do what
// 'getSymbolModifiers' does, which is to use the first declaration.
// Use a 'sortText' of 0' so that all symbol completion entries come before any other
// entries (like JavaScript identifier entries).
return {
name: displayName,
kind: getSymbolKind(symbol, location),
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] {
let start = new Date().getTime();
var entries: CompletionEntry[] = [];
@@ -3290,7 +3326,7 @@ module ts {
if (symbols) {
var nameToSymbol: Map<Symbol> = {};
for (let symbol of symbols) {
let entry = createCompletionEntry(symbol, typeInfoResolver, location);
let entry = createCompletionEntry(symbol, location);
if (entry) {
let id = escapeIdentifier(entry.name);
if (!lookUp(nameToSymbol, id)) {
@@ -3322,7 +3358,7 @@ module ts {
let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined);
if (symbol) {
let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, typeInfoResolver, location, SemanticMeaning.All);
let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, location, SemanticMeaning.All);
return {
name: entryName,
kind: displayPartsDocumentationsAndSymbolKind.symbolKind,
@@ -3349,7 +3385,7 @@ module ts {
}
// TODO(drosen): use contextual SemanticMeaning.
function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location: Node): string {
function getSymbolKind(symbol: Symbol, location: Node): string {
let flags = symbol.getFlags();
if (flags & SymbolFlags.Class) return ScriptElementKind.classElement;
@@ -3358,7 +3394,7 @@ module ts {
if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, typeResolver, location);
let result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags, location);
if (result === ScriptElementKind.unknown) {
if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
if (flags & SymbolFlags.EnumMember) return ScriptElementKind.variableElement;
@@ -3369,11 +3405,13 @@ module ts {
return result;
}
function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, typeResolver: TypeChecker, location: Node) {
if (typeResolver.isUndefinedSymbol(symbol)) {
function getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol: Symbol, flags: SymbolFlags, location: Node) {
let typeChecker = program.getTypeChecker();
if (typeChecker.isUndefinedSymbol(symbol)) {
return ScriptElementKind.variableElement;
}
if (typeResolver.isArgumentsSymbol(symbol)) {
if (typeChecker.isArgumentsSymbol(symbol)) {
return ScriptElementKind.localVariableElement;
}
if (flags & SymbolFlags.Variable) {
@@ -3397,7 +3435,7 @@ module ts {
if (flags & SymbolFlags.Property) {
if (flags & SymbolFlags.UnionProperty) {
// If union property is result of union of non method (property/accessors/variables), it is labeled as property
let unionPropertyKind = forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => {
let unionPropertyKind = forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
let rootSymbolFlags = rootSymbol.getFlags();
if (rootSymbolFlags & (SymbolFlags.PropertyOrAccessor | SymbolFlags.Variable)) {
return ScriptElementKind.memberVariableElement;
@@ -3407,7 +3445,7 @@ module ts {
if (!unionPropertyKind) {
// If this was union of all methods,
//make sure it has call signatures before we can label it as method
let typeOfUnionProperty = typeInfoResolver.getTypeOfSymbolAtLocation(symbol, location);
let typeOfUnionProperty = typeChecker.getTypeOfSymbolAtLocation(symbol, location);
if (typeOfUnionProperty.getCallSignatures().length) {
return ScriptElementKind.memberFunctionElement;
}
@@ -3440,15 +3478,16 @@ module ts {
: ScriptElementKindModifier.none;
}
// TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location
function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node,
typeResolver: TypeChecker, location: Node,
// TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location
semanticMeaning = getMeaningFromLocation(location)) {
location: Node, semanticMeaning = getMeaningFromLocation(location)) {
let typeChecker = program.getTypeChecker();
let displayParts: SymbolDisplayPart[] = [];
let documentation: SymbolDisplayPart[];
let symbolFlags = symbol.flags;
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, typeResolver, location);
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location);
let hasAddedSymbolInfo: boolean;
let type: Type;
@@ -3460,7 +3499,7 @@ module ts {
}
let signature: Signature;
type = typeResolver.getTypeOfSymbolAtLocation(symbol, location);
type = typeChecker.getTypeOfSymbolAtLocation(symbol, location);
if (type) {
if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) {
let right = (<PropertyAccessExpression>location.parent).name;
@@ -3481,7 +3520,7 @@ module ts {
if (callExpression) {
let candidateSignatures: Signature[] = [];
signature = typeResolver.getResolvedSignature(callExpression, candidateSignatures);
signature = typeChecker.getResolvedSignature(callExpression, candidateSignatures);
if (!signature && candidateSignatures.length) {
// Use the first candidate:
signature = candidateSignatures[0];
@@ -3530,7 +3569,7 @@ module ts {
displayParts.push(spacePart());
}
if (!(type.flags & TypeFlags.Anonymous)) {
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
displayParts.push.apply(displayParts, symbolToDisplayParts(typeChecker, type.symbol, enclosingDeclaration, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
}
addSignatureDisplayParts(signature, allSignatures, TypeFormatFlags.WriteArrowStyleSignature);
break;
@@ -3547,8 +3586,8 @@ module ts {
// get the signature from the declaration and write it
let functionDeclaration = <FunctionLikeDeclaration>location.parent;
let allSignatures = functionDeclaration.kind === SyntaxKind.Constructor ? type.getConstructSignatures() : type.getCallSignatures();
if (!typeResolver.isImplementationOfOverload(functionDeclaration)) {
signature = typeResolver.getSignatureFromDeclaration(functionDeclaration);
if (!typeChecker.isImplementationOfOverload(functionDeclaration)) {
signature = typeChecker.getSignatureFromDeclaration(functionDeclaration);
}
else {
signature = allSignatures[0];
@@ -3591,7 +3630,7 @@ module ts {
displayParts.push(spacePart());
displayParts.push(operatorPart(SyntaxKind.EqualsToken));
displayParts.push(spacePart());
displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, typeResolver.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration));
displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, typeChecker.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration));
}
if (symbolFlags & SymbolFlags.Enum) {
addNewLineIfDisplayPartsExist();
@@ -3627,7 +3666,7 @@ module ts {
else {
// Method/function type parameter
let signatureDeclaration = <SignatureDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter).parent;
let signature = typeResolver.getSignatureFromDeclaration(signatureDeclaration);
let signature = typeChecker.getSignatureFromDeclaration(signatureDeclaration);
if (signatureDeclaration.kind === SyntaxKind.ConstructSignature) {
displayParts.push(keywordPart(SyntaxKind.NewKeyword));
displayParts.push(spacePart());
@@ -3635,14 +3674,14 @@ module ts {
else if (signatureDeclaration.kind !== SyntaxKind.CallSignature && signatureDeclaration.name) {
addFullSymbolName(signatureDeclaration.symbol);
}
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature));
displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, sourceFile, TypeFormatFlags.WriteTypeArgumentsOfSignature));
}
}
if (symbolFlags & SymbolFlags.EnumMember) {
addPrefixForAnyFunctionOrVar(symbol, "enum member");
let declaration = symbol.declarations[0];
if (declaration.kind === SyntaxKind.EnumMember) {
let constantValue = typeResolver.getConstantValue(<EnumMember>declaration);
let constantValue = typeChecker.getConstantValue(<EnumMember>declaration);
if (constantValue !== undefined) {
displayParts.push(spacePart());
displayParts.push(operatorPart(SyntaxKind.EqualsToken));
@@ -3669,7 +3708,7 @@ module ts {
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
else {
let internalAliasSymbol = typeResolver.getSymbolAtLocation(importEqualsDeclaration.moduleReference);
let internalAliasSymbol = typeChecker.getSymbolAtLocation(importEqualsDeclaration.moduleReference);
if (internalAliasSymbol) {
displayParts.push(spacePart());
displayParts.push(operatorPart(SyntaxKind.EqualsToken));
@@ -3694,12 +3733,12 @@ module ts {
// If the type is type parameter, format it specially
if (type.symbol && type.symbol.flags & SymbolFlags.TypeParameter) {
let typeParameterParts = mapToDisplayParts(writer => {
typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(<TypeParameter>type, writer, enclosingDeclaration);
typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(<TypeParameter>type, writer, enclosingDeclaration);
});
displayParts.push.apply(displayParts, typeParameterParts);
}
else {
displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, type, enclosingDeclaration));
displayParts.push.apply(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration));
}
}
else if (symbolFlags & SymbolFlags.Function ||
@@ -3714,7 +3753,7 @@ module ts {
}
}
else {
symbolKind = getSymbolKind(symbol, typeResolver, location);
symbolKind = getSymbolKind(symbol, location);
}
}
@@ -3731,7 +3770,7 @@ module ts {
}
function addFullSymbolName(symbol: Symbol, enclosingDeclaration?: Node) {
let fullSymbolDisplayParts = symbolToDisplayParts(typeResolver, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
let fullSymbolDisplayParts = symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration || sourceFile, /*meaning*/ undefined,
SymbolFormatFlags.WriteTypeParametersOrArguments | SymbolFormatFlags.UseOnlyExternalAliasing);
displayParts.push.apply(displayParts, fullSymbolDisplayParts);
}
@@ -3763,7 +3802,7 @@ module ts {
}
function addSignatureDisplayParts(signature: Signature, allSignatures: Signature[], flags?: TypeFormatFlags) {
displayParts.push.apply(displayParts, signatureToDisplayParts(typeResolver, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature));
displayParts.push.apply(displayParts, signatureToDisplayParts(typeChecker, signature, enclosingDeclaration, flags | TypeFormatFlags.WriteTypeArgumentsOfSignature));
if (allSignatures.length > 1) {
displayParts.push(spacePart());
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
@@ -3778,7 +3817,7 @@ module ts {
function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) {
let typeParameterParts = mapToDisplayParts(writer => {
typeResolver.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration);
typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplayFromSymbol(symbol, writer, enclosingDeclaration);
});
displayParts.push.apply(displayParts, typeParameterParts);
}
@@ -3793,7 +3832,13 @@ module ts {
return undefined;
}
let symbol = typeInfoResolver.getSymbolAtLocation(node);
if (isLabelName(node)) {
return undefined;
}
let typeChecker = program.getTypeChecker();
let symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol) {
// Try getting just type at this position and show
switch (node.kind) {
@@ -3803,13 +3848,13 @@ module ts {
case SyntaxKind.ThisKeyword:
case SyntaxKind.SuperKeyword:
// For the identifiers/this/super etc get the type at position
let type = typeInfoResolver.getTypeAtLocation(node);
let type = typeChecker.getTypeAtLocation(node);
if (type) {
return {
kind: ScriptElementKind.unknown,
kindModifiers: ScriptElementKindModifier.none,
textSpan: createTextSpan(node.getStart(), node.getWidth()),
displayParts: typeToDisplayParts(typeInfoResolver, type, getContainerNode(node)),
displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)),
documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined
};
}
@@ -3818,7 +3863,7 @@ module ts {
return undefined;
}
let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node);
let displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), node);
return {
kind: displayPartsDocumentationsAndKind.symbolKind,
kindModifiers: getSymbolModifiers(symbol),
@@ -3874,7 +3919,8 @@ module ts {
return undefined;
}
let symbol = typeInfoResolver.getSymbolAtLocation(node);
let typeChecker = program.getTypeChecker();
let symbol = typeChecker.getSymbolAtLocation(node);
// Could not find a symbol e.g. node is string or number keyword,
// or the symbol was an internal symbol and does not have a declaration e.g. undefined symbol
@@ -3889,7 +3935,7 @@ module ts {
if (symbol.flags & SymbolFlags.Alias) {
let declaration = symbol.declarations[0];
if (node.kind === SyntaxKind.Identifier && node.parent === declaration) {
symbol = typeInfoResolver.getAliasedSymbol(symbol);
symbol = typeChecker.getAliasedSymbol(symbol);
}
}
@@ -3899,25 +3945,25 @@ module ts {
// is performed at the location of property access, we would like to go to definition of the property in the short-hand
// assignment. This case and others are handled by the following code.
if (node.parent.kind === SyntaxKind.ShorthandPropertyAssignment) {
let shorthandSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
let shorthandSymbol = typeChecker.getShorthandAssignmentValueSymbol(symbol.valueDeclaration);
if (!shorthandSymbol) {
return [];
}
let shorthandDeclarations = shorthandSymbol.getDeclarations();
let shorthandSymbolKind = getSymbolKind(shorthandSymbol, typeInfoResolver, node);
let shorthandSymbolName = typeInfoResolver.symbolToString(shorthandSymbol);
let shorthandContainerName = typeInfoResolver.symbolToString(symbol.parent, node);
let shorthandSymbolKind = getSymbolKind(shorthandSymbol, node);
let shorthandSymbolName = typeChecker.symbolToString(shorthandSymbol);
let shorthandContainerName = typeChecker.symbolToString(symbol.parent, node);
return map(shorthandDeclarations,
declaration => createDefinitionInfo(declaration, shorthandSymbolKind, shorthandSymbolName, shorthandContainerName));
}
let result: DefinitionInfo[] = [];
let declarations = symbol.getDeclarations();
let symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
let symbolKind = getSymbolKind(symbol, typeInfoResolver, node);
let symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
let symbolKind = getSymbolKind(symbol, node);
let containerSymbol = symbol.parent;
let containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
let containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : "";
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
@@ -3983,7 +4029,7 @@ module ts {
// Get occurrences only supports reporting occurrences for the file queried. So
// filter down to that list.
results = filter(results, r => r.fileName === fileName);
results = filter(results, r => getCanonicalFileName(ts.normalizeSlashes(r.fileName)) === sourceFile);
}
return results;
@@ -4676,7 +4722,9 @@ module ts {
return getReferencedSymbolsForNodes(node, program.getSourceFiles(), findInStrings, findInComments);
}
function getReferencedSymbolsForNodes(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[]{
function getReferencedSymbolsForNodes(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
let typeChecker = program.getTypeChecker();
// Labels
if (isLabelName(node)) {
if (isJumpStatementTarget(node)) {
@@ -4699,7 +4747,7 @@ module ts {
return getReferencesForSuperKeyword(node);
}
let symbol = typeInfoResolver.getSymbolAtLocation(node);
let symbol = typeChecker.getSymbolAtLocation(node);
// Could not find a symbol e.g. unknown identifier
if (!symbol) {
@@ -4750,7 +4798,7 @@ module ts {
return result;
function getDefinition(symbol: Symbol): DefinitionInfo {
let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), typeInfoResolver, node);
let info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node);
let name = map(info.displayParts, p => p.text).join("");
let declarations = symbol.declarations;
if (!declarations || declarations.length === 0) {
@@ -4800,7 +4848,7 @@ module ts {
return location.getText();
}
name = typeInfoResolver.symbolToString(symbol);
name = typeChecker.symbolToString(symbol);
return stripQuotes(name);
}
@@ -5036,10 +5084,10 @@ module ts {
return;
}
let referenceSymbol = typeInfoResolver.getSymbolAtLocation(referenceLocation);
let referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation);
if (referenceSymbol) {
let referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
var relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation);
if (relatedSymbol) {
@@ -5264,7 +5312,7 @@ module ts {
// If the symbol is an alias, add what it alaises to the list
if (isImportOrExportSpecifierImportSymbol(symbol)) {
result.push(typeInfoResolver.getAliasedSymbol(symbol));
result.push(typeChecker.getAliasedSymbol(symbol));
}
// If the location is in a context sensitive location (i.e. in an object literal) try
@@ -5272,7 +5320,7 @@ module ts {
// type to the search set
if (isNameOfPropertyAssignment(location)) {
forEach(getPropertySymbolsFromContextualType(location), contextualSymbol => {
result.push.apply(result, typeInfoResolver.getRootSymbols(contextualSymbol));
result.push.apply(result, typeChecker.getRootSymbols(contextualSymbol));
});
/* Because in short-hand property assignment, location has two meaning : property name and as value of the property
@@ -5286,7 +5334,7 @@ module ts {
* so that when matching with potential reference symbol, both symbols from property declaration and variable declaration
* will be included correctly.
*/
let shorthandValueSymbol = typeInfoResolver.getShorthandAssignmentValueSymbol(location.parent);
let shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(location.parent);
if (shorthandValueSymbol) {
result.push(shorthandValueSymbol);
}
@@ -5294,7 +5342,7 @@ module ts {
// If this is a union property, add all the symbols from all its source symbols in all unioned types.
// If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list
forEach(typeInfoResolver.getRootSymbols(symbol), rootSymbol => {
forEach(typeChecker.getRootSymbols(symbol), rootSymbol => {
if (rootSymbol !== symbol) {
result.push(rootSymbol);
}
@@ -5324,9 +5372,9 @@ module ts {
function getPropertySymbolFromTypeReference(typeReference: HeritageClauseElement) {
if (typeReference) {
let type = typeInfoResolver.getTypeAtLocation(typeReference);
let type = typeChecker.getTypeAtLocation(typeReference);
if (type) {
let propertySymbol = typeInfoResolver.getPropertyOfType(type, propertyName);
let propertySymbol = typeChecker.getPropertyOfType(type, propertyName);
if (propertySymbol) {
result.push(propertySymbol);
}
@@ -5346,7 +5394,7 @@ module ts {
// If the reference symbol is an alias, check if what it is aliasing is one of the search
// symbols.
if (isImportOrExportSpecifierImportSymbol(referenceSymbol)) {
var aliasedSymbol = typeInfoResolver.getAliasedSymbol(referenceSymbol);
var aliasedSymbol = typeChecker.getAliasedSymbol(referenceSymbol);
if (searchSymbols.indexOf(aliasedSymbol) >= 0) {
return aliasedSymbol;
}
@@ -5357,13 +5405,13 @@ module ts {
// compare to our searchSymbol
if (isNameOfPropertyAssignment(referenceLocation)) {
return forEach(getPropertySymbolsFromContextualType(referenceLocation), contextualSymbol => {
return forEach(typeInfoResolver.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
return forEach(typeChecker.getRootSymbols(contextualSymbol), s => searchSymbols.indexOf(s) >= 0 ? s : undefined);
});
}
// Unwrap symbols to get to the root (e.g. transient symbols as a result of widening)
// Or a union property, use its underlying unioned symbols
return forEach(typeInfoResolver.getRootSymbols(referenceSymbol), rootSymbol => {
return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => {
// if it is in the list, then we are done
if (searchSymbols.indexOf(rootSymbol) >= 0) {
return rootSymbol;
@@ -5384,7 +5432,7 @@ module ts {
function getPropertySymbolsFromContextualType(node: Node): Symbol[] {
if (isNameOfPropertyAssignment(node)) {
let objectLiteral = <ObjectLiteralExpression>node.parent.parent;
let contextualType = typeInfoResolver.getContextualType(objectLiteral);
let contextualType = typeChecker.getContextualType(objectLiteral);
let name = (<Identifier>node).text;
if (contextualType) {
if (contextualType.flags & TypeFlags.Union) {
@@ -5676,7 +5724,7 @@ module ts {
let sourceFile = getValidSourceFile(fileName);
return SignatureHelp.getSignatureHelpItems(sourceFile, position, typeInfoResolver, cancellationToken);
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, cancellationToken);
}
/// Syntactic features
@@ -5757,6 +5805,7 @@ module ts {
synchronizeHostData();
let sourceFile = getValidSourceFile(fileName);
let typeChecker = program.getTypeChecker();
let result: ClassifiedSpan[] = [];
processNode(sourceFile);
@@ -5809,7 +5858,7 @@ module ts {
// Only walk into nodes that intersect the requested span.
if (node && textSpanIntersectsWith(span, node.getStart(), node.getWidth())) {
if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) {
let symbol = typeInfoResolver.getSymbolAtLocation(node);
let symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
let type = classifySymbol(symbol, getMeaningFromLocation(node));
if (type) {
@@ -6291,12 +6340,13 @@ module ts {
synchronizeHostData();
let sourceFile = getValidSourceFile(fileName);
let typeChecker = program.getTypeChecker();
let node = getTouchingWord(sourceFile, position);
// Can only rename an identifier.
if (node && node.kind === SyntaxKind.Identifier) {
let symbol = typeInfoResolver.getSymbolAtLocation(node);
let symbol = typeChecker.getSymbolAtLocation(node);
// Only allow a symbol to be renamed if it actually has at least one declaration.
if (symbol) {
@@ -6313,13 +6363,13 @@ module ts {
}
}
let kind = getSymbolKind(symbol, typeInfoResolver, node);
let kind = getSymbolKind(symbol, node);
if (kind) {
return {
canRename: true,
localizedErrorMessage: undefined,
displayName: symbol.name,
fullDisplayName: typeInfoResolver.getFullyQualifiedName(symbol),
fullDisplayName: typeChecker.getFullyQualifiedName(symbol),
kind: kind,
kindModifiers: getSymbolModifiers(symbol),
triggerSpan: createTextSpan(node.getStart(), node.getWidth())
+57 -9
View File
@@ -178,7 +178,9 @@ module ts.SignatureHelp {
argumentCount: number;
}
export function getSignatureHelpItems(sourceFile: SourceFile, position: number, typeInfoResolver: TypeChecker, cancellationToken: CancellationTokenObject): SignatureHelpItems {
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, cancellationToken: CancellationTokenObject): SignatureHelpItems {
let typeChecker = program.getTypeChecker();
// Decide whether to show signature help
let startingToken = findTokenOnLeftOfPosition(sourceFile, position);
if (!startingToken) {
@@ -196,15 +198,61 @@ module ts.SignatureHelp {
let call = argumentInfo.invocation;
let candidates = <Signature[]>[];
let resolvedSignature = typeInfoResolver.getResolvedSignature(call, candidates);
let resolvedSignature = typeChecker.getResolvedSignature(call, candidates);
cancellationToken.throwIfCancellationRequested();
if (!candidates.length) {
// We didn't have any sig help items produced by the TS compiler. If this is a JS
// file, then see if we can figure out anything better.
if (isJavaScript(sourceFile.fileName)) {
return createJavaScriptSignatureHelpItems(argumentInfo);
}
return undefined;
}
return createSignatureHelpItems(candidates, resolvedSignature, argumentInfo);
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo): SignatureHelpItems {
if (argumentInfo.invocation.kind !== SyntaxKind.CallExpression) {
return undefined;
}
// See if we can find some symbol with the call expression name that has call signatures.
let callExpression = <CallExpression>argumentInfo.invocation;
let expression = callExpression.expression;
let name = expression.kind === SyntaxKind.Identifier
? <Identifier> expression
: expression.kind === SyntaxKind.PropertyAccessExpression
? (<PropertyAccessExpression>expression).name
: undefined;
if (!name || !name.text) {
return undefined;
}
let typeChecker = program.getTypeChecker();
for (let sourceFile of program.getSourceFiles()) {
let nameToDeclarations = sourceFile.getNamedDeclarations();
let declarations = getProperty(nameToDeclarations, name.text);
if (declarations) {
for (let declaration of declarations) {
let symbol = declaration.symbol;
if (symbol) {
let type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration);
if (type) {
let callSignatures = type.getCallSignatures();
if (callSignatures && callSignatures.length) {
return createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo);
}
}
}
}
}
}
}
/**
* Returns relevant information for the argument list and the current argument if we are
* in the argument of an invocation; returns undefined otherwise.
@@ -494,8 +542,8 @@ module ts.SignatureHelp {
let invocation = argumentListInfo.invocation;
let callTarget = getInvokedExpression(invocation)
let callTargetSymbol = typeInfoResolver.getSymbolAtLocation(callTarget);
let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined);
let callTargetSymbol = typeChecker.getSymbolAtLocation(callTarget);
let callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined);
let items: SignatureHelpItem[] = map(candidates, candidateSignature => {
let signatureHelpParameters: SignatureHelpParameter[];
let prefixDisplayParts: SymbolDisplayPart[] = [];
@@ -511,12 +559,12 @@ module ts.SignatureHelp {
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
let parameterParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, invocation));
suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts);
}
else {
let typeParameterParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, invocation));
prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts);
prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
@@ -526,7 +574,7 @@ module ts.SignatureHelp {
}
let returnTypeParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, invocation));
suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts);
return {
@@ -561,7 +609,7 @@ module ts.SignatureHelp {
function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter {
let displayParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildParameterDisplay(parameter, writer, invocation));
let isOptional = hasQuestionToken(parameter.valueDeclaration);
@@ -575,7 +623,7 @@ module ts.SignatureHelp {
function createSignatureHelpParameterForTypeParameter(typeParameter: TypeParameter): SignatureHelpParameter {
let displayParts = mapToDisplayParts(writer =>
typeInfoResolver.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildTypeParameterDisplay(typeParameter, writer, invocation));
return {
name: typeParameter.symbol.name,
+4
View File
@@ -652,4 +652,8 @@ module ts {
typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
});
}
export function isJavaScript(fileName: string) {
return fileExtensionIs(fileName, ".js");
}
}