コード例 #1
0
            private static GlobalFlowStateDictionaryAnalysisValue CreateAnalysisValue(
                IDeferredTypeEntity entity,
                IOperation parameterOrLocalReferenceOperation,
                GlobalFlowStateDictionaryAnalysisValue defaultValue,
                EnumerationCount enumerationCount)
            {
                var operationsSetBuilder = PooledHashSet <IOperation> .GetInstance();

                operationsSetBuilder.Add(parameterOrLocalReferenceOperation);
                var newInvocationSet = new TrackingEnumerationSet(
                    operationsSetBuilder.ToImmutableAndFree(),
                    enumerationCount);

                var trackedEntitiesBuilder = PooledDictionary <IDeferredTypeEntity, TrackingEnumerationSet> .GetInstance();

                trackedEntitiesBuilder.Add(entity, newInvocationSet);

                var analysisValue = new GlobalFlowStateDictionaryAnalysisValue(
                    trackedEntitiesBuilder.ToImmutableDictionaryAndFree(),
                    GlobalFlowStateDictionaryAnalysisValueKind.Known);

                return(defaultValue.Kind == GlobalFlowStateDictionaryAnalysisValueKind.Known
                    ? GlobalFlowStateDictionaryAnalysisValue.Merge(analysisValue, defaultValue, false)
                    : analysisValue);
            }
コード例 #2
0
 private void UpdateGlobalValue(GlobalFlowStateDictionaryAnalysisValue value)
 {
     if (value.Kind == GlobalFlowStateDictionaryAnalysisValueKind.Known)
     {
         var newState = GlobalFlowStateDictionaryAnalysisValue.Merge(GlobalState, value, false);
         SetAbstractValue(GlobalEntity, newState);
     }
 }
