コード例 #1
0
        /// <summary>
        ///  Add public types from the given source PackageDatabase to this one.
        ///  Returns an array indicating which items were added. True means the
        ///  member or a descendant were unique. False means nothing was new.
        ///  Null means the type and descendants were excluded as non-public.
        /// </summary>
        /// <param name="source">PackageDatabase to add from</param>
        /// <returns>For each member, true if added, false if not unique, null if not a public type</returns>
        public DatabaseAddResult Add(PackageDatabase source, ArdbVersion ardbVersion)
        {
            // Merge namespaces into a common tree to find unique parts of this package
            DatabaseAddResult result = new DatabaseAddResult(source);

            AddUniqueMembers(source, 0, 0, result, ardbVersion);
            return(result);
        }
コード例 #2
0
        public AddReferenceDatabase(ArdbVersion ardbVersion)
        {
            this.DatabaseFormatVersion = ardbVersion;
            this.StringStore           = new StringStore();
            this.DeclaredMembers       = new ItemTree();

            this.DeclaredMemberTypes = new List <SymbolType>();
            this.DeclaredMemberTypes.Add(SymbolType.Package);

            this.Index = new MemberIndex();

            _mergedMembers = new MergedMembersDatabase(this.StringStore);
        }
コード例 #3
0
        private void VerifyQueryResults(AddReferenceDatabase ardb, ArdbVersion version)
        {
            // "Diagnostics."
            MemberQuery           query   = new MemberQuery(PackageDatabaseTests.NS_DIAGNOSTICS + ".", false, false);
            PartialArray <Symbol> results = new PartialArray <Symbol>(10);

            query.TryFindMembers(ardb, ref results);
            Assert.AreEqual(3, results.Count);
            Assert.AreEqual("Logger, Memory, TraceWatch", PackageDatabaseTests.ResultNamesToString(results));

            if (version == ArdbVersion.V1)
            {
                // V1 has no TFM data. This call also verifies that most current client
                // can query older format without raising an exception.
                Assert.AreEqual(String8.Empty, ardb.GetFrameworkTargets(results[0].Index));
                return;
            }

            for (int i = 0; i < results.Count; i++)
            {
                Symbol symbol = results[i];
                string fx     = ardb.GetFrameworkTargets(symbol.Index).ToString();

                if (symbol.Name.ToString() == "TraceWatch")
                {
                    Assert.AreEqual(PackageDatabaseTests.NET20, fx);
                }
                else if (symbol.Name.ToString() == "Memory")
                {
                    Assert.AreEqual(PackageDatabaseTests.NET35, fx);
                }
                else
                {
                    Assert.AreEqual(@"<tfms><tfm>net20</tfm><tfm>net35</tfm></tfms>", fx);
                }
            }
        }
