internal VacuumSyntax(SyntaxBase syntax) : base(syntax) { }
public TypeSymbol GetTypeInfo(SyntaxBase syntax) => typeAssignmentVisitor.GetTypeInfo(syntax);
public DeclaredTypeAssignment?GetDeclaredTypeAssignment(SyntaxBase syntax) => declaredTypeManager.GetDeclaredTypeAssignment(syntax);
internal BySyntax(SyntaxBase syntax) : base(syntax) { }
private static string GetFunctionMarkdown(FunctionSymbol function, ImmutableArray <FunctionArgumentSyntax> arguments, SyntaxBase functionCall, SemanticModel model) { var buffer = new StringBuilder(); buffer.Append($"```bicep\nfunction "); buffer.Append(function.Name); buffer.Append('('); const string argumentSeparator = ", "; foreach (FunctionArgumentSyntax argumentSyntax in arguments) { var argumentType = model.GetTypeInfo(argumentSyntax); buffer.Append(argumentType); buffer.Append(argumentSeparator); } // remove trailing argument separator (if any) if (arguments.Length > 0) { buffer.Remove(buffer.Length - argumentSeparator.Length, argumentSeparator.Length); } buffer.Append("): "); buffer.Append(model.GetTypeInfo(functionCall)); buffer.Append("\n```"); return(buffer.ToString()); }
public static HashSet <DeclaredSymbol> GetResourceDependencies(SemanticModel semanticModel, SyntaxBase syntax) { var visitor = new ResourceDependencyFinderVisitor(semanticModel); visitor.Visit(syntax); return(visitor.resourceDependencies); }
/// <summary> /// Returns the symbol that was bound to the specified syntax node. Will return null for syntax nodes that never get bound to symbols. Otherwise, /// a symbol will always be returned. Binding failures are represented with a non-null error symbol. /// </summary> /// <param name="syntax">the syntax node</param> public Symbol?GetSymbolInfo(SyntaxBase syntax) => this.bindings.TryGetValue(syntax);
private static DocumentHighlight CreateExpectedHighlight(ImmutableArray<int> lineStarts, SyntaxBase syntax) => new DocumentHighlight { Range = PositionHelper.GetNameRange(lineStarts, syntax), Kind = GetExpectedHighlightKind(syntax) };
private static ScopeData?ValidateScope(SemanticModel semanticModel, LogInvalidScopeDiagnostic logInvalidScopeFunc, ResourceScope supportedScopes, SyntaxBase bodySyntax, ObjectPropertySyntax?scopeProperty) { if (scopeProperty is null) { // no scope provided - use the target scope for the file if (!supportedScopes.HasFlag(semanticModel.TargetScope)) { logInvalidScopeFunc(bodySyntax, semanticModel.TargetScope, supportedScopes); return(null); } return(null); } var scopeSymbol = scopeProperty.Value switch { // scope indexing can only happen with references to module or resource collections ArrayAccessSyntax { BaseExpression : VariableAccessSyntax baseVariableAccess } => semanticModel.GetSymbolInfo(baseVariableAccess),
public SyntaxItem(SyntaxBase syntax, int depth) { Syntax = syntax; Depth = depth; }
/// <summary> /// Converts the specified bicep expression tree into an ARM template expression tree. /// The returned tree may be rooted at either a function expression or jtoken expression. /// </summary> /// <param name="expression">The expression</param> public LanguageExpression ConvertExpression(SyntaxBase expression) { switch (expression) { case BooleanLiteralSyntax boolSyntax: return(CreateFunction(boolSyntax.Value ? "true" : "false")); case NumericLiteralSyntax numericSyntax: return(new JTokenExpression(numericSyntax.Value)); case StringSyntax stringSyntax: // using the throwing method to get semantic value of the string because // error checking should have caught any errors by now return(ConvertString(stringSyntax)); case NullLiteralSyntax _: return(CreateFunction("null")); case ObjectSyntax @object: return(ConvertObject(@object)); case ArraySyntax array: return(ConvertArray(array)); case ParenthesizedExpressionSyntax parenthesized: // template expressions do not have operators so parentheses are irrelevant return(ConvertExpression(parenthesized.Expression)); case UnaryOperationSyntax unary: return(ConvertUnary(unary)); case BinaryOperationSyntax binary: return(ConvertBinary(binary)); case TernaryOperationSyntax ternary: return(CreateFunction( "if", ConvertExpression(ternary.ConditionExpression), ConvertExpression(ternary.TrueExpression), ConvertExpression(ternary.FalseExpression))); case FunctionCallSyntax function: return(ConvertFunction( function.Name.IdentifierName, function.Arguments.Select(a => ConvertExpression(a.Expression)))); case InstanceFunctionCallSyntax instanceFunctionCall: var namespaceSymbol = context.SemanticModel.GetSymbolInfo(instanceFunctionCall.BaseExpression); Assert(namespaceSymbol is NamespaceSymbol, $"BaseExpression must be a NamespaceSymbol, instead got: '{namespaceSymbol?.Kind}'"); return(ConvertFunction( instanceFunctionCall.Name.IdentifierName, instanceFunctionCall.Arguments.Select(a => ConvertExpression(a.Expression)))); case ArrayAccessSyntax arrayAccess: return(AppendProperties( ToFunctionExpression(arrayAccess.BaseExpression), ConvertExpression(arrayAccess.IndexExpression))); case PropertyAccessSyntax propertyAccess: if (propertyAccess.BaseExpression is VariableAccessSyntax propVariableAccess && context.SemanticModel.GetSymbolInfo(propVariableAccess) is ResourceSymbol resourceSymbol) { // special cases for certain resource property access. if we recurse normally, we'll end up // generating statements like reference(resourceId(...)).id which are not accepted by ARM var typeReference = EmitHelpers.GetTypeReference(resourceSymbol); switch (propertyAccess.PropertyName.IdentifierName) { case "id": return(GetLocallyScopedResourceId(resourceSymbol)); case "name": return(GetResourceNameExpression(resourceSymbol)); case "type": return(new JTokenExpression(typeReference.FullyQualifiedType)); case "apiVersion": return(new JTokenExpression(typeReference.ApiVersion)); case "properties": // use the reference() overload without "full" to generate a shorter expression return(GetReferenceExpression(resourceSymbol, typeReference, false)); } } var moduleAccess = TryGetModulePropertyAccess(propertyAccess); if (moduleAccess != null) { var(moduleSymbol, outputName) = moduleAccess.Value; return(AppendProperties( GetModuleOutputsReferenceExpression(moduleSymbol), new JTokenExpression(outputName), new JTokenExpression("value"))); } return(AppendProperties( ToFunctionExpression(propertyAccess.BaseExpression), new JTokenExpression(propertyAccess.PropertyName.IdentifierName))); case VariableAccessSyntax variableAccess: return(ConvertVariableAccess(variableAccess)); default: throw new NotImplementedException($"Cannot emit unexpected expression of type {expression.GetType().Name}"); } }
public SyntaxBase?GetParent(SyntaxBase syntax) => typeAssignmentVisitor.GetParent(syntax);
public DeployTimeConstantDirectViolationVisitor(SyntaxBase deployTimeConstantContainer, SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter, Dictionary <DeclaredSymbol, ObjectType> existingResourceBodyObjectTypeOverrides) : base(deployTimeConstantContainer, semanticModel, diagnosticWriter, existingResourceBodyObjectTypeOverrides) { }
public SyntaxBase?GetParent(SyntaxBase syntax) => syntaxTree.Hierarchy.GetParent(syntax);
private static TypeSymbol NarrowTypeInternal(ITypeManager typeManager, SyntaxBase expression, TypeSymbol targetType, IDiagnosticWriter diagnosticWriter, TypeMismatchErrorFactory typeMismatchErrorFactory, bool skipConstantCheck, bool skipTypeErrors) { if (targetType is ResourceType targetResourceType) { // When assigning a resource, we're really assigning the value of the resource body. var narrowedBody = NarrowTypeInternal(typeManager, expression, targetResourceType.Body.Type, diagnosticWriter, typeMismatchErrorFactory, skipConstantCheck, skipTypeErrors); return(new ResourceType(targetResourceType.TypeReference, narrowedBody)); } if (targetType is ModuleType targetModuleType) { var narrowedBody = NarrowTypeInternal(typeManager, expression, targetModuleType.Body.Type, diagnosticWriter, typeMismatchErrorFactory, skipConstantCheck, skipTypeErrors); return(new ModuleType(targetModuleType.Name, narrowedBody)); } // TODO: The type of this expression and all subexpressions should be cached var expressionType = typeManager.GetTypeInfo(expression); // since we dynamically checked type, we need to collect the errors but only if the caller wants them if (skipTypeErrors == false && expressionType is ErrorType) { diagnosticWriter.WriteMultiple(expressionType.GetDiagnostics()); return(targetType); } // basic assignability check if (AreTypesAssignable(expressionType, targetType) == false) { // fundamentally different types - cannot assign diagnosticWriter.Write(typeMismatchErrorFactory(targetType, expressionType, expression)); return(targetType); } // object assignability check if (expression is ObjectSyntax objectValue && targetType is ObjectType targetObjectType) { return(NarrowObjectType(typeManager, objectValue, targetObjectType, diagnosticWriter, skipConstantCheck)); } if (expression is ObjectSyntax objectDiscriminated && targetType is DiscriminatedObjectType targetDiscriminated) { return(NarrowDiscriminatedObjectType(typeManager, objectDiscriminated, targetDiscriminated, diagnosticWriter, skipConstantCheck)); } // array assignability check if (expression is ArraySyntax arrayValue && targetType is ArrayType targetArrayType) { return(NarrowArrayAssignmentType(typeManager, arrayValue, targetArrayType, diagnosticWriter, skipConstantCheck)); } if (targetType is UnionType targetUnionType) { return(UnionType.Create(targetUnionType.Members.Where(x => AreTypesAssignable(expressionType, x.Type) == true))); } return(targetType); }
public TypeSymbol?GetDeclaredType(SyntaxBase syntax) => typeAssignmentVisitor.GetDeclaredType(syntax);
/// <summary> /// Gets the list of compile-time constant violations. An error is logged for every occurrence of an expression that is not entirely composed of literals. /// It may return inaccurate results for malformed trees. /// </summary> /// <param name="expression">the expression to check for compile-time constant violations</param> /// <param name="diagnosticWriter">Diagnostic writer instance</param> public static void GetCompileTimeConstantViolation(SyntaxBase expression, IDiagnosticWriter diagnosticWriter) { var visitor = new CompileTimeConstantVisitor(diagnosticWriter); visitor.Visit(expression); }
public DeclaredTypeAssignment?GetDeclaredTypeAssignment(SyntaxBase syntax) => typeAssignmentVisitor.GetDeclaredTypeAssignment(syntax);
public SyntaxBase?GetParent(SyntaxBase syntax) => bicepFile.Hierarchy.GetParent(syntax);
public LanguageExpression GetManagementGroupResourceId(SyntaxBase managementGroupNameProperty, bool fullyQualified) => converter.GenerateManagementGroupResourceId(managementGroupNameProperty, fullyQualified);
public static SyntaxTrivia?TryFindMostSpecificTriviaInclusive(this SyntaxBase root, int offset, Func <SyntaxTrivia, bool> predicate) => TryFindMostSpecificTriviaInternal(root, offset, predicate, inclusive: true);
public void EmitProperty(string name, SyntaxBase expressionValue) => EmitPropertyInternal(new JTokenExpression(name), expressionValue);
public ResourceSymbol(ISymbolContext context, string name, ResourceDeclarationSyntax declaringSyntax, SyntaxBase body) : base(context, name, declaringSyntax, declaringSyntax.Name) { this.Body = body; }
public void EmitProperty(SyntaxBase syntaxKey, SyntaxBase syntaxValue) => EmitPropertyInternal(converter.ConvertExpression(syntaxKey), syntaxValue);
protected override SyntaxBase ReplaceResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) { if (syntax.TryGetBody() is not ObjectSyntax resourceBody || resourceBody.SafeGetPropertyByName("name") is not ObjectPropertySyntax resourceNameProp || resourceNameProp.Value is not StringSyntax resourceName) { return(syntax); } if (semanticModel.GetSymbolInfo(syntax) is not ResourceSymbol resourceSymbol || resourceSymbol.Type is not ResourceType resourceType) { return(syntax); } if (resourceType.TypeReference.Types.Length < 2) { // we're only looking for child resources here return(syntax); } foreach (var otherResourceSymbol in semanticModel.Root.GetAllResourceDeclarations()) { if (otherResourceSymbol.Type is not ResourceType otherResourceType || otherResourceType.TypeReference.Types.Length != resourceType.TypeReference.Types.Length - 1 || !resourceType.TypeReference.TypesString.StartsWith($"{otherResourceType.TypeReference.TypesString}/", StringComparison.OrdinalIgnoreCase)) { continue; } // The other resource is a parent type to this one. check if we can refactor the name. if (otherResourceSymbol.DeclaringResource.TryGetBody() is not ObjectSyntax otherResourceBody || otherResourceBody.SafeGetPropertyByName("name") is not ObjectPropertySyntax otherResourceNameProp) { continue; } if (TryGetReplacementChildName(resourceName, otherResourceNameProp.Value, otherResourceSymbol) is not { } newName) { continue; } var replacementNameProp = new ObjectPropertySyntax(resourceNameProp.Key, resourceNameProp.Colon, newName); var parentProp = new ObjectPropertySyntax( SyntaxFactory.CreateIdentifier(LanguageConstants.ResourceParentPropertyName), SyntaxFactory.ColonToken, SyntaxFactory.CreateVariableAccess(otherResourceSymbol.Name)); var replacementBody = new ObjectSyntax( resourceBody.OpenBrace, // parent prop comes first! parentProp.AsEnumerable().Concat(resourceBody.Children.Replace(resourceNameProp, replacementNameProp)), resourceBody.CloseBrace); // at the top we just checked if there is a legitimate body // but to do the replacement correctly we may need to wrap it inside an IfConditionSyntax SyntaxBase replacementValue = syntax.Value switch { ObjectSyntax => replacementBody, IfConditionSyntax ifCondition => new IfConditionSyntax(ifCondition.Keyword, ifCondition.ConditionExpression, replacementBody), // should not be possible _ => throw new NotImplementedException($"Unexpected resource value type '{syntax.Value.GetType().Name}'.") }; return(new ResourceDeclarationSyntax( syntax.LeadingNodes, syntax.Keyword, syntax.Name, syntax.Type, syntax.ExistingKeyword, syntax.Assignment, replacementValue)); } return(syntax); }
private void EmitPropertyInternal(LanguageExpression expressionKey, SyntaxBase syntaxValue) => EmitPropertyInternal(expressionKey, () => EmitExpression(syntaxValue));
public TypeSymbol?GetDeclaredType(SyntaxBase syntax) => declaredTypeManager.GetDeclaredType(syntax);
public static TypeSymbol NarrowTypeAndCollectDiagnostics(ITypeManager typeManager, SyntaxBase expression, TypeSymbol targetType, IDiagnosticWriter diagnosticWriter) { // generic error creator if a better one was not specified. TypeMismatchErrorFactory typeMismatchErrorFactory = (expectedType, actualType, errorExpression) => DiagnosticBuilder.ForPosition(errorExpression).ExpectedValueTypeMismatch(ShouldWarn(targetType), expectedType, actualType); return(NarrowTypeInternal(typeManager, expression, targetType, diagnosticWriter, typeMismatchErrorFactory, skipConstantCheck: false, skipTypeErrors: false)); }
public ExpressionConverter CreateConverterForIndexReplacement(SyntaxBase nameSyntax, SyntaxBase?indexExpression, SyntaxBase newContext) { var inaccessibleLocals = this.context.DataFlowAnalyzer.GetInaccessibleLocalsAfterSyntaxMove(nameSyntax, newContext); var inaccessibleLocalLoops = inaccessibleLocals.Select(local => GetEnclosingForExpression(local)).Distinct().ToList(); switch (inaccessibleLocalLoops.Count) { case 0: // moving the name expression does not produce any inaccessible locals (no locals means no loops) // regardless if there is an index expression or not, we don't need to append replacements return(this); case 1 when indexExpression != null: // TODO: Run data flow analysis on the array expression as well. (Will be needed for nested resource loops) var @for = inaccessibleLocalLoops.Single(); var current = this; foreach (var local in inaccessibleLocals) { var replacementValue = GetLoopVariableExpression(local, @for, this.ConvertExpression(indexExpression)); current = current.AppendReplacement(local, replacementValue); } return(current); default: throw new NotImplementedException("Mismatch between count of index expressions and inaccessible symbols during array access index replacement."); } }
public void EmitPropertyExpressionWithExpressionKey(SyntaxBase expressionKey, SyntaxBase expressionValue) { var keyExpression = converter.ConvertExpression(expressionKey); var keyText = ExpressionSerializer.SerializeExpression(keyExpression); EmitPropertyExpression(keyText, expressionValue); }