diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index a9c9fa67..94f85ecc 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -38,10 +38,24 @@ namespace CppSharp.AST /// public abstract class Declaration : INamedDecl { + + private DeclarationContext @namespace; + public DeclarationContext OriginalNamespace; + // Namespace the declaration is contained in. - public DeclarationContext Namespace; + public DeclarationContext Namespace + { + get { return @namespace; } + set + { + @namespace = value; + if (OriginalNamespace == null) + OriginalNamespace = @namespace; + } + } private string name; + public virtual string OriginalName { get; set;} // Name of the declaration. public virtual string Name @@ -66,17 +80,14 @@ namespace CppSharp.AST } } - // Name of the declaration. - public virtual string OriginalName { get; set;} - public string QualifiedOriginalName { get { - if (Namespace == null) + if (OriginalNamespace == null) return OriginalName; - return Namespace.IsRoot ? OriginalName - : string.Format("{0}::{1}", Namespace.QualifiedOriginalName, OriginalName); + return OriginalNamespace.IsRoot ? OriginalName + : string.Format("{0}::{1}", OriginalNamespace.QualifiedOriginalName, OriginalName); } } diff --git a/src/AST/Property.cs b/src/AST/Property.cs index 8367cc07..1b8b93a2 100644 --- a/src/AST/Property.cs +++ b/src/AST/Property.cs @@ -5,11 +5,6 @@ namespace CppSharp.AST /// public class Property : Declaration, ITypedDecl { - public Property() - { - - } - public Type Type { get { return QualifiedType.Type; } @@ -17,17 +12,12 @@ namespace CppSharp.AST public QualifiedType QualifiedType { get; set; } - public Method GetMethod - { - get; - set; - } + public Method GetMethod { get; set; } - public Method SetMethod - { - get; - set; - } + public Method SetMethod { get; set; } + + // The field that should be get and set by this property + public Field Field { get; set; } public override T Visit(IDeclVisitor visitor) { diff --git a/src/AST/Type.cs b/src/AST/Type.cs index 18b5b2f9..bcf2b258 100644 --- a/src/AST/Type.cs +++ b/src/AST/Type.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; namespace CppSharp.AST { @@ -162,6 +163,14 @@ namespace CppSharp.AST { return Type.ToString(); } + + public override bool Equals(object obj) + { + if (!(obj is QualifiedType)) return false; + + var type = (QualifiedType) obj; + return Type.Equals(type.Type) && Qualifiers.Equals(type.Qualifiers); + } } /// @@ -184,6 +193,14 @@ namespace CppSharp.AST { return visitor.VisitTagType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as TagType; + if (type == null) return false; + + return Declaration.Equals(type.Declaration); + } } /// @@ -216,6 +233,18 @@ namespace CppSharp.AST { return visitor.VisitArrayType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as ArrayType; + if (type == null) return false; + var equals = Type.Equals(type.Type) && SizeType.Equals(type.SizeType); + + if (SizeType == ArraySize.Constant) + equals &= Size.Equals(type.Size); + + return equals; + } } /// @@ -238,6 +267,14 @@ namespace CppSharp.AST { return visitor.VisitFunctionType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as FunctionType; + if (type == null) return false; + + return ReturnType.Equals(type.ReturnType) && Parameters.SequenceEqual(type.Parameters); + } } /// @@ -281,6 +318,15 @@ namespace CppSharp.AST { return visitor.VisitPointerType(this, QualifiedPointee.Qualifiers); } + + public override bool Equals(object obj) + { + var type = obj as PointerType; + if (type == null) return false; + + return QualifiedPointee.Equals(type.QualifiedPointee) + && Modifier == type.Modifier; + } } /// @@ -299,6 +345,14 @@ namespace CppSharp.AST { return visitor.VisitMemberPointerType(this, quals); } + + public override bool Equals(object obj) + { + var pointer = obj as MemberPointerType; + if (pointer == null) return false; + + return Pointee.Equals(pointer.Pointee); + } } /// @@ -317,6 +371,15 @@ namespace CppSharp.AST { return visitor.VisitTypedefType(this, quals); } + + public override bool Equals(object obj) + { + var typedef = obj as TypedefType; + if (typedef == null) return false; + + var t = Declaration.Equals(typedef.Declaration); + return t; + } } /// @@ -337,6 +400,14 @@ namespace CppSharp.AST { return visitor.VisitDecayedType(this, quals); } + + public override bool Equals(object obj) + { + var decay = obj as DecayedType; + if (decay == null) return false; + + return Original.Equals(decay.Original); + } } /// @@ -382,6 +453,28 @@ namespace CppSharp.AST public QualifiedType Type; public Declaration Declaration; public long Integral; + + public override bool Equals(object obj) + { + if (!(obj is TemplateArgument)) return false; + var arg = (TemplateArgument) obj; + + if (Kind != arg.Kind) return false; + + switch (Kind) + { + case ArgumentKind.Type: + return Type.Equals(arg.Type); + case ArgumentKind.Declaration: + return Declaration.Equals(arg.Declaration); + case ArgumentKind.Integral: + return Integral.Equals(arg.Integral); + case ArgumentKind.Expression: + return true; + default: + throw new Exception("Unknowed TemplateArgument Kind"); + } + } } /// @@ -405,6 +498,15 @@ namespace CppSharp.AST { return visitor.VisitTemplateSpecializationType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as TemplateSpecializationType; + if (type == null) return false; + + return Arguments.SequenceEqual(type.Arguments) + && Template.Equals(type.Template); + } } /// @@ -412,18 +514,21 @@ namespace CppSharp.AST /// public class TemplateParameterType : Type { - public TemplateParameterType() - { - } - public TemplateParameter Parameter; - public Template Template; public override T Visit(ITypeVisitor visitor, TypeQualifiers quals = new TypeQualifiers()) { return visitor.VisitTemplateParameterType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as TemplateParameterType; + if (type == null) return false; + + return Parameter.Equals(type.Parameter); + } } /// @@ -431,11 +536,6 @@ namespace CppSharp.AST /// public class TemplateParameterSubstitutionType : Type { - public TemplateParameterSubstitutionType() - { - - } - public QualifiedType Replacement; public override T Visit(ITypeVisitor visitor, @@ -443,6 +543,14 @@ namespace CppSharp.AST { return visitor.VisitTemplateParameterSubstitutionType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as TemplateParameterSubstitutionType; + if (type == null) return false; + + return Replacement.Equals(type.Replacement); + } } /// @@ -451,11 +559,6 @@ namespace CppSharp.AST /// public class InjectedClassNameType : Type { - public InjectedClassNameType() - { - - } - public TemplateSpecializationType TemplateSpecialization; public Class Class; @@ -464,6 +567,15 @@ namespace CppSharp.AST { return visitor.VisitInjectedClassNameType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as InjectedClassNameType; + if (type == null) return false; + + return TemplateSpecialization.Equals(type.TemplateSpecialization) + && Class.Equals(type.Class); + } } /// @@ -471,11 +583,6 @@ namespace CppSharp.AST /// public class DependentNameType : Type { - public DependentNameType() - { - - } - public override T Visit(ITypeVisitor visitor, TypeQualifiers quals = new TypeQualifiers()) { @@ -500,6 +607,14 @@ namespace CppSharp.AST { return visitor.VisitCILType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as CILType; + if (type == null) return false; + + return Type == type.Type; + } } #region Primitives @@ -567,6 +682,14 @@ namespace CppSharp.AST { return visitor.VisitBuiltinType(this, quals); } + + public override bool Equals(object obj) + { + var type = obj as BuiltinType; + if (type == null) return false; + + return Type == type.Type; + } } #endregion diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index 2f8c2b48..ed454281 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -3,23 +3,24 @@ namespace CppSharp.AST { public static class ASTUtils { - public static bool CheckIgnoreFunction(Class @class, Function function) + public static bool CheckIgnoreFunction(Function function) { if (function.Ignore) return true; if (function is Method) - return CheckIgnoreMethod(@class, function as Method); + return CheckIgnoreMethod(function as Method); return false; } - public static bool CheckIgnoreMethod(Class @class, Method method) + public static bool CheckIgnoreMethod(Method method) { if (method.Ignore) return true; var isEmptyCtor = method.IsConstructor && method.Parameters.Count == 0; - if (@class.IsValueType && isEmptyCtor) + var @class = method.Namespace as Class; + if (@class != null && @class.IsValueType && isEmptyCtor) return true; if (method.IsCopyConstructor || method.IsMoveConstructor) @@ -40,14 +41,12 @@ namespace CppSharp.AST return false; } - public static bool CheckIgnoreField(Class @class, Field field) + public static bool CheckIgnoreField(Field field) { - if (field.Ignore) return true; - - if (field.Access != AccessSpecifier.Public) + if (field.Access != AccessSpecifier.Public) return true; - return false; + return field.Ignore; } } } diff --git a/src/Generator/Diagnostics.cs b/src/Generator/Diagnostics.cs index b3719440..84452491 100644 --- a/src/Generator/Diagnostics.cs +++ b/src/Generator/Diagnostics.cs @@ -72,6 +72,42 @@ namespace CppSharp consumer.Emit(diagInfo); } + + public static void EmitMessage(this IDiagnosticConsumer consumer, + string msg, params object[] args) + { + var diagInfo = new DiagnosticInfo + { + Kind = DiagnosticKind.Message, + Message = string.Format(msg, args) + }; + + consumer.Emit(diagInfo); + } + + public static void EmitWarning(this IDiagnosticConsumer consumer, + string msg, params object[] args) + { + var diagInfo = new DiagnosticInfo + { + Kind = DiagnosticKind.Warning, + Message = string.Format(msg, args) + }; + + consumer.Emit(diagInfo); + } + + public static void EmitError(this IDiagnosticConsumer consumer, + string msg, params object[] args) + { + var diagInfo = new DiagnosticInfo + { + Kind = DiagnosticKind.Error, + Message = string.Format(msg, args) + }; + + consumer.Emit(diagInfo); + } } public class TextDiagnosticPrinter : IDiagnosticConsumer diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index c0cf56b3..b1bcbe84 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -125,6 +125,7 @@ namespace CppSharp Passes.CleanUnit(Options); Passes.SortDeclarations(); Passes.ResolveIncompleteDecls(); + Passes.CheckIgnoredDecls(); } public void AddPostPasses() @@ -132,7 +133,7 @@ namespace CppSharp Passes.CleanInvalidDeclNames(); Passes.CheckIgnoredDecls(); Passes.CheckFlagEnums(); - Passes.CheckAmbiguousOverloads(); + Passes.CheckDuplicateNames(); Generator.SetupPasses(Passes); } diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 49bf6f25..4d21dac1 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -213,9 +213,7 @@ namespace CppSharp.Generators.CLI GenerateClassFields(@class); - // Generate a property for each field if class is not value type - if (@class.IsRefType) - GenerateClassProperties(@class); + GenerateClassProperties(@class); GenerateClassEvents(@class); GenerateClassMethods(@class); @@ -250,8 +248,8 @@ namespace CppSharp.Generators.CLI PushIndent(); WriteLine("property System::IntPtr Instance"); WriteStartBraceIndent(); - WriteLine("virtual System::IntPtr get() override;"); - WriteLine("virtual void set(System::IntPtr instance) override;"); + WriteLine("virtual System::IntPtr get();"); + WriteLine("virtual void set(System::IntPtr instance);"); WriteCloseBraceIndent(); NewLine(); @@ -273,9 +271,6 @@ namespace CppSharp.Generators.CLI var function = functionTemplate.TemplatedFunction; - var typeNames = template.Parameters.Select( - param => "typename " + param.Name).ToList(); - var typeCtx = new CLITypePrinterContext() { Kind = TypePrinterContextKind.Template, @@ -288,7 +283,12 @@ namespace CppSharp.Generators.CLI var retType = function.ReturnType.Type.Visit(typePrinter, function.ReturnType.Qualifiers); - WriteLine("generic<{0}>", string.Join(", ", typeNames)); + var typeNamesStr = ""; + var paramNames = template.Parameters.Select(param => param.Name).ToList(); + if (paramNames.Any()) + typeNamesStr = "typename " + string.Join(", typename ", paramNames); + + WriteLine("generic<{0}>", typeNamesStr); WriteLine("{0} {1}({2});", retType, SafeIdentifier(function.Name), GenerateParametersList(function.Parameters)); } @@ -346,7 +346,7 @@ namespace CppSharp.Generators.CLI PushIndent(); foreach (var field in @class.Fields) { - if (ASTUtils.CheckIgnoreField(@class, field)) continue; + if (ASTUtils.CheckIgnoreField(field)) continue; GenerateDeclarationCommon(field); if (@class.IsUnion) @@ -401,7 +401,7 @@ namespace CppSharp.Generators.CLI var staticMethods = new List(); foreach (var method in @class.Methods) { - if (ASTUtils.CheckIgnoreMethod(@class, method)) + if (ASTUtils.CheckIgnoreMethod(method)) continue; if (method.IsConstructor) @@ -477,39 +477,33 @@ namespace CppSharp.Generators.CLI public void GenerateClassProperties(Class @class) { - PushIndent(); - foreach (var field in @class.Fields) - { - if (ASTUtils.CheckIgnoreField(@class, field)) - continue; - - GenerateDeclarationCommon(field); - GenerateProperty(field); - } - PopIndent(); - PushIndent(); foreach (var prop in @class.Properties) { if (prop.Ignore) continue; GenerateDeclarationCommon(prop); - GenerateProperty(prop); + var isGetter = prop.GetMethod != null || prop.Field != null; + var isSetter = prop.SetMethod != null || prop.Field != null; + GenerateProperty(prop, isGetter, isSetter); } PopIndent(); } - public void GenerateProperty(T decl) + public void GenerateProperty(T decl, bool isGetter = true, bool isSetter = true) where T : Declaration, ITypedDecl { + if (!(isGetter || isSetter)) + return; + PushBlock(CLIBlockKind.Property, decl); var type = decl.Type.Visit(TypePrinter, decl.QualifiedType.Qualifiers); WriteLine("property {0} {1}", type, decl.Name); WriteStartBraceIndent(); - WriteLine("{0} get();", type); - WriteLine("void set({0});", type); + if(isGetter) WriteLine("{0} get();", type); + if(isSetter) WriteLine("void set({0});", type); WriteCloseBraceIndent(); PopBlock(); @@ -517,10 +511,7 @@ namespace CppSharp.Generators.CLI public void GenerateMethod(Method method) { - if (method.Ignore) return; - - if (method.Access != AccessSpecifier.Public) - return; + if (ASTUtils.CheckIgnoreMethod(method)) return; PushBlock(CLIBlockKind.Method, method); diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 944c03a6..c8fa8214 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using CppSharp.AST; using CppSharp.Types; +using Type = CppSharp.AST.Type; namespace CppSharp.Generators.CLI { @@ -124,7 +125,7 @@ namespace CppSharp.Generators.CLI foreach (var method in @class.Methods) { - if (ASTUtils.CheckIgnoreMethod(@class, method)) + if (ASTUtils.CheckIgnoreMethod(method)) continue; GenerateDeclarationCommon(method); @@ -154,16 +155,11 @@ namespace CppSharp.Generators.CLI WriteCloseBraceIndent(); PopBlock(NewLineKind.BeforeNextBlock); } - - foreach (var field in @class.Fields) - { - if (ASTUtils.CheckIgnoreField(@class, field)) - continue; - - GenerateFieldProperty(field); - } } + foreach (var property in @class.Properties) + GenerateProperty(property); + foreach (var @event in @class.Events) { if (@event.Ignore) @@ -209,9 +205,6 @@ namespace CppSharp.Generators.CLI var function = template.TemplatedFunction; - var typeNames = template.Parameters.Select( - param => "typename " + param.Name).ToList(); - var typeCtx = new CLITypePrinterContext() { Kind = TypePrinterContextKind.Template, @@ -224,10 +217,15 @@ namespace CppSharp.Generators.CLI var retType = function.ReturnType.Type.Visit(typePrinter, function.ReturnType.Qualifiers); - WriteLine("generic<{0}>", string.Join(", ", typeNames)); - WriteLine("{0} {1}::{2}({3})", retType, QualifiedIdentifier(@class), - SafeIdentifier(function.Name), - GenerateParametersList(function.Parameters)); + var typeNamesStr = ""; + var paramNames = template.Parameters.Select(param => param.Name).ToList(); + if (paramNames.Any()) + typeNamesStr = "typename " + string.Join(", typename ", paramNames); + + WriteLine("generic<{0}>", typeNamesStr); + WriteLine("{0} {1}::{2}({3})", retType, + QualifiedIdentifier(@class), SafeIdentifier(function.Name), + GenerateParametersList(function.Parameters)); WriteStartBraceIndent(); @@ -239,82 +237,119 @@ namespace CppSharp.Generators.CLI printer.Context = oldCtx; } - private void GenerateFieldProperty(Field field) + private void GenerateProperty(Property property) { - var @class = field.Class; + if (property.Ignore) return; + + PushBlock(CLIBlockKind.Property); + var @class = property.Namespace as Class; - GeneratePropertyGetter(field, @class); - GeneratePropertySetter(field, @class); + if (property.Field != null) + { + GeneratePropertyGetter(property.Field, @class, property.Name, property.Type); + GeneratePropertySetter(property.Field, @class, property.Name, property.Type); + } + else + { + GeneratePropertyGetter(property.GetMethod, @class, property.Name, property.Type); + GeneratePropertySetter(property.SetMethod, @class, property.Name, property.Type); + } + PopBlock(); } - private void GeneratePropertySetter(T decl, Class @class) + private void GeneratePropertySetter(T decl, Class @class, string name, Type type) where T : Declaration, ITypedDecl { + if (decl == null) + return; + WriteLine("void {0}::{1}::set({2} value)", QualifiedIdentifier(@class), - decl.Name, decl.Type); + name, type); WriteStartBraceIndent(); - var param = new Parameter - { - Name = "value", - QualifiedType = decl.QualifiedType - }; + if (decl is Function) + { + var func = decl as Function; + if(func.Parameters[0].Name != "value") + WriteLine("auto {0} = value;", func.Parameters[0].Name); + GenerateFunctionCall(func, @class); + } + else + { + var param = new Parameter + { + Name = "value", + QualifiedType = decl.QualifiedType + }; - var ctx = new MarshalContext(Driver) - { - Parameter = param, - ArgName = param.Name, - }; + var ctx = new MarshalContext(Driver) + { + Parameter = param, + ArgName = param.Name, + }; - var marshal = new CLIMarshalManagedToNativePrinter(ctx); - param.Visit(marshal); + var marshal = new CLIMarshalManagedToNativePrinter(ctx); + param.Visit(marshal); - string variable; - if (decl is Variable) - variable = string.Format("::{0}::{1}", - @class.QualifiedOriginalName, decl.OriginalName); - else - variable = string.Format("((::{0}*)NativePtr)->{1}", - @class.QualifiedOriginalName, decl.OriginalName); + string variable; + if (decl is Variable) + variable = string.Format("::{0}::{1}", + @class.QualifiedOriginalName, decl.OriginalName); + else + variable = string.Format("((::{0}*)NativePtr)->{1}", + @class.QualifiedOriginalName, decl.OriginalName); - if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) - Write(marshal.Context.SupportBefore); + if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) + Write(marshal.Context.SupportBefore); - WriteLine("{0} = {1};", variable, marshal.Context.Return); + WriteLine("{0} = {1};", variable, marshal.Context.Return); + } WriteCloseBraceIndent(); NewLine(); } - private void GeneratePropertyGetter(T decl, Class @class) + private void GeneratePropertyGetter(T decl, Class @class, string name, Type type) where T : Declaration, ITypedDecl { - WriteLine("{0} {1}::{2}::get()", decl.Type, QualifiedIdentifier(@class), - decl.Name); + if (decl == null) + return; + + WriteLine("{0} {1}::{2}::get()", type, QualifiedIdentifier(@class), + name); WriteStartBraceIndent(); - string variable; - if (decl is Variable) - variable = string.Format("::{0}::{1}", - @class.QualifiedOriginalName, decl.OriginalName); + if (decl is Function) + { + var func = decl as Function; + GenerateFunctionCall(func, @class); + } else - variable = string.Format("((::{0}*)NativePtr)->{1}", + { + string variable; + if (decl is Variable) + variable = string.Format("::{0}::{1}", @class.QualifiedOriginalName, decl.OriginalName); + else + variable = string.Format("((::{0}*)NativePtr)->{1}", + @class.QualifiedOriginalName, decl.OriginalName); - var ctx = new MarshalContext(Driver) - { - ArgName = decl.Name, - ReturnVarName = variable, - ReturnType = decl.QualifiedType - }; + var ctx = new MarshalContext(Driver) + { + ArgName = decl.Name, + ReturnVarName = variable, + ReturnType = decl.QualifiedType + }; - var marshal = new CLIMarshalNativeToManagedPrinter(ctx); - decl.Visit(marshal); + var marshal = new CLIMarshalNativeToManagedPrinter(ctx); + decl.Visit(marshal); - if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) - Write(marshal.Context.SupportBefore); + if (!string.IsNullOrWhiteSpace(marshal.Context.SupportBefore)) + Write(marshal.Context.SupportBefore); - WriteLine("return {0};", marshal.Context.Return); + WriteLine("return {0};", marshal.Context.Return); + } + WriteCloseBraceIndent(); NewLine(); @@ -428,10 +463,10 @@ namespace CppSharp.Generators.CLI private void GenerateVariable(Variable variable, Class @class) { - GeneratePropertyGetter(variable, @class); + GeneratePropertyGetter(variable, @class, variable.Name, variable.Type); if (!variable.QualifiedType.Qualifiers.IsConst) - GeneratePropertySetter(variable, @class); + GeneratePropertySetter(variable, @class, variable.Name, variable.Type); } private void GenerateClassConstructor(Class @class, bool isIntPtr) @@ -483,7 +518,7 @@ namespace CppSharp.Generators.CLI foreach (var field in @class.Fields) { - if (ASTUtils.CheckIgnoreField(@class, field)) continue; + if (ASTUtils.CheckIgnoreField(field)) continue; var nativeField = string.Format("{0}{1}", nativeVar, field.OriginalName); @@ -621,7 +656,7 @@ namespace CppSharp.Generators.CLI foreach (var field in @class.Fields) { - if (ASTUtils.CheckIgnoreField(@class, field)) continue; + if (ASTUtils.CheckIgnoreField(field)) continue; var varName = string.Format("_native.{0}", field.OriginalName); diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index e55bde5d..7af14831 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -384,7 +384,7 @@ namespace CppSharp.Generators.CSharp foreach (var method in @class.Methods) { - if (ASTUtils.CheckIgnoreMethod(@class, method)) + if (ASTUtils.CheckIgnoreMethod(method)) continue; if (method.IsConstructor) @@ -432,7 +432,7 @@ namespace CppSharp.Generators.CSharp foreach (var field in @class.Fields) { - if (ASTUtils.CheckIgnoreField(@class, field)) continue; + if (ASTUtils.CheckIgnoreField(field)) continue; var nativeField = string.Format("{0}->{1}", Helpers.GeneratedIdentifier("ptr"), field.OriginalName); @@ -582,13 +582,14 @@ namespace CppSharp.Generators.CSharp foreach (var field in @class.Fields) { + if (ASTUtils.CheckIgnoreField(field)) continue; GenerateClassField(@class, isInternal, field); } } private void GenerateClassField(Class @class, bool isInternal, Field field) { - if (ASTUtils.CheckIgnoreField(@class, field)) return; + if (ASTUtils.CheckIgnoreField(field)) return; PushBlock(CSharpBlockKind.Field); @@ -794,7 +795,7 @@ namespace CppSharp.Generators.CSharp var staticMethods = new List(); foreach (var method in @class.Methods) { - if (ASTUtils.CheckIgnoreMethod(@class, method)) + if (ASTUtils.CheckIgnoreMethod(method)) continue; if (method.IsConstructor) @@ -985,7 +986,7 @@ namespace CppSharp.Generators.CSharp foreach (var ctor in @class.Constructors) { - if (ASTUtils.CheckIgnoreMethod(@class, ctor)) + if (ASTUtils.CheckIgnoreMethod(ctor)) continue; GenerateMethod(ctor, @class); diff --git a/src/Generator/Passes/CheckAmbiguousOverloads.cs b/src/Generator/Passes/CheckAmbiguousOverloads.cs deleted file mode 100644 index ae6922d5..00000000 --- a/src/Generator/Passes/CheckAmbiguousOverloads.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using CppSharp.AST; -using CppSharp.Generators; - -namespace CppSharp.Passes -{ - struct OverloadSignature - { - public string Return; - public List Parameters; - public Function Function; - - public OverloadSignature(Function function) - { - Function = function; - - Return = function.ReturnType.ToString(); - Parameters = new List(); - - foreach (var param in function.Parameters) - { - var paramType = param.Type.ToString(); - Parameters.Add(paramType); - } - } - - public static bool IsAmbiguous(OverloadSignature overload1, - OverloadSignature overload2, Class @class) - { - if (overload1.Function == overload2.Function) - return false; - - if (ASTUtils.CheckIgnoreFunction(@class, overload1.Function)) - return false; - - if (ASTUtils.CheckIgnoreFunction(@class, overload2.Function)) - return false; - - // TODO: Default parameters? - if (overload1.Parameters.Count != overload2.Parameters.Count) - return false; - - if (overload1.Parameters.Count == 0) - return true; - - for (var i = 0; i < overload1.Parameters.Count; i++) - { - if (overload1.Parameters[i] != overload2.Parameters[i]) - return false; - } - - return true; - } - }; - - public class CheckAmbiguousOverloads : TranslationUnitPass - { - private readonly ISet visited; - - public CheckAmbiguousOverloads() - { - visited = new HashSet(); - Options.VisitNamespaceEnums = false; - Options.VisitNamespaceTemplates = false; - Options.VisitNamespaceTypedefs = false; - Options.VisitNamespaceEvents = false; - Options.VisitNamespaceVariables = false; - - Options.VisitClassBases = false; - Options.VisitClassFields = false; - Options.VisitClassProperties = false; - } - - public override bool VisitClassDecl(Class @class) - { - visited.Clear(); - return base.VisitClassDecl(@class); - } - - public override bool VisitMethodDecl(Method method) - { - CheckOverloads(method); - return false; - } - - public override bool VisitFunctionDecl(Function function) - { - CheckOverloads(function); - return false; - } - - private bool CheckOverloads(Function function) - { - if (visited.Contains(function)) - return false; - - if (function.Ignore) - return false; - - var overloads = function.Namespace.GetFunctionOverloads(function); - var signatures = overloads.Select(fn => new OverloadSignature(fn)).ToList(); - - foreach (var sig1 in signatures) - { - visited.Add(sig1.Function); - - if (sig1.Function.Ignore) - continue; - - foreach (var sig2 in signatures) - { - if (sig2.Function.Ignore) - continue; - - var @class = function.Namespace as Class; - if (!OverloadSignature.IsAmbiguous(sig1, sig2, @class)) - continue; - - Driver.Diagnostics.EmitWarning(DiagnosticId.AmbiguousOverload, - "Overload {0} is ambiguous, renaming automatically", - sig1.Function.QualifiedOriginalName); - - RenameOverload(sig1.Function); - return false; - } - } - - return true; - } - - public void RenameOverload(Function function) - { - function.Name = function.Name + "0"; - } - } - - public static class CheckAmbiguousOverloadsExtensions - { - public static void CheckAmbiguousOverloads(this PassBuilder builder) - { - var pass = new CheckAmbiguousOverloads(); - builder.AddPass(pass); - } - } -} diff --git a/src/Generator/Passes/CheckDuplicatedNamesPass.cs b/src/Generator/Passes/CheckDuplicatedNamesPass.cs new file mode 100644 index 00000000..1f9b2b95 --- /dev/null +++ b/src/Generator/Passes/CheckDuplicatedNamesPass.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using CppSharp.AST; + +namespace CppSharp.Passes +{ + class DeclarationName + { + private readonly string Name; + private readonly Dictionary methodSignatures; + private int Count; + + public DeclarationName(string name) + { + Name = name; + methodSignatures = new Dictionary(); + } + + public bool UpdateName(Declaration decl) + { + if (decl.Name != Name) + throw new Exception("Invalid name"); + + var method = decl as Method; + if (method != null) + { + return UpdateName(method); + } + + var count = Count++; + if (count == 0) + return false; + + decl.Name += count.ToString(CultureInfo.InvariantCulture); + return true; + } + + private bool UpdateName(Method method) + { + var @params = method.Parameters.Select(p => p.QualifiedType.ToString()); + var signature = string.Format("{0}({1})", Name,string.Join( ", ", @params)); + + if (Count == 0) + Count++; + + if (!methodSignatures.ContainsKey(signature)) + { + methodSignatures.Add(signature, 0); + return false; + } + + var methodCount = ++methodSignatures[signature]; + + if (Count < methodCount+1) + Count = methodCount+1; + + method.Name += methodCount.ToString(CultureInfo.InvariantCulture); + return true; + } + } + + public class CheckDuplicatedNamesPass : TranslationUnitPass + { + private readonly IDictionary names; + + public CheckDuplicatedNamesPass() + { + names = new Dictionary(); + } + + public override bool VisitFieldDecl(Field decl) + { + if (ASTUtils.CheckIgnoreField(decl)) + return false; + + if(!AlreadyVisited(decl)) + CheckDuplicate(decl); + + return false; + } + + public override bool VisitProperty(Property decl) + { + if(!AlreadyVisited(decl)) + CheckDuplicate(decl); + + return false; + } + + public override bool VisitMethodDecl(Method decl) + { + if (ASTUtils.CheckIgnoreMethod(decl)) + return false; + + if(!AlreadyVisited(decl)) + CheckDuplicate(decl); + + return false; + } + + public override bool VisitClassDecl(Class @class) + { + if (AlreadyVisited(@class) || @class.IsIncomplete) + return false; + + // DeclarationName should always process methods first, + // so we visit methods first. + foreach (var method in @class.Methods) + VisitMethodDecl(method); + + foreach (var field in @class.Fields) + VisitFieldDecl(field); + + foreach (var property in @class.Properties) + VisitProperty(property); + + return false; + } + + void CheckDuplicate(Declaration decl) + { + if (decl.IsDependent || decl.Ignore) + return; + + if (string.IsNullOrWhiteSpace(decl.Name)) + return; + + var fullName = decl.QualifiedName; + + // If the name is not yet on the map, then add it. + if (!names.ContainsKey(fullName)) + names.Add(fullName, new DeclarationName(decl.Name)); + + if (names[fullName].UpdateName(decl)) + Driver.Diagnostics.EmitWarning("Duplicate name {0}, renamed to {1}", fullName, decl.Name); + } + } + + public static class CheckDuplicateNamesExtensions + { + public static void CheckDuplicateNames(this PassBuilder builder) + { + var pass = new CheckDuplicatedNamesPass(); + builder.AddPass(pass); + } + } +} diff --git a/src/Generator/Passes/DuplicatedNamesCheckerPass.cs b/src/Generator/Passes/DuplicatedNamesCheckerPass.cs deleted file mode 100644 index 3424cad2..00000000 --- a/src/Generator/Passes/DuplicatedNamesCheckerPass.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using CppSharp.AST; - -namespace CppSharp.Passes -{ - public class DuplicatedNamesCheckerPass : TranslationUnitPass - { - private readonly IDictionary names; - - public DuplicatedNamesCheckerPass() - { - names = new Dictionary(); - } - - public override bool VisitClassDecl(Class @class) - { - if (@class.Ignore) return false; - - names.Clear(); - return base.VisitClassDecl(@class); - } - - public override bool VisitDeclaration(Declaration decl) - { - if (AlreadyVisited(decl)) - return true; - - Visited.Add(decl); - - CheckDuplicate(decl); - return base.VisitDeclaration(decl); - } - - public override bool VisitParameterDecl(Parameter parameter) - { - return true; - } - - void CheckDuplicate(Declaration decl) - { - if (string.IsNullOrWhiteSpace(decl.Name)) - return; - - Declaration duplicate; - - // If the name is not yet on the map, then add it. - if (!names.TryGetValue(decl.Name, out duplicate)) - { - names[decl.Name] = decl; - return; - } - - // Else we found a duplicate name and need to change it. - Console.WriteLine("Found a duplicate named declaration: {0}", - decl.Name); - } - } - - public static class CheckDuplicateNamesExtensions - { - public static void CheckDuplicateNames(this PassBuilder builder) - { - var pass = new DuplicatedNamesCheckerPass(); - builder.AddPass(pass); - } - } -} diff --git a/src/Generator/Passes/FieldToPropertyPass.cs b/src/Generator/Passes/FieldToPropertyPass.cs new file mode 100644 index 00000000..2997e1d6 --- /dev/null +++ b/src/Generator/Passes/FieldToPropertyPass.cs @@ -0,0 +1,33 @@ +using CppSharp.AST; + +namespace CppSharp.Passes +{ + public class FieldToPropertyPass : TranslationUnitPass + { + public override bool VisitFieldDecl(Field field) + { + var @class = field.Namespace as Class; + if (@class == null) + return false; + + if (@class.IsValueType) + return false; + + if (ASTUtils.CheckIgnoreField(field)) + return false; + + var prop = new Property() + { + Name = field.Name, + Namespace = field.Namespace, + QualifiedType = field.QualifiedType, + Field = field + }; + @class.Properties.Add(prop); + + field.ExplicityIgnored = true; + + return false; + } + } +} diff --git a/src/Generator/Passes/FunctionToInstanceMethodPass.cs b/src/Generator/Passes/FunctionToInstanceMethodPass.cs index 3b48a1e2..e169947d 100644 --- a/src/Generator/Passes/FunctionToInstanceMethodPass.cs +++ b/src/Generator/Passes/FunctionToInstanceMethodPass.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using CppSharp.AST; +using CppSharp.Generators; namespace CppSharp.Passes { @@ -44,19 +45,23 @@ namespace CppSharp.Passes 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, - Parameters = function.Parameters.Skip(1).ToList(), + Parameters = function.Parameters, CallingConvention = function.CallingConvention, IsVariadic = function.IsVariadic, IsInline = function.IsInline, Conversion = MethodConversionKind.FunctionToInstanceMethod }; + if (Driver.Options.GeneratorKind == LanguageGeneratorKind.CSharp) + method.Parameters = method.Parameters.Skip(1).ToList(); + @class.Methods.Add(method); Console.WriteLine("Instance method: {0}::{1}", @class.Name, diff --git a/src/Generator/Passes/FunctionToStaticMethodPass.cs b/src/Generator/Passes/FunctionToStaticMethodPass.cs index cdc02baf..f7bc833b 100644 --- a/src/Generator/Passes/FunctionToStaticMethodPass.cs +++ b/src/Generator/Passes/FunctionToStaticMethodPass.cs @@ -33,7 +33,8 @@ namespace CppSharp.Passes // Create a new fake method so it acts as a static method. var method = new Method() { - Namespace = @class.Namespace, + Namespace = @class, + OriginalNamespace = function.Namespace, Name = name, OriginalName = function.OriginalName, Mangled = function.Mangled, diff --git a/src/Generator/Passes/GetterSetterToPropertyPass.cs b/src/Generator/Passes/GetterSetterToPropertyPass.cs index 6fa6e2a3..8039611f 100644 --- a/src/Generator/Passes/GetterSetterToPropertyPass.cs +++ b/src/Generator/Passes/GetterSetterToPropertyPass.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics; +using System.Linq; using CppSharp.AST; namespace CppSharp.Passes @@ -44,51 +46,97 @@ namespace CppSharp.Passes return !isRetVoid && isGetter && method.Parameters.Count == 0; } + Property GetOrCreateProperty(Class @class, string name, QualifiedType type) + { + var prop = @class.Properties.FirstOrDefault(property => property.Name == name + && property.QualifiedType.Equals(type)); + + var prop2 = @class.Properties.FirstOrDefault(property => property.Name == name); + + if (prop == null && prop2 != null) + Driver.Diagnostics.EmitWarning(DiagnosticId.PropertySynthetized, + "Property {0}::{1} already exist with type {2}", @class.Name, name, type.Type.ToString()); + + if (prop != null) + return prop; + + prop = new Property + { + Name = name, + Namespace = @class, + QualifiedType = type + }; + + @class.Properties.Add(prop); + return prop; + } + public override bool VisitMethodDecl(Method method) { - //var expansions = method.PreprocessedEntities.OfType(); - //if (expansions.Any(e => e.Text.Contains("ACCESSOR"))) - // System.Diagnostics.Debugger.Break(); + if (AlreadyVisited(method)) + return false; - if (!IsGetter(method)) + if (ASTUtils.CheckIgnoreMethod(method)) return false; var @class = method.Namespace as Class; - foreach (var classMethod in @class.Methods) + + if (@class == null || @class.IsIncomplete) + return false; + + if (IsGetter(method)) { - if (!IsSetter(classMethod)) - continue; + var name = method.Name.Substring("get".Length); + var prop = GetOrCreateProperty(@class, name, method.ReturnType); + prop.GetMethod = method; - if (classMethod.Parameters[0].Type.Equals(method.ReturnType.Type)) - continue; + // Do not generate the original method now that we know it is a getter. + method.IsGenerated = false; - var getName = method.Name.Substring("get".Length); - var setName = classMethod.Name.Substring("set".Length); + Driver.Diagnostics.EmitMessage(DiagnosticId.PropertySynthetized, + "Getter created: {0}::{1}", @class.Name, name); - if (getName != setName) - continue; + return false; + } - // We found a compatible pair of methods, create a property. - var prop = new Property - { - Name = getName, - Namespace = @class, - QualifiedType = method.ReturnType - }; + if (IsSetter(method) && IsValidSetter(method)) + { + var name = method.Name.Substring("set".Length); - // Ignore the original methods now that we have a property. - method.ExplicityIgnored = true; - classMethod.ExplicityIgnored = true; + var type = method.Parameters[0].QualifiedType; + var prop = GetOrCreateProperty(@class, name, type); + prop.SetMethod = method; - @class.Properties.Add(prop); + // Ignore the original method now that we know it is a setter. + method.IsGenerated = false; Driver.Diagnostics.EmitMessage(DiagnosticId.PropertySynthetized, - "Getter/setter property created: {0}::{1}", @class.Name, - getName); - return true; + "Setter created: {0}::{1}", @class.Name, name); + + return false; } return false; } + + // Check if a matching getter exist or no other setter exists. + private bool IsValidSetter(Method method) + { + var @class = method.Namespace as Class; + var name = method.Name.Substring("set".Length); + + if (method.Parameters.Count == 0) + return false; + + var type = method.Parameters[0].Type; + + var getter = @class.Methods.FirstOrDefault(m => m.Name == "Get" + name && m.Type.Equals(type)); + + var otherSetter = @class.Methods.FirstOrDefault(m => m.Name == method.Name + && m.Parameters.Count == 1 + && !m.Parameters[0].Type.Equals(type)); + + return getter != null || otherSetter == null; + } } } diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index f89719ae..256f026c 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -463,6 +463,7 @@ void Parser::WalkVTable(clang::CXXRecordDecl* RD, CppSharp::AST::Class^ C) { case TargetCXXABI::Microsoft: { +#if SVN_REVISION >= 187409 MicrosoftVFTableContext VTContext(*AST); auto VFPtrs = VTContext.getVFPtrOffsets(RD); @@ -481,6 +482,7 @@ void Parser::WalkVTable(clang::CXXRecordDecl* RD, CppSharp::AST::Class^ C) C->Layout->VFTables->Add(Info); break; } +#endif } case TargetCXXABI::GenericItanium: {