protected virtual void ResolveMultipleInheritanceMembers(CodeTypeDeclaration generatedType, HashSet <CodeTypeMember> shadows, CodeConstructor constructor) { Func <CodeTypeDeclaration, IEnumerable <CodeTypeDeclaration> > getBaseTypes = type => { var interfaceType = CodeDomHelper.GetOrCreateUserItem <CodeTypeDeclaration>(type, CodeDomHelper.InterfaceKey); if (interfaceType == null) { interfaceType = type; } return(interfaceType.BaseTypes.Cast <CodeTypeReference>().Select(r => r.GetTypeForReference()).Where(c => c != null)); }; var layering = Layering <CodeTypeDeclaration> .CreateLayers(generatedType, getBaseTypes); CodeTypeDeclaration implBaseType = FindBaseClassAndCreateShadows(generatedType, shadows, layering); IEnumerable <CodeTypeDeclaration> inheritedBaseClasses; if (implBaseType != null) { inheritedBaseClasses = implBaseType.Closure(getBaseTypes); var implementationRef = new CodeTypeReference(); implementationRef.BaseType = implBaseType.Name; var n = implBaseType.GetReferenceForType().Namespace(); if (n != null && n.EndsWith(implBaseType.Name)) { implementationRef.BaseType = n + "." + implBaseType.Name; } else { implementationRef.SetNamespace(n); } generatedType.BaseTypes.Insert(0, implementationRef); } else { inheritedBaseClasses = Enumerable.Empty <CodeTypeDeclaration>(); AddImplementationBaseClass(generatedType); } for (int i = layering.Count - 1; i >= 0; i--) { foreach (var baseType in layering[i]) { if (!inheritedBaseClasses.Contains(baseType) && baseType != generatedType && ShouldContainMembers(generatedType, baseType.GetReferenceForType())) { var dependent = baseType.DependentMembers(false); if (dependent != null) { foreach (var inheritedMember in dependent) { RecursivelyAddDependentMembers(generatedType.Members, constructor.Statements, inheritedMember, shadows); } } } } } }
/// <summary> /// Initializes the generated type for the NMeta extension /// </summary> /// <param name="input">The NMeta extension</param> /// <param name="generatedType">The generated type for the extension</param> /// <param name="context">The transformation context</param> public override void Transform(IExtension input, CodeTypeDeclaration generatedType, ITransformationContext context) { SetTypeReferenceForMappedType(input, generatedType.GetReferenceForType()); base.Transform(input, generatedType, context); generatedType.IsClass = true; generatedType.BaseTypes.Add(new CodeTypeReference(typeof(ModelElementExtension <,>).Name, CreateReference(input.AdornedClass, true, context), generatedType.GetReferenceForType())); generatedType.WriteDocumentation(input.Summary ?? string.Format("The {0} extension", input.Name), input.Remarks); CreateFromMethod(input, generatedType, context); CreateGetExtension(input, generatedType, context); }
/// <summary> /// Creates the constructor for the extension /// </summary> /// <param name="input">The NMeta extension</param> /// <param name="generatedType">The generated type declaration for the extension</param> /// <param name="context">The transformation context</param> protected virtual void CreateConstructor(IExtension input, CodeTypeDeclaration generatedType, ITransformationContext context) { var classRef = CreateReference(input.AdornedClass, true, context); var constructor = CodeDomHelper.GetOrCreateDefaultConstructor(generatedType, () => new CodeConstructor()); constructor.Attributes = MemberAttributes.Public; constructor.ReturnType = generatedType.GetReferenceForType(); constructor.Parameters.Add(new CodeParameterDeclarationExpression(classRef, "parent")); constructor.BaseConstructorArgs.Add(new CodeArgumentReferenceExpression("parent")); constructor.WriteDocumentation("Creates a new extension instance for the given parent", null, new Dictionary <string, string>() { { "parent", "The parent model element" } }); if (!generatedType.Members.Contains(constructor)) { generatedType.Members.Add(constructor); } }
/// <summary> /// Gets called when the given type is added to the output namespace, e.g. to prevent name conflicts /// </summary> /// <param name="type"></param> private void AddType(CodeNamespace ns, CodeTypeDeclaration type) { var name = CreateNewValidName(ns, type.Name); var typeRef = type.GetReferenceForType(); var isSelfPointing = false; if (typeRef != null && typeRef.UserData.Contains(CodeDomHelper.NamespaceKey)) { isSelfPointing = typeRef.BaseType == type.Name; if (CodeDomHelper.Namespace(typeRef) == null) { CodeDomHelper.SetNamespace(typeRef, ns.Name); } } if (name != type.Name) { type.Name = name; if (isSelfPointing) { typeRef.BaseType = name; } } ns.Types.Add(type); }
/// <summary> /// Initializes the generated type declaration /// </summary> /// <param name="input">The input model element</param> /// <param name="generatedType">The generated class declaration</param> /// <param name="context">The transformation context</param> /// <remarks>Can be overridden to refine code generation</remarks> public override void Transform(T input, CodeTypeDeclaration generatedType, ITransformationContext context) { HashSet <CodeTypeMember> shadows; var ownShadows = generatedType.Shadows(false); if (ownShadows != null) { shadows = new HashSet <CodeTypeMember>(ownShadows); } else { shadows = new HashSet <CodeTypeMember>(); } var constructor = CodeDomHelper.GetOrCreateDefaultConstructor(generatedType, () => new CodeConstructor() { Attributes = MemberAttributes.Public }); var dependends = generatedType.DependentMembers(false); if (dependends != null) { foreach (var member in dependends) { RecursivelyAddDependentMembers(generatedType.Members, constructor.Statements, member, shadows); } } var interfaceDecl = CreateSeparatePublicInterface(input, generatedType); if (interfaceDecl != null) { CodeDomHelper.SetUserItem(generatedType, CodeDomHelper.InterfaceKey, interfaceDecl); var dependentTypes = CodeDomHelper.DependentTypes(generatedType, true); dependentTypes.Add(interfaceDecl); var typeReference = generatedType.GetReferenceForType(); typeReference.BaseType = interfaceDecl.Name; CreateInterfaceMembers(generatedType, interfaceDecl); for (int i = generatedType.BaseTypes.Count - 1; i >= 0; i--) { var baseTypeRef = generatedType.BaseTypes[i]; var baseType = CodeDomHelper.GetOrCreateUserItem <CodeTypeDeclaration>(baseTypeRef, CodeDomHelper.ClassKey); if (baseType == null) { continue; } interfaceDecl.BaseTypes.Add(baseTypeRef); generatedType.BaseTypes.RemoveAt(i); } generatedType.BaseTypes.Add(typeReference); ResolveMultipleInheritanceMembers(generatedType, shadows, constructor); } if (constructor.Statements.Count > 0) { CodeDomHelper.SetUserItem(generatedType, CodeDomHelper.ConstructorKey, constructor); generatedType.Members.Add(constructor); } }
protected virtual void ResolveMultipleInheritanceMembers(CodeTypeDeclaration generatedType, HashSet <CodeTypeMember> shadows, CodeConstructor constructor) { var allClasses = generatedType.Closure(GetBaseClasses); var layering = Layering <CodeTypeDeclaration> .CreateLayers(generatedType, c => Edges(c, allClasses)); CodeTypeDeclaration implBaseType = null; int layerIndex; for (layerIndex = layering.Count - 1; layerIndex >= 0; layerIndex--) { var layer = layering[layerIndex]; if (layer.Count == 1 && layer.First() != generatedType && !shadows.IntersectsWith(AllFeatures(layer.First()))) { implBaseType = layer.First(); break; } foreach (var cl in layer) { shadows.UnionWith(Refinements(cl)); } } IEnumerable <CodeTypeDeclaration> inheritedBaseClasses; if (implBaseType != null) { inheritedBaseClasses = layering.Take(layerIndex + 1).SelectMany(s => s); var implementationRef = new CodeTypeReference(); implementationRef.BaseType = implBaseType.Name; var n = implBaseType.GetReferenceForType().Namespace(); if (n != null && n.EndsWith(implBaseType.Name)) { implementationRef.BaseType = n + "." + implBaseType.Name; } else { implementationRef.SetNamespace(n); } generatedType.BaseTypes.Insert(0, implementationRef); } else { inheritedBaseClasses = Enumerable.Empty <CodeTypeDeclaration>(); AddImplementationBaseClass(generatedType); } CodeDomHelper.SetUserItem(generatedType, CodeDomHelper.BaseClassesKey, inheritedBaseClasses); for (int i = layerIndex + 1; i < layering.Count; i++) { foreach (var baseType in layering[i]) { if (baseType != generatedType) { var dependent = baseType.DependentMembers(false); if (dependent != null) { foreach (var inheritedMember in dependent) { RecursivelyAddDependentMembers(generatedType.Members, constructor.Statements, inheritedMember, shadows); } } } } } }
private void GenerateTypeConverter(CodeTypeDeclaration generatedType, Dictionary <ILiteral, string> fieldNames) { var dependents = generatedType.DependentTypes(true); if (dependents.Any(c => c.Name == generatedType.Name + "Converter") || fieldNames.All(field => field.Value == field.Key.Name)) { return; } var typeConverter = new CodeTypeDeclaration(generatedType.Name + "Converter"); typeConverter.BaseTypes.Add(typeof(TypeConverter).ToTypeReference()); var stringTypeRef = new CodeTypeOfExpression(typeof(string)); var canConvertFromMethod = new CodeMemberMethod { Name = "CanConvertFrom", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(bool)) }; canConvertFromMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(ITypeDescriptorContext).ToTypeReference(), "context")); canConvertFromMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(System.Type).ToTypeReference(), "sourceType")); var sourceTypeRef = new CodeArgumentReferenceExpression("sourceType"); canConvertFromMethod.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(sourceTypeRef, CodeBinaryOperatorType.IdentityEquality, stringTypeRef))); typeConverter.Members.Add(canConvertFromMethod); var canConvertTo = new CodeMemberMethod { Name = "CanConvertTo", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(bool)) }; canConvertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(ITypeDescriptorContext).ToTypeReference(), "context")); canConvertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(System.Type), "destinationType")); var destinationTypeRef = new CodeArgumentReferenceExpression("destinationType"); canConvertTo.Statements.Add(new CodeMethodReturnStatement(new CodeBinaryOperatorExpression(destinationTypeRef, CodeBinaryOperatorType.IdentityEquality, stringTypeRef))); typeConverter.Members.Add(canConvertTo); var typeRef = generatedType.GetReferenceForType(); var typeExpression = new CodeTypeReferenceExpression(typeRef); var convertFrom = new CodeMemberMethod { Name = "ConvertFrom", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(object)) }; convertFrom.Parameters.Add(new CodeParameterDeclarationExpression(typeof(ITypeDescriptorContext).ToTypeReference(), "context")); convertFrom.Parameters.Add(new CodeParameterDeclarationExpression(typeof(CultureInfo).ToTypeReference(), "culture")); convertFrom.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "value")); var valueRef = new CodeArgumentReferenceExpression("value"); var nullRef = new CodePrimitiveExpression(); convertFrom.Statements.Add(new CodeConditionStatement(new CodeBinaryOperatorExpression(valueRef, CodeBinaryOperatorType.IdentityEquality, nullRef), new CodeMethodReturnStatement(new CodeDefaultValueExpression(typeRef)))); var valueString = new CodeVariableDeclarationStatement(typeof(string), "valueString", new CodeMethodInvokeExpression(valueRef, "ToString")); convertFrom.Statements.Add(valueString); var valueStringRef = new CodeVariableReferenceExpression(valueString.Name); foreach (var field in fieldNames) { convertFrom.Statements.Add(new CodeConditionStatement(new CodeBinaryOperatorExpression(valueStringRef, CodeBinaryOperatorType.ValueEquality, new CodePrimitiveExpression(field.Key.Name)), new CodeMethodReturnStatement(new CodeFieldReferenceExpression(typeExpression, field.Value)))); } convertFrom.Statements.Add(new CodeMethodReturnStatement(new CodeDefaultValueExpression(typeRef))); typeConverter.Members.Add(convertFrom); var convertTo = new CodeMemberMethod { Name = "ConvertTo", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(object)) }; convertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(ITypeDescriptorContext).ToTypeReference(), "context")); convertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(CultureInfo).ToTypeReference(), "culture")); convertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "value")); convertTo.Parameters.Add(new CodeParameterDeclarationExpression(typeof(System.Type).ToTypeReference(), "destinationType")); convertTo.Statements.Add(new CodeConditionStatement(new CodeBinaryOperatorExpression(valueRef, CodeBinaryOperatorType.IdentityEquality, nullRef), new CodeMethodReturnStatement(nullRef))); var valueCasted = new CodeVariableDeclarationStatement(typeRef, "valueCasted", new CodeCastExpression(typeRef, valueRef)); convertTo.Statements.Add(valueCasted); var valueCastedRef = new CodeVariableReferenceExpression(valueCasted.Name); foreach (var field in fieldNames) { convertTo.Statements.Add(new CodeConditionStatement(new CodeBinaryOperatorExpression(valueCastedRef, CodeBinaryOperatorType.ValueEquality, new CodeFieldReferenceExpression(typeExpression, field.Value)), new CodeMethodReturnStatement(new CodePrimitiveExpression(field.Key.Name)))); } convertTo.ThrowException <ArgumentOutOfRangeException>("value"); typeConverter.Members.Add(convertTo); generatedType.AddAttribute(typeof(TypeConverterAttribute), new CodeTypeOfExpression(typeConverter.Name)); dependents.Add(typeConverter); }