Browse Source

Merge pull request #237 from azeno/minor-improvements

Minor improvements
pull/238/head
João Matos 11 years ago
parent
commit
d79d5e7a2d
  1. 37
      src/AST/Class.cs
  2. 12
      src/AST/Function.cs
  3. 5
      src/AST/Method.cs
  4. 195
      src/AST/Namespace.cs
  5. 1
      src/Core/Parser/ASTConverter.cs
  6. 1
      src/CppParser/AST.h
  7. 10
      src/CppParser/Bindings/CLI/AST.cpp
  8. 6
      src/CppParser/Bindings/CLI/AST.h
  9. 22
      src/CppParser/Bindings/CSharp/AST.cs
  10. 1
      src/CppParser/Parser.cpp
  11. 164
      src/Generator.Tests/AST/TestAST.cs
  12. 127
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  13. 75
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  14. 1
      src/Parser/Parser.cpp
  15. 6
      tests/CLITemp/CLITemp.cs
  16. 9
      tests/CLITemp/CLITemp.h
  17. 22
      tests/Native/AST.h

37
src/AST/Class.cs

@ -133,6 +133,28 @@ namespace CppSharp.AST
Layout = new ClassLayout(); Layout = new ClassLayout();
} }
public Class(Class @class)
: base(@class)
{
Bases = new List<BaseClassSpecifier>(@class.Bases);
Fields = new List<Field>(@class.Fields);
Properties = new List<Property>(@class.Properties);
Methods = new List<Method>(@class.Methods);
Specifiers = new List<AccessSpecifierDecl>(@class.Specifiers);
IsPOD = @class.IsPOD;
Type = @class.Type;
Layout = new ClassLayout(@class.Layout);
IsAbstract = @class.IsAbstract;
IsUnion = @class.IsUnion;
IsOpaque = @class.IsOpaque;
IsDynamic = @class.IsDynamic;
IsPolymorphic = @class.IsPolymorphic;
HasNonTrivialDefaultConstructor = @class.HasNonTrivialDefaultConstructor;
HasNonTrivialCopyConstructor = @class.HasNonTrivialCopyConstructor;
HasNonTrivialDestructor = @class.HasNonTrivialDestructor;
IsStatic = @class.IsStatic;
}
public bool HasBase public bool HasBase
{ {
get { return Bases.Count > 0; } get { return Bases.Count > 0; }
@ -149,8 +171,8 @@ namespace CppSharp.AST
{ {
foreach (var @base in Bases) foreach (var @base in Bases)
{ {
if (@base.IsClass && @base.Class.IsDeclared) if (@base.IsClass && @base.Class.IsDeclared)
return @base.Class; return @base.Class;
} }
return null; return null;
@ -199,11 +221,16 @@ namespace CppSharp.AST
} }
} }
public override IEnumerable<Function> FindOperator(CXXOperatorKind kind)
{
return Methods.Where(m => m.OperatorKind == kind);
}
public override IEnumerable<Function> GetOverloads(Function function) public override IEnumerable<Function> GetOverloads(Function function)
{ {
if (function.IsOperator) if (function.IsOperator)
return Methods.Where(fn => fn.OperatorKind == function.OperatorKind); return Methods.Where(fn => fn.OperatorKind == function.OperatorKind);
var methods = Methods.Where(m => m.Name == function.Name); var methods = Methods.Where(m => m.Name == function.Name);
if (methods.ToList().Count != 0) if (methods.ToList().Count != 0)
return methods; return methods;

12
src/AST/Function.cs

@ -37,9 +37,21 @@ namespace CppSharp.AST
HasDefaultValue = false; HasDefaultValue = false;
} }
public Parameter(Parameter p)
: base(p)
{
HasDefaultValue = p.HasDefaultValue;
Index = p.Index;
IsIndirect = p.IsIndirect;
Kind = p.Kind;
QualifiedType = p.QualifiedType;
Usage = p.Usage;
}
public Type Type { get { return QualifiedType.Type; } } public Type Type { get { return QualifiedType.Type; } }
public QualifiedType QualifiedType { get; set; } public QualifiedType QualifiedType { get; set; }
public bool IsIndirect { get; set; } public bool IsIndirect { get; set; }
public uint Index { get; set; }
public ParameterKind Kind { get; set; } public ParameterKind Kind { get; set; }
public ParameterUsage Usage { get; set; } public ParameterUsage Usage { get; set; }

5
src/AST/Method.cs

