Esempio n. 1
0
        public (Uri entrypointUri, ImmutableDictionary <Uri, string> filesToSave) DecompileFileWithModules(Uri entryJsonUri, Uri entryBicepUri)
        {
            var workspace      = new Workspace();
            var decompileQueue = new Queue <(Uri, Uri)>();

            decompileQueue.Enqueue((entryJsonUri, entryBicepUri));

            while (decompileQueue.Count > 0)
            {
                var(jsonUri, bicepUri) = decompileQueue.Dequeue();

                if (PathHelper.HasBicepExtension(jsonUri))
                {
                    throw new InvalidOperationException($"Cannot decompile the file with .bicep extension: {jsonUri}.");
                }

                if (workspace.TryGetSourceFile(bicepUri, out _))
                {
                    continue;
                }

                if (!fileResolver.TryRead(jsonUri, out var jsonInput, out _))
                {
                    throw new InvalidOperationException($"Failed to read {jsonUri}");
                }

                var(program, jsonTemplateUrisByModule) = TemplateConverter.DecompileTemplate(workspace, fileResolver, bicepUri, jsonInput);
                var bicepFile = SourceFileFactory.CreateBicepFile(bicepUri, program.ToText());
                workspace.UpsertSourceFile(bicepFile);

                foreach (var module in program.Children.OfType <ModuleDeclarationSyntax>())
                {
                    var moduleRelativePath = SyntaxHelper.TryGetModulePath(module, out _);
                    if (moduleRelativePath == null ||
                        !LocalModuleReference.Validate(moduleRelativePath, out _) ||
                        !Uri.TryCreate(bicepUri, moduleRelativePath, out var moduleUri))
                    {
                        // Do our best, but keep going if we fail to resolve a module file
                        continue;
                    }

                    if (!workspace.TryGetSourceFile(moduleUri, out _) && jsonTemplateUrisByModule.TryGetValue(module, out var linkedTemplateUri))
                    {
                        decompileQueue.Enqueue((linkedTemplateUri, moduleUri));
                    }
                }
            }

            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ParentChildResourceNameRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new DependsOnRemovalRewriter(semanticModel));
            RewriteSyntax(workspace, entryBicepUri, semanticModel => new ForExpressionSimplifierRewriter(semanticModel));
            for (var i = 0; i < 5; i++)
            {
                // This is a little weird. If there are casing issues nested inside casing issues (e.g. in an object), then the inner casing issue will have no type information
                // available, as the compilation will not have associated a type with it (since there was no match on the outer object). So we need to correct the outer issue first,
                // and then move to the inner one. We need to recompute the entire compilation to do this. It feels simpler to just do this in passes over the file, rather than on demand.
                if (!RewriteSyntax(workspace, entryBicepUri, semanticModel => new TypeCasingFixerRewriter(semanticModel)))
                {
                    break;
                }
            }

            return(entryBicepUri, PrintFiles(workspace));
        }
Esempio n. 2
0
        private void EmitParameter(JsonTextWriter jsonWriter, ParameterSymbol parameterSymbol, ExpressionEmitter emitter)
        {
            var declaringParameter = parameterSymbol.DeclaringParameter;

            var properties = new List <ObjectPropertySyntax>();

            if (parameterSymbol.Type is ResourceType resourceType)
            {
                // Encode a resource type as a string parameter with a metadata for the resource type.
                properties.Add(SyntaxFactory.CreateObjectProperty("type", SyntaxFactory.CreateStringLiteral(LanguageConstants.String.Name)));
                properties.Add(SyntaxFactory.CreateObjectProperty(
                                   LanguageConstants.ParameterMetadataPropertyName,
                                   SyntaxFactory.CreateObject(new[]
                {
                    SyntaxFactory.CreateObjectProperty(
                        LanguageConstants.MetadataResourceTypePropertyName,
                        SyntaxFactory.CreateStringLiteral(resourceType.TypeReference.FormatName())),
                })));
            }
            else if (SyntaxHelper.TryGetPrimitiveType(declaringParameter) is TypeSymbol primitiveType)
            {
                properties.Add(SyntaxFactory.CreateObjectProperty("type", SyntaxFactory.CreateStringLiteral(primitiveType.Name)));
            }
            else
            {
                // this should have been caught by the type checker long ago
                throw new ArgumentException($"Unable to find primitive type for parameter {parameterSymbol.Name}");
            }

            jsonWriter.WriteStartObject();

            var parameterObject = SyntaxFactory.CreateObject(properties);

            if (declaringParameter.Modifier is ParameterDefaultValueSyntax defaultValueSyntax)
            {
                parameterObject = parameterObject.MergeProperty("defaultValue", defaultValueSyntax.DefaultValue);
            }

            parameterObject = AddDecoratorsToBody(declaringParameter, parameterObject, SyntaxHelper.TryGetPrimitiveType(declaringParameter) ?? parameterSymbol.Type);

            foreach (var property in parameterObject.Properties)
            {
                if (property.TryGetKeyText() is string propertyName)
                {
                    emitter.EmitProperty(propertyName, property.Value);
                }
            }

            jsonWriter.WriteEndObject();
        }
