Example #1
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);
        }
Example #2
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>
        /// <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));
        }