Merge remote-tracking branch 'upstream/master' into fix3737

This commit is contained in:
Ryan Cavanaugh
2015-07-07 15:36:13 -07:00
53 changed files with 512 additions and 473 deletions

View File

@@ -892,7 +892,8 @@ namespace ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
checkStrictModeFunctionName(<FunctionExpression>node);
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, "__function");
let bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
case SyntaxKind.ClassExpression:
case SyntaxKind.ClassDeclaration:
return bindClassLikeDeclaration(<ClassLikeDeclaration>node);
@@ -964,7 +965,8 @@ namespace ts {
bindBlockScopedDeclaration(node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
}
else {
bindAnonymousDeclaration(node, SymbolFlags.Class, "__class");
let bindingName = node.name ? node.name.text : "__class";
bindAnonymousDeclaration(node, SymbolFlags.Class, bindingName);
}
let symbol = node.symbol;

View File

@@ -7303,6 +7303,16 @@ namespace ts {
checkGrammarJsxElement(node);
checkJsxPreconditions(node);
// If we're compiling under --jsx react, the symbol 'React' should
// be marked as 'used' so we don't incorrectly elide its import. And if there
// is no 'React' symbol in scope, we should issue an error.
if (compilerOptions.jsx === JsxEmit.React) {
let reactSym = resolveName(node.tagName, 'React', SymbolFlags.Value, Diagnostics.Cannot_find_name_0, 'React');
if (reactSym) {
getSymbolLinks(reactSym).referenced = true;
}
}
let targetAttributesType = getJsxElementAttributesType(node);
let nameTable: Map<boolean> = {};

View File

@@ -2892,33 +2892,36 @@ namespace ts {
log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start));
}
// Check if this is a valid completion location
if (contextToken && isCompletionListBlocker(contextToken)) {
log("Returning an empty list because completion was requested in an invalid position.");
return undefined;
}
let options = program.getCompilerOptions();
let jsx = options.jsx !== JsxEmit.None;
let target = options.target;
// Find the node where completion is requested on, in the case of a completion after
// a dot, it is the member access expression other wise, it is a request for all
// visible symbols in the scope, and the node is the current location.
// Find the node where completion is requested on.
// Also determine whether we are trying to complete with members of that node
// or attributes of a JSX tag.
let node = currentToken;
let isRightOfDot = false;
let isRightOfOpenTag = false;
let location = getTouchingPropertyName(sourceFile, position);
if(contextToken) {
let kind = contextToken.kind;
if (kind === SyntaxKind.DotToken && contextToken.parent.kind === SyntaxKind.PropertyAccessExpression) {
node = (<PropertyAccessExpression>contextToken.parent).expression;
isRightOfDot = true;
if (contextToken) {
// Bail out if this is a known invalid completion location
if (isCompletionListBlocker(contextToken)) {
log("Returning an empty list because completion was requested in an invalid position.");
return undefined;
}
else if (kind === SyntaxKind.DotToken && contextToken.parent.kind === SyntaxKind.QualifiedName) {
node = (<QualifiedName>contextToken.parent).left;
isRightOfDot = true;
let { parent, kind } = contextToken;
if (kind === SyntaxKind.DotToken) {
if (parent.kind === SyntaxKind.PropertyAccessExpression) {
node = (<PropertyAccessExpression>contextToken.parent).expression;
isRightOfDot = true;
}
else if (parent.kind === SyntaxKind.QualifiedName) {
node = (<QualifiedName>contextToken.parent).left;
isRightOfDot = true;
}
else {
// There is nothing that precedes the dot, so this likely just a stray character
// or leading into a '...' token. Just bail out instead.
return undefined;
}
}
else if (kind === SyntaxKind.LessThanToken && sourceFile.languageVariant === LanguageVariant.JSX) {
isRightOfOpenTag = true;
@@ -3010,68 +3013,21 @@ namespace ts {
}
function tryGetGlobalSymbols(): boolean {
let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken);
let jsxContainer = tryGetContainingJsxElement(contextToken);
if (objectLikeContainer) {
// We're looking up possible property names from contextual/inferred/declared type.
isMemberCompletion = true;
let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
let importClause: ImportClause;
let jsxContainer: JsxOpeningLikeElement;
let typeForObject: Type;
let existingMembers: Declaration[];
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
// We are completing on contextual types, but may also include properties
// other than those within the declared type.
isNewIdentifierLocation = true;
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
}
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
// We are *only* completing on properties from the type being destructured.
isNewIdentifierLocation = false;
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
}
else {
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
}
if (!typeForObject) {
return false;
}
let typeMembers = typeChecker.getPropertiesOfType(typeForObject);
if (typeMembers && typeMembers.length > 0) {
// Add filtered items to the completion list
symbols = filterObjectMembersList(typeMembers, existingMembers);
}
return true;
if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
return tryGetObjectLikeCompletionSymbols(objectLikeContainer);
}
else if (getAncestor(contextToken, SyntaxKind.ImportClause)) {
// cursor is in import clause
if (importClause = <ImportClause>getAncestor(contextToken, SyntaxKind.ImportClause)) {
// cursor is in an import clause
// try to show exported member for imported module
isMemberCompletion = true;
isNewIdentifierLocation = true;
if (showCompletionsInImportsClause(contextToken)) {
let importDeclaration = <ImportDeclaration>getAncestor(contextToken, SyntaxKind.ImportDeclaration);
Debug.assert(importDeclaration !== undefined);
let exports: Symbol[];
if (importDeclaration.moduleSpecifier) {
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
if (moduleSpecifierSymbol) {
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
}
}
//let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray;
}
return true;
return tryGetImportClauseCompletionSymbols(importClause);
}
else if (jsxContainer) {
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
let attrsType: Type;
if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) {
// Cursor is inside a JSX self-closing element or opening element
@@ -3144,16 +3100,16 @@ namespace ts {
return scope;
}
function isCompletionListBlocker(previousToken: Node): boolean {
function isCompletionListBlocker(contextToken: Node): boolean {
let start = new Date().getTime();
let result = isInStringOrRegularExpressionOrTemplateLiteral(previousToken) ||
isIdentifierDefinitionLocation(previousToken) ||
isRightOfIllegalDot(previousToken);
let result = isInStringOrRegularExpressionOrTemplateLiteral(contextToken) ||
isIdentifierDefinitionLocation(contextToken) ||
isDotOfNumericLiteral(contextToken);
log("getCompletionsAtPosition: isCompletionListBlocker: " + (new Date().getTime() - start));
return result;
}
function showCompletionsInImportsClause(node: Node): boolean {
function shouldShowCompletionsInImportsClause(node: Node): boolean {
if (node) {
// import {|
// import {a,|
@@ -3227,12 +3183,12 @@ namespace ts {
return false;
}
function isInStringOrRegularExpressionOrTemplateLiteral(previousToken: Node): boolean {
if (previousToken.kind === SyntaxKind.StringLiteral
|| previousToken.kind === SyntaxKind.RegularExpressionLiteral
|| isTemplateLiteralKind(previousToken.kind)) {
let start = previousToken.getStart();
let end = previousToken.getEnd();
function isInStringOrRegularExpressionOrTemplateLiteral(contextToken: Node): boolean {
if (contextToken.kind === SyntaxKind.StringLiteral
|| contextToken.kind === SyntaxKind.RegularExpressionLiteral
|| isTemplateLiteralKind(contextToken.kind)) {
let start = contextToken.getStart();
let end = contextToken.getEnd();
// To be "in" one of these literals, the position has to be:
// 1. entirely within the token text.
@@ -3243,14 +3199,94 @@ namespace ts {
}
if (position === end) {
return !!(<LiteralExpression>previousToken).isUnterminated ||
previousToken.kind === SyntaxKind.RegularExpressionLiteral;
return !!(<LiteralExpression>contextToken).isUnterminated
|| contextToken.kind === SyntaxKind.RegularExpressionLiteral;
}
}
return false;
}
/**
* Aggregates relevant symbols for completion in object literals and object binding patterns.
* Relevant symbols are stored in the captured 'symbols' variable.
*
* @returns true if 'symbols' was successfully populated; false otherwise.
*/
function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | BindingPattern): boolean {
// We're looking up possible property names from contextual/inferred/declared type.
isMemberCompletion = true;
let typeForObject: Type;
let existingMembers: Declaration[];
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
// We are completing on contextual types, but may also include properties
// other than those within the declared type.
isNewIdentifierLocation = true;
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
}
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
// We are *only* completing on properties from the type being destructured.
isNewIdentifierLocation = false;
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
}
else {
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
}
if (!typeForObject) {
return false;
}
let typeMembers = typeChecker.getPropertiesOfType(typeForObject);
if (typeMembers && typeMembers.length > 0) {
// Add filtered items to the completion list
symbols = filterObjectMembersList(typeMembers, existingMembers);
}
return true;
}
/**
* Aggregates relevant symbols for completion in import clauses; for instance,
*
* import { $ } from "moduleName";
*
* Relevant symbols are stored in the captured 'symbols' variable.
*
* @returns true if 'symbols' was successfully populated; false otherwise.
*/
function tryGetImportClauseCompletionSymbols(importClause: ImportClause): boolean {
// cursor is in import clause
// try to show exported member for imported module
if (shouldShowCompletionsInImportsClause(contextToken)) {
isMemberCompletion = true;
isNewIdentifierLocation = false;
let importDeclaration = <ImportDeclaration>importClause.parent;
Debug.assert(importDeclaration !== undefined && importDeclaration.kind === SyntaxKind.ImportDeclaration);
let exports: Symbol[];
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
if (moduleSpecifierSymbol) {
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
}
//let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray;
}
else {
isMemberCompletion = false;
isNewIdentifierLocation = true;
}
return true;
}
/**
* Returns the immediate owning object literal or binding pattern of a context token,
* on the condition that one exists and that the context implies completion should be given.
@@ -3318,101 +3354,98 @@ namespace ts {
return false;
}
function isIdentifierDefinitionLocation(previousToken: Node): boolean {
if (previousToken) {
let containingNodeKind = previousToken.parent.kind;
switch (previousToken.kind) {
case SyntaxKind.CommaToken:
return containingNodeKind === SyntaxKind.VariableDeclaration ||
containingNodeKind === SyntaxKind.VariableDeclarationList ||
containingNodeKind === SyntaxKind.VariableStatement ||
containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, |
isFunction(containingNodeKind) ||
containingNodeKind === SyntaxKind.ClassDeclaration || // class A<T, |
containingNodeKind === SyntaxKind.FunctionDeclaration || // function A<T, |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A<T, |
containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x, y|
function isIdentifierDefinitionLocation(contextToken: Node): boolean {
let containingNodeKind = contextToken.parent.kind;
switch (contextToken.kind) {
case SyntaxKind.CommaToken:
return containingNodeKind === SyntaxKind.VariableDeclaration ||
containingNodeKind === SyntaxKind.VariableDeclarationList ||
containingNodeKind === SyntaxKind.VariableStatement ||
containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { foo, |
isFunction(containingNodeKind) ||
containingNodeKind === SyntaxKind.ClassDeclaration || // class A<T, |
containingNodeKind === SyntaxKind.FunctionDeclaration || // function A<T, |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A<T, |
containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x, y|
case SyntaxKind.DotToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [.|
case SyntaxKind.DotToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [.|
case SyntaxKind.ColonToken:
return containingNodeKind === SyntaxKind.BindingElement; // var {x :html|
case SyntaxKind.ColonToken:
return containingNodeKind === SyntaxKind.BindingElement; // var {x :html|
case SyntaxKind.OpenBracketToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x|
case SyntaxKind.OpenBracketToken:
return containingNodeKind === SyntaxKind.ArrayBindingPattern; // var [x|
case SyntaxKind.OpenParenToken:
return containingNodeKind === SyntaxKind.CatchClause ||
isFunction(containingNodeKind);
case SyntaxKind.OpenParenToken:
return containingNodeKind === SyntaxKind.CatchClause ||
isFunction(containingNodeKind);
case SyntaxKind.OpenBraceToken:
return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface a { |
containingNodeKind === SyntaxKind.TypeLiteral; // let x : { |
case SyntaxKind.OpenBraceToken:
return containingNodeKind === SyntaxKind.EnumDeclaration || // enum a { |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface a { |
containingNodeKind === SyntaxKind.TypeLiteral; // let x : { |
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; |
case SyntaxKind.SemicolonToken:
return containingNodeKind === SyntaxKind.PropertySignature &&
contextToken.parent && contextToken.parent.parent &&
(contextToken.parent.parent.kind === SyntaxKind.InterfaceDeclaration || // interface a { f; |
contextToken.parent.parent.kind === SyntaxKind.TypeLiteral); // let x : { a; |
case SyntaxKind.LessThanToken:
return containingNodeKind === SyntaxKind.ClassDeclaration || // class A< |
containingNodeKind === SyntaxKind.FunctionDeclaration || // function A< |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A< |
isFunction(containingNodeKind);
case SyntaxKind.LessThanToken:
return containingNodeKind === SyntaxKind.ClassDeclaration || // class A< |
containingNodeKind === SyntaxKind.FunctionDeclaration || // function A< |
containingNodeKind === SyntaxKind.InterfaceDeclaration || // interface A< |
isFunction(containingNodeKind);
case SyntaxKind.StaticKeyword:
return containingNodeKind === SyntaxKind.PropertyDeclaration;
case SyntaxKind.StaticKeyword:
return containingNodeKind === SyntaxKind.PropertyDeclaration;
case SyntaxKind.DotDotDotToken:
return containingNodeKind === SyntaxKind.Parameter ||
containingNodeKind === SyntaxKind.Constructor ||
(previousToken.parent && previousToken.parent.parent &&
previousToken.parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [...z|
case SyntaxKind.DotDotDotToken:
return containingNodeKind === SyntaxKind.Parameter ||
(contextToken.parent && contextToken.parent.parent &&
contextToken.parent.parent.kind === SyntaxKind.ArrayBindingPattern); // var [...z|
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
return containingNodeKind === SyntaxKind.Parameter;
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
return containingNodeKind === SyntaxKind.Parameter;
case SyntaxKind.ClassKeyword:
case SyntaxKind.EnumKeyword:
case SyntaxKind.InterfaceKeyword:
case SyntaxKind.FunctionKeyword:
case SyntaxKind.VarKeyword:
case SyntaxKind.GetKeyword:
case SyntaxKind.SetKeyword:
case SyntaxKind.ImportKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.YieldKeyword:
case SyntaxKind.TypeKeyword: // type htm|
return true;
}
case SyntaxKind.ClassKeyword:
case SyntaxKind.EnumKeyword:
case SyntaxKind.InterfaceKeyword:
case SyntaxKind.FunctionKeyword:
case SyntaxKind.VarKeyword:
case SyntaxKind.GetKeyword:
case SyntaxKind.SetKeyword:
case SyntaxKind.ImportKeyword:
case SyntaxKind.LetKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.YieldKeyword:
case SyntaxKind.TypeKeyword: // type htm|
return true;
}
// Previous token may have been a keyword that was converted to an identifier.
switch (previousToken.getText()) {
case "class":
case "interface":
case "enum":
case "function":
case "var":
case "static":
case "let":
case "const":
case "yield":
return true;
}
// Previous token may have been a keyword that was converted to an identifier.
switch (contextToken.getText()) {
case "class":
case "interface":
case "enum":
case "function":
case "var":
case "static":
case "let":
case "const":
case "yield":
return true;
}
return false;
}
function isRightOfIllegalDot(previousToken: Node): boolean {
if (previousToken && previousToken.kind === SyntaxKind.NumericLiteral) {
let text = previousToken.getFullText();
function isDotOfNumericLiteral(contextToken: Node): boolean {
if (contextToken.kind === SyntaxKind.NumericLiteral) {
let text = contextToken.getFullText();
return text.charAt(text.length - 1) === ".";
}