コード例 #4
0
        private bool AddUniqueMembers(
            PackageDatabase source,
            int sourceMemberIndex,
            int targetMemberIndex,
            DatabaseAddResult result,
            ArdbVersion version)
        {
            int           pathLength              = result.CurrentPath.Length;
            SymbolDetails memberDetails           = source.DeclaredMemberDetails[sourceMemberIndex];
            bool          hasUniqueDescendants    = false;
            int           indexToAddChildrenUnder = targetMemberIndex;

            // Add public types and namespaces which contain either
            bool addMember = false;

            if (memberDetails.Type == SymbolType.FrameworkTarget)
            {
                String8 encodedFrameworkNames = source.StringStore[source.DeclaredMembers.GetNameIdentifier(sourceMemberIndex)];
                result.CurrentFrameworkNames = new HashSet <string>(encodedFrameworkNames.ToString().ToFrameworkNames());
            }
            else if (memberDetails.Type == SymbolType.Namespace)
            {
                addMember = ContainsPublics(source, sourceMemberIndex);
            }
            else if (memberDetails.Type == SymbolType.Assembly)
            {
                if (result.CurrentFrameworkNames != null)
                {
                    result.CurrentFrameworkNames.Clear();
                }
            }
            else if (memberDetails.Type.IsType())
            {
                addMember = memberDetails.Modifiers.HasFlag(SymbolModifier.Public);
            }

            // Add the member if it is a public type or contains them [and set 'indexInTarget' to the added member]
            if (addMember)
            {
                result.PublicTypeCount++;

                // Remap name for target StringStore [all unique names will be added anyway]
                int     memberName     = source.DeclaredMembers.GetNameIdentifier(sourceMemberIndex);
                String8 memberNameText = source.StringStore[memberName];
                result.CurrentPath.Append((result.CurrentPath.Length > 0 ? "." : "") + memberNameText.ToString());
                memberName = this.StringStore.FindOrAddString(memberNameText);

                string           fullTypeName;
                HashSet <string> frameworkTargets;

                // See if this name is already found in the merged namespace tree
                if (!this.MergedMembers.TryFindChildByName(targetMemberIndex, memberName, out indexToAddChildrenUnder))
                {
                    // If not, add it, and the tree is unique because this name is
                    indexToAddChildrenUnder = this.MergedMembers.Add(targetMemberIndex, memberName);

                    // Identify the package which added it
                    int packageNameIdentifier = this.StringStore.FindOrAddString(source.Identity.PackageName);
                    this.MergedMemberSourcePackageIdentifier.Add(packageNameIdentifier);
                    this.MergedMemberDuplicateCount.Add(1);

                    hasUniqueDescendants = true;
                    result.MergedTypeCount++;

                    if (version != ArdbVersion.V1 && memberDetails.Type.IsType())
                    {
                        // We have encountered a fully-qualified type name for the
                        // very first time. We will associate this name with the
                        // current framework target. We will also remember this
                        // sourceMemberIndex, in order to use it as the item
                        // to add when populating the ARDB.
                        fullTypeName = result.CurrentPath.ToString();
                        result.TypeToFrameworkTargetsMap.Add(fullTypeName, new HashSet <string>());

                        if (result.CurrentFrameworkNames != null)
                        {
                            result.TypeToFrameworkTargetsMap[fullTypeName].UnionWith(result.CurrentFrameworkNames);
                        }

                        result.TypeNameToTypeIndexMap.Add(fullTypeName, sourceMemberIndex);
                    }
                }
                else
                {
                    // Otherwise, if this is a duplicate with another entry in the same package, still include it (different framework targets)
                    String8 sourcePackage = this.StringStore[this.MergedMemberSourcePackageIdentifier[indexToAddChildrenUnder]];
                    if (version != ArdbVersion.V1 &&
                        result.CurrentFrameworkNames != null &&
                        sourcePackage.Equals(source.Identity.PackageName))
                    {
                        hasUniqueDescendants = true;
                        result.MergedTypeCount++;

                        if (version != ArdbVersion.V1 && memberDetails.Type.IsType())
                        {
                            // We have encountered a fully-qualified type name that we've seen
                            // before. We will record the current framework target but
                            // will already have a source member index to use to add
                            // to the ARDB later.
                            fullTypeName     = result.CurrentPath.ToString();
                            frameworkTargets = result.TypeToFrameworkTargetsMap[fullTypeName];
                            frameworkTargets.UnionWith(result.CurrentFrameworkNames);
                            Debug.Assert(result.TypeNameToTypeIndexMap.ContainsKey(fullTypeName));
                        }
                    }
                    else
                    {
                        // If this isn't unique, increment the count of copies
                        this.MergedMemberDuplicateCount[indexToAddChildrenUnder] += 1;
                    }
                }
            }

            if (!memberDetails.Type.IsType())
            {
                int childIndex = source.DeclaredMembers.GetFirstChild(sourceMemberIndex);
                while (childIndex > 0)
                {
                    hasUniqueDescendants |= AddUniqueMembers(source, childIndex, indexToAddChildrenUnder, result, version);
                    childIndex            = source.DeclaredMembers.GetNextSibling(childIndex);
                }
            }

            // Add the package which had this member to results if it wasn't unique
            if (hasUniqueDescendants == false)
            {
                result.SourcePackageNames[sourceMemberIndex] = this.StringStore[this.MergedMemberSourcePackageIdentifier[indexToAddChildrenUnder]];
            }

            // Record whether this member was unique (and added)
            result.WasMemberAdded[sourceMemberIndex] = hasUniqueDescendants;
            result.CurrentPath.Length = pathLength;
            return(hasUniqueDescendants);
        }
