Skip to content

Commit f2731e4

Browse files
Merge pull request #3757 from Microsoft/noImportClauseBuilders
Don't show builders in import clauses
2 parents 719498e + d353d62 commit f2731e4

File tree

4 files changed

+144
-91
lines changed

4 files changed

+144
-91
lines changed

src/services/services.ts

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,68 +3010,21 @@ namespace ts {
30103010
}
30113011

30123012
function tryGetGlobalSymbols(): boolean {
3013-
let objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken);
3014-
let jsxContainer = tryGetContainingJsxElement(contextToken);
3015-
if (objectLikeContainer) {
3016-
// We're looking up possible property names from contextual/inferred/declared type.
3017-
isMemberCompletion = true;
3018-
3019-
let typeForObject: Type;
3020-
let existingMembers: Declaration[];
3021-
3022-
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
3023-
// We are completing on contextual types, but may also include properties
3024-
// other than those within the declared type.
3025-
isNewIdentifierLocation = true;
3026-
3027-
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
3028-
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
3029-
}
3030-
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
3031-
// We are *only* completing on properties from the type being destructured.
3032-
isNewIdentifierLocation = false;
3033-
3034-
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
3035-
existingMembers = (<BindingPattern>objectLikeContainer).elements;
3036-
}
3037-
else {
3038-
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
3039-
}
3040-
3041-
if (!typeForObject) {
3042-
return false;
3043-
}
3013+
let objectLikeContainer: ObjectLiteralExpression | BindingPattern;
3014+
let importClause: ImportClause;
3015+
let jsxContainer: JsxOpeningLikeElement;
30443016

