Merge pull request #3757 from Microsoft/noImportClauseBuilders

Don't show builders in import clauses
This commit is contained in:
Daniel Rosenwasser 2015-07-07 14:45:39 -07:00
commit f2731e4033
4 changed files with 144 additions and 91 deletions

View file

@ -3010,68 +3010,21 @@ namespace ts {
} }
function tryGetGlobalSymbols(): boolean { function tryGetGlobalSymbols(): boolean {
let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken); let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
let jsxContainer = tryGetContainingJsxElement(contextToken); let importClause: ImportClause;
if (objectLikeContainer) { let jsxContainer: JsxOpeningLikeElement;
// We're looking up possible property names from contextual/inferred/declared type.
isMemberCompletion = true;
let typeForObject: Type; if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
let existingMembers: Declaration[]; return tryGetObjectLikeCompletionSymbols(objectLikeContainer);
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;
} }
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 // try to show exported member for imported module
isMemberCompletion = true; return tryGetImportClauseCompletionSymbols(importClause);
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;
} }
else if (jsxContainer) {
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
let attrsType: Type; let attrsType: Type;
if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) { if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) {
// Cursor is inside a JSX self-closing element or opening element // Cursor is inside a JSX self-closing element or opening element
@ -3153,7 +3106,7 @@ namespace ts {
return result; return result;
} }
function showCompletionsInImportsClause(node: Node): boolean { function shouldShowCompletionsInImportsClause(node: Node): boolean {
if (node) { if (node) {
// import {| // import {|
// import {a,| // import {a,|
@ -3251,6 +3204,86 @@ namespace ts {
return false; 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, * 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. * on the condition that one exists and that the context implies completion should be given.

View file

@ -1,32 +0,0 @@
/// <reference path='fourslash.ts'/>
// @Filename: m1.ts
////export var foo: number = 1;
////export function bar() { return 10; }
////export function baz() { return 10; }
// @Filename: m2.ts
////import {/*1*/, /*2*/ from "m1"
////import {/*3*/} from "m1"
////import {foo,/*4*/ from "m1"
////import {bar as /*5*/, /*6*/ from "m1"
////import {foo, bar, baz as b,/*7*/} from "m1"
function verifyCompletionAtMarker(marker: string, ...completions: string[]) {
goTo.marker(marker);
if (completions.length) {
for (var i = 0; i < completions.length; ++i) {
verify.completionListContains(completions[i]);
}
}
else {
verify.completionListIsEmpty();
}
}
verifyCompletionAtMarker("1", "foo", "bar", "baz");
verifyCompletionAtMarker("2", "foo", "bar", "baz");
verifyCompletionAtMarker("3", "foo", "bar", "baz");
verifyCompletionAtMarker("4", "bar", "baz");
verifyCompletionAtMarker("5");
verifyCompletionAtMarker("6", "foo", "baz");
verifyCompletionAtMarker("7");

View file

@ -0,0 +1,39 @@
/// <reference path='fourslash.ts'/>
// @Filename: m1.ts
////export var foo: number = 1;
////export function bar() { return 10; }
////export function baz() { return 10; }
// @Filename: m2.ts
////import {/*1*/, /*2*/ from "m1"
////import {/*3*/} from "m1"
////import {foo,/*4*/ from "m1"
////import {bar as /*5*/, /*6*/ from "m1"
////import {foo, bar, baz as b,/*7*/} from "m1"
function verifyCompletionAtMarker(marker: string, showBuilder: boolean, ...completions: string[]) {
goTo.marker(marker);
if (completions.length) {
for (let completion of completions) {
verify.completionListContains(completion);
}
}
else {
verify.completionListIsEmpty();
}
if (showBuilder) {
verify.completionListAllowsNewIdentifier();
}
else {
verify.not.completionListAllowsNewIdentifier();
}
}
verifyCompletionAtMarker("1", /*showBuilder*/ false, "foo", "bar", "baz");
verifyCompletionAtMarker("2", /*showBuilder*/ false, "foo", "bar", "baz");
verifyCompletionAtMarker("3", /*showBuilder*/ false, "foo", "bar", "baz");
verifyCompletionAtMarker("4", /*showBuilder*/ false, "bar", "baz");
verifyCompletionAtMarker("5", /*showBuilder*/ true);
verifyCompletionAtMarker("6", /*showBuilder*/ false, "foo", "baz");
verifyCompletionAtMarker("7", /*showBuilder*/ false);

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts'/>
////declare module "M1" {
//// export var V;
////}
////
////declare module "M2" {
//// import { /**/ } from "M1"
////}
goTo.marker();
verify.completionListContains("V");
verify.not.completionListAllowsNewIdentifier();