private AnalysisEntity( ISymbol?symbol, ImmutableArray <AbstractIndex> indices, SyntaxNode?instanceReferenceOperationSyntax, InterproceduralCaptureId?captureId, PointsToAbstractValue location, ITypeSymbol type, AnalysisEntity?parent, bool isThisOrMeInstance) { Debug.Assert(!indices.IsDefault); Debug.Assert(symbol != null || !indices.IsEmpty || instanceReferenceOperationSyntax != null || captureId.HasValue); Debug.Assert(parent == null || parent.Type.HasValueCopySemantics() || !indices.IsEmpty); Symbol = symbol; Indices = indices; InstanceReferenceOperationSyntax = instanceReferenceOperationSyntax; CaptureId = captureId; InstanceLocation = location; Type = type; Parent = parent; IsThisOrMeInstance = isThisOrMeInstance; _ignoringLocationHashCodeParts = ComputeIgnoringLocationHashCodeParts(); EqualsIgnoringInstanceLocationId = HashUtilities.Combine(_ignoringLocationHashCodeParts); }
public override TAbstractAnalysisValue VisitTypeParameterObjectCreation(ITypeParameterObjectCreationOperation operation, object argument) { var value = base.VisitTypeParameterObjectCreation(operation, argument); PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(operation); return(HandleInstanceCreation(operation, instanceLocation, value)); }
public static AnalysisEntity Create( InterproceduralCaptureId interproceduralCaptureId, ITypeSymbol type, PointsToAbstractValue instanceLocation) { return(new AnalysisEntity(interproceduralCaptureId, type, instanceLocation)); }
/// <summary> /// Transfers the analysis data rooted from <paramref name="assignedValueOperation"/> to <paramref name="targetAnalysisEntity"/>, for a value type assignment operation. /// This involves transfer of data for of all <see cref="AnalysisEntity"/> instances that share the same <see cref="AnalysisEntity.InstanceLocation"/> as the valueAnalysisEntity for the <paramref name="assignedValueOperation"/> /// to all <see cref="AnalysisEntity"/> instances that share the same <see cref="AnalysisEntity.InstanceLocation"/> as <paramref name="targetAnalysisEntity"/>. /// </summary> private void TransferValueTypeInstanceAnalysisDataForAssignment(AnalysisEntity targetAnalysisEntity, IOperation assignedValueOperation) { Debug.Assert(HasPointsToAnalysisResult); Debug.Assert(targetAnalysisEntity.Type.HasValueCopySemantics()); IEnumerable <AnalysisEntity> dependentAnalysisEntities; if (AnalysisEntityFactory.TryCreate(assignedValueOperation, out AnalysisEntity valueAnalysisEntity)) { dependentAnalysisEntities = GetChildAnalysisEntities(valueAnalysisEntity); } else { // For allocations. PointsToAbstractValue newValueLocation = GetPointsToAbstractValue(assignedValueOperation); dependentAnalysisEntities = GetChildAnalysisEntities(newValueLocation); } foreach (AnalysisEntity dependentInstance in dependentAnalysisEntities) { // Clone the dependent instance but with with target as the root. AnalysisEntity newAnalysisEntity = AnalysisEntityFactory.CreateWithNewInstanceRoot(dependentInstance, targetAnalysisEntity); var dependentValue = GetAbstractValue(dependentInstance); SetAbstractValue(newAnalysisEntity, dependentValue); } }
protected override void ResetReferenceTypeInstanceAnalysisData(PointsToAbstractValue pointsToValue) { Debug.Assert(HasPointsToAnalysisResult); IEnumerable <AnalysisEntity> dependantAnalysisEntities = GetChildAnalysisEntities(pointsToValue); ResetInstanceAnalysisDataCore(dependantAnalysisEntities); }
public static AnalysisEntity Create(ISymbol?symbol, ImmutableArray <AbstractIndex> indices, ITypeSymbol type, PointsToAbstractValue instanceLocation, AnalysisEntity?parent) { Debug.Assert(symbol != null || !indices.IsEmpty); Debug.Assert(parent == null || parent.InstanceLocation == instanceLocation); return(new AnalysisEntity(symbol, indices, instanceLocation, type, parent)); }
protected override PropertySetAbstractValue VisitAssignmentOperation(IAssignmentOperation operation, object?argument) { PropertySetAbstractValue?baseValue = base.VisitAssignmentOperation(operation, argument); // If we need to evaluate hazardous usages on initializations, track assignments of properties and fields, so // at the end of the CFG we can figure out which assignment operations to flag. if (this.TrackedFieldPropertyAssignments != null && this.TrackedTypeSymbols.Any(s => operation.Target.Type.GetBaseTypesAndThis().Contains(s)) && (operation.Target.Kind == OperationKind.PropertyReference || operation.Target.Kind == OperationKind.FieldReference || operation.Target.Kind == OperationKind.FlowCaptureReference)) { AnalysisEntity?targetAnalysisEntity = null; if (operation.Target.Kind == OperationKind.FlowCaptureReference) { if (this.TryUnwrapFlowCaptureReference(operation.Target, out IOperation? lValueOperation, OperationKind.PropertyReference, OperationKind.FieldReference)) { this.AnalysisEntityFactory.TryCreate(lValueOperation, out targetAnalysisEntity); } } else { this.AnalysisEntityFactory.TryCreate(operation.Target, out targetAnalysisEntity); } if (targetAnalysisEntity != null) { PointsToAbstractValue pointsToAbstractValue = this.GetPointsToAbstractValue(operation.Value); if (!this.TrackedFieldPropertyAssignments.TryGetValue( targetAnalysisEntity, out TrackedAssignmentData trackedAssignmentData)) { trackedAssignmentData = new TrackedAssignmentData(); this.TrackedFieldPropertyAssignments.Add(targetAnalysisEntity, trackedAssignmentData); } if (pointsToAbstractValue.Kind == PointsToAbstractValueKind.KnownLocations) { foreach (AbstractLocation abstractLocation in pointsToAbstractValue.Locations) { trackedAssignmentData.TrackAssignmentWithAbstractLocation(operation, abstractLocation); } } else if (pointsToAbstractValue.Kind is PointsToAbstractValueKind.Unknown or PointsToAbstractValueKind.UnknownNotNull) { trackedAssignmentData.TrackAssignmentWithUnknownLocation(operation); } else if (pointsToAbstractValue.NullState == NullAbstractValue.Null) { // Do nothing. } else { Debug.Fail($"Unhandled PointsToAbstractValue: Kind = {pointsToAbstractValue.Kind}, NullState = {pointsToAbstractValue.NullState}"); } } }
protected override TAbstractAnalysisValue ComputeAnalysisValueForOutArgument(IArgumentOperation operation, TAbstractAnalysisValue defaultValue) { if (operation.Value.Type != null) { PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(operation); return(HandleInstanceCreation(operation.Value.Type, instanceLocation, defaultValue)); } return(defaultValue); }
private AnalysisEntity(INamedTypeSymbol typeSymbol, PointsToAbstractValue location) { Debug.Assert(typeSymbol != null); Debug.Assert(location != null); SymbolOpt = typeSymbol; InstanceLocation = location; Type = typeSymbol; Indices = ImmutableArray <AbstractIndex> .Empty; }
private AnalysisEntity(IInstanceReferenceOperation instanceReferenceOperation, PointsToAbstractValue location) { Debug.Assert(instanceReferenceOperation != null); Debug.Assert(location != null); InstanceReferenceOperationSyntaxOpt = instanceReferenceOperation.Syntax; InstanceLocation = location; Type = instanceReferenceOperation.Type; Indices = ImmutableArray <AbstractIndex> .Empty; }
private void AddToMap(PointsToAbstractValue instanceLocation, AnalysisEntity analysisEntity) { Debug.Assert(instanceLocation != null); if (!_analysisEntitiesPerInstance.TryGetValue(instanceLocation, out var builder)) { builder = ImmutableHashSet.CreateBuilder <AnalysisEntity>(); } builder.Add(analysisEntity); _analysisEntitiesPerInstance[instanceLocation] = builder; }
public ArgumentInfo( IOperation operation, AnalysisEntity?analysisEntity, PointsToAbstractValue instanceLocation, TAbstractAnalysisValue value) { Operation = operation; AnalysisEntity = analysisEntity; InstanceLocation = instanceLocation; Value = value; }
/// <summary> /// A <see cref="PropertyMapper.PointsToAbstractValueCallback"/> for flagging assigning null to a property. /// </summary> /// <param name="pointsToAbstractValue">Value assigned to the property.</param> /// <returns>Flagged if null, Unflagged if not null, MaybeFlagged otherwise.</returns> public static PropertySetAbstractValueKind FlagIfNull(PointsToAbstractValue pointsToAbstractValue) { return(pointsToAbstractValue.NullState switch { NullAbstractValue.Null => PropertySetAbstractValueKind.Flagged, NullAbstractValue.NotNull => PropertySetAbstractValueKind.Unflagged, NullAbstractValue.MaybeNull => PropertySetAbstractValueKind.MaybeFlagged, _ => PropertySetAbstractValueKind.Unknown, });
public AnalysisEntityFactory( Func <IOperation, PointsToAbstractValue> getPointsToAbstractValueOpt, INamedTypeSymbol containingTypeSymbol) { _getPointsToAbstractValueOpt = getPointsToAbstractValueOpt; _analysisEntityMap = new Dictionary <IOperation, AnalysisEntity>(); _instanceLocationsForSymbols = new Dictionary <ISymbol, PointsToAbstractValue>(); var thisOrMeInstanceLocation = AbstractLocation.CreateThisOrMeLocation(containingTypeSymbol); var instanceLocation = new PointsToAbstractValue(thisOrMeInstanceLocation); ThisOrMeInstance = AnalysisEntity.CreateThisOrMeInstance(containingTypeSymbol, instanceLocation); }
private bool TryCreate(ISymbol symbolOpt, ImmutableArray <AbstractIndex> indices, ITypeSymbol type, IOperation instanceOpt, out AnalysisEntity analysisEntity) { Debug.Assert(symbolOpt != null || !indices.IsEmpty); Debug.Assert(type != null); analysisEntity = null; // Only analyze member symbols if we have points to analysis result. if (_getPointsToAbstractValueOpt == null && symbolOpt?.Kind != SymbolKind.Local && symbolOpt?.Kind != SymbolKind.Parameter) { return(false); } // Workaround for https://github.com/dotnet/roslyn-analyzers/issues/1602 if (instanceOpt != null && instanceOpt.Type == null) { return(false); } PointsToAbstractValue instanceLocationOpt = null; AnalysisEntity parentOpt = null; if (instanceOpt?.Type != null) { if (instanceOpt.Type.HasValueCopySemantics()) { if (TryCreate(instanceOpt, out parentOpt)) { instanceLocationOpt = parentOpt.InstanceLocation; } else { // For value type allocations, we store the points to location. var instancePointsToValue = _getPointsToAbstractValueOpt(instanceOpt); if (instancePointsToValue.Kind != PointsToAbstractValueKind.NoLocation) { instanceLocationOpt = instancePointsToValue; } } } else { instanceLocationOpt = _getPointsToAbstractValueOpt(instanceOpt); } } analysisEntity = Create(symbolOpt, indices, type, instanceLocationOpt, parentOpt); return(true); }
protected DataFlowOperationVisitor( AbstractValueDomain <TAbstractAnalysisValue> valueDomain, INamedTypeSymbol containingTypeSymbol, DataFlowAnalysisResult <NullBlockAnalysisResult, NullAbstractValue> nullAnalysisResultOpt, DataFlowAnalysisResult <PointsToBlockAnalysisResult, PointsToAbstractValue> pointsToAnalysisResultOpt) { ValueDomain = valueDomain; _nullAnalysisResultOpt = nullAnalysisResultOpt; _pointsToAnalysisResultOpt = pointsToAnalysisResultOpt; _valueCacheBuilder = ImmutableDictionary.CreateBuilder <IOperation, TAbstractAnalysisValue>(); _pendingArgumentsToReset = new List <IArgumentOperation>(); ThisOrMePointsToAbstractValue = GetThisOrMeInstancePointsToValue(containingTypeSymbol); }
private void HandlePossibleInvalidatingOperation(IOperation invalidatedInstance) { PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(invalidatedInstance); foreach (AbstractLocation location in instanceLocation.Locations) { if (CurrentAnalysisData.TryGetValue(location, out DisposeAbstractValue currentDisposeValue) && currentDisposeValue.Kind != DisposeAbstractValueKind.NotDisposable) { SetAbstractValue(location, DisposeAbstractValue.Invalid); } } }
private void HandlePossibleEscapingOperation(IOperation escapingOperation, IOperation escapedInstance) { PointsToAbstractValue pointsToValue = GetPointsToAbstractValue(escapedInstance); foreach (AbstractLocation location in pointsToValue.Locations) { if (CurrentAnalysisData.TryGetValue(location, out DisposeAbstractValue currentDisposeValue)) { DisposeAbstractValue newDisposeValue = currentDisposeValue.WithNewEscapingOperation(escapingOperation); SetAbstractValue(location, newDisposeValue); } } }
private AnalysisEntity(ISymbol symbolOpt, ImmutableArray <AbstractIndex> indices, PointsToAbstractValue location, ITypeSymbol type, AnalysisEntity parentOpt) { Debug.Assert(!indices.IsDefault); Debug.Assert(symbolOpt != null || !indices.IsEmpty); Debug.Assert(location != null); Debug.Assert(type != null); Debug.Assert(parentOpt == null || parentOpt.Type.HasValueCopySemantics()); SymbolOpt = symbolOpt; Indices = indices; InstanceLocation = location; Type = type; ParentOpt = parentOpt; }
public AnalysisEntityFactory( Func <IOperation, PointsToAbstractValue> getPointsToAbstractValueOpt, INamedTypeSymbol containingTypeSymbol) { _getPointsToAbstractValueOpt = getPointsToAbstractValueOpt; _analysisEntitiesPerInstance = ImmutableDictionary.CreateBuilder <PointsToAbstractValue, ImmutableHashSet <AnalysisEntity> .Builder>(); _analysisEntityMap = new Dictionary <IOperation, AnalysisEntity>(); _instanceLocationsForSymbols = new Dictionary <ISymbol, PointsToAbstractValue>(); var thisOrMeInstanceLocation = AbstractLocation.CreateThisOrMeLocation(containingTypeSymbol); var instanceLocation = new PointsToAbstractValue(thisOrMeInstanceLocation); ThisOrMeInstance = AnalysisEntity.CreateThisOrMeInstance(containingTypeSymbol, instanceLocation); AddToMap(instanceLocation, ThisOrMeInstance); }
private IEnumerable <AnalysisEntity> GetChildAnalysisEntities(PointsToAbstractValue instanceLocationOpt) { // We are interested only in dependent child/member infos, not the root info. if (instanceLocationOpt != null) { IEnumerable <AnalysisEntity> trackedEntities = TrackedEntities; if (trackedEntities != null) { return(trackedEntities.Where(entity => entity.InstanceLocation.Equals(instanceLocationOpt) && entity.IsChildOrInstanceMember) .ToImmutableHashSet()); } } return(ImmutableHashSet <AnalysisEntity> .Empty); }
private ImmutableHashSet <AnalysisEntity> GetChildAnalysisEntities(PointsToAbstractValue instanceLocationOpt, Func <AnalysisEntity, bool> predicateOpt) { // We are interested only in dependent child/member infos, not the root info. if (instanceLocationOpt == null || instanceLocationOpt.Kind == PointsToAbstractValueKind.Unknown) { return(ImmutableHashSet <AnalysisEntity> .Empty); } if (predicateOpt == null) { predicateOpt = entity => IsChildAnalysisEntity(entity, instanceLocationOpt); } return(GetChildAnalysisEntities(predicateOpt)); }
public AnalysisEntityFactory( Func <IOperation, PointsToAbstractValue> getPointsToAbstractValueOpt, Func <bool> getIsInsideObjectInitializer, INamedTypeSymbol containingTypeSymbol) { _getPointsToAbstractValueOpt = getPointsToAbstractValueOpt; _getIsInsideObjectInitializer = getIsInsideObjectInitializer; _analysisEntityMap = new Dictionary <IOperation, AnalysisEntity>(); _instanceLocationsForSymbols = new Dictionary <ISymbol, PointsToAbstractValue>(); var thisOrMeInstanceLocation = AbstractLocation.CreateThisOrMeLocation(containingTypeSymbol); var instanceLocation = PointsToAbstractValue.Create(thisOrMeInstanceLocation, mayBeNull: false); ThisOrMeInstance = AnalysisEntity.CreateThisOrMeInstance(containingTypeSymbol, instanceLocation); }
/// <summary> /// A <see cref="PropertyMapper.PointsToAbstractValueCallback"/> for flagging assigning null to a property. /// </summary> /// <param name="pointsToAbstractValue">Value assigned to the property.</param> /// <returns>Flagged if null, Unflagged if not null, MaybeFlagged otherwise.</returns> public static PropertySetAbstractValueKind FlagIfNull(PointsToAbstractValue pointsToAbstractValue) { switch (pointsToAbstractValue.NullState) { case NullAbstractValue.Null: return(PropertySetAbstractValueKind.Flagged); case NullAbstractValue.NotNull: return(PropertySetAbstractValueKind.Unflagged); case NullAbstractValue.MaybeNull: return(PropertySetAbstractValueKind.MaybeFlagged); default: return(PropertySetAbstractValueKind.Unknown); } }
internal AnalysisEntityFactory( ControlFlowGraph controlFlowGraph, WellKnownTypeProvider wellKnownTypeProvider, Func <IOperation, PointsToAbstractValue>?getPointsToAbstractValue, Func <bool> getIsInsideAnonymousObjectInitializer, Func <IFlowCaptureOperation, bool> getIsLValueFlowCapture, INamedTypeSymbol containingTypeSymbol, AnalysisEntity?interproceduralInvocationInstance, AnalysisEntity?interproceduralThisOrMeInstanceForCaller, ImmutableStack <IOperation>?interproceduralCallStack, ImmutableDictionary <ISymbol, PointsToAbstractValue>?interproceduralCapturedVariablesMap, Func <IOperation, AnalysisEntity?>?interproceduralGetAnalysisEntityForFlowCapture, Func <ISymbol, ImmutableStack <IOperation>?> getInterproceduralCallStackForOwningSymbol) { _controlFlowGraph = controlFlowGraph; _wellKnownTypeProvider = wellKnownTypeProvider; _getPointsToAbstractValue = getPointsToAbstractValue; _getIsInsideAnonymousObjectInitializer = getIsInsideAnonymousObjectInitializer; _getIsLValueFlowCapture = getIsLValueFlowCapture; _interproceduralThisOrMeInstanceForCaller = interproceduralThisOrMeInstanceForCaller; _interproceduralCallStack = interproceduralCallStack; _interproceduralGetAnalysisEntityForFlowCapture = interproceduralGetAnalysisEntityForFlowCapture; _getInterproceduralCallStackForOwningSymbol = getInterproceduralCallStackForOwningSymbol; _analysisEntityMap = new Dictionary <IOperation, AnalysisEntity?>(); _tupleElementEntitiesMap = new Dictionary <ITupleOperation, ImmutableArray <AnalysisEntity> >(); _captureIdEntityMap = new Dictionary <CaptureId, AnalysisEntity>(); _captureIdCopyValueMap = new Dictionary <CaptureId, CopyAbstractValue>(); _instanceLocationsForSymbols = new Dictionary <ISymbol, PointsToAbstractValue>(); if (interproceduralCapturedVariablesMap != null) { _instanceLocationsForSymbols.AddRange(interproceduralCapturedVariablesMap); } if (interproceduralInvocationInstance != null) { ThisOrMeInstance = interproceduralInvocationInstance; } else { var thisOrMeInstanceLocation = AbstractLocation.CreateThisOrMeLocation(containingTypeSymbol, interproceduralCallStack); var instanceLocation = PointsToAbstractValue.Create(thisOrMeInstanceLocation, mayBeNull: false); ThisOrMeInstance = AnalysisEntity.CreateThisOrMeInstance(containingTypeSymbol, instanceLocation); } }
private void HandleDisposingOperation(IOperation disposingOperation, IOperation disposedInstance) { if (disposedInstance.Type?.IsDisposable(IDisposableNamedType) == false) { return; } PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(disposedInstance); foreach (AbstractLocation location in instanceLocation.Locations) { if (CurrentAnalysisData.TryGetValue(location, out DisposeAbstractValue currentDisposeValue)) { DisposeAbstractValue disposeValue = currentDisposeValue.WithNewDisposingOperation(disposingOperation); SetAbstractValue(location, disposeValue); } } }
private void HandlePossibleEscapingOperation(IOperation escapingOperation, IOperation escapedInstance) { if (escapedInstance?.Type == null || !escapedInstance.Type.IsDisposable(_iDisposable)) { return; } PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(escapedInstance); foreach (AbstractLocation location in instanceLocation.Locations) { if (CurrentAnalysisData.TryGetValue(location, out DisposeAbstractValue currentDisposeValue)) { DisposeAbstractValue newDisposeValue = currentDisposeValue.WithNewEscapingOperation(escapingOperation); SetAbstractValue(location, newDisposeValue); } } }
private IEnumerable <AnalysisEntity> GetChildAnalysisEntities(PointsToAbstractValue instanceLocationOpt) { // We are interested only in dependent child/member infos, not the root info. if (instanceLocationOpt != null) { IList <AnalysisEntity> trackedEntities = TrackedEntities?.ToList(); if (trackedEntities != null) { Debug.Assert(trackedEntities.ToSet().Count == trackedEntities.Count); foreach (var entity in trackedEntities) { if (entity.InstanceLocation.Equals(instanceLocationOpt) && entity.IsChildOrInstanceMember) { yield return(entity); } } } } }
protected IEnumerable <AnalysisEntity> GetChildAnalysisEntities(PointsToAbstractValue instanceLocationOpt) { // We are interested only in dependent child/member infos, not the root info. if (instanceLocationOpt != null) { var trackedEntitiesBuilder = ImmutableArray.CreateBuilder <AnalysisEntity>(); AddTrackedEntities(trackedEntitiesBuilder); if (trackedEntitiesBuilder.Count > 0) { Debug.Assert(trackedEntitiesBuilder.ToSet().Count == trackedEntitiesBuilder.Count); foreach (var entity in trackedEntitiesBuilder) { if (entity.InstanceLocation.Equals(instanceLocationOpt) && entity.IsChildOrInstanceMember) { yield return(entity); } } } } }
protected override TAbstractAnalysisValue ComputeAnalysisValueForEscapedRefOrOutArgument(IArgumentOperation operation, TAbstractAnalysisValue defaultValue) { Debug.Assert(operation.Parameter.RefKind is RefKind.Ref or RefKind.Out); if (operation.Value.Type != null) { PointsToAbstractValue instanceLocation = GetPointsToAbstractValue(operation); var value = HandleInstanceCreation(operation.Value, instanceLocation, defaultValue); if (operation.Parameter.RefKind == RefKind.Ref) { // Escaped ref argument must be set to unknown value. SetAbstractValue(instanceLocation, ValueDomain.UnknownOrMayBeValue); return(defaultValue); } else { // Escaped out argument is caller's responsibility and must not be set to unknown value. return(value); } } return(defaultValue); }