[Clang] Fix crash in CIndex, when visiting a static_assert without message
After implementation of "[Clang] Implement P2741R3 - user-generated static_assert messages" (47ccfd7a89e2a9a747a7114db18db1376324799c) the c indexer crashes when handling a `static_assert` w/o any message. This is caused by using `dyn_cast` to get the literal string, which isn't working on `nullptr`. Reviewed By: cor3ntin Differential Revision: https://reviews.llvm.org/D156053
This commit is contained in:
parent
ca9a3354d0
commit
86da763ab6
@ -1294,7 +1294,7 @@ bool CursorVisitor::VisitUnresolvedUsingTypenameDecl(
|
||||
bool CursorVisitor::VisitStaticAssertDecl(StaticAssertDecl *D) {
|
||||
if (Visit(MakeCXCursor(D->getAssertExpr(), StmtParent, TU, RegionOfInterest)))
|
||||
return true;
|
||||
if (auto *Message = dyn_cast<StringLiteral>(D->getMessage()))
|
||||
if (auto *Message = D->getMessage())
|
||||
if (Visit(MakeCXCursor(Message, StmtParent, TU, RegionOfInterest)))
|
||||
return true;
|
||||
return false;
|
||||
|
@ -1172,6 +1172,80 @@ TEST_F(LibclangParseTest, UnaryOperator) {
|
||||
});
|
||||
}
|
||||
|
||||
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<CXCursor> 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(
|
||||
template <unsigned s>
|
||||
constexpr unsigned size(const char (&)[s])
|
||||
{
|
||||
return s - 1;
|
||||
}
|
||||
|
||||
struct Message {
|
||||
static constexpr char message[] = "Hello World!";
|
||||
constexpr const char* data() const { return message;}
|
||||
constexpr unsigned size() const
|
||||
{
|
||||
return ::size(message);
|
||||
}
|
||||
};
|
||||
Message message;
|
||||
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<CXCursor> staticAssertCsr;
|
||||
Traverse([&](CXCursor cursor, CXCursor parent) -> CXChildVisitResult {
|
||||
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;
|
||||
|
@ -88,13 +88,17 @@ public:
|
||||
});
|
||||
}
|
||||
template <typename F>
|
||||
void Traverse(const F &TraversalFunctor) {
|
||||
CXCursor TuCursor = clang_getTranslationUnitCursor(ClangTU);
|
||||
void Traverse(const CXCursor &cursor, const F &TraversalFunctor) {
|
||||
std::reference_wrapper<const F> FunctorRef = std::cref(TraversalFunctor);
|
||||
clang_visitChildren(TuCursor,
|
||||
clang_visitChildren(cursor,
|
||||
&TraverseStateless<std::reference_wrapper<const F>>,
|
||||
&FunctorRef);
|
||||
}
|
||||
|
||||
template <typename F> 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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user