in Elfie/Elfie/Model/AddReferenceDatabase.cs [250:379]
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);
}
}
}