#include "../clang-tidy/utils/DeclRefExprUtils.h" #include "ClangTidyDiagnosticConsumer.h" #include "ClangTidyTest.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" #include "gtest/gtest.h" namespace clang { namespace tidy { namespace { using namespace clang::ast_matchers; class ConstReferenceDeclRefExprsTransform : public ClangTidyCheck { public: ConstReferenceDeclRefExprsTransform(StringRef CheckName, ClangTidyContext *Context) : ClangTidyCheck(CheckName, Context) {} void registerMatchers(MatchFinder *Finder) override { Finder->addMatcher(varDecl(hasName("target")).bind("var"), this); } void check(const MatchFinder::MatchResult &Result) override { const auto *D = Result.Nodes.getNodeAs("var"); using utils::decl_ref_expr::constReferenceDeclRefExprs; const auto const_decrefexprs = constReferenceDeclRefExprs( *D, *cast(D->getDeclContext())->getBody(), *Result.Context); for (const DeclRefExpr *const Expr : const_decrefexprs) { assert(Expr); diag(Expr->getBeginLoc(), "const usage") << FixItHint::CreateInsertion(Expr->getBeginLoc(), "/*const*/"); } } }; } // namespace namespace test { void RunTest(StringRef Snippet) { StringRef CommonCode = R"( struct ConstTag{}; struct NonConstTag{}; struct S { void constMethod() const; void nonConstMethod(); void operator()(ConstTag) const; void operator()(NonConstTag); void operator[](int); void operator[](int) const; bool operator==(const S&) const; int int_member; int* ptr_member; }; struct Derived : public S { }; void useVal(S); void useRef(S&); void usePtr(S*); void usePtrPtr(S**); void usePtrConstPtr(S* const*); void useConstRef(const S&); void useConstPtr(const S*); void useConstPtrRef(const S*&); void useConstPtrPtr(const S**); void useConstPtrConstRef(const S* const&); void useConstPtrConstPtr(const S* const*); void useInt(int); void useIntRef(int&); void useIntConstRef(const int&); void useIntPtr(int*); void useIntConstPtr(const int*); )"; std::string Code = (CommonCode + Snippet).str(); llvm::SmallVector Parts; StringRef(Code).split(Parts, "/*const*/"); EXPECT_EQ(Code, runCheckOnCode( join(Parts, ""))); } TEST(ConstReferenceDeclRefExprsTest, ConstValueVar) { RunTest(R"( void f(const S target) { useVal(/*const*/target); useConstRef(/*const*/target); useConstPtr(&target); useConstPtrConstRef(&target); /*const*/target.constMethod(); /*const*/target(ConstTag{}); /*const*/target[42]; useConstRef((/*const*/target)); (/*const*/target).constMethod(); (void)(/*const*/target == /*const*/target); (void)target; (void)⌖ (void)*⌖ S copy1 = /*const*/target; S copy2(/*const*/target); useInt(/*const*/target.int_member); useIntConstRef(/*const*/target.int_member); useIntPtr(target.ptr_member); useIntConstPtr(&target.int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, ConstRefVar) { RunTest(R"( void f(const S& target) { useVal(/*const*/target); useConstRef(/*const*/target); useConstPtr(&target); useConstPtrConstRef(&target); /*const*/target.constMethod(); /*const*/target(ConstTag{}); /*const*/target[42]; useConstRef((/*const*/target)); (/*const*/target).constMethod(); (void)(/*const*/target == /*const*/target); (void)target; (void)⌖ (void)*⌖ S copy1 = /*const*/target; S copy2(/*const*/target); useInt(/*const*/target.int_member); useIntConstRef(/*const*/target.int_member); useIntPtr(target.ptr_member); useIntConstPtr(&target.int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, ValueVar) { RunTest(R"( void f(S target, const S& other) { useConstRef(/*const*/target); useVal(/*const*/target); useConstPtr(&target); useConstPtrConstRef(&target); /*const*/target.constMethod(); target.nonConstMethod(); /*const*/target(ConstTag{}); target[42]; /*const*/target(ConstTag{}); target(NonConstTag{}); useRef(target); usePtr(&target); useConstRef((/*const*/target)); (/*const*/target).constMethod(); (void)(/*const*/target == /*const*/target); (void)(/*const*/target == other); (void)target; (void)⌖ (void)*⌖ S copy1 = /*const*/target; S copy2(/*const*/target); useInt(/*const*/target.int_member); useIntConstRef(/*const*/target.int_member); useIntPtr(target.ptr_member); useIntConstPtr(&target.int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, RefVar) { RunTest(R"( void f(S& target) { useVal(/*const*/target); useConstRef(/*const*/target); useConstPtr(&target); useConstPtrConstRef(&target); /*const*/target.constMethod(); target.nonConstMethod(); /*const*/target(ConstTag{}); target[42]; useConstRef((/*const*/target)); (/*const*/target).constMethod(); (void)(/*const*/target == /*const*/target); (void)target; (void)⌖ (void)*⌖ S copy1 = /*const*/target; S copy2(/*const*/target); useInt(/*const*/target.int_member); useIntConstRef(/*const*/target.int_member); useIntPtr(target.ptr_member); useIntConstPtr(&target.int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, PtrVar) { RunTest(R"( void f(S* target) { useVal(*target); useConstRef(*target); useConstPtr(target); useConstPtrConstRef(/*const*/target); /*const*/target->constMethod(); target->nonConstMethod(); (*target)(ConstTag{}); (*target)[42]; target->operator[](42); useConstRef((*target)); (/*const*/target)->constMethod(); (void)(*target == *target); (void)*target; (void)target; S copy1 = *target; S copy2(*target); useInt(target->int_member); useIntConstRef(target->int_member); useIntPtr(target->ptr_member); useIntConstPtr(&target->int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, ConstPtrVar) { RunTest(R"( void f(const S* target) { useVal(*target); useConstRef(*target); useConstPtr(target); useConstPtrRef(target); useConstPtrPtr(&target); useConstPtrConstPtr(&target); useConstPtrConstRef(/*const*/target); /*const*/target->constMethod(); (*target)(ConstTag{}); (*target)[42]; /*const*/target->operator[](42); (void)(*target == *target); (void)target; (void)*target; if(target) {} S copy1 = *target; S copy2(*target); useInt(target->int_member); useIntConstRef(target->int_member); useIntPtr(target->ptr_member); useIntConstPtr(&target->int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, ConstPtrPtrVar) { RunTest(R"( void f(const S** target) { useVal(**target); useConstRef(**target); useConstPtr(*target); useConstPtrRef(*target); useConstPtrPtr(target); useConstPtrConstPtr(target); useConstPtrConstRef(*target); (void)target; (void)*target; (void)**target; if(target) {} if(*target) {} S copy1 = **target; S copy2(**target); useInt((*target)->int_member); useIntConstRef((*target)->int_member); useIntPtr((*target)->ptr_member); useIntConstPtr(&(*target)->int_member); } )"); } TEST(ConstReferenceDeclRefExprsTest, ConstPtrConstPtrVar) { RunTest(R"( void f(const S* const* target) { useVal(**target); useConstRef(**target); useConstPtr(*target); useConstPtrConstPtr(target); useConstPtrConstRef(*target); (void)target; (void)target; (void)**target; if(target) {} if(*target) {} S copy1 = **target; S copy2(**target); useInt((*target)->int_member); useIntConstRef((*target)->int_member); useIntPtr((*target)->ptr_member); useIntConstPtr(&(*target)->int_member); } )"); } } // namespace test } // namespace tidy } // namespace clang