Esempio n. 3
0
        public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolver fileResolver, RootConfiguration configuration)
        {
            Trace.WriteLine($"Building semantic model for {sourceFile.FileUri}");

            Compilation   = compilation;
            SourceFile    = sourceFile;
            FileResolver  = fileResolver;
            Configuration = configuration;

            // create this in locked mode by default
            // this blocks accidental type or binding queries until binding is done
            // (if a type check is done too early, unbound symbol references would cause incorrect type check results)
            var symbolContext = new SymbolContext(compilation, this);

            SymbolContext = symbolContext;

            Binder      = new Binder(compilation.NamespaceProvider, sourceFile, symbolContext);
            TypeManager = new TypeManager(Binder, fileResolver);

            // name binding is done
            // allow type queries now
            symbolContext.Unlock();

            this.emitLimitationInfoLazy = new Lazy <EmitLimitationInfo>(() => EmitLimitationCalculator.Calculate(this));
            this.symbolHierarchyLazy    = new Lazy <SymbolHierarchy>(() =>
            {
                var hierarchy = new SymbolHierarchy();
                hierarchy.AddRoot(this.Root);

                return(hierarchy);
            });
            this.resourceAncestorsLazy = new Lazy <ResourceAncestorGraph>(() => ResourceAncestorGraph.Compute(this));
            this.ResourceMetadata      = new ResourceMetadataCache(this);

            // lazy loading the linter will delay linter rule loading
            // and configuration loading until the linter is actually needed
            this.linterAnalyzerLazy = new Lazy <LinterAnalyzer>(() => new LinterAnalyzer(configuration));

            this.allResourcesLazy = new Lazy <ImmutableArray <ResourceMetadata> >(() => GetAllResourceMetadata());

            // lazy load single use diagnostic set
            this.allDiagnostics = new Lazy <IEnumerable <IDiagnostic> >(() => AssembleDiagnostics());

            this.parameterTypePropertiesLazy = new Lazy <ImmutableArray <TypeProperty> >(() =>
            {
                var paramTypeProperties = new List <TypeProperty>();

                foreach (var param in this.Root.ParameterDeclarations.DistinctBy(p => p.Name))
                {
                    var typePropertyFlags = TypePropertyFlags.WriteOnly;
                    if (SyntaxHelper.TryGetDefaultValue(param.DeclaringParameter) == null)
                    {
                        // if there's no default value, it must be specified
                        typePropertyFlags |= TypePropertyFlags.Required;
                    }

                    var description = SemanticModelHelper.TryGetDescription(this, param.DeclaringParameter);
                    paramTypeProperties.Add(new TypeProperty(param.Name, param.Type, typePropertyFlags, description));
                }

                return(paramTypeProperties.ToImmutableArray());
            });

            this.outputTypePropertiesLazy = new Lazy <ImmutableArray <TypeProperty> >(() =>
            {
                var outputTypeProperties = new List <TypeProperty>();

                foreach (var output in this.Root.OutputDeclarations.DistinctBy(o => o.Name))
                {
                    var description = SemanticModelHelper.TryGetDescription(this, output.DeclaringOutput);
                    outputTypeProperties.Add(new TypeProperty(output.Name, output.Type, TypePropertyFlags.ReadOnly, description));
                }

                return(outputTypeProperties.ToImmutableArray());
            });
        }
