I'm trying to parse a single C++ file that looks as follows:
#include <memory>
#include <string>
#include "foo.h"
std::unique_ptr<wchar_t[]> FooBar::baz(std::wstring const& text)
{
auto result = std::make_unique<wchar_t[]>(text.length() + 1);
std::copy(text.begin(), text.end(), result.get());
result.get()[text.length()] = 0;
return result;
}
int main(int argc, char* argv[])
{
return 0;
}
To parse the file, I use libclang:
#include "clang-c/Index.h"
#include <iostream>
CXChildVisitResult visitor(CXCursor cursor, CXCursor, CXClientData) {
CXCursorKind kind = clang_getCursorKind(cursor);
// Consider functions and methods
if (kind == CXCursorKind::CXCursor_FunctionDecl ||
kind == CXCursorKind::CXCursor_CXXMethod) {
auto cursorName = clang_getCursorDisplayName(cursor);
std::cout << "Found Function: " << clang_getCString(cursorName) << std::endl;
clang_disposeString(cursorName);
}
return CXChildVisit_Recurse;
}
int main(int argc, char* argv[])
{
CXIndex index = clang_createIndex(
/* excludeDeclsFromPCH */1,
/* displayDiagnostics=*/1
);
constexpr const char* defaultArguments[] = {
"-std=c++17",
"-ferror-limit=0",
};
CXTranslationUnit TU = clang_parseTranslationUnit(
index,
"C:\\PATH\\TO\\test.cpp",
/*command_line_args=*/defaultArguments,
/*num_command_line_args=*/std::extent<decltype(defaultArguments)>::value,
/*unsaved_files=*/nullptr,
/*num_unsaved_files=*/0,
CXTranslationUnit_SingleFileParse | CXTranslationUnit_KeepGoing
);
CXCursor cursor = clang_getTranslationUnitCursor(TU);
clang_visitChildren(
cursor,
visitor,
nullptr);
clang_disposeTranslationUnit(TU);
clang_disposeIndex(index);
return 0;
}
The output is:
test.cpp:3:10: error: 'foo.h' file not found
test.cpp:5:1: error: use of undeclared identifier 'std'
test.cpp:5:28: error: use of undeclared identifier 'FooBar'
test.cpp:5:40: error: use of undeclared identifier 'std'
Found Function: main(int, char **)
All pre-processor errors are fine and expected, my problem is that FooBar::baz()
is not recognized as a function.
I intentionally haven't provided the include directory of foo.h
as a compiler flag (-I
) because I want this tool to be standalone, i. e., operate on arbitrary single C++ source files, to extract the function names.
In the Clang API docs I read that CXTranslationUnit_SingleFileParse
is specifically designed for this use case, but somehow it doesn't provide the expected results.
What am I missing?
Disclaimer: I'm aware that it is unconventional to try to force an actual compiler to ignore syntax errors due to unresolved includes, but ctags
or tree-sitter
do not give satisfying results, as they are only fuzzy parsers.