Skip to content
Permalink
Browse files

Adding a test and rewriting ClangSharpPInvokeGenerator to use the new…

… extensions
  • Loading branch information...
tannergooding committed Apr 24, 2019
1 parent 232aee0 commit e0b4acbe3cfcff173e9323dea9cca32d2cda8147
@@ -36,5 +36,35 @@ public void Basic(string name)
Directory.Delete(dir, true);
}
}

[Theory]
[InlineData("basic")]
[InlineData("example with spaces")]
[InlineData("")]
public void BasicWrapper(string name)
{
// Create a unique directory
var dir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(dir);

try
{
// Create a file with the right name
var file = new FileInfo(Path.Combine(dir, name + ".c"));
File.WriteAllText(file.FullName, "int main() { return 0; }");

var index = CXIndex.Create();
var translationUnit = CXTranslationUnit.Parse(index, file.FullName, Array.Empty<string>(), Array.Empty<CXUnsavedFile>(), CXTranslationUnit_Flags.CXTranslationUnit_None);
var clangFile = translationUnit.GetFile(file.FullName);
var clangFileName = clangFile.Name;
var clangFileNameString = clangFileName.CString;

Assert.Equal(file.FullName, clangFileNameString);
}
finally
{
Directory.Delete(dir, true);
}
}
}
}
@@ -23,11 +23,11 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
return CXChildVisitResult.CXChildVisit_Continue;
}