Esempio n. 4
0
        /// <summary>
        /// Visits a memory pattern member
        /// </summary>
        /// <param name="plan">Test file plan</param>
        /// <param name="testSetPlan">TestSetPlan to visit</param>
        /// <param name="mempatMember">Memory pattern member syntax node</param>
        private void VisitMemoryPatternMember(TestFilePlan plan, TestSetPlan testSetPlan, MemoryPatternMemberNode mempatMember)
        {
            // --- Check ID duplication
            var id = mempatMember.Id;

            if (testSetPlan.ContainsSymbol(id))
            {
                ReportError(Errors.T0006, plan, mempatMember.IdSpan, id);
                return;
            }

            // --- Evaluate byte array
            var bytes      = new List <byte>();
            var errorFound = false;

            foreach (var mempat in mempatMember.Patterns)
            {
                if (mempat is BytePatternNode bytePattern)
                {
                    foreach (var byteExpr in bytePattern.Bytes)
                    {
                        var value = Eval(plan, testSetPlan, byteExpr);
                        if (value != null)
                        {
                            bytes.Add((byte)value.AsNumber());
                        }
                        else
                        {
                            errorFound = true;
                        }
                    }
                }
                else if (mempat is WordPatternNode wordPattern)
                {
                    foreach (var byteExpr in wordPattern.Words)
                    {
                        var value = Eval(plan, testSetPlan, byteExpr);
                        if (value != null)
                        {
                            var word = value.AsWord();
                            bytes.Add((byte)word);
                            bytes.Add((byte)(word >> 8));
                        }
                        else
                        {
                            errorFound = true;
                        }
                    }
                }
                else if (mempat is TextPatternNode textPattern)
                {
                    foreach (var val in SyntaxHelper.SpectrumStringToBytes(textPattern.String))
                    {
                        bytes.Add(val);
                    }
                }
            }

            if (errorFound)
            {
                return;
            }
            testSetPlan.SetDataMember(id, new ExpressionValue(bytes.ToArray()));
        }
Esempio n. 5
0
        private void EmitParameter(ParameterSymbol parameterSymbol)
        {
            // local function
            bool IsSecure(SyntaxBase?value) => value is BooleanLiteralSyntax boolLiteral && boolLiteral.Value;

            if (!(SyntaxHelper.TryGetPrimitiveType(parameterSymbol.DeclaringParameter) is TypeSymbol primitiveType))
            {
                // this should have been caught by the type checker long ago
                throw new ArgumentException($"Unable to find primitive type for parameter {parameterSymbol.Name}");
            }

            writer.WriteStartObject();

            if (parameterSymbol.DeclaringParameter.Decorators.Any())
            {
                var parameterType   = SyntaxFactory.CreateStringLiteral(primitiveType.Name);
                var parameterObject = SyntaxFactory.CreateObject(SyntaxFactory.CreateObjectProperty("type", parameterType).AsEnumerable());

                if (parameterSymbol.Modifier is ParameterDefaultValueSyntax defaultValueSyntax)
                {
                    parameterObject.MergeProperty("defaultValue", defaultValueSyntax.DefaultValue);
                }

                foreach (var decoratorSyntax in parameterSymbol.DeclaringParameter.Decorators.Reverse())
                {
                    var symbol = this.context.SemanticModel.GetSymbolInfo(decoratorSyntax.Expression);

                    if (symbol is FunctionSymbol decoratorSymbol)
                    {
                        var argumentTypes = decoratorSyntax.Arguments
                                            .Select(argument => this.context.SemanticModel.TypeManager.GetTypeInfo(argument))
                                            .ToArray();

                        // There should be exact one matching decorator since there's no errors.
                        Decorator decorator = this.context.SemanticModel.Root.ImportedNamespaces
                                              .SelectMany(ns => ns.Value.Type.DecoratorResolver.GetMatches(decoratorSymbol, argumentTypes))
                                              .Single();

                        parameterObject = decorator.Evaluate(decoratorSyntax, primitiveType, parameterObject);
                    }
                }

                foreach (var property in parameterObject.Properties)
                {
                    if (property.TryGetKeyText() is string propertyName)
                    {
                        this.emitter.EmitProperty(propertyName, property.Value);
                    }
                }
            }
            else
            {
                // TODO: remove this before the 0.3 release.
                switch (parameterSymbol.Modifier)
                {
                case null:
                    this.emitter.EmitProperty("type", GetTemplateTypeName(primitiveType, secure: false));

                    break;

                case ParameterDefaultValueSyntax defaultValueSyntax:
                    this.emitter.EmitProperty("type", GetTemplateTypeName(primitiveType, secure: false));
                    this.emitter.EmitProperty("defaultValue", defaultValueSyntax.DefaultValue);

                    break;

                case ObjectSyntax modifierSyntax:
                    // this would throw on duplicate properties in the object node - we are relying on emitter checking for errors at the beginning
                    var properties = modifierSyntax.ToKnownPropertyValueDictionary();

                    this.emitter.EmitProperty("type", GetTemplateTypeName(primitiveType, IsSecure(properties.TryGetValue("secure"))));

                    // relying on validation here as well (not all of the properties are valid in all contexts)
                    foreach (string modifierPropertyName in ParameterModifierPropertiesToEmitDirectly)
                    {
                        this.emitter.EmitOptionalPropertyExpression(modifierPropertyName, properties.TryGetValue(modifierPropertyName));
                    }

                    this.emitter.EmitOptionalPropertyExpression("defaultValue", properties.TryGetValue(LanguageConstants.ParameterDefaultPropertyName));
                    this.emitter.EmitOptionalPropertyExpression("allowedValues", properties.TryGetValue(LanguageConstants.ParameterAllowedPropertyName));

                    break;
                }
            }

            writer.WriteEndObject();
        }
