[clang-tidy] Add inconsistent declaration parameter name check

This is first of series of patches, porting code from my project colobot-lint,
as I mentioned recently in cfe-dev mailing list.

This patch adds a new check in readability module:
readability-inconsistent-declaration-parameter-name. I also added appropriate
testcases and documentation.

I chose readability module, as it seems it is the best place for it.

I think I followed the rules of LLVM coding guideline, but I may have missed
something, as I usually use other code formatting style.

http://reviews.llvm.org/D12462

Patch by Piotr Dziwinski!

llvm-svn: 247261
This commit is contained in:
Alexander Kornienko 2015-09-10 10:07:11 +00:00
parent 1d7f0faf93
commit 11d4d6446e
7 changed files with 606 additions and 0 deletions

View File

@ -6,6 +6,7 @@ add_clang_library(clangTidyReadabilityModule
ElseAfterReturnCheck.cpp
FunctionSizeCheck.cpp
IdentifierNamingCheck.cpp
InconsistentDeclarationParameterNameCheck.cpp
NamedParameterCheck.cpp
NamespaceCommentCheck.cpp
ReadabilityTidyModule.cpp

View File

@ -0,0 +1,336 @@
//===--- 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"
#include <algorithm>
#include <functional>
#include <sstream>
namespace clang {
namespace tidy {
namespace readability {
using namespace ast_matchers;
namespace {
AST_MATCHER(FunctionDecl, hasOtherDeclarations) {
auto It = Node.redecls_begin();
auto EndIt = Node.redecls_end();
if (It == EndIt)
return false;
++It;
return It != EndIt;
}
struct DifferingParamInfo {
DifferingParamInfo(StringRef SourceName, StringRef OtherName,
SourceRange OtherNameRange, bool GenerateFixItHint)
: SourceName(SourceName), OtherName(OtherName),
OtherNameRange(OtherNameRange), GenerateFixItHint(GenerateFixItHint) {}
StringRef SourceName;
StringRef OtherName;
SourceRange OtherNameRange;
bool GenerateFixItHint;
};
using DifferingParamsContainer = llvm::SmallVector<DifferingParamInfo, 10>;
struct InconsistentDeclarationInfo {
InconsistentDeclarationInfo(SourceLocation DeclarationLocation,
DifferingParamsContainer &&DifferingParams)
: DeclarationLocation(DeclarationLocation),
DifferingParams(std::move(DifferingParams)) {}
SourceLocation DeclarationLocation;
DifferingParamsContainer DifferingParams;
};
using InconsistentDeclarationsContainer =
llvm::SmallVector<InconsistentDeclarationInfo, 2>;
bool checkIfFixItHintIsApplicable(
const FunctionDecl *ParameterSourceDeclaration,
const ParmVarDecl *SourceParam, const FunctionDecl *OriginalDeclaration) {
// Assumptions with regard to function declarations/definition:
// * If both function declaration and definition are seen, assume that
// definition is most up-to-date, and use it to generate replacements.
// * If only function declarations are seen, there is no easy way to tell
// which is up-to-date and which is not, so don't do anything.
// TODO: This may be changed later, but for now it seems the reasonable
// solution.
if (!ParameterSourceDeclaration->isThisDeclarationADefinition())
return false;
// Assumption: if parameter is not referenced in function defintion body, it
// may indicate that it's outdated, so don't touch it.
if (!SourceParam->isReferenced())
return false;
// In case there is the primary template definition and (possibly several)
// template specializations (and each with possibly several redeclarations),
// it is not at all clear what to change.
if (OriginalDeclaration->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization)
return false;
// Other cases seem OK to allow replacements.
return true;
}
DifferingParamsContainer
findDifferingParamsInDeclaration(const FunctionDecl *ParameterSourceDeclaration,
const FunctionDecl *OtherDeclaration,
const FunctionDecl *OriginalDeclaration) {
DifferingParamsContainer DifferingParams;
auto SourceParamIt = ParameterSourceDeclaration->param_begin();
auto OtherParamIt = OtherDeclaration->param_begin();
while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
OtherParamIt != OtherDeclaration->param_end()) {
auto SourceParamName = (*SourceParamIt)->getName();
auto OtherParamName = (*OtherParamIt)->getName();
// FIXME: Provide a way to extract commented out parameter name from comment
// next to it.
if (!SourceParamName.empty() && !OtherParamName.empty() &&
SourceParamName != OtherParamName) {
SourceRange OtherParamNameRange =
DeclarationNameInfo((*OtherParamIt)->getDeclName(),
(*OtherParamIt)->getLocation()).getSourceRange();
bool GenerateFixItHint = checkIfFixItHintIsApplicable(
ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
DifferingParams.emplace_back(SourceParamName, OtherParamName,
OtherParamNameRange, GenerateFixItHint);
}
++SourceParamIt;
++OtherParamIt;
}
return DifferingParams;
}
InconsistentDeclarationsContainer
findInconsitentDeclarations(const FunctionDecl *OriginalDeclaration,
const FunctionDecl *ParameterSourceDeclaration,
SourceManager &SM) {
InconsistentDeclarationsContainer InconsistentDeclarations;
SourceLocation ParameterSourceLocation =
ParameterSourceDeclaration->getLocation();
for (const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
SourceLocation OtherLocation = OtherDeclaration->getLocation();
if (OtherLocation != ParameterSourceLocation) { // Skip self.
DifferingParamsContainer DifferingParams =
findDifferingParamsInDeclaration(ParameterSourceDeclaration,
OtherDeclaration,
OriginalDeclaration);
if (!DifferingParams.empty()) {
InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
std::move(DifferingParams));
}
}
}
// Sort in order of appearance in translation unit to generate clear
// diagnostics.
std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
[&SM](const InconsistentDeclarationInfo &Info1,
const InconsistentDeclarationInfo &Info2) {
return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
Info2.DeclarationLocation);
});
return InconsistentDeclarations;
}
const FunctionDecl *
getParameterSourceDeclaration(const FunctionDecl *OriginalDeclaration) {
const FunctionTemplateDecl *PrimaryTemplate =
OriginalDeclaration->getPrimaryTemplate();
if (PrimaryTemplate != nullptr) {
// In case of template specializations, use primary template declaration as
// the source of parameter names.
return PrimaryTemplate->getTemplatedDecl();
}
// In other cases, try to change to function definition, if available.
if (OriginalDeclaration->isThisDeclarationADefinition())
return OriginalDeclaration;
for (const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
if (OtherDeclaration->isThisDeclarationADefinition()) {
return OtherDeclaration;
}
}
// No definition found, so return original declaration.
return OriginalDeclaration;
}
std::string joinParameterNames(
const DifferingParamsContainer &DifferingParams,
std::function<StringRef(const DifferingParamInfo &)> ChooseParamName) {
llvm::SmallVector<char, 40> Buffer;
llvm::raw_svector_ostream Str(Buffer);
bool First = true;
for (const DifferingParamInfo &ParamInfo : DifferingParams) {
if (First)
First = false;
else
Str << ", ";
Str << "'" << ChooseParamName(ParamInfo).str() << "'";
}
return Str.str().str();
}
void formatDifferingParamsDiagnostic(
InconsistentDeclarationParameterNameCheck *Check,
const SourceLocation &Location, StringRef OtherDeclarationDescription,
const DifferingParamsContainer &DifferingParams) {
auto ChooseOtherName =
[](const DifferingParamInfo &ParamInfo) { return ParamInfo.OtherName; };
auto ChooseSourceName =
[](const DifferingParamInfo &ParamInfo) { return ParamInfo.SourceName; };
auto ParamDiag =
Check->diag(Location,
"differing parameters are named here: (%0), in %1: (%2)",
DiagnosticIDs::Level::Note)
<< joinParameterNames(DifferingParams, ChooseOtherName)
<< OtherDeclarationDescription
<< joinParameterNames(DifferingParams, ChooseSourceName);
for (const DifferingParamInfo &ParamInfo : DifferingParams) {
if (ParamInfo.GenerateFixItHint) {
ParamDiag << FixItHint::CreateReplacement(
CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
ParamInfo.SourceName);
}
}
}
void formatDiagnosticsForDeclarations(
InconsistentDeclarationParameterNameCheck *Check,
const FunctionDecl *ParameterSourceDeclaration,
const FunctionDecl *OriginalDeclaration,
const InconsistentDeclarationsContainer &InconsistentDeclarations) {
Check->diag(
OriginalDeclaration->getLocation(),
"function %q0 has %1 other declaration%s1 with different parameter names")
<< OriginalDeclaration
<< static_cast<int>(InconsistentDeclarations.size());
int Count = 1;
for (const InconsistentDeclarationInfo &InconsistentDeclaration :
InconsistentDeclarations) {
Check->diag(InconsistentDeclaration.DeclarationLocation,
"the %ordinal0 inconsistent declaration seen here",
DiagnosticIDs::Level::Note)
<< Count;
formatDifferingParamsDiagnostic(
Check, InconsistentDeclaration.DeclarationLocation,
"the other declaration", InconsistentDeclaration.DifferingParams);
++Count;
}
}
void formatDiagnostics(
InconsistentDeclarationParameterNameCheck *Check,
const FunctionDecl *ParameterSourceDeclaration,
const FunctionDecl *OriginalDeclaration,
const InconsistentDeclarationsContainer &InconsistentDeclarations,
StringRef FunctionDescription, StringRef ParameterSourceDescription) {
for (const InconsistentDeclarationInfo &InconsistentDeclaration :
InconsistentDeclarations) {
Check->diag(InconsistentDeclaration.DeclarationLocation,
"%0 %q1 has a %2 with different parameter names")
<< FunctionDescription << OriginalDeclaration
<< ParameterSourceDescription;
Check->diag(ParameterSourceDeclaration->getLocation(), "the %0 seen here",
DiagnosticIDs::Level::Note)
<< ParameterSourceDescription;
formatDifferingParamsDiagnostic(
Check, InconsistentDeclaration.DeclarationLocation,
ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
}
}
} // anonymous namespace
void InconsistentDeclarationParameterNameCheck::registerMatchers(
MatchFinder *Finder) {
Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
.bind("functionDecl"),
this);
}
void InconsistentDeclarationParameterNameCheck::check(
const MatchFinder::MatchResult &Result) {
const auto *OriginalDeclaration =
Result.Nodes.getNodeAs<FunctionDecl>("functionDecl");
if (VisitedDeclarations.count(OriginalDeclaration) > 0)
return; // Avoid multiple warnings.
const FunctionDecl *ParameterSourceDeclaration =
getParameterSourceDeclaration(OriginalDeclaration);
InconsistentDeclarationsContainer InconsistentDeclarations =
findInconsitentDeclarations(OriginalDeclaration,
ParameterSourceDeclaration,
*Result.SourceManager);
if (InconsistentDeclarations.empty()) {
// Avoid unnecessary further visits.
markRedeclarationsAsVisited(OriginalDeclaration);
return;
}
if (OriginalDeclaration->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
formatDiagnostics(this, ParameterSourceDeclaration, OriginalDeclaration,
InconsistentDeclarations,
"function template specialization",
"primary template declaration");
} else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
formatDiagnostics(this, ParameterSourceDeclaration, OriginalDeclaration,
InconsistentDeclarations, "function", "definition");
} else {
formatDiagnosticsForDeclarations(this, ParameterSourceDeclaration,
OriginalDeclaration,
InconsistentDeclarations);
}
markRedeclarationsAsVisited(OriginalDeclaration);
}
void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
const FunctionDecl *OriginalDeclaration) {
for (const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
VisitedDeclarations.insert(Redecl);
}
}
} // namespace readability
} // namespace tidy
} // namespace clang

