mirror of https://github.com/mono/CppSharp.git
				
				
			
				 3 changed files with 1 additions and 243 deletions
			
			
		@ -1,227 +0,0 @@
				@@ -1,227 +0,0 @@
					 | 
				
			||||
using System; | 
				
			||||
using System.Collections.Generic; | 
				
			||||
using System.Linq; | 
				
			||||
using CppSharp.AST; | 
				
			||||
using CppSharp.Generators; | 
				
			||||
using CppSharp.Generators.CLI; | 
				
			||||
using CppSharp.Passes; | 
				
			||||
 | 
				
			||||
namespace CppSharp | 
				
			||||
{ | 
				
			||||
    // This pass adds Equals and GetHashCode methods to classes.
 | 
				
			||||
    // It will also add a ToString method if the insertion operator (<<)
 | 
				
			||||
    // of the class is overloaded.
 | 
				
			||||
    // Note that the OperatorToClassPass needs to run first in order for
 | 
				
			||||
    // this to work.
 | 
				
			||||
    public class ObjectOverridesPass : TranslationUnitPass | 
				
			||||
    { | 
				
			||||
        private Generator Generator { get; set; } | 
				
			||||
 | 
				
			||||
        public ObjectOverridesPass(Generator generator) | 
				
			||||
        { | 
				
			||||
            Generator = generator; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        private bool needsStreamInclude; | 
				
			||||
        private void OnUnitGenerated(GeneratorOutput output) | 
				
			||||
        { | 
				
			||||
            needsStreamInclude = false; | 
				
			||||
            foreach (var template in output.Outputs) | 
				
			||||
            { | 
				
			||||
                foreach (var block in template.FindBlocks(BlockKind.MethodBody)) | 
				
			||||
                { | 
				
			||||
                    var method = block.Object as Method; | 
				
			||||
                    VisitMethod(method, block); | 
				
			||||
                } | 
				
			||||
                if (needsStreamInclude) | 
				
			||||
                { | 
				
			||||
                    var sourcesTemplate = template as CLISources; | 
				
			||||
                    if (sourcesTemplate != null) | 
				
			||||
                    { | 
				
			||||
                        foreach (var block in sourcesTemplate.FindBlocks(BlockKind.Includes)) | 
				
			||||
                        { | 
				
			||||
                            block.WriteLine("#include <sstream>"); | 
				
			||||
                            block.WriteLine(""); | 
				
			||||
                            break; | 
				
			||||
                        } | 
				
			||||
                        break; | 
				
			||||
                    } | 
				
			||||
                } | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        private void VisitMethod(Method method, Block block) | 
				
			||||
        { | 
				
			||||
            if (!method.IsSynthetized) | 
				
			||||
                return; | 
				
			||||
 | 
				
			||||
            var @class = (Class)method.Namespace; | 
				
			||||
 | 
				
			||||
            if (method.Name == "GetHashCode" && method.Parameters.Count == 0) | 
				
			||||
                GenerateGetHashCode(block); | 
				
			||||
 | 
				
			||||
            if (method.Name == "Equals" && method.Parameters.Count == 1) | 
				
			||||
                GenerateEquals(@class, block, method); | 
				
			||||
 | 
				
			||||
            if (method.Name == "ToString" && method.Parameters.Count == 0) | 
				
			||||
                GenerateToString(block); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        void GenerateGetHashCode(Block block) | 
				
			||||
        { | 
				
			||||
            block.Write("return (int)NativePtr;"); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        void GenerateEquals(Class @class, Block block, Method method) | 
				
			||||
        { | 
				
			||||
            var cliTypePrinter = new CLITypePrinter(Context); | 
				
			||||
            var classCliType = @class.Visit(cliTypePrinter); | 
				
			||||
 | 
				
			||||
            block.WriteLine("if (!object) return false;"); | 
				
			||||
            block.WriteLine("auto obj = dynamic_cast<{0}>({1});", | 
				
			||||
                classCliType, method.Parameters[0].Name); | 
				
			||||
            block.NewLine(); | 
				
			||||
 | 
				
			||||
            block.WriteLine("if (!obj) return false;"); | 
				
			||||
            block.Write("return __Instance == obj->__Instance;"); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        void GenerateToString(Block block) | 
				
			||||
        { | 
				
			||||
            needsStreamInclude = true; | 
				
			||||
            block.WriteLine("std::ostringstream os;"); | 
				
			||||
            block.WriteLine("os << *NativePtr;"); | 
				
			||||
            block.Write("return clix::marshalString<clix::E_UTF8>(os.str());"); | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        private bool isHooked; | 
				
			||||
        public override bool VisitClassDecl(Class @class) | 
				
			||||
        { | 
				
			||||
            // FIXME: Add a better way to hook the event
 | 
				
			||||
            if (!isHooked) | 
				
			||||
            { | 
				
			||||
                Generator.OnUnitGenerated += OnUnitGenerated; | 
				
			||||
                isHooked = true; | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            if (!VisitDeclaration(@class)) | 
				
			||||
                return false; | 
				
			||||
 | 
				
			||||
            // We can't handle value types yet
 | 
				
			||||
            // The generated code assumes that a NativePtr is available
 | 
				
			||||
            if (@class.IsValueType) | 
				
			||||
                return false; | 
				
			||||
 | 
				
			||||
            foreach (var method in @class.Methods) | 
				
			||||
            { | 
				
			||||
                if (!IsInsertionOperator(method)) | 
				
			||||
                    continue; | 
				
			||||
 | 
				
			||||
                // Create the ToString method
 | 
				
			||||
                var stringType = GetType("std::string"); | 
				
			||||
                if (stringType == null) | 
				
			||||
                    stringType = new CILType(typeof(string)); | 
				
			||||
                var toStringMethod = new Method() | 
				
			||||
                { | 
				
			||||
                    Name = "ToString", | 
				
			||||
                    Namespace = @class, | 
				
			||||
                    ReturnType = new QualifiedType(stringType), | 
				
			||||
                    SynthKind = FunctionSynthKind.ComplementOperator, | 
				
			||||
                    IsProxy = true | 
				
			||||
                }; | 
				
			||||
                toStringMethod.OverriddenMethods.Add(new Method { Name = "ToString" }); | 
				
			||||
                @class.Methods.Add(toStringMethod); | 
				
			||||
 | 
				
			||||
                Diagnostics.Debug("Function converted to ToString: {0}::{1}", | 
				
			||||
                    @class.Name, method.Name); | 
				
			||||
 | 
				
			||||
                break; | 
				
			||||
            } | 
				
			||||
 | 
				
			||||
            var methodEqualsParam = new Parameter | 
				
			||||
            { | 
				
			||||
                Name = "object", | 
				
			||||
                QualifiedType = new QualifiedType(new CILType(typeof(Object))) | 
				
			||||
            }; | 
				
			||||
 | 
				
			||||
            var methodEquals = new Method | 
				
			||||
            { | 
				
			||||
                Name = "Equals", | 
				
			||||
                Namespace = @class, | 
				
			||||
                ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Bool)), | 
				
			||||
                SynthKind = FunctionSynthKind.ComplementOperator, | 
				
			||||
                IsProxy = true | 
				
			||||
            }; | 
				
			||||
 | 
				
			||||
            methodEqualsParam.Namespace = methodEquals; | 
				
			||||
            methodEquals.Parameters.Add(methodEqualsParam); | 
				
			||||
 | 
				
			||||
            methodEquals.OverriddenMethods.Add(new Method { Name = "Equals" }); | 
				
			||||
            @class.Methods.Add(methodEquals); | 
				
			||||
 | 
				
			||||
            var methodHashCode = new Method | 
				
			||||
            { | 
				
			||||
                Name = "GetHashCode", | 
				
			||||
                Namespace = @class, | 
				
			||||
                ReturnType = new QualifiedType(new BuiltinType(PrimitiveType.Int)), | 
				
			||||
                SynthKind = FunctionSynthKind.ComplementOperator, | 
				
			||||
                IsProxy = true | 
				
			||||
            }; | 
				
			||||
            methodHashCode.OverriddenMethods.Add(new Method { Name = "GetHashCode" }); | 
				
			||||
 | 
				
			||||
            @class.Methods.Add(methodHashCode); | 
				
			||||
            return true; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        private Dictionary<string, AST.Type> typeCache; | 
				
			||||
        protected AST.Type GetType(string typeName) | 
				
			||||
        { | 
				
			||||
            if (typeCache == null) | 
				
			||||
                typeCache = new Dictionary<string, AST.Type>(); | 
				
			||||
            AST.Type result; | 
				
			||||
            if (!typeCache.TryGetValue(typeName, out result)) | 
				
			||||
            { | 
				
			||||
                var typeDef = ASTContext.FindTypedef(typeName) | 
				
			||||
                    .FirstOrDefault(); | 
				
			||||
                if (typeDef != null) | 
				
			||||
                    result = new TypedefType() { Declaration = typeDef }; | 
				
			||||
                typeCache.Add(typeName, result); | 
				
			||||
            } | 
				
			||||
            return result; | 
				
			||||
        } | 
				
			||||
 | 
				
			||||
        private bool IsInsertionOperator(Method method) | 
				
			||||
        { | 
				
			||||
            // Do some basic check
 | 
				
			||||
            if (!method.IsOperator) | 
				
			||||
                return false; | 
				
			||||
            if (method.OperatorKind != CXXOperatorKind.LessLess) | 
				
			||||
                return false; | 
				
			||||
            if (method.Parameters.Count != 2) | 
				
			||||
                return false; | 
				
			||||
 | 
				
			||||
            // Check that first parameter is a std::ostream&
 | 
				
			||||
            var fstType = method.Parameters[0].Type as PointerType; | 
				
			||||
            if (fstType == null) | 
				
			||||
                return false; | 
				
			||||
            var oStreamType = GetType("std::ostream"); | 
				
			||||
            if (oStreamType == null) | 
				
			||||
                return false; | 
				
			||||
            if (!oStreamType.Equals(fstType.Pointee)) | 
				
			||||
                return false; | 
				
			||||
 | 
				
			||||
            // Check that second parameter is a const CLASS&
 | 
				
			||||
            var sndType = method.Parameters[1].Type as PointerType; | 
				
			||||
            if (sndType == null) | 
				
			||||
                return false; | 
				
			||||
            if (!sndType.QualifiedPointee.Qualifiers.IsConst) | 
				
			||||
                return false; | 
				
			||||
            var @class = method.Namespace as Class; | 
				
			||||
            var classType = new TagType(@class); | 
				
			||||
            if (!classType.Equals(sndType.Pointee)) | 
				
			||||
                return false; | 
				
			||||
 | 
				
			||||
            return true; | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue