Skip to content
Permalink
Browse files

Support a few more statement and declaration types (#115)

* Support InitListExpr

* Support CXXConversionDecl

* Fixing spacing of VarDecls and trim unnecessary literal specifiers

* Print a diagnostic when encountering a function template

* Handle non-virtual method declarations from base classes

* Take LValueReferenceType transformations into account when visiting AddrOf unary operators

* Provide a more fine-tuned way to exclude methods and change --with-namespace to be called --with-using
  • Loading branch information
tannergooding committed Dec 6, 2019
1 parent 3d3f5d8 commit 39d7508a99d5d0c1981aae60209833b1db15b881
@@ -95,11 +95,7 @@ public void Write<T>(T value)

public void WriteIndentation()
{
if (NeedsNewline)
{
WriteLine();
}
NeedsNewline = false;
WriteNewlineIfNeeded();

for (var i = 0; i < _indentationLevel; i++)
{
@@ -125,6 +121,15 @@ public void WriteLine<T>(T value)
WriteLine();
}

public void WriteNewlineIfNeeded()
{
if (NeedsNewline)
{
WriteLine();
}
NeedsNewline = false;
}

public void WriteSemicolonIfNeeded()
{
if (NeedsSemicolon)
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ClangSharp.Interop;

namespace ClangSharp
@@ -37,6 +38,15 @@ private void VisitDecl(Decl decl)
return;
}
}
else if (decl is FunctionDecl functionDecl)
{
var fullName = GetFunctionDeclFullName(functionDecl);

if (_config.ExcludedNames.Contains(fullName))
{
return;
}
}
}

switch (decl.Kind)
@@ -86,7 +96,13 @@ private void VisitDecl(Decl decl)
// case CX_DeclKind.CX_DeclKind_BuiltinTemplate:
// case CX_DeclKind.CX_DeclKind_Concept:
// case CX_DeclKind.CX_DeclKind_ClassTemplate:
// case CX_DeclKind.CX_DeclKind_FunctionTemplate:

case CX_DeclKind.CX_DeclKind_FunctionTemplate:
{
VisitFunctionTemplateDecl((FunctionTemplateDecl)decl);
break;
}

// case CX_DeclKind.CX_DeclKind_TypeAliasTemplate:
// case CX_DeclKind.CX_DeclKind_VarTemplate:
// case CX_DeclKind.CX_DeclKind_TemplateTemplateParm:
@@ -152,13 +168,12 @@ private void VisitDecl(Decl decl)
case CX_DeclKind.CX_DeclKind_CXXMethod:
case CX_DeclKind.CX_DeclKind_CXXConstructor:
case CX_DeclKind.CX_DeclKind_CXXDestructor:
case CX_DeclKind.CX_DeclKind_CXXConversion:
{
VisitFunctionDecl((CXXMethodDecl)decl, (CXXRecordDecl)decl.DeclContext);
break;
}


// case CX_DeclKind.CX_DeclKind_CXXConversion:
// case CX_DeclKind.CX_DeclKind_MSProperty:
// case CX_DeclKind.CX_DeclKind_NonTypeTemplateParm:

@@ -394,6 +409,13 @@ private void VisitFieldDecl(FieldDecl fieldDecl)

private void VisitFunctionDecl(FunctionDecl functionDecl, CXXRecordDecl cxxRecordDecl)
{
var fullName = GetFunctionDeclFullName(functionDecl);

if (_config.ExcludedNames.Contains(fullName))
{
return;
}

var name = GetRemappedCursorName(functionDecl);

if (cxxRecordDecl is null)
@@ -404,8 +426,8 @@ private void VisitFunctionDecl(FunctionDecl functionDecl, CXXRecordDecl cxxRecor
WithAttributes("*");
WithAttributes(name);

WithNamespaces("*");
WithNamespaces(name);
WithUsings("*");
WithUsings(name);

var type = functionDecl.Type;
var callConv = CXCallingConv.CXCallingConv_Invalid;
@@ -501,7 +523,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl, CXXRecordDecl cxxRecor
{
_isMethodClassUnsafe = true;
}
else
else if (!IsUnsafe(cxxRecordDecl))
{
_outputBuilder.Write("unsafe");
_outputBuilder.Write(' ');
@@ -611,6 +633,7 @@ private void VisitFunctionDecl(FunctionDecl functionDecl, CXXRecordDecl cxxRecor
_outputBuilder.WriteBlockEnd();
}
}
_outputBuilder.NeedsNewline = true;

VisitDecls(functionDecl.Decls);

@@ -663,6 +686,11 @@ static void VisitCtorInitializers(PInvokeGenerator pinvokeGenerator, CXXConstruc
}
}

private void VisitFunctionTemplateDecl(FunctionTemplateDecl functionTemplateDecl)
{
AddDiagnostic(DiagnosticLevel.Warning, $"Function templates are not supported: '{functionTemplateDecl.Name}'. Generated bindings may be incomplete.", functionTemplateDecl);
}

private void VisitParmVarDecl(ParmVarDecl parmVarDecl)
{
var cursorParent = parmVarDecl.CursorParent;
@@ -770,7 +798,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)

if (cxxRecordDecl != null)
{
hasVtbl = HasVtbl(this, cxxRecordDecl);
hasVtbl = HasVtbl(cxxRecordDecl);
}

if (recordDecl.IsUnion)
@@ -782,7 +810,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)
_outputBuilder.WriteIndented(GetAccessSpecifierName(recordDecl));
_outputBuilder.Write(' ');