コード例 #5
0
        private void ImportPublics(
            PackageDatabase source,
            int sourceMemberIndex,
            int targetMemberIndex,
            bool?[] uniqueMembers,
            ArdbVersion ardbVersion)
        {
            SymbolDetails memberDetails = source.DeclaredMemberDetails[sourceMemberIndex];

            // Skip adding any subtrees which are not unique
            if (uniqueMembers != null)
            {
                bool?wasUnique = uniqueMembers[sourceMemberIndex];
                if (wasUnique == null)
                {
                    // Not added because not a public type (or ancestor wasn't)
                    return;
                }
                else if (wasUnique == false)
                {
                    // Not added because a non-unique item was detected for a package db
                    // that is not permitted to add duplicates (only MS frameworks pkgs should).
                    return;
                }
            }

            int indexInTarget = targetMemberIndex;

            // Index everything except the sentinel root. Also skip assembly nodes,
            // as matches will occur at the package node (which will actually
            // represent either a package or a reference assembly).
            if (sourceMemberIndex > 0 && (ardbVersion != ArdbVersion.V1 || memberDetails.Type != SymbolType.FrameworkTarget))
            {
                // Remap name for target StringStore
                int memberName = source.DeclaredMembers.GetNameIdentifier(sourceMemberIndex);
                memberName = this.StringStore.FindOrAddString(source.StringStore[memberName]);

                // Add this member if it doesn't already exist [ex: same namespaces in multiple binaries in Package]
                if (!this.DeclaredMembers.TryFindChildByName(targetMemberIndex, memberName, out indexInTarget))
                {
                    // Add member to target tree
                    indexInTarget = this.DeclaredMembers.Add(targetMemberIndex, memberName);
                    this.DeclaredMemberTypes.Add(memberDetails.Type);

                    // Validate DeclaredMembers and DeclaredMemberTypes are in sync
                    if (this.DeclaredMemberTypes.Count != this.DeclaredMembers.Count)
                    {
                        throw new InvalidOperationException(String.Format(Resources.DatabaseArraysOutOfSync, "DeclaredMemberTypes"));
                    }

                    // Add member to index [types and namespaces so 'find second-to-last value' search works]
                    this.Index.AddItem(memberName, indexInTarget);

                    if (memberDetails.Type == SymbolType.Package)
                    {
                        int addedNode;

                        // If this package is a pre-release version, we will introduce
                        // a new node that holds the specific release details. This is
                        // a short-term fix required to allow a fixer to request installation
                        // of a pre-release only package. Nuget will add a new API in the future
                        // that prevents the need for this node (which we can then remove).
                        if (source.Identity.ReleaseName.IsPrereleaseVersion())
                        {
                            int packageReleaseId = this.StringStore.FindOrAddString(source.Identity.ReleaseName);
                            addedNode = this.DeclaredMembers.Add(indexInTarget, packageReleaseId);

                            if (ardbVersion == ArdbVersion.V1)
                            {
                                // For V1, we injected the prerelease node as a parent to all
                                // following nodes. For post-V1, this node is a sibling with
                                // popularity rank.
                                indexInTarget = addedNode;
                            }

                            this.DeclaredMemberTypes.Add(SymbolType.Version);
                        }

                        // Inject popularity rank as an sibling node of package contents
                        int popularityRank   = source.GetPopularityRank(sourceMemberIndex);
                        int popularityRankId = this.StringStore.FindOrAddString(popularityRank.ToString());
                        addedNode = this.DeclaredMembers.Add(indexInTarget, popularityRankId);

                        if (ardbVersion == ArdbVersion.V1)
                        {
                            // For V1, we injected the popularity rank directly underneath the
                            // package or pre-release node. Post-V1, this node is a sibling of
                            // the target frameworks node.
                            // popularity rank.
                            indexInTarget = addedNode;
                        }

                        this.DeclaredMemberTypes.Add(SymbolType.PopularityRank);
                    }
                }
                else if (ardbVersion == ArdbVersion.V1)
                {
                    if (memberDetails.Type == SymbolType.Package)
                    {
                        // For V1, we need to skip injected popularity node and prerelease nodes
                        // when looking for duplicate children. This isn't required for post-V1, as
                        // these nodes are introduced as siblings of the TFM and/or assembly-level data.
                        indexInTarget = this.DeclaredMembers.GetFirstChild(indexInTarget);

                        SymbolType symbolType = this.GetMemberType(indexInTarget);
                        if (symbolType == SymbolType.Version)
                        {
                            indexInTarget = this.DeclaredMembers.GetFirstChild(indexInTarget);
                        }

                        // At this point, we should always have the popularity rank in hand
                        Debug.Assert(this.GetMemberType(indexInTarget) == SymbolType.PopularityRank);
                    }
                    else if (memberDetails.Type == SymbolType.FrameworkTarget)
                    {
                        // If we find a TFM node, we will skip past it;
                        indexInTarget = this.DeclaredMembers.GetFirstChild(indexInTarget);
                    }
                }
            }

            // Recurse on children down to type level. We do not walk type members.
            // This means that we will exclude public nested types from the database.
            if (!memberDetails.Type.IsType())
            {
                int childIndex = source.DeclaredMembers.GetFirstChild(sourceMemberIndex);
                while (childIndex > 0)
                {
                    ImportPublics(source, childIndex, indexInTarget, uniqueMembers, ardbVersion);
                    childIndex = source.DeclaredMembers.GetNextSibling(childIndex);
                }
            }
        }
