Beispiel #1
0
        public static GetterSetter GetPropertyInfo(CXXMethodDecl decl)
        {
            GetterSetter gs;

            if (allPropertyMethods.TryGetValue(decl, out gs))
            {
                return(gs);
            }
            return(null);
        }
Beispiel #2
0
 public static IEnumerable <string> GetMethodComments(CXXMethodDecl decl)
 {
     return(ExtractTextComments(decl.DumpToString()));
 }
Beispiel #3
0
        public override void VisitCXXMethodDecl(CXXMethodDecl decl, VisitKind visitKind)
        {
            if (visitKind != VisitKind.Enter)
            {
                return;
            }

            var isConstructor = decl is CXXConstructorDecl;

            if (decl is CXXDestructorDecl || isConstructor)
            {
                return;
            }

            if (decl.IsCopyAssignmentOperator || decl.IsMoveAssignmentOperator)
            {
                return;
            }

            if (decl.Parent == null)
            {
                return;
            }
            if (!decl.Parent.QualifiedName.StartsWith("Urho3D::"))
            {
                return;
            }

            // Only get methods prefixed with Get with no parameters
            // and Set methods that return void and take a single parameter
            var name = decl.Name;

            // Handle Get methods that are not really getters
            // This is a get method that does not get anything

            QualType type;

            if (name.StartsWith("Get") || name.StartsWith("Is"))
            {
                if (decl.Parameters.Count() != 0)
                {
                    return;
                }
                if (decl.ReturnQualType.ToString() == "void")
                {
                    return;
                }
                if (name == "IsElementEventSender" ||
                    name == "IsOpen" ||
                    name == "IsPressed")
                {
                    return;
                }

                type = decl.ReturnQualType;
            }
            else if (name.StartsWith("Set"))
            {
                if (decl.Parameters.Count() != 1)
                {
                    return;
                }
                if (!(decl.ReturnQualType.Bind() is Sharpie.Bind.Types.VoidType))
                {
                    return;
                }
                if ((name == "SetTypeName" || name == "SetType") && decl.Parent.Name == "UnknownComponent")
                {
                    return;
                }
                if (decl.Access != AccessSpecifier.Public)
                {
                    return;
                }
                type = decl.Parameters.FirstOrDefault().QualType;
            }
            else
            {
                return;
            }

            Dictionary <string, Dictionary <QualType, GetterSetter> > typeProperties;

            if (!allProperties.TryGetValue(decl.Parent.Name, out typeProperties))
            {
                typeProperties = new Dictionary <string, Dictionary <QualType, GetterSetter> >();
                allProperties[decl.Parent.Name] = typeProperties;
            }

            var propName = name.Substring(name.StartsWith("Is") ? 2 : 3);

            Dictionary <QualType, GetterSetter> property;

            if (!typeProperties.TryGetValue(propName, out property))
            {
                property = new Dictionary <QualType, GetterSetter>();
                typeProperties[propName] = property;
            }
            GetterSetter gs;

            if (!property.TryGetValue(type, out gs))
            {
                gs = new GetterSetter()
                {
                    Name = propName
                };
            }

            if (name.StartsWith("Get") || name.StartsWith("Is"))
            {
                Console.WriteLine($"Getter exists for {name}");
                if (propName != decl.Parent.Name || propName == "Text")
                {
                    // do not generate Getter if propertyName equals to typename (Text type already has a workaround for this case)
                    gs.Getter = decl;
                }
            }
            else
            {
                if (gs.Setter != null)
                {
                    Console.WriteLine($"Setter exists for {name}");
                }
                gs.Setter = decl;
            }
            property[type] = gs;
        }