if (IsUnsafe(recordDecl) || hasVtbl)
if (IsUnsafe(recordDecl))
{
_outputBuilder.Write("unsafe");
_outputBuilder.Write(' ');
@@ -796,6 +824,7 @@ private void VisitRecordDecl(RecordDecl recordDecl)
if (hasVtbl)
{
_outputBuilder.WriteIndentedLine("public readonly Vtbl* lpVtbl;");
_outputBuilder.NeedsNewline = true;
}

if (cxxRecordDecl != null)
@@ -869,20 +898,14 @@ private void VisitRecordDecl(RecordDecl recordDecl)
_outputBuilder.NeedsNewline = true;
}

foreach (var cxxMethodDecl in cxxRecordDecl.Methods)
if (hasVtbl)
{
if (cxxMethodDecl.IsVirtual)
{
continue;
}

Visit(cxxMethodDecl);
_outputBuilder.NeedsNewline = true;
OutputDelegateSignatures(this, cxxRecordDecl, cxxRecordDecl, hitsPerName: new Dictionary<string, int>());
}

if (hasVtbl)
if (cxxRecordDecl != null)
{
OutputDelegateSignatures(this, cxxRecordDecl, cxxRecordDecl, hitsPerName: new Dictionary<string, int>());
OutputMethods(this, cxxRecordDecl, cxxRecordDecl);
}

VisitDecls(recordDecl.Decls);
@@ -965,36 +988,6 @@ static int GetBitfieldCount(PInvokeGenerator pinvokeGenerator, RecordDecl record
return count;
}

static CXXRecordDecl GetRecordDeclForBaseSpecifier(CXXBaseSpecifier cxxBaseSpecifier)
{
Type baseType = cxxBaseSpecifier.Type;
{
if (baseType is TypedefType typedefType)
{
baseType = typedefType.Decl.UnderlyingType;
}

if (baseType is ElaboratedType elaboratedType)
{
baseType = elaboratedType.CanonicalType;
}
}
{
if (baseType is TypedefType typedefType)
{
baseType = typedefType.Decl.UnderlyingType;
}

if (baseType is ElaboratedType elaboratedType)
{
baseType = elaboratedType.CanonicalType;
}
}

var baseRecordType = (RecordType)baseType;
return (CXXRecordDecl)baseRecordType.Decl;
}

static bool HasFields(PInvokeGenerator pinvokeGenerator, CXXRecordDecl cxxRecordDecl)
{
var hasFields = cxxRecordDecl.Fields.Any();
@@ -1015,50 +1008,56 @@ static bool HasFields(PInvokeGenerator pinvokeGenerator, CXXRecordDecl cxxRecord
return hasFields;
}

static bool HasVtbl(PInvokeGenerator pinvokeGenerator, CXXRecordDecl cxxRecordDecl)
static void OutputDelegateSignatures(PInvokeGenerator pinvokeGenerator, CXXRecordDecl rootCxxRecordDecl, CXXRecordDecl cxxRecordDecl, Dictionary<string, int> hitsPerName)
{
var hasDirectVtbl = cxxRecordDecl.Methods.Any((method) => method.IsVirtual);
var indirectVtblCount = 0;

foreach (var cxxBaseSpecifier in cxxRecordDecl.Bases)
{
var baseCxxRecordDecl = GetRecordDeclForBaseSpecifier(cxxBaseSpecifier);
OutputDelegateSignatures(pinvokeGenerator, rootCxxRecordDecl, baseCxxRecordDecl, hitsPerName);
}

if (HasVtbl(pinvokeGenerator, baseCxxRecordDecl))
foreach (var cxxMethodDecl in cxxRecordDecl.Methods)
{
if (!cxxMethodDecl.IsVirtual)
{
indirectVtblCount++;
continue;
}
}

if (indirectVtblCount > 1)
{
pinvokeGenerator.AddDiagnostic(DiagnosticLevel.Warning, "Unsupported cxx record declaration: 'multiple virtual bases'. Generated bindings may be incomplete.", cxxRecordDecl);
}
pinvokeGenerator._outputBuilder.NeedsNewline = true;
pinvokeGenerator._visitedDecls.Add(cxxMethodDecl);

return hasDirectVtbl || (indirectVtblCount != 0);
var remappedName = FixupNameForMultipleHits(pinvokeGenerator, cxxMethodDecl, hitsPerName);
pinvokeGenerator.VisitFunctionDecl(cxxMethodDecl, rootCxxRecordDecl);
RestoreNameForMultipleHits(pinvokeGenerator, cxxMethodDecl, hitsPerName, remappedName);
}
}

