diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index fd12bb41be47a..ed97a1da13d04 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -570,6 +570,8 @@ clang-format libclang -------- +- Added ``CXCallExprKind`` and ``clang_getCursorCallExprKind``. + Static Analyzer --------------- diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 60db3cf0966c0..1828b8ec3edaa 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -6663,6 +6663,52 @@ clang_getUnaryOperatorKindSpelling(enum CXUnaryOperatorKind kind); CINDEX_LINKAGE enum CXUnaryOperatorKind clang_getCursorUnaryOperatorKind(CXCursor cursor); +/** + * Describes the kind of CallExpr. + */ +enum CXCallExprKind { + /** Not a CallExpr. */ + CXCallExpr_Invalid = 0, + /** Simple C function call. */ + CXCallExpr_Default, + /** Call to overloaded operator using operator syntax. */ + CXCallExpr_CXXOperatorCallExpr, + /** + * Call to a member function written with member call syntax or + * normal function-call syntax within a member function. + */ + CXCallExpr_CXXMemberCallExpr, + /** Call to a CUDA kernel function. */ + CXCallExpr_CUDAKernelCallExpr, + /** Call to a C++ constructor. */ + CXCallExpr_CXXConstructExpr, + /** + * Call to an inherited base class constructor from an + * inheriting constructor. Implicitly forwards arguments. + */ + CXCallExpr_CXXInheritedCtorInitExpr, + /** + * C++ functional cast expression building a temporary object. + */ + CXCallExpr_CXXTemporaryObjectExpr, + /** + * Explicit type conversion using functional notation, unresolved + * due to type-dependency. + */ + CXCallExpr_CXXUnresolvedConstructExpr, + /** + * Call to a user-defined literal. + */ + CXCallExpr_UserDefinedLiteral, +}; + +/** + * Retrieve the detailed kind of a call expression. + * + * If this cursor is not a CallExpr then returns Invalid. + */ +CINDEX_LINKAGE enum CXCallExprKind clang_getCursorCallExprKind(CXCursor cursor); + /** * @} */ diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 454ee1e42aed1..436ebcc580ad4 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -9731,3 +9731,31 @@ enum CXUnaryOperatorKind clang_getCursorUnaryOperatorKind(CXCursor cursor) { return CXUnaryOperator_Invalid; } + +enum CXCallExprKind clang_getCursorCallExprKind(CXCursor cursor) { + if (clang_isExpression(cursor.kind)) { + const Expr *expr = getCursorExpr(cursor); + + switch (expr->getStmtClass()) { + case Stmt::CallExprClass: + return CXCallExpr_Default; + case Stmt::CXXOperatorCallExprClass: + return CXCallExpr_CXXOperatorCallExpr; + case Stmt::CXXMemberCallExprClass: + return CXCallExpr_CXXMemberCallExpr; + case Stmt::CUDAKernelCallExprClass: + return CXCallExpr_CUDAKernelCallExpr; + case Stmt::CXXConstructExprClass: + return CXCallExpr_CXXConstructExpr; + case Stmt::CXXInheritedCtorInitExprClass: + return CXCallExpr_CXXInheritedCtorInitExpr; + case Stmt::CXXTemporaryObjectExprClass: + return CXCallExpr_CXXTemporaryObjectExpr; + case Stmt::CXXUnresolvedConstructExprClass: + return CXCallExpr_CXXUnresolvedConstructExpr; + case Stmt::UserDefinedLiteralClass: + return CXCallExpr_UserDefinedLiteral; + } + } + return CXCallExpr_Invalid; +} \ No newline at end of file diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map index 5676198a286d9..0c3a4fc3f8b00 100644 --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -428,6 +428,11 @@ LLVM_17 { clang_getCursorUnaryOperatorKind; }; +LLVM_19 { + global: + clang_getCursorCallExprKind; +}; + # Example of how to add a new symbol version entry. If you do add a new symbol # version, please update the example to depend on the version you added. # LLVM_X { diff --git a/clang/unittests/libclang/LibclangTest.cpp b/clang/unittests/libclang/LibclangTest.cpp index 87075a46d7518..06ebe6729f065 100644 --- a/clang/unittests/libclang/LibclangTest.cpp +++ b/clang/unittests/libclang/LibclangTest.cpp @@ -1172,6 +1172,30 @@ TEST_F(LibclangParseTest, UnaryOperator) { }); } +TEST_F(LibclangParseTest, clang_getCursorCallExprKind) { + std::string Main = "main.cpp"; + const char testSource[] = R"cpp( +struct X{ + int operator+(int) const; +}; + +int x = X() + 1; +)cpp"; + WriteFile(Main, testSource); + ClangTU = clang_parseTranslationUnit(Index, Main.c_str(), nullptr, 0, nullptr, + 0, TUFlags); + + Traverse([](CXCursor cursor, CXCursor parent) -> CXChildVisitResult { + if (cursor.kind == CXCursor_CallExpr) { + EXPECT_EQ(clang_getCursorCallExprKind(cursor), + CXCallExpr_CXXOperatorCallExpr); + return CXChildVisit_Break; + } + + return CXChildVisit_Recurse; + }); +} + TEST_F(LibclangParseTest, VisitStaticAssertDecl_noMessage) { const char testSource[] = R"cpp(static_assert(true))cpp"; std::string fileName = "main.cpp";