Ejemplo n.º 1
0
                private void Build()
                {
                    // Set up the current method locals
                    DeclareLocals(_currentScope, _topLevelMethod.Parameters);
                    // Treat 'this' as a formal parameter of the top-level method
                    if (_topLevelMethod.TryGetThisParameter(out var thisParam) && (object)thisParam != null)
                    {
                        DeclareLocals(_currentScope, ImmutableArray.Create <Symbol>(thisParam));
                    }

                    Visit(_currentScope.BoundNode);

                    // Clean Up Resources

                    foreach (var scopes in _scopesAfterLabel.Values)
                    {
                        scopes.Free();
                    }
                    _scopesAfterLabel.Free();

                    Debug.Assert(_labelsInScope.Count == 1);
                    var labels = _labelsInScope.Pop();

                    labels.Free();
                    _labelsInScope.Free();
                }
Ejemplo n.º 2
0
 protected override void Free()
 {
     _labelsDefined.Free();
     _labelsUsed.Free();
     _usingDeclarations.Free();
     base.Free();
 }
Ejemplo n.º 3
0
 public void Free()
 {
     if (_lazyMap != null)
     {
         _lazyMap.Free();
         _lazyMap = null;
     }
 }
Ejemplo n.º 4
0
 public void Free()
 {
     foreach (var item in ThrowLocations)
     {
         item.Value.Free();
     }
     ThrowLocations.Free();
     CatchBlockUsed.Free();
 }
Ejemplo n.º 5
0
        public static ImmutableDictionary <K, ImmutableArray <V> > ToImmutableMultiDictionaryAndFree <K, V>(this PooledDictionary <K, ArrayBuilder <V> > builders)
        {
            var result = ImmutableDictionary.CreateBuilder <K, ImmutableArray <V> >();

            foreach (var(key, items) in builders)
            {
                result.Add(key, items.ToImmutableAndFree());
            }

            builders.Free();
            return(result.ToImmutable());
        }
Ejemplo n.º 6
0
        internal ImmutableArray <GeneratedSourceText> ToImmutableAndFree()
        {
            // https://github.com/dotnet/roslyn/issues/42627: This needs to be consistently ordered
            ArrayBuilder <GeneratedSourceText> builder = ArrayBuilder <GeneratedSourceText> .GetInstance();

            foreach (var(hintName, sourceText) in _sourcesAdded)
            {
                builder.Add(new GeneratedSourceText(hintName, sourceText));
            }
            _sourcesAdded.Free();
            return(builder.ToImmutableAndFree());
        }
Ejemplo n.º 7
0
        public static Dictionary <K, V> ToDictionaryAndFree <K, V>(this PooledDictionary <K, V> builders)
        {
            var dictionary = new Dictionary <K, V>(builders.Count);

            foreach (var(key, items) in builders)
            {
                dictionary.Add(key, items);
            }

            builders.Free();
            return(dictionary);
        }
