Author: nataliakokoromyti Date: 2026-05-12T17:57:38+03:00 New Revision: 5977cb59bda303e1ca98e7e7edc961fdb8160ab7
URL: https://github.com/llvm/llvm-project/commit/5977cb59bda303e1ca98e7e7edc961fdb8160ab7 DIFF: https://github.com/llvm/llvm-project/commit/5977cb59bda303e1ca98e7e7edc961fdb8160ab7.diff LOG: [clangd] Avoid crash on pseudo-destructor selection (#195939) clangd crashes during textDocument/codeAction on valid pseudo-destructor expressions like y->~decltype(A())(). The bug is in Selection.cpp::earlySourceRange(), which assumes destructor names always have NamedTypeInfo. The fix is adding null checks before calling getTypeLoc(). Fixes #195788. Added: Modified: clang-tools-extra/clangd/Selection.cpp clang-tools-extra/clangd/unittests/SelectionTests.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index b79ffc7d5a6e9..21c9e71d3db65 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -895,13 +895,19 @@ class SelectionVisitor : public RecursiveASTVisitor<SelectionVisitor> { // rather than the TypeLoc nested inside it. // We still traverse the TypeLoc, because it may contain other targeted // things like the T in ~Foo<T>(). - if (const auto *CDD = N.get<CXXDestructorDecl>()) - return CDD->getNameInfo().getNamedTypeInfo()->getTypeLoc().getBeginLoc(); + // FIXME: Investigate if getNamedTypeInfo() can still return null for + // invalid cases, and drop these checks when it never returns null. + if (const auto *CDD = N.get<CXXDestructorDecl>()) { + if (auto *TypeInfo = CDD->getNameInfo().getNamedTypeInfo()) + return TypeInfo->getTypeLoc().getBeginLoc(); + } if (const auto *ME = N.get<MemberExpr>()) { auto NameInfo = ME->getMemberNameInfo(); if (NameInfo.getName().getNameKind() == - DeclarationName::CXXDestructorName) - return NameInfo.getNamedTypeInfo()->getTypeLoc().getBeginLoc(); + DeclarationName::CXXDestructorName) { + if (auto *TypeInfo = NameInfo.getNamedTypeInfo()) + return TypeInfo->getTypeLoc().getBeginLoc(); + } } return SourceRange(); diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index 5e897fae79df4..396990e6ea929 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -665,6 +665,24 @@ TEST(SelectionTest, InjectedClassName) { EXPECT_FALSE(D->isInjectedClassName()); } +TEST(SelectionTest, PseudoDestructorMissingTypeInfo) { + llvm::StringLiteral Code = R"cpp( + struct A { ~A(); }; + void b(const A *y) { + y->~decltype(A())(); + } + )cpp"; + auto AST = TestTU::withCode(Code).build(); + bool Seen = false; + // No crash. + SelectionTree::createEach(AST.getASTContext(), AST.getTokens(), 0, + Code.size(), [&](SelectionTree) { + Seen = true; + return true; + }); + EXPECT_TRUE(Seen); +} + TEST(SelectionTree, Metrics) { const char *Code = R"cpp( // error-ok: testing behavior on recovery expression _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
