/// <summary> /// Look up for user type based on the specified symbol. /// </summary> /// <param name="type">The symbol.</param> /// <param name="userType">The found user type.</param> /// <returns><c>true</c> if user type was found.</returns> internal virtual bool GetUserType(Symbol type, out UserType userType) { userType = GlobalCache.GetUserType(type); if (!(userType is TemplateUserType)) { return(userType != null); } TemplateUserType specializedUserType = (TemplateUserType)userType; if (specializedUserType != null) { userType = specializedUserType; } else { // We could not find the specialized template. // Return null in this case. userType = null; } return(userType != null); }
/// <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> /// <param name="commonNamespace">The namespace name for types found in multiple modules.</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)); }