コード例 #6
0
        private void AddReferenceDatabaseBasicHelper(ArdbVersion version)
        {
            AddReferenceDatabase ardb = new AddReferenceDatabase(version);
            DatabaseAddResult    result;

            // Build and add the sample PackageDatabase
            PackageDatabase source = PackageDatabaseTests.BuildDefaultSample("V1");

            result = CallAddUniqueMembers(ardb, source);

            // Verify at least something was added
            int ardbCountFirstAdd = ardb.Count;

            Assert.IsTrue(result.WasMemberAdded[0].Value);

            // Add the sample again; verify nothing was added
            source = PackageDatabaseTests.BuildDefaultSample("V2");
            result = CallAddUniqueMembers(ardb, source);
            Assert.IsFalse(result.WasMemberAdded[0].Value);
            Assert.AreEqual(ardbCountFirstAdd, ardb.Count);

            // Add a namespace with a private class; verify nothing added
            source = PackageDatabaseTests.BuildDefaultSample("V3");
            MutableSymbol diagnostics = source.MutableRoot.FindByFullName(BuildDiagnosticsNamespaceFor(source.Identity.PackageName), PackageDatabaseTests.SEPARATOR_CHAR);
            MutableSymbol internalNs  = diagnostics.AddChild(new MutableSymbol("Internal", SymbolType.Namespace));

            internalNs.AddChild(new MutableSymbol("Tracer", SymbolType.Class)
            {
                Modifiers = SymbolModifier.Internal
            });
            result = CallAddUniqueMembers(ardb, source);
            Assert.IsFalse(result.WasMemberAdded[0].Value);
            Assert.AreEqual(ardbCountFirstAdd, ardb.Count);

            // Add a new public class (existing namespace); verify it is added
            source      = PackageDatabaseTests.BuildDefaultSample("V4");
            diagnostics = source.MutableRoot.FindByFullName(BuildDiagnosticsNamespaceFor(source.Identity.PackageName), PackageDatabaseTests.SEPARATOR_CHAR);
            diagnostics.AddChild(new MutableSymbol("TraceWatch", SymbolType.Class)
            {
                Modifiers = SymbolModifier.Public | SymbolModifier.Static
            });
            result = CallAddUniqueMembers(ardb, source);
            Assert.IsTrue(result.WasMemberAdded[0].Value);
            Assert.IsTrue(result.WasMemberAdded[result.WasMemberAdded.Length - 1].Value);
            Assert.AreNotEqual(ardbCountFirstAdd, ardb.Count);

            // Verify a query [expect Diagnostics. to match Logger, Memory, and TraceWatch
            ardb.ConvertToImmutable();
            VerifyQueryResults(ardb, version);

            // Double-convert ARDB. Verify queries still work correctly.
            ardb.ConvertToImmutable();
            VerifyQueryResults(ardb, version);

            // Round trip to string; verify query still right, count matches
            string sampleArdbFilePath = "Sample.ardb.txt";

            Write.ToFile(ardb.WriteText, sampleArdbFilePath);
            AddReferenceDatabase reloaded = new AddReferenceDatabase(version);

            Read.FromFile(reloaded.ReadText, sampleArdbFilePath);

            VerifyQueryResults(reloaded, version);
            Assert.AreEqual(ardb.Count, reloaded.Count);

            string sampleRewriteArdbFilePath = "Sample.Rewrite.ardb.txt";

            Write.ToFile(reloaded.WriteText, sampleRewriteArdbFilePath);
            Assert.AreEqual(File.ReadAllText(sampleArdbFilePath), File.ReadAllText(sampleRewriteArdbFilePath));
        }