Пример #1
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        => AssignTypeWithCaching(syntax, () => {
            var stringSyntax = syntax.TryGetType();

            if (stringSyntax != null && stringSyntax.IsInterpolated())
            {
                // TODO: in the future, we can relax this check to allow interpolation with compile-time constants.
                // right now, codegen will still generate a format string however, which will cause problems for the type.
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).ResourceTypeInterpolationUnsupported()));
            }

            var stringContent = stringSyntax?.GetLiteralValue();
            if (stringContent == null)
            {
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType()));
            }

            // TODO: This needs proper namespace, type, and version resolution logic in the future
            var typeReference = ResourceTypeReference.TryParse(stringContent);
            if (typeReference == null)
            {
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType()));
            }

            // TODO: Construct/lookup type information based on JSON schema or swagger
            // for now assuming very basic resource schema
            return(new ResourceType(stringContent, LanguageConstants.CreateResourceProperties(typeReference), additionalProperties: null, typeReference));
        });
Пример #2
0
 public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
 {
     currentDeclaration = declarations[syntax.Name.IdentifierName];
     declarationAccessDict[currentDeclaration] = new List <SyntaxBase>();
     base.VisitResourceDeclarationSyntax(syntax);
     currentDeclaration = null;
 }
Пример #3
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        => AssignTypeWithDiagnostics(syntax, diagnostics => {
            var stringSyntax = syntax.TryGetType();

            if (stringSyntax != null && stringSyntax.IsInterpolated())
            {
                // TODO: in the future, we can relax this check to allow interpolation with compile-time constants.
                // right now, codegen will still generate a format string however, which will cause problems for the type.
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).ResourceTypeInterpolationUnsupported()));
            }

            var stringContent = stringSyntax?.TryGetLiteralValue();
            if (stringContent == null)
            {
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType()));
            }

            // TODO: This needs proper namespace, type, and version resolution logic in the future
            var typeReference = ResourceTypeReference.TryParse(stringContent);
            if (typeReference == null)
            {
                return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType()));
            }

            var declaredType = resourceTypeRegistrar.GetType(typeReference);

            return(TypeValidator.NarrowTypeAndCollectDiagnostics(typeManager, syntax.Body, declaredType, diagnostics));
        });
Пример #4
0
        public FunctionExpression GetResourceIdExpression(ResourceDeclarationSyntax resourceSyntax, ResourceTypeReference typeReference)
        {
            if (typeReference.Types.Length == 1)
            {
                return(new FunctionExpression(
                           "resourceId",
                           new LanguageExpression[]
                {
                    new JTokenExpression(typeReference.FullyQualifiedType),
                    GetResourceNameExpression(resourceSyntax),
                },
                           Array.Empty <LanguageExpression>()));
            }

            var nameSegments = typeReference.Types.Select(
                (type, i) => new FunctionExpression(
                    "split",
                    new LanguageExpression[] { GetResourceNameExpression(resourceSyntax), new JTokenExpression("/") },
                    new LanguageExpression[] { new JTokenExpression(i) }));

            return(new FunctionExpression(
                       "resourceId",
                       new LanguageExpression[]
            {
                new JTokenExpression(typeReference.FullyQualifiedType),
            }.Concat(nameSegments).ToArray(),
                       Array.Empty <LanguageExpression>()));
        }
