Add getTypeOfNode function to checker API

This commit is contained in:
Jason Freeman 2014-08-13 11:38:21 -07:00
parent 96fba4d867
commit 12a0909fdd
3 changed files with 172 additions and 71 deletions

View File

@ -81,19 +81,16 @@ module ts {
getTypeCount: () => typeCount,
checkProgram: checkProgram,
emitFiles: invokeEmitter,
getSymbolOfNode: getSymbolOfNode,
getParentOfSymbol: getParentOfSymbol,
getTypeOfSymbol: getTypeOfSymbol,
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
getPropertiesOfType: getPropertiesOfType,
getPropertyOfType: getPropertyOfType,
getSignaturesOfType: getSignaturesOfType,
getIndexTypeOfType: getIndexTypeOfType,
getReturnTypeOfSignature: getReturnTypeOfSignature,
resolveEntityName: resolveEntityName,
getSymbolsInScope: getSymbolsInScope,
getSymbolInfo: getSymbolInfo,
getTypeOfExpression: getTypeOfExpression,
getTypeOfNode: getTypeOfNode,
typeToString: typeToString,
symbolToString: symbolToString,
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType
@ -6546,30 +6543,42 @@ module ts {
return mapToArray(symbols);
}
// True if the given identifier is the identifier of a declaration node
function isDeclarationIdentifier(identifier: Identifier): boolean {
if (identifier.parent) {
switch (identifier.parent.kind) {
case SyntaxKind.TypeParameter:
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Property:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.EnumMember:
case SyntaxKind.Method:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportDeclaration:
return (<Declaration>identifier.parent).name === identifier;
case SyntaxKind.CatchBlock:
return (<CatchBlock>identifier.parent).variable === identifier;
}
// True if the given identifier, string literal, or number literal is the name of a declaration node
function isDeclarationName(name: Node): boolean {
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
return false;
}
var parent = name.parent;
if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) {
return (<Declaration>parent).name === name;
}
if (parent.kind === SyntaxKind.CatchBlock) {
return (<CatchBlock>parent).variable === name;
}
return false;
}
function isDeclaration(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.TypeParameter:
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Property:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.EnumMember:
case SyntaxKind.Method:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportDeclaration:
return true;
}
return false;
}
@ -6582,6 +6591,7 @@ module ts {
}
function isExpression(node: Node): boolean {
// Omitted expression?
switch (node.kind) {
case SyntaxKind.ThisKeyword:
case SyntaxKind.SuperKeyword:
@ -6605,49 +6615,119 @@ module ts {
case SyntaxKind.ConditionalExpression:
return true;
case SyntaxKind.QualifiedName:
while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent;
return node.parent && node.parent.kind === SyntaxKind.TypeQuery;
while (node.parent.kind === SyntaxKind.QualifiedName) node = node.parent;
return node.parent.kind === SyntaxKind.TypeQuery;
case SyntaxKind.Identifier:
if (node.parent.kind === SyntaxKind.TypeQuery) {
return true;
}
// Fall through
case SyntaxKind.NumericLiteral:
case SyntaxKind.StringLiteral:
var parent = node.parent;
if (parent) {
if (isExpression(parent)) return true;
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.Property:
case SyntaxKind.EnumMember:
return (<VariableDeclaration>parent).initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.CaseClause:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SwitchStatement:
return (<ExpressionStatement>parent).expression === node;
case SyntaxKind.ForStatement:
return (<ForStatement>parent).initializer === node || (<ForStatement>parent).condition === node ||
(<ForStatement>parent).iterator === node;
case SyntaxKind.ForInStatement:
return (<ForInStatement>parent).variable === node || (<ForInStatement>parent).expression === node;
}
if (parent.kind === SyntaxKind.TypeAssertion) {
return node === (<TypeAssertion>parent).operand;
}
if (isExpression(parent)) {
return true;
}
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.Property:
case SyntaxKind.EnumMember:
return (<VariableDeclaration>parent).initializer === node;
case SyntaxKind.ExpressionStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.ReturnStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.CaseClause:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SwitchStatement:
return (<ExpressionStatement>parent).expression === node;
case SyntaxKind.ForStatement:
return (<ForStatement>parent).initializer === node || (<ForStatement>parent).condition === node ||
(<ForStatement>parent).iterator === node;
case SyntaxKind.ForInStatement:
return (<ForInStatement>parent).variable === node || (<ForInStatement>parent).expression === node;
}
}
return false;
}
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:
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:
var parent = node.parent;
if (parent.kind === SyntaxKind.TypeQuery) {
return false;
}
if (isTypeNode(parent)) {
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.indexOf(node) >= 0;
}
}
return false;
}
function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {
return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) &&
(<QualifiedName>node.parent).right === node;
}
function getSymbolOfIdentifier(identifier: Identifier) {
if (isDeclarationIdentifier(identifier)) {
if (isDeclarationName(identifier)) {
return getSymbolOfNode(identifier.parent);
}
@ -6725,14 +6805,36 @@ module ts {
return undefined;
}
function getTypeOfExpression(node: Node) {
function getTypeOfNode(node: Node): Type {
if (isExpression(node)) {
while (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
node = node.parent;
}
return <Type>getApparentType(checkExpression(node));
return getTypeOfExpression(<Expression>node);
}
return unknownType;
if (isTypeNode(node)) {
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName) {
var symbol = getSymbolInfo(node);
return getDeclaredTypeOfSymbol(symbol);
}
return getTypeFromTypeNode(<TypeNode>node);
}
if (isDeclaration(node)) {
// In this case, we call getSymbolOfNode instead of getSymbolInfo because it is a declaration
var symbol = getSymbolOfNode(node);
return getTypeOfSymbol(symbol);
}
var isExportAssignment = node.kind === SyntaxKind.Identifier && node.parent.kind === SyntaxKind.ExportAssignment;
if (isDeclarationName(node) || isExportAssignment) {
var symbol = getSymbolInfo(node);
return getTypeOfSymbol(symbol);
}
}
function getTypeOfExpression(expr: Expression): Type {
if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) {
expr = expr.parent;
}
return <Type>getApparentType(checkExpression(expr));
}
function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{
@ -6743,13 +6845,13 @@ module ts {
var propertiesByName: Map<Symbol> = {};
var results: Symbol[] = [];
forEach(getPropertiesOfType(apparentType), (s) => {
forEach(getPropertiesOfType(apparentType), s => {
propertiesByName[s.name] = s;
results.push(s);
});
var resolved = resolveObjectTypeMembers(<ObjectType>type);
forEachValue(resolved.members, (s) => {
forEachValue(resolved.members, s => {
if (symbolIsValue(s) && !propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);
@ -6757,7 +6859,7 @@ module ts {
});
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
forEach(getPropertiesOfType(globalFunctionType), (s) => {
forEach(getPropertiesOfType(globalFunctionType), s => {
if (!propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);

View File

@ -217,7 +217,9 @@ module ts {
FirstKeyword = BreakKeyword,
LastKeyword = StringKeyword,
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypeReference,
LastTypeNode = ArrayType
}
export enum NodeFlags {
@ -593,19 +595,16 @@ module ts {
getTypeCount(): number;
checkProgram(): void;
emitFiles(): EmitResult;
getSymbolOfNode(node: Node): Symbol;
getParentOfSymbol(symbol: Symbol): Symbol;
getTypeOfSymbol(symbol: Symbol): Type;
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
getPropertiesOfType(type: Type): Symbol[];
getPropertyOfType(type: Type, propetyName: string): Symbol;
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
getReturnTypeOfSignature(signature: Signature): Type;
resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolInfo(node: Node): Symbol;
getTypeOfExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type;
getTypeOfNode(node: Node): Type;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];

View File

@ -1693,7 +1693,7 @@ module ts {
// Right of dot member completion list
if (isRightOfDot) {
var type: Type = typeInfoResolver.getTypeOfExpression(mappedNode);
var type: Type = typeInfoResolver.getTypeOfNode(mappedNode);
if (!type) {
return undefined;
}