From a493ea9bcb2a1d94481d30e41db8b0bdf235ab42 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Thu, 3 Jun 2021 15:15:16 -0700 Subject: [PATCH] fix(language-service): fix autocomplete info display for some cases (#42472) Before this commit, attribute completion display parts were retrieved but not assigned. In addition, the switch case was non-exhaustive because it did not include `StructuralDirectiveAttribute`. PR Close #42472 --- packages/language-service/ivy/completions.ts | 17 ++++++++++++----- packages/language-service/ivy/display_parts.ts | 5 ++++- .../ivy/test/completions_spec.ts | 4 ++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/language-service/ivy/completions.ts b/packages/language-service/ivy/completions.ts index 2b72fefc833..212e461c684 100644 --- a/packages/language-service/ivy/completions.ts +++ b/packages/language-service/ivy/completions.ts @@ -579,6 +579,7 @@ export class CompletionBuilder { displayParts = info.displayParts; documentation = info.documentation; break; + case AttributeCompletionKind.StructuralDirectiveAttribute: case AttributeCompletionKind.DirectiveInput: case AttributeCompletionKind.DirectiveOutput: const propertySymbol = getAttributeCompletionSymbol(completion, this.typeChecker); @@ -586,11 +587,17 @@ export class CompletionBuilder { return undefined; } + let kind: DisplayInfoKind; + if (completion.kind === AttributeCompletionKind.DirectiveInput) { + kind = DisplayInfoKind.PROPERTY; + } else if (completion.kind === AttributeCompletionKind.DirectiveOutput) { + kind = DisplayInfoKind.EVENT; + } else { + kind = DisplayInfoKind.DIRECTIVE; + } + info = getTsSymbolDisplayInfo( - this.tsLS, this.typeChecker, propertySymbol, - completion.kind === AttributeCompletionKind.DirectiveInput ? DisplayInfoKind.PROPERTY : - DisplayInfoKind.EVENT, - completion.directive.tsSymbol.name); + this.tsLS, this.typeChecker, propertySymbol, kind, completion.directive.tsSymbol.name); if (info === null) { return undefined; } @@ -602,7 +609,7 @@ export class CompletionBuilder { name: entryName, kind: unsafeCastDisplayInfoKindToScriptElementKind(kind), kindModifiers: ts.ScriptElementKindModifier.none, - displayParts: [], + displayParts, documentation, }; } diff --git a/packages/language-service/ivy/display_parts.ts b/packages/language-service/ivy/display_parts.ts index fefda80e9c7..f948286bd39 100644 --- a/packages/language-service/ivy/display_parts.ts +++ b/packages/language-service/ivy/display_parts.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {isNamedClassDeclaration} from '@angular/compiler-cli/src/ngtsc/reflection'; import {DirectiveInScope, ReferenceSymbol, ShimLocation, Symbol, SymbolKind, VariableSymbol} from '@angular/compiler-cli/src/ngtsc/typecheck/api'; import * as ts from 'typescript'; @@ -155,7 +156,9 @@ export function getTsSymbolDisplayInfo( tsLS: ts.LanguageService, checker: ts.TypeChecker, symbol: ts.Symbol, kind: DisplayInfoKind, ownerName: string|null): DisplayInfo|null { const decl = symbol.valueDeclaration; - if (decl === undefined || (!ts.isPropertyDeclaration(decl) && !ts.isMethodDeclaration(decl)) || + if (decl === undefined || + (!ts.isPropertyDeclaration(decl) && !ts.isMethodDeclaration(decl) && + !isNamedClassDeclaration(decl)) || !ts.isIdentifier(decl.name)) { return null; } diff --git a/packages/language-service/ivy/test/completions_spec.ts b/packages/language-service/ivy/test/completions_spec.ts index 5fa39aa5c8e..f4cb8513b40 100644 --- a/packages/language-service/ivy/test/completions_spec.ts +++ b/packages/language-service/ivy/test/completions_spec.ts @@ -586,6 +586,10 @@ describe('completions', () => { unsafeCastDisplayInfoKindToScriptElementKind(DisplayInfoKind.DIRECTIVE), ['ngFor']); expectReplacementText(completions, templateFile.contents, 'ng'); + const details = templateFile.getCompletionEntryDetails( + 'ngFor', /* formatOptions */ undefined, + /* preferences */ undefined)!; + expect(toText(details.displayParts)).toEqual('(directive) NgFor.NgFor: NgFor'); }); it('should return structural directive completions for just the structural marker', () => {