Beispiel #4
0
		public override void VisitCXXMethodDecl(CXXMethodDecl decl, VisitKind visitKind)
		{
			if (!MethodIsBindable (decl, visitKind))
				return;

			var cmethodBuilder = new StringBuilder();

			AstType pinvokeReturn, methodReturn;
			WrapKind returnIsWrapped;
			ICSharpCode.NRefactory.CSharp.ParameterModifier pinvokeMod, methodMod;

			LookupMarshalTypes(decl.ReturnQualType, out pinvokeReturn, out pinvokeMod, out methodReturn, out methodMod, out returnIsWrapped, isReturn: true);
			var methodReturn2 = methodReturn.Clone();

			var propertyInfo = ScanBaseTypes.GetPropertyInfo(decl);
			if (propertyInfo != null) {
				propertyInfo.HostType = currentType;
				if (decl.Name.StartsWith("Get") || decl.Name.StartsWith("Is"))
					propertyInfo.MethodReturn = methodReturn.Clone();
			}

			var methodName = decl.Name;
			if (currentTypeNames.Contains(methodName))
				methodName += (uniqueMethodName++).ToString();
			currentTypeNames.Add(methodName);

			//
			// PInvoke declaration + C counterpart declaration
			//
			string pinvoke_name = currentType.Name + "_" + methodName;
			var isConstructor = decl is CXXConstructorDecl;

			if (isConstructor) {
				pinvokeReturn = new SimpleType ("IntPtr");

				// Do not bind a default constructor for Skeleton
				if (currentType.Name == "Skeleton")
					return;
			}

			var pinvoke = new MethodDeclaration
			{
				Name = pinvoke_name,
				ReturnType = pinvokeReturn,
				Modifiers = Modifiers.Extern | Modifiers.Static | Modifiers.Internal
			};
			if (!decl.IsStatic && !isConstructor)
				pinvoke.Parameters.Add(new ParameterDeclaration(new SimpleType("IntPtr"), "handle"));

			var dllImport = new Attribute { Type = new SimpleType("DllImport") };
			dllImport.Arguments.Add (new PrimitiveExpression ("mono-urho"));
			dllImport.Arguments.Add (new AssignmentExpression (new IdentifierExpression ("CallingConvention"), csParser.ParseExpression ("CallingConvention.Cdecl")));
			pinvoke.Attributes.Add(new AttributeSection(dllImport));

			// The C counterpart
			var cinvoke = new StringBuilder();
			string marshalReturn = "{0}";
			string creturnType = CleanTypeCplusplus(decl.ReturnQualType);

			switch (creturnType) {
			case "bool":
				creturnType = "int";
				break;
			case "Urho3D::StringHash":
				creturnType = "int";
				marshalReturn = "({0}).Value ()";
				break;
			case "Urho3D::String":
			case "const Urho3D::String &":
			case "const class Urho3D::String &":
				creturnType = "const char *";
				marshalReturn = "strdup(({0}).CString ())";
				break;
			case "const struct Urho3D::TileMapInfo2D &":
				creturnType = "Urho3D::TileMapInfo2D";
				break;
			case "const struct Urho3D::CrowdObstacleAvoidanceParams &":
				creturnType = "Urho3D::CrowdObstacleAvoidanceParams";
				break;
			case "const class Urho3D::Vector3 &":
			case "const class Urho3D::Vector2 &":
			case "const class Urho3D::Vector4 &":
			case "const class Urho3D::IntVector2 &":
			case "const class Urho3D::Quaternion &":
			case "const class Urho3D::Plane &":
			case "const class Urho3D::BoundingBox &": 
			case "const class Urho3D::Color &":
				
			case "Urho3D::Vector3":
			case "Urho3D::Vector2":
			case "Urho3D::Vector4":
			case "Urho3D::IntVector2":
			case "Urho3D::Quaternion":
			case "Urho3D::Plane":
			case "Urho3D::BoundingBox":
			case "Urho3D::Color":
				var nsIndex = creturnType.IndexOf ("Urho3D::") + "Urho3D".Length;
				creturnType = "Interop" + creturnType.Remove (0, nsIndex).Trim ('&', ' ') + " ";
				marshalReturn = "*((" + creturnType + " *) &({0}))";
				break;
			}

			if (creturnType.StartsWith("SharedPtr<"))
			{
				creturnType = creturnType.ExtractGenericParameter().DropClassOrStructPrefix() + " *";
				marshalReturn =
					"auto copy = {0};\n" +
					"\tauto plain = copy.Get();\n" +
					"\tcopy.Detach();\n" +
					"\tdelete copy;\n" +
					"\treturn plain;";
			}

			const string methodNameSuffix = "%MethodSuffix%";
			const string variantConverterMask = "%VariantConvertor%";

			if (isConstructor)
				cmethodBuilder.Append($"DllExport void *\n{pinvoke_name}{methodNameSuffix} (");
			else
				cmethodBuilder.Append($"DllExport {creturnType}\n{pinvoke_name}{methodNameSuffix} (");

			if (decl.IsStatic) {
				cinvoke.Append($"{decl.Parent.Name}::{decl.Name} (");

			} else if (isConstructor) {
				cinvoke.Append($"new {decl.Name}(");
			}

			else {
				cmethodBuilder.Append($"Urho3D::{decl.Parent.Name} *_target");
				if (decl.Parameters.Any())
					cmethodBuilder.Append(", ");
				cinvoke.Append($"_target->{decl.Name} (");
			}

			//
			// Method declaration
			//
			MethodDeclaration method = null;
			ConstructorDeclaration constructor = null;

			if (isConstructor) {
				constructor = new ConstructorDeclaration
				{
					Name = RemapMemberName(decl.Parent.Name, decl.Name),

					Modifiers = (decl.IsStatic ? Modifiers.Static : 0) |
						(propertyInfo != null ? Modifiers.Private : Modifiers.Public)  |
						(decl.Name == "ToString" ? Modifiers.Override : 0)
				};
				constructor.Body = new BlockStatement();
			} else {
				method = new MethodDeclaration
				{
					Name = RemapMemberName(decl.Parent.Name, decl.Name),
					ReturnType = methodReturn,
					Modifiers = (decl.IsStatic ? Modifiers.Static : 0) |
						(propertyInfo != null ? Modifiers.Private : Modifiers.Public)
				};
				method.Body = new BlockStatement();
			}

			// 
			// Marshal from C# to C and the C support to call into C++
			//
			var invoke = new InvocationExpression(new IdentifierExpression(pinvoke_name));
			if (!decl.IsStatic && !isConstructor)
				invoke.Arguments.Add(new IdentifierExpression("handle"));
			bool first = true;
			int anonymousParameterNameCount = 1;
			int currentParamCount = -1;
			foreach (var param in decl.Parameters) {
				currentParamCount++;
				AstType pinvokeParameter, parameter;
				WrapKind wrapKind;

				if (!first) {
					cinvoke.Append(", ");
					cmethodBuilder.Append(", ");
				} else
					first = false;

				LookupMarshalTypes(param.QualType, out pinvokeParameter, out pinvokeMod, out parameter, out methodMod, out wrapKind);

				string paramName = param.Name;
				if (string.IsNullOrEmpty(paramName))
					paramName = "param" + (anonymousParameterNameCount++);

				Expression parameterReference = new IdentifierExpression (paramName);
				switch (currentType.Name) {
				case "Input":
					switch (decl.Name) {
					case "GetMouseButtonDown":
					case "GetMouseButtonPress":
						parameter = new SimpleType ("MouseButton");
						parameterReference = new CastExpression (new PrimitiveType ("int"), parameterReference);
						break;
					case "GetKeyPress":
					case "GetKeyDown":
					case "GetScancodeFromKey":
					case "GetKeyName":
						if (currentParamCount == 0 && paramName == "key") {
							parameter = new SimpleType ("Key");
							parameterReference = new CastExpression (new PrimitiveType ("int"), parameterReference);
						}
						break;
					}
					break;
				case "VertexBuffer":
					switch (decl.Name) {
					case "SetSize":
						if (currentParamCount == 1 && paramName == "elementMask") {
							parameter = new SimpleType ("ElementMask");
							parameterReference = new CastExpression (new PrimitiveType ("uint"), parameterReference);
						}
						break;
					case "GetVertexSize":
						if (currentParamCount == 0 && paramName == "elementMask") {
							parameter = new SimpleType ("ElementMask");
							parameterReference = new CastExpression (new PrimitiveType ("uint"), parameterReference);
						}
						break;
					case "GetElementOffset":
						if (currentParamCount == 0 && paramName == "elementMask") {
							parameter = new SimpleType ("ElementMask");
							parameterReference = new CastExpression (new PrimitiveType ("uint"), parameterReference);
						}
						break;
					}
					break;
				case "Log":
					switch (decl.Name) {
					case "Write":
						if (currentParamCount == 0 && paramName == "level") {
							parameter = new SimpleType ("LogLevel");
							parameterReference = new CastExpression (new PrimitiveType ("int"), parameterReference);
						}
						break;
					}
					break;
				}

				if (constructor == null)
					method.Parameters.Add(new ParameterDeclaration(parameter, paramName, methodMod));
				else
					constructor.Parameters.Add(new ParameterDeclaration(parameter, paramName, methodMod));

				pinvoke.Parameters.Add(new ParameterDeclaration(pinvokeParameter, paramName, pinvokeMod));
				switch (wrapKind) {
				case WrapKind.None:
					invoke.Arguments.Add(parameterReference);
					break;
				case WrapKind.HandleMember:
				case WrapKind.UrhoObject:
					var cond = new ConditionalExpression (new BinaryOperatorExpression (new CastExpression (new PrimitiveType ("object"), parameterReference), BinaryOperatorType.Equality, new PrimitiveExpression (null)),
					csParser.ParseExpression ("IntPtr.Zero"), csParser.ParseExpression (paramName + ".Handle"));
					invoke.Arguments.Add (cond);
					break;
				case WrapKind.EventHandler:
					invoke.Arguments.Add(parameterReference);
					break;
				case WrapKind.StringHash:
					invoke.Arguments.Add (csParser.ParseExpression (paramName + ".Code"));
					break;
				case WrapKind.RefBlittable:
					invoke.Arguments.Add (new DirectionExpression (FieldDirection.Ref, parameterReference));
					break;
				case WrapKind.VectorSharedPtr:
					throw new NotImplementedException ("Vector marshaling not supported for parameters yet");
				}

				var ctype = CleanTypeCplusplus (param.QualType);
				string paramInvoke = paramName;
				switch (ctype) {
				case "bool":
					ctype = "int";
					break;
				case "Urho3D::Deserializer &":
				case "Urho3D::Serializer &":
					ctype = "File *";
					paramInvoke = $"*{paramInvoke}";
					break;
				case "const class Urho3D::String &":
					ctype = "const char *";
					paramInvoke = $"Urho3D::String({paramInvoke})";
					break;
				case "Urho3D::StringHash":
					ctype = "int";
					paramInvoke = $"Urho3D::StringHash({paramInvoke})";
					break;
				case "const class Urho3D::Variant &":
					paramInvoke = $"{variantConverterMask}({paramInvoke})";
					break;
				}

				cmethodBuilder.Append($"{ctype} {paramName}");
				cinvoke.Append($"{paramInvoke}");
			}
			cinvoke.Append(")");
			cmethodBuilder.Append(")\n{\n\t");

			// if the type has a ctor accepting Context - add a parameterless one that will use "this(Application.CurrentContext)"
			if (isConstructor &&
				decl.Parameters.Count() == 1 &&
				decl.Parameters.ElementAt(0).QualType.ToString() == "class Urho3D::Context *") {
				var ctor = new ConstructorDeclaration {
						Modifiers = Modifiers.Public,
						Body = new BlockStatement(),
						Initializer = new ConstructorInitializer { ConstructorInitializerType = ConstructorInitializerType.This }
					};
				ctor.Initializer.Arguments.Add(csParser.ParseExpression("Application.CurrentContext"));
				currentType.Members.Add(ctor);
			}

			if (method != null && methodReturn is Sharpie.Bind.Types.VoidType) {
				method.Body.Add(invoke);
				//	pn ($"fprintf (stderr,\"DEBUG {creturnType} {pinvoke_name} (...)\\n\");");
				cmethodBuilder.AppendLine($"{cinvoke.ToString()};");
			} else {
				ReturnStatement ret = null;
				Expression returnExpression;


				if (!isConstructor)
					ret = new ReturnStatement();

				switch (returnIsWrapped) {
				case WrapKind.HandleMember:
					returnExpression = new InvocationExpression (new MemberReferenceExpression (new IdentifierExpression ("Runtime"), "LookupRefCounted", methodReturn2), invoke);
					break;
				case WrapKind.UrhoObject:
					returnExpression = new InvocationExpression (new MemberReferenceExpression (new IdentifierExpression ("Runtime"), "LookupObject", methodReturn2), invoke);
					break;
				case WrapKind.EventHandler:
					returnExpression = invoke;
					break;
				case WrapKind.StringHash:
					returnExpression = new ObjectCreateExpression (new SimpleType ("StringHash"), invoke);
					break;
				case WrapKind.MarshalPtrToString:
					returnExpression = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression("Marshal"), "PtrToStringAnsi"), invoke);
					break;
				case WrapKind.MarshalPtrToStruct:
					returnExpression = new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression("Marshal"), "PtrToStructure"), invoke, new TypeOfExpression(methodReturn2));
					returnExpression = new CastExpression(methodReturn2.Clone(), returnExpression);
					break;
				case WrapKind.VectorSharedPtr:
					var cacheName = "_" + method.Name + "_cache";
					var f = new FieldDeclaration () {
						ReturnType = method.ReturnType.Clone (),
						Modifiers = Modifiers.Private | (method.Modifiers & Modifiers.Static)
					};
					f.Variables.Add (new VariableInitializer (cacheName, null));
					currentType.Members.Add (f);
					
					var sharedPtrType = (methodReturn as SimpleType).TypeArguments.First ().Clone ();
					//TODO: check if UrhoObject
					var create = (sharedPtrType.ToString() == "AnimationState") ? "CreateVectorSharedPtrRefcountedProxy" : "CreateVectorSharedPtrProxy";

					returnExpression = new ConditionalExpression (
						new BinaryOperatorExpression (new IdentifierExpression (cacheName), BinaryOperatorType.InEquality, new PrimitiveExpression (null)),
						new IdentifierExpression (cacheName),
						new AssignmentExpression (
							new IdentifierExpression (cacheName), 
							new InvocationExpression (
								new MemberReferenceExpression (
									new IdentifierExpression ("Runtime"), create, sharedPtrType),
								invoke)));
						
						
					break;
				default:
					returnExpression = invoke;
					break;
				}
				if (ret != null) {
					ret.Expression = returnExpression;
					method.Body.Add(ret);
				} else {
					if (currentType.ClassType == ClassType.Class){
						//usually, the Context is the first object user creates so let's add additional check if engine is inited
						if (currentType.Name == "Context") {
							constructor.Body.Add (new InvocationExpression (new IdentifierExpression ("CheckEngine"), null));
						}
						bool hasBaseTypes = currentType.BaseTypes.Count != 0;
						if (hasBaseTypes) {
							constructor.Initializer = new ConstructorInitializer {
								ConstructorInitializerType = ConstructorInitializerType.Base,
							};
							constructor.Initializer.Arguments.Add(csParser.ParseExpression("UrhoObjectFlag.Empty"));
						}
						var ctorAssign = new AssignmentExpression(new IdentifierExpression("handle"), returnExpression);
						constructor.Body.Add(new ExpressionStatement(ctorAssign));
						if (hasBaseTypes) { 
							constructor.Body.Add (new InvocationExpression (new MemberReferenceExpression (new IdentifierExpression ("Runtime"), "RegisterObject"), new ThisReferenceExpression ()));
						}
					}
				}
				var rstr = String.Format(marshalReturn, cinvoke.ToString());
				CXXRecordDecl returnType;

				//Wrap with WeakPtr all RefCounted subclasses constructors
				if (isConstructor) {
					if (ScanBaseTypes.nameToDecl.TryGetValue(decl.Parent.QualifiedName, out returnType) && returnType.IsDerivedFrom(ScanBaseTypes.UrhoRefCounted))
						rstr = $"WeakPtr<{decl.Name}>({rstr})";
				}

				cmethodBuilder.AppendLine(!rstr.Contains("\treturn ") ? $"return {rstr};" : rstr);
			}
			cmethodBuilder.AppendLine("}\n");

			var code = cmethodBuilder.ToString();

			const string variantArgDef = "const class Urho3D::Variant &";

			//if methods contains Variant argument -- replace it with overloads
			if (code.Contains(variantArgDef))
			{
				var variantSupportedTypes = new Dictionary<string, string>
					{
						//C++ - C# types map
						{"const class Urho3D::Vector3 &", "Vector3"},
						{"const class Urho3D::IntRect &", "IntRect"},
						{"const class Urho3D::Color &", "Color"},
						{"const class Urho3D::Vector2 &", "Vector2"},
						{"const class Urho3D::Vector4 &", "Vector4"},
						{"const class Urho3D::IntVector2 &", "IntVector2"},
						{"const class Urho3D::Quaternion &", "Quaternion"},
						{"int", "int"},
						{"float", "float"},
						{"const char *", "string"},
						//TODO: Matrix, StringHash?
					};
				var primitiveTypes = new[] { "int", "float", "string" };

				pn("// Urho3D::Variant overloads begin:");
				int index = 0;
				foreach (var item in variantSupportedTypes)
				{
					//C:
					p(code
						.Replace(variantArgDef, item.Key)
						.Replace(methodNameSuffix, index.ToString())
						.Replace(variantConverterMask, item.Key == "const char *" ? "Urho3D::String" : string.Empty));
					//methodNameSuffix to avoid error:
					//  error C2733: second C linkage of overloaded function 'function name' not allowed.

					//C#:
					var isPrimitive = primitiveTypes.Contains(item.Value);

					AstType argumentType;
					var argumentModifier = ICSharpCode.NRefactory.CSharp.ParameterModifier.None;
					if (!isPrimitive)
					{
						argumentType = new SimpleType(item.Value);
						argumentModifier = ICSharpCode.NRefactory.CSharp.ParameterModifier.Ref;
					}
					else
					{
						argumentType = new PrimitiveType(item.Value);
					}

					var dllImportItem = (MethodDeclaration)pinvoke.Clone();
					var originalEntryPointName = dllImportItem.Name;
					dllImportItem.Name += index;
					var variantParam = dllImportItem.Parameters.First(p => p.ToString().Contains(variantArgDef));
					variantParam.Type = argumentType.Clone();
					variantParam.ParameterModifier = argumentModifier;
					currentType.Members.Add(dllImportItem);

					var clonedMethod = (MethodDeclaration)method.Clone();
					variantParam = clonedMethod.Parameters.First(p => p.ToString().Contains(variantArgDef));
					variantParam.Type = argumentType.Clone();

					//add 'index' to all EntryPoint invocations inside the method (no mater how complex method body is):
					//and 'ref' keyword for the argument
					clonedMethod.Body.Descendants
						.OfType<InvocationExpression>()
						.Where(ie => ie.Target is IdentifierExpression && ((IdentifierExpression)ie.Target).Identifier == originalEntryPointName)
						.ToList()
						.ForEach(ie =>
							{
								if (!isPrimitive)
								{
									//non-primitive types should be marked with 'ref' keyword
									var argument = ie.Arguments.OfType<IdentifierExpression>().First(arg => arg.Identifier == variantParam.Name);
									ie.Arguments.Remove(argument);
									ie.Arguments.Add(new DirectionExpression(FieldDirection.Ref, argument));
								}

								var exp = (IdentifierExpression)ie.Target;
								exp.Identifier += index;
							});

					currentType.Members.Add(clonedMethod);
					InsertSummaryComments(clonedMethod, StringUtil.GetMethodComments(decl));

					index++;
				}
				pn("// Urho3D::Variant overloads end.");
			}
			//method does not have "Variant" arguments
			else
			{
				//C:
				pn(code
					.Replace(methodNameSuffix, string.Empty)
					.Replace(variantConverterMask, string.Empty));

				//C#:
				currentType.Members.Add(pinvoke);

				if (method == null)
					currentType.Members.Add(constructor);
				else
				{
					currentType.Members.Add(method);
					InsertSummaryComments(method, StringUtil.GetMethodComments(decl));
				}
			}

		}
