protected override IDictionary <AnalysisEntity, TValue> MergeCore(IDictionary <AnalysisEntity, TValue> map1, IDictionary <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); Debug.Assert(map2 != null); var resultMap = new Dictionary <AnalysisEntity, TValue>(); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; var equivalentKeys2 = map2.Keys.Where(key => key.EqualsIgnoringInstanceLocation(key1)); if (!equivalentKeys2.Any()) { // Absence of entity from one branch indicates we don't know its values. TValue mergedValue = ValueDomain.Merge(value1, ValueDomain.UnknownOrMayBeValue); resultMap.Add(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { TValue value2 = map2[key2]; TValue mergedValue = ValueDomain.Merge(value1, value2); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { resultMap[key1] = mergedValue; } else { AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); if (resultMap.TryGetValue(mergedKey, out var existingValue)) { mergedValue = ValueDomain.Merge(mergedValue, existingValue); } else if (ReferenceEquals(mergedValue, ValueDomain.UnknownOrMayBeValue)) { // Do no add a new key-value pair to the resultMap if the value is UnknownOrMayBeValue. continue; } resultMap[mergedKey] = mergedValue; } } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { // Absence of entity from one branch indicates we don't know its values. TValue mergedValue = ValueDomain.Merge(value2, ValueDomain.UnknownOrMayBeValue); resultMap.Add(key2, mergedValue); } } return(resultMap); }
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); } } }
/// <summary> /// Checks if the value domain is equal to another. <b>Method skips a names comparison.</b> /// </summary> /// <param name="instance">The compared value domain.</param> /// <param name="valueDomain">The value domain to compare.</param> /// <param name="allNumsEqual">Specifies if an integer data type is equal to a number data type.</param> /// <param name="allEqualsToNull">Specifies if a none data type is equal to other.</param> /// <returns>Value specyfing equality.</returns> public static bool EqualsObj(this ValueDomain instance, ValueDomain valueDomain, bool allNumsEqual = false, bool allEqualsToNull = false) { if (!instance.DataType.EqualsObj(valueDomain.DataType, allNumsEqual, allEqualsToNull) || instance.Signature != valueDomain.Signature) { return(false); } return(true); }
TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { if (key.HasConstantValue) { return(value); } var defaultValue = GetDefaultValue(key); return(ValueDomain.Merge(value, defaultValue)); }
protected override void SetAbstractValueForAssignment(IOperation target, IOperation assignedValueOperation, TAbstractAnalysisValue assignedValue, bool mayBeAssignment = false) { if (AnalysisEntityFactory.TryCreate(target, out AnalysisEntity targetAnalysisEntity)) { if (mayBeAssignment) { assignedValue = ValueDomain.Merge(GetAbstractValue(targetAnalysisEntity), assignedValue); } SetAbstractValueForAssignment(targetAnalysisEntity, assignedValueOperation, assignedValue); } }
internal TAbstractAnalysisValue VisitArray(IEnumerable <IOperation> operations, object argument) { var values = new List <TAbstractAnalysisValue>(); foreach (var operation in operations) { var result = VisitOperationArrayElement(operation, argument); values.Add(result); } return(ValueDomain.Merge(values)); }
public override TAbstractAnalysisValue VisitConditional(IConditionalOperation operation, object argument) { var _ = Visit(operation.Condition, argument); var whenTrue = Visit(operation.WhenTrue, argument); var whenFalse = Visit(operation.WhenFalse, argument); if (operation.Condition.ConstantValue.HasValue && operation.Condition.ConstantValue.Value is bool condition) { return(condition ? whenTrue : whenFalse); } return(ValueDomain.Merge(whenTrue, whenFalse)); }
protected sealed override void ComputeHashCodeParts(ArrayBuilder <int> builder) { builder.Add(ValueDomain.GetHashCode()); builder.Add(OwningSymbol.GetHashCode()); builder.Add(ControlFlowGraph.OriginalOperation.GetHashCode()); builder.Add(InterproceduralAnalysisConfiguration.GetHashCode()); builder.Add(PessimisticAnalysis.GetHashCode()); builder.Add(PredicateAnalysis.GetHashCode()); builder.Add(ExceptionPathsAnalysis.GetHashCode()); builder.Add(CopyAnalysisResultOpt.GetHashCodeOrDefault()); builder.Add(PointsToAnalysisResultOpt.GetHashCodeOrDefault()); builder.Add(InterproceduralAnalysisDataOpt.GetHashCodeOrDefault()); builder.Add(InterproceduralAnalysisPredicateOpt.GetHashCodeOrDefault()); ComputeHashCodePartsSpecific(builder); }
protected sealed override void ComputeHashCodeParts(Action <int> addPart) { addPart(ValueDomain.GetHashCode()); addPart(OwningSymbol.GetHashCode()); addPart(ControlFlowGraph.OriginalOperation.GetHashCode()); addPart(AnalyzerOptions.GetHashCode()); addPart(InterproceduralAnalysisConfiguration.GetHashCode()); addPart(PessimisticAnalysis.GetHashCode()); addPart(PredicateAnalysis.GetHashCode()); addPart(ExceptionPathsAnalysis.GetHashCode()); addPart(CopyAnalysisResultOpt.GetHashCodeOrDefault()); addPart(PointsToAnalysisResultOpt.GetHashCodeOrDefault()); addPart(ValueContentAnalysisResultOpt.GetHashCodeOrDefault()); addPart(InterproceduralAnalysisDataOpt.GetHashCodeOrDefault()); addPart(InterproceduralAnalysisPredicateOpt.GetHashCodeOrDefault()); ComputeHashCodePartsSpecific(addPart); }
protected sealed override void ComputeHashCodeParts(ref RoslynHashCode hashCode) { hashCode.Add(ValueDomain.GetHashCode()); hashCode.Add(OwningSymbol.GetHashCode()); hashCode.Add(ControlFlowGraph.GetHashCode()); hashCode.Add(AnalyzerOptions.GetHashCode()); hashCode.Add(InterproceduralAnalysisConfiguration.GetHashCode()); hashCode.Add(PessimisticAnalysis.GetHashCode()); hashCode.Add(PredicateAnalysis.GetHashCode()); hashCode.Add(ExceptionPathsAnalysis.GetHashCode()); hashCode.Add(CopyAnalysisResult.GetHashCodeOrDefault()); hashCode.Add(PointsToAnalysisResult.GetHashCodeOrDefault()); hashCode.Add(ValueContentAnalysisResult.GetHashCodeOrDefault()); hashCode.Add(InterproceduralAnalysisData.GetHashCodeOrDefault()); hashCode.Add(InterproceduralAnalysisPredicate.GetHashCodeOrDefault()); ComputeHashCodePartsSpecific(ref hashCode); }
public override TAbstractAnalysisValue VisitCoalesce(ICoalesceOperation operation, object argument) { var leftValue = Visit(operation.Value, argument); var rightValue = Visit(operation.WhenNull, argument); var leftNullValue = GetNullAbstractValue(operation.Value); switch (leftNullValue) { case NullAbstractValue.Null: return(rightValue); case NullAbstractValue.NotNull: return(leftValue); default: return(ValueDomain.Merge(leftValue, rightValue)); } }
public override TAbstractAnalysisValue VisitConditionalAccess(IConditionalAccessOperation operation, object argument) { var leftValue = Visit(operation.Operation, argument); var whenNullValue = Visit(operation.WhenNotNull, argument); var leftNullValue = GetNullAbstractValue(operation.Operation); switch (leftNullValue) { case NullAbstractValue.Null: return(GetAbstractDefaultValue(operation.WhenNotNull.Type)); case NullAbstractValue.NotNull: return(whenNullValue); default: var value1 = GetAbstractDefaultValue(operation.WhenNotNull.Type); return(ValueDomain.Merge(value1, whenNullValue)); } }
protected sealed override bool ComputeEqualsByHashCodeParts(CacheBasedEquatable <TAnalysisContext> obj) { var other = (AbstractDataFlowAnalysisContext <TAnalysisData, TAnalysisContext, TAnalysisResult, TAbstractAnalysisValue>)obj; return(ValueDomain.GetHashCode() == other.ValueDomain.GetHashCode() && OwningSymbol.GetHashCode() == other.OwningSymbol.GetHashCode() && ControlFlowGraph.GetHashCode() == other.ControlFlowGraph.GetHashCode() && AnalyzerOptions.GetHashCode() == other.AnalyzerOptions.GetHashCode() && InterproceduralAnalysisConfiguration.GetHashCode() == other.InterproceduralAnalysisConfiguration.GetHashCode() && PessimisticAnalysis.GetHashCode() == other.PessimisticAnalysis.GetHashCode() && PredicateAnalysis.GetHashCode() == other.PredicateAnalysis.GetHashCode() && ExceptionPathsAnalysis.GetHashCode() == other.ExceptionPathsAnalysis.GetHashCode() && CopyAnalysisResult.GetHashCodeOrDefault() == other.CopyAnalysisResult.GetHashCodeOrDefault() && PointsToAnalysisResult.GetHashCodeOrDefault() == other.PointsToAnalysisResult.GetHashCodeOrDefault() && ValueContentAnalysisResult.GetHashCodeOrDefault() == other.ValueContentAnalysisResult.GetHashCodeOrDefault() && InterproceduralAnalysisData.GetHashCodeOrDefault() == other.InterproceduralAnalysisData.GetHashCodeOrDefault() && InterproceduralAnalysisPredicate.GetHashCodeOrDefault() == other.InterproceduralAnalysisPredicate.GetHashCodeOrDefault() && ComputeEqualsByHashCodeParts(other)); }
public override CopyAnalysisData Merge(CopyAnalysisData map1, CopyAnalysisData map2) { Debug.Assert(map1 != null); Debug.Assert(map2 != null); AssertValidCopyAnalysisData(map1); AssertValidCopyAnalysisData(map2); var result = new Dictionary <AnalysisEntity, CopyAbstractValue>(); foreach (var kvp in map1) { var key = kvp.Key; var value1 = kvp.Value; // If the key exists in both maps, use the merged value. // Otherwise, use the default value. CopyAbstractValue mergedValue; if (map2.TryGetValue(key, out var value2)) { mergedValue = ValueDomain.Merge(value1, value2); } else { mergedValue = GetDefaultValue(key); } result.Add(key, mergedValue); } foreach (var kvp in map2) { if (!result.ContainsKey(kvp.Key)) { result.Add(kvp.Key, GetDefaultValue(kvp.Key)); } } AssertValidCopyAnalysisData(result); return(result); CopyAbstractValue GetDefaultValue(AnalysisEntity analysisEntity) => new CopyAbstractValue(analysisEntity); }
protected override void SetAbstractValueForAssignment(IOperation target, IOperation?assignedValueOperation, TAbstractAnalysisValue assignedValue, bool mayBeAssignment = false) { if (AnalysisEntityFactory.TryCreate(target, out var targetAnalysisEntity)) { if (!HasCompletePointsToAnalysisResult && targetAnalysisEntity.IsChildOrInstanceMemberNeedingCompletePointsToAnalysis()) { // We are not tracking points to values for fields and properties. // So, it is not possible to accurately track value changes to target entity which is a member. // Conservatively assume that the entity is assigned an unknown value. assignedValue = ValueDomain.UnknownOrMayBeValue; } else if (mayBeAssignment) { assignedValue = ValueDomain.Merge(GetAbstractValue(targetAnalysisEntity), assignedValue); } SetAbstractValueForAssignment(targetAnalysisEntity, assignedValueOperation, assignedValue); } }
TValue GetMergedValue(ArrayBuilder <TValue> values) { Debug.Assert(values.Count > 0); var mergedValue = values[0]; for (var i = 1; i < values.Count; i++) { mergedValue = GetMergedValueCore(mergedValue, values[i]); } return(mergedValue); TValue GetMergedValueCore(TValue value1, TValue value2) { TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); return(mergedValue); } }
#pragma warning disable CA1725 // Parameter names should match base declaration public override CoreCopyAnalysisData Merge(CoreCopyAnalysisData map1, CoreCopyAnalysisData map2) #pragma warning restore CA1725 // Parameter names should match base declaration { CopyAnalysisData.AssertValidCopyAnalysisData(map1); CopyAnalysisData.AssertValidCopyAnalysisData(map2); var result = new DictionaryAnalysisData <AnalysisEntity, CopyAbstractValue>(); foreach (var kvp in map1) { var key = kvp.Key; var value1 = kvp.Value; // If the key exists in both maps, use the merged value. // Otherwise, use the default value. CopyAbstractValue mergedValue; if (map2.TryGetValue(key, out var value2)) { mergedValue = ValueDomain.Merge(value1, value2); } else { mergedValue = _getDefaultCopyValue(key); } result.Add(key, mergedValue); } foreach (var kvp in map2) { if (!result.ContainsKey(kvp.Key)) { result.Add(kvp.Key, _getDefaultCopyValue(kvp.Key)); } } CopyAnalysisData.AssertValidCopyAnalysisData(result); return(result); }
/// <summary> /// Resets the analysis data for an object instance passed around as an <see cref="IArgumentOperation"/>. /// </summary> private void ResetInstanceAnalysisDataForArgument(IArgumentOperation operation) { // For reference types passed as arguments, // reset all analysis data for the instance members as the content might change for them. if (HasPointsToAnalysisResult && PessimisticAnalysis && operation.Value.Type != null && !operation.Value.Type.HasValueCopySemantics()) { ResetReferenceTypeInstanceAnalysisData(operation.Value); } // Handle ref/out arguments as escapes. if (operation.Parameter.RefKind != RefKind.None) { var value = GetCachedAbstractValue(operation); if (operation.Parameter.RefKind != RefKind.Out) { value = ValueDomain.Merge(value, GetCachedAbstractValue(operation.Value)); } SetAbstractValueForAssignment(operation.Value, operation, value); } }
protected void ResetCurrentAnalysisData(IDictionary <AbstractLocation, TAbstractAnalysisValue> currentAnalysisData, IDictionary <AbstractLocation, TAbstractAnalysisValue> newAnalysisDataOpt) { // 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. foreach (var key in currentAnalysisData.Keys) { SetAbstractValue(key, ValueDomain.UnknownOrMayBeValue); } } else { // Merge the values from current and new analysis data. var keys = currentAnalysisData.Keys.Concat(newAnalysisDataOpt.Keys).ToArray(); 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); } } }
public override DictionaryAnalysisData <AnalysisEntity, TValue> Merge(DictionaryAnalysisData <AnalysisEntity, TValue> map1, DictionaryAnalysisData <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); AssertValidAnalysisData(map1); Debug.Assert(map2 != null); AssertValidAnalysisData(map2); TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { if (key.HasConstantValue) { return(value); } var defaultValue = GetDefaultValue(key); return(ValueDomain.Merge(value, defaultValue)); } var resultMap = new DictionaryAnalysisData <AnalysisEntity, TValue>(); var newKeys = PooledHashSet <AnalysisEntity> .GetInstance(); 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); AssertValidEntryForMergedMap(key1, mergedValue); resultMap.Add(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]; TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { AssertValidEntryForMergedMap(key1, mergedValue); resultMap[key1] = mergedValue; } else { if (key1.SymbolOpt == null || key1.SymbolOpt != key2.SymbolOpt) { // 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); TValue newMergedValue = mergedValue; var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } Debug.Assert(ValueDomain.Compare(value1, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(mergedValue, newMergedValue) <= 0); mergedValue = newMergedValue; if (!isExistingKeyInInput && !isExistingKeyInResult && 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); } AssertValidEntryForMergedMap(mergedKey, mergedValue); resultMap[mergedKey] = mergedValue; } } } 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); resultMap.Add(key1, mergedValue); continue; } if (!resultMap.ContainsKey(key1)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); AssertValidEntryForMergedMap(key1, mergedValue); resultMap.Add(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); AssertValidEntryForMergedMap(key2, mergedValue); resultMap.Add(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); if (ReferenceEquals(resultMap[newKey], GetDefaultValue(newKey))) { resultMap.Remove(newKey); } } newKeys.Free(); Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); AssertValidAnalysisData(resultMap); return(resultMap); bool IsAnalysisEntityForFieldOrProperty(AnalysisEntity entity) => entity.SymbolOpt?.Kind == SymbolKind.Field || entity.SymbolOpt?.Kind == SymbolKind.Property; }
protected override IDictionary <AnalysisEntity, TValue> MergeCore(IDictionary <AnalysisEntity, TValue> map1, IDictionary <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); Debug.Assert(map2 != null); TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { var defaultValue = GetDefaultValue(key); return(key.SymbolOpt != null?ValueDomain.Merge(value, defaultValue) : defaultValue); } var resultMap = new Dictionary <AnalysisEntity, TValue>(); var map2LookupIgnoringInstanceLocation = map2.Keys.ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; var equivalentKeys2 = map2LookupIgnoringInstanceLocation[key1.EqualsIgnoringInstanceLocationId]; if (!equivalentKeys2.Any()) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key1, value1); resultMap.Add(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { TValue value2 = map2[key2]; TValue mergedValue = ValueDomain.Merge(value1, value2); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { resultMap[key1] = mergedValue; } else { AnalysisEntity mergedKey = key1.WithMergedInstanceLocation(key2); if (resultMap.TryGetValue(mergedKey, out var existingValue)) { mergedValue = ValueDomain.Merge(mergedValue, existingValue); } else if (ReferenceEquals(mergedValue, ValueDomain.UnknownOrMayBeValue)) { // PERF: Do not add a new key-value pair to the resultMap if the value is UnknownOrMayBeValue. continue; } else if (key1.SymbolOpt == null || key1.SymbolOpt != key2.SymbolOpt) { // PERF: Do not add a add a new key-value pair to the resultMap for unrelated entities or non-symbol based entities. continue; } resultMap[mergedKey] = mergedValue; } } } foreach (var kvp in map2) { var key2 = kvp.Key; var value2 = kvp.Value; if (!resultMap.ContainsKey(key2)) { TValue mergedValue = GetMergedValueForEntityPresentInOneMap(key2, value2); resultMap.Add(key2, mergedValue); } } return(resultMap); }
public override IDictionary <AnalysisEntity, TValue> Merge(IDictionary <AnalysisEntity, TValue> map1, IDictionary <AnalysisEntity, TValue> map2) { Debug.Assert(map1 != null); Debug.Assert(map2 != null); TValue GetMergedValueForEntityPresentInOneMap(AnalysisEntity key, TValue value) { var defaultValue = GetDefaultValue(key); return(ValueDomain.Merge(value, defaultValue)); } var resultMap = new Dictionary <AnalysisEntity, TValue>(); var newKeys = new HashSet <AnalysisEntity>(); var map2LookupIgnoringInstanceLocation = map2.Keys.ToLookup(entity => entity.EqualsIgnoringInstanceLocationId); foreach (var entry1 in map1) { AnalysisEntity key1 = entry1.Key; TValue value1 = entry1.Value; 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); resultMap.Add(key1, mergedValue); continue; } foreach (AnalysisEntity key2 in equivalentKeys2) { TValue value2 = map2[key2]; TValue mergedValue = ValueDomain.Merge(value1, value2); Debug.Assert(ValueDomain.Compare(value1, mergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, mergedValue) <= 0); if (key1.InstanceLocation.Equals(key2.InstanceLocation)) { resultMap[key1] = mergedValue; } else { if (key1.SymbolOpt == null || key1.SymbolOpt != key2.SymbolOpt) { // 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); TValue newMergedValue = mergedValue; var isExistingKeyInInput = false; var isExistingKeyInResult = false; if (resultMap.TryGetValue(mergedKey, out var existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInResult = true; } if (map1.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } if (map2.TryGetValue(mergedKey, out existingValue)) { newMergedValue = ValueDomain.Merge(newMergedValue, existingValue); isExistingKeyInInput = true; } Debug.Assert(ValueDomain.Compare(value1, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(value2, newMergedValue) <= 0); Debug.Assert(ValueDomain.Compare(mergedValue, newMergedValue) <= 0); mergedValue = newMergedValue; if (!isExistingKeyInInput && !isExistingKeyInResult && 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); } resultMap[mergedKey] = mergedValue; } } if (!resultMap.ContainsKey(key1)) { resultMap[key1] = ValueDomain.UnknownOrMayBeValue; } } 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); resultMap.Add(key2, mergedValue); } } foreach (var newKey in newKeys) { Debug.Assert(!map1.ContainsKey(newKey)); Debug.Assert(!map2.ContainsKey(newKey)); if (ReferenceEquals(resultMap[newKey], GetDefaultValue(newKey))) { resultMap.Remove(newKey); } } Debug.Assert(Compare(map1, resultMap) <= 0); Debug.Assert(Compare(map2, resultMap) <= 0); return(resultMap); }
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.SymbolOpt == null || !Equals(key1.SymbolOpt, key2.SymbolOpt)) { // 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);