Type tree that represents template user type.
Inheritance: UserTypeTree
Esempio n. 1
0
        /// <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;
        }