Пример #5
0
        // these need to be kept synchronized
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // in certain cases, errors will cause this visitor to short-circuit,
            // which causes state to be left over after processing a peer declaration
            // let's clean it up
            var previousBodyType = this.bodyType;

            this.bodyType = null;
            ResetState();

            // Once https://github.com/Azure/bicep/issues/1177 is fixed,
            // it should be possible to use
            // model.GetSymbolInfo(syntax.Body) is ObectType
            // Currently propertyFlags are not propagated
            var symbol = model.GetSymbolInfo(syntax);

            switch (symbol)
            {
            case ResourceSymbol {
                    IsCollection: false, Type : ResourceType {
                        Body : ObjectType bodyObj
                    }
            } :
                this.bodyType = bodyObj;
                break;
Пример #6
0
        public void EmitResourceIdReference(ResourceDeclarationSyntax resourceSyntax, ResourceTypeReference typeReference)
        {
            var resourceIdExpression = converter.GetResourceIdExpression(resourceSyntax, typeReference);
            var serialized           = ExpressionSerializer.SerializeExpression(resourceIdExpression);

            writer.WriteValue(serialized);
        }
Пример #7
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // Push this resource onto the stack and process its body (including children).
            //
            // We process *this* resource using postorder because VisitDeclaration will do
            // some initialization.
            VisitDeclaration(syntax, base.VisitResourceDeclarationSyntax);

            // Resources are special because a lexically nested resource implies a dependency
            // They are both a source of declarations and a use of them.
            if (!bindings.TryGetValue(syntax, out var symbol) || symbol is not DeclaredSymbol currentDeclaration)
            {
                // If we've failed to bind the symbol, we should already have an error, and a cycle should not be possible
                return;
            }

            if (declarationAccessDict.TryGetValue(currentDeclaration, out var accesses))
            {
                // Walk all ancestors and add a reference from this resource
                foreach (var ancestor in currentDeclarations.OfType <ResourceSymbol>())
                {
                    accesses.Add(ancestor.DeclaringResource);
                }
            }
        }
Пример #8
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // Skip analysis for ErrorSymbol and similar cases, these are invalid cases, and won't be emitted.
            var symbol = this.binder.GetSymbolInfo(syntax) as ResourceSymbol;

            if (symbol is null)
            {
                base.VisitResourceDeclarationSyntax(syntax);
                return;
            }

            // We don't need to do anything here to validate types and their relationships, that was handled during type assignment.
            this.ancestry.Add(symbol, ImmutableArray.CreateRange(this.ancestorResources.Reverse()));

            try
            {
                // This will recursively process the resource body - capture the 'current' declaration's declared resource
                // type so we can validate nesting.
                this.ancestorResources.Push(symbol);
                base.VisitResourceDeclarationSyntax(syntax);
            }
            finally
            {
                this.ancestorResources.Pop();
            }
        }
Пример #9
0
        public override IEnumerable <IDiagnostic> AnalyzeInternal(SemanticModel model)
        {
            List <IDiagnostic> diagnostics = new();

            foreach (ResourceMetadata resource in model.AllResources)
            {
                ResourceDeclarationSyntax resourceSyntax = resource.Symbol.DeclaringResource;
                if (resourceSyntax.TryGetBody()?.TryGetPropertyByNameRecursive("properties", "storageProfile", "imageReference") is ObjectPropertySyntax imageReferenceSyntax)
                {
                    var imageReferenceValue = imageReferenceSyntax.Value;

                    if (imageReferenceValue is ObjectSyntax imageReferenceProperties)
                    {
                        AddDiagnosticsIfImageReferencePropertiesContainPreview(imageReferenceProperties, diagnostics);
                    }
                    else if (imageReferenceValue is VariableAccessSyntax &&
                             model.GetSymbolInfo(imageReferenceValue) is VariableSymbol variableSymbol &&
                             variableSymbol.Value is ObjectSyntax variableValueSyntax)
                    {
                        AddDiagnosticsIfImageReferencePropertiesContainPreview(variableValueSyntax, diagnostics);
                    }
                }
            }

            return(diagnostics);
        }
