private void GeneratePartialClassHeader(StringBuilder sb, bool isUserFile) { sb.AppendLine("// Generated class v" + this.htmlUnitVersion + (isUserFile ? ", can be modified" : ", don't modify")); sb.AppendLine(); if (!isUserFile) { sb.AppendLine("using System;"); sb.AppendLine("using System.Collections.Generic;"); sb.AppendLine("using System.Collections.Specialized;"); sb.AppendLine("using System.Linq;"); sb.AppendLine("using System.Text;"); sb.AppendLine(); } sb.Append("namespace "); sb.AppendLine(TargetNamespace); sb.AppendLine("{"); var interfaceList = new StringBuilder(); if (isUserFile) { sb.AppendLine(" public partial class " + TargetNameWithoutNamespace); } else { IEnumerable <Type> wrappedInterfaces = WrappedType .GetInterfaces() .Where(i => Repository.TypeIsWrapped(i)); foreach (var wrappedInterface in wrappedInterfaces) { interfaceList.AppendFormat(", {0}", Repository.GetTargetFullName(wrappedInterface)); Repository.MarkUsageOfType(wrappedInterface); } if (WrappedBase != null && Repository.TypeIsWrapped(WrappedBase)) { Repository.MarkUsageOfType(WrappedBase); } sb.AppendFormat( " public partial class {0} : {1}{2}\r\n", TargetNameWithoutNamespace, TargetBaseName, interfaceList ); } sb.AppendLine(" {"); }
private void ScanMembers(Type type) { // The special meal of today: find interfaces that is new on this class, and clashes with existing fields! var newInterfacesForThisSubclass = WrappedType .GetInterfaces() .Except(WrappedBase != null ? WrappedBase.GetInterfaces() : new Type[] { }) .Where(i => Repository.TypeIsWrapped(i)); var existingNames = new HashSet <string>( Methods.Values.Select(m => m.TargetMethodInfo.Name)); var methodsOfNewInterfaces = newInterfacesForThisSubclass .SelectMany(il => il.GetMethods()) .Where(m => existingNames.Contains(m.Name)) .ToArray(); foreach (var wmiRo in Methods.Values) { var wmi = wmiRo; // To get correct lambda closure! var conflictingMethods = methodsOfNewInterfaces .Where(m => wmi.TargetMethodInfo.Name == m.Name) .Where(m => IsMethodSignatureCastable(m, wmi.TargetMethodInfo)) .ToArray(); foreach (var cm in conflictingMethods) { Console.WriteLine("Conflicting method: " + cm); } if (conflictingMethods.Any()) { throw new InvalidOperationException(); } } // First extract all properties and methods IEnumerable <MethodInfo> nonObsoleteMethods = type .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any())) .Where(mi => (!mi.Name.Contains("<"))) // TODO: Support methods with weird names that starts with "<bridge>" .Where(mi => (type.BaseType == null || type.BaseType.GetMethod(mi.Name, mi.GetParameters().Select(pi => pi.ParameterType).ToArray()) == null)); foreach (MethodInfo method in nonObsoleteMethods) { bool wrappedAsProperty = false; if (method.Name.Length > 3 && method.IsPublic) { if (method.Name.StartsWith("get") && method.ReturnType != typeof(void) && method.GetParameters().Length == 0 // We can't convert methods to properties that will cause the property to have the same name as the type. && method.Name.Substring(3) != type.Name) { GetWrapperPropInfoFor(Properties, method.Name.Substring(3)).GetterMethod = method; wrappedAsProperty = true; } else if (method.Name.StartsWith("set") && method.GetParameters().Length == 1 && method.ReturnType == typeof(void)) { GetWrapperPropInfoFor(Properties, method.Name.Substring(3)).SetterMethod = method; wrappedAsProperty = true; } } if (!wrappedAsProperty) { Methods.Add(method.ToString(), new WrapperMethodInfo(this, method)); } } if (!type.IsAbstract) { // Extract constructors var nonObsoletePublicConstructors = type .GetConstructors() .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any())) .Where(mi => mi.DeclaringType == type) .Where(mi => !mi.IsAbstract); foreach (var constructor in nonObsoletePublicConstructors) { Constructors.Add(new WrapperConstructorInfo(this, constructor)); } } // Extract public static var publicStaticFields = type .GetFields(BindingFlags.Public | BindingFlags.Static) .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any())) .Where(f => !f.FieldType.IsInterface); foreach (var field in publicStaticFields) { StaticPublicFields.Add(new WrapperStaticPublicField(this, field)); } }
public void GenerateInterfaceCode(StringBuilder sb) { // {0} is namespace declarations // {1} is namespace of interface // {2} is name of interface // {3} is to be filled with methods and properties etc.. var baseInterfaceString = new StringBuilder(); foreach (var baseInterface in WrappedType.GetInterfaces().Where(i => Repository.TypeIsWrapped(i))) { Repository.MarkUsageOfType(baseInterface); baseInterfaceString.Append(", "); baseInterfaceString.Append(Repository.GetTargetFullName(baseInterface)); } const string fileFmt = @"// Wrapper for {5} {0} namespace {1} {{ public interface {2} : NHtmlUnit.IObjectWrapper{3} {{ {4} }} }} "; var namespaceIncludes = @"// Generated class v" + this.htmlUnitVersion + @", don't modify using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Text; "; var body = new StringBuilder(); #warning HACK HACK HACK ON if (!WrappedType.FullName.StartsWith("org.w3c.dom.")) { foreach (var wpi in Properties.Where(x => x.Value.GetterMethod != null)) { wpi.Value.GeneratePropertyCode(body); } foreach (var wm in Methods) { wm.Value.GenerateMethodCode(body); } } sb.AppendFormat(fileFmt, namespaceIncludes, TargetNamespace, TargetNameWithoutNamespace, baseInterfaceString, body, WrappedType.FullName); }