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); }
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); }