Exemple #1
0
        public bool TryCreate(IOperation operation, out AnalysisEntity analysisEntity)
        {
            if (_analysisEntityMap.TryGetValue(operation, out analysisEntity))
            {
                return(analysisEntity != null);
            }

            analysisEntity = null;
            ISymbol symbolOpt = null;
            ImmutableArray <AbstractIndex> indices = ImmutableArray <AbstractIndex> .Empty;
            IOperation  instanceOpt = null;
            ITypeSymbol type        = operation.Type;

            switch (operation)
            {
            case ILocalReferenceOperation localReference:
                symbolOpt = localReference.Local;
                break;

            case IParameterReferenceOperation parameterReference:
                symbolOpt = parameterReference.Parameter;
                break;

            case IMemberReferenceOperation memberReference:
                instanceOpt = memberReference.Instance;
                GetSymbolAndIndicesForMemberReference(memberReference, ref symbolOpt, ref indices);

                // Workaround for https://github.com/dotnet/roslyn/issues/22736 (IPropertyReferenceExpressions in IAnonymousObjectCreationExpression are missing a receiver).
                if (instanceOpt == null &&
                    symbolOpt != null &&
                    memberReference is IPropertyReferenceOperation propertyReference)
                {
                    instanceOpt = propertyReference.GetAnonymousObjectCreation();
                }

                break;

            case IArrayElementReferenceOperation arrayElementReference:
                instanceOpt = arrayElementReference.ArrayReference;
                indices     = CreateAbstractIndices(arrayElementReference.Indices);
                break;

            case IDynamicIndexerAccessOperation dynamicIndexerAccess:
                instanceOpt = dynamicIndexerAccess.Operation;
                indices     = CreateAbstractIndices(dynamicIndexerAccess.Arguments);
                break;

            case IConditionalAccessInstanceOperation conditionalAccessInstance:
                IConditionalAccessOperation conditionalAccess = conditionalAccessInstance.GetConditionalAccess();
                instanceOpt = conditionalAccess.Operation;
                if (conditionalAccessInstance.Parent is IMemberReferenceOperation memberReferenceParent)
                {
                    GetSymbolAndIndicesForMemberReference(memberReferenceParent, ref symbolOpt, ref indices);
                }
                break;

            case IInstanceReferenceOperation instanceReference:
                if (_getPointsToAbstractValueOpt != null)
                {
                    instanceOpt = instanceReference.GetInstance(_getIsInsideAnonymousObjectInitializer());
                    if (instanceOpt == null)
                    {
                        // Reference to this or base instance.
                        analysisEntity = _interproceduralCallStackOpt != null && _interproceduralCallStackOpt.Peek().DescendantsAndSelf().Contains(instanceReference) ?
                                         _interproceduralThisOrMeInstanceForCallerOpt :
                                         ThisOrMeInstance;
                    }
                    else
                    {
                        var instanceLocation = _getPointsToAbstractValueOpt(instanceReference);
                        analysisEntity = AnalysisEntity.Create(instanceReference, instanceLocation);
                    }
                }
                break;

            case IInvocationOperation invocation:
                symbolOpt   = invocation.TargetMethod;
                instanceOpt = invocation.Instance;
                break;

            case IConversionOperation conversion:
                return(TryCreate(conversion.Operand, out analysisEntity));

            case IParenthesizedOperation parenthesized:
                return(TryCreate(parenthesized.Operand, out analysisEntity));

            case IArgumentOperation argument:
                return(TryCreate(argument.Value, out analysisEntity));

            case IFlowCaptureOperation flowCapture:
                analysisEntity = GetOrCreateForFlowCapture(flowCapture.Id, flowCapture.Value.Type, flowCapture);
                break;

            case IFlowCaptureReferenceOperation flowCaptureReference:
                analysisEntity = GetOrCreateForFlowCapture(flowCaptureReference.Id, flowCaptureReference.Type, flowCaptureReference);
                break;

            case IDeclarationExpressionOperation declarationExpression:
                switch (declarationExpression.Expression)
                {
                case ILocalReferenceOperation localReference:
                    return(TryCreateForSymbolDeclaration(localReference.Local, out analysisEntity));

                case ITupleOperation tupleOperation:
                    return(TryCreate(tupleOperation, out analysisEntity));
                }

                break;

            case IVariableDeclaratorOperation variableDeclarator:
                symbolOpt = variableDeclarator.Symbol;
                type      = variableDeclarator.Symbol.Type;
                break;

            case IDeclarationPatternOperation declarationPattern:
                var declaredLocal = declarationPattern.DeclaredSymbol as ILocalSymbol;
                symbolOpt = declaredLocal;
                type      = declaredLocal?.Type;
                break;

            default:
                break;
            }

            if (symbolOpt != null || !indices.IsEmpty)
            {
                TryCreate(symbolOpt, indices, type, instanceOpt, out analysisEntity);
            }

            _analysisEntityMap[operation] = analysisEntity;
            return(analysisEntity != null);
        }
