private int ImportPackageNodes(PackageDatabase source) { int packageNodeIndex, sourceMemberIndex, targetMemberIndex; sourceMemberIndex = targetMemberIndex = 0; // 0 == sentinel root sourceMemberIndex = source.DeclaredMembers.GetFirstChild(sourceMemberIndex); SymbolDetails memberDetails = source.DeclaredMemberDetails[sourceMemberIndex]; int memberName = source.DeclaredMembers.GetNameIdentifier(sourceMemberIndex); memberName = this.StringStore.FindOrAddString(source.StringStore[memberName]); targetMemberIndex = this.DeclaredMembers.Add(targetMemberIndex, memberName); this.DeclaredMemberTypes.Add(memberDetails.Type); packageNodeIndex = targetMemberIndex; Debug.Assert(memberDetails.Type == SymbolType.Package); Debug.Assert(source.DeclaredMembers.GetNextSibling(sourceMemberIndex) < 0); // Add optional pre-release node if (source.Identity.ReleaseName.IsPrereleaseVersion()) { int packageReleaseId = this.StringStore.FindOrAddString(source.Identity.ReleaseName); this.DeclaredMembers.Add(targetMemberIndex, packageReleaseId); 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()); this.DeclaredMembers.Add(targetMemberIndex, popularityRankId); this.DeclaredMemberTypes.Add(SymbolType.PopularityRank); return(packageNodeIndex); }
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); }
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); } } }
private void ImportFrameworkTargets(PackageDatabase source, int packageMemberIndex, DatabaseAddResult databaseAddResult) { Dictionary <string, HashSet <int> > frameworkTargetsToIncludedTypes = new Dictionary <string, HashSet <int> >(); HashSet <int> frameworkTargetTypes; foreach (string type in Sorted(databaseAddResult.TypeToFrameworkTargetsMap.Keys)) { HashSet <string> frameworkTargetsSet = databaseAddResult.TypeToFrameworkTargetsMap[type]; string[] frameworkTargets = new string[frameworkTargetsSet.Count]; frameworkTargetsSet.CopyTo(frameworkTargets, 0); Array.Sort(frameworkTargets); string sortedFrameworkTargets = StringExtensions.EncodeFrameworkNamesToXml(frameworkTargets); if (!frameworkTargetsToIncludedTypes.TryGetValue(sortedFrameworkTargets, out frameworkTargetTypes)) { frameworkTargetTypes = frameworkTargetsToIncludedTypes[sortedFrameworkTargets] = new HashSet <int>(); } frameworkTargetTypes.Add(databaseAddResult.TypeNameToTypeIndexMap[type]); } foreach (string sortedFrameworkTargets in frameworkTargetsToIncludedTypes.Keys) { int frameworkTargetsId = this.StringStore.FindOrAddString(sortedFrameworkTargets); int frameworkTargetIndex = this.DeclaredMembers.Add(packageMemberIndex, frameworkTargetsId); this.DeclaredMemberTypes.Add(SymbolType.FrameworkTarget); // Now we'll add all types associated with this framework target set // To do so, we grab a single example from the source that expresses // the fully-qualified name, walk its tree, and add it to the target frameworkTargetTypes = frameworkTargetsToIncludedTypes[sortedFrameworkTargets]; Stack <int> nodes = new Stack <int>(); foreach (int typeIndex in frameworkTargetTypes) { int sourceMemberIndex = typeIndex; SymbolDetails details = source.DeclaredMemberDetails[sourceMemberIndex]; while (details.Type == SymbolType.Namespace || details.Type.IsType()) { nodes.Push(sourceMemberIndex); sourceMemberIndex = source.DeclaredMembers.GetParent(sourceMemberIndex); details = source.DeclaredMemberDetails[sourceMemberIndex]; } int targetMemberIndex = frameworkTargetIndex; while (nodes.Count > 0) { sourceMemberIndex = nodes.Pop(); details = source.DeclaredMemberDetails[sourceMemberIndex]; int memberName = source.DeclaredMembers.GetNameIdentifier(sourceMemberIndex); memberName = this.StringStore.FindOrAddString(source.StringStore[memberName]); int indexInTarget; if (!this.DeclaredMembers.TryFindChildByName(targetMemberIndex, memberName, out indexInTarget)) { targetMemberIndex = this.DeclaredMembers.Add(targetMemberIndex, memberName); this.Index.AddItem(memberName, targetMemberIndex); this.DeclaredMemberTypes.Add(details.Type); } else { targetMemberIndex = indexInTarget; } } } } }