Esempio n. 6
0
        private SyntaxNode Mutate(SyntaxNode currentNode, MutationContext context)
        {
            // don't mutate immutable nodes
            if (!SyntaxHelper.CanBeMutated(currentNode))
            {
                return(currentNode);
            }

            // identify static related structure
            switch (currentNode)
            {
            // static fields
            case FieldDeclarationSyntax fieldDeclaration when fieldDeclaration.Modifiers.Any(x => x.Kind() == SyntaxKind.StaticKeyword):
                context = new MutationContext
                {
                    InStaticValue = true
                };
                break;

            // static constructors
            case ConstructorDeclarationSyntax constructorDeclaration when constructorDeclaration.Modifiers.Any(x => x.Kind() == SyntaxKind.StaticKeyword):
                context = new MutationContext
                {
                    InStaticValue = true
                };
                if (MustInjectCoverageLogic)
                {
                    return(MutateStaticConstructor(constructorDeclaration, context));
                }
                break;

            // static properties
            case PropertyDeclarationSyntax propertyDeclaration when propertyDeclaration.Modifiers.Any(x => x.Kind() == SyntaxKind.StaticKeyword) && propertyDeclaration.AccessorList != null:
                context = new MutationContext
                {
                    InStaticValue = true
                };
                if (MustInjectCoverageLogic)
                {
                    return(MutateStaticAccessor(propertyDeclaration, context));
                }
                break;
            }

            switch (currentNode)
            {
            // apply statement specific strategies (where applicable)
            case ExpressionStatementSyntax tentativeAssignment when tentativeAssignment.Expression is AssignmentExpressionSyntax assign:
                return(MutateAssignment(tentativeAssignment, assign, context));

            case ExpressionStatementSyntax tentativeAssignment when tentativeAssignment.Expression is PostfixUnaryExpressionSyntax || tentativeAssignment.Expression is PrefixUnaryExpressionSyntax:
                return(MutateUnaryStatement(tentativeAssignment, context));

            case ExpressionStatementSyntax expressionStatement:
                // we must skip the expression statement part
                return(currentNode.ReplaceNode(expressionStatement.Expression, Mutate(expressionStatement.Expression, context)));

            case IfStatementSyntax ifStatement:
                return(MutateIfStatement(ifStatement, context));

            case ForStatementSyntax forStatement:
                return(MutateForStatement(forStatement, context));
            }
            return(MutateExpression(currentNode, context));
        }
Esempio n. 7
0
 public override string ToString()
 {
     return(SyntaxHelper.GetFullTypeName(this));
 }