diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -87,14 +87,16 @@ public: ASTWalker(DeclCallback Callback) : Callback(Callback) {} + // Operators are always ADL extension points, by design references to them + // doesn't count as uses (generally the type should provide them). Hence + // treat these as implicit references. + // We do this in traverse to make sure rest of the visitor doesn't see + // operator calls. bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *S) { if (!WalkUpFromCXXOperatorCallExpr(S)) return false; - - // Operators are always ADL extension points, by design references to them - // doesn't count as uses (generally the type should provide them). - // Don't traverse the callee. - + report(S->getOperatorLoc(), llvm::cast(S->getCalleeDecl()), + RefType::Implicit); for (auto *Arg : S->arguments()) if (!TraverseStmt(Arg)) return false; diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -292,12 +292,13 @@ TEST(WalkAST, Operator) { // References to operators are not counted as uses. - testWalk("struct string {}; int operator+(string, string);", + testWalk("struct string {}; int $implicit^operator+(string, string);", "int k = string() ^+ string();"); - testWalk("struct string {int operator+(string); }; ", - "int k = string() ^+ string();"); - testWalk("struct string { friend int operator+(string, string); }; ", + testWalk("struct string {int $implicit^operator+(string); }; ", "int k = string() ^+ string();"); + testWalk( + "struct string { friend int $implicit^operator+(string, string); }; ", + "int k = string() ^+ string();"); } TEST(WalkAST, Functions) {