Author: Macro Terra
Date: 2026-09-04T09:26:59+03:00
New Revision: bea0cf1245823ea6993fce88bb888b0e4612a5e3

URL: 
https://github.com/llvm/llvm-project/commit/bea0cf1245823ea6993fce88bb888b0e4612a5e3
DIFF: 
https://github.com/llvm/llvm-project/commit/bea0cf1245823ea6993fce88bb888b0e4612a5e3.diff

LOG: [clangd] Avoid invalid include-fixer fuzzy-find queries (#212134)

Fixes #200571.

`operator::align_val_t` is parsed as a conversion-function-id, whose
target type is `::align_val_t`. During typo recovery, Sema correctly
passes clangd a `DeclarationNameInfo` with kind
`CXXConversionFunctionName`; it is not a malformed ordinary identifier.

`UnresolvedNameRecorder` previously flattened every
`DeclarationNameInfo` through `getAsString()`. For a conversion-function
name, that presentation string contains the conversion target type and
can therefore contain a qualified type such as `std::align_val_t`. The
recorder then incorrectly stored that string as `UnresolvedName::Name`
and forwarded it as `FuzzyFindRequest::Query`.

Reject only `CXXConversionFunctionName` before this lossy conversion.
Such a name cannot be represented by IncludeFixer's `Name + Scopes`
model: its embedded type qualification is not the scope of an unresolved
symbol. Other special names, such as overloaded operators, retain their
existing behavior because they may be valid unqualified index names.

Add a regression test for the conversion-function recovery path.

Testing: not run after this source-only refinement.

Added: 
    

Modified: 
    clang-tools-extra/clangd/IncludeFixer.cpp
    clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/IncludeFixer.cpp 
b/clang-tools-extra/clangd/IncludeFixer.cpp
index 5ecf853524a3f..2f056575702e0 100644
--- a/clang-tools-extra/clangd/IncludeFixer.cpp
+++ b/clang-tools-extra/clangd/IncludeFixer.cpp
@@ -397,6 +397,13 @@ std::optional<std::string> getSpelledSpecifier(const 
CXXScopeSpec &SS,
 std::optional<CheapUnresolvedName> extractUnresolvedNameCheaply(
     const SourceManager &SM, const DeclarationNameInfo &Unresolved,
     CXXScopeSpec *SS, const LangOptions &LangOpts, bool UnresolvedIsSpecifier) 
{
+  // Sema reports an unresolved conversion target type separately. Don't
+  // overwrite that record with the enclosing conversion function name, whose
+  // type cannot be represented by Name + Scopes.
+  if (Unresolved.getName().getNameKind() ==
+      DeclarationName::CXXConversionFunctionName)
+    return std::nullopt;
+
   CheapUnresolvedName Result;
   Result.Name = Unresolved.getAsString();
   if (SS && SS->isNotEmpty()) { // "::" or "ns::"

diff  --git a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp 
b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
index e7950526a3ec3..c986b22bd1056 100644
--- a/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
@@ -1563,6 +1563,43 @@ TEST(IncludeFixerTest, NoCrashMemberAccess) {
       UnorderedElementsAre(Diag(Test.range(), "no member named 'xy' in 'X'")));
 }
 
+TEST(IncludeFixerTest, NoCrashOnQualifiedConversionFunctionName) {
+  auto TU = TestTU::withCode(R"cpp(// error-ok
+namespace std {}
+void f() { operator new[](0, operator::align_val_t{}); }
+  )cpp");
+  TU.ExtraArgs.push_back("-std=c++17");
+  auto Index = buildIndexWithSymbol(
+      SymbolWithHeader{"std::align_val_t", "unittest:///new.h", "<new>"});
+  TU.ExternalIndex = Index.get();
+
+  EXPECT_THAT(TU.build().getDiagnostics(), Not(IsEmpty()));
+}
+
+TEST(IncludeFixerTest, FixConversionFunctionTargetType) {
+  Annotations Test(R"cpp(// error-ok
+$insert[[]]struct Wrapper {
+  template <typename T>
+  operator T() const { return T(); }
+};
+
+void f() {
+  Wrapper W;
+  auto V = W.operator::$target[[Something]]();
+}
+  )cpp");
+  auto TU = TestTU::withCode(Test.code());
+  auto Index = buildIndexWithSymbol(
+      SymbolWithHeader{"Something", "unittest:///test.h", "\"test.h\""});
+  TU.ExternalIndex = Index.get();
+
+  EXPECT_THAT(TU.build().getDiagnostics(),
+              Contains(Field(
+                  &Diag::Fixes,
+                  Contains(Fix(Test.range("insert"), "#include \"test.h\"\n",
+                               "Include \"test.h\" for symbol Something")))));
+}
+
 TEST(IncludeFixerTest, UseCachedIndexResults) {
   // As index results for the identical request are cached, more than 5 fixes
   // are generated.


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to