@ -148,6 +148,11 @@ namespace CppSharp.AST
public Class ExplicitInterfaceImpl { get; set; } public Class ExplicitInterfaceImpl { get; set; }
public override T Visit<T>(IDeclVisitor<T> visitor)
{
return visitor.VisitMethodDecl(this);
}
public override QualifiedType GetFunctionType() public override QualifiedType GetFunctionType()
{ {
var qualifiedType = base.GetFunctionType(); var qualifiedType = base.GetFunctionType();

195
src/AST/Namespace.cs

@ -25,16 +25,16 @@ namespace CppSharp.AST
public Dictionary<ulong, Declaration> Anonymous; public Dictionary<ulong, Declaration> Anonymous;
// True if the context is inside an extern "C" context. // True if the context is inside an extern "C" context.
public bool IsExternCContext; public bool IsExternCContext;
public override string LogicalName public override string LogicalName
{ {
get { return IsAnonymous ? "<anonymous>" : base.Name; } get { return IsAnonymous ? "<anonymous>" : base.Name; }
} }
public override string LogicalOriginalName public override string LogicalOriginalName
{ {
get { return IsAnonymous ? "<anonymous>" : base.OriginalName; } get { return IsAnonymous ? "<anonymous>" : base.OriginalName; }
} }
protected DeclarationContext() protected DeclarationContext()
@ -51,6 +51,22 @@ namespace CppSharp.AST
Anonymous = new Dictionary<ulong, Declaration>(); Anonymous = new Dictionary<ulong, Declaration>();
} }
protected DeclarationContext(DeclarationContext dc)
: base(dc)
{
Namespaces = new List<Namespace>(dc.Namespaces);
Enums = new List<Enumeration>(dc.Enums);
Functions = new List<Function>(dc.Functions);
Classes = new List<Class>(dc.Classes);
Templates = new List<Template>(dc.Templates);
Typedefs = new List<TypedefDecl>(dc.Typedefs);
Variables = new List<Variable>(dc.Variables);
Events = new List<Event>(dc.Events);
TypeReferences = new List<TypeReference>(dc.TypeReferences);
Anonymous = new Dictionary<ulong, Declaration>(dc.Anonymous);
IsAnonymous = dc.IsAnonymous;
}
public IEnumerable<DeclarationContext> GatherParentNamespaces() public IEnumerable<DeclarationContext> GatherParentNamespaces()
{ {
var children = new List<DeclarationContext>(); var children = new List<DeclarationContext>();
@ -71,25 +87,25 @@ namespace CppSharp.AST
public Declaration FindAnonymous(ulong key) public Declaration FindAnonymous(ulong key)
{ {
return Anonymous.ContainsKey(key) ? Anonymous[key] : null; return Anonymous.ContainsKey(key) ? Anonymous[key] : null;
} }
public DeclarationContext FindDeclaration(IEnumerable<string> declarations) public DeclarationContext FindDeclaration(IEnumerable<string> declarations)
{ {
DeclarationContext currentDeclaration = this; DeclarationContext currentDeclaration = this;
foreach (var declaration in declarations) foreach (var declaration in declarations)
{ {
var subDeclaration = currentDeclaration.Namespaces var subDeclaration = currentDeclaration.Namespaces
.Concat<DeclarationContext>(currentDeclaration.Classes) .Concat<DeclarationContext>(currentDeclaration.Classes)
.FirstOrDefault(e => e.Name.Equals(declaration)); .FirstOrDefault(e => e.Name.Equals(declaration));
if (subDeclaration == null) if (subDeclaration == null)
return null; return null;
currentDeclaration = subDeclaration; currentDeclaration = subDeclaration;
} }
return currentDeclaration as DeclarationContext; return currentDeclaration as DeclarationContext;
} }
public Namespace FindNamespace(string name) public Namespace FindNamespace(string name)
@ -165,34 +181,34 @@ namespace CppSharp.AST
} }
public Function FindFunction(string name, bool createDecl = false) public Function FindFunction(string name, bool createDecl = false)
{ {
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
return null; return null;
var entries = name.Split(new string[] { "::" }, var entries = name.Split(new string[] { "::" },
StringSplitOptions.RemoveEmptyEntries).ToList(); StringSplitOptions.RemoveEmptyEntries).ToList();
if (entries.Count <= 1) if (entries.Count <= 1)
{ {
var function = Functions.Find(e => e.Name.Equals(name)); var function = Functions.Find(e => e.Name.Equals(name));
if (function == null && createDecl) if (function == null && createDecl)
{ {
function = new Function() { Name = name, Namespace = this }; function = new Function() { Name = name, Namespace = this };
Functions.Add(function); Functions.Add(function);
} }
return function; return function;
} }
var funcName = entries[entries.Count - 1]; var funcName = entries[entries.Count - 1];
var namespaces = entries.Take(entries.Count - 1); var namespaces = entries.Take(entries.Count - 1);
var @namespace = FindNamespace(namespaces); var @namespace = FindNamespace(namespaces);
if (@namespace == null) if (@namespace == null)
return null; return null;
return @namespace.FindFunction(funcName, createDecl); return @namespace.FindFunction(funcName, createDecl);
} }
Class CreateClass(string name, bool isComplete) Class CreateClass(string name, bool isComplete)
@ -229,7 +245,7 @@ namespace CppSharp.AST
DeclarationContext declContext = FindDeclaration(namespaces); DeclarationContext declContext = FindDeclaration(namespaces);
if (declContext == null) if (declContext == null)
{ {
declContext = FindClass(entries[0]); declContext = FindClass(entries[0]);
if (declContext == null) if (declContext == null)
return null; return null;
@ -294,15 +310,30 @@ namespace CppSharp.AST
public TypedefDecl FindTypedef(string name, bool createDecl = false) public TypedefDecl FindTypedef(string name, bool createDecl = false)
{ {
var typedef = Typedefs.Find(e => e.Name.Equals(name)); var entries = name.Split(new string[] { "::" },
StringSplitOptions.RemoveEmptyEntries).ToList();
if (typedef == null && createDecl)
if (entries.Count <= 1)
{ {
typedef = new TypedefDecl { Name = name, Namespace = this }; var typeDef = Typedefs.Find(e => e.Name.Equals(name));
Typedefs.Add(typedef);
if (typeDef == null && createDecl)
{
typeDef = new TypedefDecl() { Name = name, Namespace = this };
Typedefs.Add(typeDef);
}
return typeDef;
} }
return typedef; var typeDefName = entries[entries.Count - 1];
var namespaces = entries.Take(entries.Count - 1);
var @namespace = FindNamespace(namespaces);
if (@namespace == null)
return null;
return @namespace.FindTypedef(typeDefName, createDecl);
} }
public T FindType<T>(string name) where T : Declaration public T FindType<T>(string name) where T : Declaration
@ -320,13 +351,13 @@ namespace CppSharp.AST
return Enums.Find(e => e.ItemsByName.ContainsKey(name)); return Enums.Find(e => e.ItemsByName.ContainsKey(name));
} }
public IEnumerable<Function> FindOperator(CXXOperatorKind kind) public virtual IEnumerable<Function> FindOperator(CXXOperatorKind kind)
{ {
return Functions.Where(fn => fn.OperatorKind == kind); return Functions.Where(fn => fn.OperatorKind == kind);
} }
public virtual IEnumerable<Function> GetOverloads(Function function) public virtual IEnumerable<Function> GetOverloads(Function function)
{ {
if (function.IsOperator) if (function.IsOperator)
return FindOperator(function.OperatorKind); return FindOperator(function.OperatorKind);
return Functions.Where(fn => fn.Name == function.Name); return Functions.Where(fn => fn.Name == function.Name);
@ -335,17 +366,17 @@ namespace CppSharp.AST
public bool HasDeclarations public bool HasDeclarations
{ {
get get
{ {
Predicate<Declaration> pred = (t => t.IsGenerated); Predicate<Declaration> pred = (t => t.IsGenerated);
return Enums.Exists(pred) || HasFunctions || Typedefs.Exists(pred) return Enums.Exists(pred) || HasFunctions || Typedefs.Exists(pred)
|| Classes.Any() || Namespaces.Exists(n => n.HasDeclarations); || Classes.Any() || Namespaces.Exists(n => n.HasDeclarations);
} }
} }
public bool HasFunctions public bool HasFunctions
{ {
get get
{ {
Predicate<Declaration> pred = (t => t.IsGenerated); Predicate<Declaration> pred = (t => t.IsGenerated);
return Functions.Exists(pred) || Namespaces.Exists(n => n.HasFunctions); return Functions.Exists(pred) || Namespaces.Exists(n => n.HasFunctions);
} }
@ -357,18 +388,18 @@ namespace CppSharp.AST
/// <summary> /// <summary>
/// Represents a C++ namespace. /// Represents a C++ namespace.
/// </summary> /// </summary>
public class Namespace : DeclarationContext public class Namespace : DeclarationContext
{ {
public override string LogicalName public override string LogicalName
{ {
get { return IsInline ? string.Empty : base.Name; } get { return IsInline ? string.Empty : base.Name; }
} }
public override string LogicalOriginalName public override string LogicalOriginalName
{ {
get { return IsInline ? string.Empty : base.OriginalName; } get { return IsInline ? string.Empty : base.OriginalName; }
} }
public bool IsInline; public bool IsInline;
public override T Visit<T>(IDeclVisitor<T> visitor) public override T Visit<T>(IDeclVisitor<T> visitor)

1
src/Core/Parser/ASTConverter.cs

@ -803,6 +803,7 @@ namespace CppSharp
_param.QualifiedType = typeConverter.VisitQualified(decl.QualifiedType); _param.QualifiedType = typeConverter.VisitQualified(decl.QualifiedType);
_param.IsIndirect = decl.IsIndirect; _param.IsIndirect = decl.IsIndirect;
_param.HasDefaultValue = decl.HasDefaultValue; _param.HasDefaultValue = decl.HasDefaultValue;
_param.Index = decl.Index;
return _param; return _param;
} }

1
src/CppParser/AST.h

@ -433,6 +433,7 @@ struct CS_API Parameter : public Declaration
CppSharp::CppParser::AST::QualifiedType QualifiedType; CppSharp::CppParser::AST::QualifiedType QualifiedType;
bool IsIndirect; bool IsIndirect;
bool HasDefaultValue; bool HasDefaultValue;
unsigned int Index;
}; };
enum struct CXXMethodKind enum struct CXXMethodKind

10
src/CppParser/Bindings/CLI/AST.cpp

@ -1459,6 +1459,16 @@ void CppSharp::Parser::AST::Parameter::HasDefaultValue::set(bool value)
((::CppSharp::CppParser::AST::Parameter*)NativePtr)->HasDefaultValue = value; ((::CppSharp::CppParser::AST::Parameter*)NativePtr)->HasDefaultValue = value;
} }
unsigned int CppSharp::Parser::AST::Parameter::Index::get()
{
return ((::CppSharp::CppParser::AST::Parameter*)NativePtr)->Index;
}
void CppSharp::Parser::AST::Parameter::Index::set(unsigned int value)
{
((::CppSharp::CppParser::AST::Parameter*)NativePtr)->Index = value;
}
CppSharp::Parser::AST::Function::Function(::CppSharp::CppParser::AST::Function* native) CppSharp::Parser::AST::Function::Function(::CppSharp::CppParser::AST::Function* native)
: CppSharp::Parser::AST::Declaration((::CppSharp::CppParser::AST::Declaration*)native) : CppSharp::Parser::AST::Declaration((::CppSharp::CppParser::AST::Declaration*)native)
{ {

6
src/CppParser/Bindings/CLI/AST.h

@ -1120,6 +1120,12 @@ namespace CppSharp
bool get(); bool get();
void set(bool); void set(bool);
} }
property unsigned int Index
{
unsigned int get();
void set(unsigned int);
}
}; };
public ref class Function : CppSharp::Parser::AST::Declaration public ref class Function : CppSharp::Parser::AST::Declaration