Ejemplo n.º 8
0
        public static Dictionary <K, ImmutableArray <V> > ToMultiDictionaryAndFree <K, V>(this PooledDictionary <K, ArrayBuilder <V> > builders)
        {
            var dictionary = new Dictionary <K, ImmutableArray <V> >(builders.Count);

            foreach (var(key, items) in builders)
            {
                dictionary.Add(key, items.ToImmutableAndFree());
            }

            builders.Free();
            return(dictionary);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Produce a topological sort of a given directed acyclic graph, given a set of nodes which include all nodes
        /// that have no predecessors. Any nodes not in the given set, but reachable through successors, will be added
        /// to the result. This is an iterative rather than recursive implementation, so it is unlikely to cause a stack
        /// overflow.
        /// </summary>
        /// <typeparam name="TNode">The type of the node</typeparam>
        /// <param name="nodes">Any subset of the nodes that includes all nodes with no predecessors</param>
        /// <param name="successors">A function mapping a node to its set of successors</param>
        /// <param name="result">A list of all reachable nodes, in which each node always precedes its successors</param>
        /// <returns>true if successful; false if not successful due to cycles in the graph</returns>
        public static bool TryIterativeSort <TNode>(
            IEnumerable <TNode> nodes,
            Func <TNode, ImmutableArray <TNode> > successors,
            out ImmutableArray <TNode> result
            ) where TNode : notnull
        {
            // First, count the predecessors of each node
            PooledDictionary <TNode, int> predecessorCounts = PredecessorCounts(
                nodes,
                successors,
                out ImmutableArray <TNode> allNodes
                );

            // Initialize the ready set with those nodes that have no predecessors
            var ready = ArrayBuilder <TNode> .GetInstance();

            foreach (TNode node in allNodes)
            {
                if (predecessorCounts[node] == 0)
                {
                    ready.Push(node);
                }
            }

            // Process the ready set. Output a node, and decrement the predecessor count of its successors.
            var resultBuilder = ArrayBuilder <TNode> .GetInstance();

            while (ready.Count != 0)
            {
                var node = ready.Pop();
                resultBuilder.Add(node);
                foreach (var succ in successors(node))
                {
                    var count = predecessorCounts[succ];
                    Debug.Assert(count != 0);
                    predecessorCounts[succ] = count - 1;
                    if (count == 1)
                    {
                        ready.Push(succ);
                    }
                }
            }

            // At this point all the nodes should have been output, otherwise there was a cycle
            bool hadCycle = predecessorCounts.Count != resultBuilder.Count;

            result = hadCycle ? ImmutableArray <TNode> .Empty : resultBuilder.ToImmutable();
            predecessorCounts.Free();
            ready.Free();
            resultBuilder.Free();
            return(!hadCycle);
        }
        protected override void Dispose(bool disposing)
        {
            if (IsDisposed)
            {
                return;
            }

            if (disposing)
            {
                _coreAnalysisData.Free();
                _coreAnalysisData = null !;
            }

            base.Dispose(disposing);
        }
Ejemplo n.º 11
0
        public static ImmutableArray <TNode> IterativeSort <TNode>(IEnumerable <TNode> nodes, Func <TNode, ImmutableArray <TNode> > successors)
        {
            // First, count the predecessors of each node
            PooledDictionary <TNode, int> predecessorCounts = PredecessorCounts(nodes, successors, out ImmutableArray <TNode> allNodes);

            // Initialize the ready set with those nodes that have no predecessors
            var ready = ArrayBuilder <TNode> .GetInstance();

            foreach (TNode node in allNodes)
            {
                if (predecessorCounts[node] == 0)
                {
                    ready.Push(node);
                }
            }

            // Process the ready set. Output a node, and decrement the predecessor count of its successors.
            var resultBuilder = ImmutableArray.CreateBuilder <TNode>();

            while (ready.Count != 0)
            {
                var node = ready.Pop();
                resultBuilder.Add(node);
                foreach (var succ in successors(node))
                {
                    var count = predecessorCounts[succ];
                    Debug.Assert(count != 0);
                    predecessorCounts[succ] = count - 1;
                    if (count == 1)
                    {
                        ready.Push(succ);
                    }
                }
            }

            // At this point all the nodes should have been output, otherwise there was a cycle
            if (predecessorCounts.Count != resultBuilder.Count)
            {
                throw new ArgumentException("Cycle in the input graph");
            }

            predecessorCounts.Free();
            ready.Free();
            return(resultBuilder.ToImmutable());
        }
Ejemplo n.º 12
0
        private void GenerateImpl()
        {
            SetInitialDebugDocument();

            // Synthesized methods should have a sequence point
            // at offset 0 to ensure correct stepping behavior.
            if (_emitPdbSequencePoints && _method.IsImplicitlyDeclared)
            {
                _builder.DefineInitialHiddenSequencePoint();
            }

            try
            {
                EmitStatement(_boundBody);

                if (_indirectReturnState == IndirectReturnState.Needed)
                {
                    // it is unfortunate that return was not handled while we were in scope of the method
                    // it can happen in rare cases involving exception handling (for example all returns were from a try)
                    // in such case we can still handle return here.
                    HandleReturn();
                }

                if (!_diagnostics.HasAnyErrors())
                {
                    _builder.Realize();
                }
            }
            catch (EmitCancelledException)
            {
                Debug.Assert(_diagnostics.HasAnyErrors());
            }

            _synthesizedLocalOrdinals.Free();

            Debug.Assert(!(_expressionTemps?.Count > 0), "leaking expression temps?");
            _expressionTemps?.Free();
            _savedSequencePoints?.Free();
        }
Ejemplo n.º 13
0
 protected override void Free()
 {
     _variableSlot.Free();
     base.Free();
 }
        private void ResolveAndBindMissingAssemblies(
            TCompilation compilation,
            ImmutableArray <AssemblyData> explicitAssemblies,
            ImmutableArray <PEModule> explicitModules,
            ImmutableArray <MetadataReference> explicitReferences,
            ImmutableArray <ResolvedReference> explicitReferenceMap,
            MetadataReferenceResolver resolver,
            MetadataImportOptions importOptions,
            bool supersedeLowerVersions,
            [In, Out] ArrayBuilder <AssemblyReferenceBinding[]> referenceBindings,
            [In, Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName,
            out ImmutableArray <AssemblyData> allAssemblies,
            out ImmutableArray <MetadataReference> metadataReferences,
            out ImmutableArray <ResolvedReference> resolvedReferences,
            DiagnosticBag resolutionDiagnostics)
        {
            Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt);
            Debug.Assert(referenceBindings.Count == explicitAssemblies.Length);
            Debug.Assert(explicitReferences.Length == explicitReferenceMap.Length);

            // -1 for assembly being built:
            int totalReferencedAssemblyCount = explicitAssemblies.Length - 1;

            var implicitAssemblies = ArrayBuilder <AssemblyData> .GetInstance();

            // tracks identities we already asked the resolver to resolve:
            var requestedIdentities = PooledHashSet <AssemblyIdentity> .GetInstance();

            PooledDictionary <AssemblyIdentity, PortableExecutableReference> previouslyResolvedAssembliesOpt = null;

            // Avoid resolving previously resolved missing references. If we call to the resolver again we would create new assembly symbols for them,
            // which would not match the previously created ones. As a result we would get duplicate PE types and conversion errors.
            var previousScriptCompilation = compilation.ScriptCompilationInfo?.PreviousScriptCompilation;

            if (previousScriptCompilation != null)
            {
                previouslyResolvedAssembliesOpt = PooledDictionary <AssemblyIdentity, PortableExecutableReference> .GetInstance();

                foreach (var entry in previousScriptCompilation.GetBoundReferenceManager().GetImplicitlyResolvedAssemblyReferences())
                {
                    previouslyResolvedAssembliesOpt.Add(entry.Key, entry.Value);
                }
            }

            var metadataReferencesBuilder = ArrayBuilder <MetadataReference> .GetInstance();

            Dictionary <MetadataReference, MergedAliases> lazyAliasMap = null;

            // metadata references and corresponding bindings of their references, used to calculate a fixed point:
            var referenceBindingsToProcess = ArrayBuilder <(MetadataReference, ArraySegment <AssemblyReferenceBinding>)> .GetInstance();

            // collect all missing identities, resolve the assemblies and bind their references against explicit definitions:
            GetInitialReferenceBindingsToProcess(explicitModules, explicitReferences, explicitReferenceMap, referenceBindings, totalReferencedAssemblyCount, referenceBindingsToProcess);

            // NB: includes the assembly being built:
            int explicitAssemblyCount = explicitAssemblies.Length;

            try
            {
                while (referenceBindingsToProcess.Count > 0)
                {
                    var referenceAndBindings = referenceBindingsToProcess.Pop();
                    var requestingReference  = referenceAndBindings.Item1;
                    var bindings             = referenceAndBindings.Item2;

                    foreach (var binding in bindings)
                    {
                        // only attempt to resolve unbound references (regardless of version difference of the bound ones)
                        if (binding.IsBound)
                        {
                            continue;
                        }

                        if (!requestedIdentities.Add(binding.ReferenceIdentity))
                        {
                            continue;
                        }

                        PortableExecutableReference resolvedReference;
                        if (previouslyResolvedAssembliesOpt == null || !previouslyResolvedAssembliesOpt.TryGetValue(binding.ReferenceIdentity, out resolvedReference))
                        {
                            resolvedReference = resolver.ResolveMissingAssembly(requestingReference, binding.ReferenceIdentity);
                            if (resolvedReference == null)
                            {
                                continue;
                            }
                        }

                        var data = ResolveMissingAssembly(binding.ReferenceIdentity, resolvedReference, importOptions, resolutionDiagnostics);
                        if (data == null)
                        {
                            continue;
                        }

                        // The resolver may return different version than we asked for, so it may happen that
                        // it returns the same identity for two different input identities (e.g. if a higher version
                        // of an assembly is available than what the assemblies reference: "A, v1" -> "A, v3" and "A, v2" -> "A, v3").
                        // If such case occurs merge the properties (aliases) of the resulting references in the same way we do
                        // during initial explicit references resolution.

                        // -1 for assembly being built:
                        int index = explicitAssemblyCount - 1 + metadataReferencesBuilder.Count;

                        var existingReference = TryAddAssembly(data.Identity, resolvedReference, index, resolutionDiagnostics, Location.None, assemblyReferencesBySimpleName, supersedeLowerVersions);
                        if (existingReference != null)
                        {
                            MergeReferenceProperties(existingReference, resolvedReference, resolutionDiagnostics, ref lazyAliasMap);
                            continue;
                        }

                        metadataReferencesBuilder.Add(resolvedReference);
                        implicitAssemblies.Add(data);

                        var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer);
                        referenceBindings.Add(referenceBinding);
                        referenceBindingsToProcess.Push((resolvedReference, new ArraySegment <AssemblyReferenceBinding>(referenceBinding)));
                    }
                }

                if (implicitAssemblies.Count == 0)
                {
                    Debug.Assert(lazyAliasMap == null);

                    resolvedReferences = ImmutableArray <ResolvedReference> .Empty;
                    metadataReferences = ImmutableArray <MetadataReference> .Empty;
                    allAssemblies      = explicitAssemblies;
                    return;
                }

                // Rebind assembly references that were initially missing. All bindings established above
                // are against explicitly specified references.

                allAssemblies = explicitAssemblies.AddRange(implicitAssemblies);

                for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++)
                {
                    var referenceBinding = referenceBindings[bindingsIndex];

                    for (int i = 0; i < referenceBinding.Length; i++)
                    {
                        var binding = referenceBinding[i];

                        // We don't rebind references bound to a non-matching version of a reference that was explicitly
                        // specified, even if we have a better version now.
                        if (binding.IsBound)
                        {
                            continue;
                        }

                        // We only need to resolve against implicitly resolved assemblies,
                        // since we already resolved against explicitly specified ones.
                        referenceBinding[i] = ResolveReferencedAssembly(
                            binding.ReferenceIdentity,
                            allAssemblies,
                            explicitAssemblyCount,
                            IdentityComparer);
                    }
                }

                UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies);

                metadataReferences = metadataReferencesBuilder.ToImmutable();
                resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount);
            }
            finally
            {
                implicitAssemblies.Free();
                requestedIdentities.Free();
                referenceBindingsToProcess.Free();
                metadataReferencesBuilder.Free();
                previouslyResolvedAssembliesOpt?.Free();
            }
        }
