Exemplo n.º 1
0
    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);
    }
Exemplo n.º 2
0
    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);
        }
    }
Exemplo n.º 3
0
    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;
        }
    }
Exemplo n.º 4
0
    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);
        }
    }
Exemplo n.º 5
0
    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;
                    }
                }
            }
        }
    }
Exemplo n.º 6
0
    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);
        }
    }
Exemplo n.º 7
0
    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);
    }
Exemplo n.º 8
0
    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));
        }
    }
Exemplo n.º 9
0
    /*
     * 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);
    }
Exemplo n.º 10
0
    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"));
    }
Exemplo n.º 11
0
    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());
    }
Exemplo n.º 12
0
    /*
     * 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);
    }
Exemplo n.º 13
0
    /*
     * 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);
    }
Exemplo n.º 14
0
    /*
     * 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();
    }
Exemplo n.º 15
0
 public static unsafe bool IsQObject(Smoke.Class *klass)
 {
     return(IsDerivedFrom(ByteArrayManager.GetString(klass->className), "QObject"));
 }
Exemplo n.º 16
0
    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);
            }
        }
    }
Exemplo n.º 17
0
    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));
    }
Exemplo n.º 18
0
    public CodeTypeReference CppToCSharp(Smoke.Class *klass)
    {
        bool isRef;

        return(this.CppToCSharp(ByteArrayManager.GetString(klass->className), out isRef));
    }
Exemplo n.º 19
0
    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);
            }
        }
    }
Exemplo n.º 20
0
    /*
     * 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();
    }
Exemplo n.º 21
0
 public override string ToString()
 {
     return(ByteArrayManager.GetString(module_name));
 }
Exemplo n.º 22
0
    // 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);
            }
        }
    }
Exemplo n.º 23
0
    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);
            }
        }
    }
Exemplo n.º 24
0
    /*
     * 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;
    }
Exemplo n.º 25
0
    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);
    }