11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 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())
117 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
119 DifferingParams.emplace_back(SourceParamName, OtherParamName,
120 OtherParamNameRange, GenerateFixItHint);
130 InconsistentDeclarationsContainer
131 findInconsitentDeclarations(
const FunctionDecl *OriginalDeclaration,
132 const FunctionDecl *ParameterSourceDeclaration,
134 InconsistentDeclarationsContainer InconsistentDeclarations;
135 SourceLocation ParameterSourceLocation =
136 ParameterSourceDeclaration->getLocation();
138 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
139 SourceLocation OtherLocation = OtherDeclaration->getLocation();
140 if (OtherLocation != ParameterSourceLocation) {
142 findDifferingParamsInDeclaration(ParameterSourceDeclaration,
144 OriginalDeclaration);
145 if (!DifferingParams.empty()) {
146 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
147 std::move(DifferingParams));
154 std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
155 [&SM](
const InconsistentDeclarationInfo &Info1,
156 const InconsistentDeclarationInfo &Info2) {
157 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
158 Info2.DeclarationLocation);
160 return InconsistentDeclarations;
164 getParameterSourceDeclaration(
const FunctionDecl *OriginalDeclaration) {
165 const FunctionTemplateDecl *PrimaryTemplate =
166 OriginalDeclaration->getPrimaryTemplate();
167 if (PrimaryTemplate !=
nullptr) {
170 return PrimaryTemplate->getTemplatedDecl();
175 if (OriginalDeclaration->isThisDeclarationADefinition())
176 return OriginalDeclaration;
178 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
179 if (OtherDeclaration->isThisDeclarationADefinition()) {
180 return OtherDeclaration;
185 return OriginalDeclaration;
188 std::string joinParameterNames(
190 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
191 llvm::SmallVector<char, 40> Buffer;
192 llvm::raw_svector_ostream Str(Buffer);
194 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
200 Str <<
"'" << ChooseParamName(ParamInfo).str() <<
"'";
202 return Str.str().str();
205 void formatDifferingParamsDiagnostic(
206 InconsistentDeclarationParameterNameCheck *Check, SourceLocation
Location,
207 StringRef OtherDeclarationDescription,
208 const DifferingParamsContainer &DifferingParams) {
209 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
210 return ParamInfo.OtherName;
212 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
213 return ParamInfo.SourceName;
217 Check->diag(Location,
218 "differing parameters are named here: (%0), in %1: (%2)",
219 DiagnosticIDs::Level::Note)
220 << joinParameterNames(DifferingParams, ChooseOtherName)
221 << OtherDeclarationDescription
222 << joinParameterNames(DifferingParams, ChooseSourceName);
224 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
225 if (ParamInfo.GenerateFixItHint) {
226 ParamDiag << FixItHint::CreateReplacement(
227 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
228 ParamInfo.SourceName);
233 void formatDiagnosticsForDeclarations(
234 InconsistentDeclarationParameterNameCheck *Check,
235 const FunctionDecl *ParameterSourceDeclaration,
236 const FunctionDecl *OriginalDeclaration,
237 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
239 OriginalDeclaration->getLocation(),
240 "function %q0 has %1 other declaration%s1 with different parameter names")
241 << OriginalDeclaration
242 << static_cast<int>(InconsistentDeclarations.size());
244 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
245 InconsistentDeclarations) {
246 Check->diag(InconsistentDeclaration.DeclarationLocation,
247 "the %ordinal0 inconsistent declaration seen here",
248 DiagnosticIDs::Level::Note)
251 formatDifferingParamsDiagnostic(
252 Check, InconsistentDeclaration.DeclarationLocation,
253 "the other declaration", InconsistentDeclaration.DifferingParams);
259 void formatDiagnostics(
260 InconsistentDeclarationParameterNameCheck *Check,
261 const FunctionDecl *ParameterSourceDeclaration,
262 const FunctionDecl *OriginalDeclaration,
263 const InconsistentDeclarationsContainer &InconsistentDeclarations,
264 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
265 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
266 InconsistentDeclarations) {
267 Check->diag(InconsistentDeclaration.DeclarationLocation,
268 "%0 %q1 has a %2 with different parameter names")
269 << FunctionDescription << OriginalDeclaration
270 << ParameterSourceDescription;
272 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
273 DiagnosticIDs::Level::Note)
274 << ParameterSourceDescription;
276 formatDifferingParamsDiagnostic(
277 Check, InconsistentDeclaration.DeclarationLocation,
278 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
284 void InconsistentDeclarationParameterNameCheck::registerMatchers(
285 MatchFinder *Finder) {
286 Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
287 .bind(
"functionDecl"),
291 void InconsistentDeclarationParameterNameCheck::check(
292 const MatchFinder::MatchResult &Result) {
293 const auto *OriginalDeclaration =
294 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
296 if (VisitedDeclarations.count(OriginalDeclaration) > 0)
299 const FunctionDecl *ParameterSourceDeclaration =
300 getParameterSourceDeclaration(OriginalDeclaration);
302 InconsistentDeclarationsContainer InconsistentDeclarations =
303 findInconsitentDeclarations(OriginalDeclaration,
304 ParameterSourceDeclaration,
305 *Result.SourceManager);
306 if (InconsistentDeclarations.empty()) {
308 markRedeclarationsAsVisited(OriginalDeclaration);
312 if (OriginalDeclaration->getTemplatedKind() ==
313 FunctionDecl::TK_FunctionTemplateSpecialization) {
314 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
315 InconsistentDeclarations,
316 "function template specialization",
317 "primary template declaration");
318 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
319 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
320 InconsistentDeclarations,
"function",
"definition");
322 formatDiagnosticsForDeclarations(
this, ParameterSourceDeclaration,
324 InconsistentDeclarations);
327 markRedeclarationsAsVisited(OriginalDeclaration);
330 void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
331 const FunctionDecl *OriginalDeclaration) {
332 for (
const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
333 VisitedDeclarations.insert(Redecl);
SourceLocation DeclarationLocation
SourceRange OtherNameRange
DifferingParamsContainer DifferingParams
AST_MATCHER(VarDecl, isAsm)