Beispiel #5
0
		// 
		// Determines if we should bind a method that the C++ API scanner found
		//
		bool MethodIsBindable (CXXMethodDecl decl, VisitKind visitKind)
		{
			// We only care about enter visits, not leave
			if (visitKind != VisitKind.Enter)
				return false;

			// Global definitions, not inside a class, skip
			if (currentType == null) 
				return false;

			// Do not bother with constructors in abstract classes
			var isConstructor = decl is CXXConstructorDecl;
			if (isConstructor && decl.Parent.IsAbstract)
				return false;

			// Do not wrap constructors
			if (decl is CXXDestructorDecl)
				return false;

			// Not supported in C#
			if (decl.IsCopyAssignmentOperator || decl.IsMoveAssignmentOperator)
				return false;

			// TODO: temporary, do not handle opreators
			if (!isConstructor && decl.Name.StartsWith ("operator", StringComparison.Ordinal))
				return false;

			// Sanity check
			if (RemapTypeName (decl.Parent.Name) != currentType.Name) {
				//Console.WriteLine("For some reason we go t amethod that does not belong here {0}.{1} on {2}", decl.Parent.Name, decl.Name, currentType.Name);
				return false;
			}

			// We only bind the public API
			if (decl.Access != AccessSpecifier.Public)
				return false;

			// Skip blacklisted methods
			if (SkipMethod (decl))
				return false;

			// Temporary: while we add support for other things, just to debug things
			// remove types we do not support
			int variantArgumentsCount = 0;
			foreach (var p in decl.Parameters)
			{
				bool isVariantArgument = IsVariantType(p.QualType);
				if (isVariantArgument)
					variantArgumentsCount++;

				if (IsUnsupportedType(p.QualType, returnType: false) && !isVariantArgument)
				{
					//Console.WriteLine($"Bailing out on {p.QualType} from {decl.QualifiedName}");
					return false;
				}
			}

			if (variantArgumentsCount > 1)
				return false; //it won't be easy to handle if it has more than one Variant argument

			if (IsUnsupportedType(decl.ReturnQualType, returnType: true)) {//variant return type is not support yet
				//Console.WriteLine($"RETURN Bailing out on {decl.ReturnQualType} from {decl.QualifiedName}");
				return false;
			}
			return true;
		}
