llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: Mythreya Kuricheti (MythreyaK) <details> <summary>Changes</summary> Fixes clangd/clangd#<!-- -->2323. Assumes `self` is of the record type in the declaration. ```cpp struct Foo { int member {}; auto&& getter1(this auto&& self) { // assume `self` is is `Foo` return self.member; }; ``` --- Full diff: https://github.com/llvm/llvm-project/pull/155143.diff 3 Files Affected: - (modified) clang-tools-extra/clangd/unittests/RenameTests.cpp (+42-1) - (modified) clang/lib/Sema/HeuristicResolver.cpp (+26) - (modified) clang/unittests/Sema/HeuristicResolverTest.cpp (+18-1) ``````````diff diff --git a/clang-tools-extra/clangd/unittests/RenameTests.cpp b/clang-tools-extra/clangd/unittests/RenameTests.cpp index 2cb0722f7f285..4701ae07d0d12 100644 --- a/clang-tools-extra/clangd/unittests/RenameTests.cpp +++ b/clang-tools-extra/clangd/unittests/RenameTests.cpp @@ -17,10 +17,11 @@ #include "clang/Tooling/Core/Replacement.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/MemoryBuffer.h" -#include <algorithm> #include "gmock/gmock.h" #include "gtest/gtest.h" +#include <algorithm> + namespace clang { namespace clangd { namespace { @@ -2468,6 +2469,46 @@ TEST(CrossFileRenameTests, adjustmentCost) { } } +TEST(RenameTest, RenameWithExplicitObjectPararameter) { + Annotations Test = {R"cpp( + struct Foo { + int [[memb^er]] {}; + auto&& getter1(this auto&& self) { + auto local = [&] { + return self.[[memb^er]]; + }(); + return local + self.[[memb^er]]; + } + auto&& getter2(this Foo&& self) { + return self.[[memb^er]]; + } + int normal() { + return [[memb^er]]; + } + }; + )cpp"}; + + auto TU = TestTU::withCode(Test.code()); + TU.ExtraArgs.push_back("-std=c++23"); + auto AST = TU.build(); + + llvm::StringRef NewName = "m_member"; + auto Index = TU.index(); + + for (const auto &RenamePos : Test.points()) { + auto RenameResult = rename({RenamePos, NewName, AST, testPath(TU.Filename), + getVFSFromAST(AST), Index.get()}); + + ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); + auto Res = RenameResult.get(); + + ASSERT_TRUE(bool(RenameResult)) << RenameResult.takeError(); + ASSERT_EQ(1u, RenameResult->GlobalChanges.size()); + EXPECT_EQ(applyEdits(std::move(RenameResult->GlobalChanges)).front().second, + expectedResult(Test, NewName)); + } +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 933841beeac3d..20f7d0fca2066 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -14,6 +14,7 @@ #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "llvm/ADT/identity.h" +#include <optional> namespace clang { @@ -301,9 +302,34 @@ std::vector<const NamedDecl *> HeuristicResolverImpl::resolveMemberExpr( return {}; } + // check if member expr is in the context of an explicit object method + // If so, it's safe to assume the templated arg is of type of the record + const auto ExplicitMemberHeuristic = + [&](const Expr *Base) -> std::optional<QualType> { + if (auto *DeclRef = dyn_cast_if_present<DeclRefExpr>(Base)) { + auto *PrDecl = dyn_cast_if_present<ParmVarDecl>(DeclRef->getDecl()); + + if (PrDecl && PrDecl->isExplicitObjectParameter()) { + auto CxxRecord = dyn_cast_if_present<CXXRecordDecl>( + PrDecl->getDeclContext()->getParent()); + + if (CxxRecord) { + return Ctx.getTypeDeclType(dyn_cast<TypeDecl>(CxxRecord)); + } + } + } + + return std::nullopt; + }; + // Try resolving the member inside the expression's base type. Expr *Base = ME->isImplicitAccess() ? nullptr : ME->getBase(); QualType BaseType = ME->getBaseType(); + + if (auto Type = ExplicitMemberHeuristic(Base)) { + BaseType = *Type; + } + BaseType = simplifyType(BaseType, Base, ME->isArrow()); return resolveDependentMember(BaseType, ME->getMember(), NoFilter); } diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 7df25e01e66d4..21aca7a3489b8 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -41,7 +41,7 @@ template <typename InputNode, typename ParamT, typename InputMatcher, typename... OutputMatchers> void expectResolution(llvm::StringRef Code, ResolveFnT<ParamT> ResolveFn, const InputMatcher &IM, const OutputMatchers &...OMS) { - auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++20"}); + auto TU = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++23"}); auto &Ctx = TU->getASTContext(); auto InputMatches = match(IM, Ctx); ASSERT_EQ(1u, InputMatches.size()); @@ -449,6 +449,23 @@ TEST(HeuristicResolver, MemberExpr_DefaultTemplateArgument_Recursive) { cxxMethodDecl(hasName("foo")).bind("output")); } +TEST(HeuristicResolver, MemberExpr_ExplicitObjectParameter) { + std::string Code = R"cpp( + struct Foo { + int m_int; + + int bar(this auto&& self) { + return self.m_int; + } + }; + )cpp"; + // Test resolution of "m_int" in "self.m_int()". + expectResolution( + Code, &HeuristicResolver::resolveMemberExpr, + cxxDependentScopeMemberExpr(hasMemberName("m_int")).bind("input"), + fieldDecl(hasName("m_int")).bind("output")); +} + TEST(HeuristicResolver, DeclRefExpr_StaticMethod) { std::string Code = R"cpp( template <typename T> `````````` </details> https://github.com/llvm/llvm-project/pull/155143 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits