/// <summary> /// Post process the types: /// - If UserType has static members in more than one module, split it into multiple user types. /// - Find parent type/namespace. /// </summary> /// <param name="userTypes">The list of user types.</param> /// <param name="symbolNamespaces">The symbol namespaces.</param> /// <returns>Newly generated user types.</returns> 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); }
/// <summary> /// Post process the types: /// - If UserType has static members in more than one module, split it into multiple user types. /// - Find parent type/namespace. /// </summary> /// <param name="userTypes">The list of user types.</param> /// <param name="symbolNamespaces">The symbol namespaces.</param> /// <returns>Newly generated user types.</returns> internal IEnumerable <UserType> ProcessTypes(IEnumerable <UserType> userTypes, Dictionary <Symbol, string> symbolNamespaces, string commonNamespace) { List <UserType> newTypes = new List <UserType>(); // Collect all constants used by template types Dictionary <string, Symbol> constantsDictionary = new Dictionary <string, Symbol>(); foreach (TemplateUserType templateType in userTypes.OfType <TemplateUserType>()) { foreach (SpecializedTemplateUserType specialization in templateType.Specializations) { foreach (Symbol symbol in specialization.AllTemplateArguments) { if (symbol.Tag != CodeTypeTag.TemplateArgumentConstant) { continue; } if (!constantsDictionary.ContainsKey(symbol.Name)) { constantsDictionary.Add(symbol.Name, symbol); } } } } // Create user types for template type constants if (constantsDictionary.Count > 0) { // Create namespace that will contain all constants (TemplateConstants) NamespaceUserType templateConstants = new NamespaceUserType(new[] { "TemplateConstants" }, commonNamespace, this); newTypes.Add(templateConstants); // Foreach constant, create new user type foreach (Symbol symbol in constantsDictionary.Values) { symbol.UserType = new TemplateArgumentConstantUserType(symbol, this); symbol.UserType.UpdateDeclaredInType(templateConstants); newTypes.Add(symbol.UserType); } } // Assign generated user types to template type constant arguments foreach (TemplateUserType templateType in userTypes.OfType <TemplateUserType>()) { foreach (SpecializedTemplateUserType specialization in templateType.Specializations) { foreach (Symbol symbol in specialization.AllTemplateArguments) { if (symbol.Tag != CodeTypeTag.TemplateArgumentConstant || symbol.UserType != null) { continue; } symbol.UserType = constantsDictionary[symbol.Name].UserType; } } } // Split user types that have static members in more than one module List <UserType> staticUserTypes = new List <UserType>(); Dictionary <Symbol, UserType> staticUserTypesBySymbol = new Dictionary <Symbol, UserType>(); foreach (UserType userType in userTypes) { if (userType.DontExportStaticFields) { continue; } List <Symbol> symbols = GlobalCache.GetSymbolStaticFieldsSymbols(userType.Symbol); if (symbols == null || symbols.Count <= 1) { continue; } bool foundSameNamespace = false; foreach (var symbol in symbols) { string nameSpace = symbol.Module.Namespace; if (userType.Namespace != nameSpace) { UserType staticUserType = new UserType(symbol, null, nameSpace, this) { ExportOnlyStaticFields = true }; staticUserTypes.Add(staticUserType); staticUserTypesBySymbol.Add(symbol, staticUserType); } else { foundSameNamespace = true; } } if (!foundSameNamespace) { userType.DontExportStaticFields = true; } } newTypes.AddRange(staticUserTypes); // TODO: This needs to happen before template types creation. We need to verify that all types declared in template type are matched correctly. // Find parent type/namespace Dictionary <string, Dictionary <string, UserType> > namespaceTypesByModuleNamespace = new Dictionary <string, Dictionary <string, UserType> >(); Action <UserType> findParentType = (UserType userType) => { Symbol symbol = userType.Symbol; string symbolName = symbol.Name; List <string> namespaces = symbol.Namespaces; if (namespaces.Count == 1) { // Class is not defined in namespace nor in type. return; } Dictionary <string, UserType> namespaceTypes; string notNullUserTypeNamespace = userType.Namespace ?? string.Empty; if (!namespaceTypesByModuleNamespace.TryGetValue(notNullUserTypeNamespace, out namespaceTypes)) { namespaceTypesByModuleNamespace.Add(notNullUserTypeNamespace, namespaceTypes = new Dictionary <string, UserType>()); } 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); if (namespaceUserType != null && userType.Namespace != namespaceUserType.Namespace) { staticUserTypesBySymbol.TryGetValue(symbol.Module.GetSymbol(currentNamespace), out namespaceUserType); } if (namespaceUserType != null && userType.Namespace != namespaceUserType.Namespace) { namespaceUserType = null; } } if (namespaceUserType == null) { namespaceUserType = new NamespaceUserType(new string[] { namespaces[i] }, previousNamespaceUserType == null ? userType.Namespace : null, this); if (previousNamespaceUserType != null) { namespaceUserType.UpdateDeclaredInType(previousNamespaceUserType); } namespaceTypes.Add(currentNamespace, namespaceUserType); newTypes.Add(namespaceUserType); } previousNamespaceUserType = namespaceUserType; } userType.UpdateDeclaredInType(previousNamespaceUserType); }; foreach (UserType userType in userTypes.Concat(staticUserTypes)) { Symbol symbol = userType.Symbol; if (symbol.Tag != CodeTypeTag.Class && symbol.Tag != CodeTypeTag.Structure && symbol.Tag != CodeTypeTag.Union && symbol.Tag != CodeTypeTag.Enum) { continue; } if (userType is TemplateUserType templateType) { foreach (SpecializedTemplateUserType specializedType in templateType.Specializations) { findParentType(specializedType); } templateType.UpdateDeclaredInType(templateType.SpecializedRepresentative.DeclaredInType); // TODO: Once we fix how we pick specialized representative this won't be needed. Specialized representative needs to have all inner types. if (templateType.SpecializedRepresentative.DeclaredInType is TemplateUserType t) { templateType.UpdateDeclaredInType(t); } if (templateType.SpecializedRepresentative.DeclaredInType is SpecializedTemplateUserType t2) { templateType.UpdateDeclaredInType(t2.TemplateType.SpecializedRepresentative); } } else { findParentType(userType); } } // Update Class Name if it has duplicate with the namespace it is declared in foreach (UserType userType in newTypes.Concat(userTypes)) { if (userType.DeclaredInType != null && userType.TypeName == userType.DeclaredInType.TypeName) { // Since changing user type name can generate duplicate name, we need to adjust name to be unique. int counter = 0; do { if (counter > 0) { userType.UpdateConstructorNameSuffix($"_{counter}"); } else { userType.UpdateConstructorNameSuffix("_"); } counter++; }while (userType.DeclaredInType.InnerTypes.Where(t => t != userType).Any(t => t.TypeName == userType.TypeName)); } } // 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 (SpecializedTemplateUserType specializedUserType in templateUserType.Specializations) { 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)); }
/// <summary> /// Post process the types: /// - If UserType has static members in more than one module, split it into multiple user types. /// - Find parent type/namespace. /// </summary> /// <param name="userTypes">The list of user types.</param> /// <param name="symbolNamespaces">The symbol namespaces.</param> /// <returns>Newly generated user types.</returns> 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 != CodeTypeTag.Class && symbol.Tag != CodeTypeTag.Structure && symbol.Tag != CodeTypeTag.Union && symbol.Tag != CodeTypeTag.Enum) { 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)); }