/// <summary> /// Tries to match the specified type name against template arguments. /// </summary> /// <param name="typeName">The type name.</param> /// <param name="argumentName">The found argument name.</param> /// <returns><c>true</c> if template argument was matched.</returns> public bool TryGetTemplateArgument(string typeName, out string argumentName) { // Does it belong to our template arguments? int index = templateArgumentsAsSymbols.FindIndex(s => s.Name == typeName); if (index >= 0) { argumentName = NumberOfTemplateArguments == 1 ? TemplateArgumentsNameBase : TemplateArgumentsNameBase + (index + 1); return(true); } // Does it belong to one of the "parent" template types? UserType parentType = DeclaredInType; while (parentType != null) { TemplateUserType templateParentType = parentType as TemplateUserType; if (templateParentType != null) { return(templateParentType.TryGetTemplateArgument(typeName, out argumentName)); } parentType = parentType.DeclaredInType; } // Template argument wasn't found argumentName = ""; return(false); }
/// <summary> /// Adds the specified user type as derived class to all its base classes. /// </summary> /// <param name="userType">The user type.</param> private void AddDerivedClassToBaseClasses(UserType userType) { IEnumerable <Symbol> allBaseClasses = userType.Symbol.GetAllBaseClasses(); foreach (Symbol baseClass in allBaseClasses) { UserType baseClassUserType = GlobalCache.GetUserType(baseClass); TemplateUserType templateUserType = baseClassUserType as TemplateUserType; if (templateUserType != null) { baseClassUserType = templateUserType.TemplateType; } if (baseClassUserType != null) { baseClassUserType.AddDerivedClass(userType); } } }
/// <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> /// Initializes a new instance of the <see cref="TemplateUserTypeFactory"/> class. /// </summary> /// <param name="originalFactory">The original user type factory.</param> /// <param name="templateType">The template user type.</param> public TemplateUserTypeFactory(UserTypeFactory originalFactory, TemplateUserType templateType) : base(originalFactory) { TemplateType = templateType; OriginalFactory = originalFactory; }
/// <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> /// Gets the common base types for all specializations. /// </summary> /// <param name="factory">The user type factory.</param> private string[] GetCommonBaseTypesForAllSpecializations(UserTypeFactory factory) { // If we don't have specializations, we cannot continue if (!SpecializedTypes.Any()) { return(null); } // Do this for every template argument string[] results = new string[NumberOfTemplateArguments]; for (int i = 0; i < NumberOfTemplateArguments; i++) { // Get all specializations for current template argument Symbol[] specializedSymbols = SpecializedTypes.Select(r => r.templateArgumentsAsSymbols[i]).ToArray(); TypeOfSpecializationType specializationType = TypeOfSpecializationType.Unmatched; UserType commonType = null; foreach (Symbol type in specializedSymbols) { // Check base type if (type.Tag == Dia2Lib.SymTagEnum.SymTagBaseType || type.Tag == Dia2Lib.SymTagEnum.SymTagEnum) { if (type.Name != "void") { specializationType = TypeOfSpecializationType.Anything; break; } else { specializationType = TypeOfSpecializationType.Variable; continue; } } // Check pointer, array and function types, they inherit Variable if (type.Tag == Dia2Lib.SymTagEnum.SymTagPointerType || type.Tag == Dia2Lib.SymTagEnum.SymTagArrayType || type.Tag == Dia2Lib.SymTagEnum.SymTagFunctionType) { specializationType = TypeOfSpecializationType.Variable; continue; } if (type.Tag != Dia2Lib.SymTagEnum.SymTagUDT) { throw new NotImplementedException("Unexpected symbol type " + type.Tag + ". Symbol name: " + type.Name); } // Check if type has user type UserType userType = type.UserType; if (userType == null) { // TODO: This shouldn't happen specializationType = TypeOfSpecializationType.Variable; continue; } if (specializationType == TypeOfSpecializationType.Variable) { continue; } // If user type is template, get parent template type (one that describes all specializations) var templateType = userType as TemplateUserType; if (templateType != null) { userType = templateType.TemplateType; } if (specializationType == TypeOfSpecializationType.Unmatched) { specializationType = TypeOfSpecializationType.UserType; commonType = userType; continue; } // Try to find common type for commonType and userType var commonTypeBases = ExtractAllBaseClasses(commonType); var userTypeBases = ExtractAllBaseClasses(userType); bool found = false; foreach (var ct in commonTypeBases) { foreach (var ut in userTypeBases) { if (ut == ct) { found = true; commonType = ut; break; } } if (found) { break; } } if (!found) { specializationType = TypeOfSpecializationType.Variable; } } // Save result based on specialization type string userTypeName = null; var templateCommonType = commonType as TemplateUserType; switch (specializationType) { case TypeOfSpecializationType.Anything: userTypeName = null; break; case TypeOfSpecializationType.Variable: userTypeName = "Variable"; break; case TypeOfSpecializationType.UserType: if (templateCommonType != null) { // Common specialization is template type. In order to use it, we need to take specialization from this type // and not the one that engine picked up as generalization. UserType templateArgumentUserType = templateArgumentsAsUserTypes[i]; List <UserType> baseClasses = ExtractAllBaseClasses(templateArgumentUserType); foreach (UserType baseClass in baseClasses) { TemplateUserType templateBaseClass = baseClass as TemplateUserType; if (templateBaseClass != null && templateCommonType == templateBaseClass.TemplateType) { templateCommonType = templateBaseClass; break; } } // In order to use template as specialization, we need to have all arguments coming from our template arguments. // If not, we cannot trust them and should continue with the base classes. var tree = new TemplateTypeTree(templateCommonType, factory); bool ok = true; do { // Check if all arguments are coming from our template arguments. ok = true; foreach (var args in tree.SpecializedArguments) { if (args != null) { foreach (var arg in args) { if (!(arg is TemplateArgumentTreeType) && !(arg is UserTypeTree && ((UserTypeTree)arg).UserType is TemplateArgumentUserType)) { ok = false; break; } } } } if (!ok) { // Find base class that we should continue with UserType nextBaseClass = null; Symbol symbol = templateCommonType.Symbol; while (nextBaseClass == null) { if (symbol.BaseClasses == null || symbol.BaseClasses.Length == 0) { // We have finished all break; } if (symbol.BaseClasses.Length > 1) { // We cannot match common type with multi-inheritance break; } symbol = symbol.BaseClasses[0]; nextBaseClass = symbol?.UserType; } // No base class, use Variable if (nextBaseClass == null) { userTypeName = "Variable"; break; } else if (nextBaseClass is TemplateUserType) { // Base class is template, continue with checks templateCommonType = (TemplateUserType)nextBaseClass; tree = new TemplateTypeTree(templateCommonType, factory); } else { // Base class is not template, so we can stop testing it. userTypeName = nextBaseClass.FullClassName; break; } } }while (!ok); // All checks passed for this template user type, use it. if (ok) { userTypeName = tree.GetTypeString(); } } else { userTypeName = commonType.FullClassName; } break; case TypeOfSpecializationType.Unmatched: default: throw new NotImplementedException("Unexpected specialization type " + specializationType + " for template type " + ClassName); } results[i] = userTypeName; } return(results); }
/// <summary> /// Adds the symbols to user type factory and generates the user types. /// </summary> /// <param name="symbols">The template symbols grouped around the same template type.</param> /// <param name="type">The XML type description.</param> /// <param name="nameSpace">The namespace.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <returns>Generated user types for the specified symbols.</returns> internal IEnumerable<UserType> AddSymbols(IEnumerable<Symbol> symbols, XmlType type, string nameSpace, UserTypeGenerationFlags generationFlags) { if (!type.IsTemplate && symbols.Count() > 1) throw new Exception("Type has more than one symbol for " + type.Name); if (!type.IsTemplate) { yield return AddSymbol(symbols.First(), type, nameSpace, generationFlags); } else { // Bucketize template user types based on number of template arguments var buckets = new Dictionary<int, List<TemplateUserType>>(); foreach (Symbol symbol in symbols) { UserType userType = null; try { // We want to ignore "empty" generic classes (for now) if (symbol.Name == null || symbol.Size == 0) continue; // Generate template user type TemplateUserType templateType = new TemplateUserType(symbol, type, nameSpace, this); #if false // TODO: Verify if we want to use simple user type instead of template user type if (templateType.AllTemplateArguments.Count == 0) { // Template does not have arguments that can be used by generic // Make it specialized type userType = this.AddSymbol(symbol, null, moduleName, generationOptions); } else #endif { List<TemplateUserType> templates; symbol.UserType = templateType; if (!buckets.TryGetValue(templateType.AllTemplateArguments.Count, out templates)) buckets.Add(templateType.AllTemplateArguments.Count, templates = new List<TemplateUserType>()); templates.Add(templateType); } } catch (Exception ex) { // TODO: Verify if we need to add this as specialization if (ex.Message != "Wrongly formed template argument") throw; } if (userType != null) yield return userType; } // Add newly generated types foreach (List<TemplateUserType> templatesInBucket in buckets.Values) { // TODO: Verify that all templates in the list can be described by the same class (also do check for inner-types) // Sort Templates by Class Name. // This removes ambiguity caused by parallel type processing. // List<TemplateUserType> templates = templatesInBucket.OrderBy(t => t.Symbol.Name.Count(c => c == '*')) .ThenBy(t => t.Symbol.Name.Count(c => c == '<')) .ThenBy(t => t.Symbol.Name).ToList(); // Select best suited type for template TemplateUserType template = templates.First(); foreach (var specializedTemplate in templates) { var arguments = specializedTemplate.AllTemplateArguments; // Check if all arguments are different if (arguments.Distinct().Count() == arguments.Count()) { // Check if all arguments are simple user type bool simpleUserType = true; foreach (var argument in arguments) { var argumentSymbol = GlobalCache.GetSymbol(argument, specializedTemplate.Module); if (argumentSymbol.Tag != SymTagEnum.SymTagUDT || argumentSymbol.Name.Contains("<")) { simpleUserType = false; break; } } if (simpleUserType) { template = specializedTemplate; break; } // Check if none of the arguments is template user type bool noneIsTemplate = true; foreach (var argument in arguments) { var argumentSymbol = GlobalCache.GetSymbol(argument, specializedTemplate.Module); if (argumentSymbol.Tag == SymTagEnum.SymTagUDT && argumentSymbol.Name.Contains("<")) { noneIsTemplate = false; break; } } if (noneIsTemplate) { template = specializedTemplate; continue; } } // This one is as good as any... } // Move all types under the selected type foreach (var specializedTemplate in templates) { template.SpecializedTypes.Add(specializedTemplate); specializedTemplate.TemplateType = template; } yield return template; } } }
/// <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)); }
/// <summary> /// Adds the symbols to user type factory and generates the user types. /// </summary> /// <param name="symbols">The template symbols grouped around the same template type.</param> /// <param name="type">The XML type description.</param> /// <param name="nameSpace">The namespace.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <returns>Generated user types for the specified symbols.</returns> internal IEnumerable <UserType> AddSymbols(IEnumerable <Symbol> symbols, XmlType type, string nameSpace, UserTypeGenerationFlags generationFlags) { if (!type.IsTemplate && symbols.Count() > 1) { throw new Exception("Type has more than one symbol for " + type.Name); } if (!type.IsTemplate) { yield return(AddSymbol(symbols.First(), type, nameSpace, generationFlags)); } else { // Bucketize template user types based on number of template arguments var buckets = new Dictionary <int, List <TemplateUserType> >(); foreach (Symbol symbol in symbols) { UserType userType = null; try { // We want to ignore "empty" generic classes (for now) if (symbol.Name == null || symbol.Size == 0) { continue; } // Generate template user type TemplateUserType templateType = new TemplateUserType(symbol, type, nameSpace, this); #if false // TODO: Verify if we want to use simple user type instead of template user type if (templateType.AllTemplateArguments.Count == 0) { // Template does not have arguments that can be used by generic // Make it specialized type userType = this.AddSymbol(symbol, null, moduleName, generationOptions); } else #endif { List <TemplateUserType> templates; symbol.UserType = templateType; if (!buckets.TryGetValue(templateType.AllTemplateArguments.Count, out templates)) { buckets.Add(templateType.AllTemplateArguments.Count, templates = new List <TemplateUserType>()); } templates.Add(templateType); } } catch (Exception ex) { // TODO: Verify if we need to add this as specialization if (ex.Message != "Wrongly formed template argument") { throw; } } if (userType != null) { yield return(userType); } } // Add newly generated types foreach (List <TemplateUserType> templatesInBucket in buckets.Values) { // TODO: Verify that all templates in the list can be described by the same class (also do check for inner-types) // Sort Templates by Class Name. // This removes ambiguity caused by parallel type processing. // List <TemplateUserType> templates = templatesInBucket.OrderBy(t => t.Symbol.Name.Count(c => c == '*')) .ThenBy(t => t.Symbol.Name.Count(c => c == '<')) .ThenBy(t => t.Symbol.Name).ToList(); // Select best suited type for template TemplateUserType template = templates.First(); foreach (var specializedTemplate in templates) { var arguments = specializedTemplate.AllTemplateArguments; // Check if all arguments are different if (arguments.Distinct().Count() == arguments.Count()) { // Check if all arguments are simple user type bool simpleUserType = true; foreach (var argument in arguments) { var argumentSymbol = GlobalCache.GetSymbol(argument, specializedTemplate.Module); if ((argumentSymbol.Tag != CodeTypeTag.Class && argumentSymbol.Tag != CodeTypeTag.Structure && argumentSymbol.Tag != CodeTypeTag.Union) || argumentSymbol.Name.Contains("<")) { simpleUserType = false; break; } } if (simpleUserType) { template = specializedTemplate; break; } // Check if none of the arguments is template user type bool noneIsTemplate = true; foreach (var argument in arguments) { var argumentSymbol = GlobalCache.GetSymbol(argument, specializedTemplate.Module); if (argumentSymbol != null && (argumentSymbol.Tag == CodeTypeTag.Class || argumentSymbol.Tag == CodeTypeTag.Structure || argumentSymbol.Tag == CodeTypeTag.Union) && argumentSymbol.Name.Contains("<")) { noneIsTemplate = false; break; } } if (noneIsTemplate) { template = specializedTemplate; continue; } } // This one is as good as any... } // Move all types under the selected type foreach (var specializedTemplate in templates) { template.SpecializedTypes.Add(specializedTemplate); specializedTemplate.TemplateType = template; } yield return(template); } } }