Index: tools/clang/extra/clang-tidy/readability/CMakeLists.txt =================================================================== --- tools/clang/extra/clang-tidy/readability/CMakeLists.txt +++ tools/clang/extra/clang-tidy/readability/CMakeLists.txt @@ -6,6 +6,7 @@ ElseAfterReturnCheck.cpp FunctionSizeCheck.cpp IdentifierNamingCheck.cpp + InconsistentDeclarationParameterNameCheck.cpp NamedParameterCheck.cpp NamespaceCommentCheck.cpp ReadabilityTidyModule.cpp Index: tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h =================================================================== --- tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h +++ tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.h @@ -0,0 +1,67 @@ +//===--- InconsistentDeclarationParameterNameCheck.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_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H + +#include "../ClangTidy.h" + +#include +#include + +namespace clang { +namespace tidy { +namespace readability { + +/// \brief Checks for declarations of functions which differ in parameter names +/// +/// This check will find inconsistencies between declarations of functions, +/// which are syntactically correct, but use different names of parameters, +/// for example: +/// +/// \code +/// // foo.hpp: +/// void foo(int a, int b, int c); +/// // foo.cpp: +/// void foo(int d, int e, int f) // warning +/// { /* ... */ } +/// \endcode +/// +/// This check should help to enforce consistency in large projects, where it often happens +/// that a definition of function is refactored, changing the parameter names, but its declaration +/// in header file is not updated. With this check, we can easily find and correct such inconsistencies, +/// keeping declaration and definition always in sync. +/// +/// Unnamed parameters are allowed, and are not taken into account when comparing function declarations, for example: +/// \code +/// void foo(int a); +/// void foo(int /*a*/); // no warning +/// \endcode +/// FIXME: provide a way to extract name of unnamed parameter from a comment next to its declaration, as in the example. +/// +/// If there are multiple declarations of same function, only one warning will be generated. +/// +class InconsistentDeclarationParameterNameCheck : public ClangTidyCheck { +public: + InconsistentDeclarationParameterNameCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + std::unordered_set ReportedFunctions; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H + Index: tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp =================================================================== --- tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp +++ tools/clang/extra/clang-tidy/readability/InconsistentDeclarationParameterNameCheck.cpp @@ -0,0 +1,98 @@ +//===--- InconsistentDeclarationParameterNameCheck.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 "InconsistentDeclarationParameterNameCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + + +namespace clang { +namespace tidy { +namespace readability { + +namespace { + +struct CheckResult { + CheckResult(bool HasInconsistentParams, + SourceLocation InconsistentDeclLoc = SourceLocation()) + : HasInconsistentParams(HasInconsistentParams), + InconsistentDeclLoc(InconsistentDeclLoc) {} + + bool HasInconsistentParams; + SourceLocation InconsistentDeclLoc; +}; + +struct InconsistentParamChecker { + static CheckResult checkForInconsitentDeclarationParameters(const FunctionDecl* FunctionDeclaration); +}; + +} // anonymous namespace + +void InconsistentDeclarationParameterNameCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + functionDecl( + unless(anyOf( + isExpansionInSystemHeader(), + isImplicit()))) + .bind("functionDecl"), this); +} + +void InconsistentDeclarationParameterNameCheck::check(const MatchFinder::MatchResult &Result) { + auto* FunctionDeclaration = Result.Nodes.getNodeAs("functionDecl"); + if (FunctionDeclaration == nullptr) + return; + + auto QualName = FunctionDeclaration->getQualifiedNameAsString(); + if (ReportedFunctions.count(QualName) > 0) + return; // avoid multiple warnings + + auto CheckResult = InconsistentParamChecker::checkForInconsitentDeclarationParameters(FunctionDeclaration); + if (CheckResult.HasInconsistentParams) { + diag(FunctionDeclaration->getLocation(), "function '%0' has other declaration with different parameter name(s)") + << QualName; + diag(CheckResult.InconsistentDeclLoc, "other declaration seen here", DiagnosticIDs::Level::Note); + ReportedFunctions.insert(QualName); + } +} + +CheckResult InconsistentParamChecker::checkForInconsitentDeclarationParameters(const FunctionDecl* FunctionDeclaration) { + auto Location = FunctionDeclaration->getLocation(); + + for (const auto& OtherDeclaration : FunctionDeclaration->redecls()) { + if (OtherDeclaration->getLocation() == Location) // skip self + continue; + + auto MyParamIt = FunctionDeclaration->param_begin(); + auto OtherParamIt = OtherDeclaration->param_begin(); + + while (MyParamIt != FunctionDeclaration->param_end() && + OtherParamIt != OtherDeclaration->param_end()) { + auto MyParamName = (*MyParamIt)->getName(); + auto OtherParamName = (*OtherParamIt)->getName(); + + if (!MyParamName.empty() && + !OtherParamName.empty() && + MyParamName != OtherParamName) { + return CheckResult{true, OtherDeclaration->getLocation()}; + } + + ++MyParamIt; + ++OtherParamIt; + } + } + + return CheckResult{false}; +} + +} // namespace readability +} // namespace tidy +} // namespace clang + Index: tools/clang/extra/clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- tools/clang/extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ tools/clang/extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -15,6 +15,7 @@ #include "ElseAfterReturnCheck.h" #include "FunctionSizeCheck.h" #include "IdentifierNamingCheck.h" +#include "InconsistentDeclarationParameterNameCheck.h" #include "NamedParameterCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" @@ -38,6 +39,8 @@ "readability-function-size"); CheckFactories.registerCheck( "readability-identifier-naming"); + CheckFactories.registerCheck( + "readability-inconsistent-declaration-parameter-name"); CheckFactories.registerCheck( "readability-named-parameter"); CheckFactories.registerCheck( Index: tools/clang/extra/docs/clang-tidy/checks/list.rst =================================================================== --- tools/clang/extra/docs/clang-tidy/checks/list.rst +++ tools/clang/extra/docs/clang-tidy/checks/list.rst @@ -47,6 +47,7 @@ readability-else-after-return readability-function-size readability-identifier-naming + readability-inconsistent-declaration-parameter-name readability-named-parameter readability-redundant-smartptr-get readability-redundant-string-cstr Index: tools/clang/extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst =================================================================== --- tools/clang/extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst +++ tools/clang/extra/docs/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.rst @@ -0,0 +1,16 @@ +readability-inconsistent-declaration-parameter-name +=================================================== + + +Find function declarations which differ in parameter names. + +Example: + +.. code:: c++ + + // in foo.hpp: + void foo(int a, int b, int c); + + // in foo.cpp: + void foo(int d, int e, int f); // warning + Index: tools/clang/extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp =================================================================== --- tools/clang/extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp +++ tools/clang/extra/test/clang-tidy/readability-inconsistent-declaration-parameter-name.cpp @@ -0,0 +1,20 @@ +// RUN: %python %S/check_clang_tidy.py %s readability-inconsistent-declaration-parameter-name %t + +void consistentFunction(int a, int b, int c); +void consistentFunction(int a, int b, int c); +void consistentFunction(int a, int b, int /*c*/); +void consistentFunction(int /*c*/, int /*c*/, int /*c*/); + +// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: function 'inconsistentFunction' has other declaration with different parameter name(s) [readability-inconsistent-declaration-parameter-name] +void inconsistentFunction(int a, int b, int c); +void inconsistentFunction(int d, int e, int f); +void inconsistentFunction(int x, int y, int z); + +struct SomeStruct +{ +// CHECK-MESSAGES: :[[@LINE+1]]:10: warning: function 'SomeStruct::inconsistentFunction' has other declaration with different parameter name(s) [readability-inconsistent-declaration-parameter-name] + void inconsistentFunction(int a); +}; + +void SomeStruct::inconsistentFunction(int b) +{}