Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -5,6 +5,7 @@ AssertSideEffectCheck.cpp AssignOperatorSignatureCheck.cpp BoolPointerImplicitConversionCheck.cpp + ConstRefBuiltinCheck.cpp DefinitionsInHeadersCheck.cpp InaccurateEraseCheck.cpp IncorrectRoundings.cpp Index: clang-tidy/misc/ConstRefBuiltinCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/ConstRefBuiltinCheck.h @@ -0,0 +1,39 @@ +//===--- ConstRefBuiltinCheck.h - clang-tidy---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_CONST_REF_BUILTIN_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_CONST_REF_BUILTIN_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace misc { + +/// Checks for function parameters that are const& to builtin types. +/// +/// Const reference to builtin type, such as int, adds an unnecessary layer of +/// indirection. The Check will also warn on const& to typedef to builtin. It +/// will not warn if the const& paramter was due to template instantiation. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc-const-ref-builtin.html +class ConstRefBuiltinCheck : public ClangTidyCheck { +public: + ConstRefBuiltinCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_CONST_REF_BUILTIN_H Index: clang-tidy/misc/ConstRefBuiltinCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/ConstRefBuiltinCheck.cpp @@ -0,0 +1,69 @@ +//===--- ConstRefBuiltinCheck.cpp - clang-tidy-----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ConstRefBuiltinCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace misc { + +void ConstRefBuiltinCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + parmVarDecl(hasType(references( + qualType(isConstQualified()) + .bind("referenced_type"))), + hasType(references(hasCanonicalType(builtinType()))), + unless(hasType(references(substTemplateTypeParmType())))) + .bind("param"), + this); +} + +void ConstRefBuiltinCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Parameter = Result.Nodes.getNodeAs("param"); + const auto *Function = + dyn_cast_or_null(Parameter->getParentFunctionOrMethod()); + + if (Function == nullptr) + return; + + auto ReferencedType = *Result.Nodes.getNodeAs("referenced_type"); + + auto ParamTL = Parameter->getTypeSourceInfo()->getTypeLoc(); + auto TypeRange = CharSourceRange::getTokenRange(Parameter->getLocStart(), + ParamTL.getLocEnd()); + + ReferencedType.removeLocalConst(); + + auto Fix = + FixItHint::CreateReplacement(TypeRange, ReferencedType.getAsString()); + + if (Parameter->getName().empty()) { + auto Diag = diag(Parameter->getLocation(), + "const reference to %0 type at index '%1' in function '%2'") + << ReferencedType + << Parameter->getFunctionScopeIndex() + << Function->getName() + << Fix; + } else { + auto Diag = diag(Parameter->getLocation(), + "const reference to %0 at parameter '%1' in function '%2'") + << ReferencedType + << Parameter->getName() + << Function->getName() + << Fix; + } +} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -14,6 +14,7 @@ #include "AssertSideEffectCheck.h" #include "AssignOperatorSignatureCheck.h" #include "BoolPointerImplicitConversionCheck.h" +#include "ConstRefBuiltinCheck.h" #include "DefinitionsInHeadersCheck.h" #include "InaccurateEraseCheck.h" #include "IncorrectRoundings.h" @@ -53,6 +54,8 @@ "misc-assign-operator-signature"); CheckFactories.registerCheck( "misc-bool-pointer-implicit-conversion"); + CheckFactories.registerCheck( + "misc-const-ref-builtin"); CheckFactories.registerCheck( "misc-definitions-in-headers"); CheckFactories.registerCheck( Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -48,6 +48,7 @@ misc-assert-side-effect misc-assign-operator-signature misc-bool-pointer-implicit-conversion + misc-const-ref-builtin misc-definitions-in-headers misc-inaccurate-erase misc-incorrect-roundings Index: docs/clang-tidy/checks/misc-const-ref-builtin.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-const-ref-builtin.rst @@ -0,0 +1,28 @@ +.. title:: clang-tidy - misc-const-ref-builtin + +misc-const-ref-builtin +====================== + +This check will warn about function arguments that are const refs to builtin +types, such as int or double. It will also warn about const refs to typedefs to +builtin types. It will not flag function arguments that are due to template +instantiations. + +Example code:: + + void f(const int& i); + + +The parameter i will be flagged. + +Example code:: + + template + void g(const T&); + + void X() { + g(5); + } + + +The instantiation of g will not be flagged. Index: test/clang-tidy/misc-const-ref-builtin.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-const-ref-builtin.cpp @@ -0,0 +1,119 @@ +// RUN: %check_clang_tidy %s misc-const-ref-builtin %t + +void f(const int& i); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'int' at parameter 'i' in function 'f' [misc-const-ref-builtin] +// CHECK-FIXES: void f(int i); + +void f(const int& i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'int' at parameter 'i' in function 'f' [misc-const-ref-builtin] + // CHECK-FIXES: void f(int i) { + int k = i; +} + +void f2(const int&); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'int' type at index '0' in function 'f2' [misc-const-ref-builtin] +// CHECK-FIXES: void f2(int) + +void f2(const int& i) { + // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: const reference to 'int' at parameter 'i' in function 'f2' [misc-const-ref-builtin] + // CHECK-FIXES: void f2(int i) { + int k = i; +} + +typedef int Int; +void t(const Int& i); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'Int' (aka 'int') at parameter 'i' in function 't' [misc-const-ref-builtin] +// CHECK-FIXES: void t(Int i) + +void t(const Int& i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'Int' (aka 'int') at parameter 'i' in function 't' [misc-const-ref-builtin] + // CHECK-FIXES: void t(Int i) { + int k = i; +} + +//Function template +template +void g(const T& t_) { + T t = t_; +} + +// Explicit Specialization +template<> +void g(const long& l) { + //CHECK-MESSAGES: :[[@LINE-1]]:26: warning: const reference to 'long' at parameter 'l' in function 'g' [misc-const-ref-builtin] + // CHECK-FIXES: void g(long l) { + long i = l; +} + + +// Explicit Specialization (deduced type) +template<> +void g(const double& d) { + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: const reference to 'double' at parameter 'd' in function 'g' [misc-const-ref-builtin] + // CHECK-FIXES: void g(double d) { + + double f = d; +} + +template +void g2(const T&, const char& c); +// CHECK-MESSAGES: :[[@LINE-1]]:31: warning: const reference to 'char' at parameter 'c' in function 'g2' [misc-const-ref-builtin] +// CHECK-FIXES: void g2(const T&, char c); + +template +class Klass { +public: + void k(const T& t); + void k2(const short& s); + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: const reference to 'short' at parameter 's' in function 'k2' [misc-const-ref-builtin] + // CHECK-FIXES: void k2(short s); + + void k3(const T& t, const short& s); + // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: const reference to 'short' at parameter 's' in function 'k3' [misc-const-ref-builtin] + // CHECK-FIXES: void k3(const T& t, short s); +}; + +class K2 { +public: + template + void f(const T& t); +}; + +class Bar {}; + +void X() { + g(5); + g(123.456); + g2(5,'a'); + Klass kbar; + K2 k2; + k2.f(6); +}; + +void f3(); + +void h(int& i); + +void f4(const Bar& bar); + +class Baz { + int i; +}; + +void f5(const Baz& baz); + +void f(const int& i, const int& j); +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: const reference to 'int' at parameter 'i' in function 'f' [misc-const-ref-builtin] +// CHECK-MESSAGES: :[[@LINE-2]]:33: warning: const reference to 'int' at parameter 'j' in function 'f' [misc-const-ref-builtin] +// CHECK-FIXES: void f(int i, int j); + +#define MAKE_FUNC(Name) void Name(const int& i); + +MAKE_FUNC(test1); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: const reference to 'int' at parameter 'i' in function 'test1' [misc-const-ref-builtin] +// CHECK-FIXES-NOT: void test1(int i); + +#define MAKE_FUNC2(Name, ArgType) void Name(const ArgType& i); +MAKE_FUNC2(test2, int); +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: const reference to 'int' at parameter 'i' in function 'test2' [misc-const-ref-builtin] +// CHECK-FIXES-NOT: void test2(int i);