Beispiel #1
0
        public override IEnumerable <IDiagnostic> AnalyzeInternal(SemanticModel model)
        {
            Lazy <ImmutableDictionary <DeclaredSymbol, ImmutableHashSet <ResourceDependency> > > inferredDependenciesMap =
                new Lazy <ImmutableDictionary <DeclaredSymbol, ImmutableHashSet <ResourceDependency> > >(
                    () => ResourceDependencyVisitor.GetResourceDependencies(
                        model,
                        new ResourceDependencyVisitor.Options {
                IgnoreExplicitDependsOn = true
            }));
            var visitor = new ResourceVisitor(this, inferredDependenciesMap, model);

            visitor.Visit(model.SourceFile.ProgramSyntax);
            return(visitor.diagnostics);
        }
Beispiel #2
0
        public static BicepDeploymentGraph CreateDeploymentGraph(CompilationContext context, string entryFilePath)
        {
            var nodes = new List <BicepDeploymentGraphNode>();
            var edges = new List <BicepDeploymentGraphEdge>();

            var queue = new Queue <(SemanticModel, string, string?)>();
            var entrySemanticModel = context.Compilation.GetEntrypointSemanticModel();

            queue.Enqueue((entrySemanticModel, entryFilePath, null));

            while (queue.Count > 0)
            {
                var(semanticModel, filePath, parentId) = queue.Dequeue();
                var nodesBySymbol        = new Dictionary <DeclaredSymbol, BicepDeploymentGraphNode>();
                var dependenciesBySymbol = ResourceDependencyVisitor.GetResourceDependencies(semanticModel)
                                           .Where(x => x.Key.Name != LanguageConstants.MissingName && x.Key.Name != LanguageConstants.ErrorName)
                                           .ToImmutableDictionary(x => x.Key, x => x.Value);

                var errors = semanticModel.GetAllDiagnostics().Where(x => x.Level == DiagnosticLevel.Error).ToList();

                // Create nodes.
                foreach (var symbol in dependenciesBySymbol.Keys)
                {
                    var id = parentId is null ? symbol.Name : $"{parentId}::{symbol.Name}";

                    if (symbol is ResourceSymbol resourceSymbol)
                    {
                        var resourceType     = resourceSymbol.TryGetResourceTypeReference()?.FullyQualifiedType ?? "<unknown>";
                        var isCollection     = resourceSymbol.IsCollection;
                        var resourceSpan     = resourceSymbol.DeclaringResource.Span;
                        var range            = resourceSpan.ToRange(context.LineStarts);
                        var resourceHasError = errors.Any(error => TextSpan.AreOverlapping(resourceSpan, error.Span));

                        nodesBySymbol[symbol] = new BicepDeploymentGraphNode(id, resourceType, isCollection, range, false, resourceHasError, filePath);
                    }

                    if (symbol is ModuleSymbol moduleSymbol)
                    {
                        var directory          = Path.GetDirectoryName(filePath);
                        var moduleRelativePath = moduleSymbol.DeclaringModule.TryGetPath()?.TryGetLiteralValue();
                        var moduleFilePath     = directory is not null && moduleRelativePath is not null
                            ? Path.GetFullPath(Path.Combine(directory, moduleRelativePath))
                            : null;

                        var isCollection   = moduleSymbol.IsCollection;
                        var moduleSpan     = moduleSymbol.DeclaringModule.Span;
                        var range          = moduleSpan.ToRange(context.LineStarts);
                        var moduleHasError = errors.Any(error => TextSpan.AreOverlapping(moduleSpan, error.Span));

                        var hasChildren = false;

                        if (moduleFilePath is not null &&
                            moduleSymbol.TryGetSemanticModel(out var moduleSemanticModel, out var _) &&
                            moduleSemanticModel is SemanticModel bicepModel &&
                            (bicepModel.Root.ResourceDeclarations.Any() || bicepModel.Root.ModuleDeclarations.Any()))
                        {
                            hasChildren = true;
                            queue.Enqueue((bicepModel, moduleFilePath, id));
                        }

                        nodesBySymbol[symbol] = new BicepDeploymentGraphNode(id, "<module>", isCollection, range, hasChildren, moduleHasError, moduleFilePath);
                    }
                }

                nodes.AddRange(nodesBySymbol.Values);

                // Create edges.
                foreach (var(symbol, dependencies) in dependenciesBySymbol)
                {
                    if (!nodesBySymbol.TryGetValue(symbol, out var source))
                    {
                        continue;
                    }

                    foreach (var dependency in dependencies)
                    {
                        if (!nodesBySymbol.TryGetValue(dependency.Resource, out var target))
                        {
                            continue;
                        }

                        edges.Add(new BicepDeploymentGraphEdge(source.Id, target.Id));
                    }
                }
            }

            return(new BicepDeploymentGraph(
                       nodes.OrderBy(node => node.Id),
                       edges.OrderBy(edge => $"{edge.SourceId}>{edge.TargetId}"),
                       entrySemanticModel.GetAllDiagnostics().Count(x => x.Level == DiagnosticLevel.Error)));
        }