Merge pull request #676 from Microsoft/completionFixes

Completion fixes
This commit is contained in:
Mohamed Hegazy
2014-09-17 17:31:30 -07:00
97 changed files with 506 additions and 322 deletions

View File

@@ -2432,7 +2432,7 @@ module ts {
case SyntaxKind.Identifier:
case SyntaxKind.QualifiedName:
var symbol = getSymbolInfo(node);
return getDeclaredTypeOfSymbol(symbol);
return symbol && getDeclaredTypeOfSymbol(symbol);
default:
return unknownType;
}
@@ -3472,41 +3472,6 @@ module ts {
return getAncestor(node, kind) !== undefined;
}
function getAncestor(node: Node, kind: SyntaxKind): Node {
switch (kind) {
// special-cases that can be come first
case SyntaxKind.ClassDeclaration:
while (node) {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
return <ClassDeclaration>node;
case SyntaxKind.EnumDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportDeclaration:
// early exit cases - declarations cannot be nested in classes
return undefined;
default:
node = node.parent;
continue;
}
}
break;
default:
while (node) {
if (node.kind === kind) {
return node;
}
else {
node = node.parent;
}
}
break;
}
return undefined;
}
// EXPRESSION TYPE CHECKING
function checkIdentifier(node: Identifier): Type {
@@ -3853,6 +3818,11 @@ module ts {
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
// be "pushed" onto a node using the contextualType property.
function getContextualType(node: Expression): Type {
if (isInsideWithStatementBody(node)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return undefined;
}
if (node.contextualType) {
return node.contextualType;
}
@@ -6718,7 +6688,20 @@ module ts {
return findChildAtPosition(sourceFile);
}
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
function isInsideWithStatementBody(node: Node): boolean {
if (node) {
while (node.parent) {
if (node.parent.kind === SyntaxKind.WithStatement && (<WithStatement>node.parent).statement === node) {
return true;
}
node = node.parent;
}
}
return false;
}
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]{
var symbols: SymbolTable = {};
var memberFlags: NodeFlags = 0;
function copySymbol(symbol: Symbol, meaning: SymbolFlags) {
@@ -6738,6 +6721,12 @@ module ts {
}
}
}
if (isInsideWithStatementBody(location)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return [];
}
while (location) {
if (location.locals && !isGlobalSourceFile(location)) {
copySymbols(location.locals, meaning);
@@ -7010,6 +6999,11 @@ module ts {
}
function getSymbolInfo(node: Node) {
if (isInsideWithStatementBody(node)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return undefined;
}
if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
// This is a declaration, call getSymbolOfNode
return getSymbolOfNode(node.parent);
@@ -7064,9 +7058,15 @@ module ts {
}
function getTypeOfNode(node: Node): Type {
if (isInsideWithStatementBody(node)) {
// We cannot answer semantic questions within a with block, do not proceed any further
return unknownType;
}
if (isExpression(node)) {
return getTypeOfExpression(<Expression>node);
}
if (isTypeNode(node)) {
return getTypeFromTypeNode(<TypeNode>node);
}
@@ -7079,7 +7079,7 @@ module ts {
if (isTypeDeclarationName(node)) {
var symbol = getSymbolInfo(node);
return getDeclaredTypeOfSymbol(symbol);
return symbol && getDeclaredTypeOfSymbol(symbol);
}
if (isDeclaration(node)) {
@@ -7090,12 +7090,12 @@ module ts {
if (isDeclarationOrFunctionExpressionOrCatchVariableName(node)) {
var symbol = getSymbolInfo(node);
return getTypeOfSymbol(symbol);
return symbol && getTypeOfSymbol(symbol);
}
if (isInRightSideOfImportOrExportAssignment(node)) {
var symbol = getSymbolInfo(node);
var declaredType = getDeclaredTypeOfSymbol(symbol);
var declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
}
@@ -7147,7 +7147,7 @@ module ts {
}
function getRootSymbol(symbol: Symbol) {
return (symbol.flags & SymbolFlags.Transient) ? getSymbolLinks(symbol).target : symbol;
return ((symbol.flags & SymbolFlags.Transient) && getSymbolLinks(symbol).target) || symbol;
}
// Emitter support

View File

@@ -531,6 +531,39 @@ module ts {
return false;
}
export function getAncestor(node: Node, kind: SyntaxKind): Node {
switch (kind) {
// special-cases that can be come first
case SyntaxKind.ClassDeclaration:
while (node) {
switch (node.kind) {
case SyntaxKind.ClassDeclaration:
return <ClassDeclaration>node;
case SyntaxKind.EnumDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportDeclaration:
// early exit cases - declarations cannot be nested in classes
return undefined;
default:
node = node.parent;
continue;
}
}
break;
default:
while (node) {
if (node.kind === kind) {
return node;
}
node = node.parent;
}
break;
}
return undefined;
}
enum ParsingContext {
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
@@ -2200,10 +2233,38 @@ module ts {
function parseCallAndAccess(expr: Expression, inNewExpression: boolean): Expression {
while (true) {
var dotStart = scanner.getTokenPos();
if (parseOptional(SyntaxKind.DotToken)) {
var propertyAccess = <PropertyAccess>createNode(SyntaxKind.PropertyAccess, expr.pos);
// Technically a keyword is valid here as all keywords are identifier names.
// However, often we'll encounter this in error situations when the keyword
// is actually starting another valid construct.
//
// So, we check for the following specific case:
//
// name.
// keyword identifierNameOrKeyword
//
// Note: the newlines are important here. For example, if that above code
// were rewritten into:
//
// name.keyword
// identifierNameOrKeyword
//
// Then we would consider it valid. That's because ASI would take effect and
// the code would be implicitly: "name.keyword; identifierNameOrKeyword".
// In the first case though, ASI will not take effect because there is not a
// line terminator after the keyword.
if (scanner.hasPrecedingLineBreak() && scanner.isReservedWord() && lookAhead(() => scanner.isReservedWord())) {
grammarErrorAtPos(dotStart, scanner.getStartPos() - dotStart, Diagnostics.Identifier_expected);
var id = <Identifier>createMissingNode();
}
else {
var id = parseIdentifierName();
}
propertyAccess.left = expr;
propertyAccess.right = parseIdentifierName();
propertyAccess.right = id;
expr = finishNode(propertyAccess);
continue;
}