Exemple #2
0
        public bool TryCreateForTupleElements(ITupleOperation tupleOperation, out ImmutableArray <AnalysisEntity> elementEntities)
        {
            if (_tupleElementEntitiesMap.TryGetValue(tupleOperation, out elementEntities))
            {
                return(!elementEntities.IsDefault);
            }

            try
            {
                elementEntities = default;
                if (!tupleOperation.Type.IsTupleType)
                {
                    return(false);
                }

                var tupleType = (INamedTypeSymbol)tupleOperation.Type;
                if (tupleType.TupleElements.IsDefault)
                {
                    return(false);
                }

                PointsToAbstractValue instanceLocation  = _getPointsToAbstractValueOpt(tupleOperation);
                var            underlyingValueTupleType = tupleType.GetUnderlyingValueTupleTypeOrThis();
                AnalysisEntity parentEntity             = null;
                if (tupleOperation.TryGetParentTupleOperation(out var parentTupleOperationOpt, out var elementOfParentTupleContainingTuple) &&
                    TryCreateForTupleElements(parentTupleOperationOpt, out var parentTupleElementEntities))
                {
                    Debug.Assert(parentTupleOperationOpt.Elements.Length == parentTupleElementEntities.Length);
                    for (int i = 0; i < parentTupleOperationOpt.Elements.Length; i++)
                    {
                        if (parentTupleOperationOpt.Elements[i] == elementOfParentTupleContainingTuple)
                        {
                            parentEntity     = parentTupleElementEntities[i];
                            instanceLocation = parentEntity.InstanceLocation;
                            break;
                        }
                    }

                    Debug.Assert(parentEntity != null);
                }
                else
                {
                    parentEntity = AnalysisEntity.Create(underlyingValueTupleType, ImmutableArray <AbstractIndex> .Empty,
                                                         underlyingValueTupleType, instanceLocation, parentOpt: null);
                }

                Debug.Assert(parentEntity.InstanceLocation == instanceLocation);

                var builder = ArrayBuilder <AnalysisEntity> .GetInstance(tupleType.TupleElements.Length);

                foreach (var field in tupleType.TupleElements)
                {
                    var tupleFieldName        = field.CorrespondingTupleField.Name;
                    var mappedValueTupleField = underlyingValueTupleType.GetMembers(tupleFieldName).OfType <IFieldSymbol>().FirstOrDefault();
                    if (mappedValueTupleField == null)
                    {
                        builder.Free();
                        return(false);
                    }

                    builder.Add(AnalysisEntity.Create(mappedValueTupleField, indices: ImmutableArray <AbstractIndex> .Empty,
                                                      type: mappedValueTupleField.Type, instanceLocation, parentEntity));
                }

                elementEntities = builder.ToImmutableAndFree();
                return(true);
            }
        public bool TryCreate(IOperation operation, [NotNullWhen(returnValue: true)] out AnalysisEntity?analysisEntity)
        {
            if (_analysisEntityMap.TryGetValue(operation, out analysisEntity))
            {
                return(analysisEntity != null);
            }

            analysisEntity = null;
            ISymbol?symbol = null;
            ImmutableArray <AbstractIndex> indices = ImmutableArray <AbstractIndex> .Empty;
            IOperation? instance = null;
            ITypeSymbol?type     = operation.Type;

            switch (operation)
            {
            case ILocalReferenceOperation localReference:
                symbol = localReference.Local;
                break;

            case IParameterReferenceOperation parameterReference:
                symbol = parameterReference.Parameter;
                break;

            case IMemberReferenceOperation memberReference:
                instance = memberReference.Instance;
                GetSymbolAndIndicesForMemberReference(memberReference, ref symbol, ref indices);

                // Workaround for https://github.com/dotnet/roslyn/issues/22736 (IPropertyReferenceExpressions in IAnonymousObjectCreationExpression are missing a receiver).
                if (instance == null &&
                    symbol != null &&
                    memberReference is IPropertyReferenceOperation propertyReference)
                {
                    instance = propertyReference.GetAnonymousObjectCreation();
                }

                break;

            case IArrayElementReferenceOperation arrayElementReference:
                instance = arrayElementReference.ArrayReference;
                indices  = CreateAbstractIndices(arrayElementReference.Indices);
                break;

            case IDynamicIndexerAccessOperation dynamicIndexerAccess:
                instance = dynamicIndexerAccess.Operation;
                indices  = CreateAbstractIndices(dynamicIndexerAccess.Arguments);
                break;

            case IConditionalAccessInstanceOperation conditionalAccessInstance:
                IConditionalAccessOperation?conditionalAccess = conditionalAccessInstance.GetConditionalAccess();
                instance = conditionalAccess?.Operation;
                if (conditionalAccessInstance.Parent is IMemberReferenceOperation memberReferenceParent)
                {
                    GetSymbolAndIndicesForMemberReference(memberReferenceParent, ref symbol, ref indices);
                }
                break;

            case IInstanceReferenceOperation instanceReference:
                if (_getPointsToAbstractValue != null)
                {
                    instance = instanceReference.GetInstance(_getIsInsideAnonymousObjectInitializer());
                    if (instance == null)
                    {
                        // Reference to this or base instance.
                        analysisEntity = _interproceduralCallStack != null && _interproceduralCallStack.Peek().DescendantsAndSelf().Contains(instanceReference) ?
                                         _interproceduralThisOrMeInstanceForCaller :
                                         ThisOrMeInstance;
                    }
                    else
                    {
                        var instanceLocation = _getPointsToAbstractValue(instanceReference);
                        analysisEntity = AnalysisEntity.Create(instanceReference, instanceLocation);
                    }
                }
                break;

            case IConversionOperation conversion:
                return(TryCreate(conversion.Operand, out analysisEntity));

            case IParenthesizedOperation parenthesized:
                return(TryCreate(parenthesized.Operand, out analysisEntity));

            case IArgumentOperation argument:
                return(TryCreate(argument.Value, out analysisEntity));

            case IFlowCaptureOperation flowCapture:
                var isLvalueFlowCapture = _getIsLValueFlowCapture(flowCapture);
                analysisEntity = GetOrCreateForFlowCapture(flowCapture.Id, flowCapture.Value.Type, flowCapture, isLvalueFlowCapture);

                // Store flow capture copy values for simple flow captures of non-flow captured entity.
                // This enables pseudo copy-analysis of values of these two entities in absence of true copy analysis, which is expensive.
                if (!isLvalueFlowCapture &&
                    TryCreate(flowCapture.Value, out var capturedEntity) &&
                    capturedEntity.CaptureId == null &&
                    !_captureIdCopyValueMap.ContainsKey(flowCapture.Id) &&
                    analysisEntity.Type.IsValueType == capturedEntity.Type.IsValueType)
                {
                    // Skip flow capture for conversions unless we know the points to value
                    // for conversion and operand is identical.
                    if (flowCapture.Value is IConversionOperation conversion)
                    {
                        if (_getPointsToAbstractValue == null ||
                            _getPointsToAbstractValue(conversion) != _getPointsToAbstractValue(conversion.Operand))
                        {
                            break;
                        }
                    }

                    var kind      = capturedEntity.Type.IsValueType ? CopyAbstractValueKind.KnownValueCopy : CopyAbstractValueKind.KnownReferenceCopy;
                    var copyValue = new CopyAbstractValue(ImmutableHashSet.Create(analysisEntity, capturedEntity), kind);
                    _captureIdCopyValueMap.Add(flowCapture.Id, copyValue);
                }

                break;

            case IFlowCaptureReferenceOperation flowCaptureReference:
                analysisEntity = GetOrCreateForFlowCapture(flowCaptureReference.Id, flowCaptureReference.Type, flowCaptureReference, flowCaptureReference.IsLValueFlowCaptureReference());
                break;

            case IDeclarationExpressionOperation declarationExpression:
                switch (declarationExpression.Expression)
                {
                case ILocalReferenceOperation localReference:
                    return(TryCreateForSymbolDeclaration(localReference.Local, out analysisEntity));

                case ITupleOperation tupleOperation:
                    return(TryCreate(tupleOperation, out analysisEntity));
                }

                break;

            case IVariableDeclaratorOperation variableDeclarator:
                symbol = variableDeclarator.Symbol;
                type   = variableDeclarator.Symbol.Type;
                break;

            case IDeclarationPatternOperation declarationPattern:
                var declaredLocal = declarationPattern.DeclaredSymbol as ILocalSymbol;
                symbol = declaredLocal;
                type   = declaredLocal?.Type;
                break;

            default:
                break;
            }

            if (symbol != null || !indices.IsEmpty)
            {
                TryCreate(symbol, indices, type !, instance, out analysisEntity);
            }

            _analysisEntityMap[operation] = analysisEntity;
            return(analysisEntity != null);
        }