Index: clang-tidy/readability/AvoidConstParamsInDecls.h =================================================================== --- /dev/null +++ clang-tidy/readability/AvoidConstParamsInDecls.h @@ -0,0 +1,33 @@ +//===--- AvoidConstParamsInDecls.h - clang-tidy----------------------------===// +// +// 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_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +// Detect function declarations that have const value parameters and discourage +// them. +class AvoidConstParamsInDecls : public ClangTidyCheck { +public: + using ClangTidyCheck::ClangTidyCheck; + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOID_CONST_PARAMS_IN_DECLS_H Index: clang-tidy/readability/AvoidConstParamsInDecls.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/AvoidConstParamsInDecls.cpp @@ -0,0 +1,71 @@ +//===--- AvoidConstParamsInDecls.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 "AvoidConstParamsInDecls.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace readability { +namespace { + +SourceRange getTypeRange(const ParmVarDecl &Param) { + if (Param.getIdentifier() != nullptr) + return SourceRange(Param.getLocStart(), + Param.getLocEnd().getLocWithOffset(-1)); + return Param.getSourceRange(); +} + +} // namespace + + +void AvoidConstParamsInDecls::registerMatchers(MatchFinder *Finder) { + const auto ConstParamDecl = + parmVarDecl(hasType(qualType(isConstQualified()))).bind("param"); + Finder->addMatcher(functionDecl(unless(isDefinition()), + has(typeLoc(forEach(ConstParamDecl)))) + .bind("func"), + this); +} + +void AvoidConstParamsInDecls::check(const MatchFinder::MatchResult &Result) { + const auto *Func = Result.Nodes.getNodeAs("func"); + const auto *Param = Result.Nodes.getNodeAs("param"); + + QualType Type = Param->getType(); + if (!Type.isLocalConstQualified()) + return; + + Type.removeLocalConst(); + + auto Diag = diag(Param->getLocStart(), + "parameter %0 is const-qualified in the function " + "declaration; const-qualification of parameters only has an " + "effect in function definitions"); + if (Param->getName().empty()) { + for (unsigned int i = 0; i < Func->getNumParams(); ++i) { + if (Param == Func->getParamDecl(i)) { + Diag << (i + 1); + break; + } + } + } else { + Diag << Param; + } + Diag << FixItHint::CreateReplacement(getTypeRange(*Param), + Type.getAsString()); +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyReadabilityModule + AvoidConstParamsInDecls.cpp BracesAroundStatementsCheck.cpp ContainerSizeEmptyCheck.cpp ElseAfterReturnCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AvoidConstParamsInDecls.h" #include "BracesAroundStatementsCheck.h" #include "ContainerSizeEmptyCheck.h" #include "ElseAfterReturnCheck.h" @@ -32,6 +33,8 @@ class ReadabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "readability-avoid-const-params-in-decls"); CheckFactories.registerCheck( "readability-braces-around-statements"); CheckFactories.registerCheck( Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -89,8 +89,9 @@ performance-faster-string-find performance-for-range-copy performance-implicit-cast-in-loop - performance-unnecessary-value-param performance-unnecessary-copy-initialization + performance-unnecessary-value-param + readability-avoid-const-params-in-decls readability-braces-around-statements readability-container-size-empty readability-else-after-return Index: docs/clang-tidy/checks/readability-avoid-const-params-in-decls.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-avoid-const-params-in-decls.rst @@ -0,0 +1,17 @@ +.. title:: clang-tidy - readability-avoid-const-params-in-decls + +readability-avoid-const-params-in-decls +======================================= + +Checks whether a function declaration has parameters that are top level const. + +`const` values in declarations do not affect the signature of a function, so +they should not be put there. For example: + +Examples: + +.. code:: c++ + + void f(const string); // Bad: const is top level. + void f(const string&); // Good: const is not top level. + Index: test/clang-tidy/readability-avoid-const-params-in-decls.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-avoid-const-params-in-decls.cpp @@ -0,0 +1,78 @@ +// RUN: %check_clang_tidy %s readability-avoid-const-params-in-decls %t + +using alias_type = bool; +using alias_const_type = const bool; + + +void F1(const int i); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified in the function declaration; const-qualification of parameters only has an effect in function definitions [readability-avoid-const-params-in-decls] +// CHECK-FIXES: void F1(int i); + +void F2(const int *const i); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified +// CHECK-FIXES: void F2(const int * i); + +void F3(int const i); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified +// CHECK-FIXES: void F3(int i); + +void F4(alias_type const i); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'i' is const-qualified +// CHECK-FIXES: void F4(alias_type i); + +void F5(const int); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified +// CHECK-FIXES: void F5(int); + +void F6(const int *const); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified +// BUG(b/27584482): void F6(const int *); should be produced + +void F7(int, const int); +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: parameter 2 is const-qualified +// CHECK-FIXES: void F7(int, int); + +void F8(const int, const int); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 1 is const-qualified +// CHECK-MESSAGES: :[[@LINE-2]]:20: warning: parameter 2 is const-qualified +// CHECK-FIXES: void F8(int, int); + +void F9(const int long_name); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: parameter 'long_name' +// CHECK-FIXES: void F9(int long_name); + +void F10(const int *const *const long_name); +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: parameter 'long_name' +// CHECK-FIXES: void F10(const int *const * long_name); + + +struct Foo { + Foo(const int i); + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: parameter 'i' + // CHECK-FIXES: Foo(int i); + + void operator()(const int i); + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: parameter 'i' + // CHECK-FIXES: void operator()(int i); +}; + +// Do not match on definitions +void NF1(const int i) {} +void NF2(const int *const i) {} +void NF3(int const i) {} +void NF4(alias_type const i) {} +void NF5(const int) {} +void NF6(const int *const) {} +void NF7(int, const int) {} +void NF8(const int, const int) {} + +// Do not match on other stuff +void NF(const alias_type& i); +void NF(const int &i); +void NF(const int *i); +void NF(alias_const_type i); +void NF(const alias_type&); +void NF(const int&); +void NF(const int*); +void NF(const int* const*); +void NF(alias_const_type);