Skip to content
Permalink
Browse files

Minor fixups to provide better diagnostics and notes on what should b…

…e done. (#47)

* Some minor fixups to try and ensure we handle things appropriately

* Print diagnostics so users know when there are potential parsing issues.
  • Loading branch information...
tannergooding committed May 12, 2019
1 parent 0d6204a commit 7c45035494ab335b90c2a813fcd456f58732d272
@@ -8,10 +8,19 @@ public AttachedFunctionDeclData(int parmCount)
{
Debug.Assert(parmCount != -1);

IsDeprecated = false;
IsDllExport = false;
IsDllImport = false;
ParmCount = parmCount;
RemainingParmCount = parmCount;
}

public bool IsDeprecated { get; set; }

public bool IsDllExport { get; set; }

public bool IsDllImport { get; set; }

public int ParmCount { get; }

public int RemainingParmCount { get; set; }
@@ -52,6 +52,19 @@ public CXChildVisitResult VisitDeclRefExpr(CXCursor cursor, CXCursor parent, CXC
}
}

public CXChildVisitResult VisitDLLExport(CXCursor cursor, CXCursor parent, CXClientData data)
{
Debug.Assert(parent.Kind == CXCursorKind.CXCursor_DLLExport);

switch (cursor.Kind)
{
default:
{
return Unhandled(cursor, parent);
}
}
}

