private void ResolveCircularTypes(List <IRTypeNode> circle) { // All unique types within the given list are moved together into a seperate // namespace, because that's the only way to solve these kind of circular dependancies. // This list will NEVER contain enums! var distincttypes = circle.Distinct().Cast <IRClass>(); // TODO: Better naming algorithm?! (Longest commong substring) // The longest substring between the fullnames of each type's namespace. var allTypeNamespaceNames = circle.Select(type => _TypeNSMapper[type].FullName).ToList(); var newNSName = DependancyUtil.LongestmatchingSubstring(allTypeNamespaceNames).Trim('.'); // Also construct a shortname from the new namespace fullname var newNSShortName = newNSName.Substring(newNSName.LastIndexOf('.') + 1); // Append the suffix to lower chances of collision newNSName = newNSName + EXTRACTED_NS_SUFFIX; newNSShortName = newNSShortName + EXTRACTED_NS_SUFFIX; // There still might already be a namespace with that name, so a test is necessary anyway! var newNS = _program.GetCreateNamespace(newNSName); // And copy over all types to this namespace. foreach (var irClass in distincttypes) { var oldNS = _TypeNSMapper[irClass]; MoveType(irClass, oldNS, newNS); } // No need to add the namespace to the program anymore! }
// Compares the heights of both namespaces in a mental NON-CIRCULAR TREE. // The tree has the limitation that references are only allowed towards the root. // This method returns -1 if nsOne is closer to the root. // This method returns +1 is nsTwo is closer to the root. private int CompareNSHeights(IRNamespace nsOne, IRNamespace nsTwo) { List <string> nsNames = new List <string>(); nsNames.Add(nsOne.FullName); nsNames.Add(nsTwo.FullName); var commonSubstr = DependancyUtil.LongestmatchingSubstring(nsNames); // Both namespaces share a hypothetical parent namespace. if (commonSubstr.Count() > 0) { return(nsOne.FullName.CompareTo(nsTwo.FullName)); } // If there is no shared namespace, resort to amount of imports both types do. var depsNSOne = _NSDependancies[nsOne].Count(); var depsNSTwo = _NSDependancies[nsTwo].Count(); // NSTwo has less dependancies, so it's considered closer to the root. // This is a vague heuristic, ideally the one closer to the root has NO dependancies. if (depsNSTwo < depsNSOne) { return(1); } // Per default, nsOne is higher up the tree than nsTwo. return(-1); }
private void ResolveCircularTypes(List <IRTypeNode> circle) { // All unique types within the given list are moved together into a seperate // namespace, because that's the only way to solve these kind of circular dependancies. // This list will NEVER contain enums! IEnumerable <IRClass> distincttypes = circle.Distinct().Cast <IRClass>(); // TODO: Better naming algorithm?! (Longest commong substring) // The longest substring between the fullnames of each type's namespace. var allTypeNamespaceNames = circle.Select(type => _TypeNSMapper[type].FullName).ToList(); string newNSName = DependancyUtil.LongestmatchingSubstring(allTypeNamespaceNames).Trim('.'); // Also construct a shortname from the new namespace fullname string newNSShortName = newNSName.Substring(newNSName.LastIndexOf('.') + 1); // NOTE; A suffix is appended here in order to not increase the degree count // for the subject namespace (vertex). // Pulling types into a seperate namespace helps flattening the graph into a spanning, // while the alternative would increase the length of circular namespace chains. newNSName += EXTRACTED_NS_SUFFIX; newNSShortName += EXTRACTED_NS_SUFFIX; // There still might already be a namespace with that name, so a test is necessary anyway! IRNamespace newNS = _program.GetCreateNamespace(newNSName); // And copy over all types to this namespace. foreach (IRClass irClass in distincttypes) { IRNamespace oldNS = _TypeNSMapper[irClass]; MoveType(irClass, oldNS, newNS); } // No need to add the namespace to the program anymore! }