Ejemplo n.º 15
0
        private TaintedDataConfig(Compilation compilation)
        {
            this.WellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);
            this.SourceSymbolMap       = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > >();
            this.SanitizerSymbolMap    = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > >();
            this.SinkSymbolMap         = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > >();

            // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance.
            // Same for sanitizers.
            PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap =
                PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance();

            PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap =
                PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance();

            // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance.
            PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks =
                PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance();

            try
            {
                // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times.
                foreach (SinkKind sinkKind in Enum.GetValues(typeof(SinkKind)))
                {
                    ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind);
                    if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap))
                    {
                        lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >(
                            () => { return(new TaintedDataSymbolMap <SourceInfo>(this.WellKnownTypeProvider, sources)); },
                            LazyThreadSafetyMode.ExecutionAndPublication);
                        sourcesToSymbolMap.Add(sources, lazySourceSymbolMap);
                    }

                    this.SourceSymbolMap.Add(sinkKind, lazySourceSymbolMap);

                    ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind);
                    if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap))
                    {
                        lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >(
                            () => { return(new TaintedDataSymbolMap <SanitizerInfo>(this.WellKnownTypeProvider, sanitizers)); },
                            LazyThreadSafetyMode.ExecutionAndPublication);
                        sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap);
                    }

                    this.SanitizerSymbolMap.Add(sinkKind, lazySanitizerSymbolMap);

                    ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind);
                    if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair))
                    {
                        sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>());
                        sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair);
                    }

                    sinksPair.SinkKinds.Add(sinkKind);
                    sinksPair.SinkInfos.UnionWith(sinks);
                }

                foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks)
                {
                    ImmutableHashSet <SinkInfo>             sinks             = kvp.Value.SinkInfos.ToImmutable();
                    Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >(
                        () => { return(new TaintedDataSymbolMap <SinkInfo>(this.WellKnownTypeProvider, sinks)); },
                        LazyThreadSafetyMode.ExecutionAndPublication);
                    foreach (SinkKind sinkKind in kvp.Value.SinkKinds)
                    {
                        this.SinkSymbolMap.Add(sinkKind, lazySinkSymbolMap);
                    }
                }
            }
            finally
            {
                sourcesToSymbolMap.Free();
                sanitizersToSymbolMap.Free();
                sourceSanitizersToSinks.Free();
            }
        }