public CXChildVisitResult VisitDLLImport(CXCursor cursor, CXCursor parent, CXClientData data)
{
Debug.Assert(parent.Kind == CXCursorKind.CXCursor_DLLImport);
@@ -170,14 +183,14 @@ public CXChildVisitResult VisitFunctionDecl(CXCursor cursor, CXCursor parent, CX
return Handle(VisitTypeRef, cursor, parent, data);
}

case CXCursorKind.CXCursor_CompoundStmt:
case CXCursorKind.CXCursor_UnexposedAttr:
{
return CXChildVisitResult.CXChildVisit_Continue;
return Handle(VisitUnexposedAttr, cursor, parent, data);
}

case CXCursorKind.CXCursor_UnexposedAttr:
case CXCursorKind.CXCursor_DLLExport:
{
return Handle(VisitUnexposedAttr, cursor, parent, data);
return Handle(VisitDLLExport, cursor, parent, data);
}

case CXCursorKind.CXCursor_DLLImport:
@@ -295,6 +308,11 @@ public CXChildVisitResult VisitTranslationUnit(CXCursor cursor, CXCursor parent,
return Handle(VisitTypedefDecl, cursor, parent, data);
}

case CXCursorKind.CXCursor_VarDecl:
{
return Handle(VisitVarDecl, cursor, parent, data);
}

default:
{
return Unhandled(cursor, parent);
@@ -412,7 +430,7 @@ public CXChildVisitResult VisitUnexposedDecl(CXCursor cursor, CXCursor parent, C

case CXCursorKind.CXCursor_VarDecl:
{
return CXChildVisitResult.CXChildVisit_Continue;
return Handle(VisitVarDecl, cursor, parent, data);
}

default:
@@ -440,6 +458,19 @@ public CXChildVisitResult VisitUnexposedExpr(CXCursor cursor, CXCursor parent, C
}
}

public CXChildVisitResult VisitVarDecl(CXCursor cursor, CXCursor parent, CXClientData data)
{
Debug.Assert(parent.Kind == CXCursorKind.CXCursor_VarDecl);

switch (cursor.Kind)
{
default:
{
return Unhandled(cursor, parent);
}
}
}

protected virtual bool BeginHandle(CXCursor cursor, CXCursor parent)
{
return true;
@@ -141,9 +141,18 @@ protected override bool BeginHandle(CXCursor cursor, CXCursor parent)
}

case CXCursorKind.CXCursor_UnexposedAttr:
{
return BeginHandleUnexposedAttr(cursor, parent);
}

case CXCursorKind.CXCursor_DLLExport:
{
return BeginHandleDLLExport(cursor, parent);
}

case CXCursorKind.CXCursor_DLLImport:
{
return false;
return BeginHandleDLLImport(cursor, parent);
}

default:
@@ -179,6 +188,7 @@ protected override void EndHandle(CXCursor cursor, CXCursor parent)
case CXCursorKind.CXCursor_DeclRefExpr:
case CXCursorKind.CXCursor_IntegerLiteral:
case CXCursorKind.CXCursor_UnexposedAttr:
case CXCursorKind.CXCursor_DLLExport:
case CXCursorKind.CXCursor_DLLImport:
{
clearOutputBuilder = false;
@@ -373,6 +383,38 @@ private bool BeginHandleDeclRefExpr(CXCursor cursor, CXCursor parent)
}
}

private bool BeginHandleDLLExport(CXCursor cursor, CXCursor parent)
{
Debug.Assert(cursor.Kind == CXCursorKind.CXCursor_DLLExport);

if (_attachedData.TryGetValue(parent, out var data) && (data is AttachedFunctionDeclData functionDeclData))
{
functionDeclData.IsDllExport = true;
return true;
}
else
{
Unhandled(cursor, parent);
return false;
}
}

private bool BeginHandleDLLImport(CXCursor cursor, CXCursor parent)
{
Debug.Assert(cursor.Kind == CXCursorKind.CXCursor_DLLImport);

if (_attachedData.TryGetValue(parent, out var data) && (data is AttachedFunctionDeclData functionDeclData))
{
functionDeclData.IsDllImport = true;
return true;
}
else
{
Unhandled(cursor, parent);
return false;
}
}

private bool BeginHandleEnumConstantDecl(CXCursor cursor, CXCursor parent)
{
Debug.Assert(cursor.Kind == CXCursorKind.CXCursor_EnumConstantDecl);
@@ -509,6 +551,11 @@ private bool BeginHandleFunctionDecl(CXCursor cursor, CXCursor parent)
}
InitializeOutputBuilder(_config.MethodClassName);

// TODO: We should probably build the function declaration in the attached data
// and ultimately print it out when we are done handling everything. This would
// allow us to validate things like "is it a valid dll import" or add additional
// information like "is it deprecated".

_attachedData.Add(cursor, new AttachedFunctionDeclData(type.NumArgTypes));

_outputBuilder.AddUsing("System.Runtime.InteropServices");
@@ -662,6 +709,7 @@ private bool BeginHandleParmDecl(CXCursor cursor, CXCursor parent)
}
else if ((parent.Kind == CXCursorKind.CXCursor_FieldDecl) || (parent.Kind == CXCursorKind.CXCursor_ParmDecl))
{
// TODO: We should properly handle inline function pointers for fields and method parameters
return true;
}
else
@@ -889,6 +937,7 @@ private bool BeginHandleTypeRef(CXCursor cursor, CXCursor parent)
}
else
{
// TODO: Should probably have more checks around the type ref to ensure we don't miss anything
return true;
}
}
@@ -932,6 +981,47 @@ private bool BeginHandleUnaryOperator(CXCursor cursor, CXCursor parent)
}
}

private bool BeginHandleUnexposedAttr(CXCursor cursor, CXCursor parent)
{
Debug.Assert(cursor.Kind == CXCursorKind.CXCursor_UnexposedAttr);

if (_attachedData.TryGetValue(parent, out var data) && (data is AttachedFunctionDeclData functionDeclData))
{
var translationUnit = cursor.TranslationUnit;
translationUnit.Tokenize(cursor.Extent, out CXToken[] tokens);

if (tokens is null)
{
var token = translationUnit.GetToken(cursor.Location);
Debug.Assert(!token.Equals(default(CXToken)));
tokens = new CXToken[] { token };
}
Debug.Assert(tokens.Length == 1);

if (tokens[0].Kind != CXTokenKind.CXToken_Identifier)
{
Unhandled(cursor, parent);
return false;
}

var identifier = tokens[0].GetSpelling(translationUnit).ToString();

if (identifier != "deprecated")
{
Unhandled(cursor, parent);
return false;
}

functionDeclData.IsDeprecated = true;
return true;
}
else
{
Unhandled(cursor, parent);
return false;
}
}

