From 3b5f24557e6f7a7f2ad0430167c4fe907954b016 Mon Sep 17 00:00:00 2001 From: Jonny Eskew Date: Wed, 4 Oct 2023 14:08:45 -0400 Subject: [PATCH] Provide a declared type for imported variable accesses to enable completions (#12050) Resolves #12049 The CompletionProvider always queries the *declared* type (rather than the assigned type) of expressions when supplying completions. Since we supply a declared type for variable accesses (even though variables have no type declaration), it makes sense to do so for imported variables as well. ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/12050) --- .../TypeSystem/DeclaredTypeManager.cs | 8 ++- .../CompletionTests.cs | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs b/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs index ca7bb116c2c..f150a333206 100644 --- a/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs +++ b/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs @@ -964,9 +964,11 @@ private DeclaredTypeAssignment GetTestType(TestDeclarationSyntax syntax) var variableType = this.typeManager.GetTypeInfo(variableSymbol.DeclaringVariable.Value); return new DeclaredTypeAssignment(variableType, variableSymbol.DeclaringVariable); - case WildcardImportSymbol wildcardImportSymbol when IsCycleFree(wildcardImportSymbol): - var wildcardImportType = this.typeManager.GetTypeInfo(wildcardImportSymbol.DeclaringSyntax); - return new DeclaredTypeAssignment(wildcardImportType, declaringSyntax: null); + case ImportedSymbol importedSymbol when importedSymbol.Kind == SymbolKind.Variable: + return new DeclaredTypeAssignment(importedSymbol.Type, declaringSyntax: null); + + case WildcardImportSymbol wildcardImportSymbol: + return new DeclaredTypeAssignment(wildcardImportSymbol.Type, declaringSyntax: null); case DeclaredSymbol declaredSymbol when IsCycleFree(declaredSymbol): // the syntax node is referencing a declared symbol diff --git a/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs b/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs index 3e664fd22a2..a06a82e70b6 100644 --- a/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs +++ b/src/Bicep.LangServer.IntegrationTests/CompletionTests.cs @@ -4443,5 +4443,65 @@ [new Uri("file:///mod2.bicep")] = mod2Content, completions.Should().Contain(c => c.Label == "mod2.buzz"); } } + + [TestMethod] + public async Task Compile_time_imports_offer_imported_symbol_property_completions() + { + var modContent = """ + @export() + var foo = { + bar: 'bar' + baz: 'baz' + } + """; + + var mod2Content = """ + @export() + var fizz = { + buzz: 'buzz' + pop: 'pop' + } + """; + + var mainContent = """ + import {foo} from 'mod.bicep' + import {fizz} from 'mod2.bicep' + + output obj object = { + bar: foo.| + pop: fizz.| + } + """; + + var (text, cursors) = ParserHelper.GetFileWithCursors(mainContent, '|'); + Uri mainUri = new Uri("file:///main.bicep"); + var files = new Dictionary + { + [new Uri("file:///mod.bicep")] = modContent, + [new Uri("file:///mod2.bicep")] = mod2Content, + [mainUri] = text + }; + + var bicepFile = SourceFileFactory.CreateBicepFile(mainUri, text); + using var helper = await LanguageServerHelper.StartServerWithText( + this.TestContext, + files, + bicepFile.FileUri, + services => services.WithFeatureOverrides(new(CompileTimeImportsEnabled: true))); + + var file = new FileRequestHelper(helper.Client, bicepFile); + + var completions = await file.RequestCompletion(cursors[0]); + completions.Should().Contain(c => c.Label == "bar"); + completions.Should().Contain(c => c.Label == "baz"); + completions.Should().NotContain(c => c.Label == "buzz"); + completions.Should().NotContain(c => c.Label == "pop"); + + completions = await file.RequestCompletion(cursors[1]); + completions.Should().Contain(c => c.Label == "buzz"); + completions.Should().Contain(c => c.Label == "pop"); + completions.Should().NotContain(c => c.Label == "bar"); + completions.Should().NotContain(c => c.Label == "baz"); + } } }