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

Reply via email to