Index: clang/tools/libclang/CIndex.cpp =================================================================== --- clang/tools/libclang/CIndex.cpp +++ clang/tools/libclang/CIndex.cpp @@ -1294,7 +1294,7 @@ bool CursorVisitor::VisitStaticAssertDecl(StaticAssertDecl *D) { if (Visit(MakeCXCursor(D->getAssertExpr(), StmtParent, TU, RegionOfInterest))) return true; - if (auto *Message = dyn_cast(D->getMessage())) + if (auto *Message = D->getMessage()) if (Visit(MakeCXCursor(Message, StmtParent, TU, RegionOfInterest))) return true; return false; Index: clang/unittests/libclang/LibclangTest.cpp =================================================================== --- clang/unittests/libclang/LibclangTest.cpp +++ clang/unittests/libclang/LibclangTest.cpp @@ -1172,6 +1172,69 @@ }); } +TEST_F(LibclangParseTest, VisitStaticAssertDecl_noMessage) { + const char testSource[] = R"cpp(static_assert(true))cpp"; + std::string fileName = "main.cpp"; + WriteFile(fileName, testSource); + const char *Args[] = {"-xc++"}; + ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, 1, + nullptr, 0, TUFlags); + + std::optional staticAssertCsr; + Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult { + if (cursor.kind == CXCursor_StaticAssert) { + staticAssertCsr.emplace(cursor); + return CXChildVisit_Break; + } + return CXChildVisit_Recurse; + }); + ASSERT_TRUE(staticAssertCsr.has_value()); + Traverse(*staticAssertCsr, [](CXCursor cursor, CXCursor parent){ + EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr); + return CXChildVisit_Break; + }); + EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), ""); +} + + +TEST_F(LibclangParseTest, VisitStaticAssertDecl_exprMessage) { + const char testSource[] = R"cpp( +#include +static constexpr std::string_view message{"Hallo Welt!"}; +static_assert(true, message); +)cpp"; + std::string fileName = "main.cpp"; + WriteFile(fileName, testSource); + const char *Args[] = {"-xc++", "-std=c++26"}; + ClangTU = clang_parseTranslationUnit(Index, fileName.c_str(), Args, std::size(Args), + nullptr, 0, TUFlags); + ASSERT_EQ(clang_getNumDiagnostics(ClangTU), 0); + std::optional staticAssertCsr; + Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult { + // std::cout << fromCXString(clang_getCursorKindSpelling(cursor.kind)) << ": "<< fromCXString(clang_getCursorSpelling(cursor)) << std::endl; + if (cursor.kind == CXCursor_StaticAssert) { + staticAssertCsr.emplace(cursor); + } + return CXChildVisit_Continue; + }); + ASSERT_TRUE(staticAssertCsr.has_value()); + size_t argCnt = 0; + Traverse(*staticAssertCsr, [&argCnt](CXCursor cursor, CXCursor parent){ + switch (argCnt) { + case 0: + EXPECT_EQ(cursor.kind, CXCursor_CXXBoolLiteralExpr); + break; + case 1: + EXPECT_EQ(cursor.kind, CXCursor_DeclRefExpr); + break; + } + ++argCnt; + return CXChildVisit_Continue; + }); + ASSERT_EQ(argCnt, 2); + EXPECT_EQ(fromCXString(clang_getCursorSpelling(*staticAssertCsr)), ""); +} + class LibclangRewriteTest : public LibclangParseTest { public: CXRewriter Rew = nullptr; Index: clang/unittests/libclang/TestUtils.h =================================================================== --- clang/unittests/libclang/TestUtils.h +++ clang/unittests/libclang/TestUtils.h @@ -88,13 +88,18 @@ }); } template - void Traverse(const F &TraversalFunctor) { - CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU); + void Traverse(const CXCursor& cursor, const F &TraversalFunctor) { std::reference_wrapper FunctorRef = std::cref(TraversalFunctor); - clang_visitChildren(TuCursor, + clang_visitChildren(cursor, &TraverseStateless>, &FunctorRef); } + + template + void Traverse(const F& TraversalFunctor) { + Traverse(clang_getTranslationUnitCursor(ClangTU), TraversalFunctor) ; + } + static std::string fromCXString(CXString cx_string) { std::string string{clang_getCString(cx_string)}; clang_disposeString(cx_string);