I tried parsing C++ methods using libClang, but when trying to get the parameters/arguments of functions, it gives the wrong types sometimes.
Example:
I have two separate methods
std::string Method::exportMethod(std::map<std::string, std::string> &defines) const
and
std::string Field::exportField(std::map<std::string, std::string> &defines) const
and I print the AST (for debugging purposes) with
CXChildVisitResult printer::printVisitor(CXCursor c, CXCursor parent, CXClientData clientData) {
recursivePrintData data = *static_cast<recursivePrintData *>(clientData);
*(data.stream) <<
data.indent <<
clang_getCursorKindSpelling(clang_getCursorKind(c)) <<
"; name: " << clang_getCursorSpelling(c) <<
", type: " << clang_getCursorType(c) <<
", arg0Type: " << clang_getArgType(clang_getCursorType(c), 0) <<
std::endl;
recursivePrintData newDat(data);
data.indent += " ";
clang_visitChildren(c, printVisitor, (void *) &data);
return CXChildVisit_Recurse;
}
(recursivePrintData is a struct containing the output stream and the current indentation level)
For the two methods the outputs are the following:
exportMethod:
CXXMethod; name: exportMethod, type: std::string (int &) const, arg0Type: int &
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
ParmDecl; name: defines, type: int &, arg0Type:
exportField:
CXXMethod; name: exportField, type: std::string (std::map<std::string, std::string> &) const, arg0Type: std::map<std::string, std::string> &
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
ParmDecl; name: defines, type: std::map<std::string, std::string> &, arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TemplateRef; name: map, type: , arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TemplateRef; name: map, type: , arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
NamespaceRef; name: std, type: , arg0Type:
TypeRef; name: std::string, type: std::string, arg0Type:
Even though the two methods are essentially the same (apart from the name), it incorrectly detects the argument of the first one as an integer reference, while it correctly handles the second one. What could be causing this?
I know this question is 9 months old, but in case anyone else stumbles across this... I struggled with this too, until I realized that I was missing the diagnostic messages that libclang was emitting. The default type for everything in clang is int
, so if your call to clang_parseTranslationUnit
is missing an include path or something else fails (but not a fatal failure), the parsed (but undefined) types default to int
. To resolve this: after you parse the translation unit, make a call to a function like this one (warnings might be alright, that's up to you):
oid printDiagnostics(CXTranslationUnit translationUnit){
int nbDiag = clang_getNumDiagnostics(translationUnit);
printf("There are %i diagnostics:\n",nbDiag);
bool foundError = false;
for (unsigned int currentDiag = 0; currentDiag < nbDiag; ++currentDiag) {
CXDiagnostic diagnotic = clang_getDiagnostic(translationUnit, currentDiag);
CXString errorString = clang_formatDiagnostic(diagnotic,clang_defaultDiagnosticDisplayOptions());
std::string tmp{clang_getCString(errorString)};
clang_disposeString(errorString);
if (tmp.find("error:") != std::string::npos) {
foundError = true;
}
std::cerr << tmp << std::endl;
}
if (foundError) {
std::cerr << "Please resolve these issues and try again." <<std::endl;
exit(-1);
}
}