コード例 #3
0
            /// <summary>
            /// Visit all the possible deferred type entities referenced by <param name="parameterOrLocalOperation"/>.
            /// </summary>
            private GlobalFlowStateDictionaryAnalysisValue VisitDeferTypeEntities(
                PointsToAnalysisResult pointsToAnalysisResult,
                IOperation parameterOrLocalOperation,
                GlobalFlowStateDictionaryAnalysisValue defaultValue,
                EnumerationCount enumerationCount)
            {
                RoslynDebug.Assert(parameterOrLocalOperation is IParameterReferenceOperation or ILocalReferenceOperation);
                // With the initial operation as the root, expand it if
                // the operation is parameter or local reference. It has only one pointToAnalysisResult, and it is a deferred execution invocation.
                // Visit its argument.
                // e.g.
                // var a = b.Concat(c);
                // a.ElementAt(10);
                // When we visit 'a.Element(10)' and look back to 'b.Concat(c)', also try to visit 'b' and 'c'.
                //
                // Update the analysis value when reach one of the following nodes.
                // 1. A parameter or local that has symbol, but no creationOperation.
                // e.g.
                // void Bar(IEnumerable<int> b, IEnumerable<int> c)
                // {
                //      var a = b.Concat(c);
                //      a.ElementAt(10);
                // }
                // When 'a.ElementAt(10)' is called, 'b' and 'c' are enumerated once.
                //
                // 2. Invocation operation that returns a deferred type.
                // e.g.
                // void Bar()
                // {
                //       var a = Enumerable.Range(1, 1);
                //       var b = Enumerable.Range(2, 2);
                //       var c = a.Concat(b);
                //       c.ElementAt(10);
                // }
                // When 'c.ElementAt(10)' is called, then 'Enumerable.Range(1, 1)', 'Enumerable.Range(2, 2)' and 'a.Concat(b)' are enumerated.
                // 3. A parameter or local reference operation with multiple AbstractLocations. Stop expanding the tree at this node
                // because we don't know how to proceed.
                // e.g.
                // void Bar(bool flag)
                // {
                //       var a = flag ? Enumerable.Range(1, 1) : Enumerable.Range(2, 2);
                //       a.ElementAt(10);
                // }
                var queue = new Queue <IOperation>();

                queue.Enqueue(parameterOrLocalOperation);
                var resultAnalysisValue = defaultValue;

                while (queue.Count > 0)
                {
                    var currentOperation = queue.Dequeue();
                    if (currentOperation is IParameterReferenceOperation or ILocalReferenceOperation)
                    {
                        var result = pointsToAnalysisResult[currentOperation];
                        if (result.Kind != PointsToAbstractValueKind.KnownLocations || result.Locations.IsEmpty)
                        {
                            continue;
                        }

                        // Expand if there is only one AbstractLocation for this operation.
                        if (result.Locations.Count == 1)
                        {
                            var location          = result.Locations.Single();
                            var creationOperation = location.Creation;
                            // Node 1: A parameter or local that has symbol, but no creation operation.
                            if (creationOperation == null &&
                                location.Symbol != null &&
                                IsDeferredType(location.LocationType?.OriginalDefinition, _wellKnownSymbolsInfo.AdditionalDeferredTypes))
                            {
                                var analysisValue = CreateAndUpdateAnalysisValue(currentOperation, new DeferredTypeSymbolEntity(location.Symbol), defaultValue, enumerationCount);
                                resultAnalysisValue = GlobalFlowStateDictionaryAnalysisValue.Merge(resultAnalysisValue, analysisValue, false);
                                continue;
                            }

                            if (creationOperation is IInvocationOperation invocationCreationOperation)
                            {
                                // Try to expand the argument of this invocation operation.
                                ExpandInvocationOperation(invocationCreationOperation, _wellKnownSymbolsInfo, queue);

                                var creationMethod = invocationCreationOperation.TargetMethod.ReducedFrom ?? invocationCreationOperation.TargetMethod;
                                // Make sure this creation operation is not 'AsEnumerable', which only do a cast, and do not create new IEnumerable type.
                                if (!_wellKnownSymbolsInfo.NoEffectLinqChainMethods.Contains(creationMethod.OriginalDefinition) &&
                                    IsDeferredType(invocationCreationOperation.Type?.OriginalDefinition, _wellKnownSymbolsInfo.AdditionalDeferredTypes))
                                {
                                    // Node 2: Invocation operation that returns a deferred type.
                                    var analysisValue =
                                        CreateAndUpdateAnalysisValue(currentOperation, new DeferredTypeCreationEntity(invocationCreationOperation), defaultValue, enumerationCount);

                                    resultAnalysisValue = GlobalFlowStateDictionaryAnalysisValue.Merge(resultAnalysisValue, analysisValue, false);
                                }

                                continue;
                            }
                        }
                        else
                        {
                            // Make sure all the locations are pointing to a deferred type.
                            if (result.Locations.Any(
                                    l => !IsDeferredType(l.LocationType?.OriginalDefinition, _wellKnownSymbolsInfo.AdditionalDeferredTypes)))
                            {
                                continue;
                            }

                            // Node 3: A parameter or local reference operation with multiple AbstractLocations.
                            var analysisValue = CreateAndUpdateAnalysisValue(
                                currentOperation,
                                new DeferredTypeEntitySet(result.Locations),
                                defaultValue,
                                enumerationCount);

                            resultAnalysisValue = GlobalFlowStateDictionaryAnalysisValue.Merge(resultAnalysisValue, analysisValue, false);
                        }
                    }

                    // Make sure we iterate into the nested operations.
                    // e.g.
                    // var a = b.Concat(c).Concat(d.Concat(e));
                    // Make sure 'd.Concat(e)' is expanded so that 'd' and 'e' could be found.
                    if (currentOperation is IInvocationOperation invocationOperation)
                    {
                        ExpandInvocationOperation(invocationOperation, _wellKnownSymbolsInfo, queue);
                    }

                    // Expand the implicit conversion operation if it is converting a deferred type to another deferred type.
                    // This might happen in such case:
                    // var c = a.OrderBy(i => i).Concat(b)
                    // The tree would be:
                    //                             a.OrderBy(i => i).Concat(b) (root)
                    //                              /                        \
                    //                          ArgumentOperation          ArgumentOperation
                    //                             /                             \
                    //                          Conversion *(expand this node)    b
                    //                            /
                    //                         a.OrderBy(i => i)
                    //                           /
                    //                         ArgumentOperation
                    //                          /
                    //                         a
                    if (currentOperation is IConversionOperation conversionOperation)
                    {
                        ExpandConversionOperation(conversionOperation, _wellKnownSymbolsInfo, queue);
                    }
                }

                return(resultAnalysisValue);
            }