Пример #1
0
 internal VacuumSyntax(SyntaxBase syntax)
     : base(syntax)
 {
 }
Пример #2
0
 public TypeSymbol GetTypeInfo(SyntaxBase syntax)
 => typeAssignmentVisitor.GetTypeInfo(syntax);
Пример #3
0
 public DeclaredTypeAssignment?GetDeclaredTypeAssignment(SyntaxBase syntax)
 => declaredTypeManager.GetDeclaredTypeAssignment(syntax);
Пример #4
0
 internal BySyntax(SyntaxBase syntax)
     : base(syntax)
 {
 }
Пример #5
0
        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);
        }
Пример #7
0
 /// <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);
Пример #8
0
 private static DocumentHighlight CreateExpectedHighlight(ImmutableArray<int> lineStarts, SyntaxBase syntax) =>
     new DocumentHighlight
     {
         Range = PositionHelper.GetNameRange(lineStarts, syntax),
         Kind = GetExpectedHighlightKind(syntax)
     };
Пример #9
0
        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),
Пример #10
0
 public SyntaxItem(SyntaxBase syntax, int depth)
 {
     Syntax = syntax;
     Depth  = depth;
 }
Пример #11
0
        /// <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}");
            }
        }
Пример #12
0
 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)
 {
 }
Пример #14
0
 public SyntaxBase?GetParent(SyntaxBase syntax)
 => syntaxTree.Hierarchy.GetParent(syntax);
Пример #15
0
        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);
        }
Пример #16
0
 public TypeSymbol?GetDeclaredType(SyntaxBase syntax)
 => typeAssignmentVisitor.GetDeclaredType(syntax);
Пример #17
0
        /// <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);
        }
Пример #18
0
 public DeclaredTypeAssignment?GetDeclaredTypeAssignment(SyntaxBase syntax)
 => typeAssignmentVisitor.GetDeclaredTypeAssignment(syntax);
Пример #19
0
 public SyntaxBase?GetParent(SyntaxBase syntax)
 => bicepFile.Hierarchy.GetParent(syntax);
Пример #20
0
 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);
Пример #22
0
 public void EmitProperty(string name, SyntaxBase expressionValue)
 => EmitPropertyInternal(new JTokenExpression(name), expressionValue);
Пример #23
0
 public ResourceSymbol(ISymbolContext context, string name, ResourceDeclarationSyntax declaringSyntax, SyntaxBase body)
     : base(context, name, declaringSyntax, declaringSyntax.Name)
 {
     this.Body = body;
 }
Пример #24
0
 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);
        }
Пример #26
0
 private void EmitPropertyInternal(LanguageExpression expressionKey, SyntaxBase syntaxValue)
 => EmitPropertyInternal(expressionKey, () => EmitExpression(syntaxValue));
Пример #27
0
 public TypeSymbol?GetDeclaredType(SyntaxBase syntax)
 => declaredTypeManager.GetDeclaredType(syntax);
Пример #28
0
        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));
        }
Пример #29
0
        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.");
            }
        }
Пример #30
0
        public void EmitPropertyExpressionWithExpressionKey(SyntaxBase expressionKey, SyntaxBase expressionValue)
        {
            var keyExpression = converter.ConvertExpression(expressionKey);
            var keyText       = ExpressionSerializer.SerializeExpression(keyExpression);

            EmitPropertyExpression(keyText, expressionValue);
        }