/// <summary> /// Initializes a new instance of the <see cref="TemplateTypeTree"/> class. /// </summary> /// <param name="templateSpecialization">The template specialization user type.</param> /// <param name="factory">The user type factory.</param> public TemplateTypeTree(UserType templateSpecialization, UserTypeFactory factory) : base(templateSpecialization) { // Get all "parent" types UserType type = templateSpecialization; List <UserType> declaredInList = new List <UserType>(); while (type != null) { declaredInList.Add(type); type = type.DeclaredInType; } declaredInList.Reverse(); DeclaredInTypeHierarchy = declaredInList.ToArray(); // Extract all template types and check if we can instantiate this instance CanInstantiate = true; SpecializedArguments = new TypeTree[DeclaredInTypeHierarchy.Length][]; for (int j = 0; j < DeclaredInTypeHierarchy.Length; j++) { // Check if current type in hierarchy is template type TemplateUserType templateType = DeclaredInTypeHierarchy[j] as TemplateUserType; if (templateType == null) { continue; } // Try to find specialized arguments for template type IReadOnlyList <Symbol> arguments = templateType.TemplateArgumentsAsSymbols; TypeTree[] specializedArguments = new TypeTree[arguments.Count]; for (int i = 0; i < arguments.Count; i++) { UserType userType; factory.GetUserType(arguments[i], out userType); if (userType != null) { specializedArguments[i] = UserTypeTree.Create(userType, factory); TemplateTypeTree templateTypeTree = specializedArguments[i] as TemplateTypeTree; if (templateTypeTree != null && !templateTypeTree.CanInstantiate) { CanInstantiate = false; } } else { // TODO: Check why do we go one more round trip through module for getting argument symbol Symbol symbol = templateSpecialization.Symbol.Module.GetSymbol(arguments[i].Name); if (symbol.Tag != SymTagEnum.SymTagBaseType) { // Base Types (Primitive Types) can be used for specialization CanInstantiate = false; } // #fixme can't deal with it specializedArguments[i] = templateType.GetSymbolTypeTree(arguments[i], factory); } } SpecializedArguments[j] = specializedArguments; } }
/// <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; }