22
src/CppParser/Bindings/CSharp/AST.cs

@ -3389,7 +3389,7 @@ namespace CppSharp
public unsafe partial class Parameter : CppSharp.Parser.AST.Declaration, IDisposable public unsafe partial class Parameter : CppSharp.Parser.AST.Declaration, IDisposable
{ {
[StructLayout(LayoutKind.Explicit, Size = 104)] [StructLayout(LayoutKind.Explicit, Size = 108)]
public new struct Internal public new struct Internal
{ {
[FieldOffset(0)] [FieldOffset(0)]
@ -3437,6 +3437,9 @@ namespace CppSharp
[FieldOffset(101)] [FieldOffset(101)]
internal bool HasDefaultValue; internal bool HasDefaultValue;
[FieldOffset(104)]
internal uint Index;
[SuppressUnmanagedCodeSecurity] [SuppressUnmanagedCodeSecurity]
[DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall, [DllImport("CppSharp.CppParser.dll", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall,
EntryPoint="??0Parameter@AST@CppParser@CppSharp@@QAE@XZ")] EntryPoint="??0Parameter@AST@CppParser@CppSharp@@QAE@XZ")]
@ -3471,7 +3474,7 @@ namespace CppSharp
public Parameter() public Parameter()
: this(IntPtr.Zero) : this(IntPtr.Zero)
{ {
__Instance = Marshal.AllocHGlobal(104); __Instance = Marshal.AllocHGlobal(108);
Internal.ctor_0(__Instance); Internal.ctor_0(__Instance);
} }
@ -3526,6 +3529,21 @@ namespace CppSharp
__ptr->HasDefaultValue = value; __ptr->HasDefaultValue = value;
} }
} }
public uint Index
{
get
{
var __ptr = (Internal*)__Instance.ToPointer();
return __ptr->Index;
}
set
{
var __ptr = (Internal*)__Instance.ToPointer();
__ptr->Index = value;
}
}
} }
public unsafe partial class Function : CppSharp.Parser.AST.Declaration, IDisposable public unsafe partial class Function : CppSharp.Parser.AST.Declaration, IDisposable