private bool BeginHandleUnexposedDecl(CXCursor cursor, CXCursor parent)
{
if (_attachedData.TryGetValue(parent, out var data))
@@ -941,6 +1031,9 @@ private bool BeginHandleUnexposedDecl(CXCursor cursor, CXCursor parent)
}
else
{
// TODO: We should validate the type of unexposed decl. It looks like these are
// normally just extern "C" declarations.

if (_predicatedCursors.TryPeek(out var activeCursor) && activeCursor.Equals(cursor))
{
_predicatedCursors.Pop();
@@ -959,6 +1052,8 @@ private bool BeginHandleUnexposedExpr(CXCursor cursor, CXCursor parent)
}
else
{
// TODO: We should probably check the type of unexposed expression

if (parent.Kind == CXCursorKind.CXCursor_EnumConstantDecl)
{
_outputBuilder.Write(" = ");
@@ -1567,6 +1662,11 @@ private string GetTypeName(CXCursor cursor, CXType type)
return "ulong";
}

case CXTypeKind.CXType_Char_S:
{
return "sbyte";
}

case CXTypeKind.CXType_WChar:
{
return "char";
@@ -83,13 +83,18 @@ public static int Run(InvocationContext context)
return -1;
}

string[] arr = { "-x", "c++" };
var arr = new string[]
{
"-xc++", // The input files are C++
"-Wno-pragma-once-outside-header" // We are processing files which may be header files
};

arr = arr.Concat(includeDirs.Select(x => "-I" + x)).ToArray();
arr = arr.Concat(defines.Select(x => "-D" + x)).ToArray();
arr = arr.Concat(additionalArgs).ToArray();

var translationFlags = CXTranslationUnit_Flags.CXTranslationUnit_None;

translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_SkipFunctionBodies; // Don't traverse function bodies
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_IncludeAttributedTypes; // Include attributed types in CXType
translationFlags |= CXTranslationUnit_Flags.CXTranslationUnit_VisitImplicitAttributes; // Implicit attributes should be visited
@@ -100,20 +105,37 @@ public static int Run(InvocationContext context)
foreach (var file in files)
{
var translationUnitError = CXTranslationUnit.Parse(createIndex, file, arr, Array.Empty<CXUnsavedFile>(), translationFlags, out CXTranslationUnit translationUnit);
bool skipProcessing = false;

if (translationUnitError != CXErrorCode.CXError_Success)
{
Console.WriteLine($"Error: '{translationUnitError}' for '{file}'.");
var numDiagnostics = translationUnit.NumDiagnostics;
Console.WriteLine($"Error: Parsing failed for '{file}' due to '{translationUnitError}'.");
skipProcessing = true;
}
else if (translationUnit.NumDiagnostics != 0)
{
Console.WriteLine($"Diagnostics for '{file}':");

for (uint i = 0; i < numDiagnostics; ++i)
for (uint i = 0; i < translationUnit.NumDiagnostics; ++i)
{
var diagnostic = translationUnit.GetDiagnostic(i);
Console.WriteLine(diagnostic.Spelling.ToString());
diagnostic.Dispose();
using (var diagnostic = translationUnit.GetDiagnostic(i))
{
Console.Write(" ");
Console.WriteLine(diagnostic.Format(CXDiagnosticDisplayOptions.CXDiagnostic_DisplayOption).ToString());

skipProcessing |= (diagnostic.Severity == CXDiagnosticSeverity.CXDiagnostic_Error);
skipProcessing |= (diagnostic.Severity == CXDiagnosticSeverity.CXDiagnostic_Fatal);
}
}
}

if (skipProcessing)
{
Console.WriteLine($"Skipping '{file}' due to one or more errors listed above.");
Console.WriteLine();
continue;
}

using (translationUnit)
{
translationUnit.Cursor.VisitChildren(writer.VisitTranslationUnit, clientData: default);

0 comments on commit 7c45035

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