Ejemplo n.º 16
0
        private static void GetFlowGraph(System.Text.StringBuilder stringBuilder, Compilation compilation, ControlFlowGraph graph,
                                         ControlFlowRegion enclosing, string idSuffix, int indent)
        {
            ImmutableArray <BasicBlock> blocks = graph.Blocks;

            var visitor = TestOperationVisitor.Singleton;
            ControlFlowRegion currentRegion        = graph.Root;
            bool lastPrintedBlockIsInCurrentRegion = true;
            PooledDictionary <ControlFlowRegion, int> regionMap = buildRegionMap();
            var localFunctionsMap = PooledDictionary <IMethodSymbol, ControlFlowGraph> .GetInstance();

            var anonymousFunctionsMap = PooledDictionary <IFlowAnonymousFunctionOperation, ControlFlowGraph> .GetInstance();

            for (int i = 0; i < blocks.Length; i++)
            {
                var block = blocks[i];

                Assert.Equal(i, block.Ordinal);

                switch (block.Kind)
                {
                case BasicBlockKind.Block:
                    Assert.NotEqual(0, i);
                    Assert.NotEqual(blocks.Length - 1, i);
                    break;

                case BasicBlockKind.Entry:
                    Assert.Equal(0, i);
                    Assert.Empty(block.Operations);
                    Assert.Empty(block.Predecessors);
                    Assert.Null(block.BranchValue);
                    Assert.NotNull(block.FallThroughSuccessor);
                    Assert.NotNull(block.FallThroughSuccessor.Destination);
                    Assert.Null(block.ConditionalSuccessor);
                    Assert.Same(graph.Root, currentRegion);
                    Assert.Same(currentRegion, block.EnclosingRegion);
                    Assert.Equal(0, currentRegion.FirstBlockOrdinal);
                    Assert.Same(enclosing, currentRegion.EnclosingRegion);
                    Assert.Null(currentRegion.ExceptionType);
                    Assert.Empty(currentRegion.Locals);
                    Assert.Empty(currentRegion.LocalFunctions);
                    Assert.Equal(ControlFlowRegionKind.Root, currentRegion.Kind);
                    Assert.True(block.IsReachable);
                    break;

                case BasicBlockKind.Exit:
                    Assert.Equal(blocks.Length - 1, i);
                    Assert.Empty(block.Operations);
                    Assert.Null(block.FallThroughSuccessor);
                    Assert.Null(block.ConditionalSuccessor);
                    Assert.Null(block.BranchValue);
                    Assert.Same(graph.Root, currentRegion);
                    Assert.Same(currentRegion, block.EnclosingRegion);
                    Assert.Equal(i, currentRegion.LastBlockOrdinal);
                    break;

                default:
                    Assert.False(true, $"Unexpected block kind {block.Kind}");
                    break;
                }

                if (block.EnclosingRegion != currentRegion)
                {
                    enterRegions(block.EnclosingRegion, block.Ordinal);
                }

                if (!lastPrintedBlockIsInCurrentRegion)
                {
                    stringBuilder.AppendLine();
                }

                appendLine($"Block[{getBlockId(block)}] - {block.Kind}{(block.IsReachable ? "" : " [UnReachable]")}");

                var predecessors = block.Predecessors;

                if (!predecessors.IsEmpty)
                {
                    appendIndent();
                    stringBuilder.Append("    Predecessors:");
                    int previousPredecessorOrdinal = -1;
                    for (var predecessorIndex = 0; predecessorIndex < predecessors.Length; predecessorIndex++)
                    {
                        var predecessorBranch = predecessors[predecessorIndex];
                        Assert.Same(block, predecessorBranch.Destination);
                        var predecessor = predecessorBranch.Source;
                        Assert.True(previousPredecessorOrdinal < predecessor.Ordinal);
                        previousPredecessorOrdinal = predecessor.Ordinal;
                        Assert.Same(blocks[predecessor.Ordinal], predecessor);

                        if (predecessorBranch.IsConditionalSuccessor)
                        {
                            Assert.Same(predecessor.ConditionalSuccessor, predecessorBranch);
                            Assert.NotEqual(ControlFlowConditionKind.None, predecessor.ConditionKind);
                        }
                        else
                        {
                            Assert.Same(predecessor.FallThroughSuccessor, predecessorBranch);
                        }

                        stringBuilder.Append($" [{getBlockId(predecessor)}");

                        if (predecessorIndex < predecessors.Length - 1 && predecessors[predecessorIndex + 1].Source == predecessor)
                        {
                            // Multiple branches from same predecessor - one must be conditional and other fall through.
                            Assert.True(predecessorBranch.IsConditionalSuccessor);
                            predecessorIndex++;
                            predecessorBranch = predecessors[predecessorIndex];
                            Assert.Same(predecessor.FallThroughSuccessor, predecessorBranch);
                            Assert.False(predecessorBranch.IsConditionalSuccessor);

                            stringBuilder.Append("*2");
                        }

                        stringBuilder.Append("]");
                    }

                    stringBuilder.AppendLine();
                }
                else if (block.Kind != BasicBlockKind.Entry)
                {
                    appendLine("    Predecessors (0)");
                }

                var statements = block.Operations;
                appendLine($"    Statements ({statements.Length})");
                foreach (var statement in statements)
                {
                    validateRoot(statement);
                    stringBuilder.AppendLine(getOperationTree(statement));
                }

                ControlFlowBranch conditionalBranch = block.ConditionalSuccessor;

                if (block.ConditionKind != ControlFlowConditionKind.None)
                {
                    Assert.NotNull(conditionalBranch);
                    Assert.True(conditionalBranch.IsConditionalSuccessor);

                    Assert.Same(block, conditionalBranch.Source);
                    if (conditionalBranch.Destination != null)
                    {
                        Assert.Same(blocks[conditionalBranch.Destination.Ordinal], conditionalBranch.Destination);
                    }

                    Assert.NotEqual(ControlFlowBranchSemantics.Return, conditionalBranch.Semantics);
                    Assert.NotEqual(ControlFlowBranchSemantics.Throw, conditionalBranch.Semantics);
                    Assert.NotEqual(ControlFlowBranchSemantics.StructuredExceptionHandling, conditionalBranch.Semantics);

                    Assert.True(block.ConditionKind == ControlFlowConditionKind.WhenTrue || block.ConditionKind == ControlFlowConditionKind.WhenFalse);
                    string jumpIfTrue = block.ConditionKind == ControlFlowConditionKind.WhenTrue ? "True" : "False";
                    appendLine($"    Jump if {jumpIfTrue} ({conditionalBranch.Semantics}) to Block[{getDestinationString(ref conditionalBranch)}]");

                    IOperation value = block.BranchValue;
                    Assert.NotNull(value);
                    validateRoot(value);
                    stringBuilder.Append(getOperationTree(value));
                    validateBranch(block, conditionalBranch);
                    stringBuilder.AppendLine();
                }
                else
                {
                    Assert.Null(conditionalBranch);
                    Assert.Equal(ControlFlowConditionKind.None, block.ConditionKind);
                }

                ControlFlowBranch nextBranch = block.FallThroughSuccessor;

                if (block.Kind == BasicBlockKind.Exit)
                {
                    Assert.Null(nextBranch);
                    Assert.Null(block.BranchValue);
                }
                else
                {
                    Assert.NotNull(nextBranch);
                    Assert.False(nextBranch.IsConditionalSuccessor);

                    Assert.Same(block, nextBranch.Source);
                    if (nextBranch.Destination != null)
                    {
                        Assert.Same(blocks[nextBranch.Destination.Ordinal], nextBranch.Destination);
                    }

                    if (nextBranch.Semantics == ControlFlowBranchSemantics.StructuredExceptionHandling)
                    {
                        Assert.Null(nextBranch.Destination);
                        Assert.Equal(block.EnclosingRegion.LastBlockOrdinal, block.Ordinal);
                        Assert.True(block.EnclosingRegion.Kind == ControlFlowRegionKind.Filter || block.EnclosingRegion.Kind == ControlFlowRegionKind.Finally);
                    }

                    appendLine($"    Next ({nextBranch.Semantics}) Block[{getDestinationString(ref nextBranch)}]");
                    IOperation value = block.ConditionKind == ControlFlowConditionKind.None ? block.BranchValue : null;

                    if (value != null)
                    {
                        Assert.True(ControlFlowBranchSemantics.Return == nextBranch.Semantics || ControlFlowBranchSemantics.Throw == nextBranch.Semantics);
                        validateRoot(value);
                        stringBuilder.Append(getOperationTree(value));
                    }
                    else
                    {
                        Assert.NotEqual(ControlFlowBranchSemantics.Return, nextBranch.Semantics);
                        Assert.NotEqual(ControlFlowBranchSemantics.Throw, nextBranch.Semantics);
                    }

                    validateBranch(block, nextBranch);
                }

                validateLocalsAndMethodsLifetime(block);

                if (currentRegion.LastBlockOrdinal == block.Ordinal && i != blocks.Length - 1)
                {
                    leaveRegions(block.EnclosingRegion, block.Ordinal);
                }
                else
                {
                    lastPrintedBlockIsInCurrentRegion = true;
                }
            }

            foreach (IMethodSymbol m in graph.LocalFunctions)
            {
                ControlFlowGraph g = localFunctionsMap[m];
                Assert.Same(g, graph.GetLocalFunctionControlFlowGraph(m));
            }

            Assert.Equal(graph.LocalFunctions.Length, localFunctionsMap.Count);

            foreach (KeyValuePair <IFlowAnonymousFunctionOperation, ControlFlowGraph> pair in anonymousFunctionsMap)
            {
                Assert.Same(pair.Value, graph.GetAnonymousFunctionControlFlowGraph(pair.Key));
            }

            regionMap.Free();
            localFunctionsMap.Free();
            anonymousFunctionsMap.Free();
            return;

            string getDestinationString(ref ControlFlowBranch branch)
            {
                return(branch.Destination != null?getBlockId(branch.Destination) : "null");
            }

            PooledObjects.PooledDictionary <ControlFlowRegion, int> buildRegionMap()
            {
                var result = PooledObjects.PooledDictionary <ControlFlowRegion, int> .GetInstance();

                int ordinal = 0;

                visit(graph.Root);

                void visit(ControlFlowRegion region)
                {
                    result.Add(region, ordinal++);

                    foreach (ControlFlowRegion r in region.NestedRegions)
                    {
                        visit(r);
                    }
                }

                return(result);
            }

            void appendLine(string line)
            {
                appendIndent();
                stringBuilder.AppendLine(line);
            }

            void appendIndent()
            {
                stringBuilder.Append(' ', indent);
            }

            void printLocals(ControlFlowRegion region)
            {
                if (!region.Locals.IsEmpty)
                {
                    appendIndent();
                    stringBuilder.Append("Locals:");
                    foreach (ILocalSymbol local in region.Locals)
                    {
                        stringBuilder.Append($" [{local.ToTestDisplayString()}]");
                    }
                    stringBuilder.AppendLine();
                }

                if (!region.LocalFunctions.IsEmpty)
                {
                    appendIndent();
                    stringBuilder.Append("Methods:");
                    foreach (IMethodSymbol method in region.LocalFunctions)
                    {
                        stringBuilder.Append($" [{method.ToTestDisplayString()}]");
                    }
                    stringBuilder.AppendLine();
                }
            }

            void enterRegions(ControlFlowRegion region, int firstBlockOrdinal)
            {
                if (region.FirstBlockOrdinal != firstBlockOrdinal)
                {
                    Assert.Same(currentRegion, region);

                    if (lastPrintedBlockIsInCurrentRegion)
                    {
                        stringBuilder.AppendLine();
                    }

                    return;
                }

                enterRegions(region.EnclosingRegion, firstBlockOrdinal);
                currentRegion = region;
                lastPrintedBlockIsInCurrentRegion = true;

                switch (region.Kind)
                {
                case ControlFlowRegionKind.Filter:
                    Assert.Empty(region.Locals);
                    Assert.Empty(region.LocalFunctions);
                    Assert.Equal(firstBlockOrdinal, region.EnclosingRegion.FirstBlockOrdinal);
                    Assert.Same(region.ExceptionType, region.EnclosingRegion.ExceptionType);
                    enterRegion($".filter {{{getRegionId(region)}}}");
                    break;

                case ControlFlowRegionKind.Try:
                    Assert.Null(region.ExceptionType);
                    Assert.Equal(firstBlockOrdinal, region.EnclosingRegion.FirstBlockOrdinal);
                    enterRegion($".try {{{getRegionId(region.EnclosingRegion)}, {getRegionId(region)}}}");
                    break;

                case ControlFlowRegionKind.FilterAndHandler:
                    enterRegion($".catch {{{getRegionId(region)}}} ({region.ExceptionType?.ToTestDisplayString() ?? "null"})");
                    break;

                case ControlFlowRegionKind.Finally:
                    Assert.Null(region.ExceptionType);
                    enterRegion($".finally {{{getRegionId(region)}}}");
                    break;

                case ControlFlowRegionKind.Catch:
                    switch (region.EnclosingRegion.Kind)
                    {
                    case ControlFlowRegionKind.FilterAndHandler:
                        Assert.Same(region.ExceptionType, region.EnclosingRegion.ExceptionType);
                        enterRegion($".handler {{{getRegionId(region)}}}");
                        break;

                    case ControlFlowRegionKind.TryAndCatch:
                        enterRegion($".catch {{{getRegionId(region)}}} ({region.ExceptionType?.ToTestDisplayString() ?? "null"})");
                        break;

                    default:
                        Assert.False(true, $"Unexpected region kind {region.EnclosingRegion.Kind}");
                        break;
                    }
                    break;

                case ControlFlowRegionKind.LocalLifetime:
                    Assert.Null(region.ExceptionType);
                    Assert.False(region.Locals.IsEmpty && region.LocalFunctions.IsEmpty);
                    enterRegion($".locals {{{getRegionId(region)}}}");
                    break;

                case ControlFlowRegionKind.TryAndCatch:
                case ControlFlowRegionKind.TryAndFinally:
                    Assert.Empty(region.Locals);
                    Assert.Empty(region.LocalFunctions);
                    Assert.Null(region.ExceptionType);
                    break;

                case ControlFlowRegionKind.StaticLocalInitializer:
                    Assert.Null(region.ExceptionType);
                    Assert.Empty(region.Locals);
                    enterRegion($".static initializer {{{getRegionId(region)}}}");
                    break;

                case ControlFlowRegionKind.ErroneousBody:
                    Assert.Null(region.ExceptionType);
                    enterRegion($".erroneous body {{{getRegionId(region)}}}");
                    break;

                default:
                    Assert.False(true, $"Unexpected region kind {region.Kind}");
                    break;
                }

                void enterRegion(string header)
                {
                    appendLine(header);
                    appendLine("{");
                    indent += 4;
                    printLocals(region);
                }
            }

            void leaveRegions(ControlFlowRegion region, int lastBlockOrdinal)
            {
                if (region.LastBlockOrdinal != lastBlockOrdinal)
                {
                    currentRegion = region;
                    lastPrintedBlockIsInCurrentRegion = false;
                    return;
                }

                string regionId = getRegionId(region);

                for (var i = 0; i < region.LocalFunctions.Length; i++)
                {
                    var method = region.LocalFunctions[i];
                    appendLine("");
                    appendLine("{   " + method.ToTestDisplayString());
                    appendLine("");
                    var g = graph.GetLocalFunctionControlFlowGraph(method);
                    localFunctionsMap.Add(method, g);
                    Assert.Equal(OperationKind.LocalFunction, g.OriginalOperation.Kind);
                    GetFlowGraph(stringBuilder, compilation, g, region, $"#{i}{regionId}", indent + 4);
                    appendLine("}");
                }

                switch (region.Kind)
                {
                case ControlFlowRegionKind.LocalLifetime:
                case ControlFlowRegionKind.Filter:
                case ControlFlowRegionKind.Try:
                case ControlFlowRegionKind.Finally:
                case ControlFlowRegionKind.FilterAndHandler:
                case ControlFlowRegionKind.StaticLocalInitializer:
                case ControlFlowRegionKind.ErroneousBody:
                    indent -= 4;
                    appendLine("}");
                    break;

                case ControlFlowRegionKind.Catch:
                    switch (region.EnclosingRegion.Kind)
                    {
                    case ControlFlowRegionKind.FilterAndHandler:
                    case ControlFlowRegionKind.TryAndCatch:
                        goto endRegion;

                    default:
                        Assert.False(true, $"Unexpected region kind {region.EnclosingRegion.Kind}");
                        break;
                    }

                    break;

endRegion:
                    goto case ControlFlowRegionKind.Filter;

                case ControlFlowRegionKind.TryAndCatch:
                case ControlFlowRegionKind.TryAndFinally:
                    break;

                default:
                    Assert.False(true, $"Unexpected region kind {region.Kind}");
                    break;
                }

                leaveRegions(region.EnclosingRegion, lastBlockOrdinal);
            }

            void validateBranch(BasicBlock fromBlock, ControlFlowBranch branch)
            {
                if (branch.Destination == null)
                {
                    Assert.Empty(branch.FinallyRegions);
                    Assert.Empty(branch.LeavingRegions);
                    Assert.Empty(branch.EnteringRegions);
                    Assert.True(ControlFlowBranchSemantics.None == branch.Semantics || ControlFlowBranchSemantics.Throw == branch.Semantics ||
                                ControlFlowBranchSemantics.Rethrow == branch.Semantics || ControlFlowBranchSemantics.StructuredExceptionHandling == branch.Semantics ||
                                ControlFlowBranchSemantics.ProgramTermination == branch.Semantics || ControlFlowBranchSemantics.Error == branch.Semantics);
                    return;
                }

                Assert.True(ControlFlowBranchSemantics.Regular == branch.Semantics || ControlFlowBranchSemantics.Return == branch.Semantics);
                Assert.True(branch.Destination.Predecessors.Contains(p => p.Source == fromBlock));

                if (!branch.FinallyRegions.IsEmpty)
                {
                    appendLine($"        Finalizing:" + buildList(branch.FinallyRegions));
                }

                ControlFlowRegion remainedIn1 = fromBlock.EnclosingRegion;

                if (!branch.LeavingRegions.IsEmpty)
                {
                    appendLine($"        Leaving:" + buildList(branch.LeavingRegions));
                    foreach (ControlFlowRegion r in branch.LeavingRegions)
                    {
                        Assert.Same(remainedIn1, r);
                        remainedIn1 = r.EnclosingRegion;
                    }
                }

                ControlFlowRegion remainedIn2 = branch.Destination.EnclosingRegion;

                if (!branch.EnteringRegions.IsEmpty)
                {
                    appendLine($"        Entering:" + buildList(branch.EnteringRegions));
                    for (int j = branch.EnteringRegions.Length - 1; j >= 0; j--)
                    {
                        ControlFlowRegion r = branch.EnteringRegions[j];
                        Assert.Same(remainedIn2, r);
                        remainedIn2 = r.EnclosingRegion;
                    }
                }

                Assert.Same(remainedIn1.EnclosingRegion, remainedIn2.EnclosingRegion);

                string buildList(ImmutableArray <ControlFlowRegion> list)
                {
                    var builder = PooledObjects.PooledStringBuilder.GetInstance();

                    foreach (ControlFlowRegion r in list)
                    {
                        builder.Builder.Append($" {{{getRegionId(r)}}}");
                    }

                    return(builder.ToStringAndFree());
                }
            }

            void validateRoot(IOperation root)
            {
                visitor.Visit(root);
                Assert.Null(root.Parent);
                Assert.Null(((Operation)root).SemanticModel);
                Assert.True(CanBeInControlFlowGraph(root), $"Unexpected node kind OperationKind.{root.Kind}");

                foreach (var operation in root.Descendants())
                {
                    visitor.Visit(operation);
                    Assert.NotNull(operation.Parent);
                    Assert.Null(((Operation)operation).SemanticModel);
                    Assert.True(CanBeInControlFlowGraph(operation), $"Unexpected node kind OperationKind.{operation.Kind}");
                }
            }

            void validateLocalsAndMethodsLifetime(BasicBlock block)
            {
                ISymbol[] localsOrMethodsInBlock = Enumerable.Concat(block.Operations, new[] { block.BranchValue }).
                                                   Where(o => o != null).
                                                   SelectMany(o => o.DescendantsAndSelf().
                                                              Select(node =>
                {
                    IMethodSymbol method;

                    switch (node.Kind)
                    {
                    case OperationKind.LocalReference:
                        return(((ILocalReferenceOperation)node).Local);

                    case OperationKind.MethodReference:
                        method = ((IMethodReferenceOperation)node).Method;
                        return(method.MethodKind == MethodKind.LocalFunction ? method.OriginalDefinition : null);

                    case OperationKind.Invocation:
                        method = ((IInvocationOperation)node).TargetMethod;
                        return(method.MethodKind == MethodKind.LocalFunction ? method.OriginalDefinition : null);

                    default:
                        return((ISymbol)null);
                    }
                }).
                                                              Where(s => s != null)).
                                                   Distinct().ToArray();

                if (localsOrMethodsInBlock.Length == 0)
                {
                    return;
                }

                var localsAndMethodsInRegions = PooledHashSet <ISymbol> .GetInstance();

                ControlFlowRegion region = block.EnclosingRegion;

                do
                {
                    foreach (ILocalSymbol l in region.Locals)
                    {
                        Assert.True(localsAndMethodsInRegions.Add(l));
                    }

                    foreach (IMethodSymbol m in region.LocalFunctions)
                    {
                        Assert.True(localsAndMethodsInRegions.Add(m));
                    }

                    region = region.EnclosingRegion;
                }while (region != null);

                foreach (ISymbol l in localsOrMethodsInBlock)
                {
                    Assert.False(localsAndMethodsInRegions.Add(l), $"Local/method without owning region {l.ToTestDisplayString()} in [{getBlockId(block)}]");
                }

                localsAndMethodsInRegions.Free();
            }

            string getBlockId(BasicBlock block)
            {
                return($"B{block.Ordinal}{idSuffix}");
            }

            string getRegionId(ControlFlowRegion region)
            {
                return($"R{regionMap[region]}{idSuffix}");
            }

            string getOperationTree(IOperation operation)
            {
                var walker = new OperationTreeSerializer(graph, currentRegion, idSuffix, anonymousFunctionsMap, compilation, operation, initialIndent: 8 + indent);

                walker.Visit(operation);
                return(walker.Builder.ToString());
            }
        }