CXCursorKind curKind = clang.getCursorKind(cursor);
CXCursorKind curKind = cursor.Kind;
if (curKind == CXCursorKind.CXCursor_EnumDecl)
{
string inheritedEnumType;
CXTypeKind kind = clang.getEnumDeclIntegerType(cursor).kind;
CXTypeKind kind = cursor.EnumDecl_IntegerType.kind;

switch (kind)
{
@@ -65,11 +65,11 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
bool hasOneValue = false;
long minValue = long.MaxValue;
long maxValue = long.MinValue;
clang.visitChildren(cursor, (cxCursor, _, __) =>
cursor.VisitChildren((cxCursor, _, __) =>
{
hasOneValue = true;

long value = clang.getEnumConstantDeclValue(cxCursor);
long value = cxCursor.EnumConstantDeclValue;
minValue = Math.Min(minValue, value);
maxValue = Math.Max(maxValue, value);

@@ -82,16 +82,16 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
}
}

var enumName = clang.getCursorSpelling(cursor).ToString();
var enumName = cursor.Spelling.ToString();

// enumName can be empty because of typedef enum { .. } enumName;
// so we have to find the sibling, and this is the only way I've found
// to do with libclang, maybe there is a better way?
if (string.IsNullOrEmpty(enumName))
{
var forwardDeclaringVisitor = new ForwardDeclarationVisitor(cursor);
clang.visitChildren(clang.getCursorLexicalParent(cursor), forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero));
enumName = clang.getCursorSpelling(forwardDeclaringVisitor.ForwardDeclarationCursor).ToString();
cursor.LexicalParent.VisitChildren(forwardDeclaringVisitor.Visit, new CXClientData(IntPtr.Zero));
enumName = forwardDeclaringVisitor.ForwardDeclarationCursor.Spelling.ToString();

if (string.IsNullOrEmpty(enumName))
{
@@ -111,9 +111,9 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
this.tw.WriteLine(" {");

// visit all the enum values
clang.visitChildren(cursor, (cxCursor, _, __) =>
cursor.VisitChildren((cxCursor, _, __) =>
{
this.tw.WriteLine(" @" + clang.getCursorSpelling(cxCursor).ToString() + " = " + clang.getEnumConstantDeclValue(cxCursor) + ",");
this.tw.WriteLine(" @" + cxCursor.Spelling.ToString() + " = " + cxCursor.EnumConstantDeclValue + ",");
return CXChildVisitResult.CXChildVisit_Continue;
}, new CXClientData(IntPtr.Zero));

@@ -9,28 +9,18 @@ internal static class Extensions
{
public static bool IsInSystemHeader(this CXCursor cursor)
{
return clang.Location_isInSystemHeader(clang.getCursorLocation(cursor)) != 0;
return cursor.Location.IsInSystemHeader;
}

public static bool IsPtrToConstChar(this CXType type)
{
var pointee = clang.getPointeeType(type);

if (clang.isConstQualifiedType(pointee) != 0)
{
switch (pointee.kind)
{
case CXTypeKind.CXType_Char_S:
return true;
}
}

return false;
var pointee = type.PointeeType;
return pointee.IsConstQualified && (pointee.kind == CXTypeKind.CXType_Char_S);
}

public static string ToPlainTypeString(this CXType type, string unknownType = "UnknownType")
{
var canonical = clang.getCanonicalType(type);
var canonical = type.CanonicalType;;
switch (type.kind)
{
case CXTypeKind.CXType_Bool:
@@ -69,7 +59,7 @@ public static string ToPlainTypeString(this CXType type, string unknownType = "U
case CXTypeKind.CXType_Unexposed:
if (canonical.kind == CXTypeKind.CXType_Unexposed)
{
return clang.getTypeSpelling(canonical).ToString();
return canonical.Spelling.ToString();
}
return canonical.ToPlainTypeString();
default:
@@ -79,13 +69,13 @@ public static string ToPlainTypeString(this CXType type, string unknownType = "U

public static string ToMarshalString(this CXCursor cursor, string cursorSpelling)
{
var canonical = clang.getCanonicalType(clang.getCursorType(cursor));
var canonical = cursor.Type.CanonicalType;

switch (canonical.kind)
{
case CXTypeKind.CXType_ConstantArray:
long arraySize = clang.getArraySize(canonical);
var elementType = clang.getCanonicalType(clang.getArrayElementType(canonical));
long arraySize = canonical.ArraySize;
var elementType = canonical.ArrayElementType.CanonicalType;

var sb = new StringBuilder();
for (int i = 0; i < arraySize; ++i)
@@ -95,7 +85,7 @@ public static string ToMarshalString(this CXCursor cursor, string cursorSpelling

return sb.ToString().TrimEnd();
case CXTypeKind.CXType_Pointer:
var pointeeType = clang.getCanonicalType(clang.getPointeeType(canonical));
var pointeeType = canonical.PointeeType.CanonicalType;
switch (pointeeType.kind)
{
case CXTypeKind.CXType_Char_S:
@@ -107,17 +97,17 @@ public static string ToMarshalString(this CXCursor cursor, string cursorSpelling
}
case CXTypeKind.CXType_Record:
case CXTypeKind.CXType_Enum:
return "public " + clang.getTypeSpelling(canonical).ToString() + " @" + cursorSpelling + ";";
return "public " + canonical.Spelling.ToString() + " @" + cursorSpelling + ";";
default:
return "public " + canonical.ToPlainTypeString() + " @" + cursorSpelling + ";";
}
}

public static void WriteFunctionInfoHelper(CXCursor cursor, TextWriter tw, string prefixStrip)
{
var functionType = clang.getCursorType(cursor);
var functionName = clang.getCursorSpelling(cursor).ToString();
var resultType = clang.getCursorResultType(cursor);
var functionType = cursor.Type;
var functionName = cursor.Spelling.ToString();
var resultType = cursor.ResultType;

tw.WriteLine(" [DllImport(libraryPath, EntryPoint = \"" + functionName + "\", CallingConvention = " + functionType.CallingConventionSpelling() + ")]");
if (resultType.IsPtrToConstChar())
@@ -134,11 +124,11 @@ public static void WriteFunctionInfoHelper(CXCursor cursor, TextWriter tw, strin

tw.Write(" " + functionName + "(");

int numArgTypes = clang.getNumArgTypes(functionType);
int numArgTypes = functionType.NumArgTypes;

for (uint i = 0; i < numArgTypes; ++i)
{
ArgumentHelper(functionType, clang.Cursor_getArgument(cursor, i), tw, i);
ArgumentHelper(functionType, cursor.GetArgument(i), tw, i);
}

tw.WriteLine(");");
@@ -147,7 +137,7 @@ public static void WriteFunctionInfoHelper(CXCursor cursor, TextWriter tw, strin

public static string CallingConventionSpelling(this CXType type)
{
var callingConvention = clang.getFunctionTypeCallingConv(type);
var callingConvention = type.FunctionTypeCallingConv;
switch (callingConvention)
{
case CXCallingConv.CXCallingConv_X86StdCall:
@@ -173,11 +163,11 @@ public static void ReturnTypeHelper(CXType resultType, TextWriter tw)

public static void ArgumentHelper(CXType functionType, CXCursor paramCursor, TextWriter tw, uint index)
{
var numArgTypes = clang.getNumArgTypes(functionType);
var type = clang.getArgType(functionType, index);
var cursorType = clang.getCursorType(paramCursor);
var numArgTypes = functionType.NumArgTypes;
var type = functionType.GetArgType(index);
var cursorType = paramCursor.Type;

var spelling = clang.getCursorSpelling(paramCursor).ToString();
var spelling = paramCursor.Spelling.ToString();
if (string.IsNullOrEmpty(spelling))
{
spelling = "param" + index;
@@ -186,14 +176,14 @@ public static void ArgumentHelper(CXType functionType, CXCursor paramCursor, Tex
switch (type.kind)
{
case CXTypeKind.CXType_Pointer:
var pointee = clang.getPointeeType(type);
var pointee = type.PointeeType;
switch (pointee.kind)
{
case CXTypeKind.CXType_Pointer:
tw.Write(pointee.IsPtrToConstChar() && clang.isConstQualifiedType(pointee) != 0 ? "string[]" : "out IntPtr");
tw.Write(pointee.IsPtrToConstChar() && pointee.IsConstQualified ? "string[]" : "out IntPtr");
break;
case CXTypeKind.CXType_FunctionProto:
tw.Write(clang.getTypeSpelling(cursorType).ToString());
tw.Write(cursorType.Spelling.ToString());
break;
case CXTypeKind.CXType_Void:
tw.Write("IntPtr");
@@ -225,23 +215,23 @@ public static void ArgumentHelper(CXType functionType, CXCursor paramCursor, Tex

private static void CommonTypeHandling(CXType type, TextWriter tw, string outParam = "")
{
bool isConstQualifiedType = clang.isConstQualifiedType(type) != 0;
bool isConstQualifiedType = type.IsConstQualified;
string spelling;

switch (type.kind)
{
// Need to unwrap elaborated types
case CXTypeKind.CXType_Elaborated:
CommonTypeHandling(clang.Type_getNamedType(type), tw, outParam);
CommonTypeHandling(type.NamedType, tw, outParam);
return;
case CXTypeKind.CXType_Typedef:
var cursor = clang.getTypeDeclaration(type);
var location = clang.getCursorLocation(cursor);
var cursor = type.Declaration;
var location = cursor.Location;

// For some reason size_t isn't considered as within a system header.
// We work around this by asking for the file name - if it's unknown, probably it's a system header
var isInSystemHeader = clang.Location_isInSystemHeader(clang.getCursorLocation(cursor)) != 0;
clang.getPresumedLocation(clang.getCursorLocation(cursor), out CXString @filename, out uint @line, out uint @column);
var isInSystemHeader = cursor.IsInSystemHeader();
cursor.Location.GetPresumedLocation(out CXString @filename, out uint @line, out uint @column);
isInSystemHeader |= filename.ToString() == string.Empty;

if (isInSystemHeader)
@@ -250,37 +240,37 @@ private static void CommonTypeHandling(CXType type, TextWriter tw, string outPar
// Getting the actual type of a typedef is painful, since platforms don't even agree on the meaning of types;
// 64-bit is "long long" on Windows but "long" on Linux, for historical reasons.
// The easiest way is to just get the size & signed-ness and write the type ourselves
var size = clang.Type_getSizeOf(type);
var signed = !clang.getTypedefDeclUnderlyingType(cursor).ToString().Contains("unsigned");
var size = type.SizeOf;
var signed = !cursor.TypedefDeclUnderlyingType.ToString().Contains("unsigned");
spelling = GetTypeName(size, signed);
}
else
{
spelling = clang.getCursorSpelling(cursor).ToString();
spelling = cursor.Spelling.ToString();
}
break;
case CXTypeKind.CXType_Record:
case CXTypeKind.CXType_Enum:
spelling = clang.getTypeSpelling(type).ToString();
spelling = type.Spelling.ToString();
break;
case CXTypeKind.CXType_IncompleteArray:
CommonTypeHandling(clang.getArrayElementType(type), tw);
CommonTypeHandling(type.ArrayElementType, tw);
spelling = "[]";
break;
case CXTypeKind.CXType_Unexposed: // Often these are enums and canonical type gets you the enum spelling
var canonical = clang.getCanonicalType(type);
var canonical = type.CanonicalType;
// unexposed decl which turns into a function proto seems to be an un-typedef'd fn pointer
if (canonical.kind == CXTypeKind.CXType_FunctionProto)
{
spelling = "IntPtr";
}
else
{
spelling = clang.getTypeSpelling(canonical).ToString();
spelling = canonical.Spelling.ToString();
}
break;
default:
spelling = clang.getCanonicalType(type).ToPlainTypeString();
spelling = type.CanonicalType.ToPlainTypeString();
break;
}

@@ -23,7 +23,7 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
return CXChildVisitResult.CXChildVisit_Continue;
}

if (clang.equalCursors(cursor, this.beginningCursor) != 0)
if (cursor.Equals(beginningCursor))
{
this.beginningCursorReached = true;
return CXChildVisitResult.CXChildVisit_Continue;
@@ -37,12 +37,12 @@ public CXChildVisitResult Visit(CXCursor cursor, CXCursor parent, IntPtr data)
return CXChildVisitResult.CXChildVisit_Continue;
}

CXCursorKind curKind = clang.getCursorKind(cursor);
CXCursorKind curKind = cursor.kind;

// look only at function decls
if (curKind == CXCursorKind.CXCursor_FunctionDecl)
{
var functionName = clang.getCursorSpelling(cursor).ToString();
var functionName = cursor.Spelling.ToString();

if (this.visitedFunctions.Contains(functionName))
{
Oops, something went wrong.

0 comments on commit e0b4acb

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