internal IEnumerable<UserType> ProcessTypes(IEnumerable<UserType> userTypes, Dictionary<Symbol, string> symbolNamespaces)
{
ConcurrentBag<UserType> newTypes = new ConcurrentBag<UserType>();
// Split user types that have static members in more than one module
Parallel.ForEach(Partitioner.Create(userTypes), (userType) =>
{
if (!userType.ExportStaticFields)
return;
Symbol[] symbols = GlobalCache.GetSymbolStaticFieldsSymbols(userType.Symbol).ToArray();
if (symbols.Length == 1)
return;
bool foundSameNamespace = false;
foreach (var symbol in symbols)
{
string nameSpace = symbol.Module.Namespace;
if (userType.Namespace != nameSpace)
newTypes.Add(new UserType(symbol, null, nameSpace) { ExportDynamicFields = false });
else
foundSameNamespace = true;
}
userType.ExportStaticFields = foundSameNamespace;
});
// Find parent type/namespace
Dictionary<string, UserType> namespaceTypes = new Dictionary<string, UserType>();
foreach (UserType userType in userTypes)
{
Symbol symbol = userType.Symbol;
if (symbol.Tag != SymTagEnum.SymTagUDT && symbol.Tag != SymTagEnum.SymTagEnum)
continue;
string symbolName = symbol.Name;
List<string> namespaces = symbol.Namespaces;
if (namespaces.Count == 1)
{
// Class is not defined in namespace nor in type.
continue;
}
StringBuilder currentNamespaceSB = new StringBuilder();
UserType previousNamespaceUserType = null;
for (int i = 0; i < namespaces.Count - 1; i++)
{
if (i > 0)
currentNamespaceSB.Append("::");
currentNamespaceSB.Append(namespaces[i]);
string currentNamespace = currentNamespaceSB.ToString();
UserType namespaceUserType;
if (!namespaceTypes.TryGetValue(currentNamespace, out namespaceUserType))
namespaceUserType = GlobalCache.GetUserType(currentNamespace, symbol.Module);
// Put type under exported template type (TODO: Remove this when template types start checking subtypes)
var templateType = namespaceUserType as TemplateUserType;
if (templateType != null)
namespaceUserType = templateType.TemplateType;
if (namespaceUserType == null)
{
namespaceUserType = new NamespaceUserType(new string[] { namespaces[i] }, previousNamespaceUserType == null ? symbolNamespaces[symbol] : null);
if (previousNamespaceUserType != null)
namespaceUserType.UpdateDeclaredInType(previousNamespaceUserType);
namespaceTypes.Add(currentNamespace, namespaceUserType);
newTypes.Add(namespaceUserType);
}
previousNamespaceUserType = namespaceUserType;
}
userType.UpdateDeclaredInType(previousNamespaceUserType);
}
// Update Class Name if it has duplicate with the namespace it is declared in
foreach (UserType userType in newTypes.Concat(userTypes))
{
userType.ClassName = userType.OriginalClassName;
if (userType.DeclaredInType != null && userType.OriginalClassName == userType.DeclaredInType.ClassName)
{
userType.ClassName += "_";
}
TemplateUserType templateUserType = userType as TemplateUserType;
if (templateUserType != null)
{
foreach (UserType specializedUserType in templateUserType.SpecializedTypes)
{
specializedUserType.ClassName = userType.ClassName;
}
}
}
// Remove duplicate types from exported template types (TODO: Remove this when template types start checking subtypes)
foreach (UserType userType in userTypes)
{
TemplateUserType templateType = userType as TemplateUserType;
if (templateType == null)
continue;
HashSet<string> uniqueTypes = new HashSet<string>();
foreach (var innerType in templateType.InnerTypes.ToArray())
{
string className;
if (!(innerType is NamespaceUserType))
className = innerType.ClassName;
else
className = innerType.Namespace;
if (uniqueTypes.Contains(className))
templateType.InnerTypes.Remove(innerType);
else
uniqueTypes.Add(className);
}
}
// Find all derived classes
foreach (UserType userType in userTypes)
{
// We are doing this only for UDTs
if (userType is EnumUserType || userType is GlobalsUserType || userType is NamespaceUserType)
continue;
// For template user types, we want to remember all specializations
TemplateUserType templateUserType = userType as TemplateUserType;
if (templateUserType != null)
{
foreach (UserType specializedUserType in templateUserType.SpecializedTypes)
{
AddDerivedClassToBaseClasses(specializedUserType);
}
}
else
{
AddDerivedClassToBaseClasses(userType);
}
}
// Merge namespaces when possible
foreach (UserType userType in newTypes)
{
NamespaceUserType nameSpace = userType as NamespaceUserType;
if (nameSpace == null)
{
continue;
}
nameSpace.MergeIfPossible();
}
// Remove empty namespaces after merge
List<UserType> removedUserTypes = new List<UserType>();
foreach (UserType userType in newTypes)
{
NamespaceUserType nameSpace = userType as NamespaceUserType;
if (nameSpace == null)
{
continue;
}
if (nameSpace.InnerTypes.Count == 0)
{
removedUserTypes.Add(nameSpace);
}
}
return newTypes.Except(removedUserTypes);
}