Пример #10
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // This check is separate from IsLoopAllowedHere because this is about the appearance of a
            // nested resource **inside** a loop.
            if (this.semanticModel.Binder.GetNearestAncestor <ForSyntax>(syntax) is ForSyntax)
            {
                this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.Span).NestedResourceNotAllowedInLoop());
            }

            // Resources can be nested, support recursion of resource declarations
            var previousLoopCapableTopLevelDeclaration = this.activeLoopCapableTopLevelDeclaration;

            this.activeLoopCapableTopLevelDeclaration = syntax;

            // stash the body (handles loops and conditions as well)
            var previousDependsOnProperty = this.currentDependsOnProperty;

            this.currentDependsOnProperty = TryGetDependsOnProperty(syntax.TryGetBody());

            base.VisitResourceDeclarationSyntax(syntax);

            // restore state
            this.currentDependsOnProperty             = previousDependsOnProperty;
            this.activeLoopCapableTopLevelDeclaration = previousLoopCapableTopLevelDeclaration;
        }
Пример #11
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            var assignedType = typeManager.GetTypeInfo(syntax);

            var currentDiagnostics = TypeValidator.GetExpressionAssignmentDiagnostics(typeManager, syntax.Body, assignedType);

            diagnostics.AddRange(currentDiagnostics);
        }
Пример #12
0
            public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
            {
                var visitor = new PropertiesVisitor(this.parent, diagnostics, model);

                visitor.Visit(syntax);

                // Note: PropertiesVisitor will navigate through all child resources, so don't call base
            }
Пример #13
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            base.VisitResourceDeclarationSyntax(syntax);

            var symbol = new ResourceSymbol(this.context, syntax.Name.IdentifierName, syntax, syntax.Body);

            this.declaredSymbols.Add(symbol);
        }
Пример #14
0
            public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
            {
                if (syntax.TryGetBody() is ObjectSyntax body)
                {
                    VisitResourceOrModuleDeclaration(syntax, body);
                }

                base.VisitResourceDeclarationSyntax(syntax);
            }
Пример #15
0
        private DeclaredTypeAssignment GetResourceType(ResourceDeclarationSyntax syntax)
        {
            var declaredResourceType = syntax.GetDeclaredType(this.resourceTypeProvider);

            // if the value is a loop (not a condition or object), the type is an array of the declared resource type
            return(new DeclaredTypeAssignment(
                       syntax.Value is ForSyntax ? new TypedArrayType(declaredResourceType, TypeSymbolValidationFlags.Default) : declaredResourceType,
                       syntax));
        }
