private void StopTrackingDataForEntity(AnalysisEntity analysisEntity, PooledHashSet <AnalysisEntity> allEntities) => StopTrackingDataForEntity(analysisEntity, CurrentAnalysisData, allEntities);
protected override void SetValueForParameterOnEntry(IParameterSymbol parameter, AnalysisEntity analysisEntity, ArgumentInfo <TAbstractAnalysisValue>?assignedValue) { // Only set the value for non-interprocedural case. // For interprocedural case, we have already initialized values for the underlying locations // of arguments from the input analysis data. Debug.Assert(Equals(analysisEntity.Symbol, parameter)); if (DataFlowAnalysisContext.InterproceduralAnalysisData == null && TryGetPointsToAbstractValueAtEntryBlockEnd(analysisEntity, out PointsToAbstractValue pointsToAbstractValue)) { SetValueForParameterPointsToLocationOnEntry(parameter, pointsToAbstractValue); } }
public bool TryGetValue(AnalysisEntity key, out TValue value) => CoreAnalysisData.TryGetValue(key, out value);
protected override void EscapeValueForParameterOnExit(IParameterSymbol parameter, AnalysisEntity analysisEntity) { Debug.Assert(Equals(analysisEntity.Symbol, parameter)); var escapedLocationsForParameter = GetEscapedLocations(analysisEntity); if (!escapedLocationsForParameter.IsEmpty) { EscapeValueForParameterPointsToLocationOnExit(parameter, analysisEntity, escapedLocationsForParameter); } }
protected override void ResetValueTypeInstanceAnalysisData(AnalysisEntity analysisEntity) { }
protected sealed override bool HasPredicatedDataForEntity(TAnalysisData analysisData, AnalysisEntity predicatedEntity) => (analysisData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>)?.HasPredicatedDataForEntity(predicatedEntity) == true;
protected sealed override PredicateValueKind ApplyPredicatedDataForEntity(TAnalysisData analysisData, AnalysisEntity predicatedEntity, bool trueData) => (analysisData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>)?.ApplyPredicatedDataForEntity(predicatedEntity, trueData) ?? PredicateValueKind.Unknown;
protected abstract void SetAbstractValue(AnalysisEntity analysisEntity, TAbstractAnalysisValue value);
/// <summary> /// Transfers the analysis data rooted from <paramref name="valueAnalysisEntityOpt"/> or <paramref name="assignedValueOperationOpt"/> 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 <paramref name="valueAnalysisEntityOpt"/> or allocation for the <paramref name="assignedValueOperationOpt"/> /// to all <see cref="AnalysisEntity"/> instances that share the same <see cref="AnalysisEntity.InstanceLocation"/> as <paramref name="targetAnalysisEntity"/>. /// </summary> private void TransferValueTypeInstanceAnalysisDataForAssignment(AnalysisEntity targetAnalysisEntity, AnalysisEntity valueAnalysisEntityOpt, IOperation assignedValueOperationOpt) { Debug.Assert(HasPointsToAnalysisResult); Debug.Assert(targetAnalysisEntity.Type.HasValueCopySemantics()); IEnumerable <AnalysisEntity> dependentAnalysisEntities; if (valueAnalysisEntityOpt != null) { if (!valueAnalysisEntityOpt.Type.HasValueCopySemantics()) { // Unboxing conversion from assigned value (reference type) to target (value copy semantics). // We do not need to transfer any data for such a case as there is no entity for unboxed value. return; } dependentAnalysisEntities = GetChildAnalysisEntities(valueAnalysisEntityOpt); } else if (assignedValueOperationOpt != null) { // For allocations. PointsToAbstractValue newValueLocation = GetPointsToAbstractValue(assignedValueOperationOpt); dependentAnalysisEntities = GetChildAnalysisEntities(newValueLocation); } else { return; } 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 EscapeValueForParameterOnExit(IParameterSymbol parameter, AnalysisEntity analysisEntity) { Debug.Assert(Equals(analysisEntity.SymbolOpt, parameter)); if (parameter.RefKind != RefKind.None) { SetAbstractValue(analysisEntity, GetDefaultValueForParameterOnExit(analysisEntity.Type)); } }
protected virtual TAbstractAnalysisValue GetDefaultValueForParameterOnEntry(IParameterSymbol parameter, AnalysisEntity analysisEntity) => ValueDomain.UnknownOrMayBeValue;
protected override void SetValueForParameterOnEntry(IParameterSymbol parameter, AnalysisEntity analysisEntity, ArgumentInfo <TAbstractAnalysisValue> assignedValueOpt) { Debug.Assert(Equals(analysisEntity.SymbolOpt, parameter)); if (assignedValueOpt != null) { SetAbstractValueForAssignment(analysisEntity, assignedValueOpt.Operation, assignedValueOpt.Value); } else { SetAbstractValue(analysisEntity, GetDefaultValueForParameterOnEntry(parameter, analysisEntity)); } }
private void SetAbstractValueForAssignment(AnalysisEntity targetAnalysisEntity, AnalysisEntity assignedValueEntityOpt, IOperation assignedValueOperationOpt, TAbstractAnalysisValue assignedValue) { // Value type and string type assignment has copy semantics. if (HasPointsToAnalysisResult && targetAnalysisEntity.Type.HasValueCopySemantics()) { // Reset the analysis values for analysis entities within the target instance. ResetValueTypeInstanceAnalysisData(targetAnalysisEntity); // Transfer the values of symbols from the assigned instance to the analysis entities in the target instance. TransferValueTypeInstanceAnalysisDataForAssignment(targetAnalysisEntity, assignedValueEntityOpt, assignedValueOperationOpt); } var addressSharedCopyValue = TryGetAddressSharedCopyValue(targetAnalysisEntity); if (addressSharedCopyValue != null) { Debug.Assert(addressSharedCopyValue.AnalysisEntities.Contains(targetAnalysisEntity)); foreach (var entity in addressSharedCopyValue.AnalysisEntities) { SetAbstractValue(entity, assignedValue); } } else { SetAbstractValue(targetAnalysisEntity, assignedValue); } }
protected sealed override void StopTrackingDataForParameter(IParameterSymbol parameter, AnalysisEntity analysisEntity) => throw new InvalidOperationException("Unreachable");
protected sealed override void StartTrackingPredicatedData(AnalysisEntity predicatedEntity, TAnalysisData truePredicateData, TAnalysisData falsePredicateData) => (CurrentAnalysisData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>)?.StartTrackingPredicatedData( predicatedEntity, truePredicateData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>, falsePredicateData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>);
protected abstract void ResetAbstractValue(AnalysisEntity analysisEntity);
protected sealed override void StopTrackingPredicatedData(AnalysisEntity predicatedEntity) => (CurrentAnalysisData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>)?.StopTrackingPredicatedData(predicatedEntity);
protected abstract TAbstractAnalysisValue GetAbstractValue(AnalysisEntity analysisEntity);
protected sealed override void TransferPredicatedData(AnalysisEntity fromEntity, AnalysisEntity toEntity) => (CurrentAnalysisData as AnalysisEntityBasedPredicateAnalysisData <TAbstractAnalysisValue>)?.TransferPredicatedData(fromEntity, toEntity);
protected abstract bool HasAbstractValue(AnalysisEntity analysisEntity);
protected virtual TAbstractAnalysisValue ComputeAnalysisValueForEscapedRefOrOutArgument(AnalysisEntity analysisEntity, IArgumentOperation operation, TAbstractAnalysisValue defaultValue) { Debug.Assert(operation.Parameter.RefKind == RefKind.Ref || operation.Parameter.RefKind == RefKind.Out); return(defaultValue); }
protected abstract void StopTrackingEntity(AnalysisEntity analysisEntity, TAnalysisData analysisData);
protected override void StopTrackingDataForParameter(IParameterSymbol parameter, AnalysisEntity analysisEntity) { Debug.Assert(DataFlowAnalysisContext.InterproceduralAnalysisData != null); if (parameter.RefKind == RefKind.None) { foreach (var location in analysisEntity.InstanceLocation.Locations) { StopTrackingAbstractValue(location); } } }
private ImmutableHashSet <AnalysisEntity> GetChildAnalysisEntities(AnalysisEntity analysisEntity) { return(GetChildAnalysisEntities(analysisEntity.InstanceLocation, entity => IsChildAnalysisEntity(entity, analysisEntity))); }
protected abstract void EscapeValueForParameterPointsToLocationOnExit(IParameterSymbol parameter, AnalysisEntity analysisEntity, ImmutableHashSet <AbstractLocation> escapedLocations);
protected static bool IsChildAnalysisEntity(AnalysisEntity entity, AnalysisEntity ancestorEntity) { return((!ancestorEntity.Type.HasValueCopySemantics() || entity.HasAncestor(ancestorEntity)) && IsChildAnalysisEntity(entity, ancestorEntity.InstanceLocation)); }
public bool HasAbstractValue(AnalysisEntity analysisEntity) => CoreAnalysisData.ContainsKey(analysisEntity);
protected static bool IsChildAnalysisEntity(AnalysisEntity entity, PointsToAbstractValue instanceLocation) { return(entity.InstanceLocation.Equals(instanceLocation) && entity.IsChildOrInstanceMember); }
#pragma warning disable CA1043 // Use Integral Or String Argument For Indexers public TValue this[AnalysisEntity key] => CoreAnalysisData[key];
public override DictionaryAnalysisData <AnalysisEntity, TValue> Merge(DictionaryAnalysisData <AnalysisEntity, TValue> map1, DictionaryAnalysisData <AnalysisEntity, TValue> map2) { AssertValidAnalysisData(map1); AssertValidAnalysisData(map2); var resultMap = new DictionaryAnalysisData <AnalysisEntity, TValue>(); using var newKeys = PooledHashSet <AnalysisEntity> .GetInstance(); using var valuesToMergeBuilder = ArrayBuilder <TValue> .GetInstance(5); var map2LookupIgnoringInstanceLocation = map2.Keys.Where(IsAnalysisEntityForFieldOrProperty) .ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; if (map2LookupIgnoringInstanceLocation.Count > 0 && IsAnalysisEntityForFieldOrProperty(key1)) { var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId]; if (!equivalentKeys2.Any()) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(!map2.ContainsKey(key1)); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { // Confirm that key2 and key1 are indeed EqualsIgnoringInstanceLocation // This ensures that we handle hash code clashes of EqualsIgnoringInstanceLocationId. if (!key1.EqualsIgnoringInstanceLocation(key2)) { continue; } TValue value2 = map2[key2]; valuesToMergeBuilder.Clear(); valuesToMergeBuilder.Add(value1); valuesToMergeBuilder.Add(value2); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { var mergedValue = GetMergedValue(valuesToMergeBuilder); AddNewEntryToResultMap(key1, mergedValue); } else { if (key1.Symbol == null || !Equals(key1.Symbol, key2.Symbol)) { // PERF: Do not add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities. continue; } AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { valuesToMergeBuilder.Add(existingValue); isExistingKeyInInput = true; } var isCandidateToBeSkipped = !isExistingKeyInInput && !isExistingKeyInResult; if (isCandidateToBeSkipped && CanSkipNewEntity(mergedKey)) { // PERF: Do not add a new key-value pair to the resultMap if the key is not reachable from tracked entities and PointsTo values. continue; } var mergedValue = GetMergedValue(valuesToMergeBuilder); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (isCandidateToBeSkipped && CanSkipNewEntry(mergedKey, mergedValue)) { // PERF: Do not add a new key-value pair to the resultMap if the value can be skipped. continue; } if (!isExistingKeyInInput) { newKeys.Add(mergedKey); } AddNewEntryToResultMap(mergedKey, mergedValue, isNewKey: !isExistingKeyInInput); } } } else if (map2.TryGetValue(key1, out var value2)) { TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); continue; } if (!resultMap.ContainsKey(key1)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AddNewEntryToResultMap(key1, mergedValue); } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); AddNewEntryToResultMap(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); var value = resultMap[newKey]; if (ReferenceEquals(value, GetDefaultValue(newKey))) { resultMap.Remove(newKey); } else { OnNewMergedValue(value); } } Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); AssertValidAnalysisData(resultMap); return(resultMap);