Skip to content

Commit 5e20b29

Browse files
authored
Show tooltips on hover for type property definitions and type additional properties accesses (#13546)
Resolves #13461 Resolves #13398 There were a couple of scenarios where the LS was not showing hover tooltips for properties: * When hovering over a type property definition * When hovering over a property name that would match against a value's additional properties type There's no way to capture a description for an object's additional properties type, but the hover can at least show the expected type.
1 parent e7c4db3 commit 5e20b29

File tree

4 files changed

+210
-81
lines changed

4 files changed

+210
-81
lines changed

src/Bicep.Core.IntegrationTests/TypeSystem/Providers/ResourceTypeProviderFactoryTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public async Task ProviderNameAndVersionAreUsedAsCacheKeys()
3131
var (clientFactory, _) = RegistryHelper.CreateMockRegistryClients(repositoryNames.Select(name => (registry, $"{repositoryPath}/{name}")).ToArray());
3232

3333
var services = new ServiceBuilder()
34-
.WithFeatureOverrides(new(ExtensibilityEnabled: true, ProviderRegistry: true, DynamicTypeLoadingEnabled: true))
34+
.WithFeatureOverrides(new(TestContext, ExtensibilityEnabled: true, ProviderRegistry: true, DynamicTypeLoadingEnabled: true))
3535
.WithContainerRegistryClientFactory(clientFactory);
3636

3737
foreach (var repoName in repositoryNames)
@@ -46,7 +46,7 @@ public async Task ProviderNameAndVersionAreUsedAsCacheKeys()
4646
"main.bicep",
4747
@$"
4848
provider 'br:example.azurecr.io/test/provider/[email protected]' as foo
49-
49+
5050
module mod './mod.bicep' = {{
5151
name: 'mod'
5252
params: {{ }}

src/Bicep.Core/Semantics/SymbolHelper.cs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static class SymbolHelper
2121
// The decision to pass in getDeclaredTypeFunc as a lambda rather than the ITypeManager interface is deliberate.
2222
// We should be conscious about not introducing cyclic dependencies, as this code is also used within the type manager, but it only needs declared types.
2323

24-
static PropertySymbol? GetPropertySymbol(TypeSymbol? baseType, string property)
24+
static PropertySymbol? GetPropertySymbol(TypeSymbol? baseType, string property, bool useAdditionalPropertiesType)
2525
{
2626
if (baseType is null)
2727
{
@@ -37,12 +37,30 @@ public static class SymbolHelper
3737

3838
if (typeProperty is null)
3939
{
40+
if (useAdditionalPropertiesType)
41+
{
42+
return GetAdditionalPropertiesSymbol(baseType);
43+
}
44+
4045
return null;
4146
}
4247

4348
return new PropertySymbol(property, typeProperty.Description, typeProperty.TypeReference.Type);
4449
}
4550

51+
static PropertySymbol? GetAdditionalPropertiesSymbol(TypeSymbol? baseType)
52+
{
53+
if (baseType is null ||
54+
TypeAssignmentVisitor.UnwrapType(baseType) is not ObjectType objectType ||
55+
objectType.AdditionalPropertiesType is null ||
56+
objectType.AdditionalPropertiesFlags.HasFlag(TypePropertyFlags.FallbackProperty))
57+
{
58+
return null;
59+
}
60+
61+
return new PropertySymbol("*", string.Empty, objectType.AdditionalPropertiesType.Type);
62+
}
63+
4664
switch (syntax)
4765
{
4866
case InstanceFunctionCallSyntax ifc:
@@ -69,20 +87,33 @@ public static class SymbolHelper
6987
return null;
7088
}
7189
case InstanceParameterizedTypeInstantiationSyntax iptic:
72-
return GetPropertySymbol(getDeclaredTypeFunc(iptic.BaseExpression), iptic.PropertyName.IdentifierName);
90+
return GetPropertySymbol(getDeclaredTypeFunc(iptic.BaseExpression), iptic.PropertyName.IdentifierName, true);
7391
case PropertyAccessSyntax propertyAccess:
7492
{
7593
var baseType = getDeclaredTypeFunc(propertyAccess.BaseExpression);
7694
var property = propertyAccess.PropertyName.IdentifierName;
7795

78-
return GetPropertySymbol(baseType, property);
96+
return GetPropertySymbol(baseType, property, true);
7997
}
8098
case TypePropertyAccessSyntax typePropertyAccess:
8199
{
82100
var baseType = getDeclaredTypeFunc(typePropertyAccess.BaseExpression);
101+
if (baseType is not null)
102+
{
103+
baseType = TypeAssignmentVisitor.UnwrapType(baseType);
104+
}
83105
var property = typePropertyAccess.PropertyName.IdentifierName;
84106

85-
return GetPropertySymbol(baseType, property);
107+
return GetPropertySymbol(baseType, property, false);
108+
}
109+
case TypeAdditionalPropertiesAccessSyntax addlPropertiesAccess:
110+
{
111+
var baseType = getDeclaredTypeFunc(addlPropertiesAccess.BaseExpression);
112+
if (baseType is not null)
113+
{
114+
baseType = TypeAssignmentVisitor.UnwrapType(baseType);
115+
}
116+
return GetAdditionalPropertiesSymbol(baseType);
86117
}
87118
case ObjectPropertySyntax objectProperty:
88119
{
@@ -97,7 +128,25 @@ public static class SymbolHelper
97128
return null;
98129
}
99130

100-
return GetPropertySymbol(baseType, property);
131+
return GetPropertySymbol(baseType, property, true);
132+
}
133+
case ObjectTypePropertySyntax objectTypeProperty:
134+
{
135+
if (objectTypeProperty.TryGetKeyText() is not string propertyName || binder.GetParent(objectTypeProperty) is not SyntaxBase parentSyntax)
136+
{
137+
return null;
138+
}
139+
140+
return GetPropertySymbol(getDeclaredTypeFunc(parentSyntax), propertyName, false);
141+
}
142+
case ObjectTypeAdditionalPropertiesSyntax addlProperties:
143+
{
144+
if (binder.GetParent(addlProperties) is not SyntaxBase parentSyntax)
145+
{
146+
return null;
147+
}
148+
149+
return GetAdditionalPropertiesSymbol(getDeclaredTypeFunc(parentSyntax));
101150
}
102151
}
103152

0 commit comments

Comments
 (0)