Beispiel #1
0
        /// <summary>
        /// Compare the root elements and, if they are equal, match up children by shallow equality, recursing on each pair.
        /// </summary>
        /// <returns>True if the elements are equal, false otherwise (in which case, firstMismatch will try to indicate a point of disagreement).</returns>
        public static bool CheckEqual(XElement expectedRoot, XElement actualRoot, IEqualityComparer <XElement> shallowComparer, out Tuple <XElement, XElement> firstMismatch)
        {
            Assert.NotNull(expectedRoot);
            Assert.NotNull(actualRoot);
            Assert.NotNull(shallowComparer);

            Tuple <XElement, XElement> rootPair = new Tuple <XElement, XElement>(expectedRoot, actualRoot);

            if (!shallowComparer.Equals(expectedRoot, actualRoot))
            {
                firstMismatch = rootPair;
                return(false);
            }

            Stack <Tuple <XElement, XElement> > stack = new Stack <Tuple <XElement, XElement> >();

            stack.Push(rootPair);

            while (stack.Count > 0)
            {
                Tuple <XElement, XElement> pair = stack.Pop();
                firstMismatch = pair;                                         // Will be overwritten if this pair is a match.
                Debug.Assert(shallowComparer.Equals(pair.Item1, pair.Item2)); // Shouldn't have been pushed otherwise.

                XElement[] children1 = pair.Item1.Elements().ToArray();
                MultiDictionary <XElement, XElement> children2Dict = new MultiDictionary <XElement, XElement>(shallowComparer);

                int children2Count = 0;
                foreach (XElement child in pair.Item2.Elements())
                {
                    children2Dict.Add(child, child);
                    children2Count++;
                }

                if (children1.Length != children2Count)
                {
                    return(false);
                }


                HashSet <XElement> children2Used = new HashSet <XElement>(ReferenceEqualityComparer.Instance);
                foreach (XElement child1 in children1)
                {
                    IEnumerable <XElement> candidates2;
                    if (children2Dict.TryGetMultipleValues(child1, out candidates2))
                    {
                        XElement child2 = candidates2.FirstOrDefault(candidate => !children2Used.Contains(candidate));
                        if (child2 == null)
                        {
                            return(false);
                        }
                        children2Used.Add(child2);
                        stack.Push(new Tuple <XElement, XElement>(child1, child2));
                    }
                    else
                    {
                        return(false);
                    }
                }

                if (children2Used.Count < children1.Length)
                {
                    return(false);
                }
            }

            firstMismatch = null;
            return(true);
        }
        private void CheckMemberDistinctness(NamespaceOrTypeSymbol symbol)
        {
            System.Diagnostics.Debug.Assert(IsAccessibleOutsideAssembly(symbol));
            System.Diagnostics.Debug.Assert(IsTrue(GetDeclaredOrInheritedCompliance(symbol)));

            MultiDictionary<string, Symbol> seenByName = new MultiDictionary<string, Symbol>(CaseInsensitiveComparison.Comparer);

            // For types, we also need to consider collisions with inherited members.
            if (symbol.Kind != SymbolKind.Namespace)
            {
                NamedTypeSymbol type = (NamedTypeSymbol)symbol;

                // NOTE: As in dev11 we're using Interfaces, rather than AllInterfaces.
                // This seems like a bug, but it's easier to reproduce it than to deal
                // with all the potential breaks.
                // NOTE: It's not clear why dev11 is looking in interfaces at all. Maybe
                // it was only supposed to happen for interface types?
                foreach (NamedTypeSymbol @interface in type.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics) // NOTE: would be handrolled in a standalone component.
                {
                    if (!IsAccessibleOutsideAssembly(@interface)) continue;

                    foreach (Symbol member in @interface.GetMembersUnordered())
                    {
                        // NOTE: As in dev11 we filter out overriding methods and properties (but not events).
                        // NOTE: As in dev11, we ignore the CLS compliance of the interface and its members.
                        if (IsAccessibleIfContainerIsAccessible(member) &&
                            (!member.IsOverride || !(member.Kind == SymbolKind.Method || member.Kind == SymbolKind.Property)))
                        {
                            seenByName.Add(member.Name, member);
                        }
                    }
                }

                NamedTypeSymbol baseType = type.BaseTypeNoUseSiteDiagnostics;
                while ((object)baseType != null)
                {
                    foreach (Symbol member in baseType.GetMembersUnordered())
                    {
                        // NOTE: As in dev11 we filter out overriding methods and properties (but not events).
                        // NOTE: Unlike for interface members, we check CLS compliance of base type members.
                        if (IsAccessibleOutsideAssembly(member) &&
                            IsTrue(GetDeclaredOrInheritedCompliance(member)) &&
                            (!member.IsOverride || !(member.Kind == SymbolKind.Method || member.Kind == SymbolKind.Property)))
                        {
                            seenByName.Add(member.Name, member);
                        }
                    }

                    baseType = baseType.BaseTypeNoUseSiteDiagnostics;
                }
            }

            // NOTE: visit the members in order so that the same one is always reported as a conflict.
            foreach (Symbol member in symbol.GetMembers())
            {
                // Filter out uninteresting members:
                if (DoNotVisit(member) ||
                    !IsAccessibleIfContainerIsAccessible(member) || // We already know that the container is accessible.
                    !IsTrue(GetDeclaredOrInheritedCompliance(member)) ||
                    member.IsOverride)
                {
                    continue;
                }

                string name = member.Name;

                IEnumerable<Symbol> sameNameSymbols;
                if (seenByName.TryGetMultipleValues(name, out sameNameSymbols))
                {
                    CheckSymbolDistinctness(member, sameNameSymbols);
                }

                seenByName.Add(name, member);
            }
        }