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 bool nameMatch(StringRef L, StringRef R,
bool Strict) {
95 return L.empty() || R.empty() || L == R;
98 return L.startswith_lower(R) || R.startswith_lower(L) ||
99 L.endswith_lower(R) || R.endswith_lower(L);
102 DifferingParamsContainer
103 findDifferingParamsInDeclaration(
const FunctionDecl *ParameterSourceDeclaration,
104 const FunctionDecl *OtherDeclaration,
105 const FunctionDecl *OriginalDeclaration,
109 auto SourceParamIt = ParameterSourceDeclaration->param_begin();
110 auto OtherParamIt = OtherDeclaration->param_begin();
112 while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
113 OtherParamIt != OtherDeclaration->param_end()) {
114 auto SourceParamName = (*SourceParamIt)->getName();
115 auto OtherParamName = (*OtherParamIt)->getName();
119 if (!nameMatch(SourceParamName, OtherParamName, Strict)) {
120 SourceRange OtherParamNameRange =
121 DeclarationNameInfo((*OtherParamIt)->getDeclName(),
122 (*OtherParamIt)->getLocation())
126 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
128 DifferingParams.emplace_back(SourceParamName, OtherParamName,
129 OtherParamNameRange, GenerateFixItHint);
139 InconsistentDeclarationsContainer
140 findInconsistentDeclarations(
const FunctionDecl *OriginalDeclaration,
141 const FunctionDecl *ParameterSourceDeclaration,
142 SourceManager &SM,
bool Strict) {
143 InconsistentDeclarationsContainer InconsistentDeclarations;
144 SourceLocation ParameterSourceLocation =
145 ParameterSourceDeclaration->getLocation();
147 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
148 SourceLocation OtherLocation = OtherDeclaration->getLocation();
149 if (OtherLocation != ParameterSourceLocation) {
151 findDifferingParamsInDeclaration(ParameterSourceDeclaration,
153 OriginalDeclaration, Strict);
154 if (!DifferingParams.empty()) {
155 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
156 std::move(DifferingParams));
163 std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
164 [&SM](
const InconsistentDeclarationInfo &Info1,
165 const InconsistentDeclarationInfo &Info2) {
166 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
167 Info2.DeclarationLocation);
169 return InconsistentDeclarations;
173 getParameterSourceDeclaration(
const FunctionDecl *OriginalDeclaration) {
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;
197 std::string joinParameterNames(
199 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
200 llvm::SmallVector<char, 40> Buffer;
201 llvm::raw_svector_ostream Str(Buffer);
203 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
209 Str <<
"'" << ChooseParamName(ParamInfo).str() <<
"'";
211 return Str.str().str();
214 void formatDifferingParamsDiagnostic(
215 InconsistentDeclarationParameterNameCheck *Check, SourceLocation
Location,
216 StringRef OtherDeclarationDescription,
217 const DifferingParamsContainer &DifferingParams) {
218 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
219 return ParamInfo.OtherName;
221 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
222 return ParamInfo.SourceName;
226 Check->diag(Location,
227 "differing parameters are named here: (%0), in %1: (%2)",
228 DiagnosticIDs::Level::Note)
229 << joinParameterNames(DifferingParams, ChooseOtherName)
230 << OtherDeclarationDescription
231 << joinParameterNames(DifferingParams, ChooseSourceName);
233 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
234 if (ParamInfo.GenerateFixItHint) {
235 ParamDiag << FixItHint::CreateReplacement(
236 CharSourceRange::getTokenRange(ParamInfo.OtherNameRange),
237 ParamInfo.SourceName);
242 void formatDiagnosticsForDeclarations(
243 InconsistentDeclarationParameterNameCheck *Check,
244 const FunctionDecl *ParameterSourceDeclaration,
245 const FunctionDecl *OriginalDeclaration,
246 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
248 OriginalDeclaration->getLocation(),
249 "function %q0 has %1 other declaration%s1 with different parameter names")
250 << OriginalDeclaration
251 << static_cast<int>(InconsistentDeclarations.size());
253 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
254 InconsistentDeclarations) {
255 Check->diag(InconsistentDeclaration.DeclarationLocation,
256 "the %ordinal0 inconsistent declaration seen here",
257 DiagnosticIDs::Level::Note)
260 formatDifferingParamsDiagnostic(
261 Check, InconsistentDeclaration.DeclarationLocation,
262 "the other declaration", InconsistentDeclaration.DifferingParams);
268 void formatDiagnostics(
269 InconsistentDeclarationParameterNameCheck *Check,
270 const FunctionDecl *ParameterSourceDeclaration,
271 const FunctionDecl *OriginalDeclaration,
272 const InconsistentDeclarationsContainer &InconsistentDeclarations,
273 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
274 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
275 InconsistentDeclarations) {
276 Check->diag(InconsistentDeclaration.DeclarationLocation,
277 "%0 %q1 has a %2 with different parameter names")
278 << FunctionDescription << OriginalDeclaration
279 << ParameterSourceDescription;
281 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
282 DiagnosticIDs::Level::Note)
283 << ParameterSourceDescription;
285 formatDifferingParamsDiagnostic(
286 Check, InconsistentDeclaration.DeclarationLocation,
287 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
293 void InconsistentDeclarationParameterNameCheck::storeOptions(
295 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
296 Options.store(Opts,
"Strict", Strict);
299 void InconsistentDeclarationParameterNameCheck::registerMatchers(
300 MatchFinder *Finder) {
301 Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
302 .bind(
"functionDecl"),
306 void InconsistentDeclarationParameterNameCheck::check(
307 const MatchFinder::MatchResult &Result) {
308 const auto *OriginalDeclaration =
309 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
311 if (VisitedDeclarations.count(OriginalDeclaration) > 0)
314 const FunctionDecl *ParameterSourceDeclaration =
315 getParameterSourceDeclaration(OriginalDeclaration);
317 InconsistentDeclarationsContainer InconsistentDeclarations =
318 findInconsistentDeclarations(OriginalDeclaration,
319 ParameterSourceDeclaration,
320 *Result.SourceManager, Strict);
321 if (InconsistentDeclarations.empty()) {
323 markRedeclarationsAsVisited(OriginalDeclaration);
327 SourceLocation StartLoc = OriginalDeclaration->getLocStart();
328 if (StartLoc.isMacroID() && IgnoreMacros) {
329 markRedeclarationsAsVisited(OriginalDeclaration);
333 if (OriginalDeclaration->getTemplatedKind() ==
334 FunctionDecl::TK_FunctionTemplateSpecialization) {
335 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
336 InconsistentDeclarations,
337 "function template specialization",
338 "primary template declaration");
339 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
340 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
341 InconsistentDeclarations,
"function",
"definition");
343 formatDiagnosticsForDeclarations(
this, ParameterSourceDeclaration,
345 InconsistentDeclarations);
348 markRedeclarationsAsVisited(OriginalDeclaration);
351 void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
352 const FunctionDecl *OriginalDeclaration) {
353 for (
const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
354 VisitedDeclarations.insert(Redecl);
AST_MATCHER(BinaryOperator, isAssignmentOperator)
SourceLocation DeclarationLocation
SourceRange OtherNameRange
DifferingParamsContainer DifferingParams
std::map< std::string, std::string > OptionMap
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//