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
