11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
18 using namespace clang::ast_matchers;
22 namespace readability {
27 auto It = Node.redecls_begin();
28 auto EndIt = Node.redecls_end();
37 struct DifferingParamInfo {
40 : SourceName(SourceName), OtherName(OtherName),
41 OtherNameRange(OtherNameRange), GenerateFixItHint(GenerateFixItHint) {}
49 using DifferingParamsContainer = llvm::SmallVector<DifferingParamInfo, 10>;
51 struct InconsistentDeclarationInfo {
61 using InconsistentDeclarationsContainer =
62 llvm::SmallVector<InconsistentDeclarationInfo, 2>;
64 bool checkIfFixItHintIsApplicable(
65 const FunctionDecl *ParameterSourceDeclaration,
66 const ParmVarDecl *SourceParam,
const FunctionDecl *OriginalDeclaration) {
74 if (!ParameterSourceDeclaration->isThisDeclarationADefinition())
79 if (!SourceParam->isReferenced())
85 if (OriginalDeclaration->getTemplatedKind() ==
86 FunctionDecl::TK_FunctionTemplateSpecialization)
93 DifferingParamsContainer
94 findDifferingParamsInDeclaration(
const FunctionDecl *ParameterSourceDeclaration,
95 const FunctionDecl *OtherDeclaration,
96 const FunctionDecl *OriginalDeclaration) {
99 auto SourceParamIt = ParameterSourceDeclaration->param_begin();
100 auto OtherParamIt = OtherDeclaration->param_begin();
102 while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
103 OtherParamIt != OtherDeclaration->param_end()) {
104 auto SourceParamName = (*SourceParamIt)->getName();
105 auto OtherParamName = (*OtherParamIt)->getName();
109 if (!SourceParamName.empty() && !OtherParamName.empty() &&
110 SourceParamName != OtherParamName) {
111 SourceRange OtherParamNameRange =
112 DeclarationNameInfo((*OtherParamIt)->getDeclName(),
113 (*OtherParamIt)->getLocation()).getSourceRange();
116 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
118 DifferingParams.emplace_back(SourceParamName, OtherParamName,
119 OtherParamNameRange, GenerateFixItHint);
129 InconsistentDeclarationsContainer
130 findInconsitentDeclarations(
const FunctionDecl *OriginalDeclaration,
131 const FunctionDecl *ParameterSourceDeclaration,
133 InconsistentDeclarationsContainer InconsistentDeclarations;
134 SourceLocation ParameterSourceLocation =
135 ParameterSourceDeclaration->getLocation();
137 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
138 SourceLocation OtherLocation = OtherDeclaration->getLocation();
139 if (OtherLocation != ParameterSourceLocation) {
140 DifferingParamsContainer DifferingParams =
141 findDifferingParamsInDeclaration(ParameterSourceDeclaration,
143 OriginalDeclaration);
144 if (!DifferingParams.empty()) {
145 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
146 std::move(DifferingParams));
153 std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
154 [&
SM](
const InconsistentDeclarationInfo &Info1,
155 const InconsistentDeclarationInfo &Info2) {
156 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
157 Info2.DeclarationLocation);
159 return InconsistentDeclarations;
163 getParameterSourceDeclaration(
const FunctionDecl *OriginalDeclaration) {
164 const FunctionTemplateDecl *PrimaryTemplate =
165 OriginalDeclaration->getPrimaryTemplate();
166 if (PrimaryTemplate !=
nullptr) {
169 return PrimaryTemplate->getTemplatedDecl();
174 if (OriginalDeclaration->isThisDeclarationADefinition())
175 return OriginalDeclaration;
177 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
178 if (OtherDeclaration->isThisDeclarationADefinition()) {
179 return OtherDeclaration;
184 return OriginalDeclaration;
187 std::string joinParameterNames(
188 const DifferingParamsContainer &DifferingParams,
189 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
190 llvm::SmallVector<char, 40> Buffer;
191 llvm::raw_svector_ostream Str(Buffer);
193 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
199 Str <<
"'" << ChooseParamName(ParamInfo).str() <<
"'";
201 return Str.str().str();
204 void formatDifferingParamsDiagnostic(
205 InconsistentDeclarationParameterNameCheck *
Check,
206 SourceLocation
Location, StringRef OtherDeclarationDescription,
207 const DifferingParamsContainer &DifferingParams) {
208 auto ChooseOtherName =
209 [](
const DifferingParamInfo &ParamInfo) {
return ParamInfo.OtherName; };
210 auto ChooseSourceName =
211 [](
const DifferingParamInfo &ParamInfo) {
return ParamInfo.SourceName; };
214 Check->diag(Location,
215 "differing parameters are named here: (%0), in %1: (%2)",
216 DiagnosticIDs::Level::Note)
217 << joinParameterNames(DifferingParams, ChooseOtherName)
218 << OtherDeclarationDescription
219 << joinParameterNames(DifferingParams, ChooseSourceName);
221 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
222 if (ParamInfo.GenerateFixItHint) {
223 ParamDiag << FixItHint::CreateReplacement(
224 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
225 ParamInfo.SourceName);
230 void formatDiagnosticsForDeclarations(
231 InconsistentDeclarationParameterNameCheck *Check,
232 const FunctionDecl *ParameterSourceDeclaration,
233 const FunctionDecl *OriginalDeclaration,
234 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
236 OriginalDeclaration->getLocation(),
237 "function %q0 has %1 other declaration%s1 with different parameter names")
238 << OriginalDeclaration
239 << static_cast<int>(InconsistentDeclarations.size());
241 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
242 InconsistentDeclarations) {
243 Check->diag(InconsistentDeclaration.DeclarationLocation,
244 "the %ordinal0 inconsistent declaration seen here",
245 DiagnosticIDs::Level::Note)
248 formatDifferingParamsDiagnostic(
249 Check, InconsistentDeclaration.DeclarationLocation,
250 "the other declaration", InconsistentDeclaration.DifferingParams);
256 void formatDiagnostics(
257 InconsistentDeclarationParameterNameCheck *Check,
258 const FunctionDecl *ParameterSourceDeclaration,
259 const FunctionDecl *OriginalDeclaration,
260 const InconsistentDeclarationsContainer &InconsistentDeclarations,
261 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
262 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
263 InconsistentDeclarations) {
264 Check->diag(InconsistentDeclaration.DeclarationLocation,
265 "%0 %q1 has a %2 with different parameter names")
266 << FunctionDescription << OriginalDeclaration
267 << ParameterSourceDescription;
269 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
270 DiagnosticIDs::Level::Note)
271 << ParameterSourceDescription;
273 formatDifferingParamsDiagnostic(
274 Check, InconsistentDeclaration.DeclarationLocation,
275 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
281 void InconsistentDeclarationParameterNameCheck::registerMatchers(
283 Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
284 .bind(
"functionDecl"),
288 void InconsistentDeclarationParameterNameCheck::check(
289 const MatchFinder::MatchResult &
Result) {
290 const auto *OriginalDeclaration =
291 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
293 if (VisitedDeclarations.count(OriginalDeclaration) > 0)
296 const FunctionDecl *ParameterSourceDeclaration =
297 getParameterSourceDeclaration(OriginalDeclaration);
299 InconsistentDeclarationsContainer InconsistentDeclarations =
300 findInconsitentDeclarations(OriginalDeclaration,
301 ParameterSourceDeclaration,
302 *Result.SourceManager);
303 if (InconsistentDeclarations.empty()) {
305 markRedeclarationsAsVisited(OriginalDeclaration);
309 if (OriginalDeclaration->getTemplatedKind() ==
310 FunctionDecl::TK_FunctionTemplateSpecialization) {
311 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
312 InconsistentDeclarations,
313 "function template specialization",
314 "primary template declaration");
315 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
316 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
317 InconsistentDeclarations,
"function",
"definition");
319 formatDiagnosticsForDeclarations(
this, ParameterSourceDeclaration,
321 InconsistentDeclarations);
324 markRedeclarationsAsVisited(OriginalDeclaration);
327 void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
328 const FunctionDecl *OriginalDeclaration) {
329 for (
const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
330 VisitedDeclarations.insert(Redecl);
AST_MATCHER(Type, isStrictlyInteger)
std::unique_ptr< ast_matchers::MatchFinder > Finder
SourceLocation DeclarationLocation
SourceRange OtherNameRange
DifferingParamsContainer DifferingParams