static void OutputDelegateSignatures(PInvokeGenerator pinvokeGenerator, CXXRecordDecl rootCxxRecordDecl, CXXRecordDecl cxxRecordDecl, Dictionary<string, int> hitsPerName)
static void OutputMethods(PInvokeGenerator pinvokeGenerator, CXXRecordDecl rootCxxRecordDecl, CXXRecordDecl cxxRecordDecl)
{
var outputBuilder = pinvokeGenerator._outputBuilder;

foreach (var cxxBaseSpecifier in cxxRecordDecl.Bases)
{
var baseCxxRecordDecl = GetRecordDeclForBaseSpecifier(cxxBaseSpecifier);
OutputDelegateSignatures(pinvokeGenerator, rootCxxRecordDecl, baseCxxRecordDecl, hitsPerName);
OutputMethods(pinvokeGenerator, rootCxxRecordDecl, baseCxxRecordDecl);
}

foreach (var cxxMethodDecl in cxxRecordDecl.Methods)
{
if (!cxxMethodDecl.IsVirtual)
if (cxxMethodDecl.IsVirtual)
{
continue;
}

pinvokeGenerator._outputBuilder.NeedsNewline = true;
pinvokeGenerator._visitedDecls.Add(cxxMethodDecl);

var remappedName = FixupNameForMultipleHits(pinvokeGenerator, cxxMethodDecl, hitsPerName);
pinvokeGenerator.VisitFunctionDecl(cxxMethodDecl, rootCxxRecordDecl);
RestoreNameForMultipleHits(pinvokeGenerator, cxxMethodDecl, hitsPerName, remappedName);
if (cxxRecordDecl == rootCxxRecordDecl)
{
pinvokeGenerator.Visit(cxxMethodDecl);
}
else
{
pinvokeGenerator.VisitFunctionDecl(cxxMethodDecl, rootCxxRecordDecl);
}
outputBuilder.NeedsNewline = true;
}
}

@@ -1797,9 +1796,9 @@ private void VisitVarDecl(VarDecl varDecl)
{
var cursorParent = varDecl.CursorParent;

if (cursorParent is TranslationUnitDecl translationUnitDecl)
if ((cursorParent is TranslationUnitDecl) || (cursorParent is LinkageSpecDecl))
{
VisitVarDeclForTranslationUnitDecl(varDecl, translationUnitDecl);
VisitVarDeclForTopLevelDecl(varDecl);
}
else if (cursorParent is DeclStmt declStmt)
{
@@ -1811,7 +1810,7 @@ private void VisitVarDecl(VarDecl varDecl)
}
}

private void VisitVarDeclForTranslationUnitDecl(VarDecl varDecl, TranslationUnitDecl translationUnitDecl)
private void VisitVarDeclForTopLevelDecl(VarDecl varDecl)
{
var name = GetRemappedCursorName(varDecl);

@@ -1820,8 +1819,8 @@ private void VisitVarDeclForTranslationUnitDecl(VarDecl varDecl, TranslationUnit
WithAttributes("*");
WithAttributes(name);

WithNamespaces("*");
WithNamespaces(name);
WithUsings("*");
WithUsings(name);

var type = varDecl.Type;
var typeName = GetRemappedTypeName(varDecl, type, out var nativeTypeName);
@@ -1847,6 +1846,13 @@ private void VisitVarDeclForDeclStmt(VarDecl varDecl, DeclStmt declStmt)
var typeName = GetRemappedTypeName(varDecl, type, out var nativeTypeName);

_outputBuilder.Write(typeName);

if (type is ArrayType)
{
_outputBuilder.Write('[');
_outputBuilder.Write(']');
}

_outputBuilder.Write(' ');
}

0 comments on commit 39d7508

Please sign in to comment.
You can’t perform that action at this time.