private int PrioritizeImports(HashSet <CdmDocumentDefinition> processedSet, ImportPriorities importPriorities, int sequence, bool skipMonikered) { // goal is to make a map from the reverse order of imports (breadth first) to the first (aka last) sequence number in that list. // This gives the semantic that the 'last/shallowest' definition for a duplicate symbol wins, // the lower in this list a document shows up, the higher priority its definitions are for resolving conflicts. // for 'moniker' imports, keep track of the 'last/shallowest' use of each moniker tag. // maps document to priority. IDictionary <CdmDocumentDefinition, int> priorityMap = importPriorities.ImportPriority; // maps moniker to document. IDictionary <string, CdmDocumentDefinition> monikerMap = importPriorities.MonikerPriorityMap; // if already in list, don't do this again if (processedSet.Contains(this)) { // if the first document in the priority map is this then the document was the starting point of the recursion. // and if this document is present in the processedSet we know that there is a cicular list of imports. if (priorityMap.ContainsKey(this) && priorityMap[this] == 0) { importPriorities.hasCircularImport = true; } return(sequence); } processedSet.Add(this); if (this.Imports != null) { var reversedImports = this.Imports.Reverse(); // first add the imports done at this level only in reverse order. foreach (var imp in reversedImports) { var impDoc = imp.Document; bool isMoniker = !string.IsNullOrWhiteSpace(imp.Moniker); // don't add the moniker imports to the priority list. if (impDoc != null && !isMoniker && !priorityMap.ContainsKey(impDoc)) { // add doc. priorityMap.Add(impDoc, sequence); sequence++; } } // now add the imports of the imports. foreach (var imp in reversedImports) { CdmDocumentDefinition impDoc = imp.Document; bool isMoniker = !string.IsNullOrWhiteSpace(imp.Moniker); // if the document has circular imports its order on the impDoc.ImportPriorities list is not correct. // since the document itself will always be the first one on the list. if (impDoc?.ImportPriorities != null && impDoc?.ImportPriorities.hasCircularImport == false) { // lucky, already done so avoid recursion and copy. ImportPriorities impPriSub = impDoc.GetImportPriorities(); impPriSub.ImportPriority.Remove(impDoc); // because already added above. foreach (var ip in impPriSub.ImportPriority) { if (priorityMap.ContainsKey(ip.Key) == false) { // add doc. priorityMap.Add(ip.Key, sequence); sequence++; } } // if the import is not monikered then merge its monikerMap to this one. if (!isMoniker) { foreach (var mp in impPriSub.MonikerPriorityMap) { monikerMap[mp.Key] = mp.Value; } } } else if (impDoc != null) { // skip the monikered imports from here if this is a monikered import itself and we are only collecting the dependencies. sequence = impDoc.PrioritizeImports(processedSet, importPriorities, sequence, isMoniker); } } // skip the monikered imports from here if this is a monikered import itself and we are only collecting the dependencies. if (!skipMonikered) { // moniker imports are prioritized by the 'closest' use of the moniker to the starting doc. so last one found in this recursion. foreach (var imp in this.Imports) { bool isMoniker = !string.IsNullOrWhiteSpace(imp.Moniker); if (imp.Document != null && isMoniker) { monikerMap[imp.Moniker] = imp.Document; } } } } return(sequence); }
private int PrioritizeImports(HashSet <CdmDocumentDefinition> processedSet, IDictionary <CdmDocumentDefinition, int> priorityMap, int sequence, IDictionary <string, CdmDocumentDefinition> monikerMap, bool skipMonikered = false) { // goal is to make a map from the reverse order of imports (breadth first) to the first (aka last) sequence number in that list. // This gives the semantic that the 'last/shallowest' definition for a duplicate symbol wins, // the lower in this list a document shows up, the higher priority its definitions are for resolving conflicts. // for 'moniker' imports, keep track of the 'last/shallowest' use of each moniker tag. // if already in list, don't do this again if (processedSet.Contains(this)) { return(sequence); } processedSet.Add(this); if (this.Imports != null) { // first add the imports done at this level only int l = this.Imports.Count; // reverse order for (int i = l - 1; i >= 0; i--) { CdmImport imp = this.Imports.AllItems[i]; CdmDocumentDefinition impDoc = imp.ResolvedDocument as CdmDocumentDefinition; // don't add the moniker imports to the priority list bool isMoniker = !string.IsNullOrWhiteSpace(imp.Moniker); if (imp.ResolvedDocument != null && !isMoniker) { if (priorityMap.ContainsKey(impDoc) == false) { // add doc priorityMap.Add(impDoc, sequence); sequence++; } } } // now add the imports of the imports for (int i = l - 1; i >= 0; i--) { CdmImport imp = this.Imports.AllItems[i]; CdmDocumentDefinition impDoc = imp.ResolvedDocument as CdmDocumentDefinition; // don't add the moniker imports to the priority list bool isMoniker = !string.IsNullOrWhiteSpace(imp.Moniker); if (impDoc?.ImportPriorities != null) { // lucky, already done so avoid recursion and copy ImportPriorities impPriSub = impDoc.GetImportPriorities(); impPriSub.ImportPriority.Remove(impDoc); // because already added above foreach (var ip in impPriSub.ImportPriority) { if (priorityMap.ContainsKey(ip.Key) == false) { // add doc priorityMap.Add(ip.Key, sequence); sequence++; } } if (!isMoniker) { foreach (var mp in impPriSub.MonikerPriorityMap) { monikerMap[mp.Key] = mp.Value; } } } else if (impDoc != null) { // skip the monikered imports from here if this is a monikered import itself and we are only collecting the dependencies sequence = impDoc.PrioritizeImports(processedSet, priorityMap, sequence, monikerMap, isMoniker); } } // skip the monikered imports from here if this is a monikered import itself and we are only collecting the dependencies if (!skipMonikered) { // moniker imports are prioritized by the 'closest' use of the moniker to the starting doc. so last one found in this recursion for (int i = 0; i < l; i++) { CdmImport imp = this.Imports.AllItems[i]; if (imp.ResolvedDocument != null && imp.Moniker != null) { monikerMap[imp.Moniker] = imp.ResolvedDocument as CdmDocumentDefinition; } } } } return(sequence); }