1
src/CppParser/Parser.cpp

@ -1885,6 +1885,7 @@ void Parser::WalkFunction(clang::FunctionDecl* FD, Function* F,
P->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &PTL)); P->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &PTL));
P->HasDefaultValue = VD->hasDefaultArg(); P->HasDefaultValue = VD->hasDefaultArg();
P->_Namespace = NS; P->_Namespace = NS;
P->Index = VD->getFunctionScopeIndex();
HandleDeclaration(VD, P); HandleDeclaration(VD, P);
F->Parameters.push_back(P); F->Parameters.push_back(P);

164
src/Generator.Tests/AST/TestAST.cs

@ -0,0 +1,164 @@
using System.Linq;
using CppSharp.Passes;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using NUnit.Framework;
namespace CppSharp.Generator.Tests.AST
{
[TestFixture]
public class TestAST : ASTTestFixture
{
private PassBuilder<TranslationUnitPass> passBuilder;
[TestFixtureSetUp]
public void Init()
{
}
[SetUp]
public void Setup()
{
ParseLibrary("AST.h");
passBuilder = new PassBuilder<TranslationUnitPass>(Driver);
}
[Test]
public void TestASTParameter()
{
var func = AstContext.FindFunction("TestParameterProperties").FirstOrDefault();
Assert.IsNotNull(func);
var paramNames = new [] { "a", "b", "c" };
var paramTypes = new []
{
new QualifiedType(new BuiltinType(PrimitiveType.Bool)),
new QualifiedType(
new PointerType()
{
Modifier = PointerType.TypeModifier.LVReference,
QualifiedPointee = new QualifiedType(
new BuiltinType(PrimitiveType.Int16),
new TypeQualifiers() { IsConst = true })
}),
new QualifiedType(
new PointerType()
{
Modifier = PointerType.TypeModifier.Pointer,
QualifiedPointee = new QualifiedType(new BuiltinType(PrimitiveType.Int32))
})
};
for (int i = 0; i < func.Parameters.Count; i++)
{
var param = func.Parameters[i];
Assert.AreEqual(paramNames[i], param.Name, "Parameter.Name");
Assert.AreEqual(paramTypes[i], param.QualifiedType, "Parameter.QualifiedType");
Assert.AreEqual(i, param.Index, "Parameter.Index");
}
Assert.IsTrue(func.Parameters[2].HasDefaultValue, "Parameter.HasDefaultValue");
}
[Test]
public void TestASTHelperMethods()
{
var @class = AstContext.FindClass("Math::Complex").FirstOrDefault();
Assert.IsNotNull(@class, "Couldn't find Math::Complex class.");
var plusOperator = @class.FindOperator(CXXOperatorKind.Plus).FirstOrDefault();
Assert.IsNotNull(plusOperator, "Couldn't find operator+ in Math::Complex class.");
var typedef = AstContext.FindTypedef("Math::Single").FirstOrDefault();
Assert.IsNotNull(typedef);
}
#region TestVisitor
class TestVisitor : IDeclVisitor<bool>
{
public bool VisitDeclaration(Declaration decl)
{
throw new System.NotImplementedException();
}
public bool VisitClassDecl(Class @class)
{
throw new System.NotImplementedException();
}
public bool VisitFieldDecl(Field field)
{
throw new System.NotImplementedException();
}
public bool VisitFunctionDecl(Function function)
{
throw new System.NotImplementedException();
}
public bool VisitMethodDecl(Method method)
{
return true;
}
public bool VisitParameterDecl(Parameter parameter)
{
throw new System.NotImplementedException();
}
public bool VisitTypedefDecl(TypedefDecl typedef)
{
throw new System.NotImplementedException();
}
public bool VisitEnumDecl(Enumeration @enum)
{
throw new System.NotImplementedException();
}
public bool VisitVariableDecl(Variable variable)
{
throw new System.NotImplementedException();
}
public bool VisitClassTemplateDecl(ClassTemplate template)
{
throw new System.NotImplementedException();
}
public bool VisitFunctionTemplateDecl(FunctionTemplate template)
{
throw new System.NotImplementedException();
}
public bool VisitMacroDefinition(MacroDefinition macro)
{
throw new System.NotImplementedException();
}
public bool VisitNamespace(Namespace @namespace)
{
throw new System.NotImplementedException();
}
public bool VisitEvent(Event @event)
{
throw new System.NotImplementedException();
}
public bool VisitProperty(Property property)
{
throw new System.NotImplementedException();
}
}
#endregion
[Test]
public void TestASTVisitor()
{
var testVisitor = new TestVisitor();
var plusOperator = AstContext.TranslationUnits
.SelectMany(u => u.Namespaces.Where(n => n.Name == "Math"))
.SelectMany(n => n.Classes.Where(c => c.Name == "Complex"))
.SelectMany(c => c.Methods.Where(m => m.OperatorKind == CXXOperatorKind.Plus))
.First();
Assert.IsTrue(plusOperator.Visit(testVisitor));
}
}
}

