10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "llvm/ADT/STLExtras.h"
20 auto It = Node.redecls_begin();
21 auto EndIt = Node.redecls_end();
30struct DifferingParamInfo {
31 DifferingParamInfo(StringRef SourceName, StringRef OtherName,
32 SourceRange OtherNameRange,
bool GenerateFixItHint)
33 : SourceName(SourceName), OtherName(OtherName),
34 OtherNameRange(OtherNameRange), GenerateFixItHint(GenerateFixItHint) {}
38 SourceRange OtherNameRange;
39 bool GenerateFixItHint;
42using DifferingParamsContainer = llvm::SmallVector<DifferingParamInfo, 10>;
44struct InconsistentDeclarationInfo {
45 InconsistentDeclarationInfo(SourceLocation DeclarationLocation,
46 DifferingParamsContainer &&DifferingParams)
47 : DeclarationLocation(DeclarationLocation),
48 DifferingParams(std::move(DifferingParams)) {}
50 SourceLocation DeclarationLocation;
51 DifferingParamsContainer DifferingParams;
54using InconsistentDeclarationsContainer =
55 llvm::SmallVector<InconsistentDeclarationInfo, 2>;
61 const ParmVarDecl *SourceParam,
62 const FunctionDecl *OriginalDeclaration) {
70 if (!ParameterSourceDeclaration->isThisDeclarationADefinition())
75 if (!SourceParam->isReferenced())
81 if (OriginalDeclaration->getTemplatedKind() ==
82 FunctionDecl::TK_FunctionTemplateSpecialization)
89static bool nameMatch(StringRef L, StringRef R,
bool Strict) {
91 return L.empty() || R.empty() || L == R;
94 return L.starts_with_insensitive(R) || R.starts_with_insensitive(L) ||
95 L.ends_with_insensitive(R) || R.ends_with_insensitive(L);
98static DifferingParamsContainer
100 const FunctionDecl *OtherDeclaration,
101 const FunctionDecl *OriginalDeclaration,
103 DifferingParamsContainer DifferingParams;
105 const auto *SourceParamIt = ParameterSourceDeclaration->param_begin();
106 const auto *OtherParamIt = OtherDeclaration->param_begin();
108 while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
109 OtherParamIt != OtherDeclaration->param_end()) {
110 if ((*SourceParamIt)->isParameterPack() !=
111 (*OtherParamIt)->isParameterPack())
114 auto SourceParamName = (*SourceParamIt)->getName();
115 auto OtherParamName = (*OtherParamIt)->getName();
119 if (!
nameMatch(SourceParamName, OtherParamName, Strict)) {
120 const SourceRange OtherParamNameRange =
121 DeclarationNameInfo((*OtherParamIt)->getDeclName(),
122 (*OtherParamIt)->getLocation())
126 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
128 DifferingParams.emplace_back(SourceParamName, OtherParamName,
129 OtherParamNameRange, GenerateFixItHint);
136 return DifferingParams;
139static InconsistentDeclarationsContainer
141 const FunctionDecl *ParameterSourceDeclaration,
142 SourceManager &SM,
bool Strict) {
143 InconsistentDeclarationsContainer InconsistentDeclarations;
144 const SourceLocation ParameterSourceLocation =
145 ParameterSourceDeclaration->getLocation();
147 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
148 const SourceLocation OtherLocation = OtherDeclaration->getLocation();
149 if (OtherLocation != ParameterSourceLocation) {
150 DifferingParamsContainer DifferingParams =
153 OriginalDeclaration, Strict);
154 if (!DifferingParams.empty()) {
155 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
156 std::move(DifferingParams));
163 llvm::sort(InconsistentDeclarations,
164 [&SM](
const InconsistentDeclarationInfo &Info1,
165 const InconsistentDeclarationInfo &Info2) {
166 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
167 Info2.DeclarationLocation);
169 return InconsistentDeclarations;
172static const FunctionDecl *
174 const FunctionTemplateDecl *PrimaryTemplate =
175 OriginalDeclaration->getPrimaryTemplate();
176 if (PrimaryTemplate !=
nullptr) {
179 return PrimaryTemplate->getTemplatedDecl();
184 if (OriginalDeclaration->isThisDeclarationADefinition())
185 return OriginalDeclaration;
187 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls())
188 if (OtherDeclaration->isThisDeclarationADefinition())
189 return OtherDeclaration;
192 return OriginalDeclaration;
196 const DifferingParamsContainer &DifferingParams,
197 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
198 llvm::SmallString<40> Str;
200 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
205 Str.append({
"'", ChooseParamName(ParamInfo),
"'"});
207 return std::string(Str);
212 StringRef OtherDeclarationDescription,
213 const DifferingParamsContainer &DifferingParams) {
214 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
215 return ParamInfo.OtherName;
217 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
218 return ParamInfo.SourceName;
223 "differing parameters are named here: (%0), in %1: (%2)",
224 DiagnosticIDs::Level::Note)
226 << OtherDeclarationDescription
229 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
230 if (ParamInfo.GenerateFixItHint) {
231 ParamDiag << FixItHint::CreateReplacement(
232 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
233 ParamInfo.SourceName);
240 const FunctionDecl *ParameterSourceDeclaration,
241 const FunctionDecl *OriginalDeclaration,
242 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
244 OriginalDeclaration->getLocation(),
245 "function %q0 has %1 other declaration%s1 with different parameter names")
246 << OriginalDeclaration
247 <<
static_cast<int>(InconsistentDeclarations.size());
249 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
250 InconsistentDeclarations) {
251 Check->diag(InconsistentDeclaration.DeclarationLocation,
252 "the %ordinal0 inconsistent declaration seen here",
253 DiagnosticIDs::Level::Note)
257 Check, InconsistentDeclaration.DeclarationLocation,
258 "the other declaration", InconsistentDeclaration.DifferingParams);
266 const FunctionDecl *ParameterSourceDeclaration,
267 const FunctionDecl *OriginalDeclaration,
268 const InconsistentDeclarationsContainer &InconsistentDeclarations,
269 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
270 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
271 InconsistentDeclarations) {
272 Check->diag(InconsistentDeclaration.DeclarationLocation,
273 "%0 %q1 has a %2 with different parameter names")
274 << FunctionDescription << OriginalDeclaration
275 << ParameterSourceDescription;
277 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
278 DiagnosticIDs::Level::Note)
279 << ParameterSourceDescription;
282 Check, InconsistentDeclaration.DeclarationLocation,
283 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
289 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
290 Options.store(Opts,
"Strict", Strict);
294 MatchFinder *Finder) {
295 Finder->addMatcher(functionDecl(hasOtherDeclarations()).bind(
"functionDecl"),
300 const MatchFinder::MatchResult &Result) {
301 const auto *OriginalDeclaration =
302 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
304 if (VisitedDeclarations.contains(OriginalDeclaration))
307 const FunctionDecl *ParameterSourceDeclaration =
310 const InconsistentDeclarationsContainer InconsistentDeclarations =
312 ParameterSourceDeclaration,
313 *Result.SourceManager, Strict);
314 if (InconsistentDeclarations.empty()) {
316 markRedeclarationsAsVisited(OriginalDeclaration);
320 const SourceLocation StartLoc = OriginalDeclaration->getBeginLoc();
321 if (StartLoc.isMacroID() && IgnoreMacros) {
322 markRedeclarationsAsVisited(OriginalDeclaration);
326 if (OriginalDeclaration->getTemplatedKind() ==
327 FunctionDecl::TK_FunctionTemplateSpecialization) {
329 InconsistentDeclarations,
330 "function template specialization",
331 "primary template declaration");
332 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
334 InconsistentDeclarations,
"function",
"definition");
338 InconsistentDeclarations);
341 markRedeclarationsAsVisited(OriginalDeclaration);
344void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
345 const FunctionDecl *OriginalDeclaration) {
346 VisitedDeclarations.insert_range(OriginalDeclaration->redecls());
Checks for declarations of functions which differ in parameter names.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
AST_MATCHER(BinaryOperator, isRelationalOperator)
static InconsistentDeclarationsContainer findInconsistentDeclarations(const FunctionDecl *OriginalDeclaration, const FunctionDecl *ParameterSourceDeclaration, SourceManager &SM, bool Strict)
static const FunctionDecl * getParameterSourceDeclaration(const FunctionDecl *OriginalDeclaration)
static void formatDiagnosticsForDeclarations(InconsistentDeclarationParameterNameCheck *Check, const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OriginalDeclaration, const InconsistentDeclarationsContainer &InconsistentDeclarations)
static void formatDifferingParamsDiagnostic(InconsistentDeclarationParameterNameCheck *Check, SourceLocation Location, StringRef OtherDeclarationDescription, const DifferingParamsContainer &DifferingParams)
static bool nameMatch(StringRef L, StringRef R, bool Strict)
static void formatDiagnostics(InconsistentDeclarationParameterNameCheck *Check, const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OriginalDeclaration, const InconsistentDeclarationsContainer &InconsistentDeclarations, StringRef FunctionDescription, StringRef ParameterSourceDescription)
static std::string joinParameterNames(const DifferingParamsContainer &DifferingParams, llvm::function_ref< StringRef(const DifferingParamInfo &)> ChooseParamName)
static bool checkIfFixItHintIsApplicable(const FunctionDecl *ParameterSourceDeclaration, const ParmVarDecl *SourceParam, const FunctionDecl *OriginalDeclaration)
static DifferingParamsContainer findDifferingParamsInDeclaration(const FunctionDecl *ParameterSourceDeclaration, const FunctionDecl *OtherDeclaration, const FunctionDecl *OriginalDeclaration, bool Strict)
llvm::StringMap< ClangTidyValue > OptionMap