using System.Linq; using CppSharp.AST; using CppSharp.AST.Extensions; using CppSharp.Generators; namespace CppSharp.Passes { /// /// This pass will try to hoist functions into classes so they /// work just like instance methods. /// public class FunctionToInstanceMethodPass : TranslationUnitPass { public override bool VisitMethodDecl(Method method) { return true; } public override bool VisitFunctionDecl(Function function) { if (!function.IsGenerated) return false; // Check if this function can be converted. if (function.Parameters.Count == 0) return false; var classParam = function.Parameters[0]; Class @class; if (!GetClassParameter(classParam, out @class)) return false; // If we reach here, it means the first parameter is of class type. // This means we can change the function to be an instance method. // Clean up the name of the function now that it will be an instance method. if (!function.Name.StartsWith(@class.Name, System.StringComparison.Ordinal)) return false; function.Name = function.Name.Substring(@class.Name.Length); function.ExplicitlyIgnore(); // Create a new fake method so it acts as an instance method. var method = new Method { Namespace = @class, OriginalNamespace = function.Namespace, Name = function.Name, OriginalName = function.OriginalName, Mangled = function.Mangled, Access = AccessSpecifier.Public, Kind = CXXMethodKind.Normal, ReturnType = function.ReturnType, CallingConvention = function.CallingConvention, IsVariadic = function.IsVariadic, IsInline = function.IsInline, Conversion = MethodConversionKind.FunctionToInstanceMethod, FunctionType = function.FunctionType }; method.Parameters.AddRange(function.Parameters.Select( p => new Parameter(p) { Namespace = method })); if (Options.GeneratorKind == GeneratorKind.CSharp) method.Parameters.RemoveAt(0); @class.Methods.Add(method); Diagnostics.Debug("Function converted to instance method: {0}::{1}", @class.Name, function.Name); return true; } public static bool GetClassParameter(Parameter classParam, out Class @class) { TagType tag; if (classParam.Type.IsPointerTo(out tag)) { @class = tag.Declaration as Class; return true; } return classParam.Type.TryGetClass(out @class); } } }