public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) { this.ValidateDirectAccessToResourceOrModuleCollection(syntax); // visit children base.VisitResourceAccessSyntax(syntax); }
public async Task HoveringOverSymbolReferencesAndDeclarationsShouldProduceHovers(DataSet dataSet) { var compilation = dataSet.CopyFilesAndCreateCompilation(TestContext, out _, out var fileUri); var uri = DocumentUri.From(fileUri); var client = await IntegrationTestHelper.StartServerWithTextAsync(this.TestContext, dataSet.Bicep, uri, resourceTypeProvider : AzResourceTypeProvider.CreateWithAzTypes(), fileResolver : BicepTestConstants.FileResolver); var symbolTable = compilation.ReconstructSymbolTable(); var lineStarts = compilation.SyntaxTreeGrouping.EntryPoint.LineStarts; var symbolReferences = SyntaxAggregator.Aggregate( compilation.SyntaxTreeGrouping.EntryPoint.ProgramSyntax, new List <SyntaxBase>(), (accumulated, node) => { if (node is ISymbolReference || node is ITopLevelNamedDeclarationSyntax) { accumulated.Add(node); } return(accumulated); }, accumulated => accumulated); foreach (var symbolReference in symbolReferences) { // by default, request a hover on the first character of the syntax, but for certain syntaxes, this doesn't make sense. // for example on an instance function call 'az.resourceGroup()', it only makes sense to request a hover on the 3rd character. var nodeForHover = symbolReference switch { ITopLevelDeclarationSyntax d => d.Keyword, ResourceAccessSyntax r => r.ResourceName, FunctionCallSyntaxBase f => f.Name, _ => symbolReference, }; var hover = await client.RequestHover(new HoverParams { TextDocument = new TextDocumentIdentifier(uri), Position = TextCoordinateConverter.GetPosition(lineStarts, nodeForHover.Span.Position) }); // fancy method to give us some annotated source code to look at if any assertions fail :) using (new AssertionScope().WithVisualCursor(compilation.SyntaxTreeGrouping.EntryPoint, nodeForHover.Span.ToZeroLengthSpan())) { if (!symbolTable.TryGetValue(symbolReference, out var symbol)) { if (symbolReference is InstanceFunctionCallSyntax && compilation.GetEntrypointSemanticModel().GetSymbolInfo(symbolReference) is FunctionSymbol ifcSymbol) { ValidateHover(hover, ifcSymbol); break; } // symbol ref not bound to a symbol hover.Should().BeNull(); continue; } switch (symbol !.Kind) {
private DeclaredTypeAssignment?GetResourceAccessType(ResourceAccessSyntax syntax) { if (!syntax.ResourceName.IsValid) { return(null); } // We should already have a symbol, use its type. var symbol = this.binder.GetSymbolInfo(syntax); if (symbol == null) { throw new InvalidOperationException("ResourceAccessSyntax was not assigned a symbol during name binding."); } if (symbol is ErrorSymbol error) { return(new DeclaredTypeAssignment(ErrorType.Create(error.GetDiagnostics()), syntax)); } else if (symbol is not ResourceSymbol resourceSymbol) { var baseType = GetDeclaredType(syntax.BaseExpression); var typeString = baseType?.Kind.ToString() ?? LanguageConstants.ErrorName; return(new DeclaredTypeAssignment(ErrorType.Create(DiagnosticBuilder.ForPosition(syntax.ResourceName).ResourceRequiredForResourceAccess(typeString)), syntax)); }
public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) { if (!currentDeclarations.TryPeek(out var currentDeclaration)) { // we're not inside a declaration, so there should be no risk of a cycle return; } declarationAccessDict[currentDeclaration].Add(syntax); base.VisitResourceAccessSyntax(syntax); }
public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) { base.VisitResourceAccessSyntax(syntax); // we need to resolve which resource delaration the LHS is pointing to - and then // validate that we can resolve the name. this.bindings.TryGetValue(syntax.BaseExpression, out var symbol); if (symbol is ErrorSymbol) { this.bindings.Add(syntax, symbol); return; } else if (symbol is null || symbol is not ResourceSymbol) { // symbol could be null in the case of an incomplete expression during parsing like `a:` var error = new ErrorSymbol(DiagnosticBuilder.ForPosition(syntax.ResourceName).ResourceRequiredForResourceAccess(symbol?.Kind.ToString() ?? LanguageConstants.ErrorName)); this.bindings.Add(syntax, error); return; } // This is the symbol of LHS and it's a valid resource. var resourceSymbol = (ResourceSymbol)symbol; var resourceBody = resourceSymbol.DeclaringResource.TryGetBody(); if (resourceBody == null) { // If we have no body then there will be nothing to reference. var error = new ErrorSymbol(DiagnosticBuilder.ForPosition(syntax.ResourceName).NestedResourceNotFound(resourceSymbol.Name, syntax.ResourceName.IdentifierName, nestedResourceNames: new [] { "(none)", })); this.bindings.Add(syntax, error); return; } if (!this.allLocalScopes.TryGetValue(resourceBody, out var localScope)) { // code defect in the declaration visitor throw new InvalidOperationException($"Local scope is missing for {syntax.GetType().Name} at {syntax.Span}"); } var referencedResource = LookupResourceSymbolByName(localScope, syntax.ResourceName); if (referencedResource is null) { var nestedResourceNames = localScope.Declarations.OfType <ResourceSymbol>().Select(r => r.Name); var error = new ErrorSymbol(DiagnosticBuilder.ForPosition(syntax.ResourceName).NestedResourceNotFound(resourceSymbol.Name, syntax.ResourceName.IdentifierName, nestedResourceNames)); this.bindings.Add(syntax, error); return; } // This is valid. this.bindings.Add(syntax, referencedResource); }
public async Task HoveringOverSymbolReferencesAndDeclarationsShouldProduceHovers(DataSet dataSet) { var uri = DocumentUri.From($"/{dataSet.Name}"); var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri, resourceTypeProvider : new AzResourceTypeProvider(new TypeLoader())); // construct a parallel compilation var compilation = dataSet.CopyFilesAndCreateCompilation(TestContext, out _); var symbolTable = compilation.ReconstructSymbolTable(); var lineStarts = compilation.SyntaxTreeGrouping.EntryPoint.LineStarts; var symbolReferences = SyntaxAggregator.Aggregate( compilation.SyntaxTreeGrouping.EntryPoint.ProgramSyntax, new List <SyntaxBase>(), (accumulated, node) => { if (node is ISymbolReference || node is ITopLevelNamedDeclarationSyntax) { accumulated.Add(node); } return(accumulated); }, accumulated => accumulated); foreach (SyntaxBase symbolReference in symbolReferences) { var nodeForHover = symbolReference switch { ITopLevelDeclarationSyntax d => d.Keyword, ResourceAccessSyntax r => r.ResourceName, _ => symbolReference, }; var hover = await client.RequestHover(new HoverParams { TextDocument = new TextDocumentIdentifier(uri), Position = PositionHelper.GetPosition(lineStarts, nodeForHover.Span.Position) }); // fancy method to give us some annotated source code to look at if any assertions fail :) using (CreateAssertionScopeWithContext(compilation.SyntaxTreeGrouping.EntryPoint, hover, nodeForHover.Span.ToZeroLengthSpan())) { if (symbolTable.TryGetValue(symbolReference, out var symbol) == false) { // symbol ref not bound to a symbol hover.Should().BeNull(); continue; } switch (symbol !.Kind) {
public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) => this.BuildWithConcat(() => base.VisitResourceAccessSyntax(syntax));
public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) { this.buffer.Append('('); base.VisitResourceAccessSyntax(syntax); this.buffer.Append(')'); }