127
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -52,8 +52,8 @@ namespace CppSharp.Generators.CLI
public void GenerateIncludeForwardRefs() public void GenerateIncludeForwardRefs()
{ {
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase,
Driver.Options); Driver.Options);
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false);
var includes = new SortedSet<string>(StringComparer.InvariantCulture); var includes = new SortedSet<string>(StringComparer.InvariantCulture);
@ -68,8 +68,8 @@ namespace CppSharp.Generators.CLI
var include = typeRef.Include; var include = typeRef.Include;
var unit = include.TranslationUnit; var unit = include.TranslationUnit;
if (unit != null && !unit.IsDeclared) if (unit != null && !unit.IsDeclared)
continue; continue;
if(!string.IsNullOrEmpty(include.File) && include.InHeader) if(!string.IsNullOrEmpty(include.File) && include.InHeader)
@ -130,8 +130,8 @@ namespace CppSharp.Generators.CLI
public void GenerateForwardRefs() public void GenerateForwardRefs()
{ {
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase,
Driver.Options); Driver.Options);
typeReferenceCollector.Process(TranslationUnit); typeReferenceCollector.Process(TranslationUnit);
var typeReferences = typeReferenceCollector.TypeReferences; var typeReferences = typeReferenceCollector.TypeReferences;
@ -151,7 +151,7 @@ namespace CppSharp.Generators.CLI
// Generate all the enum declarations for the module. // Generate all the enum declarations for the module.
foreach (var @enum in decl.Enums) foreach (var @enum in decl.Enums)
{ {
if (!@enum.IsGenerated || @enum.IsIncomplete) if (!@enum.IsGenerated || @enum.IsIncomplete)
continue; continue;
PushBlock(CLIBlockKind.Enum, @enum); PushBlock(CLIBlockKind.Enum, @enum);
@ -165,7 +165,7 @@ namespace CppSharp.Generators.CLI
// Generate all the struct/class declarations for the module. // Generate all the struct/class declarations for the module.
foreach (var @class in decl.Classes) foreach (var @class in decl.Classes)
{ {
if (!@class.IsGenerated || @class.IsIncomplete) if (!@class.IsGenerated || @class.IsIncomplete)
continue; continue;
if (@class.IsOpaque) if (@class.IsOpaque)
@ -210,7 +210,7 @@ namespace CppSharp.Generators.CLI
{ {
foreach (var typedef in decl.Typedefs) foreach (var typedef in decl.Typedefs)
{ {
if (!typedef.IsGenerated) if (!typedef.IsGenerated)
continue; continue;
GenerateTypedef(typedef); GenerateTypedef(typedef);
@ -221,7 +221,7 @@ namespace CppSharp.Generators.CLI
{ {
PushBlock(CLIBlockKind.FunctionsClass); PushBlock(CLIBlockKind.FunctionsClass);
WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension); WriteLine("public ref class {0}", TranslationUnit.FileNameWithoutExtension);
WriteLine("{"); WriteLine("{");
WriteLine("public:"); WriteLine("public:");
PushIndent(); PushIndent();
@ -240,7 +240,7 @@ namespace CppSharp.Generators.CLI
public void GenerateClass(Class @class) public void GenerateClass(Class @class)
{ {
if (!@class.IsGenerated || @class.IsIncomplete) if (!@class.IsGenerated || @class.IsIncomplete)
return; return;
GenerateDeclarationCommon(@class); GenerateDeclarationCommon(@class);
@ -270,15 +270,15 @@ namespace CppSharp.Generators.CLI
GenerateClassVariables(@class); GenerateClassVariables(@class);
PushBlock(CLIBlockKind.AccessSpecifier); PushBlock(CLIBlockKind.AccessSpecifier);
WriteLine("private:"); WriteLine("private:");
var accBlock = PopBlock(NewLineKind.IfNotEmpty); var accBlock = PopBlock(NewLineKind.IfNotEmpty);
PushBlock(CLIBlockKind.Fields);
GenerateClassFields(@class);
var fieldsBlock = PopBlock();
PushBlock(CLIBlockKind.Fields); accBlock.CheckGenerate = () => !fieldsBlock.IsEmpty;
GenerateClassFields(@class);
var fieldsBlock = PopBlock();
accBlock.CheckGenerate = () => !fieldsBlock.IsEmpty;
WriteLine("};"); WriteLine("};");
} }
@ -306,7 +306,7 @@ namespace CppSharp.Generators.CLI
PushIndent(); PushIndent();
foreach (var template in @class.Templates) foreach (var template in @class.Templates)
{ {
if (!template.IsGenerated) continue; if (!template.IsGenerated) continue;
var functionTemplate = template as FunctionTemplate; var functionTemplate = template as FunctionTemplate;
if (functionTemplate == null) continue; if (functionTemplate == null) continue;
@ -371,7 +371,7 @@ namespace CppSharp.Generators.CLI
WriteLine("{0}({1} native);", @class.Name, "System::IntPtr"); WriteLine("{0}({1} native);", @class.Name, "System::IntPtr");
foreach (var ctor in @class.Constructors) foreach (var ctor in @class.Constructors)
{ {
if (ASTUtils.CheckIgnoreMethod(ctor, Options)) if (ASTUtils.CheckIgnoreMethod(ctor, Options))
continue; continue;
@ -382,10 +382,15 @@ namespace CppSharp.Generators.CLI
GenerateMethod(ctor); GenerateMethod(ctor);
} }
if (@class.IsRefType) if (Options.GenerateFinalizers && @class.IsRefType)
{ {
GenerateClassDestructor(@class); var destructor = @class.Destructors
GenerateClassFinalizer(@class); .FirstOrDefault(d => d.Parameters.Count == 0 && d.Access == AccessSpecifier.Public);
if (destructor != null)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
} }
PopIndent(); PopIndent();
@ -393,9 +398,6 @@ namespace CppSharp.Generators.CLI
private void GenerateClassDestructor(Class @class) private void GenerateClassDestructor(Class @class)
{ {
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Destructor); PushBlock(CLIBlockKind.Destructor);
WriteLine("~{0}();", @class.Name); WriteLine("~{0}();", @class.Name);
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
@ -403,9 +405,6 @@ namespace CppSharp.Generators.CLI
private void GenerateClassFinalizer(Class @class) private void GenerateClassFinalizer(Class @class)
{ {
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Finalizer); PushBlock(CLIBlockKind.Finalizer);
WriteLine("!{0}();", @class.Name); WriteLine("!{0}();", @class.Name);
PopBlock(NewLineKind.BeforeNextBlock); PopBlock(NewLineKind.BeforeNextBlock);
@ -415,7 +414,7 @@ namespace CppSharp.Generators.CLI
{ {
// Handle the case of struct (value-type) inheritance by adding the base // Handle the case of struct (value-type) inheritance by adding the base
// properties to the managed value subtypes. // properties to the managed value subtypes.
if (@class.IsValueType) if (@class.IsValueType)
{ {
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared))
{ {
@ -447,14 +446,14 @@ namespace CppSharp.Generators.CLI
field.Offset); field.Offset);
WriteLine("{0} {1};", field.Type, field.Name); WriteLine("{0} {1};", field.Type, field.Name);
PopBlock(); PopBlock();
} }
public void GenerateClassEvents(Class @class) public void GenerateClassEvents(Class @class)
{ {
foreach (var @event in @class.Events) foreach (var @event in @class.Events)
{ {
if (!@event.IsGenerated) continue; if (!@event.IsGenerated) continue;
var cppTypePrinter = new CppTypePrinter(Driver.TypeDatabase); var cppTypePrinter = new CppTypePrinter(Driver.TypeDatabase);
var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true); var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true);
@ -494,7 +493,7 @@ namespace CppSharp.Generators.CLI
var staticMethods = new List<Method>(); var staticMethods = new List<Method>();
foreach (var method in @class.Methods) foreach (var method in @class.Methods)
{ {
if (ASTUtils.CheckIgnoreMethod(method, Options)) if (ASTUtils.CheckIgnoreMethod(method, Options))
continue; continue;
@ -522,7 +521,7 @@ namespace CppSharp.Generators.CLI
foreach(var variable in @class.Variables) foreach(var variable in @class.Variables)
{ {
if (!variable.IsGenerated) continue; if (!variable.IsGenerated) continue;
if (variable.Access != AccessSpecifier.Public) if (variable.Access != AccessSpecifier.Public)
continue; continue;
@ -590,7 +589,7 @@ namespace CppSharp.Generators.CLI
{ {
// Handle the case of struct (value-type) inheritance by adding the base // Handle the case of struct (value-type) inheritance by adding the base
// properties to the managed value subtypes. // properties to the managed value subtypes.
if (@class.IsValueType) if (@class.IsValueType)
{ {
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared))
{ {
@ -615,18 +614,18 @@ namespace CppSharp.Generators.CLI
public void GenerateIndexer(Property property) public void GenerateIndexer(Property property)
{ {
var type = property.QualifiedType.Visit(TypePrinter); var type = property.QualifiedType.Visit(TypePrinter);
var getter = property.GetMethod; var getter = property.GetMethod;
var indexParameter = getter.Parameters[0]; var indexParameter = getter.Parameters[0];
var indexParameterType = indexParameter.QualifiedType.Visit(TypePrinter); var indexParameterType = indexParameter.QualifiedType.Visit(TypePrinter);
WriteLine("property {0} default[{1}]", type, indexParameterType); WriteLine("property {0} default[{1}]", type, indexParameterType);
WriteStartBraceIndent(); WriteStartBraceIndent();
if (property.HasGetter) if (property.HasGetter)
WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name); WriteLine("{0} get({1} {2});", type, indexParameterType, indexParameter.Name);
if (property.HasSetter) if (property.HasSetter)
WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name); WriteLine("void set({1} {2}, {0} value);", type, indexParameterType, indexParameter.Name);
WriteCloseBraceIndent(); WriteCloseBraceIndent();
@ -638,9 +637,9 @@ namespace CppSharp.Generators.CLI
return; return;
PushBlock(CLIBlockKind.Property, property); PushBlock(CLIBlockKind.Property, property);
var type = property.QualifiedType.Visit(TypePrinter); var type = property.QualifiedType.Visit(TypePrinter);
if (property.IsStatic) if (property.IsStatic)
Write("static "); Write("static ");
if (property.IsIndexer) if (property.IsIndexer)
@ -679,9 +678,9 @@ namespace CppSharp.Generators.CLI
Operators.IsBuiltinOperator(method.OperatorKind); Operators.IsBuiltinOperator(method.OperatorKind);
if (method.IsStatic || isBuiltinOperator) if (method.IsStatic || isBuiltinOperator)
Write("static "); Write("static ");
if (method.OperatorKind == CXXOperatorKind.ExplicitConversion) if (method.OperatorKind == CXXOperatorKind.ExplicitConversion)
Write("explicit "); Write("explicit ");
if (method.IsConstructor || method.IsDestructor || if (method.IsConstructor || method.IsDestructor ||
@ -705,7 +704,7 @@ namespace CppSharp.Generators.CLI
public bool GenerateTypedef(TypedefDecl typedef) public bool GenerateTypedef(TypedefDecl typedef)
{ {
if (!typedef.IsGenerated) if (!typedef.IsGenerated)
return false; return false;
FunctionType function; FunctionType function;
@ -714,20 +713,20 @@ namespace CppSharp.Generators.CLI
PushBlock(CLIBlockKind.Typedef, typedef); PushBlock(CLIBlockKind.Typedef, typedef);
GenerateDeclarationCommon(typedef); GenerateDeclarationCommon(typedef);
var insideClass = typedef.Namespace is Class; var insideClass = typedef.Namespace is Class;
var attributedType = typedef.Type.GetPointee() as AttributedType; var attributedType = typedef.Type.GetPointee() as AttributedType;
if (attributedType != null) if (attributedType != null)
{ {
var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType; var equivalentFunctionType = attributedType.Equivalent.Type as FunctionType;
var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv(); var callingConvention = equivalentFunctionType.CallingConvention.ToInteropCallConv();
if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi) if (callingConvention != System.Runtime.InteropServices.CallingConvention.Winapi)
{ {
WriteLine("[{0}({1}::{2})] ", WriteLine("[{0}({1}::{2})] ",
"System::Runtime::InteropServices::UnmanagedFunctionPointer", "System::Runtime::InteropServices::UnmanagedFunctionPointer",
"System::Runtime::InteropServices::CallingConvention", "System::Runtime::InteropServices::CallingConvention",
callingConvention); callingConvention);
} }
} }
WriteLine("{0}{1};", WriteLine("{0}{1};",
@ -744,7 +743,7 @@ namespace CppSharp.Generators.CLI
public void GenerateFunction(Function function) public void GenerateFunction(Function function)
{ {
if (!function.IsGenerated) if (!function.IsGenerated)
return; return;
PushBlock(CLIBlockKind.Function, function); PushBlock(CLIBlockKind.Function, function);
@ -763,7 +762,7 @@ namespace CppSharp.Generators.CLI
public void GenerateEnum(Enumeration @enum) public void GenerateEnum(Enumeration @enum)
{ {
if (!@enum.IsGenerated || @enum.IsIncomplete) if (!@enum.IsGenerated || @enum.IsIncomplete)
return; return;
PushBlock(CLIBlockKind.Enum, @enum); PushBlock(CLIBlockKind.Enum, @enum);

75
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -60,7 +60,7 @@ namespace CppSharp.Generators.CLI
{ {
PushBlock(CLIBlockKind.IncludesForwardReferences); PushBlock(CLIBlockKind.IncludesForwardReferences);
var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, Driver.Options); var typeReferenceCollector = new CLITypeReferenceCollector(Driver.TypeDatabase, Driver.Options);
typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false); typeReferenceCollector.Process(TranslationUnit, filterNamespaces: false);
var includes = new SortedSet<string>(StringComparer.InvariantCulture); var includes = new SortedSet<string>(StringComparer.InvariantCulture);
@ -139,7 +139,7 @@ namespace CppSharp.Generators.CLI
GenerateClassConstructors(@class); GenerateClassConstructors(@class);
foreach (var method in @class.Methods) foreach (var method in @class.Methods)
{ {
if (ASTUtils.CheckIgnoreMethod(method, Options)) if (ASTUtils.CheckIgnoreMethod(method, Options))
continue; continue;
@ -205,10 +205,15 @@ namespace CppSharp.Generators.CLI
GenerateClassConstructor(@class, isIntPtr: false); GenerateClassConstructor(@class, isIntPtr: false);
GenerateClassConstructor(@class, isIntPtr: true); GenerateClassConstructor(@class, isIntPtr: true);
if (@class.IsRefType) if (Options.GenerateFinalizers && @class.IsRefType)
{ {
GenerateClassDestructor(@class); var destructor = @class.Destructors
GenerateClassFinalizer(@class); .FirstOrDefault(d => d.Parameters.Count == 0 && d.Access == AccessSpecifier.Public);
if (destructor != null)
{
GenerateClassDestructor(@class);
GenerateClassFinalizer(@class);
}
} }
} }
@ -229,9 +234,6 @@ namespace CppSharp.Generators.CLI
private void GenerateClassDestructor(Class @class) private void GenerateClassDestructor(Class @class)
{ {
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Destructor); PushBlock(CLIBlockKind.Destructor);
WriteLine("{0}::~{1}()", QualifiedIdentifier(@class), @class.Name); WriteLine("{0}::~{1}()", QualifiedIdentifier(@class), @class.Name);
@ -247,9 +249,6 @@ namespace CppSharp.Generators.CLI
private void GenerateClassFinalizer(Class @class) private void GenerateClassFinalizer(Class @class)
{ {
if (!Options.GenerateFinalizers)
return;
PushBlock(CLIBlockKind.Finalizer); PushBlock(CLIBlockKind.Finalizer);
WriteLine("{0}::!{1}()", QualifiedIdentifier(@class), @class.Name); WriteLine("{0}::!{1}()", QualifiedIdentifier(@class), @class.Name);
@ -327,37 +326,37 @@ namespace CppSharp.Generators.CLI
GeneratePropertyGetter(property.GetMethod, realOwner, property.Name, GeneratePropertyGetter(property.GetMethod, realOwner, property.Name,
property.Type); property.Type);
if (property.HasSetter) if (property.HasSetter)
if (property.IsIndexer) if (property.IsIndexer)
GeneratePropertySetter(property.SetMethod, realOwner, property.Name, GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type, property.GetMethod.Parameters[0]); property.Type, property.GetMethod.Parameters[0]);
else else
GeneratePropertySetter(property.SetMethod, realOwner, property.Name, GeneratePropertySetter(property.SetMethod, realOwner, property.Name,
property.Type); property.Type);
} }
PopBlock(); PopBlock();
} }
private void GeneratePropertySetter<T>(T decl, Class @class, string name, Type type, Parameter indexParameter = null) private void GeneratePropertySetter<T>(T decl, Class @class, string name, Type type, Parameter indexParameter = null)
where T : Declaration, ITypedDecl where T : Declaration, ITypedDecl
{ {
if (decl == null) if (decl == null)
return; return;
var args = new List<string>(); var args = new List<string>();
var isIndexer = indexParameter != null; var isIndexer = indexParameter != null;
if (isIndexer) if (isIndexer)
args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name)); args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name));
var function = decl as Function; var function = decl as Function;
var argName = function != null && !isIndexer ? function.Parameters[0].Name : "value"; var argName = function != null && !isIndexer ? function.Parameters[0].Name : "value";
args.Add(string.Format("{0} {1}", type, argName)); args.Add(string.Format("{0} {1}", type, argName));
WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class), WriteLine("void {0}::{1}::set({2})", QualifiedIdentifier(@class),
name, string.Join(", ", args)); name, string.Join(", ", args));
WriteStartBraceIndent(); WriteStartBraceIndent();
if (decl is Function && !isIndexer) if (decl is Function && !isIndexer)
{ {
var func = decl as Function; var func = decl as Function;
@ -418,11 +417,11 @@ namespace CppSharp.Generators.CLI
var isIndexer = method != null && var isIndexer = method != null &&
method.OperatorKind == CXXOperatorKind.Subscript; method.OperatorKind == CXXOperatorKind.Subscript;
var args = new List<string>(); var args = new List<string>();
if (isIndexer) if (isIndexer)
{ {
var indexParameter = method.Parameters[0]; var indexParameter = method.Parameters[0];
args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name)); args.Add(string.Format("{0} {1}", indexParameter.Type, indexParameter.Name));
} }
WriteLine("{0} {1}::{2}::get({3})", type, QualifiedIdentifier(@class), WriteLine("{0} {1}::{2}::get({3})", type, QualifiedIdentifier(@class),
@ -628,7 +627,7 @@ namespace CppSharp.Generators.CLI
{ {
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared))
{ {
GenerateStructMarshaling(@base.Class, nativeVar); GenerateStructMarshaling(@base.Class, nativeVar);
} }
foreach (var property in @class.Properties.Where( p => !ASTUtils.CheckIgnoreProperty(p))) foreach (var property in @class.Properties.Where( p => !ASTUtils.CheckIgnoreProperty(p)))
@ -779,7 +778,7 @@ namespace CppSharp.Generators.CLI
{ {
foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared)) foreach (var @base in @class.Bases.Where(b => b.IsClass && b.Class.IsDeclared))
{ {
GenerateValueTypeConstructorCallProperties(@base.Class); GenerateValueTypeConstructorCallProperties(@base.Class);
} }
foreach (var property in @class.Properties) foreach (var property in @class.Properties)
@ -811,8 +810,8 @@ namespace CppSharp.Generators.CLI
GenerateDeclarationCommon(function); GenerateDeclarationCommon(function);
var classSig = string.Format("{0}::{1}", QualifiedIdentifier(@namespace), var classSig = string.Format("{0}::{1}", QualifiedIdentifier(@namespace),
TranslationUnit.FileNameWithoutExtension); TranslationUnit.FileNameWithoutExtension);
Write("{0} {1}::{2}(", function.ReturnType, classSig, Write("{0} {1}::{2}(", function.ReturnType, classSig,
function.Name); function.Name);

1
src/Parser/Parser.cpp

@ -1900,6 +1900,7 @@ void Parser::WalkFunction(clang::FunctionDecl* FD, CppSharp::AST::Function^ F,
P->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &PTL)); P->QualifiedType = GetQualifiedType(VD->getType(), WalkType(VD->getType(), &PTL));
P->HasDefaultValue = VD->hasDefaultArg(); P->HasDefaultValue = VD->hasDefaultArg();
P->Namespace = NS; P->Namespace = NS;
P->Index = VD->getFunctionScopeIndex();
HandleDeclaration(VD, P); HandleDeclaration(VD, P);
F->Parameters->Add(P); F->Parameters->Add(P);

6
tests/CLITemp/CLITemp.cs

@ -11,6 +11,12 @@ namespace CppSharp.Tests
{ {
} }
public override void Setup(Driver driver)
{
driver.Options.GenerateFinalizers = true;
base.Setup(driver);
}
public override void Preprocess(Driver driver, ASTContext ctx) public override void Preprocess(Driver driver, ASTContext ctx)
{ {
} }

9
tests/CLITemp/CLITemp.h

@ -15,3 +15,12 @@ struct DLL_API Types
typedef int AttributedFuncType(int, int) ATTR; typedef int AttributedFuncType(int, int) ATTR;
AttributedFuncType AttributedSum; AttributedFuncType AttributedSum;
}; };
// Tests code generator to not generate a destructor/finalizer pair
// if the destructor of the C++ class is not public.
class DLL_API TestProtectedDestructors
{
~TestProtectedDestructors();
};
TestProtectedDestructors::~TestProtectedDestructors() {}

22
tests/Native/AST.h

@ -0,0 +1,22 @@
// Tests assignment of AST.Parameter properties
void TestParameterProperties(bool a, const short& b, int* c = nullptr) {};
// Tests various AST helper methods (like FindClass, FindOperator etc.)
namespace Math
{
// Tests FindClass("Math::Complex")
struct Complex {
Complex(double r, double i) : re(r), im(i) {}
Complex operator+(Complex &other);
private:
double re, im;
};
// Tests FindTypedef("Math::Single")
typedef float Single;
// Tests FindOperator method
Complex Complex::operator+(Complex &other) {
return Complex(re + other.re, im + other.im);
}
}
Loading…
Cancel
Save