Beispiel #6
0
		// Avoid generating methods that conflict in their signatures after we turn Urho::String into string
		bool SkipMethod (CXXMethodDecl decl)
		{
			//DEBUG specific method
			/*if (currentType.Name == "WorkQueue" && decl.Name == "GetFreeItem")
				return false;
			return true;*/

			switch (currentType.Name) {
			case "Graphics":
				if (decl.Name == "GetShader")
					return decl.Parameters.Skip (1).First ().QualType.ToString () == "const char *";
				if (decl.Name == "SetShaderParameter") //strange method. it has overloads for all basic types and an overload with "Variant"... (it shouldn't have Variant or should have ONLY Variant)
					return decl.Parameters.Any (p => p.QualType.ToString ().Contains ("const class Urho3D::Variant &"));
				break;
			case "DebugHud":
				if (decl.Name == "SetAppStats") //it has overloads with String and Variant (that also can handle String)
					return decl.Parameters.Any (p => p.QualType.ToString ().Contains ("const class Urho3D::Variant &"));
				break;
			case "Node":
				if (decl.Name == "GetChild")
					return decl.Parameters.First ().QualType.ToString () == "const char *";
				break;
			case "Shader":
				if (decl.Name == "GetVariation")
					return decl.Parameters.Skip (1).First ().QualType.ToString () == "const char *";
				break;
			case "Scene":
				// The following look like internal methods that should not really be surfaced
				// to the user.   If we ever find that we have to surface, then we should rename them
				// in the other method, as they will conflict with the events.
				//
				// These names are bad choices, because they are called internally when something
				// has been done, and they complete the process.   For example "NodeRemoved" should
				// really be "RemoveNode", and "NodeAdded" should really be "AddNode", but that has
				// a different method and implementation on the Scene class (that is, there is
				// already a AddNode method, which is a high-level method)
				switch (decl.Name) {
				case "NodeAdded":
				case "NodeRemoved":
				case "ComponentAdded":
				case "ComponentRemoved":
					return true;
				}
				break;
			case "Application":
				switch (decl.Name) {
				case "Application":
					return decl.Parameters.First ().QualType.ToString ().Contains ("Urho3D::Context");
				case "Setup":
				case "Start":
				case "Stop":
					return true;
				}
				break;
			case "Skeleton":
				switch (decl.Name) {
				case "GetBone":
					
					if (decl.Parameters.First ().QualType.ToString ().Contains ("String &"))
						return true;
					return false;

				}
				
				break;
			}

			switch (decl.Name) {
				case "OnDragMove":
				case "OnDragEnd":
				case "OnDragDropTest":
				case "OnDragDropFinish":
				case "OnDragCancel":
				case "OnDragBegin":
					return true;
			}

			return false;
		}
