425 lines · cpp
1#include "../clang-tidy/utils/DeclRefExprUtils.h"2#include "ClangTidyDiagnosticConsumer.h"3#include "ClangTidyTest.h"4#include "clang/ASTMatchers/ASTMatchFinder.h"5#include "clang/ASTMatchers/ASTMatchers.h"6#include "clang/Tooling/Tooling.h"7#include "gtest/gtest.h"8 9namespace clang {10namespace tidy {11 12namespace {13using namespace clang::ast_matchers;14 15template <int Indirections>16class ConstReferenceDeclRefExprsTransform : public ClangTidyCheck {17public:18 ConstReferenceDeclRefExprsTransform(StringRef CheckName,19 ClangTidyContext *Context)20 : ClangTidyCheck(CheckName, Context) {}21 22 void registerMatchers(MatchFinder *Finder) override {23 Finder->addMatcher(varDecl(hasName("target")).bind("var"), this);24 }25 26 void check(const MatchFinder::MatchResult &Result) override {27 const auto *D = Result.Nodes.getNodeAs<VarDecl>("var");28 using utils::decl_ref_expr::constReferenceDeclRefExprs;29 const auto const_decrefexprs = constReferenceDeclRefExprs(30 *D, *cast<FunctionDecl>(D->getDeclContext())->getBody(),31 *Result.Context, Indirections);32 33 for (const DeclRefExpr *const Expr : const_decrefexprs) {34 assert(Expr);35 diag(Expr->getBeginLoc(), "const usage")36 << FixItHint::CreateInsertion(Expr->getBeginLoc(), "/*const*/");37 }38 }39};40} // namespace41 42namespace test {43 44template <int Indirections> void RunTest(StringRef Snippet) {45 46 StringRef CommonCode = R"(47 struct ConstTag{};48 struct NonConstTag{};49 struct Tag1{};50 51 struct S {52 void constMethod() const;53 void nonConstMethod();54 55 static void staticMethod();56 57 void operator()(ConstTag) const;58 void operator()(NonConstTag);59 60 void operator[](int);61 void operator[](int) const;62 63 int& at(int);64 const int& at(int) const;65 const int& at(Tag1);66 67 int& weird_overload();68 const double& weird_overload() const;69 70 bool operator==(const S&) const;71 72 int int_member;73 // We consider a mutation of the `*ptr_member` to be a const use of74 // `*this`. This is consistent with the semantics of `const`-qualified75 // methods, which prevent modifying `ptr_member` but not `*ptr_member`.76 int* ptr_member;77 78 };79 80 struct Derived : public S {81 82 };83 84 void useVal(S);85 void useRef(S&);86 void usePtr(S*);87 void usePtrPtr(S**);88 void usePtrConstPtr(S* const*);89 void useConstRef(const S&);90 void useConstPtr(const S*);91 void useConstPtrRef(const S*&);92 void useConstPtrPtr(const S**);93 void useConstPtrConstRef(const S* const&);94 void useConstPtrConstPtr(const S* const*);95 96 void useInt(int);97 void useIntRef(int&);98 void useIntConstRef(const int&);99 void useIntPtr(int*);100 void useIntConstPtr(const int*);101 102 )";103 104 std::string Code = (CommonCode + Snippet).str();105 106 llvm::SmallVector<StringRef, 1> Parts;107 StringRef(Code).split(Parts, "/*const*/");108 109 EXPECT_EQ(Code,110 runCheckOnCode<ConstReferenceDeclRefExprsTransform<Indirections>>(111 join(Parts, "")));112}113 114TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) {115 RunTest<0>(R"(116 void f(const S target) {117 useVal(/*const*/target);118 useConstRef(/*const*/target);119 useConstPtr(&/*const*/target);120 useConstPtrConstRef(&/*const*/target);121 /*const*/target.constMethod();122 /*const*/target.staticMethod();123 /*const*/target(ConstTag{});124 /*const*/target[42];125 useConstRef((/*const*/target));126 (/*const*/target).constMethod();127 /*const*/target.staticMethod();128 (void)(/*const*/target == /*const*/target);129 (void)/*const*/target;130 (void)&/*const*/target;131 (void)*&/*const*/target;132 /*const*/target;133 S copy1 = /*const*/target;134 S copy2(/*const*/target);135 /*const*/target.int_member;136 useInt(/*const*/target.int_member);137 useIntConstRef(/*const*/target.int_member);138 useIntPtr(/*const*/target.ptr_member);139 useIntConstPtr(&/*const*/target.int_member);140 141 const S& const_target_ref = /*const*/target;142 const S* const_target_ptr = &/*const*/target;143 }144)");145}146 147TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) {148 RunTest<0>(R"(149 void f(const S& target) {150 useVal(/*const*/target);151 useConstRef(/*const*/target);152 useConstPtr(&/*const*/target);153 useConstPtrConstRef(&/*const*/target);154 /*const*/target.constMethod();155 /*const*/target.staticMethod();156 /*const*/target(ConstTag{});157 /*const*/target[42];158 useConstRef((/*const*/target));159 (/*const*/target).constMethod();160 (void)(/*const*/target == /*const*/target);161 (void)/*const*/target;162 (void)&/*const*/target;163 (void)*&/*const*/target;164 /*const*/target;165 S copy1 = /*const*/target;166 S copy2(/*const*/target);167 /*const*/target.int_member;168 useInt(/*const*/target.int_member);169 useIntConstRef(/*const*/target.int_member);170 useIntPtr(/*const*/target.ptr_member);171 useIntConstPtr(&/*const*/target.int_member);172 (void)/*const*/target.at(3);173 174 const S& const_target_ref = /*const*/target;175 const S* const_target_ptr = &/*const*/target;176 (void)/*const*/target.at(3);177 }178)");179}180 181TEST(ConstReferenceDeclRefExprsTest, DEBUGREMOVEME) {182 RunTest<0>(R"(183 void f(S target, const S& other) {184 S* target_ptr = ⌖185 }186)");187}188 189TEST(ConstReferenceDeclRefExprsTest, ValueVar) {190 RunTest<0>(R"(191 void f(S target, const S& other) {192 useConstRef(/*const*/target);193 useVal(/*const*/target);194 useConstPtr(&/*const*/target);195 useConstPtrConstRef(&/*const*/target);196 /*const*/target.constMethod();197 /*const*/target.staticMethod();198 target.nonConstMethod();199 /*const*/target(ConstTag{});200 /*const*/target[42];201 /*const*/target(ConstTag{});202 target(NonConstTag{});203 useRef(target);204 usePtr(&target);205 useConstRef((/*const*/target));206 (/*const*/target).constMethod();207 (void)(/*const*/target == /*const*/target);208 (void)(/*const*/target == other);209 (void)/*const*/target;210 (void)&/*const*/target;211 (void)*&/*const*/target;212 /*const*/target;213 S copy1 = /*const*/target;214 S copy2(/*const*/target);215 /*const*/target.int_member;216 useInt(/*const*/target.int_member);217 useIntConstRef(/*const*/target.int_member);218 useIntPtr(/*const*/target.ptr_member);219 useIntConstPtr(&/*const*/target.int_member);220 221 const S& const_target_ref = /*const*/target;222 const S* const_target_ptr = &/*const*/target;223 S* target_ptr = ⌖224 225 (void)/*const*/target.at(3);226 ++target.at(3);227 const int civ = /*const*/target.at(3);228 const int& cir = /*const*/target.at(3);229 int& ir = target.at(3);230 target.at(Tag1{});231 target.weird_overload();232 }233)");234}235 236TEST(ConstReferenceDeclRefExprsTest, RefVar) {237 RunTest<0>(R"(238 void f(S& target) {239 useVal(/*const*/target);240 usePtr(&target);241 useConstRef(/*const*/target);242 useConstPtr(&/*const*/target);243 useConstPtrConstRef(&/*const*/target);244 /*const*/target.constMethod();245 /*const*/target.staticMethod();246 target.nonConstMethod();247 /*const*/target(ConstTag{});248 /*const*/target[42];249 useConstRef((/*const*/target));250 (/*const*/target).constMethod();251 (void)(/*const*/target == /*const*/target);252 (void)/*const*/target;253 (void)&/*const*/target;254 (void)*&/*const*/target;255 /*const*/target;256 S copy1 = /*const*/target;257 S copy2(/*const*/target);258 /*const*/target.int_member;259 useInt(/*const*/target.int_member);260 useIntConstRef(/*const*/target.int_member);261 useIntPtr(/*const*/target.ptr_member);262 useIntConstPtr(&/*const*/target.int_member);263 264 (void)(&/*const*/target)->int_member;265 useIntRef((&target)->int_member);266 267 const S& const_target_ref = /*const*/target;268 const S* const_target_ptr = &/*const*/target;269 S* target_ptr = ⌖270 271 (void)/*const*/target.at(3);272 ++target.at(3);273 const int civ = /*const*/target.at(3);274 const int& cir = /*const*/target.at(3);275 int& ir = target.at(3);276 target.at(Tag1{});277 target.weird_overload();278 }279)");280}281 282TEST(ConstReferenceDeclRefExprsTest, PtrVar) {283 RunTest<1>(R"(284 void f(S* target) {285 useVal(*/*const*/target);286 usePtr(target);287 useConstRef(*/*const*/target);288 useConstPtr(/*const*/target);289 useConstPtrConstRef(/*const*/target);290 usePtrConstPtr(&target);291 /*const*/target->constMethod();292 /*const*/target->staticMethod();293 target->nonConstMethod();294 (*/*const*/target)(ConstTag{});295 (*/*const*/target)[42];296 /*const*/target->operator[](42);297 useConstRef((*/*const*/target));298 (/*const*/target)->constMethod();299 (void)(*/*const*/target == */*const*/target);300 (void)*/*const*/target;301 (void)/*const*/target;302 /*const*/target;303 S copy1 = */*const*/target;304 S copy2(*/*const*/target);305 /*const*/target->int_member;306 useInt(/*const*/target->int_member);307 useIntConstRef(/*const*/target->int_member);308 useIntPtr(/*const*/target->ptr_member);309 useIntConstPtr(&/*const*/target->int_member);310 311 const S& const_target_ref = */*const*/target;312 const S* const_target_ptr = /*const*/target;313 S* target_ptr = target; // FIXME: we could chect const usage of `target_ptr`314 315 (void)/*const*/target->at(3);316 ++target->at(3);317 const int civ = /*const*/target->at(3);318 const int& cir = /*const*/target->at(3);319 int& ir = target->at(3);320 target->at(Tag1{});321 target->weird_overload();322 }323)");324}325 326TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) {327 RunTest<1>(R"(328 void f(const S* target) {329 useVal(*/*const*/target);330 useConstRef(*/*const*/target);331 useConstPtr(/*const*/target);332 useConstPtrRef(/*const*/target);333 useConstPtrPtr(&/*const*/target);334 useConstPtrConstPtr(&/*const*/target);335 useConstPtrConstRef(/*const*/target);336 /*const*/target->constMethod();337 /*const*/target->staticMethod();338 (*/*const*/target)(ConstTag{});339 (*/*const*/target)[42];340 /*const*/target->operator[](42);341 (void)(*/*const*/target == */*const*/target);342 (void)/*const*/target;343 (void)*/*const*/target;344 /*const*/target;345 if(/*const*/target) {}346 S copy1 = */*const*/target;347 S copy2(*/*const*/target);348 /*const*/target->int_member;349 useInt(/*const*/target->int_member);350 useIntConstRef(/*const*/target->int_member);351 useIntPtr(/*const*/target->ptr_member);352 useIntConstPtr(&/*const*/target->int_member);353 354 const S& const_target_ref = */*const*/target;355 const S* const_target_ptr = /*const*/target;356 357 (void)/*const*/target->at(3);358 const int civ = /*const*/target->at(3);359 const int& cir = /*const*/target->at(3);360 }361)");362}363 364TEST(ConstReferenceDeclRefExprsTest, ConstPtrPtrVar) {365 RunTest<2>(R"(366 void f(const S** target) {367 useVal(**/*const*/target);368 useConstRef(**/*const*/target);369 useConstPtr(*/*const*/target);370 useConstPtrRef(*/*const*/target);371 useConstPtrPtr(/*const*/target);372 useConstPtrConstPtr(/*const*/target);373 useConstPtrConstRef(*/*const*/target);374 (void)/*const*/target;375 (void)*/*const*/target;376 (void)**/*const*/target;377 /*const*/target;378 if(/*const*/target) {}379 if(*/*const*/target) {}380 S copy1 = **/*const*/target;381 S copy2(**/*const*/target);382 (*/*const*/target)->int_member;383 useInt((*/*const*/target)->int_member);384 useIntConstRef((*/*const*/target)->int_member);385 useIntPtr((*/*const*/target)->ptr_member);386 useIntConstPtr(&(*/*const*/target)->int_member);387 388 const S& const_target_ref = **/*const*/target;389 const S* const_target_ptr = */*const*/target;390 }391)");392}393 394TEST(ConstReferenceDeclRefExprsTest, ConstPtrConstPtrVar) {395 RunTest<2>(R"(396 void f(const S* const* target) {397 useVal(**/*const*/target);398 useConstRef(**/*const*/target);399 useConstPtr(*/*const*/target);400 useConstPtrConstPtr(/*const*/target);401 useConstPtrConstRef(*/*const*/target);402 (void)/*const*/target;403 (void)*/*const*/target;404 (void)**/*const*/target;405 /*const*/target;406 if(/*const*/target) {}407 if(*/*const*/target) {}408 S copy1 = **/*const*/target;409 S copy2(**/*const*/target);410 (*/*const*/target)->int_member;411 useInt((*/*const*/target)->int_member);412 useIntConstRef((*/*const*/target)->int_member);413 useIntPtr((*/*const*/target)->ptr_member);414 useIntConstPtr(&(*/*const*/target)->int_member);415 416 const S& const_target_ref = **/*const*/target;417 const S* const_target_ptr = */*const*/target;418 }419)");420}421 422} // namespace test423} // namespace tidy424} // namespace clang425