Ejemplo n.º 17
0
        private static void ProcessBody <TSyntaxKind>(
            SemanticModel semanticModel,
            ImmutableArray <IDiagnosticAnalyzer> analyzers,
            ICodeBlockStartedAnalyzer[] bodyAnalyzers,
            ISymbol symbol,
            SyntaxNode syntax,
            CancellationToken cancellationToken,
            Action <Diagnostic> addDiagnostic,
            AnalyzerOptions analyzerOptions,
            bool continueOnError,
            Func <SyntaxNode, TSyntaxKind> getKind)
        {
            var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance();

            PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null;

            foreach (var a in bodyAnalyzers)
            {
                // Catch Exception from a.OnCodeBlockStarted
                ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () =>
                {
                    var analyzer = a.OnCodeBlockStarted(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken);
                    if (analyzer != null && analyzer != a)
                    {
                        endedAnalyzers.Add(analyzer);
                    }
                });
            }

            foreach (var nodeAnalyzer in endedAnalyzers.Concat(analyzers).OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >())
            {
                // Catch Exception from  nodeAnalyzer.SyntaxKindsOfInterest
                try
                {
                    foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest)
                    {
                        if (nodeAnalyzersByKind == null)
                        {
                            nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance();
                        }
                        ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind;
                        if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind))
                        {
                            nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance());
                        }
                        analyzersForKind.Add(nodeAnalyzer);
                    }
                }
                catch (Exception e)
                {
                    // Create a info diagnostic saying that the analyzer failed
                    addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e));
                }
            }

            if (nodeAnalyzersByKind != null)
            {
                foreach (var child in syntax.DescendantNodesAndSelf())
                {
                    ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind;
                    if (nodeAnalyzersByKind.TryGetValue(getKind(child), out analyzersForKind))
                    {
                        foreach (var analyzer in analyzersForKind)
                        {
                            // Catch Exception from analyzer.AnalyzeNode
                            ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); });
                        }
                    }
                }

                foreach (var b in nodeAnalyzersByKind.Values)
                {
                    b.Free();
                }
                nodeAnalyzersByKind.Free();
            }

            foreach (var a in endedAnalyzers.Concat(analyzers.OfType <ICodeBlockEndedAnalyzer>()))
            {
                // Catch Exception from a.OnCodeBlockEnded
                ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); });
            }

            endedAnalyzers.Free();
        }
 protected new void Free()
 {
     _dagNodeLabels.Free();
     _switchArms.Free();
     base.Free();
 }