View File

@ -0,0 +1,45 @@
//===- 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 "llvm/ADT/DenseSet.h"
namespace clang {
namespace tidy {
namespace readability {
/// \brief Checks for declarations of functions which differ in parameter names.
///
/// For detailed documentation see:
/// http://clang.llvm.org/extra/clang-tidy/checks/readability-inconsistent-declaration-parameter-name.html
///
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:
void markRedeclarationsAsVisited(const FunctionDecl *FunctionDeclaration);
llvm::DenseSet<const FunctionDecl *> VisitedDeclarations;
};
} // namespace readability
} // namespace tidy
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_INCONSISTENT_DECLARATION_PARAMETER_NAME_H

View File

@ -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"
@ -37,6 +38,8 @@ public:
"readability-function-size");
CheckFactories.registerCheck<IdentifierNamingCheck>(
"readability-identifier-naming");
CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
"readability-inconsistent-declaration-parameter-name");
CheckFactories.registerCheck<readability::NamedParameterCheck>(
"readability-named-parameter");
CheckFactories.registerCheck<RedundantSmartptrGetCheck>(

View File

@ -50,6 +50,7 @@ List of clang-tidy Checks
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

View File

@ -0,0 +1,32 @@
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
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:: c++
void foo(int a);
void foo(int); // no warning
If there are multiple declarations of same function, only one warning will be
generated.

View File

@ -0,0 +1,188 @@
// 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 2 other declarations with different parameter names [readability-inconsistent-declaration-parameter-name]
void inconsistentFunction(int a, int b, int c);
// CHECK-MESSAGES: :[[@LINE+2]]:6: note: the 1st inconsistent declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('d', 'e', 'f'), in the other declaration: ('a', 'b', 'c')
void inconsistentFunction(int d, int e, int f);
// CHECK-MESSAGES: :[[@LINE+2]]:6: note: the 2nd inconsistent declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('x', 'y', 'z'), in the other declaration: ('a', 'b', 'c')
void inconsistentFunction(int x, int y, int z);
//////////////////////////////////////////////////////
// CHECK-MESSAGES: :[[@LINE+4]]:6: warning: function 'inconsistentFunctionWithVisibleDefinition' has a definition with different parameter names [readability-inconsistent-declaration-parameter-name]
// CHECK-MESSAGES: :[[@LINE+9]]:6: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:6: note: differing parameters are named here: ('a'), in definition: ('c')
// CHECK-FIXES: void inconsistentFunctionWithVisibleDefinition(int c);
void inconsistentFunctionWithVisibleDefinition(int a);
// CHECK-MESSAGES: :[[@LINE+4]]:6: warning: function 'inconsistentFunctionWithVisibleDefinition' has a definition
// CHECK-MESSAGES: :[[@LINE+4]]:6: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:6: note: differing parameters are named here: ('b'), in definition: ('c')
// CHECK-FIXES: void inconsistentFunctionWithVisibleDefinition(int c);
void inconsistentFunctionWithVisibleDefinition(int b);
void inconsistentFunctionWithVisibleDefinition(int c) { c; }
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function 'inconsidentFunctionWithUnreferencedParameterInDefinition' has a definition
// CHECK-MESSAGES: :[[@LINE+3]]:6: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('a'), in definition: ('b')
void inconsidentFunctionWithUnreferencedParameterInDefinition(int a);
void inconsidentFunctionWithUnreferencedParameterInDefinition(int b) {}
//////////////////////////////////////////////////////
struct Struct {
// CHECK-MESSAGES: :[[@LINE+4]]:8: warning: function 'Struct::inconsistentFunction' has a definition
// CHECK-MESSAGES: :[[@LINE+6]]:14: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:8: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: void inconsistentFunction(int b);
void inconsistentFunction(int a);
};
void Struct::inconsistentFunction(int b) { b = 0; }
//////////////////////////////////////////////////////
struct SpecialFunctions {
// CHECK-MESSAGES: :[[@LINE+4]]:3: warning: function 'SpecialFunctions::SpecialFunctions' has a definition
// CHECK-MESSAGES: :[[@LINE+12]]:19: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:3: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: SpecialFunctions(int b);
SpecialFunctions(int a);
// CHECK-MESSAGES: :[[@LINE+4]]:21: warning: function 'SpecialFunctions::operator=' has a definition
// CHECK-MESSAGES: :[[@LINE+8]]:37: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:21: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: SpecialFunctions& operator=(const SpecialFunctions& b);
SpecialFunctions& operator=(const SpecialFunctions& a);
};
SpecialFunctions::SpecialFunctions(int b) { b; }
SpecialFunctions& SpecialFunctions::operator=(const SpecialFunctions& b) { b; return *this; }
//////////////////////////////////////////////////////
// CHECK-MESSAGES: :[[@LINE+5]]:6: warning: function 'templateFunctionWithSeparateDeclarationAndDefinition' has a definition
// CHECK-MESSAGES: :[[@LINE+7]]:6: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+3]]:6: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: void templateFunctionWithSeparateDeclarationAndDefinition(T b);
template<typename T>
void templateFunctionWithSeparateDeclarationAndDefinition(T a);
template<typename T>
void templateFunctionWithSeparateDeclarationAndDefinition(T b) { b; }
//////////////////////////////////////////////////////
template<typename T>
void templateFunctionWithSpecializations(T a) { a; }
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSpecializations<int>' has a primary template declaration with different parameter names [readability-inconsistent-declaration-parameter-name]
// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
void templateFunctionWithSpecializations(int b) { b; }
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSpecializations<float>' has a primary template
// CHECK-MESSAGES: :[[@LINE-10]]:6: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
void templateFunctionWithSpecializations(float c) { c; }
//////////////////////////////////////////////////////
template<typename T>
void templateFunctionWithoutDefinitionButWithSpecialization(T a);
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithoutDefinitionButWithSpecialization<int>' has a primary template
// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
void templateFunctionWithoutDefinitionButWithSpecialization(int b) { b; }
//////////////////////////////////////////////////////
template<typename T>
void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(T a);
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSeparateSpecializationDeclarationAndDefinition<int>' has a primary template
// CHECK-MESSAGES: :[[@LINE-4]]:6: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int b);
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:6: warning: function template specialization 'templateFunctionWithSeparateSpecializationDeclarationAndDefinition<int>' has a primary template
// CHECK-MESSAGES: :[[@LINE-10]]:6: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:6: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
void templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int c) { c; }
//////////////////////////////////////////////////////
template<typename T>
class ClassTemplate
{
public:
// CHECK-MESSAGES: :[[@LINE+4]]:10: warning: function 'ClassTemplate::functionInClassTemplateWithSeparateDeclarationAndDefinition' has a definition
// CHECK-MESSAGES: :[[@LINE+7]]:24: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:10: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: void functionInClassTemplateWithSeparateDeclarationAndDefinition(int b);
void functionInClassTemplateWithSeparateDeclarationAndDefinition(int a);
};
template<typename T>
void ClassTemplate<T>::functionInClassTemplateWithSeparateDeclarationAndDefinition(int b) { b; }
//////////////////////////////////////////////////////
class Class
{
public:
template<typename T>
// CHECK-MESSAGES: :[[@LINE+4]]:8: warning: function 'Class::memberFunctionTemplateWithSeparateDeclarationAndDefinition' has a definition
// CHECK-MESSAGES: :[[@LINE+12]]:13: note: the definition seen here
// CHECK-MESSAGES: :[[@LINE+2]]:8: note: differing parameters are named here: ('a'), in definition: ('b')
// CHECK-FIXES: void memberFunctionTemplateWithSeparateDeclarationAndDefinition(T b);
void memberFunctionTemplateWithSeparateDeclarationAndDefinition(T a);
template<typename T>
void memberFunctionTemplateWithSpecializations(T a) { a; }
};
//////////////////////////////////////////////////////
template<typename T>
void Class::memberFunctionTemplateWithSeparateDeclarationAndDefinition(T b) { b; }
//////////////////////////////////////////////////////
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:13: warning: function template specialization 'Class::memberFunctionTemplateWithSpecializations<int>' has a primary template
// CHECK-MESSAGES: :[[@LINE-12]]:8: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:13: note: differing parameters are named here: ('b'), in primary template declaration: ('a')
void Class::memberFunctionTemplateWithSpecializations(int b) { b; }
template<>
// CHECK-MESSAGES: :[[@LINE+3]]:13: warning: function template specialization 'Class::memberFunctionTemplateWithSpecializations<float>' has a primary template
// CHECK-MESSAGES: :[[@LINE-18]]:8: note: the primary template declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:13: note: differing parameters are named here: ('c'), in primary template declaration: ('a')
void Class::memberFunctionTemplateWithSpecializations(float c) { c; }
//////////////////////////////////////////////////////
#define DECLARE_FUNCTION_WITH_PARAM_NAME(function_name, param_name) \
void function_name(int param_name)
// CHECK-MESSAGES: :[[@LINE+1]]:34: warning: function 'macroFunction' has 1 other declaration with different parameter names [readability-inconsistent-declaration-parameter-name]
DECLARE_FUNCTION_WITH_PARAM_NAME(macroFunction, a);
// CHECK-MESSAGES: :[[@LINE+2]]:34: note: the 1st inconsistent declaration seen here
// CHECK-MESSAGES: :[[@LINE+1]]:34: note: differing parameters are named here: ('b'), in the other declaration: ('a')
DECLARE_FUNCTION_WITH_PARAM_NAME(macroFunction, b);