User type that represents template user type. For example: MyType<T>
상속: UserType
예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
                }
            }
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
 /// <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;
 }
예제 #5
0
        /// <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));
        }
예제 #6
0
        /// <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);
        }
예제 #7
0
        /// <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;
                }
            }
        }
예제 #8
0
        /// <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));
        }
예제 #9
0
        /// <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);
                }
            }
        }