private string[] GetMethodArgs(Smoke *smoke, Smoke.Method *method) { if (method->numArgs == 0) { return(new string[0]); } string className = ByteArrayManager.GetString(smoke->classes[method->classId].className); className = className.Substring(className.LastIndexOf(":") + 1); StringBuilder keyBuilder = new StringBuilder(className + "," + ByteArrayManager.GetString(smoke->methodNames[method->name])); for (short *typeIndex = smoke->argumentList + method->args; *typeIndex > 0; typeIndex++) { keyBuilder.Append(','); keyBuilder.Append(*typeIndex); } string key = keyBuilder.ToString(); if (data.ArgumentNames.ContainsKey(key)) { return(data.ArgumentNames[key]); } string argNamesFile = data.GetArgNamesFile(smoke); if (File.Exists(argNamesFile)) { foreach (string[] strings in File.ReadAllLines(argNamesFile).Select(line => line.Split(';'))) { data.ArgumentNames[strings[0]] = strings[1].Split(','); } return(data.ArgumentNames[key]); } return(null); }
public void Run() { foreach (CodeMemberProperty cmp in GenerateBasicAttributeDefinitions()) { Attribute attr = attributes[cmp.Name]; CodeMethodReferenceExpression interceptorReference = ((attr.GetMethod->flags & (uint)Smoke.MethodFlags.mf_static) == 0) ? SmokeSupport.interceptor_Invoke : SmokeSupport.staticInterceptor_Invoke; cmp.GetStatements.Add( new CodeMethodReturnStatement( new CodeCastExpression(cmp.Type, new CodeMethodInvokeExpression( interceptorReference, new CodePrimitiveExpression(ByteArrayManager.GetString(attr.Smoke->methodNames[attr.GetMethod->name])), new CodePrimitiveExpression(attr.Smoke->GetMethodSignature(attr.GetMethod)), new CodeTypeOfExpression(cmp.Type), new CodePrimitiveExpression(false))))); if (cmp.HasSet) { cmp.SetStatements.Add( new CodeMethodInvokeExpression(interceptorReference, new CodePrimitiveExpression(ByteArrayManager.GetString(attr.Smoke->methodNames[attr.Smoke->FindMungedName(attr.SetMethod)])), new CodePrimitiveExpression(attr.Smoke->GetMethodSignature(attr.SetMethod)), new CodeTypeOfExpression(typeof(void)), new CodePrimitiveExpression(false), new CodeTypeOfExpression(cmp.Type), new CodeArgumentReferenceExpression("value"))); } type.Members.Add(cmp); } }
public void ScheduleAttributeAccessor(Smoke *smoke, Smoke.Method *meth) { string name = ByteArrayManager.GetString(smoke->methodNames[meth->name]); bool isSetMethod = false; if (name.StartsWith("set")) { name = name.Remove(0, 3); isSetMethod = true; } else { // capitalize the first letter StringBuilder builder = new StringBuilder(name); builder[0] = char.ToUpper(builder[0]); name = builder.ToString(); } // If the new name clashes with a name of a type declaration, keep the lower-case name. var typesWithSameName = from member in data.GetAccessibleMembers(smoke->classes + meth->classId) where (member.Type == MemberTypes.NestedType || member.Type == MemberTypes.Method) && member.Name == name select member; if (typesWithSameName.Any()) { string className = ByteArrayManager.GetString(smoke->classes[meth->classId].className); Debug.Print(" |--Conflicting names: property/type: {0} in class {1} - keeping original property name", name, className); name = char.ToLower(name[0]) + name.Substring(1); } Attribute attr; if (!attributes.TryGetValue(name, out attr)) { attr = new Attribute(); attr.Smoke = smoke; attributes.Add(name, attr); } if (isSetMethod) { attr.SetMethod = meth; } else { attr.GetMethod = meth; } }
private void GenerateInheritedMethods(Smoke.Class *klass, MethodsGenerator methgen, AttributeGenerator attrgen, List <Smoke.ModuleIndex> alreadyImplemented) { // Contains inherited methods that have to be implemented by the current class. // We use our custom comparer, so we don't end up with the same method multiple times. IDictionary <Smoke.ModuleIndex, string> implementMethods = new Dictionary <Smoke.ModuleIndex, string>(SmokeMethodEqualityComparer.DefaultEqualityComparer); bool firstParent = true; for (short *parent = data.Smoke->inheritanceList + klass->parents; *parent > 0; parent++) { if (firstParent) { // we're only interested in parents implemented as interfaces firstParent = false; continue; } // collect all methods (+ inherited ones) and add them to the implementMethods Dictionary data.Smoke->FindAllMethods(*parent, implementMethods, true); } foreach (KeyValuePair <Smoke.ModuleIndex, string> pair in implementMethods) { Smoke.Method *meth = pair.Key.smoke->methods + pair.Key.index; Smoke.Class * ifaceKlass = pair.Key.smoke->classes + meth->classId; if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_ctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_copyctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_dtor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_internal) > 0) { // no need to check for properties here - QObjects don't support multiple inheritance anyway continue; } if (alreadyImplemented.Contains(pair.Key, SmokeMethodEqualityComparer.DefaultEqualityComparer)) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0) { attrgen.ScheduleAttributeAccessor(pair.Key.smoke, meth); continue; } CodeTypeReference type = translator.CppToCSharp(ByteArrayManager.GetString(ifaceKlass->className)); methgen.GenerateMethod(pair.Key.smoke, meth, pair.Value, type); } }
private void PostEnumMemberHook(Smoke *smoke, Smoke.Method *smokeMethod, CodeMemberField cmm, CodeTypeDeclaration type) { CodeTypeDeclaration parentType = this.memberDocumentation.Keys.FirstOrDefault(t => t.Name == (string)type.UserData["parent"]); if (parentType != null) { IList <string> docs = this.memberDocumentation[parentType]; string typeName = Regex.Escape(parentType.Name) + "::" + Regex.Escape(type.Name); if (type.Comments.Count == 0) { for (int i = 0; i < docs.Count; i++) { const string enumDoc = @"enum {0}(\s*flags {1}::\w+\s+)?(?<docsStart>.*?)(\n){{3}}"; Match matchEnum = Regex.Match(docs[i], string.Format(enumDoc, typeName, parentType.Name), RegexOptions.Singleline); if (matchEnum.Success) { string doc = (matchEnum.Groups["docsStart"].Value + matchEnum.Groups["docsEnd1"].Value).Trim(); doc = Regex.Replace(doc, @"(The \S+ type is a typedef for QFlags<\S+>\. It stores an OR combination of \S+ values\.)", string.Empty); doc = Regex.Replace(doc, @"ConstantValue(Description)?.*?(((\n){2})|$)", string.Empty, RegexOptions.Singleline).Trim(); if (!string.IsNullOrEmpty(doc)) { Util.FormatComment(doc, type, i > 0); break; } } } } string memberName = Regex.Escape(parentType.Name) + "::" + Regex.Escape(ByteArrayManager.GetString(smoke->methodNames[smokeMethod->name])); const string memberDoc = @"enum {0}.*{1}\t[^\t\n]+\t(?<docs>.*?)(&\w+;)?(\n)"; for (int i = 0; i < docs.Count; i++) { Match match = Regex.Match(docs[i], string.Format(memberDoc, typeName, memberName), RegexOptions.Singleline); if (match.Success) { string doc = match.Groups["docs"].Value.Trim(); if (!string.IsNullOrEmpty(doc)) { Util.FormatComment(char.ToUpper(doc[0]) + doc.Substring(1), cmm, i > 0); break; } } } } }
private void GetAccessibleMembers(Smoke.Class *klass, List <InternalMemberInfo> list) { if (Debug) { Console.Error.WriteLine("members from class {0}", ByteArrayManager.GetString(klass->className)); } if (klass->external) { AddReferencedMembers(klass, list); return; } CodeTypeDeclaration typeDecl; if (!SmokeTypeMap.TryGetValue((IntPtr)klass, out typeDecl)) { AddReferencedMembers(klass, list); return; } foreach (CodeTypeMember member in typeDecl.Members) { if (member is CodeMemberProperty) { list.Add(new InternalMemberInfo(MemberTypes.Property, member.Name)); } else if (member is CodeMemberMethod) { list.Add(new InternalMemberInfo(MemberTypes.Method, member.Name)); } else if (member is CodeMemberField) { list.Add(new InternalMemberInfo(MemberTypes.Field, member.Name)); } else if (member is CodeTypeDeclaration) { list.Add(new InternalMemberInfo(MemberTypes.NestedType, member.Name)); } } for (short *parent = Smoke->inheritanceList + klass->parents; *parent > 0; parent++) { Smoke.Class *parentClass = Smoke->classes + *parent; GetAccessibleMembers(parentClass, list); } }
public List <CodeMemberProperty> GenerateBasicAttributeDefinitions() { List <CodeMemberProperty> ret = new List <CodeMemberProperty>(); foreach (KeyValuePair <string, Attribute> pair in attributes) { Attribute attr = pair.Value; CodeMemberProperty prop = new CodeMemberProperty(); prop.Name = pair.Key; try { bool isRef; prop.Type = translator.CppToCSharp(attr.Smoke->types + attr.GetMethod->ret, out isRef); } catch (NotSupportedException) { string className = ByteArrayManager.GetString(attr.Smoke->classes[attr.GetMethod->classId].className); Debug.Print(" |--Won't wrap Attribute {0}::{1}", className, prop.Name); continue; } prop.HasGet = true; prop.HasSet = attr.SetMethod != (Smoke.Method *) 0; if ((attr.GetMethod->flags & (uint)Smoke.MethodFlags.mf_protected) > 0) { prop.Attributes = MemberAttributes.Family | MemberAttributes.New | MemberAttributes.Final; } else { prop.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final; } if ((attr.GetMethod->flags & (uint)Smoke.MethodFlags.mf_static) > 0) { prop.Attributes |= MemberAttributes.Static; } ret.Add(prop); if (PostAttributeProperty != null) { PostAttributeProperty(prop, type); } } return(ret); }
private void AddReferencedMembers(Smoke.Class *klass, ICollection <InternalMemberInfo> list) { string smokeClassName = ByteArrayManager.GetString(klass->className); Type type; if (!ReferencedTypeMap.TryGetValue(smokeClassName, out type)) { Console.Error.WriteLine("Couldn't find referenced class {0}", smokeClassName); return; } foreach ( MemberInfo member in type.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) { list.Add(new InternalMemberInfo(member.MemberType, member.Name)); } }
/* * convenience overload */ private void DefineEnum(Smoke.Type *type) { // we want the exact combination: t_enum | tf_stack if (type->flags != ((uint)Smoke.TypeId.t_enum | (uint)Smoke.TypeFlags.tf_stack)) { // not an enum type return; } if (type->classId == 0 || data.Smoke->classes[type->classId].external) { // defined elsewhere return; } string enumName = ByteArrayManager.GetString(type->name); this.DefineEnum(enumName); }
public string GetArgNamesFile(Smoke *smoke) { string dest = Destination; if (string.IsNullOrEmpty(dest)) { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { dest = Path.GetDirectoryName(Path.GetDirectoryName(Environment.GetFolderPath(Environment.SpecialFolder.System))); } else { dest = Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture); } } dest = Path.Combine(dest, "share"); dest = Path.Combine(dest, "smoke"); return(Path.Combine(dest, ByteArrayManager.GetString(smoke->module_name) + ".argnames.txt")); }
public string GetMethodSignature(Method *meth) { StringBuilder str = new StringBuilder(); str.Append(ByteArrayManager.GetString(methodNames[meth->name])); str.Append('('); for (short *typeIndex = argumentList + meth->args; *typeIndex > 0;) { str.Append(ByteArrayManager.GetString(types[*typeIndex].name)); if (*(++typeIndex) > 0) { str.Append(", "); } } str.Append(')'); if ((meth->flags & (ushort)MethodFlags.mf_const) != 0) { str.Append(" const"); } return(str.ToString()); }
/* * Generates an Enum member, creating the Enum if necessary. */ public void DefineMember(Smoke.Method *meth) { if ((meth->flags & (uint)Smoke.MethodFlags.mf_enum) == 0) { return; } string typeName = ByteArrayManager.GetString(data.Smoke->types[meth->ret].name); if (typeName == "long") // unnamed enum { return; } CodeTypeDeclaration enumType; if (!data.EnumTypeMap.TryGetValue(typeName, out enumType)) { enumType = DefineEnum(typeName); } CodeMemberField member = new CodeMemberField(); member.Name = ByteArrayManager.GetString(data.Smoke->methodNames[meth->name]); long value = GetEnumValue(data.Smoke, meth); if (value > int.MaxValue && enumType.BaseTypes.Count == 0) { // make the enum derive from 'long' if necessary enumType.BaseTypes.Add(new CodeTypeReference(typeof(long))); } member.InitExpression = new CodePrimitiveExpression(value); if (PostEnumMemberHook != null) { PostEnumMemberHook(data.Smoke, meth, member, enumType); } enumType.Members.Add(member); }
/* * Returns a list of classes for which we need to generate interfaces. */ private HashSet <short> GetClassList() { HashSet <short> set = new HashSet <short>(); for (short i = 1; i <= data.Smoke->numClasses; i++) { Smoke.Class *klass = data.Smoke->classes + i; if (!klass->external && translator.InterfaceClasses.Contains(ByteArrayManager.GetString(klass->className))) { set.Add(i); // also generate interfaces for the base classes of the base classes AddBaseClassesToHashSet(klass, set); } bool firstParent = true; for (short *parent = data.Smoke->inheritanceList + klass->parents; *parent > 0; parent++) { if (firstParent) { // don't generate interfaces for the first base class firstParent = false; continue; } Smoke.Class *baseClass = data.Smoke->classes + *parent; if (baseClass->external) { continue; } set.Add(*parent); AddBaseClassesToHashSet(baseClass, set); } } return(set); }
/* * Loops through all wrapped methods. Any class that is found is converted to a .NET class (see DefineClass()). * A MethodGenerator is then created to generate the methods for that class. */ public void Run() { for (short i = 1; i <= data.Smoke->numClasses; i++) { Smoke.Class *klass = data.Smoke->classes + i; if (klass->external) { continue; } DefineClass(i); } eg.DefineEnums(); // create interfaces if necessary ClassInterfacesGenerator cig = new ClassInterfacesGenerator(data, translator); cig.Run(); for (short i = 1; i <= data.Smoke->numClasses; i++) { Smoke.Class *klass = data.Smoke->classes + i; if (klass->external) { continue; } string className = ByteArrayManager.GetString(klass->className); CodeTypeDeclaration type = data.SmokeTypeMap[(IntPtr)klass]; CodeTypeDeclaration iface; if (data.InterfaceTypeMap.TryGetValue(className, out iface)) { type.BaseTypes.Add(new CodeTypeReference('I' + type.Name)); } short *parent = data.Smoke->inheritanceList + klass->parents; bool firstParent = true; while (*parent > 0) { if (firstParent) { firstParent = false; parent++; continue; } // Translator.CppToCSharp() will take care of 'interfacifying' the class name type.BaseTypes.Add(translator.CppToCSharp(data.Smoke->classes + *parent)); parent++; } } if (PreClassesHook != null) { PreClassesHook(); } GenerateMethods(); GenerateInternalImplementationMethods(); if (PostClassesHook != null) { PostClassesHook(); } MethodsGenerator.Provider.Dispose(); }
public static unsafe bool IsQObject(Smoke.Class *klass) { return(IsDerivedFrom(ByteArrayManager.GetString(klass->className), "QObject")); }
public void PostMembersHook(Smoke *smoke, Smoke.Class *klass, CodeTypeDeclaration type) { if (Util.IsQObject(klass)) { CodeMemberProperty emit = new CodeMemberProperty(); emit.Name = "Emit"; emit.Attributes = MemberAttributes.Family | MemberAttributes.New | MemberAttributes.Final; emit.HasGet = true; emit.HasSet = false; string signalsIfaceName = "I" + type.Name + "Signals"; CodeTypeReference returnType = new CodeTypeReference(signalsIfaceName); emit.Type = returnType; emit.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression( returnType, new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "Q_EMIT") ))); type.Members.Add(emit); string className = ByteArrayManager.GetString(klass->className); int colon = className.LastIndexOf("::", StringComparison.Ordinal); string prefix = (colon != -1) ? className.Substring(0, colon) : string.Empty; IList typeCollection = Data.GetTypeCollection(prefix); CodeTypeDeclaration ifaceDecl = new CodeTypeDeclaration(signalsIfaceName); ifaceDecl.IsInterface = true; if (className != "QObject") { string parentClassName = ByteArrayManager.GetString(smoke->classes[smoke->inheritanceList[klass->parents]].className); colon = parentClassName.LastIndexOf("::", StringComparison.Ordinal); prefix = (colon != -1) ? parentClassName.Substring(0, colon) : string.Empty; if (colon != -1) { parentClassName = parentClassName.Substring(colon + 2); } string parentInterface = (prefix != string.Empty) ? prefix.Replace("::", ".") + "." : string.Empty; parentInterface += "I" + parentClassName + "Signals"; ifaceDecl.BaseTypes.Add(new CodeTypeReference(parentInterface)); } Dictionary <CodeSnippetTypeMember, CodeMemberMethod> signalEvents = new Dictionary <CodeSnippetTypeMember, CodeMemberMethod>(); GetSignals(smoke, klass, delegate(string signature, string name, string typeName, IntPtr metaMethod) { CodeMemberMethod signal = new CodeMemberMethod(); signal.Attributes = MemberAttributes.Abstract; // capitalize the first letter StringBuilder builder = new StringBuilder(name); builder[0] = char.ToUpper(builder[0]); string tmp = builder.ToString(); signal.Name = tmp; bool isRef; try { if (typeName == string.Empty) { signal.ReturnType = new CodeTypeReference(typeof(void)); } else { signal.ReturnType = Translator.CppToCSharp(typeName, out isRef); } } catch (NotSupportedException) { Debug.Print(" |--Won't wrap signal {0}::{1}", className, signature); return; } CodeAttributeDeclaration attr = new CodeAttributeDeclaration("Q_SIGNAL", new CodeAttributeArgument(new CodePrimitiveExpression(signature))); signal.CustomAttributes.Add(attr); int argNum = 1; StringBuilder fullNameBuilder = new StringBuilder("Slot"); GetMetaMethodParameters(metaMethod, delegate(string paramType, string paramName) { if (paramName == string.Empty) { paramName = "arg" + argNum.ToString(); } argNum++; CodeParameterDeclarationExpression param; try { short id = smoke->IDType(paramType); CodeTypeReference paramTypeRef; if (id > 0) { paramTypeRef = Translator.CppToCSharp(smoke->types + id, out isRef); } else { if (!paramType.Contains("::")) { id = smoke->IDType(className + "::" + paramType); if (id > 0) { paramTypeRef = Translator.CppToCSharp(smoke->types + id, out isRef); } else { paramTypeRef = Translator.CppToCSharp(paramType, out isRef); } } else { paramTypeRef = Translator.CppToCSharp(paramType, out isRef); } } param = new CodeParameterDeclarationExpression(paramTypeRef, paramName); } catch (NotSupportedException) { Debug.Print(" |--Won't wrap signal {0}::{1}", className, signature); return; } if (isRef) { param.Direction = FieldDirection.Ref; } signal.Parameters.Add(param); if (argNum == 2) { fullNameBuilder.Append('<'); } fullNameBuilder.Append(param.Type.BaseType); fullNameBuilder.Append(','); }); if (fullNameBuilder[fullNameBuilder.Length - 1] == ',') { fullNameBuilder[fullNameBuilder.Length - 1] = '>'; } ifaceDecl.Members.Add(signal); CodeSnippetTypeMember signalEvent = new CodeSnippetTypeMember(); signalEvent.Name = signal.Name; CodeSnippetTypeMember existing = signalEvents.Keys.FirstOrDefault(m => m.Name == signal.Name); if (existing != null) { CodeSnippetTypeMember signalEventToUse; CodeMemberMethod signalToUse; if (signal.Parameters.Count == 0) { signalEventToUse = existing; signalToUse = signalEvents[existing]; } else { signalEventToUse = signalEvent; signalToUse = signal; } string suffix = signalToUse.Parameters.Cast <CodeParameterDeclarationExpression>().Last().Name; if (suffix.StartsWith("arg") && suffix.Length > 3 && char.IsDigit(suffix[3])) { string lastType = signalToUse.Parameters.Cast <CodeParameterDeclarationExpression>().Last().Type.BaseType; suffix = lastType.Substring(lastType.LastIndexOf('.') + 1); } else { StringBuilder lastParamBuilder = new StringBuilder(suffix); lastParamBuilder[0] = char.ToUpper(lastParamBuilder[0]); suffix = lastParamBuilder.ToString(); } signalEventToUse.Text = signalEventToUse.Text.Replace(signalEventToUse.Name, signalEventToUse.Name += suffix); } signalEvent.Text = string.Format(@" public event {0} {1} {{ add {{ QObject.Connect(this, Qt.SIGNAL(""{2}""), (QObject) value.Target, Qt.SLOT(value.Method.Name + ""{3}"")); }} remove {{ QObject.Disconnect(this, Qt.SIGNAL(""{2}""), (QObject) value.Target, Qt.SLOT(value.Method.Name + ""{3}"")); }} }}" , fullNameBuilder, signalEvent.Name, signature, signature.Substring(signature.IndexOf('('))); signalEvents.Add(signalEvent, signal); }); typeCollection.Add(ifaceDecl); foreach (KeyValuePair <CodeSnippetTypeMember, CodeMemberMethod> signalEvent in signalEvents) { CodeSnippetTypeMember implementation = signalEvent.Key; CodeCommentStatementCollection comments = new CodeCommentStatementCollection(); foreach (CodeTypeMember current in from CodeTypeMember member in type.Members where member.Name == implementation.Name select member) { if (comments.Count == 0) { comments.AddRange(current.Comments); } current.Name = "On" + current.Name; } signalEvent.Value.Comments.AddRange(comments); signalEvent.Key.Comments.AddRange(comments); type.Members.Add(signalEvent.Key); } } }
public CodeTypeReference CppToCSharp(Smoke.Type *type, out bool isRef) { string typeString = ByteArrayManager.GetString(type->name); isRef = false; if ((IntPtr)type->name == IntPtr.Zero) { return(new CodeTypeReference(typeof(void))); } Smoke.TypeId typeId = (Smoke.TypeId)(type->flags & (ushort)Smoke.TypeFlags.tf_elem); if (typeId == Smoke.TypeId.t_bool) { return(new CodeTypeReference(typeof(bool))); } if (typeId == Smoke.TypeId.t_char) { return(new CodeTypeReference(typeof(sbyte))); } if (typeId == Smoke.TypeId.t_uchar) { return(new CodeTypeReference(typeof(byte))); } if (typeId == Smoke.TypeId.t_short) { return(new CodeTypeReference(typeof(short))); } if (typeId == Smoke.TypeId.t_ushort) { return(new CodeTypeReference(typeof(ushort))); } if (typeId == Smoke.TypeId.t_int) { return(new CodeTypeReference(typeof(int))); } if (typeId == Smoke.TypeId.t_uint) { // HACK: qdrawutil.h says, DrawingHint is for internal use; nonetheless, SMOKE generates an overload using it; ignoring if (typeString == "unsigned int" || typeString == "QFlags<QDrawBorderPixmap::DrawingHint>") { return(new CodeTypeReference(typeof(uint))); } } if (typeId == Smoke.TypeId.t_long) { return(new CodeTypeReference("NativeLong")); } if (typeId == Smoke.TypeId.t_ulong) { return(new CodeTypeReference("NativeULong")); } if (typeId == Smoke.TypeId.t_float) { return(new CodeTypeReference(typeof(float))); } if (typeId == Smoke.TypeId.t_double) { return(new CodeTypeReference(typeof(double))); } return(this.CppToCSharp(typeString, out isRef)); }
public CodeTypeReference CppToCSharp(Smoke.Class *klass) { bool isRef; return(this.CppToCSharp(ByteArrayManager.GetString(klass->className), out isRef)); }
public void Run() { for (short classId = 1; classId <= data.Smoke->numClasses; classId++) { Smoke.Class *klass = data.Smoke->classes + classId; if (klass->external) { continue; } List <Property> props = new List <Property>(); if (!GetProperties(data.Smoke, classId, (name, originalType, typeName, writable, isEnum) => props.Add(new Property(name, originalType, typeName, writable, isEnum)))) { continue; } CodeTypeDeclaration type = data.SmokeTypeMap[(IntPtr)klass]; string className = ByteArrayManager.GetString(klass->className); foreach (Property prop in props) { CodeMemberProperty cmp = new CodeMemberProperty(); try { bool isRef; short id = data.Smoke->IDType(prop.Type); if (id > 0) { cmp.Type = translator.CppToCSharp(data.Smoke->types + id, out isRef); } else { if (!prop.Type.Contains("::")) { id = data.Smoke->IDType(className + "::" + prop.Type); if (id > 0) { cmp.Type = translator.CppToCSharp(data.Smoke->types + id, out isRef); } else { cmp.Type = translator.CppToCSharp(prop.Type, out isRef); } } cmp.Type = translator.CppToCSharp(prop.Type, out isRef); } } catch (NotSupportedException) { Debug.Print(" |--Won't wrap Property {0}::{1}", className, prop.Name); continue; } if (documentation.ContainsKey(type)) { IList <string> docs = documentation[type]; for (int i = 0; i < docs.Count; i++) { Match match = Regex.Match(docs[i], prop.Name + " : (const )?" + prop.OriginalType + @"\n(?<docs>This.*?)\nAccess functions:", RegexOptions.Singleline); if (match.Success) { Util.FormatComment(match.Groups["docs"].Value, cmp, i > 0); break; } } } cmp.Name = prop.Name; // capitalize the first letter StringBuilder builder = new StringBuilder(cmp.Name); builder[0] = char.ToUpper(builder[0]); string capitalized = builder.ToString(); // If the new name clashes with a name of a type declaration, keep the lower-case name (or even make the name lower-case). var typesWithSameName = from member in data.GetAccessibleMembers(data.Smoke->classes + classId) where (member.Type == MemberTypes.NestedType || member.Type == MemberTypes.Method) && member.Name == capitalized select member; if (typesWithSameName.Any()) { Debug.Print( " |--Conflicting names: property/(type or method): {0} in class {1} - keeping original property name", capitalized, className); if (capitalized == cmp.Name) { builder[0] = char.ToLower(builder[0]); cmp.Name = builder.ToString(); // lower case the property if necessary } } else { cmp.Name = capitalized; } cmp.HasGet = true; cmp.HasSet = prop.IsWritable; cmp.Attributes = MemberAttributes.Public | MemberAttributes.New | MemberAttributes.Final; cmp.CustomAttributes.Add(new CodeAttributeDeclaration("Q_PROPERTY", new CodeAttributeArgument( new CodePrimitiveExpression(prop.OriginalType)), new CodeAttributeArgument( new CodePrimitiveExpression(prop.Name)))); // ===== get-method ===== short getterMapId = FindQPropertyGetAccessorMethodMapId(classId, prop, capitalized); if (getterMapId == 0) { Debug.Print(" |--Missing 'get' method for property {0}::{1} - using QObject.Property()", className, prop.Name); cmp.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(cmp.Type, new CodeMethodInvokeExpression( new CodeThisReferenceExpression(), "Property", new CodePrimitiveExpression(prop.Name))))); } else { Smoke.MethodMap *map = data.Smoke->methodMaps + getterMapId; short getterId = map->method; if (getterId < 0) { // simply choose the first (i.e. non-const) version if there are alternatives getterId = data.Smoke->ambiguousMethodList[-getterId]; } Smoke.Method *getter = data.Smoke->methods + getterId; if (getter->classId != classId) { // The actual get method is defined in a parent class - don't create a property for it. continue; } if ((getter->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0 && (getter->flags & (uint)Smoke.MethodFlags.mf_purevirtual) == 0) { cmp.GetStatements.Add(new CodeMethodReturnStatement(new CodeCastExpression(cmp.Type, new CodeMethodInvokeExpression( SmokeSupport.interceptor_Invoke, new CodePrimitiveExpression( ByteArrayManager.GetString( data.Smoke->methodNames[getter->name ])), new CodePrimitiveExpression( data.Smoke->GetMethodSignature(getter)), new CodeTypeOfExpression(cmp.Type), new CodePrimitiveExpression(false))))); } else { cmp.HasGet = false; if (!cmp.HasSet) { // the get accessor is virtual and there's no set accessor => continue continue; } } } // ===== set-method ===== if (!prop.IsWritable) { // not writable? => continue type.Members.Add(cmp); continue; } char mungedSuffix; short setterMethId = FindQPropertySetAccessorMethodId(classId, prop, capitalized, out mungedSuffix); if (setterMethId == 0) { Debug.Print(" |--Missing 'set' method for property {0}::{1} - using QObject.SetProperty()", className, prop.Name); cmp.SetStatements.Add(new CodeExpressionStatement( new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "SetProperty", new CodePrimitiveExpression(prop.Name), new CodeArgumentReferenceExpression("value")))); } else { Smoke.Method *setter = data.Smoke->methods + setterMethId; if (setter->classId != classId) { // defined in parent class, continue type.Members.Add(cmp); continue; } string setterName = ByteArrayManager.GetString(data.Smoke->methodNames[setter->name]); if (!cmp.HasGet) { // so the 'get' method is virtual - generating a property for only the 'set' method is a bad idea MethodsGenerator mg = new MethodsGenerator(data, translator, type, klass); mg.GenerateMethod(setterMethId, setterName + mungedSuffix); continue; } cmp.SetStatements.Add(new CodeExpressionStatement( new CodeMethodInvokeExpression(SmokeSupport.interceptor_Invoke, new CodePrimitiveExpression(setterName + mungedSuffix), new CodePrimitiveExpression( this.data.Smoke->GetMethodSignature(setterMethId)), new CodeTypeOfExpression(typeof(void)), new CodePrimitiveExpression(false), new CodeTypeOfExpression(cmp.Type), new CodeArgumentReferenceExpression("value")))); } type.Members.Add(cmp); } } }
/* * Adds the methods to the classes created by Run() */ private void GenerateMethods() { short currentClassId = 0; Smoke.Class * klass = (Smoke.Class *)IntPtr.Zero; MethodsGenerator methgen = null; AttributeGenerator attrgen = null; CodeTypeDeclaration type = null; List <Smoke.ModuleIndex> alreadyImplemented = new List <Smoke.ModuleIndex>(); this.FillEnums(); for (short i = 1; i < data.Smoke->numMethodMaps; i++) { Smoke.MethodMap *map = data.Smoke->methodMaps + i; if (currentClassId != map->classId) { // we encountered a new class if (attrgen != null) { // generate inherited methods this.GenerateInheritedMethods(klass, methgen, attrgen, alreadyImplemented); // generate all scheduled attributes attrgen.Run(); if (PostMembersHooks != null) { PostMembersHooks(data.Smoke, klass, type); } methgen.GenerateProperties(); } currentClassId = map->classId; klass = data.Smoke->classes + currentClassId; type = data.SmokeTypeMap[(IntPtr)klass]; alreadyImplemented.Clear(); attrgen = new AttributeGenerator(data, translator, type); methgen = new MethodsGenerator(data, translator, type, klass); } string mungedName = ByteArrayManager.GetString(data.Smoke->methodNames[map->name]); if (map->method > 0) { Smoke.Method *meth = data.Smoke->methods + map->method; if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_property) > 0 && // non-virtual properties are excluded (meth->flags & (ushort)Smoke.MethodFlags.mf_virtual) == 0 && (meth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0) { attrgen.ScheduleAttributeAccessor(meth); continue; } methgen.GenerateMethod(map->method, mungedName); alreadyImplemented.Add(new Smoke.ModuleIndex(data.Smoke, map->method)); } else if (map->method < 0) { for (short *overload = data.Smoke->ambiguousMethodList + (-map->method); *overload > 0; overload++) { Smoke.Method *meth = data.Smoke->methods + *overload; if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_property) > 0 && // non-virtual properties are excluded (meth->flags & (ushort)Smoke.MethodFlags.mf_virtual) == 0 && (meth->flags & (ushort)Smoke.MethodFlags.mf_purevirtual) == 0) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0) { attrgen.ScheduleAttributeAccessor(meth); continue; } // if the methods differ only by constness, we will generate special code bool nextDiffersByConst = false; if (*(overload + 1) > 0) { if (SmokeMethodEqualityComparer.EqualExceptConstness(meth, data.Smoke->methods + *(overload + 1))) { nextDiffersByConst = true; } } methgen.GenerateMethod(*overload, mungedName); alreadyImplemented.Add(new Smoke.ModuleIndex(data.Smoke, *overload)); if (nextDiffersByConst) { overload++; } } } } // Generate the last scheduled attributes attrgen.Run(); // Generate remaining inherited methods this.GenerateInheritedMethods(klass, methgen, attrgen, alreadyImplemented); if (PostMembersHooks != null) { PostMembersHooks(data.Smoke, klass, type); } methgen.GenerateProperties(); AddMissingOperators(); }
public override string ToString() { return(ByteArrayManager.GetString(module_name)); }
// adapted from QtRuby's findAllMethods() public void FindAllMethods(short c, IDictionary <ModuleIndex, string> ret, bool searchSuperClasses) { Class *klass = classes + c; if (klass->external) { Smoke *smoke = (Smoke *)0; short index = 0; if (!Util.GetModuleIndexFromClassName(klass->className, ref smoke, ref index)) { Console.Error.WriteLine(" |--Failed resolving external class {0}", ByteArrayManager.GetString(klass->className)); return; } smoke->FindAllMethods(index, ret, true); return; } Smoke *thisPtr; fixed(Smoke *smoke = &this) { thisPtr = smoke; // hackish, but this is the cleanest way that I know to get the 'this' pointer } short imax = numMethodMaps; short imin = 0; short methmin = -1, methmax = -1; int icmp = -1; while (imax >= imin) { short icur = (short)((imin + imax) / 2); icmp = methodMaps[icur].classId - c; if (icmp == 0) { short pos = icur; while (icur > 0 && methodMaps[icur - 1].classId == c) { icur--; } methmin = icur; icur = pos; while (icur < imax && methodMaps[icur + 1].classId == c) { icur++; } methmax = icur; break; } if (icmp > 0) { imax = (short)(icur - 1); } else { imin = (short)(icur + 1); } } if (icmp != 0) { Console.Error.WriteLine("WARNING: FindAllMethods failed for class {0}", ByteArrayManager.GetString(classes[c].className)); return; } for (short i = methmin; i <= methmax; i++) { string mungedName = ByteArrayManager.GetString(methodNames[methodMaps[i].name]); short methId = methodMaps[i].method; if (methId > 0) { ret[new ModuleIndex(thisPtr, methId)] = mungedName; } else { for (short *overload = ambiguousMethodList + (-methId); *overload > 0; overload++) { ret[new ModuleIndex(thisPtr, *overload)] = mungedName; } } } if (searchSuperClasses) { for (short *parent = inheritanceList + classes[c].parents; *parent > 0; parent++) { FindAllMethods(*parent, ret, true); } } }
public void Run() { HashSet <short> interfaceClasses = GetClassList(); // Make the interfaces known first, otherwise Translator won't work correctly. foreach (short idx in interfaceClasses) { Smoke.Class *klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); int colon = className.LastIndexOf("::", StringComparison.Ordinal); string prefix = (colon != -1) ? className.Substring(0, colon) : string.Empty; string name = (colon != -1) ? className.Substring(colon + 2) : className; CodeTypeDeclaration ifaceDecl = new CodeTypeDeclaration('I' + name); ifaceDecl.IsInterface = true; CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass", new CodeAttributeArgument( new CodePrimitiveExpression(className))); ifaceDecl.CustomAttributes.Add(attr); data.GetTypeCollection(prefix).Add(ifaceDecl); data.InterfaceTypeMap[className] = ifaceDecl; } // Now generate the methods. foreach (short idx in interfaceClasses) { Smoke.Class * klass = data.Smoke->classes + idx; string className = ByteArrayManager.GetString(klass->className); CodeTypeDeclaration ifaceDecl = data.InterfaceTypeMap[className]; short *parent = data.Smoke->inheritanceList + klass->parents; while (*parent > 0) { ifaceDecl.BaseTypes.Add(translator.CppToCSharp(data.Smoke->classes + *parent)); parent++; } MethodsGenerator mg = new MethodsGenerator(data, translator, ifaceDecl, klass); AttributeGenerator ag = new AttributeGenerator(data, translator, ifaceDecl); List <IntPtr> methods = new List <IntPtr>(); ///TODO: replace this algorithm, it's highly inefficient for (short i = 0; i <= data.Smoke->numMethods && data.Smoke->methods[i].classId <= idx; i++) { Smoke.Method *meth = data.Smoke->methods + i; if (meth->classId != idx) { continue; } string methName = ByteArrayManager.GetString(data.Smoke->methodNames[meth->name]); // we don't want anything except protected, const or empty flags if ((meth->flags & (ushort)Smoke.MethodFlags.mf_enum) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_ctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_copyctor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_dtor) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_static) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_internal) > 0 || (meth->flags & (ushort)Smoke.MethodFlags.mf_protected) > 0 || methName.StartsWith("operator")) { continue; } if ((meth->flags & (ushort)Smoke.MethodFlags.mf_attribute) > 0) { ag.ScheduleAttributeAccessor(meth); continue; } methods.Add((IntPtr)meth); } methods.Sort(CompareSmokeMethods); foreach (Smoke.Method *method in methods) { CodeMemberMethod cmm = mg.GenerateBasicMethodDefinition(data.Smoke, method); if (cmm != null && !ifaceDecl.HasMethod(cmm)) { ifaceDecl.Members.Add(cmm); } } mg.GenerateProperties(); foreach (CodeMemberProperty prop in ag.GenerateBasicAttributeDefinitions()) { ifaceDecl.Members.Add(prop); } } }
/* * Create a .NET class from a smoke class. * A class Namespace::Foo is mapped to Namespace.Foo. Classes that are not in any namespace go into the default namespace. * For namespaces that contain functions, a Namespace.Global class is created which holds the functions as methods. */ private void DefineClass(short classId) { Smoke.Class *smokeClass = data.Smoke->classes + classId; string smokeName = ByteArrayManager.GetString(smokeClass->className); string mapName = smokeName; string name; string prefix = string.Empty; if (smokeClass->size == 0 && !translator.NamespacesAsClasses.Contains(smokeName)) { if (smokeName == "QGlobalSpace") { // global space name = data.GlobalSpaceClassName; mapName = name; } else { // namespace prefix = smokeName; name = "Global"; mapName = prefix + "::Global"; } } else { int colon = smokeName.LastIndexOf("::", StringComparison.Ordinal); prefix = (colon != -1) ? smokeName.Substring(0, colon) : string.Empty; name = (colon != -1) ? smokeName.Substring(colon + 2) : smokeName; } // define the .NET class CodeTypeDeclaration type; bool alreadyDefined; if (!(alreadyDefined = data.CSharpTypeMap.TryGetValue(mapName, out type))) { type = new CodeTypeDeclaration(name); CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass", new CodeAttributeArgument( new CodePrimitiveExpression(smokeName))); type.CustomAttributes.Add(attr); type.IsPartial = true; } else { int toBeRemoved = -1; for (int i = 0; i < type.CustomAttributes.Count; i++) { CodeAttributeDeclaration attr = type.CustomAttributes[i]; if (attr.Name == "SmokeClass" && attr.Arguments.Count == 1 && ((string)((CodePrimitiveExpression)attr.Arguments[0].Value).Value) == "QGlobalSpace") { toBeRemoved = i; break; } } if (toBeRemoved > -1) { type.CustomAttributes.RemoveAt(toBeRemoved); CodeAttributeDeclaration attr = new CodeAttributeDeclaration("SmokeClass", new CodeAttributeArgument( new CodePrimitiveExpression(smokeName))); type.CustomAttributes.Add(attr); } } if (smokeClass->parents != 0) { short *parent = data.Smoke->inheritanceList + smokeClass->parents; if (*parent > 0) { type.BaseTypes.Add( new CodeTypeReference(ByteArrayManager.GetString((data.Smoke->classes + *parent)->className).Replace("::", "."))); } } if (Util.IsClassAbstract(data.Smoke, classId)) { type.TypeAttributes |= TypeAttributes.Abstract; } if (PreMembersHooks != null) { PreMembersHooks(data.Smoke, smokeClass, type); } if (!alreadyDefined) { DefineWrapperClassFieldsAndMethods(smokeClass, type); data.CSharpTypeMap[mapName] = type; IList collection = data.GetTypeCollection(prefix); collection.Add(type); type.UserData.Add("parent", prefix); // add the internal implementation type for abstract classes if ((type.TypeAttributes & TypeAttributes.Abstract) == TypeAttributes.Abstract) { CodeTypeDeclaration implType = new CodeTypeDeclaration(); implType.Name = type.Name + "Internal"; implType.BaseTypes.Add(new CodeTypeReference(type.Name)); implType.IsPartial = true; implType.TypeAttributes = TypeAttributes.NotPublic; CodeConstructor dummyCtor = new CodeConstructor(); dummyCtor.Parameters.Add(new CodeParameterDeclarationExpression(new CodeTypeReference(typeof(Type)), "dummy")); dummyCtor.BaseConstructorArgs.Add(new CodeSnippetExpression("(System.Type) null")); dummyCtor.Attributes = MemberAttributes.Family; implType.Members.Add(dummyCtor); data.InternalTypeMap[type] = implType; collection.Add(implType); } } data.SmokeTypeMap[(IntPtr)smokeClass] = type; }
public CodeMemberMethod GenerateBasicMethodDefinition(Smoke *smoke, Smoke.Method *method, string cppSignature, CodeTypeReference iface) { // do we actually want that method? string className = ByteArrayManager.GetString(smokeClass->className); string completeSignature = className + "::" + cppSignature; if (translator.ExcludedMethods.Any(regex => regex.IsMatch(completeSignature))) { return(null); } CodeParameterDeclarationExpressionCollection args = new CodeParameterDeclarationExpressionCollection(); int count = 1; bool isRef; // make instance operators static and bring the arguments in the correct order string methName = ByteArrayManager.GetString(smoke->methodNames[method->name]); bool isOperator = false; string explicitConversionType = null; if (methName.StartsWith("operator")) { string op = methName.Substring(8); if (unsupportedOperators.Contains(op)) { // not supported Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } if (op == "<<") { methName = "Write"; } else if (op == ">>") { methName = "Read"; } // binary/unary operator if (binaryOperators.Contains(op) || unaryOperators.Contains(op)) { // instance operator if (smoke->classes[method->classId].size > 0) { if (op == "*" && method->numArgs == 0 || (op == "++" || op == "--") && method->numArgs == 1) { // dereference operator and postfix in-/decrement operator are not supported Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } try { CodeParameterDeclarationExpression exp = new CodeParameterDeclarationExpression(translator.CppToCSharp(className, out isRef), "arg" + count++); args.Add(exp); } catch (NotSupportedException) { Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } } else { // global operator if (op == "*" && method->numArgs == 0 || (op == "++" || op == "--") && method->numArgs == 2) { // dereference operator and postfix in-/decrement operator are not supported Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } } isOperator = true; } else if (op[0] == ' ') { // conversion operator explicitConversionType = op.Substring(1); if (explicitConversionType.Contains("QVariant")) { return(null); } try { explicitConversionType = translator.CppToCSharp(explicitConversionType, out isRef).GetStringRepresentation(); if (smoke->classes[method->classId].size > 0) { CodeParameterDeclarationExpression exp = new CodeParameterDeclarationExpression(translator.CppToCSharp(className, out isRef), "arg" + count++); args.Add(exp); } } catch (NotSupportedException) { Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } isOperator = true; } } // translate arguments string[] methodArgs = isOperator ? null : GetMethodArgs(smoke, method); for (short *typeIndex = smoke->argumentList + method->args; *typeIndex > 0; typeIndex++) { try { args.Add(this.GetArgument(smoke, typeIndex, methodArgs, args, ref count)); } catch (NotSupportedException) { Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } } this.RemovePreviousOverload(args, char.ToUpper(methName[0]) + methName.Substring(1)); // translate return type CodeTypeReference returnType; try { returnType = translator.CppToCSharp(smoke->types + method->ret, out isRef); } catch (NotSupportedException) { Debug.Print(" |--Won't wrap method {0}::{1}", className, cppSignature); return(null); } CodeMemberMethod cmm; if ((method->flags & (uint)Smoke.MethodFlags.mf_ctor) > 0) { cmm = new CodeConstructor(); cmm.Attributes = 0; // initialize to 0 so we can do |= ((CodeConstructor)cmm).ChainedConstructorArgs.Add(new CodeSnippetExpression("(System.Type) null")); } else { cmm = new CodeMemberMethod(); cmm.Attributes = 0; // initialize to 0 so we can do |= string csName = methName; if (!isOperator && methName != "finalize" && !qMethodExp.IsMatch(methName)) { // capitalize the first letter StringBuilder builder = new StringBuilder(csName); builder[0] = char.ToUpper(builder[0]); string tmp = builder.ToString(); // If the new name clashes with a name of a type declaration, keep the lower-case name. var typesWithSameName = from member in data.GetAccessibleMembers(smokeClass) where member.Type == MemberTypes.NestedType && member.Name == tmp select member; var propertiesWithSameName = (from member in data.GetAccessibleMembers(smokeClass) where member.Type == MemberTypes.Property && member.Name == tmp select member).ToList(); if (iface != null && propertiesWithSameName.Count() == 1 && (method->flags & (uint)Smoke.MethodFlags.mf_protected) == 0) { cmm.PrivateImplementationType = iface; csName = tmp; } else { if (propertiesWithSameName.Any()) { if ((method->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0) { Debug.Print( " |--Conflicting names: method/(type or property): {0} in class {1} - keeping original method name", tmp, className); } else { csName = tmp; } } else if (typesWithSameName.Any()) { Debug.Print(" |--Conflicting names: method/classname: {0} in class {1} - keeping original method name", tmp, className); } else { csName = tmp; } } } if (explicitConversionType != null) { cmm.Name = "explicit operator " + explicitConversionType; cmm.ReturnType = new CodeTypeReference(" "); } else { cmm.Name = csName; cmm.ReturnType = returnType; } } // for destructors we already have this stuff set if ((method->flags & (uint)Smoke.MethodFlags.mf_dtor) == 0) { // set access if ((method->flags & (uint)Smoke.MethodFlags.mf_protected) > 0) { cmm.Attributes |= MemberAttributes.Family; } else { cmm.Attributes |= MemberAttributes.Public; } if (isOperator) { cmm.Attributes |= MemberAttributes.Final | MemberAttributes.Static; } else if (cmm.Name == "ToString" && args.Count == 0 && cmm.ReturnType.BaseType == "System.String") { cmm.Attributes = MemberAttributes.Public | MemberAttributes.Override; } else { if ((method->flags & (uint)Smoke.MethodFlags.mf_static) > 0) { cmm.Attributes |= MemberAttributes.Static; } else { // virtual/final MemberAttributes access; bool foundInInterface; bool isOverride = MethodOverrides(smoke, method, out access, out foundInInterface); // methods that have to be implemented from interfaces can't override anything if (iface == null && (isOverride = MethodOverrides(smoke, method, out access, out foundInInterface))) { cmm.Attributes = access | MemberAttributes.Override; } else if (foundInInterface) { cmm.Attributes = access; } if ((method->flags & (uint)Smoke.MethodFlags.mf_purevirtual) > 0) { if (!m_internalImplementation) { cmm.Attributes = (cmm.Attributes & ~MemberAttributes.ScopeMask) | MemberAttributes.Abstract; // The code generator doesn't like MemberAttributes.Abstract | MemberAttributes.Override being set. if (isOverride && !type.IsInterface) { cmm.ReturnType.BaseType = "override " + cmm.ReturnType.BaseType == "System.Void" ? "void" : cmm.ReturnType.BaseType; } } else { cmm.Attributes |= MemberAttributes.Override; } } if ((method->flags & (uint)Smoke.MethodFlags.mf_virtual) == 0 && (method->flags & (uint)Smoke.MethodFlags.mf_purevirtual) == 0 && !isOverride) { cmm.Attributes |= MemberAttributes.Final | MemberAttributes.New; } } } } else { // hack, so we don't have to use CodeSnippetTypeMember to generator the destructor cmm.ReturnType = new CodeTypeReference(" "); } // add the parameters foreach (CodeParameterDeclarationExpression exp in args) { cmm.Parameters.Add(exp); } this.DistributeMethod(cmm); return(cmm); }