Repository navigation
[include-cleaner] Attribute inherited member operators to the derived type - #240052
Spikhalskiy wants to merge 2 commits into
Conversation
… type A member operator call reported the provider of `getArg(0)->getType()`. For an operator inherited from a base class, that argument is a derived-to-base implicit cast, so the use was attributed to the base class instead of the type the operator was called on. `VisitMemberExpr` already strips implicit casts, so `p.get()` and `p->x` disagreed. With libstdc++, `std::shared_ptr` inherits `operator->` and `operator*` from `std::__shared_ptr_access` in `bits/shared_ptr_base.h`, so `misc-include-cleaner` reported `<memory>` as unused after `p->x`, while libc++, which declares them on `std::shared_ptr`, did not. This strips implicit casts from the object argument the same way, and adds `WalkAST` tests for inherited `operator+`, `operator->` and `operator*`. Fixes llvm#240048
|
@llvm/pr-subscribers-clang-tools-extra Author: Dmitry Spikhalsky (Spikhalskiy) ChangesA member operator call reported the provider of With libstdc++, This strips implicit casts from the object argument the same way, and adds Fixes #240048 Full diff: https://github.com/llvm/llvm-project/pull/240052.diff 3 Files Affected:
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index de205ae3343db9..c3481b91e6da87 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -283,6 +283,12 @@ infrastructure are described first, followed by tool-specific sections.
{option}`IgnoreHeaders` patterns containing `/` against header paths on
Windows.
+- Improved {doc}`misc-include-cleaner
+ <clang-tidy/checks/misc/include-cleaner>` check by attributing a member
+ operator inherited from a base class to the derived type, so the derived
+ type's header is no longer reported as unused. This made `<memory>` look
+ unused after `p->x` on a `std::shared_ptr` with libstdc++ but not libc++.
+
- Fixed an infinite loop in {doc}`misc-multiple-inheritance
<clang-tidy/checks/misc/multiple-inheritance>` when checking a class that
inherits from itself or has a circular inheritance graph.
diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
index 5449411371e601..68a2cef03d86f6 100644
--- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -161,8 +161,10 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
return false;
if (auto *CD = S->getCalleeDecl()) {
if (isa<CXXMethodDecl>(CD)) {
- // Treat this as a regular member reference.
- report(S->getOperatorLoc(), getMemberProvider(S->getArg(0)->getType()),
+ // Treat this as a regular member reference. Like VisitMemberExpr, look
+ // through the derived-to-base cast an inherited operator adds.
+ report(S->getOperatorLoc(),
+ getMemberProvider(S->getArg(0)->IgnoreImpCasts()->getType()),
RefType::Implicit);
} else {
report(S->getOperatorLoc(), dyn_cast<NamedDecl>(CD), RefType::Implicit);
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index c9519c2e91b68a..87e78eb7750885 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -502,6 +502,21 @@ TEST(WalkAST, Operator) {
testWalk(
"struct string {int operator+(string); }; using $implicit^foo = string;",
"int k = foo() ^+ string();");
+ // Inherited member operators are attributed to the derived type, like other
+ // inherited members.
+ testWalk("struct Base { int operator+(Base); }; "
+ "struct $implicit^Derived : Base {};",
+ "int k = Derived() ^+ Derived();");
+ testWalk(R"cpp(
+ template <typename T> struct PtrBase { T *operator->(); T &operator*(); };
+ template <typename T> struct $implicit^Ptr : PtrBase<T> {};
+ struct Foo { int a; };)cpp",
+ "void test(Ptr<Foo> &V) { V^->a; }");
+ testWalk(R"cpp(
+ template <typename T> struct PtrBase { T *operator->(); T &operator*(); };
+ template <typename T> struct $implicit^Ptr : PtrBase<T> {};
+ struct Foo { int a; };)cpp",
+ "void test(Ptr<Foo> &V) { (^*V).a; }");
}
TEST(WalkAST, VarDecls) {
|
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
A member operator call reported the provider of
getArg(0)->getType(). For an operator inherited from a base class, that argument is a derived-to-base implicit cast, so the use was attributed to the base class instead of the type the operator was called on.VisitMemberExpralready strips implicit casts, sop.get()andp->xdisagreed.With libstdc++,
std::shared_ptrinheritsoperator->andoperator*fromstd::__shared_ptr_accessinbits/shared_ptr_base.h, somisc-include-cleanerreported<memory>as unused afterp->x, while libc++, which declares them onstd::shared_ptr, did not.This strips implicit casts from the object argument the same way, and adds
WalkASTtests for inheritedoperator+,operator->andoperator*.Fixes #240048