Пример #16
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        => AssignTypeWithDiagnostics(syntax, diagnostics =>
        {
            var declaredType = syntax.GetDeclaredType(resourceTypeProvider);
            if (declaredType is ErrorType)
            {
                return(declaredType);
            }

            if (declaredType is ResourceType resourceType && !resourceTypeProvider.HasType(resourceType.TypeReference))
            {
Пример #17
0
 public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) =>
 this.BuildStatement(syntax, () =>
 {
     this.VisitNodes(syntax.LeadingNodes);
     this.Visit(syntax.Keyword);
     this.documentStack.Push(Nil);
     this.Visit(syntax.Name);
     this.Visit(syntax.Type);
     this.Visit(syntax.ExistingKeyword);
     this.Visit(syntax.Assignment);
     this.Visit(syntax.Value);
 });
Пример #18
0
 public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
 {
     this.Visit(syntax.Keyword);
     this.Visit(syntax.Name);
     this.Visit(syntax.Type);
     this.Visit(syntax.Assignment);
     allowedFlags = FunctionFlags.Default;
     this.Visit(syntax.IfCondition);
     allowedFlags = FunctionFlags.RequiresInlining;
     this.Visit(syntax.Body);
     allowedFlags = FunctionFlags.Default;
 }
Пример #19
0
 public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
 {
     allowedFlags = FunctionFlags.ResoureDecorator;
     this.VisitNodes(syntax.LeadingNodes);
     this.Visit(syntax.Keyword);
     this.Visit(syntax.Name);
     this.Visit(syntax.Type);
     this.Visit(syntax.ExistingKeyword);
     this.Visit(syntax.Assignment);
     allowedFlags = FunctionFlags.RequiresInlining;
     this.Visit(syntax.Value);
     allowedFlags = FunctionFlags.Default;
 }
Пример #20
0
        private LanguageExpression GetResourceNameExpression(ResourceDeclarationSyntax resourceSyntax)
        {
            if (resourceSyntax.Body is not ObjectSyntax objectSyntax)
            {
                // this condition should have already been validated by the type checker
                throw new ArgumentException($"Expected resource syntax to have type {typeof(ObjectSyntax)}, but found {resourceSyntax.Body.GetType()}");
            }

            // this condition should have already been validated by the type checker
            var namePropertySyntax = objectSyntax.SafeGetPropertyByName("name") ?? throw new ArgumentException("Expected resource syntax body to contain property 'name'");

            return(ConvertExpression(namePropertySyntax.Value));
        }
Пример #21
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        => AssignTypeWithDiagnostics(syntax, diagnostics =>
        {
            var declaredType = syntax.GetDeclaredType(binder.TargetScope, resourceTypeProvider);

            this.ValidateDecortors(syntax.Decorators, declaredType, diagnostics);

            if (declaredType is ErrorType)
            {
                return(declaredType);
            }

            if (declaredType is ResourceType resourceType && !resourceTypeProvider.HasType(binder.TargetScope, resourceType.TypeReference))
            {
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            this.activeLoopCapableTopLevelDeclaration = syntax;

            // stash the body (handles loops and conditions as well)
            this.currentDependsOnProperty = TryGetDependsOnProperty(syntax.TryGetBody());

            base.VisitResourceDeclarationSyntax(syntax);

            // clear the stash
            this.currentDependsOnProperty = null;

            this.activeLoopCapableTopLevelDeclaration = null;
        }
Пример #23
0
 // these need to be kept synchronized
 public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
 {
     // Once https://github.com/Azure/bicep/issues/1177 is fixed,
     // it should be possible to use
     // model.GetSymbolInfo(syntax.Body) is ObectType
     // Currently propertyFlags are not propagated
     if (model.GetSymbolInfo(syntax) is ResourceSymbol resourceSymbol &&
         resourceSymbol.Type is ResourceType resourceType &&
         resourceType.Body is ObjectType bodyObj)
     {
         this.bodyObj = bodyObj;
     }
     base.VisitResourceDeclarationSyntax(syntax);
     this.bodyObj = null;
 }
Пример #24
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            if (!(this.model.GetSymbolInfo(syntax) is ResourceSymbol resourceSymbol))
            {
                throw new InvalidOperationException("Unbound declaration");
            }

            // save previous declaration as we may call this recursively
            var prevDeclaration = this.currentDeclaration;

            this.currentDeclaration = resourceSymbol;
            this.resourceDependencies[resourceSymbol] = new HashSet <DeclaredSymbol>();
            base.VisitResourceDeclarationSyntax(syntax);

            // restore previous declaration
            this.currentDeclaration = prevDeclaration;
        }
Пример #25
0
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // Skip analysis for ErrorSymbol and similar cases, these are invalid cases, and won't be emitted.
            if (semanticModel.ResourceMetadata.TryLookup(syntax) is not DeclaredResourceMetadata resource)
            {
                base.VisitResourceDeclarationSyntax(syntax);
                return;
            }

            if (semanticModel.Binder.GetNearestAncestor <ResourceDeclarationSyntax>(syntax) is {} nestedParentSyntax)
            {
                // nested resource parent syntax
                if (semanticModel.ResourceMetadata.TryLookup(nestedParentSyntax) is DeclaredResourceMetadata parentResource)
                {
                    this.ancestry.Add(resource, new ResourceAncestor(ResourceAncestorType.Nested, parentResource, null));
                }
            }
Пример #26
0
        private LanguageExpression GetResourceNameExpression(ResourceDeclarationSyntax resourceSyntax)
        {
            if (!(resourceSyntax.Body is ObjectSyntax objectSyntax))
            {
                // this condition should have already been validated by the type checker
                throw new ArgumentException($"Expected resource syntax to have type {typeof(ObjectSyntax)}, but found {resourceSyntax.Body.GetType()}");
            }

            var namePropertySyntax = objectSyntax.Properties.FirstOrDefault(p => LanguageConstants.IdentifierComparer.Equals(p.TryGetKeyText(), "name"));

            if (namePropertySyntax == null)
            {
                // this condition should have already been validated by the type checker
                throw new ArgumentException($"Expected resource syntax body to contain property 'name'");
            }

            return(ConvertExpression(namePropertySyntax.Value));
        }
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // Skip analysis for ErrorSymbol and similar cases, these are invalid cases, and won't be emitted.
            var symbol = this.binder.GetSymbolInfo(syntax) as ResourceSymbol;

            if (symbol is null)
            {
                base.VisitResourceDeclarationSyntax(syntax);
                return;
            }

            if (this.binder.GetNearestAncestor <ResourceDeclarationSyntax>(syntax) is {} nestedParentSyntax)
            {
                // nested resource parent syntax
                if (this.binder.GetSymbolInfo(nestedParentSyntax) is ResourceSymbol parentSymbol)
                {
                    this.ancestry.Add(symbol, new ResourceAncestor(ResourceAncestorType.Nested, parentSymbol, null));
                }
            }
        // these need to be kept synchronized
        public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax)
        {
            // in certain cases, errors will cause this visitor to short-circuit,
            // which causes state to be left over after processing a peer declaration
            // let's clean it up
            var previousBodyType = this.bodyType;

            this.bodyType = null;
            ResetState();

            // Once https://github.com/Azure/bicep/issues/1177 is fixed,
            // it should be possible to use
            // model.GetSymbolInfo(syntax.Body) is ObectType
            // Currently propertyFlags are not propagated
            if (model.GetSymbolInfo(syntax) is ResourceSymbol resourceSymbol)
            {
                this.bodyType = resourceSymbol.TryGetBodyObjectType();
            }

            base.VisitResourceDeclarationSyntax(syntax);
            this.bodyType = previousBodyType;
        }
Пример #29
0
        public LanguageExpression GetLocallyScopedResourceIdExpression(ResourceDeclarationSyntax resourceSyntax, ResourceTypeReference typeReference)
        {
            IEnumerable <LanguageExpression> nameSegments;

            if (typeReference.Types.Length == 1)
            {
                nameSegments = GetResourceNameExpression(resourceSyntax).AsEnumerable();
            }
            else
            {
                nameSegments = typeReference.Types.Select(
                    (type, i) => new FunctionExpression(
                        "split",
                        new LanguageExpression[] { GetResourceNameExpression(resourceSyntax), new JTokenExpression("/") },
                        new LanguageExpression[] { new JTokenExpression(i) }));
            }

            return(ScopeHelper.FormatLocallyScopedResourceId(
                       context.SemanticModel,
                       typeReference.FullyQualifiedType,
                       nameSegments));
        }
Пример #30
0
        private DeclaredTypeAssignment?GetPropertyAccessType(PropertyAccessSyntax syntax)
        {
            if (!syntax.PropertyName.IsValid)
            {
                return(null);
            }

            var baseExpressionAssignment = GetDeclaredTypeAssignment(syntax.BaseExpression);

            // it's ok to rely on useSyntax=true because those types have already been established

            var body = baseExpressionAssignment?.DeclaringSyntax switch
            {
                ResourceDeclarationSyntax resourceDeclarationSyntax => resourceDeclarationSyntax.TryGetBody(),
                _ => baseExpressionAssignment?.DeclaringSyntax as ObjectSyntax,
            };

            return(GetObjectPropertyType(
                       baseExpressionAssignment?.Reference.Type,
                       body,
                       syntax.PropertyName.IdentifierName,
                       useSyntax: true));
        }