Beispiel #7
0
		public static IEnumerable<string> GetMethodComments(CXXMethodDecl decl)
		{
			return ExtractTextComments(decl.DumpToString());
		}
Beispiel #8
0
		public override void VisitCXXMethodDecl(CXXMethodDecl decl, VisitKind visitKind)
		{
			if (visitKind != VisitKind.Enter)
				return;

			var isConstructor = decl is CXXConstructorDecl;
			if (decl is CXXDestructorDecl || isConstructor)
				return;

			if (decl.IsCopyAssignmentOperator || decl.IsMoveAssignmentOperator)
				return;

			if (decl.Parent == null)
				return;
			if (!decl.Parent.QualifiedName.StartsWith("Urho3D::"))
				return;

			// Only get methods prefixed with Get with no parameters
			// and Set methods that return void and take a single parameter
			var name = decl.Name;

			// Handle Get methods that are not really getters
			// This is a get method that does not get anything

			QualType type;
			if (name.StartsWith("Get") || name.StartsWith("Is")) {
				if (decl.Parameters.Count() != 0)
					return;
				if (decl.ReturnQualType.ToString() == "void")
					return;
				if (name == "IsElementEventSender" ||
					name == "IsOpen" ||
					name == "IsPressed")
					return;

				type = decl.ReturnQualType;
			} else if (name.StartsWith("Set")) {
				if (decl.Parameters.Count() != 1)
					return;
				if (!(decl.ReturnQualType.Bind() is Sharpie.Bind.Types.VoidType))
					return;
				if ((name == "SetTypeName" || name == "SetType") && decl.Parent.Name == "UnknownComponent")
					return;
				if (decl.Access != AccessSpecifier.Public)
					return;
				type = decl.Parameters.FirstOrDefault().QualType;
			} else
				return;

			Dictionary<string, Dictionary<QualType, GetterSetter>> typeProperties;
			if (!allProperties.TryGetValue(decl.Parent.Name, out typeProperties)) {
				typeProperties = new Dictionary<string, Dictionary<QualType, GetterSetter>>();
				allProperties[decl.Parent.Name] = typeProperties;
			}

			var propName = name.Substring(name.StartsWith("Is") ? 2 : 3);

			Dictionary<QualType, GetterSetter> property;

			if (!typeProperties.TryGetValue(propName, out property)) {
				property = new Dictionary<QualType, GetterSetter>();
				typeProperties[propName] = property;
			}
			GetterSetter gs;
			if (!property.TryGetValue(type, out gs)) {
				gs = new GetterSetter() { Name = propName };
			}

			if (name.StartsWith("Get") || name.StartsWith("Is")) {
				Console.WriteLine($"Getter exists for {name}");
				gs.Getter = decl;
			} else {
				if (gs.Setter != null) {
					Console.WriteLine($"Setter exists for {name}");
				}
				gs.Setter = decl;
			}
			property[type] = gs;
		}
Beispiel #9
0
		public static GetterSetter GetPropertyInfo(CXXMethodDecl decl)
		{
			GetterSetter gs;
			if (allPropertyMethods.TryGetValue(decl, out gs))
				return gs;
			return null;
		}