/// <summary> /// Gets the dictionary of generic type constraints per template argument (that has constraint). /// </summary> /// <param name="factory">The user type factory.</param> private Dictionary <string, string> GetGenericTypeConstraintsDictionary(UserTypeFactory factory) { Dictionary <string, string> result = new Dictionary <string, string>(); #if false string[] commonBaseSpecializationTypes = GetCommonBaseTypesForAllSpecializations(factory); if (commonBaseSpecializationTypes == null || commonBaseSpecializationTypes.All(r => string.IsNullOrEmpty(r))) #endif { // no restrictions return(result); } #if false StringBuilder sb = new StringBuilder(); if (commonBaseSpecializationTypes.Count() == 1) { result.Add(TemplateArgumentsNameBase, commonBaseSpecializationTypes[0]); } else { for (int i = 0; i < commonBaseSpecializationTypes.Count(); i++) { if (!string.IsNullOrEmpty(commonBaseSpecializationTypes[i])) { result.Add(string.Format("{0}{1}", TemplateArgumentsNameBase, i + 1), commonBaseSpecializationTypes[i]); } } } return(result); #endif }
/// <summary> /// Initializes a new instance of the <see cref="SpecializedTemplateUserType"/> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">User type factory that contains this element.</param> public SpecializedTemplateUserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) : base(symbol, xmlType, nameSpace, factory) { Factory = CreateFactory(factory); OriginalFactory = factory; // Enumerate all template arguments as strings List <Symbol> allTemplateArguments = new List <Symbol>(); List <Symbol> templateArgumentsAsSymbols = new List <Symbol>(); for (int i = 0; i < Symbol.Namespaces.Count - 1; i++) { if (!ParseTemplateArguments(Module, Symbol.Namespaces[i], allTemplateArguments)) { WronglyFormed = true; break; } } if (!WronglyFormed) { WronglyFormed = !ParseTemplateArguments(Module, Symbol.Namespaces.Last(), templateArgumentsAsSymbols); allTemplateArguments.AddRange(templateArgumentsAsSymbols); } if (!WronglyFormed) { AllTemplateArguments = allTemplateArguments; TemplateArgumentsAsSymbols = templateArgumentsAsSymbols; } }
/// <summary> /// Creates type tree that represents UserType base on the specified UserType and user type factory. /// </summary> /// <param name="userType">The user type.</param> /// <param name="factory">The user type factory.</param> /// <returns>Type tree that represents UserType</returns> internal static UserTypeTree Create(UserType userType, UserTypeFactory factory) { // Check arguments if (userType == null) throw new ArgumentNullException(nameof(userType)); // If user type is template or declared in template user type, // we need to force template because of possible template types used from "parent" type. var type = userType; while (type != null) { var templateType = type as TemplateUserType; if (templateType != null) return new TemplateTypeTree(userType, factory); type = type.DeclaredInType; } // Check if user type is enumeration var enumType = userType as EnumUserType; if (enumType != null) return new EnumTreeType(enumType); // We are now certain that it is regular user type return new UserTypeTree(userType); }
/// <summary> /// Gets the type tree for the specified field. /// </summary> /// <param name="field">The field.</param> /// <param name="factory">The user type factory.</param> /// <param name="extractingBaseClass">if set to <c>true</c> user type field is being generated for getting base class.</param> /// <param name="bitLength">Number of bits used for this symbol.</param> protected override TypeTree GetFieldTypeTree(SymbolField field, UserTypeFactory factory, bool extractingBaseClass, int bitLength = 0) { // Do not match specializations when getting type for base class. if (extractingBaseClass || NumberOfTemplateArguments == 0) { return(GetSymbolTypeTree(field.Type, factory, bitLength)); } // Check field in all specializations var specializedFields = SpecializedTypes.Select(r => new Tuple <TemplateUserType, SymbolField>(r, r.Symbol.Fields.FirstOrDefault(q => q.Name == field.Name))).ToArray(); if (specializedFields.Any(r => r.Item2 == null)) { // TODO: Incorrect bucketization. Field does not exist in all specialization. return(GetSymbolTypeTree(field.Type, factory, bitLength)); } if (specializedFields.All(r => r.Item2.Type.Name == field.Type.Name)) { // There is no specialization, all types across the specializations are the same. return(GetSymbolTypeTree(field.Type, factory, bitLength)); } // Try to get type tree TypeTree result = GetSymbolTypeTree(field.Type, factory, bitLength); return(FixTypeTree(result, field.Type, factory)); }
/// <summary> /// Extracts all fields from the user type. /// </summary> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> protected override IEnumerable <UserTypeField> ExtractFields(UserTypeFactory factory, UserTypeGenerationFlags generationFlags) { ExportStaticFields = true; var fields = Symbol.Fields.OrderBy(s => s.Name).ToArray(); bool useThisClass = generationFlags.HasFlag(UserTypeGenerationFlags.UseDirectClassAccess); HashSet <string> usedNames = new HashSet <string>(); foreach (var field in fields) { if (string.IsNullOrEmpty(field.Type.Name)) { continue; } if (IsFieldFiltered(field)) { continue; } field.PropertyName = NormalizeSymbolNamespace(UserTypeField.GetPropertyName(field, this)); while (usedNames.Contains(field.PropertyName)) { field.PropertyName += "_"; } if (field.Name.Contains("@") || field.PropertyName.Length > 511) { // Skip names containing '@' continue; } // Skip fields that are actual values of enum values if (field.Type.Tag == CodeTypeTag.Enum && field.Type.EnumValues.Any(t => t.Item1 == field.Name)) { continue; } var userField = ExtractField(field, factory, generationFlags, forceIsStatic: true); if (field.Type.Tag == CodeTypeTag.Pointer) { // Do not use const values for pointers. // We do not allow user type implicit conversion from integers. userField.ConstantValue = string.Empty; } userField.FieldName = NormalizeSymbolNamespace(userField.FieldName); userField.PropertyName = NormalizeSymbolNamespace(userField.PropertyName); yield return(userField); usedNames.Add(field.PropertyName); } foreach (var field in GetAutoGeneratedFields(false, useThisClass)) { yield return(field); } }
private TypeTree FixTypeTree(TypeTree typeTree, Symbol type, UserTypeFactory factory) { // Check basic type BasicTypeTree basicTypeTree = typeTree as BasicTypeTree; if (basicTypeTree != null) { // Basic type tree is not challenged against template arguments, so try to do that. UserType basicUserType; if (CreateFactory(factory).GetUserType(type, out basicUserType)) { TypeTree tree = UserTypeTree.Create(basicUserType, factory); if (tree != null) { return(tree); } } // Failed to match the type // TODO: Look for typedeclared. Class is using different types than in template specialization. We cannot support it right now. return(new VariableTypeTree()); } // Check array type ArrayTypeTree arrayTypeTree = typeTree as ArrayTypeTree; if (arrayTypeTree != null) { TypeTree elementTypeTree = FixTypeTree(arrayTypeTree.ElementType, type.ElementType, factory); if (elementTypeTree != arrayTypeTree.ElementType) { return(new ArrayTypeTree(elementTypeTree)); } return(arrayTypeTree); } // Check pointer type PointerTypeTree pointerTypeTree = typeTree as PointerTypeTree; if (pointerTypeTree != null) { TypeTree elementTypeTree = FixTypeTree(pointerTypeTree.ElementType, type.ElementType, factory); if (elementTypeTree != pointerTypeTree.ElementType) { return(new PointerTypeTree(elementTypeTree)); } return(pointerTypeTree); } return(typeTree); }
/// <summary> /// Extracts all fields from the user type. /// </summary> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> protected override IEnumerable <UserTypeField> ExtractFields(UserTypeFactory factory, UserTypeGenerationFlags generationFlags) { ExportStaticFields = true; var fields = Symbol.Fields.OrderBy(s => s.Name).ToArray(); bool useThisClass = generationFlags.HasFlag(UserTypeGenerationFlags.UseClassFieldsFromDiaSymbolProvider); string previousName = ""; foreach (var field in fields) { if (string.IsNullOrEmpty(field.Type.Name)) { continue; } if (IsFieldFiltered(field) || field.Name == previousName) { continue; } if (field.Name.Contains("@")) { // Skip names contaings '@' continue; } // Skip fields that are actual values of enum values if (field.Type.Tag == Dia2Lib.SymTagEnum.SymTagEnum && field.Type.GetEnumValues().Any(t => t.Item1 == field.Name)) { continue; } var userField = ExtractField(field, factory, generationFlags, forceIsStatic: true); if (field.Type.Tag == Dia2Lib.SymTagEnum.SymTagPointerType) { // Do not use const values for pointers. // We do not allow user type implicit conversion from integers. userField.ConstantValue = string.Empty; } userField.FieldName = NormalizeSymbolNamespace(userField.FieldName); userField.PropertyName = NormalizeSymbolNamespace(userField.PropertyName); yield return(userField); previousName = field.Name; } foreach (var field in GetAutoGeneratedFields(false, useThisClass)) { yield return(field); } }
/// <summary> /// Writes the code for this user type to the specified output. /// </summary> /// <param name="output">The output.</param> /// <param name="error">The error text writer.</param> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="indentation">The current indentation.</param> public override void WriteCode(IndentedWriter output, TextWriter error, UserTypeFactory factory, UserTypeGenerationFlags generationFlags, int indentation = 0) { // Check if we need to write namespace string nameSpace = (DeclaredInType as NamespaceUserType)?.FullClassName ?? Namespace; string enumBasicType = GetEnumBasicType(Symbol); if ((DeclaredInType == null || (!generationFlags.HasFlag(UserTypeGenerationFlags.SingleFileExport) && DeclaredInType is NamespaceUserType)) && !string.IsNullOrEmpty(nameSpace)) { output.WriteLine(indentation, "namespace {0}", nameSpace); output.WriteLine(indentation++, "{{"); } // Write beginning of the enumeration if (generationFlags.HasFlag(UserTypeGenerationFlags.GenerateFieldTypeInfoComment)) { output.WriteLine(indentation, "// {0} (original name: {1})", ClassName, Symbol.Name); } if (AreValuesFlags()) { output.WriteLine(indentation, @"[System.Flags]"); } if (Symbol.Size != 0) { output.WriteLine(indentation, @"public enum {0} : {1}", ClassName, enumBasicType); } else { output.WriteLine(indentation, @"public enum {0}", ClassName); } output.WriteLine(indentation++, @"{{"); // Write values foreach (var enumValue in Symbol.EnumValues) { string value = enumValue.Item2; if (!FitsBasicType(enumBasicType, ref value)) { output.WriteLine(indentation, "{0} = ({1}){2},", enumValue.Item1, enumBasicType, value); } else { output.WriteLine(indentation, "{0} = {1},", enumValue.Item1, value); } } // Enumeration end output.WriteLine(--indentation, @"}}"); if ((DeclaredInType == null || (!generationFlags.HasFlag(UserTypeGenerationFlags.SingleFileExport) && DeclaredInType is NamespaceUserType)) && !string.IsNullOrEmpty(nameSpace)) { output.WriteLine(--indentation, "}}"); } }
/// <summary> /// Initializes a new instance of the <see cref="UserType"/> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">User type factory that contains this element.</param> public UserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) { Symbol = symbol; Factory = factory; InnerTypes = new List <UserType>(); DerivedClasses = new HashSet <UserType>(); typeNameCache = SimpleCache.CreateStruct(() => GetTypeName()); fullTypeNameCache = SimpleCache.CreateStruct(() => GetFullTypeName()); constructorNameCache = SimpleCache.CreateStruct(() => GetConstructorName()); namespaceCache = SimpleCache.CreateStruct(() => GetNamespace(nameSpace)); membersCache = SimpleCache.CreateStruct(() => GetMembers().ToArray()); constructorsCache = SimpleCache.CreateStruct(() => GetConstructors().ToArray()); baseClassCache = SimpleCache.CreateStruct(() => GetBaseClass(Symbol)); memoryBufferOffsetCache = SimpleCache.CreateStruct(() => GetMemoryBufferOffset()); }
/// <summary> /// Gets the type tree for the specified field. /// </summary> /// <param name="field">The field.</param> /// <param name="factory">The user type factory.</param> /// <param name="extractingBaseClass">if set to <c>true</c> user type field is being generated for getting base class.</param> /// <param name="bitLength">Number of bits used for this symbol.</param> protected override TypeTree GetFieldTypeTree(SymbolField field, UserTypeFactory factory, bool extractingBaseClass, int bitLength = 0) { // Do not match specializations when getting type for base class. if (extractingBaseClass || NumberOfTemplateArguments == 0) { return(GetSymbolTypeTree(field.Type, factory, bitLength)); } // Check field in all specializations var specializedFields = SpecializedTypes.Select(r => new Tuple <TemplateUserType, SymbolField>(r, r.Symbol.Fields.FirstOrDefault(q => q.Name == field.Name))).ToArray(); if (specializedFields.Any(r => r.Item2 == null)) { // TODO: Incorrect bucketization. Field does not exist in all specialization. return(GetSymbolTypeTree(field.Type, factory, bitLength)); } if (specializedFields.All(r => r.Item2.Type.Name == field.Type.Name)) { // There is no specialization, all types across the specializations are the same. return(GetSymbolTypeTree(field.Type, factory, bitLength)); } // Try to get type tree TypeTree result = GetSymbolTypeTree(field.Type, factory, bitLength); if (result is BasicTypeTree) { // Basic type tree is not challenged against template arguments, so try to do that. UserType basicUserType; if (CreateFactory(factory).GetUserType(field.Type, out basicUserType)) { TypeTree tree = UserTypeTree.Create(basicUserType, factory); if (tree != null) { return(tree); } } // Failed to match the type // TODO: Look for typedeclared. Class is using different types than in template specialization. We cannot support it right now. return(new VariableTypeTree()); } return(result); }
/// <summary> /// Extracts all fields from the user type. /// </summary> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> protected override IEnumerable<UserTypeField> ExtractFields(UserTypeFactory factory, UserTypeGenerationFlags generationFlags) { ExportStaticFields = true; var fields = Symbol.Fields.OrderBy(s => s.Name).ToArray(); bool useThisClass = generationFlags.HasFlag(UserTypeGenerationFlags.UseClassFieldsFromDiaSymbolProvider); string previousName = ""; foreach (var field in fields) { if (string.IsNullOrEmpty(field.Type.Name)) continue; if (IsFieldFiltered(field) || field.Name == previousName) continue; if (field.Name.Contains("@")) { // Skip names contaings '@' continue; } // Skip fields that are actual values of enum values if (field.Type.Tag == Dia2Lib.SymTagEnum.SymTagEnum && field.Type.GetEnumValues().Any(t => t.Item1 == field.Name)) continue; var userField = ExtractField(field, factory, generationFlags, forceIsStatic: true); if (field.Type.Tag == Dia2Lib.SymTagEnum.SymTagPointerType) { // Do not use const values for pointers. // We do not allow user type implicit conversion from integers. userField.ConstantValue = string.Empty; } userField.FieldName = NormalizeSymbolNamespace(userField.FieldName); userField.PropertyName = NormalizeSymbolNamespace(userField.PropertyName); yield return userField; previousName = field.Name; } foreach (var field in GetAutoGeneratedFields(false, useThisClass)) yield return field; }
/// <summary> /// Creates the user type factory based on this template user type. /// </summary> /// <param name="factory">The original user type factory.</param> private UserTypeFactory CreateFactory(UserTypeFactory factory) { // Check if we are trying to create factory from factory that we already created var templateFactory = factory as TemplateUserTypeFactory; if (templateFactory != null) { if (templateFactory.TemplateType != this) { return(CreateFactory(templateFactory.OriginalFactory)); } // TODO: Verify if we want to keep existing template factory or we want to add our type too return(templateFactory); } return(new TemplateUserTypeFactory(factory, this)); }
/// <summary> /// Updates the template arguments (symbols and user types). /// </summary> /// <param name="factory">The user type factory.</param> /// <returns><c>true</c> if all template arguments are resolved as user types.</returns> public bool UpdateTemplateArguments(UserTypeFactory factory) { bool result = true; templateArgumentsAsSymbols = ParseTemplateArguments(factory, Module, Symbol.Namespaces.Last()).ToList(); templateArgumentsAsUserTypes.Clear(); foreach (Symbol symbol in templateArgumentsAsSymbols) { // Try to get user type for the symbol UserType specializationUserType = null; if (!factory.GetUserType(symbol, out specializationUserType)) { if (symbol.Tag != CodeTypeTag.Enum && symbol.Tag != CodeTypeTag.Class && symbol.Tag != CodeTypeTag.Structure && symbol.Tag != CodeTypeTag.Union) { try { var typeString = GetSymbolTypeTree(symbol, factory).GetTypeString(); specializationUserType = new TemplateArgumentUserType(typeString, symbol); } catch { } } } templateArgumentsAsUserTypes.Add(specializationUserType); result = result && specializationUserType != null; } // Enumerate all template arguments as strings IEnumerable <Symbol> allTemplateArguments = Enumerable.Empty <Symbol>(); foreach (string symbolName in Symbol.Namespaces) { allTemplateArguments = allTemplateArguments.Concat(ParseTemplateArguments(factory, Module, symbolName)); } AllTemplateArguments = allTemplateArguments.Select(s => s.Name).ToList(); // TODO: Unused types should be removed return(result); }
private static IEnumerable <Symbol> ParseTemplateArguments(UserTypeFactory factory, Module module, string symbolName) { int templateStart = symbolName.IndexOf('<'); if (templateStart > 0) { // Parse template arguments List <string> arguments = new List <string>(); for (int i = templateStart + 1; i < symbolName.Length && symbolName[i] != '>'; i++) { string originalyExtractedType = XmlTypeTransformation.ExtractType(symbolName, i); string extractedType = originalyExtractedType.Trim(); i += originalyExtractedType.Length; if (string.IsNullOrEmpty(extractedType)) { // This can happen only when list is empty if (arguments.Count > 0) { throw new NotImplementedException("Unexpected empty template argument in symbol " + symbolName); } break; } arguments.Add(extractedType); // Try to see if argument is number (constants are removed from the template arguments as they cannot be used in C#) double constant; if (!double.TryParse(extractedType, out constant)) { // Check if type is existing type (symbol) Symbol symbol = GlobalCache.GetSymbol(extractedType, module); if (symbol == null) { throw new Exception("Wrongly formed template argument"); } yield return(symbol); } } } }
/// <summary> /// Writes the code for this user type to the specified output. /// </summary> /// <param name="output">The output.</param> /// <param name="error">The error text writer.</param> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="indentation">The current indentation.</param> public override void WriteCode(IndentedWriter output, TextWriter error, UserTypeFactory factory, UserTypeGenerationFlags generationFlags, int indentation = 0) { string[] namespaces = this.namespaces; if (generationFlags.HasFlag(UserTypeGenerationFlags.GenerateNamespaceAsStaticClass)) { namespaces = NamespaceSymbol.Split(".".ToCharArray()); } // Declared In Type with namespace if (DeclaredInType != null || generationFlags.HasFlag(UserTypeGenerationFlags.GenerateNamespaceAsStaticClass)) { foreach (string innerClass in namespaces) { output.WriteLine(indentation, "public static partial class {0}", innerClass); output.WriteLine(indentation++, @"{{"); } } else { output.WriteLine(indentation, "namespace {0}", Namespace); output.WriteLine(indentation++, @"{{"); } // Inner types foreach (var innerType in InnerTypes) { output.WriteLine(); innerType.WriteCode(output, error, factory, generationFlags, indentation); } // Declared In Type with namespace if (DeclaredInType != null || generationFlags.HasFlag(UserTypeGenerationFlags.GenerateNamespaceAsStaticClass)) { foreach (string innerClass in namespaces) { output.WriteLine(--indentation, "}}"); } } else { output.WriteLine(--indentation, "}}"); } }
/// <summary> /// Writes the code for this user type to the specified output. /// </summary> /// <param name="output">The output.</param> /// <param name="error">The error text writer.</param> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="indentation">The current indentation.</param> public override void WriteCode(IndentedWriter output, TextWriter error, UserTypeFactory factory, UserTypeGenerationFlags generationFlags, int indentation = 0) { // Declared In Type with namespace if (DeclaredInType != null) { foreach (string innerClass in namespaces) { output.WriteLine(indentation, "public static class {0}", innerClass); output.WriteLine(indentation++, @"{{"); } } else { output.WriteLine(indentation, "namespace {0}", Namespace); output.WriteLine(indentation++, @"{{"); } // Inner types foreach (var innerType in InnerTypes) { output.WriteLine(); innerType.WriteCode(output, error, factory, generationFlags, indentation); } // Declared In Type with namespace if (DeclaredInType != null) { foreach (string innerClass in namespaces) { output.WriteLine(--indentation, "}}"); } } else { output.WriteLine(--indentation, "}}"); } }
/// <summary> /// Writes the code for this user type to the specified output. /// </summary> /// <param name="output">The output.</param> /// <param name="error">The error text writer.</param> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="indentation">The current indentation.</param> public override void WriteCode(IndentedWriter output, TextWriter error, UserTypeFactory factory, UserTypeGenerationFlags generationFlags, int indentation = 0) { // Check if we need to write namespace string nameSpace = (DeclaredInType as NamespaceUserType)?.FullClassName ?? Namespace; if ((DeclaredInType == null || (!generationFlags.HasFlag(UserTypeGenerationFlags.SingleFileExport) && DeclaredInType is NamespaceUserType)) && !string.IsNullOrEmpty(nameSpace)) { output.WriteLine(indentation, "namespace {0}", nameSpace); output.WriteLine(indentation++, "{{"); } // Write beginning of the enumeration if (generationFlags.HasFlag(UserTypeGenerationFlags.GenerateFieldTypeInfoComment)) output.WriteLine(indentation, "// {0} (original name: {1})", ClassName, Symbol.Name); if (AreValuesFlags()) output.WriteLine(indentation, @"[System.Flags]"); if (Symbol.Size != 0) output.WriteLine(indentation, @"public enum {0} : {1}", ClassName, GetEnumBasicType(Symbol)); else output.WriteLine(indentation, @"public enum {0}", ClassName); output.WriteLine(indentation++, @"{{"); // Write values foreach (var enumValue in Symbol.GetEnumValues()) { output.WriteLine(indentation, "{0} = {1},", enumValue.Item1, enumValue.Item2); } // Enumeration end output.WriteLine(--indentation, @"}}"); if ((DeclaredInType == null || (!generationFlags.HasFlag(UserTypeGenerationFlags.SingleFileExport) && DeclaredInType is NamespaceUserType)) && !string.IsNullOrEmpty(nameSpace)) { output.WriteLine(--indentation, "}}"); } }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { TypeTree baseType = base.GetBaseClassTypeTree(error, type, factory, out baseClassOffset); this.baseClassOffset = baseClassOffset; return baseType; }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { TypeTree baseType = base.GetBaseClassTypeTree(error, type, CreateFactory(factory), out baseClassOffset); // Check if base type is template argument. It if is, export it as if it is multi class inheritance. UserTypeTree userBaseType = baseType as UserTypeTree; TemplateArgumentUserType primitiveUserType = userBaseType != null ? userBaseType.UserType as TemplateArgumentUserType : null; if (userBaseType != null && primitiveUserType != null) { var dict = GetGenericTypeConstraintsDictionary(factory); string commonBaseClass; if (dict.TryGetValue(primitiveUserType.ClassName, out commonBaseClass)) return UserTypeTree.Create(new TemplateArgumentUserType(commonBaseClass, null), factory); baseClassOffset = 0; return new MultiClassInheritanceTypeTree(); } return baseType; }
/// <summary> /// Initializes a new instance of the <see cref="UserTypeFactory"/> class. /// </summary> /// <param name="factory">The user type factory.</param> public UserTypeFactory(UserTypeFactory factory) : this(factory.typeTransformations, factory.CodeNaming) { }
/// <summary> /// Gets the type tree for the specified field. /// </summary> /// <param name="field">The field.</param> /// <param name="factory">The user type factory.</param> /// <param name="extractingBaseClass">if set to <c>true</c> user type field is being generated for getting base class.</param> /// <param name="bitLength">Number of bits used for this symbol.</param> protected override TypeTree GetFieldTypeTree(SymbolField field, UserTypeFactory factory, bool extractingBaseClass, int bitLength = 0) { // Do not match specializations when getting type for base class. if (extractingBaseClass || NumberOfTemplateArguments == 0) return GetSymbolTypeTree(field.Type, factory, bitLength); // Check field in all specializations var specializedFields = SpecializedTypes.Select(r => new Tuple<TemplateUserType, SymbolField>(r, r.Symbol.Fields.FirstOrDefault(q => q.Name == field.Name))).ToArray(); if (specializedFields.Any(r => r.Item2 == null)) { // TODO: Incorrect bucketization. Field does not exist in all specialization. return GetSymbolTypeTree(field.Type, factory, bitLength); } if (specializedFields.All(r => r.Item2.Type.Name == field.Type.Name)) { // There is no specialization, all types across the specializations are the same. return GetSymbolTypeTree(field.Type, factory, bitLength); } // Try to get type tree TypeTree result = GetSymbolTypeTree(field.Type, factory, bitLength); if (result is BasicTypeTree) { // Basic type tree is not challenged against template arguments, so try to do that. UserType basicUserType; if (CreateFactory(factory).GetUserType(field.Type, out basicUserType)) { TypeTree tree = UserTypeTree.Create(basicUserType, factory); if (tree != null) { return tree; } } // Failed to match the type // TODO: Look for typedeclared. Class is using different types than in template specialization. We cannot support it right now. return new VariableTypeTree(); } return result; }
/// <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> /// Initializes a new instance of the <see cref="EnumUserType"/> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">User type factory that contains this element.</param> public EnumUserType(Symbol symbol, string nameSpace, UserTypeFactory factory) : base(symbol, null, nameSpace, factory) { areValuesFlagsCache = SimpleCache.CreateStruct(CheckIfValuesAreFlags); basicTypeCache = SimpleCache.CreateStruct(() => GetEnumBasicType(Symbol)); }
private static IEnumerable<Symbol> ParseTemplateArguments(UserTypeFactory factory, Module module, string symbolName) { int templateStart = symbolName.IndexOf('<'); if (templateStart > 0) { // Parse template arguments List<string> arguments = new List<string>(); for (int i = templateStart + 1; i < symbolName.Length && symbolName[i] != '>'; i++) { string originalyExtractedType = XmlTypeTransformation.ExtractType(symbolName, i); string extractedType = originalyExtractedType.Trim(); i += originalyExtractedType.Length; if (string.IsNullOrEmpty(extractedType)) { // This can happen only when list is empty if (arguments.Count > 0) throw new NotImplementedException("Unexpected empty template argument in symbol " + symbolName); break; } arguments.Add(extractedType); // Try to see if argument is number (constants are removed from the template arguments as they cannot be used in C#) double constant; if (!double.TryParse(extractedType, out constant)) { // Check if type is existing type (symbol) Symbol symbol = GlobalCache.GetSymbol(extractedType, module); if (symbol == null) throw new Exception("Wrongly formed template argument"); yield return symbol; } } } }
/// <summary> /// Generates user type field based on the specified symbol field and all other fields that are prepared for this function. /// Do not use this function directly, unless you are calling it from overridden function. /// </summary> /// <param name="field">The symbol field.</param> /// <param name="fieldType">The field tree type.</param> /// <param name="factory">The user type factory.</param> /// <param name="simpleFieldValue">The code foe "simple field value" used when creating transformation.</param> /// <param name="gettingField">The code for getting field variable.</param> /// <param name="isStatic">if set to <c>true</c> generated field should be static.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="extractingBaseClass">if set to <c>true</c> user type field is being generated for getting base class.</param> protected override UserTypeField ExtractFieldInternal(SymbolField field, TypeTree fieldType, UserTypeFactory factory, string simpleFieldValue, string gettingField, bool isStatic, UserTypeGenerationFlags generationFlags, bool extractingBaseClass) { // Physical code generation make sense only for non-static fields if (!isStatic) { bool lazyCacheUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.LazyCacheUserTypeFields); bool cacheUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.CacheUserTypeFields); bool cacheStaticUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.CacheStaticUserTypeFields); string constructorText = ""; string fieldName = field.Name; string fieldTypeString = fieldType.GetTypeString(); BasicTypeTree baseType = fieldType as BasicTypeTree; ArrayTypeTree codeArrayType = fieldType as ArrayTypeTree; UserTypeTree userType = fieldType as UserTypeTree; TransformationTypeTree transformationType = fieldType as TransformationTypeTree; bool isEmbedded = field.Type.Tag != CodeTypeTag.Pointer; // Specialization for basic types if (baseType != null) { if (baseType.BasicType == "string") { int charSize = field.Type.ElementType.Size; constructorText = string.Format("ReadString(GetCodeType().Module.Process, ReadPointer(memoryBuffer, memoryBufferOffset + {0}, {1}), {2})", field.Offset, field.Type.Size, charSize); } else if (baseType.BasicType != "NakedPointer") { if (field.LocationType == LocationType.BitField) { constructorText = string.Format("Read{0}(memoryBuffer, memoryBufferOffset + {1}, {2}, {3})", baseType.GetTypeString().UppercaseFirst(), field.Offset, field.Size, field.BitPosition); } else { constructorText = string.Format("Read{0}(memoryBuffer, memoryBufferOffset + {1})", baseType.GetTypeString().UppercaseFirst(), field.Offset); } } } // Specialization for arrays else if (codeArrayType != null) { if (codeArrayType.ElementType is BasicTypeTree) { baseType = (BasicTypeTree)codeArrayType.ElementType; if (baseType != null && baseType.BasicType != "string" && baseType.BasicType != "NakedPointer") { int arraySize = field.Type.Size; int elementSize = field.Type.ElementType.Size; if (baseType.BasicType == "char") { constructorText = string.Format("Read{0}Array(memoryBuffer, memoryBufferOffset + {1}, {2}, {3})", baseType.GetTypeString().UppercaseFirst(), field.Offset, arraySize / elementSize, elementSize); } else { constructorText = string.Format("Read{0}Array(memoryBuffer, memoryBufferOffset + {1}, {2})", baseType.GetTypeString().UppercaseFirst(), field.Offset, arraySize / elementSize); } fieldTypeString = baseType.GetTypeString() + "[]"; } } } // Specialization for user types else if (userType != null && !extractingBaseClass) { if (!(userType.UserType is EnumUserType)) { string thisClassCodeType; if (IsTypeUsingStaticCodeType(this)) { thisClassCodeType = ClassCodeType; } else { thisClassCodeType = "thisClass.Value.GetCodeType()"; usedThisClass = true; } // Check if type is embedded if (!isEmbedded) { // If user type is not embedded, we do have pointer inside of our memory buffer that we can read directly if (IsTypeUsingStaticCodeType(this)) { constructorText = string.Format("ReadPointer<{0}>({4}, \"{1}\", memoryBuffer, memoryBufferOffset + {2}, {3})", fieldTypeString, fieldName, field.Offset, field.Type.Size, ClassCodeType); } else { constructorText = string.Format("ReadPointer<{0}>(thisClass, \"{1}\", memoryBuffer, memoryBufferOffset + {2}, {3})", fieldTypeString, fieldName, field.Offset, field.Type.Size); usedThisClass = true; } // Do downcasting if field has vtable if (userType.UserType.Symbol.HasVTable() && userType.UserType.DerivedClasses.Count > 0) { constructorText += ".DowncastObject()"; } } else { // If user type is embedded, we can reuse memory buffer that we already have in this class string fieldAddress = string.Format("memoryBufferAddress + (ulong)(memoryBufferOffset + {0})", field.Offset); string fieldCodeType = string.Format("{0}.GetClassFieldType(\"{1}\")", thisClassCodeType, fieldName); if (IsTypeUsingStaticCodeType(userType.UserType)) { fieldCodeType = string.Format("{0}.{1}", userType.UserType.FullClassName, ClassCodeType); } else if (IsTypeUsingStaticCodeType(this)) { fieldCodeType = AddFieldCodeType(fieldName); } constructorText = string.Format("new {0}(memoryBuffer, memoryBufferOffset + {1}, memoryBufferAddress, {2}, {3}, \"{4}\")", fieldTypeString, field.Offset, fieldCodeType, fieldAddress, fieldName); } } else { // TODO: This is enum. Read how much enum base type is big and just cast to enum type... } } // Specialization for transformations else if (transformationType != null) { if (!isEmbedded) { string thisClassCodeType; if (IsTypeUsingStaticCodeType(this)) { thisClassCodeType = ClassCodeType; } else { thisClassCodeType = "thisClass.Value.GetCodeType()"; usedThisClass = true; } string fieldAddress = string.Format("memoryBufferAddress + (ulong)(memoryBufferOffset + {0})", field.Offset); string fieldVariable = string.Format("Variable.CreateNoCast({0}.GetClassFieldType(\"{1}\"), {2}, \"{1}\")", thisClassCodeType, fieldName, fieldAddress); if (transformationType.Transformation.Transformation.HasPhysicalConstructor) { fieldVariable = string.Format("{0}, memoryBuffer, memoryBufferOffset + {1}, memoryBufferAddress", fieldVariable, field.Offset); } simpleFieldValue = fieldVariable; constructorText = string.Format("new {0}({1})", fieldTypeString, fieldVariable); } } // If we found suitable physical representation, generate the field if (!string.IsNullOrEmpty(constructorText)) { return new UserTypeField() { ConstructorText = constructorText, FieldName = "_" + fieldName, FieldType = fieldTypeString, FieldTypeInfoComment = string.Format("// {0} {1};", field.Type.Name, fieldName), PropertyName = UserTypeField.GetPropertyName(field, this), Static = isStatic, UseUserMember = lazyCacheUserTypeFields, CacheResult = cacheUserTypeFields || (isStatic && cacheStaticUserTypeFields), SimpleFieldValue = simpleFieldValue, } } ; } return(base.ExtractFieldInternal(field, fieldType, factory, simpleFieldValue, gettingField, isStatic, generationFlags, extractingBaseClass)); }
/// <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> /// Initializes a new instance of the <see cref="UserTypeFactory"/> class. /// </summary> /// <param name="factory">The user type factory.</param> public UserTypeFactory(UserTypeFactory factory) : this(factory.typeTransformations) { }
/// <summary> /// Initializes a new instance of the <see cref="NamespaceUserType"/> class. /// </summary> /// <param name="innerNamespaces">The list of inner namespaces (e.g. chrono in std::chrono).</param> /// <param name="topLevelNamespace">The top level namespace (e.g. module name).</param> /// <param name="factory">User type factory that contains this element.</param> internal NamespaceUserType(IEnumerable <string> innerNamespaces, string topLevelNamespace, UserTypeFactory factory) : base(symbol: null, xmlType: null, nameSpace: null, factory: factory) { namespaces = innerNamespaces.Select(s => CodeNaming.FixUserNaming(s)).ToList(); if (topLevelNamespace != null) { namespaces.Insert(0, topLevelNamespace); } }
/// <summary> /// Gets the dictionary of generic type constraints per template argument (that has constraint). /// </summary> /// <param name="factory">The user type factory.</param> private Dictionary<string, string> GetGenericTypeConstraintsDictionary(UserTypeFactory factory) { Dictionary<string, string> result = new Dictionary<string, string>(); #if false string[] commonBaseSpecializationTypes = GetCommonBaseTypesForAllSpecializations(factory); if (commonBaseSpecializationTypes == null || commonBaseSpecializationTypes.All(r => string.IsNullOrEmpty(r))) #endif { // no restrictions return result; } #if false StringBuilder sb = new StringBuilder(); if (commonBaseSpecializationTypes.Count() == 1) result.Add(TemplateArgumentsNameBase, commonBaseSpecializationTypes[0]); else for (int i = 0; i < commonBaseSpecializationTypes.Count(); i++) if (!string.IsNullOrEmpty(commonBaseSpecializationTypes[i])) result.Add(string.Format("{0}{1}", TemplateArgumentsNameBase, i + 1), commonBaseSpecializationTypes[i]); return result; #endif }
/// <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> /// Creates the user type factory based on this template user type. /// </summary> /// <param name="factory">The original user type factory.</param> private UserTypeFactory CreateFactory(UserTypeFactory factory) { // Check if we are trying to create factory from factory that we already created var templateFactory = factory as TemplateUserTypeFactory; if (templateFactory != null) { if (templateFactory.TemplateType != this) return CreateFactory(templateFactory.OriginalFactory); // TODO: Verify if we want to keep existing template factory or we want to add our type too return templateFactory; } return new TemplateUserTypeFactory(factory, this); }
/// <summary> /// Generates user type field based on the specified symbol field and all other fields that are prepared for this function. /// Do not use this function directly, unless you are calling it from overridden function. /// </summary> /// <param name="field">The symbol field.</param> /// <param name="fieldType">The field tree type.</param> /// <param name="factory">The user type factory.</param> /// <param name="simpleFieldValue">The code foe "simple field value" used when creating transformation.</param> /// <param name="gettingField">The code for getting field variable.</param> /// <param name="isStatic">if set to <c>true</c> generated field should be static.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="extractingBaseClass">if set to <c>true</c> user type field is being generated for getting base class.</param> protected override UserTypeField ExtractFieldInternal(SymbolField field, TypeTree fieldType, UserTypeFactory factory, string simpleFieldValue, string gettingField, bool isStatic, UserTypeGenerationFlags generationFlags, bool extractingBaseClass) { // Physical code generation make sense only for non-static fields if (!isStatic) { bool lazyCacheUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.LazyCacheUserTypeFields); bool cacheUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.CacheUserTypeFields); bool cacheStaticUserTypeFields = generationFlags.HasFlag(UserTypeGenerationFlags.CacheStaticUserTypeFields); string constructorText = ""; string fieldName = field.Name; string fieldTypeString = fieldType.GetTypeString(); BasicTypeTree baseType = fieldType as BasicTypeTree; ArrayTypeTree codeArrayType = fieldType as ArrayTypeTree; UserTypeTree userType = fieldType as UserTypeTree; TransformationTypeTree transformationType = fieldType as TransformationTypeTree; bool isEmbedded = field.Type.Tag != SymTagEnum.SymTagPointerType; // Specialization for basic types if (baseType != null) { if (baseType.BasicType == "string") { int charSize = field.Type.ElementType.Size; constructorText = string.Format("ReadString(GetCodeType().Module.Process, ReadPointer(memoryBuffer, memoryBufferOffset + {0}, {1}), {2})", field.Offset, field.Type.Size, charSize); } else if (baseType.BasicType != "NakedPointer") { if (field.LocationType == LocationType.BitField) constructorText = string.Format("Read{0}(memoryBuffer, memoryBufferOffset + {1}, {2}, {3})", baseType.GetTypeString().UppercaseFirst(), field.Offset, field.Size, field.BitPosition); else constructorText = string.Format("Read{0}(memoryBuffer, memoryBufferOffset + {1})", baseType.GetTypeString().UppercaseFirst(), field.Offset); } } // Specialization for arrays else if (codeArrayType != null) { if (codeArrayType.ElementType is BasicTypeTree) { baseType = (BasicTypeTree)codeArrayType.ElementType; if (baseType != null && baseType.BasicType != "string" && baseType.BasicType != "NakedPointer") { int arraySize = field.Type.Size; int elementSize = field.Type.ElementType.Size; if (baseType.BasicType == "char") constructorText = string.Format("Read{0}Array(memoryBuffer, memoryBufferOffset + {1}, {2}, {3})", baseType.GetTypeString().UppercaseFirst(), field.Offset, arraySize / elementSize, elementSize); else constructorText = string.Format("Read{0}Array(memoryBuffer, memoryBufferOffset + {1}, {2})", baseType.GetTypeString().UppercaseFirst(), field.Offset, arraySize / elementSize); fieldTypeString = baseType.GetTypeString() + "[]"; } } } // Specialization for user types else if (userType != null && !extractingBaseClass) { if (!(userType.UserType is EnumUserType)) { string thisClassCodeType; if (IsTypeUsingStaticCodeType(this)) thisClassCodeType = ClassCodeType; else { thisClassCodeType = "thisClass.Value.GetCodeType()"; usedThisClass = true; } // Check if type is embedded if (!isEmbedded) { // If user type is not embedded, we do have pointer inside of our memory buffer that we can read directly if (IsTypeUsingStaticCodeType(this)) constructorText = string.Format("ReadPointer<{0}>({4}, \"{1}\", memoryBuffer, memoryBufferOffset + {2}, {3})", fieldTypeString, fieldName, field.Offset, field.Type.Size, ClassCodeType); else { constructorText = string.Format("ReadPointer<{0}>(thisClass, \"{1}\", memoryBuffer, memoryBufferOffset + {2}, {3})", fieldTypeString, fieldName, field.Offset, field.Type.Size); usedThisClass = true; } // Do downcasting if field has vtable if (userType.UserType.Symbol.HasVTable() && userType.UserType.DerivedClasses.Count > 0) constructorText += ".DowncastObject()"; } else { // If user type is embedded, we can reuse memory buffer that we already have in this class string fieldAddress = string.Format("memoryBufferAddress + (ulong)(memoryBufferOffset + {0})", field.Offset); string fieldCodeType = string.Format("{0}.GetClassFieldType(\"{1}\")", thisClassCodeType, fieldName); if (IsTypeUsingStaticCodeType(userType.UserType)) { fieldCodeType = string.Format("{0}.{1}", userType.UserType.FullClassName, ClassCodeType); } else if (IsTypeUsingStaticCodeType(this)) { fieldCodeType = AddFieldCodeType(fieldName); } constructorText = string.Format("new {0}(memoryBuffer, memoryBufferOffset + {1}, memoryBufferAddress, {2}, {3}, \"{4}\")", fieldTypeString, field.Offset, fieldCodeType, fieldAddress, fieldName); } } else { // TODO: This is enum. Read how much enum base type is big and just cast to enum type... } } // Specialization for transformations else if (transformationType != null) { if (!isEmbedded) { string thisClassCodeType; if (IsTypeUsingStaticCodeType(this)) thisClassCodeType = ClassCodeType; else { thisClassCodeType = "thisClass.Value.GetCodeType()"; usedThisClass = true; } string fieldAddress = string.Format("memoryBufferAddress + (ulong)(memoryBufferOffset + {0})", field.Offset); string fieldVariable = string.Format("Variable.CreateNoCast({0}.GetClassFieldType(\"{1}\"), {2}, \"{1}\")", thisClassCodeType, fieldName, fieldAddress); if (transformationType.Transformation.Transformation.HasPhysicalConstructor) { fieldVariable = string.Format("{0}, memoryBuffer, memoryBufferOffset + {1}, memoryBufferAddress", fieldVariable, field.Offset); } simpleFieldValue = fieldVariable; constructorText = string.Format("new {0}({1})", fieldTypeString, fieldVariable); } } // If we found suitable physical representation, generate the field if (!string.IsNullOrEmpty(constructorText)) return new UserTypeField() { ConstructorText = constructorText, FieldName = "_" + fieldName, FieldType = fieldTypeString, FieldTypeInfoComment = string.Format("// {0} {1};", field.Type.Name, fieldName), PropertyName = UserTypeField.GetPropertyName(fieldName, this), Static = isStatic, UseUserMember = lazyCacheUserTypeFields, CacheResult = cacheUserTypeFields || (isStatic && cacheStaticUserTypeFields), SimpleFieldValue = simpleFieldValue, }; } return base.ExtractFieldInternal(field, fieldType, factory, simpleFieldValue, gettingField, isStatic, generationFlags, extractingBaseClass); }
/// <summary> /// Initializes a new instance of the <see cref="TemplateArgumentTreeType"/> class. /// </summary> /// <param name="templateArgumentNumber">The template type argument number.</param> /// <param name="templateSpecialization">The template specialization user type.</param> /// <param name="factory">The user type factory.</param> public TemplateArgumentTreeType(int templateArgumentNumber, UserType templateSpecialization, UserTypeFactory factory) : base(templateSpecialization, factory) { ArgumentNumber = templateArgumentNumber; }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { baseClassOffset = 0; return new StaticClassTypeTree(); }
/// <summary> /// Initializes a new instance of the <see cref="TemplateUserType"/> class. /// </summary> /// <param name="template">Specialized template user type that will be used as representative for generating code.</param> /// <param name="specializations"></param> /// <param name="factory">User type factory that contains this element.</param> public TemplateUserType(SpecializedTemplateUserType template, List <SpecializedTemplateUserType> specializations, UserTypeFactory factory) : base(template.Symbol, null, template.Namespace, factory) { Specializations = specializations; SpecializedRepresentative = template; foreach (SpecializedTemplateUserType specialization in specializations) { specialization.TemplateType = this; } }
/// <summary> /// Initializes a new instance of the <see cref="SingleClassInheritanceWithInterfacesTypeTree"/> class. /// </summary> /// <param name="baseClassUserType">The base class user type.</param> /// <param name="factory">The user type factory.</param> public SingleClassInheritanceWithInterfacesTypeTree(UserType baseClassUserType, UserTypeFactory factory) { BaseClassUserType = UserTypeTree.Create(baseClassUserType, factory); }
/// <summary> /// Gets the list of generic type constraints. /// </summary> /// <param name="factory">The user type factory.</param> protected override IEnumerable<string> GetGenericTypeConstraints(UserTypeFactory factory) { var dict = GetGenericTypeConstraintsDictionary(CreateFactory(factory)); return dict.Select(t => string.Format("where {0} : {1}", t.Key, t.Value)); }
public bool UpdateTemplateArguments(UserTypeFactory userTypeFactory) { // TODO: This looks like it is not needed, verify with some huge example PDBs. //throw new NotImplementedException(); return(true); }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { TypeTree baseType = base.GetBaseClassTypeTree(error, type, CreateFactory(factory), out baseClassOffset); // Check if base type is template argument. It if is, export it as if it is multi class inheritance. UserTypeTree userBaseType = baseType as UserTypeTree; TemplateArgumentUserType primitiveUserType = userBaseType != null ? userBaseType.UserType as TemplateArgumentUserType : null; if (userBaseType != null && primitiveUserType != null) { var dict = GetGenericTypeConstraintsDictionary(factory); string commonBaseClass; if (dict.TryGetValue(primitiveUserType.ClassName, out commonBaseClass)) { return(UserTypeTree.Create(new TemplateArgumentUserType(commonBaseClass, null), factory)); } baseClassOffset = 0; return(new MultiClassInheritanceTypeTree()); } return(baseType); }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { baseClassOffset = 0; return(new StaticClassTypeTree()); }
/// <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> /// 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; throw new Exception("This should never happen"); } 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; 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) { userTypeName = new TemplateTypeTree(templateCommonType, factory).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> /// Updates the template arguments (symbols and user types). /// </summary> /// <param name="factory">The user type factory.</param> /// <returns><c>true</c> if all template arguments are resolved as user types.</returns> public bool UpdateTemplateArguments(UserTypeFactory factory) { bool result = true; templateArgumentsAsSymbols = ParseTemplateArguments(factory, Module, Symbol.Namespaces.Last()).ToList(); templateArgumentsAsUserTypes.Clear(); foreach (Symbol symbol in templateArgumentsAsSymbols) { // Try to get user type for the symbol UserType specializationUserType = null; if (!factory.GetUserType(symbol, out specializationUserType)) { if (symbol.Tag != Dia2Lib.SymTagEnum.SymTagEnum && symbol.Tag != Dia2Lib.SymTagEnum.SymTagUDT) { var typeString = GetSymbolTypeTree(symbol, factory).GetTypeString(); specializationUserType = new TemplateArgumentUserType(typeString, symbol); } } templateArgumentsAsUserTypes.Add(specializationUserType); result = result && specializationUserType != null; } // Enumerate all template arguments as strings IEnumerable<Symbol> allTemplateArguments = Enumerable.Empty<Symbol>(); foreach (string symbolName in Symbol.Namespaces) { allTemplateArguments = allTemplateArguments.Concat(ParseTemplateArguments(factory, Module, symbolName)); } AllTemplateArguments = allTemplateArguments.Select(s => s.Name).ToList(); // TODO: Unused types should be removed return result; }
/// <summary> /// Initializes a new instance of the <see cref="PhysicalUserType"/> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">User type factory that contains this element.</param> public PhysicalUserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) : base(symbol, xmlType, nameSpace, factory) { }
/// <summary> /// Gets the list of generic type constraints. /// </summary> /// <param name="factory">The user type factory.</param> protected override IEnumerable <string> GetGenericTypeConstraints(UserTypeFactory factory) { var dict = GetGenericTypeConstraintsDictionary(CreateFactory(factory)); return(dict.Select(t => string.Format("where {0} : {1}", t.Key, t.Value))); }
/// <summary> /// Initializes a new instance of the <see cref="TemplateUserType" /> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">The user type factory.</param> public TemplateUserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) : base(symbol, xmlType, nameSpace) { UpdateTemplateArguments(factory); ExportStaticFields = false; }
/// <summary> /// Gets the type tree for the specified type (symbol). /// </summary> /// <param name="type">The type.</param> /// <param name="factory">The user type factory.</param> /// <param name="bitLength">Number of bits used for this symbol.</param> internal override TypeTree GetSymbolTypeTree(Symbol type, UserTypeFactory factory, int bitLength = 0) { return base.GetSymbolTypeTree(type, CreateFactory(factory), bitLength); }
/// <summary> /// Writes the code for this user type to the specified output. /// </summary> /// <param name="output">The output.</param> /// <param name="error">The error text writer.</param> /// <param name="factory">The user type factory.</param> /// <param name="generationFlags">The user type generation flags.</param> /// <param name="indentation">The current indentation.</param> public override void WriteCode(IndentedWriter output, TextWriter error, UserTypeFactory factory, UserTypeGenerationFlags generationFlags, int indentation = 0) { // Declared In Type with namespace if (DeclaredInType != null) { foreach (string innerClass in namespaces) { output.WriteLine(indentation, "public static partial class {0}", innerClass); output.WriteLine(indentation++, @"{{"); } } else { output.WriteLine(indentation, "namespace {0}", Namespace); output.WriteLine(indentation++, @"{{"); } // Inner types foreach (var innerType in InnerTypes) { output.WriteLine(); innerType.WriteCode(output, error, factory, generationFlags, indentation); } // Declared In Type with namespace if (DeclaredInType != null) foreach (string innerClass in namespaces) output.WriteLine(--indentation, "}}"); else output.WriteLine(--indentation, "}}"); }
/// <summary> /// Initializes a new instance of the <see cref="TemplateUserType" /> class. /// </summary> /// <param name="symbol">The symbol we are generating this user type from.</param> /// <param name="xmlType">The XML description of the type.</param> /// <param name="nameSpace">The namespace it belongs to.</param> /// <param name="factory">The user type factory.</param> public TemplateUserType(Symbol symbol, XmlType xmlType, string nameSpace, UserTypeFactory factory) : base(symbol, xmlType, nameSpace) { UpdateTemplateArguments(factory); ExportStaticFields = false; }
/// <summary> /// Gets the type tree for the base class. /// If class has multi inheritance, it can return MultiClassInheritanceTypeTree or SingleClassInheritanceWithInterfacesTypeTree. /// </summary> /// <param name="error">The error text writer.</param> /// <param name="type">The type for which we are getting base class.</param> /// <param name="factory">The user type factory.</param> /// <param name="baseClassOffset">The base class offset.</param> protected override TypeTree GetBaseClassTypeTree(TextWriter error, Symbol type, UserTypeFactory factory, out int baseClassOffset) { TypeTree baseType = base.GetBaseClassTypeTree(error, type, factory, out baseClassOffset); this.baseClassOffset = baseClassOffset; return(baseType); }
/// <summary> /// Gets the type tree for the specified type (symbol). /// </summary> /// <param name="type">The type.</param> /// <param name="factory">The user type factory.</param> /// <param name="bitLength">Number of bits used for this symbol.</param> internal override TypeTree GetSymbolTypeTree(Symbol type, UserTypeFactory factory, int bitLength = 0) { return(base.GetSymbolTypeTree(type, CreateFactory(factory), bitLength)); }