-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a libclang-style C API #337
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #337 +/- ##
==========================================
- Coverage 74.43% 69.02% -5.42%
==========================================
Files 8 9 +1
Lines 3204 3574 +370
==========================================
+ Hits 2385 2467 +82
- Misses 819 1107 +288
... and 2 files with indirect coverage changes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There were too many comments to post at once. Showing the first 10 out of 41. Check the log or trigger a new build to see more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There were too many comments to post at once. Showing the first 10 out of 24. Check the log or trigger a new build to see more.
static inline bool isNull(const CXScope& S) { return !S.data[0]; } | ||
|
||
static inline clang::Decl* getDecl(const CXScope& S) { | ||
return const_cast<clang::Decl*>(static_cast<const clang::Decl*>(S.data[0])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use const_cast [cppcoreguidelines-pro-type-const-cast]
return const_cast<clang::Decl*>(static_cast<const clang::Decl*>(S.data[0]));
^
auto* I = getInterpreter(scope); | ||
if (const Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { | ||
if (arena) { | ||
JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use C-style cast to convert between unrelated types [cppcoreguidelines-pro-type-cstyle-cast]
JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new.
^
auto* I = getInterpreter(scope); | ||
if (const Cpp::JitCall JC = Cpp::MakeFunctionCallableImpl(I, getDecl(Ctor))) { | ||
if (arena) { | ||
JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: integer to pointer cast pessimizes optimization opportunities [performance-no-int-to-ptr]
JC.Invoke(&arena, {}, (void*)~0); // Tell Invoke to use placement new.
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we are quite close. Can we silence the codecov somehow without duplicating tests? Can we move the refactorings in CppInterOp.cpp as a separate PR?
include/clang-c/CXCppInterOp.h
Outdated
* | ||
* \param prepend Whether to prepend the directory to the search path. | ||
*/ | ||
void clang_interpreter_addSearchPath(CXInterpreter I, const char* dir, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to shorten these interfaces. Maybe Cpp_AddSearchPath
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we only expose opaque pointers in the C API, I believe libclang uses this naming style to warn users about the type of the input argument. However, for historical reasons, libclang appears to lack strict rules on capitalization.
The naming convention is like clang_
+ ClassName
+ methodName
or clang_
+ functionName
.
Here are some examples:
typedef void *CXIndexAction;
CINDEX_LINKAGE CXIndexAction clang_IndexAction_create(CXIndex CIdx);
CINDEX_LINKAGE void clang_IndexAction_dispose(CXIndexAction);
CINDEX_LINKAGE CXIdxClientContainer
clang_index_getClientContainer(const CXIdxContainerInfo *);
CINDEX_LINKAGE unsigned clang_CXXMethod_isDeleted(CXCursor C);
CINDEX_LINKAGE CXString clang_Module_getName(CXModule Module);
CINDEX_LINKAGE CXCursor clang_getCanonicalCursor(CXCursor);
CINDEX_LINKAGE unsigned
clang_PrintingPolicy_getProperty(CXPrintingPolicy Policy, enum CXPrintingPolicyProperty Property);
CINDEX_LINKAGE void
clang_PrintingPolicy_setProperty(CXPrintingPolicy Policy,
enum CXPrintingPolicyProperty Property,
unsigned Value);
CINDEX_LINKAGE CXPrintingPolicy clang_getCursorPrintingPolicy(CXCursor);
CINDEX_LINKAGE void clang_PrintingPolicy_dispose(CXPrintingPolicy Policy);
CINDEX_LINKAGE CXString clang_getCursorPrettyPrinted(CXCursor Cursor, CXPrintingPolicy Policy);
@@ -262,16 +264,16 @@ namespace Cpp { | |||
|
|||
/// This is similar to GetName() function, but besides | |||
/// the name, it also gets the template arguments. | |||
CPPINTEROP_API std::string GetCompleteName(TCppType_t klass); | |||
CPPINTEROP_API std::string GetCompleteName(TCppScope_t klass); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! We should probably adopt the CX
enum style so that the compiler could help us with finding these wrong cases. Related to compiler-research/CPyCppyy#8.
Yes. I'll make another PR for the changes in |
66ccc69
to
1bb9ead
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There were too many comments to post at once. Showing the first 10 out of 12. Check the log or trigger a new build to see more.
@@ -98,6 +100,19 @@ TEST(InterpreterTest, CreateInterpreter) { | |||
"#endif"); | |||
EXPECT_TRUE(Cpp::GetNamed("cpp17")); | |||
EXPECT_FALSE(Cpp::GetNamed("cppUnknown")); | |||
|
|||
// C API | |||
const char* args[] = {"-std=c++14"}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not declare C-style arrays, use std::array<> instead [cppcoreguidelines-avoid-c-arrays]
const char* args[] = {"-std=c++14"};
^
|
||
// C API | ||
const char* args[] = {"-std=c++14"}; | ||
auto CXI = clang_createInterpreter(args, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: 'auto CXI' can be declared as 'auto *CXI' [llvm-qualified-auto]
auto CXI = clang_createInterpreter(args, 1); | |
auto *CXI = clang_createInterpreter(args, 1); |
|
||
// C API | ||
const char* args[] = {"-std=c++14"}; | ||
auto CXI = clang_createInterpreter(args, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not implicitly decay an array into a pointer; consider using gsl::array_view or an explicit cast instead [cppcoreguidelines-pro-bounds-array-to-pointer-decay]
auto CXI = clang_createInterpreter(args, 1);
^
clang_Interpreter_dispose(CXI); | ||
|
||
CXI = clang_createInterpreterFromRawPtr(I); | ||
auto CLI = clang_Interpreter_getClangInterpreter(CXI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: 'auto CLI' can be declared as 'auto *CLI' [llvm-qualified-auto]
auto CLI = clang_Interpreter_getClangInterpreter(CXI); | |
auto *CLI = clang_Interpreter_getClangInterpreter(CXI); |
CXI = clang_createInterpreterFromRawPtr(I); | ||
auto CLI = clang_Interpreter_getClangInterpreter(CXI); | ||
EXPECT_TRUE(CLI); | ||
auto I2 = clang_Interpreter_takeInterpreterAsPtr(CXI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: 'auto I2' can be declared as 'auto *I2' [llvm-qualified-auto]
auto I2 = clang_Interpreter_takeInterpreterAsPtr(CXI); | |
auto *I2 = clang_Interpreter_takeInterpreterAsPtr(CXI); |
|
||
void dispose_string(CXString string) { | ||
if (string.private_flags == 1 && string.data) | ||
free(const_cast<void*>(string.data)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: calling legacy resource function without passing a 'gsl::owner<>' [cppcoreguidelines-owning-memory]
free(const_cast<void*>(string.data));
^
|
||
void dispose_string(CXString string) { | ||
if (string.private_flags == 1 && string.data) | ||
free(const_cast<void*>(string.data)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not manage memory manually; use RAII [cppcoreguidelines-no-malloc]
free(const_cast<void*>(string.data));
^
|
||
void dispose_string(CXString string) { | ||
if (string.private_flags == 1 && string.data) | ||
free(const_cast<void*>(string.data)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: do not use const_cast [cppcoreguidelines-pro-type-const-cast]
free(const_cast<void*>(string.data));
^
free(const_cast<void*>(string.data)); | ||
} | ||
|
||
CXScope make_scope(const clang::Decl* D, const CXInterpreter I) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: 'I' declared with a const-qualified typedef; results in the type being 'CXInterpreterImpl *const' instead of 'const CXInterpreterImpl *' [misc-misplaced-const]
CXScope make_scope(const clang::Decl* D, const CXInterpreter I) {
^
Additional context
include/clang-c/CXCppInterOp.h:25: typedef declared here
typedef struct CXInterpreterImpl* CXInterpreter;
^
#include <memory> | ||
#include <vector> | ||
#include "llvm/Support/Valgrind.h" | ||
#include "clang-c/CXCppInterOp.h" | ||
#include "clang-c/CXString.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: #includes are not sorted properly [llvm-include-order]
#include "clang-c/CXString.h" | |
#include "clang-c/CXCppInterOp.h" | |
#include "clang-c/CXString.h" | |
#include "llvm/Support/Valgrind.h" | |
#include <memory> | |
#include <vector> |
1bb9ead
to
bc67a64
Compare
if (!clang_hasDefaultConstructor(S)) | ||
return clang::cxscope::MakeCXScope(nullptr, getNewTU(S)); | ||
|
||
auto* CXXRD = llvm::dyn_cast_or_null<clang::CXXRecordDecl>(getDecl(S)); | ||
if (!CXXRD) | ||
return clang::cxscope::MakeCXScope(nullptr, getNewTU(S)); | ||
|
||
const auto* Res = | ||
getInterpreter(S)->getSema().LookupDefaultConstructor(CXXRD); | ||
return clang::cxscope::MakeCXScope(Res, getNewTU(S)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't we forward to Cpp::GetDefaultConstructor
? I see this trend in several interfaces. Is there some limitation on the C++ side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
|
||
void dispose_string(CXString string); | ||
|
||
CXScope make_scope(const clang::Decl* D, const CXInterpreter I); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: 'I' declared with a const-qualified typedef; results in the type being 'CXInterpreterImpl *const' instead of 'const CXInterpreterImpl *' [misc-misplaced-const]
CXScope make_scope(const clang::Decl* D, const CXInterpreter I);
^
Additional context
include/clang-c/CXCppInterOp.h:25: typedef declared here
typedef struct CXInterpreterImpl* CXInterpreter;
^
|
||
void dispose_string(CXString string); | ||
|
||
CXScope make_scope(const clang::Decl* D, const CXInterpreter I); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: parameter 'I' is const-qualified in the function declaration; const-qualification of parameters only has an effect in function definitions [readability-avoid-const-params-in-decls]
CXScope make_scope(const clang::Decl* D, const CXInterpreter I); | |
CXScope make_scope(const clang::Decl* D, CXInterpreter I); |
bc67a64
to
573a6a8
Compare
- Add `CXScope` and `CXQualType` as a bridge between libclang types and CppInterOp's types - Add C API for interpreter and scope manipulations
Do we know why some builds are failing? |
Since there is a substantial overlap with libclang’s API, I am only exposing the API I currently use in this PR.
This PR introduces two types,
CXScope
andCXQualType
, which wrapTCppScope_t
andTCppType_t
, respectively. The structure of these two types is the same as libclang'sCXCursor
/CXType
, with the only difference being that they store a handle to the interpreter instead of a CXTranslationUnit. This paves the way for upstreaming changes to libclang.