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 auto SourceParamName = (*SourceParamIt)->getName();
111 auto OtherParamName = (*OtherParamIt)->getName();
115 if (!
nameMatch(SourceParamName, OtherParamName, Strict)) {
116 SourceRange OtherParamNameRange =
117 DeclarationNameInfo((*OtherParamIt)->getDeclName(),
118 (*OtherParamIt)->getLocation())
122 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
124 DifferingParams.emplace_back(SourceParamName, OtherParamName,
125 OtherParamNameRange, GenerateFixItHint);
132 return DifferingParams;
135static InconsistentDeclarationsContainer
137 const FunctionDecl *ParameterSourceDeclaration,
138 SourceManager &SM,
bool Strict) {
139 InconsistentDeclarationsContainer InconsistentDeclarations;
140 SourceLocation ParameterSourceLocation =
141 ParameterSourceDeclaration->getLocation();
143 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
144 SourceLocation OtherLocation = OtherDeclaration->getLocation();
145 if (OtherLocation != ParameterSourceLocation) {
146 DifferingParamsContainer DifferingParams =
149 OriginalDeclaration, Strict);
150 if (!DifferingParams.empty()) {
151 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
152 std::move(DifferingParams));
159 llvm::sort(InconsistentDeclarations,
160 [&SM](
const InconsistentDeclarationInfo &Info1,
161 const InconsistentDeclarationInfo &Info2) {
162 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
163 Info2.DeclarationLocation);
165 return InconsistentDeclarations;
168static const FunctionDecl *
170 const FunctionTemplateDecl *PrimaryTemplate =
171 OriginalDeclaration->getPrimaryTemplate();
172 if (PrimaryTemplate !=
nullptr) {
175 return PrimaryTemplate->getTemplatedDecl();
180 if (OriginalDeclaration->isThisDeclarationADefinition())
181 return OriginalDeclaration;
183 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
184 if (OtherDeclaration->isThisDeclarationADefinition()) {
185 return OtherDeclaration;
190 return OriginalDeclaration;
194 const DifferingParamsContainer &DifferingParams,
195 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
196 llvm::SmallString<40> Str;
198 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
203 Str.append({
"'", ChooseParamName(ParamInfo),
"'"});
205 return std::string(Str);
210 StringRef OtherDeclarationDescription,
211 const DifferingParamsContainer &DifferingParams) {
212 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
213 return ParamInfo.OtherName;
215 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
216 return ParamInfo.SourceName;
221 "differing parameters are named here: (%0), in %1: (%2)",
222 DiagnosticIDs::Level::Note)
224 << OtherDeclarationDescription
227 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
228 if (ParamInfo.GenerateFixItHint) {
229 ParamDiag << FixItHint::CreateReplacement(
230 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
231 ParamInfo.SourceName);
238 const FunctionDecl *ParameterSourceDeclaration,
239 const FunctionDecl *OriginalDeclaration,
240 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
242 OriginalDeclaration->getLocation(),
243 "function %q0 has %1 other declaration%s1 with different parameter names")
244 << OriginalDeclaration
245 <<
static_cast<int>(InconsistentDeclarations.size());
247 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
248 InconsistentDeclarations) {
249 Check->diag(InconsistentDeclaration.DeclarationLocation,
250 "the %ordinal0 inconsistent declaration seen here",
251 DiagnosticIDs::Level::Note)
255 Check, InconsistentDeclaration.DeclarationLocation,
256 "the other declaration", InconsistentDeclaration.DifferingParams);
264 const FunctionDecl *ParameterSourceDeclaration,
265 const FunctionDecl *OriginalDeclaration,
266 const InconsistentDeclarationsContainer &InconsistentDeclarations,
267 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
268 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
269 InconsistentDeclarations) {
270 Check->diag(InconsistentDeclaration.DeclarationLocation,
271 "%0 %q1 has a %2 with different parameter names")
272 << FunctionDescription << OriginalDeclaration
273 << ParameterSourceDescription;
275 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
276 DiagnosticIDs::Level::Note)
277 << ParameterSourceDescription;
280 Check, InconsistentDeclaration.DeclarationLocation,
281 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
287 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
288 Options.store(Opts,
"Strict", Strict);
292 MatchFinder *Finder) {
293 Finder->addMatcher(functionDecl(hasOtherDeclarations()).bind(
"functionDecl"),
298 const MatchFinder::MatchResult &Result) {
299 const auto *OriginalDeclaration =
300 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
302 if (VisitedDeclarations.contains(OriginalDeclaration))
305 const FunctionDecl *ParameterSourceDeclaration =
308 InconsistentDeclarationsContainer InconsistentDeclarations =
310 ParameterSourceDeclaration,
311 *Result.SourceManager, Strict);
312 if (InconsistentDeclarations.empty()) {
314 markRedeclarationsAsVisited(OriginalDeclaration);
318 SourceLocation StartLoc = OriginalDeclaration->getBeginLoc();
319 if (StartLoc.isMacroID() && IgnoreMacros) {
320 markRedeclarationsAsVisited(OriginalDeclaration);
324 if (OriginalDeclaration->getTemplatedKind() ==
325 FunctionDecl::TK_FunctionTemplateSpecialization) {
327 InconsistentDeclarations,
328 "function template specialization",
329 "primary template declaration");
330 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
332 InconsistentDeclarations,
"function",
"definition");
336 InconsistentDeclarations);
339 markRedeclarationsAsVisited(OriginalDeclaration);
342void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
343 const FunctionDecl *OriginalDeclaration) {
344 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