3045-
let typeMembers = typeChecker.getPropertiesOfType(typeForObject);
3046-
if (typeMembers && typeMembers.length > 0) {
3047-
// Add filtered items to the completion list
3048-
symbols = filterObjectMembersList(typeMembers, existingMembers);
3049-
}
3050-
return true;
3017+
if (objectLikeContainer = tryGetObjectLikeCompletionContainer(contextToken)) {
3018+
return tryGetObjectLikeCompletionSymbols(objectLikeContainer);
30513019
}
3052-
else if (getAncestor(contextToken, SyntaxKind.ImportClause)) {
3053-
// cursor is in import clause
3054-
// try to show exported member for imported module
3055-
isMemberCompletion = true;
3056-
isNewIdentifierLocation = true;
3057-
if (showCompletionsInImportsClause(contextToken)) {
3058-
let importDeclaration = <ImportDeclaration>getAncestor(contextToken, SyntaxKind.ImportDeclaration);
3059-
Debug.assert(importDeclaration !== undefined);
3060-
3061-
let exports: Symbol[];
3062-
if (importDeclaration.moduleSpecifier) {
3063-
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
3064-
if (moduleSpecifierSymbol) {
3065-
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
3066-
}
3067-
}
30683020

3069-
//let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
3070-
symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray;
3071-
}
3072-
return true;
3021+
if (importClause = <ImportClause>getAncestor(contextToken, SyntaxKind.ImportClause)) {
3022+
// cursor is in an import clause
3023+
// try to show exported member for imported module
3024+
return tryGetImportClauseCompletionSymbols(importClause);
30733025
}
3074-
else if (jsxContainer) {
3026+
3027+
if (jsxContainer = tryGetContainingJsxElement(contextToken)) {
30753028
let attrsType: Type;
30763029
if ((jsxContainer.kind === SyntaxKind.JsxSelfClosingElement) || (jsxContainer.kind === SyntaxKind.JsxOpeningElement)) {
30773030
// Cursor is inside a JSX self-closing element or opening element
@@ -3153,7 +3106,7 @@ namespace ts {
31533106
return result;
31543107
}
31553108

3156-
function showCompletionsInImportsClause(node: Node): boolean {
3109+
function shouldShowCompletionsInImportsClause(node: Node): boolean {
31573110
if (node) {
31583111
// import {|
31593112
// import {a,|
@@ -3251,6 +3204,86 @@ namespace ts {
32513204
return false;
32523205
}
32533206

3207+
/**
3208+
* Aggregates relevant symbols for completion in object literals and object binding patterns.
3209+
* Relevant symbols are stored in the captured 'symbols' variable.
3210+
*
3211+
* @returns true if 'symbols' was successfully populated; false otherwise.
3212+
*/
3213+
function tryGetObjectLikeCompletionSymbols(objectLikeContainer: ObjectLiteralExpression | BindingPattern): boolean {
3214+
// We're looking up possible property names from contextual/inferred/declared type.
3215+
isMemberCompletion = true;
3216+
3217+
let typeForObject: Type;
3218+
let existingMembers: Declaration[];
3219+
3220+
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
3221+
// We are completing on contextual types, but may also include properties
3222+
// other than those within the declared type.
3223+
isNewIdentifierLocation = true;
3224+
3225+
typeForObject = typeChecker.getContextualType(<ObjectLiteralExpression>objectLikeContainer);
3226+
existingMembers = (<ObjectLiteralExpression>objectLikeContainer).properties;
3227+
}
3228+
else if (objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern) {
3229+
// We are *only* completing on properties from the type being destructured.
3230+
isNewIdentifierLocation = false;
3231+
3232+
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
3233+
existingMembers = (<BindingPattern>objectLikeContainer).elements;
3234+
}
3235+
else {
3236+
Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);
3237+
}
3238+
3239+
if (!typeForObject) {
3240+
return false;
3241+
}
3242+
3243+
let typeMembers = typeChecker.getPropertiesOfType(typeForObject);
3244+
if (typeMembers && typeMembers.length > 0) {
3245+
// Add filtered items to the completion list
3246+
symbols = filterObjectMembersList(typeMembers, existingMembers);
3247+
}
3248+
return true;
3249+
}
3250+
3251+
/**
3252+
* Aggregates relevant symbols for completion in import clauses; for instance,
3253+
*
3254+
* import { $ } from "moduleName";
3255+
*
3256+
* Relevant symbols are stored in the captured 'symbols' variable.
3257+
*
3258+
* @returns true if 'symbols' was successfully populated; false otherwise.
3259+
*/
3260+
function tryGetImportClauseCompletionSymbols(importClause: ImportClause): boolean {
3261+
// cursor is in import clause
3262+
// try to show exported member for imported module
3263+
if (shouldShowCompletionsInImportsClause(contextToken)) {
3264+
isMemberCompletion = true;
3265+
isNewIdentifierLocation = false;
3266+
3267+
let importDeclaration = <ImportDeclaration>importClause.parent;
3268+
Debug.assert(importDeclaration !== undefined && importDeclaration.kind === SyntaxKind.ImportDeclaration);
3269+
3270+
let exports: Symbol[];
3271+
let moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importDeclaration.moduleSpecifier);
3272+
if (moduleSpecifierSymbol) {
3273+
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
3274+
}
3275+
3276+
//let exports = typeInfoResolver.getExportsOfImportDeclaration(importDeclaration);
3277+
symbols = exports ? filterModuleExports(exports, importDeclaration) : emptyArray;
3278+
}
3279+
else {
3280+
isMemberCompletion = false;
3281+
isNewIdentifierLocation = true;
3282+
}
3283+
3284+
return true;
3285+
}
3286+
32543287
/**
32553288
* Returns the immediate owning object literal or binding pattern of a context token,
32563289
* on the condition that one exists and that the context implies completion should be given.

tests/cases/fourslash/completionForExports.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
// @Filename: m1.ts
4+
////export var foo: number = 1;
5+
////export function bar() { return 10; }
6+
////export function baz() { return 10; }
7+
8+
// @Filename: m2.ts
9+
////import {/*1*/, /*2*/ from "m1"
10+
////import {/*3*/} from "m1"
11+
////import {foo,/*4*/ from "m1"
12+
////import {bar as /*5*/, /*6*/ from "m1"
13+
////import {foo, bar, baz as b,/*7*/} from "m1"
14+
function verifyCompletionAtMarker(marker: string, showBuilder: boolean, ...completions: string[]) {
15+
goTo.marker(marker);
16+
if (completions.length) {
17+
for (let completion of completions) {
18+
verify.completionListContains(completion);
19+
}
20+
}
21+
else {
22+
verify.completionListIsEmpty();
23+
}
24+
25+
if (showBuilder) {
26+
verify.completionListAllowsNewIdentifier();
27+
}
28+
else {
29+
verify.not.completionListAllowsNewIdentifier();
30+
}
31+
}
32+
33+
verifyCompletionAtMarker("1", /*showBuilder*/ false, "foo", "bar", "baz");
34+
verifyCompletionAtMarker("2", /*showBuilder*/ false, "foo", "bar", "baz");
35+
verifyCompletionAtMarker("3", /*showBuilder*/ false, "foo", "bar", "baz");
36+
verifyCompletionAtMarker("4", /*showBuilder*/ false, "bar", "baz");
37+
verifyCompletionAtMarker("5", /*showBuilder*/ true);
38+
verifyCompletionAtMarker("6", /*showBuilder*/ false, "foo", "baz");
39+
verifyCompletionAtMarker("7", /*showBuilder*/ false);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////declare module "M1" {
4+
//// export var V;
5+
////}
6+
////
7+
////declare module "M2" {
8+
//// import { /**/ } from "M1"
9+
////}
10+
11+
goTo.marker();
12+
verify.completionListContains("V");
13+
verify.not.completionListAllowsNewIdentifier();

0 commit comments

Comments
 (0)