Пример #1
0
        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);
        }
Пример #2
0
 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));
            }
Пример #5
0
        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));
        }
Пример #8
0
 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);
 }
Пример #9
0
 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));
        }
Пример #14
0
            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);
            }
Пример #15
0
        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);
            }
Пример #18
0
        /// <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);
         }
     }
 }
Пример #20
0
        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);