protected override void ResetCurrentAnalysisData(DisposeAnalysisData newAnalysisDataOpt = null) { // Reset the current analysis data, while ensuring that we don't violate the monotonicity, i.e. we cannot remove any existing key from currentAnalysisData. if (newAnalysisDataOpt == null) { // Just set the values for existing keys to ValueDomain.UnknownOrMayBeValue. var keys = CurrentAnalysisData.Keys.ToImmutableArray(); foreach (var key in keys) { SetAbstractValue(key, ValueDomain.UnknownOrMayBeValue); } } else { // Merge the values from current and new analysis data. var keys = CurrentAnalysisData.Keys.Concat(newAnalysisDataOpt.Keys).ToImmutableHashSet(); foreach (var key in keys) { var value1 = CurrentAnalysisData.TryGetValue(key, out var currentValue) ? currentValue : ValueDomain.Bottom; var value2 = newAnalysisDataOpt.TryGetValue(key, out var newValue) ? newValue : ValueDomain.Bottom; var mergedValue = ValueDomain.Merge(value1, value2); SetAbstractValue(key, mergedValue); } } }
private void SetValueFromPredicate( AnalysisEntity key, NullAbstractValue value, NullAnalysisData negatedCurrentAnalysisData, bool equals, bool inferInCurrentAnalysisData, bool inferInNegatedCurrentAnalysisData, ref PredicateValueKind predicateValueKind) { var negatedValue = NegatePredicateValue(value); if (CurrentAnalysisData.TryGetValue(key, out NullAbstractValue existingValue) && IsValidValueForPredicateAnalysis(existingValue) && (existingValue == NullAbstractValue.Null || value == NullAbstractValue.Null)) { if (value == existingValue && equals || negatedValue == existingValue && !equals) { predicateValueKind = PredicateValueKind.AlwaysTrue; negatedValue = NullAbstractValue.Invalid; inferInCurrentAnalysisData = false; } if (negatedValue == existingValue && equals || value == existingValue && !equals) { predicateValueKind = PredicateValueKind.AlwaysFalse; value = NullAbstractValue.Invalid; inferInNegatedCurrentAnalysisData = false; } } if (!equals) { if (value != NullAbstractValue.Invalid && negatedValue != NullAbstractValue.Invalid) { var temp = value; value = negatedValue; negatedValue = temp; } } if (inferInCurrentAnalysisData) { // Set value for the CurrentAnalysisData. SetAbstractValue(CurrentAnalysisData, key, value); } if (inferInNegatedCurrentAnalysisData) { // Set negated value for the NegatedCurrentAnalysisData. SetAbstractValue(negatedCurrentAnalysisData, key, negatedValue); } }
protected override CopyAbstractValue ComputeAnalysisValueForReferenceOperation(IOperation operation, CopyAbstractValue defaultValue) { if (AnalysisEntityFactory.TryCreate(operation, out AnalysisEntity analysisEntity)) { return(CurrentAnalysisData.TryGetValue(analysisEntity, out CopyAbstractValue value) ? value : GetDefaultCopyValue(analysisEntity)); } else { return(defaultValue); } }
private void HandlePossibleEscapingOperation(IOperation escapingOperation, ImmutableHashSet <AbstractLocation> escapedLocations) { foreach (AbstractLocation escapedLocation in escapedLocations) { if (CurrentAnalysisData.TryGetValue(escapedLocation, out DisposeAbstractValue currentDisposeValue) && currentDisposeValue.Kind != DisposeAbstractValueKind.Unknown) { DisposeAbstractValue newDisposeValue = currentDisposeValue.WithNewEscapingOperation(escapingOperation); SetAbstractValue(escapedLocation, newDisposeValue); } } }
protected override void UpdateValuesForAnalysisData(CopyAnalysisData targetAnalysisData) { // We need to trim the copy values to only include the entities that are existing keys in targetAnalysisData. var processedEntities = PooledHashSet <AnalysisEntity> .GetInstance(); var builder = ArrayBuilder <AnalysisEntity> .GetInstance(targetAnalysisData.CoreAnalysisData.Count); try { builder.AddRange(targetAnalysisData.CoreAnalysisData.Keys); for (int i = 0; i < builder.Count; i++) { var key = builder[i]; if (!processedEntities.Add(key)) { continue; } if (CurrentAnalysisData.TryGetValue(key, out var newValue)) { var existingValue = targetAnalysisData[key]; if (newValue.AnalysisEntities.Count == 1) { if (existingValue.AnalysisEntities.Count == 1) { continue; } } else if (newValue.AnalysisEntities.Count > 1) { var entitiesToExclude = newValue.AnalysisEntities.Where(e => !targetAnalysisData.HasAbstractValue(e)); if (entitiesToExclude.Any()) { newValue = newValue.WithEntitiesRemoved(entitiesToExclude); } } if (newValue != existingValue) { targetAnalysisData.SetAbstactValueForEntities(newValue, entityBeingAssignedOpt: null); } processedEntities.AddRange(newValue.AnalysisEntities); } } } finally { processedEntities.Free(); builder.Free(); } }
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); } } }
protected override PointsToAbstractValue GetAbstractValue(AnalysisEntity analysisEntity) { if (!ShouldBeTracked(analysisEntity.Type)) { return(PointsToAbstractValue.NoLocation); } if (!CurrentAnalysisData.TryGetValue(analysisEntity, out var value)) { value = _defaultPointsToValueGenerator.GetOrCreateDefaultValue(analysisEntity); } return(value); }
protected override PredicateValueKind SetValueForEqualsOrNotEqualsComparisonOperator(IBinaryOperation operation, CopyAnalysisData negatedCurrentAnalysisData, bool equals) { Debug.Assert(operation.IsComparisonOperator()); if (GetCopyAbstractValue(operation.LeftOperand).Kind != CopyAbstractValueKind.Unknown && GetCopyAbstractValue(operation.RightOperand).Kind != CopyAbstractValueKind.Unknown && AnalysisEntityFactory.TryCreate(operation.LeftOperand, out AnalysisEntity leftEntity) && AnalysisEntityFactory.TryCreate(operation.RightOperand, out AnalysisEntity rightEntity)) { var predicateKind = PredicateValueKind.Unknown; if (!CurrentAnalysisData.TryGetValue(rightEntity, out CopyAbstractValue rightValue)) { rightValue = new CopyAbstractValue(rightEntity); } else if (rightValue.AnalysisEntities.Contains(leftEntity)) { // We have "a == b && a == b" or "a == b && a != b" // For both cases, condition on right is always true or always false and redundant. predicateKind = equals ? PredicateValueKind.AlwaysTrue : PredicateValueKind.AlwaysFalse; } else if (negatedCurrentAnalysisData.TryGetValue(rightEntity, out var negatedRightValue) && negatedRightValue.AnalysisEntities.Contains(leftEntity)) { // We have "a == b || a == b" or "a == b || a != b" // For both cases, condition on right is always true or always false and redundant. predicateKind = equals ? PredicateValueKind.AlwaysFalse : PredicateValueKind.AlwaysTrue; } if (predicateKind != PredicateValueKind.Unknown) { if (!equals) { // "a == b && a != b" or "a == b || a != b" // CurrentAnalysisData and negatedCurrentAnalysisData are both unknown values. foreach (var entity in rightValue.AnalysisEntities) { SetAbstractValue(CurrentAnalysisData, entity, CopyAbstractValue.Invalid, fromPredicate: true); SetAbstractValue(negatedCurrentAnalysisData, entity, CopyAbstractValue.Invalid, fromPredicate: true); } } return(predicateKind); } var analysisData = equals ? CurrentAnalysisData : negatedCurrentAnalysisData; SetAbstractValue(analysisData, leftEntity, rightValue, fromPredicate: true); } return(PredicateValueKind.Unknown); }
protected override PointsToAbstractValue GetAbstractValue(AnalysisEntity analysisEntity) { if (analysisEntity.Type.HasValueCopySemantics()) { return(PointsToAbstractValue.NoLocation); } if (!CurrentAnalysisData.TryGetValue(analysisEntity, out var value)) { value = analysisEntity.SymbolOpt?.Kind == SymbolKind.Local ? ValueDomain.Bottom : ValueDomain.UnknownOrMayBeValue; } return(value); }
protected override void SetValueForParameterOnEntry(IParameterSymbol parameter, AnalysisEntity analysisEntity, ArgumentInfo <CopyAbstractValue> assignedValueOpt) { CopyAbstractValue copyValue; if (assignedValueOpt != null) { var assignedEntities = assignedValueOpt.Value.AnalysisEntities; if (assignedValueOpt.AnalysisEntityOpt != null && !assignedEntities.Contains(assignedValueOpt.AnalysisEntityOpt)) { assignedEntities = assignedEntities.Add(assignedValueOpt.AnalysisEntityOpt); } var newAnalysisEntities = assignedEntities; CopyAbstractValueKind newKind; if (assignedValueOpt.Value.Kind.IsKnown()) { newKind = assignedValueOpt.Value.Kind; } else if (assignedValueOpt.AnalysisEntityOpt == null || assignedValueOpt.AnalysisEntityOpt.Type.IsValueType) { newKind = CopyAbstractValueKind.KnownValueCopy; } else { newKind = CopyAbstractValueKind.KnownReferenceCopy; } foreach (var entity in assignedEntities) { if (CurrentAnalysisData.TryGetValue(entity, out var existingValue)) { newAnalysisEntities = newAnalysisEntities.Union(existingValue.AnalysisEntities); newKind = newKind.MergeIfBothKnown(existingValue.Kind); } } copyValue = assignedValueOpt.Value.AnalysisEntities.Count == newAnalysisEntities.Count ? assignedValueOpt.Value : new CopyAbstractValue(newAnalysisEntities, newKind); } else { copyValue = GetDefaultCopyValue(analysisEntity); } SetAbstractValue(CurrentAnalysisData, analysisEntity, copyValue, TryGetAddressSharedCopyValue, initializingParameters: true); }
private void SetValueForComparisonOperator(IOperation target, IOperation assignedValue, bool equals, ref PredicateValueKind predicateValueKind, ValueContentAnalysisData targetAnalysisData) { ValueContentAbstractValue currentAssignedValue = GetCachedAbstractValue(assignedValue); if (currentAssignedValue.IsLiteralState && AnalysisEntityFactory.TryCreate(target, out AnalysisEntity targetEntity)) { if (CurrentAnalysisData.TryGetValue(targetEntity, out ValueContentAbstractValue existingTargetValue) && existingTargetValue.IsLiteralState) { var newValue = currentAssignedValue.IntersectLiteralValues(existingTargetValue); if (newValue.NonLiteralState == ValueContainsNonLiteralState.Invalid) { predicateValueKind = equals ? PredicateValueKind.AlwaysFalse : PredicateValueKind.AlwaysTrue; } else if (predicateValueKind != PredicateValueKind.AlwaysFalse && newValue.IsLiteralState && newValue.LiteralValues.Count == 1 && currentAssignedValue.LiteralValues.Count == 1 && existingTargetValue.LiteralValues.Count == 1) { predicateValueKind = equals ? PredicateValueKind.AlwaysTrue : PredicateValueKind.AlwaysFalse; } currentAssignedValue = newValue; } if (equals) { CopyAbstractValue copyValue = GetCopyAbstractValue(target); if (copyValue.Kind.IsKnown()) { // https://github.com/dotnet/roslyn-analyzers/issues/2106 tracks enabling the below assert. //Debug.Assert(copyValue.AnalysisEntities.Contains(targetEntity)); foreach (var analysisEntity in copyValue.AnalysisEntities) { SetAbstractValue(targetAnalysisData, analysisEntity, currentAssignedValue); } } else { SetAbstractValue(targetAnalysisData, targetEntity, currentAssignedValue); } } } }
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); } } }
protected override ValueContentAbstractValue GetAbstractValue(AnalysisEntity analysisEntity) => CurrentAnalysisData.TryGetValue(analysisEntity, out var value) ? value : ValueDomain.UnknownOrMayBeValue;
private bool IsNotOrMaybeValidatedLocation(AbstractLocation location) => CurrentAnalysisData.TryGetValue(location, out var value) && (value == ParameterValidationAbstractValue.NotValidated || value == ParameterValidationAbstractValue.MayBeValidated);
protected override ParameterValidationAbstractValue GetAbstractValue(AbstractLocation location) => CurrentAnalysisData.TryGetValue(location, out var value) ? value : ValueDomain.Bottom;
protected override DisposeAbstractValue GetAbstractValue(AbstractLocation location) => CurrentAnalysisData.TryGetValue(location, out var value) ? value : ValueDomain.UnknownOrMayBeValue;
protected override NullAbstractValue GetAbstractValue(ISymbol symbol) => CurrentAnalysisData.TryGetValue(symbol, out var value) ? value : UnknownOrMayBeValue;
protected override CopyAbstractValue GetAbstractValue(AnalysisEntity analysisEntity) => CurrentAnalysisData.TryGetValue(analysisEntity, out var value) ? value : CopyAbstractValue.Unknown;
private void SetValueFromPredicate( AnalysisEntity key, NullAbstractValue value, PointsToAnalysisData negatedCurrentAnalysisData, bool equals, bool inferInCurrentAnalysisData, bool inferInNegatedCurrentAnalysisData, IOperation target, ref PredicateValueKind predicateValueKind) { // Compute the negated value. NullAbstractValue negatedValue = NegatePredicateValue(value); // Check if the key already has an existing "Null" or "NotNull" NullState that would make the condition always true or false. // If so, set the predicateValueKind to always true/false, set the value in branch that can never be taken to NullAbstractValue.Invalid // and turn off value inference in one of the branch. if (CurrentAnalysisData.TryGetValue(key, out PointsToAbstractValue existingPointsToValue)) { NullAbstractValue existingNullValue = existingPointsToValue.NullState; if (IsValidValueForPredicateAnalysis(existingNullValue) && (existingNullValue == NullAbstractValue.Null || value == NullAbstractValue.Null)) { if (value == existingNullValue && equals || negatedValue == existingNullValue && !equals) { predicateValueKind = PredicateValueKind.AlwaysTrue; negatedValue = NullAbstractValue.Invalid; inferInCurrentAnalysisData = false; } if (negatedValue == existingNullValue && equals || value == existingNullValue && !equals) { predicateValueKind = PredicateValueKind.AlwaysFalse; value = NullAbstractValue.Invalid; inferInNegatedCurrentAnalysisData = false; } } } // Swap value and negatedValue if we are processing not-equals operator. if (!equals) { if (value != NullAbstractValue.Invalid && negatedValue != NullAbstractValue.Invalid) { var temp = value; value = negatedValue; negatedValue = temp; } } if (inferInCurrentAnalysisData) { // Set value for the CurrentAnalysisData. SetAbstractValueFromPredicate(CurrentAnalysisData, key, target, value); } if (inferInNegatedCurrentAnalysisData) { // Set negated value for the NegatedCurrentAnalysisData. SetAbstractValueFromPredicate(negatedCurrentAnalysisData, key, target, negatedValue); } }