Ejemplo n.º 19
0
        private async Task AnalyzeDeclaringReference(CompilationEvent.SymbolDeclared symbolEvent, SyntaxReference decl, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken)
        {
            var symbol = symbolEvent.Symbol;
            var syntax = await decl.GetSyntaxAsync();

            var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance();

            endedAnalyzers.AddRange(CodeBlockEndedAnalyzers);
            var nodeAnalyzers = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance();

            nodeAnalyzers.AddRange(Analyzers.OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >());
            foreach (var da in CodeBlockStartedAnalyzers)
            {
                // Catch Exception from da.OnCodeBlockStarted
                ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () =>
                {
                    var blockStatefulAnalyzer = da.OnCodeBlockStarted(syntax, symbol, symbolEvent.SemanticModel(decl), addDiagnostic, cancellationToken);
                    var endedAnalyzer         = blockStatefulAnalyzer as ICodeBlockEndedAnalyzer;
                    if (endedAnalyzer != null)
                    {
                        endedAnalyzers.Add(endedAnalyzer);
                    }
                    var nodeAnalyzer = blockStatefulAnalyzer as ISyntaxNodeAnalyzer <TSyntaxKind>;
                    if (nodeAnalyzer != null)
                    {
                        nodeAnalyzers.Add(nodeAnalyzer);
                    }
                });
            }

            PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null;

            foreach (var nodeAnalyzer in nodeAnalyzers)
            {
                // Catch Exception from  nodeAnalyzer.SyntaxKindsOfInterest
                try
                {
                    foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest)
                    {
                        if (nodeAnalyzersByKind == null)
                        {
                            nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance();
                        }
                        ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind;
                        if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind))
                        {
                            nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance());
                        }
                        analyzersForKind.Add(nodeAnalyzer);
                    }
                }
                catch (Exception e)
                {
                    // Create a info diagnostic saying that the analyzer failed
                    addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e));
                }
            }
            nodeAnalyzers.Free();

            SemanticModel semanticModel = (nodeAnalyzersByKind != null || endedAnalyzers.Any()) ? symbolEvent.SemanticModel(decl) : null;

            if (nodeAnalyzersByKind != null)
            {
                semanticModel = symbolEvent.SemanticModel(decl);
                foreach (var child in syntax.DescendantNodesAndSelf())
                {
                    ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind;
                    if (nodeAnalyzersByKind.TryGetValue(GetKind(child), out analyzersForKind))
                    {
                        foreach (var analyzer in analyzersForKind)
                        {
                            // Catch Exception from analyzer.AnalyzeNode
                            ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, cancellationToken); });
                        }
                    }
                }

                foreach (var b in nodeAnalyzersByKind.Values)
                {
                    b.Free();
                }
                nodeAnalyzersByKind.Free();
            }

            foreach (var a in endedAnalyzers)
            {
                // Catch Exception from a.OnCodeBlockEnded
                ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, cancellationToken); });
            }
            endedAnalyzers.Free();
        }
