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;
194 return OriginalDeclaration;
198 const DifferingParamsContainer &DifferingParams,
199 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
200 llvm::SmallString<40> Str;
202 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
207 Str.append({
"'", ChooseParamName(ParamInfo),
"'"});
209 return std::string(Str);
214 StringRef OtherDeclarationDescription,
215 const DifferingParamsContainer &DifferingParams) {
216 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
217 return ParamInfo.OtherName;
219 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
220 return ParamInfo.SourceName;
225 "differing parameters are named here: (%0), in %1: (%2)",
226 DiagnosticIDs::Level::Note)
228 << OtherDeclarationDescription
231 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
232 if (ParamInfo.GenerateFixItHint) {
233 ParamDiag << FixItHint::CreateReplacement(
234 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
235 ParamInfo.SourceName);
242 const FunctionDecl *ParameterSourceDeclaration,
243 const FunctionDecl *OriginalDeclaration,
244 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
246 OriginalDeclaration->getLocation(),
247 "function %q0 has %1 other declaration%s1 with different parameter names")
248 << OriginalDeclaration
249 <<
static_cast<int>(InconsistentDeclarations.size());
251 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
252 InconsistentDeclarations) {
253 Check->diag(InconsistentDeclaration.DeclarationLocation,
254 "the %ordinal0 inconsistent declaration seen here",
255 DiagnosticIDs::Level::Note)
259 Check, InconsistentDeclaration.DeclarationLocation,
260 "the other declaration", InconsistentDeclaration.DifferingParams);
268 const FunctionDecl *ParameterSourceDeclaration,
269 const FunctionDecl *OriginalDeclaration,
270 const InconsistentDeclarationsContainer &InconsistentDeclarations,
271 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
272 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
273 InconsistentDeclarations) {
274 Check->diag(InconsistentDeclaration.DeclarationLocation,
275 "%0 %q1 has a %2 with different parameter names")
276 << FunctionDescription << OriginalDeclaration
277 << ParameterSourceDescription;
279 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
280 DiagnosticIDs::Level::Note)
281 << ParameterSourceDescription;
284 Check, InconsistentDeclaration.DeclarationLocation,
285 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
291 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
292 Options.store(Opts,
"Strict", Strict);
296 MatchFinder *Finder) {
297 Finder->addMatcher(functionDecl(hasOtherDeclarations()).bind(
"functionDecl"),
302 const MatchFinder::MatchResult &Result) {
303 const auto *OriginalDeclaration =
304 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
306 if (VisitedDeclarations.contains(OriginalDeclaration))
309 const FunctionDecl *ParameterSourceDeclaration =
312 const InconsistentDeclarationsContainer InconsistentDeclarations =
314 ParameterSourceDeclaration,
315 *Result.SourceManager, Strict);
316 if (InconsistentDeclarations.empty()) {
318 markRedeclarationsAsVisited(OriginalDeclaration);
322 const SourceLocation StartLoc = OriginalDeclaration->getBeginLoc();
323 if (StartLoc.isMacroID() && IgnoreMacros) {
324 markRedeclarationsAsVisited(OriginalDeclaration);
328 if (OriginalDeclaration->getTemplatedKind() ==
329 FunctionDecl::TK_FunctionTemplateSpecialization) {
331 InconsistentDeclarations,
332 "function template specialization",
333 "primary template declaration");
334 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
336 InconsistentDeclarations,
"function",
"definition");
340 InconsistentDeclarations);
343 markRedeclarationsAsVisited(OriginalDeclaration);
346void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
347 const FunctionDecl *OriginalDeclaration) {
348 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