Merge branch 'master' into symbolInfoFormatting
This commit is contained in:
commit
279791e99e
5 changed files with 257 additions and 234 deletions
|
@ -7134,6 +7134,22 @@ module ts {
|
|||
return mapToArray(symbols);
|
||||
}
|
||||
|
||||
function isTypeDeclarationName(name: Node): boolean {
|
||||
return name.kind == SyntaxKind.Identifier &&
|
||||
isTypeDeclaration(name.parent) &&
|
||||
(<Declaration>name.parent).name === name;
|
||||
}
|
||||
|
||||
function isTypeDeclaration(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// True if the given identifier is part of a type reference
|
||||
function isTypeReferenceIdentifier(entityName: EntityName): boolean {
|
||||
var node: Node = entityName;
|
||||
|
@ -7212,6 +7228,78 @@ module ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isTypeNode(node: Node): boolean {
|
||||
if (SyntaxKind.FirstTypeNode <= node.kind && node.kind <= SyntaxKind.LastTypeNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
return true;
|
||||
case SyntaxKind.VoidKeyword:
|
||||
return node.parent.kind !== SyntaxKind.PrefixOperator;
|
||||
case SyntaxKind.StringLiteral:
|
||||
// Specialized signatures can have string literals as their parameters' type names
|
||||
return node.parent.kind === SyntaxKind.Parameter;
|
||||
|
||||
// Identifiers and qualified names may be type nodes, depending on their context. Climb
|
||||
// above them to find the lowest container
|
||||
case SyntaxKind.Identifier:
|
||||
// If the identifier is the RHS of a qualified name, then it's a type iff its parent is.
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
// fall through
|
||||
case SyntaxKind.QualifiedName:
|
||||
// At this point, node is either a qualified name or an identifier
|
||||
Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName, "'node' was expected to be a qualified name or identifier in 'isTypeNode'.");
|
||||
|
||||
var parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.TypeQuery) {
|
||||
return false;
|
||||
}
|
||||
// Do not recursively call isTypeNode on the parent. In the example:
|
||||
//
|
||||
// var a: A.B.C;
|
||||
//
|
||||
// Calling isTypeNode would consider the qualified name A.B a type node. Only C or
|
||||
// A.B.C is a type node.
|
||||
if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) {
|
||||
return true;
|
||||
}
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
return node === (<TypeParameterDeclaration>parent).constraint;
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return node === (<VariableDeclaration>parent).type;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node === (<FunctionDeclaration>parent).type;
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
return node === (<SignatureDeclaration>parent).type;
|
||||
case SyntaxKind.TypeAssertion:
|
||||
return node === (<TypeAssertion>parent).type;
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return (<CallExpression>parent).typeArguments && (<CallExpression>parent).typeArguments.indexOf(node) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
|
|
|
@ -391,100 +391,6 @@ module ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this function only works when given a node with valid parent pointers.
|
||||
*/
|
||||
export function isTypeNode(node: Node): boolean {
|
||||
if (node.kind >= SyntaxKind.FirstTypeNode && node.kind <= SyntaxKind.LastTypeNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
return true;
|
||||
case SyntaxKind.VoidKeyword:
|
||||
return node.parent.kind !== SyntaxKind.PrefixOperator;
|
||||
case SyntaxKind.StringLiteral:
|
||||
// Specialized signatures can have string literals as their parameters' type names
|
||||
return node.parent.kind === SyntaxKind.Parameter;
|
||||
// Identifiers and qualified names may be type nodes, depending on their context. Climb
|
||||
// above them to find the lowest container
|
||||
case SyntaxKind.Identifier:
|
||||
// If the identifier is the RHS of a qualified name, then it's a type iff its parent is.
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
// Fall through
|
||||
case SyntaxKind.QualifiedName:
|
||||
// At this point, node is either a qualified name or an identifier
|
||||
var parent = node.parent;
|
||||
if (parent.kind === SyntaxKind.TypeQuery) {
|
||||
return false;
|
||||
}
|
||||
// Do not recursively call isTypeNode on the parent. In the example:
|
||||
//
|
||||
// var a: A.B.C;
|
||||
//
|
||||
// Calling isTypeNode would consider the qualified name A.B a type node. Only C or
|
||||
// A.B.C is a type node.
|
||||
if (parent.kind >= SyntaxKind.FirstTypeNode && parent.kind <= SyntaxKind.LastTypeNode) {
|
||||
return true;
|
||||
}
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
return node === (<TypeParameterDeclaration>parent).constraint;
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return node === (<VariableDeclaration>parent).type;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node === (<FunctionDeclaration>parent).type;
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
return node === (<SignatureDeclaration>parent).type;
|
||||
case SyntaxKind.TypeAssertion:
|
||||
return node === (<TypeAssertion>parent).type;
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return (<CallExpression>parent).typeArguments && (<CallExpression>parent).typeArguments.indexOf(node) >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: this function only works when given a node with valid parent pointers.
|
||||
*
|
||||
* returns true if the given identifier is the name of a type declaration node (class, interface, enum, type parameter, etc)
|
||||
*/
|
||||
export function isTypeDeclarationName(name: Node): boolean {
|
||||
return name.kind == SyntaxKind.Identifier &&
|
||||
isTypeDeclaration(name.parent) &&
|
||||
(<Declaration>name.parent).name === name;
|
||||
}
|
||||
|
||||
|
||||
export function isTypeDeclaration(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function getContainingFunction(node: Node): SignatureDeclaration {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
|
|
|
@ -1259,9 +1259,9 @@ module ts {
|
|||
filename: string; // the file where the completion was requested
|
||||
position: number; // position in the file where the completion was requested
|
||||
entries: CompletionEntry[]; // entries for this completion
|
||||
symbols: Map<Symbol>; // symbols by entry name map
|
||||
location: Node; // the node where the completion was requested
|
||||
typeChecker: TypeChecker;// the typeChecker used to generate this completion
|
||||
symbols: Map<Symbol>; // symbols by entry name map
|
||||
location: Node; // the node where the completion was requested
|
||||
typeChecker: TypeChecker; // the typeChecker used to generate this completion
|
||||
}
|
||||
|
||||
interface FormattingOptions {
|
||||
|
@ -1968,11 +1968,12 @@ module ts {
|
|||
(node.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node.parent).externalModuleName === node));
|
||||
}
|
||||
|
||||
enum SearchMeaning {
|
||||
enum SemanticMeaning {
|
||||
None = 0x0,
|
||||
Value = 0x1,
|
||||
Type = 0x2,
|
||||
Namespace = 0x4
|
||||
Namespace = 0x4,
|
||||
All = Value | Type | Namespace
|
||||
}
|
||||
|
||||
enum BreakContinueSearchType {
|
||||
|
@ -2258,16 +2259,20 @@ module ts {
|
|||
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.
|
||||
return {
|
||||
name: displayName,
|
||||
kind: getSymbolKind(symbol),
|
||||
kind: getSymbolKind(symbol, SemanticMeaning.All),
|
||||
kindModifiers: getSymbolModifiers(symbol)
|
||||
};
|
||||
}
|
||||
|
||||
function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) {
|
||||
function getCompletionEntriesFromSymbols(symbols: Symbol[], session: CompletionSession): void {
|
||||
forEach(symbols, (symbol) => {
|
||||
forEach(symbols, symbol => {
|
||||
var entry = createCompletionEntry(symbol);
|
||||
if (entry && !lookUp(session.symbols, entry.name)) {
|
||||
session.entries.push(entry);
|
||||
|
@ -2608,7 +2613,11 @@ module ts {
|
|||
var type = session.typeChecker.getTypeOfSymbol(symbol);
|
||||
Debug.assert(type, "Could not find type for symbol");
|
||||
var completionEntry = createCompletionEntry(symbol);
|
||||
var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location);
|
||||
// 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.
|
||||
var displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getSourceFile(filename), session.location, session.typeChecker, session.location, SemanticMeaning.All);
|
||||
return {
|
||||
name: entryName,
|
||||
kind: displayPartsDocumentationsAndSymbolKind.symbolKind,
|
||||
|
@ -2651,13 +2660,19 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
function getSymbolKind(symbol: Symbol): string {
|
||||
function getSymbolKind(symbol: Symbol, meaningAtLocation: SemanticMeaning): string {
|
||||
var flags = typeInfoResolver.getRootSymbol(symbol).getFlags();
|
||||
|
||||
if (flags & SymbolFlags.Module) return ScriptElementKind.moduleElement;
|
||||
if (flags & SymbolFlags.Class) return ScriptElementKind.classElement;
|
||||
if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
|
||||
if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement;
|
||||
|
||||
// The following should only apply if encountered at a type position,
|
||||
// and need to have precedence over other meanings if this is the case.
|
||||
if (meaningAtLocation & SemanticMeaning.Type) {
|
||||
if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement;
|
||||
if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
|
||||
}
|
||||
|
||||
var result = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, flags);
|
||||
if (result === ScriptElementKind.unknown) {
|
||||
if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement;
|
||||
|
@ -2730,7 +2745,10 @@ module ts {
|
|||
: ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
function getSymbolDisplayPartsDocumentationAndSymbolKind(symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node, typeResolver: TypeChecker, location: Node) {
|
||||
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)) {
|
||||
var displayParts: SymbolDisplayPart[] = [];
|
||||
var documentation: SymbolDisplayPart[];
|
||||
var symbolFlags = typeResolver.getRootSymbol(symbol).flags;
|
||||
|
@ -2841,7 +2859,7 @@ module ts {
|
|||
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile, /*meaning*/ undefined, SymbolFormatFlags.WriteTypeParametersOrArguments));
|
||||
writeTypeParametersOfSymbol(symbol, sourceFile);
|
||||
}
|
||||
if (symbolFlags & SymbolFlags.Interface) {
|
||||
if ((symbolFlags & SymbolFlags.Interface) && (semanticMeaning & SemanticMeaning.Type)) {
|
||||
addNewLineIfDisplayPartsExist();
|
||||
displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
|
||||
displayParts.push(spacePart());
|
||||
|
@ -2860,7 +2878,7 @@ module ts {
|
|||
displayParts.push(spacePart());
|
||||
displayParts.push.apply(displayParts, symbolToDisplayParts(typeResolver, symbol, sourceFile));
|
||||
}
|
||||
if (symbolFlags & SymbolFlags.TypeParameter) {
|
||||
if ((symbolFlags & SymbolFlags.TypeParameter) && (semanticMeaning & SemanticMeaning.Type)) {
|
||||
addNewLineIfDisplayPartsExist();
|
||||
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
displayParts.push(textPart("type parameter"));
|
||||
|
@ -2940,9 +2958,9 @@ module ts {
|
|||
}
|
||||
}
|
||||
else {
|
||||
symbolKind = getSymbolKind(symbol);
|
||||
symbolKind = getSymbolKind(symbol, semanticMeaning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!documentation) {
|
||||
documentation = symbol.getDocumentationComment();
|
||||
|
@ -3033,8 +3051,8 @@ module ts {
|
|||
|
||||
var displayPartsDocumentationsAndKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, sourceFile, getContainerNode(node), typeInfoResolver, node);
|
||||
return {
|
||||
kind: getSymbolKind(symbol),
|
||||
kindModifiers: displayPartsDocumentationsAndKind.symbolKind,
|
||||
kind: displayPartsDocumentationsAndKind.symbolKind,
|
||||
kindModifiers: getSymbolModifiers(symbol),
|
||||
textSpan: new TypeScript.TextSpan(node.getStart(), node.getWidth()),
|
||||
displayParts: displayPartsDocumentationsAndKind.displayParts,
|
||||
documentation: displayPartsDocumentationsAndKind.documentation
|
||||
|
@ -3146,10 +3164,9 @@ module ts {
|
|||
|
||||
var declarations = symbol.getDeclarations();
|
||||
var symbolName = typeInfoResolver.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
|
||||
var symbolKind = getSymbolKind(symbol);
|
||||
var symbolKind = getSymbolKind(symbol, getMeaningFromLocation(node));
|
||||
var containerSymbol = symbol.parent;
|
||||
var containerName = containerSymbol ? typeInfoResolver.symbolToString(containerSymbol, node) : "";
|
||||
var containerKind = containerSymbol ? getSymbolKind(symbol) : "";
|
||||
|
||||
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
|
||||
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
|
||||
|
@ -3854,7 +3871,7 @@ module ts {
|
|||
searchSymbol: Symbol,
|
||||
searchText: string,
|
||||
searchLocation: Node,
|
||||
searchMeaning: SearchMeaning,
|
||||
searchMeaning: SemanticMeaning,
|
||||
findInStrings: boolean,
|
||||
findInComments: boolean,
|
||||
result: ReferenceEntry[]): void {
|
||||
|
@ -4153,114 +4170,6 @@ module ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function getMeaningFromDeclaration(node: Declaration): SearchMeaning {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.CatchBlock:
|
||||
return SearchMeaning.Value;
|
||||
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return SearchMeaning.Type;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return SearchMeaning.Value | SearchMeaning.Type;
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral) {
|
||||
return SearchMeaning.Namespace | SearchMeaning.Value;
|
||||
}
|
||||
else if (isInstantiated(node)) {
|
||||
return SearchMeaning.Namespace | SearchMeaning.Value;
|
||||
}
|
||||
else {
|
||||
return SearchMeaning.Namespace;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace;
|
||||
}
|
||||
Debug.fail("Unknown declaration type");
|
||||
}
|
||||
|
||||
function isTypeReference(node: Node): boolean {
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName && (<QualifiedName>node.parent).right === node)
|
||||
node = node.parent;
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeReference;
|
||||
}
|
||||
|
||||
function isNamespaceReference(node: Node): boolean {
|
||||
var root = node;
|
||||
var isLastClause = true;
|
||||
if (root.parent.kind === SyntaxKind.QualifiedName) {
|
||||
while (root.parent && root.parent.kind === SyntaxKind.QualifiedName)
|
||||
root = root.parent;
|
||||
|
||||
isLastClause = (<QualifiedName>root).right === node;
|
||||
}
|
||||
|
||||
return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
|
||||
}
|
||||
|
||||
function isInRightSideOfImport(node: EntityName) {
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node.parent).entityName === node;
|
||||
}
|
||||
|
||||
function getMeaningFromRightHandSideOfImport(node: Node) {
|
||||
Debug.assert(node.kind === SyntaxKind.Identifier);
|
||||
|
||||
// import a = |b|; // Namespace
|
||||
// import a = |b.c|; // Value, type, namespace
|
||||
// import a = |b.c|.d; // Namespace
|
||||
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName &&
|
||||
(<QualifiedName>node.parent).right === node &&
|
||||
node.parent.parent.kind === SyntaxKind.ImportDeclaration) {
|
||||
return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace;
|
||||
}
|
||||
return SearchMeaning.Namespace;
|
||||
}
|
||||
|
||||
function getMeaningFromLocation(node: Node): SearchMeaning {
|
||||
if (node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
return SearchMeaning.Value | SearchMeaning.Type | SearchMeaning.Namespace;
|
||||
}
|
||||
else if (isInRightSideOfImport(node)) {
|
||||
return getMeaningFromRightHandSideOfImport(node);
|
||||
}
|
||||
else if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
|
||||
return getMeaningFromDeclaration(node.parent);
|
||||
}
|
||||
else if (isTypeReference(node)) {
|
||||
return SearchMeaning.Type;
|
||||
}
|
||||
else if (isNamespaceReference(node)) {
|
||||
return SearchMeaning.Namespace;
|
||||
}
|
||||
else {
|
||||
return SearchMeaning.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/** Given an initial searchMeaning, extracted from a location, widen the search scope based on the declarations
|
||||
* of the corresponding symbol. e.g. if we are searching for "Foo" in value position, but "Foo" references a class
|
||||
* then we need to widen the search to include type positions as well.
|
||||
|
@ -4268,7 +4177,7 @@ module ts {
|
|||
* module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
|
||||
* do not intersect in any of the three spaces.
|
||||
*/
|
||||
function getIntersectingMeaningFromDeclarations(meaning: SearchMeaning, declarations: Declaration[]): SearchMeaning {
|
||||
function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning {
|
||||
if (declarations) {
|
||||
do {
|
||||
// The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module]
|
||||
|
@ -4478,6 +4387,114 @@ module ts {
|
|||
return emitOutput;
|
||||
}
|
||||
|
||||
function getMeaningFromDeclaration(node: Declaration): SemanticMeaning {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.CatchBlock:
|
||||
return SemanticMeaning.Value;
|
||||
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return SemanticMeaning.Type;
|
||||
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return SemanticMeaning.Value | SemanticMeaning.Type;
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if ((<ModuleDeclaration>node).name.kind === SyntaxKind.StringLiteral) {
|
||||
return SemanticMeaning.Namespace | SemanticMeaning.Value;
|
||||
}
|
||||
else if (isInstantiated(node)) {
|
||||
return SemanticMeaning.Namespace | SemanticMeaning.Value;
|
||||
}
|
||||
else {
|
||||
return SemanticMeaning.Namespace;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
|
||||
}
|
||||
Debug.fail("Unknown declaration type");
|
||||
}
|
||||
|
||||
function isTypeReference(node: Node): boolean {
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName && (<QualifiedName>node.parent).right === node)
|
||||
node = node.parent;
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeReference;
|
||||
}
|
||||
|
||||
function isNamespaceReference(node: Node): boolean {
|
||||
var root = node;
|
||||
var isLastClause = true;
|
||||
if (root.parent.kind === SyntaxKind.QualifiedName) {
|
||||
while (root.parent && root.parent.kind === SyntaxKind.QualifiedName)
|
||||
root = root.parent;
|
||||
|
||||
isLastClause = (<QualifiedName>root).right === node;
|
||||
}
|
||||
|
||||
return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
|
||||
}
|
||||
|
||||
function isInRightSideOfImport(node: EntityName) {
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node.parent).entityName === node;
|
||||
}
|
||||
|
||||
function getMeaningFromRightHandSideOfImport(node: Node) {
|
||||
Debug.assert(node.kind === SyntaxKind.Identifier);
|
||||
|
||||
// import a = |b|; // Namespace
|
||||
// import a = |b.c|; // Value, type, namespace
|
||||
// import a = |b.c|.d; // Namespace
|
||||
|
||||
if (node.parent.kind === SyntaxKind.QualifiedName &&
|
||||
(<QualifiedName>node.parent).right === node &&
|
||||
node.parent.parent.kind === SyntaxKind.ImportDeclaration) {
|
||||
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
|
||||
}
|
||||
return SemanticMeaning.Namespace;
|
||||
}
|
||||
|
||||
function getMeaningFromLocation(node: Node): SemanticMeaning {
|
||||
if (node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
|
||||
}
|
||||
else if (isInRightSideOfImport(node)) {
|
||||
return getMeaningFromRightHandSideOfImport(node);
|
||||
}
|
||||
else if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
|
||||
return getMeaningFromDeclaration(node.parent);
|
||||
}
|
||||
else if (isTypeReference(node)) {
|
||||
return SemanticMeaning.Type;
|
||||
}
|
||||
else if (isNamespaceReference(node)) {
|
||||
return SemanticMeaning.Namespace;
|
||||
}
|
||||
else {
|
||||
return SemanticMeaning.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Signature help
|
||||
/**
|
||||
* This is a semantic operation.
|
||||
|
@ -4646,7 +4663,7 @@ module ts {
|
|||
|
||||
return result;
|
||||
|
||||
function classifySymbol(symbol: Symbol, isInTypePosition: boolean) {
|
||||
function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning) {
|
||||
var flags = symbol.getFlags();
|
||||
|
||||
if (flags & SymbolFlags.Class) {
|
||||
|
@ -4655,10 +4672,7 @@ module ts {
|
|||
else if (flags & SymbolFlags.Enum) {
|
||||
return ClassificationTypeNames.enumName;
|
||||
}
|
||||
else if (flags & SymbolFlags.Module) {
|
||||
return ClassificationTypeNames.moduleName;
|
||||
}
|
||||
else if (isInTypePosition) {
|
||||
else if (meaningAtPosition & SemanticMeaning.Type) {
|
||||
if (flags & SymbolFlags.Interface) {
|
||||
return ClassificationTypeNames.interfaceName;
|
||||
}
|
||||
|
@ -4666,6 +4680,9 @@ module ts {
|
|||
return ClassificationTypeNames.typeParameterName;
|
||||
}
|
||||
}
|
||||
else if (flags & SymbolFlags.Module) {
|
||||
return ClassificationTypeNames.moduleName;
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(node: Node) {
|
||||
|
@ -4674,7 +4691,7 @@ module ts {
|
|||
if (node.kind === SyntaxKind.Identifier && node.getWidth() > 0) {
|
||||
var symbol = typeInfoResolver.getSymbolInfo(node);
|
||||
if (symbol) {
|
||||
var type = classifySymbol(symbol, isTypeNode(node) || isTypeDeclarationName(node));
|
||||
var type = classifySymbol(symbol, getMeaningFromLocation(node));
|
||||
if (type) {
|
||||
result.push({
|
||||
textSpan: new TypeScript.TextSpan(node.getStart(), node.getWidth()),
|
||||
|
@ -5135,7 +5152,7 @@ module ts {
|
|||
|
||||
// Only allow a symbol to be renamed if it actually has at least one declaration.
|
||||
if (symbol && symbol.getDeclarations() && symbol.getDeclarations().length > 0) {
|
||||
var kind = getSymbolKind(symbol);
|
||||
var kind = getSymbolKind(symbol, getMeaningFromLocation(node));
|
||||
if (kind) {
|
||||
return getRenameInfo(symbol.name, typeInfoResolver.getFullyQualifiedName(symbol), kind,
|
||||
getSymbolModifiers(symbol),
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
//// /** c1_nc_l1*/
|
||||
//// public nc_l1: () => void;
|
||||
////}
|
||||
////var i1/*1iq*/_i: i1;
|
||||
////var i1/*1iq*/_i: /*16i*/i1;
|
||||
////i1_i./*1*/i/*2q*/1_f1(/*2*/);
|
||||
////i1_i.i1_n/*3q*/c_f1(/*3*/);
|
||||
////i1_i.f/*4q*/1(/*4*/);
|
||||
|
@ -179,7 +179,7 @@
|
|||
//// nc_f1(): void;
|
||||
//// nc_l1: () => void;
|
||||
////}
|
||||
////var i2/*36iq*/_i: i2;
|
||||
////var i2/*36iq*/_i: /*51i*/i2;
|
||||
////var i3/*37iq*/_i: i3;
|
||||
////i2_i./*36*/i2/*37q*/_f1(/*37*/);
|
||||
////i2_i.i2_n/*38q*/c_f1(/*38*/);
|
||||
|
@ -370,6 +370,9 @@ verify.completionListContains("i1_i", "(var) i1_i: i1", "");
|
|||
verify.completionListContains("c1", "class c1", "");
|
||||
verify.completionListContains("c1_i", "(var) c1_i: c1", "");
|
||||
|
||||
goTo.marker('16i');
|
||||
verify.completionListContains("i1", "interface i1", "i1 is interface with properties");
|
||||
|
||||
goTo.marker('17iq');
|
||||
verify.quickInfoIs("(var) c2_i: c2", "");
|
||||
goTo.marker('18iq');
|
||||
|
@ -653,6 +656,10 @@ verify.completionListContains("i2_i", "(var) i2_i: i2", "");
|
|||
verify.completionListContains("i3", "interface i3", "");
|
||||
verify.completionListContains("i3_i", "(var) i3_i: i3", "");
|
||||
|
||||
goTo.marker('51i');
|
||||
verify.completionListContains("i2", "interface i2", "");
|
||||
verify.completionListContains("i3", "interface i3", "");
|
||||
|
||||
goTo.marker('52');
|
||||
verify.quickInfoIs("(constructor) c5(): c5", "");
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
//// fnfoo(/**param help*/b: number): string;
|
||||
//// nc_fnfoo(b: number): string;
|
||||
////}
|
||||
////var i2/*6*/_i: i2;
|
||||
////var i2/*6*/_i: /*34i*/i2;
|
||||
////var i2_i/*7*/_x = i2_i./*8*/x;
|
||||
////var i2_i/*9*/_foo = i2_i.f/*10*/oo;
|
||||
////var i2_i_f/*11*/oo_r = i2_i.f/*12q*/oo(/*12*/30);
|
||||
|
@ -218,6 +218,11 @@ verify.completionListContains("i2_i_fnfoo_r", "(var) i2_i_fnfoo_r: string", "");
|
|||
verify.completionListContains("i2_i_nc_fnfoo", "(var) i2_i_nc_fnfoo: (b: number) => string", "");
|
||||
verify.completionListContains("i2_i_nc_fnfoo_r", "(var) i2_i_nc_fnfoo_r: string", "");
|
||||
|
||||
goTo.marker('34i');
|
||||
verify.completionListContains("i1", "interface i1", "this is interface 1");
|
||||
verify.completionListContains("nc_i1", "interface nc_i1", "");
|
||||
verify.completionListContains("i2", "interface i2", "this is interface 2 with memebers");
|
||||
|
||||
goTo.marker('36');
|
||||
verify.completionListContains("a", "(parameter) a: number", "i3_i a");
|
||||
|
||||
|
|
Loading…
Reference in a new issue