Ejemplo n.º 20
0
 public void Free()
 {
     _temps.Free();
     _map.Free();
 }
Ejemplo n.º 21
0
        public override void Initialize(AnalysisContext context)
        {
            context.EnableConcurrentExecution();
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);

            context.RegisterCompilationStartAction(
                (CompilationStartAnalysisContext compilationContext) =>
            {
                TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilationContext.Compilation);
                TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind);
                if (sourceInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind);
                if (sinkInfoSymbolMap.IsEmpty)
                {
                    return;
                }

                compilationContext.RegisterOperationBlockStartAction(
                    operationBlockStartContext =>
                {
                    ISymbol owningSymbol = operationBlockStartContext.OwningSymbol;
                    if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options,
                                                                TaintedDataEnteringSinkDescriptor, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken))
                    {
                        return;
                    }

                    PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance();

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation;
                        IOperation rootOperation = operationAnalysisContext.Operation.GetRoot();
                        if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property))
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                rootOperationsNeedingAnalysis.Add(rootOperation);
                            }
                        }
                    },
                        OperationKind.PropertyReference);

                    operationBlockStartContext.RegisterOperationAction(
                        operationAnalysisContext =>
                    {
                        IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation;
                        IOperation rootOperation = operationAnalysisContext.Operation.GetRoot();
                        PooledDictionary <PointsToCheck, ImmutableHashSet <string> > evaluateWithPointsToAnalysis         = null;
                        PooledDictionary <ValueContentCheck, ImmutableHashSet <string> > evaluateWithValueContentAnalysis = null;
                        PointsToAnalysisResult pointsToAnalysisResult         = null;
                        ValueContentAnalysisResult valueContentAnalysisResult = null;
                        if (rootOperation.TryGetEnclosingControlFlowGraph(out ControlFlowGraph cfg))
                        {
                            pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult(
                                cfg,
                                owningSymbol,
                                operationAnalysisContext.Options,
                                WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation),
                                InterproceduralAnalysisConfiguration.Create(
                                    operationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: operationAnalysisContext.CancellationToken),
                                interproceduralAnalysisPredicateOpt: null);
                            if (pointsToAnalysisResult == null)
                            {
                                return;
                            }
                        }

                        if (sourceInfoSymbolMap.RequiresValueContentAnalysis)
                        {
                            valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult(
                                cfg,
                                owningSymbol,
                                operationAnalysisContext.Options,
                                WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation),
                                InterproceduralAnalysisConfiguration.Create(
                                    operationAnalysisContext.Options,
                                    SupportedDiagnostics,
                                    defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive,
                                    cancellationToken: operationAnalysisContext.CancellationToken),
                                out var copyAnalysisResult,
                                out pointsToAnalysisResult);
                            if (valueContentAnalysisResult == null)
                            {
                                return;
                            }
                        }

                        try
                        {
                            if (sourceInfoSymbolMap.IsSourceMethod(
                                    invocationOperation.TargetMethod,
                                    invocationOperation.Arguments,
                                    invocationOperation.Arguments.Select(o => pointsToAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(),
                                    invocationOperation.Arguments.Select(o => valueContentAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(),
                                    out _))
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add(rootOperation);
                                }
                            }
                        }
                        finally
                        {
                            evaluateWithPointsToAnalysis?.Free();
                            evaluateWithValueContentAnalysis?.Free();
                        }
                    },
                        OperationKind.Invocation);

                    if (taintedDataConfig.HasTaintArraySource(SinkKind))
                    {
                        operationBlockStartContext.RegisterOperationAction(
                            operationAnalysisContext =>
                        {
                            IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation;
                            if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol &&
                                sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol))
                            {
                                lock (rootOperationsNeedingAnalysis)
                                {
                                    rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot());
                                }
                            }
                        },
                            OperationKind.ArrayInitializer);
                    }

                    operationBlockStartContext.RegisterOperationBlockEndAction(
                        operationBlockAnalysisContext =>
                    {
                        try
                        {
                            lock (rootOperationsNeedingAnalysis)
                            {
                                if (!rootOperationsNeedingAnalysis.Any())
                                {
                                    return;
                                }

                                foreach (IOperation rootOperation in rootOperationsNeedingAnalysis)
                                {
                                    if (!rootOperation.TryGetEnclosingControlFlowGraph(out var cfg))
                                    {
                                        continue;
                                    }

                                    TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult(
                                        cfg,
                                        operationBlockAnalysisContext.Compilation,
                                        operationBlockAnalysisContext.OwningSymbol,
                                        operationBlockAnalysisContext.Options,
                                        TaintedDataEnteringSinkDescriptor,
                                        sourceInfoSymbolMap,
                                        taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind),
                                        sinkInfoSymbolMap,
                                        operationBlockAnalysisContext.CancellationToken);
                                    if (taintedDataAnalysisResult == null)
                                    {
                                        return;
                                    }

                                    foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks)
                                    {
                                        if (!sourceSink.SinkKinds.Contains(this.SinkKind))
                                        {
                                            continue;
                                        }

                                        foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins)
                                        {
                                            // Something like:
                                            // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'.
                                            Diagnostic diagnostic = Diagnostic.Create(
                                                this.TaintedDataEnteringSinkDescriptor,
                                                sourceSink.Sink.Location,
                                                additionalLocations: new Location[] { sourceOrigin.Location },
                                                messageArgs: new object[] {
                                                sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat),
                                                sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat)
                                            });
                                            operationBlockAnalysisContext.ReportDiagnostic(diagnostic);
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            rootOperationsNeedingAnalysis.Free();
                        }
                    });
                });
            });
        }
 protected new void Free()
 {
     _dagNodeLabels.Free();
     base.Free();
 }