10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 21 namespace readability {
26 auto It = Node.redecls_begin();
27 auto EndIt = Node.redecls_end();
36 struct DifferingParamInfo {
39 : SourceName(SourceName), OtherName(OtherName),
40 OtherNameRange(OtherNameRange), GenerateFixItHint(GenerateFixItHint) {}
48 using DifferingParamsContainer = llvm::SmallVector<DifferingParamInfo, 10>;
50 struct InconsistentDeclarationInfo {
60 using InconsistentDeclarationsContainer =
61 llvm::SmallVector<InconsistentDeclarationInfo, 2>;
63 bool checkIfFixItHintIsApplicable(
64 const FunctionDecl *ParameterSourceDeclaration,
65 const ParmVarDecl *SourceParam,
const FunctionDecl *OriginalDeclaration) {
73 if (!ParameterSourceDeclaration->isThisDeclarationADefinition())
78 if (!SourceParam->isReferenced())
84 if (OriginalDeclaration->getTemplatedKind() ==
85 FunctionDecl::TK_FunctionTemplateSpecialization)
92 bool nameMatch(StringRef L, StringRef R,
bool Strict) {
94 return L.empty() || R.empty() || L == R;
97 return L.startswith_lower(R) || R.startswith_lower(L) ||
98 L.endswith_lower(R) || R.endswith_lower(L);
101 DifferingParamsContainer
102 findDifferingParamsInDeclaration(
const FunctionDecl *ParameterSourceDeclaration,
103 const FunctionDecl *OtherDeclaration,
104 const FunctionDecl *OriginalDeclaration,
108 auto SourceParamIt = ParameterSourceDeclaration->param_begin();
109 auto OtherParamIt = OtherDeclaration->param_begin();
111 while (SourceParamIt != ParameterSourceDeclaration->param_end() &&
112 OtherParamIt != OtherDeclaration->param_end()) {
113 auto SourceParamName = (*SourceParamIt)->getName();
114 auto OtherParamName = (*OtherParamIt)->getName();
118 if (!nameMatch(SourceParamName, OtherParamName, Strict)) {
119 SourceRange OtherParamNameRange =
120 DeclarationNameInfo((*OtherParamIt)->getDeclName(),
121 (*OtherParamIt)->getLocation())
125 ParameterSourceDeclaration, *SourceParamIt, OriginalDeclaration);
127 DifferingParams.emplace_back(SourceParamName, OtherParamName,
128 OtherParamNameRange, GenerateFixItHint);
138 InconsistentDeclarationsContainer
139 findInconsistentDeclarations(
const FunctionDecl *OriginalDeclaration,
140 const FunctionDecl *ParameterSourceDeclaration,
141 SourceManager &SM,
bool Strict) {
142 InconsistentDeclarationsContainer InconsistentDeclarations;
143 SourceLocation ParameterSourceLocation =
144 ParameterSourceDeclaration->getLocation();
146 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
147 SourceLocation OtherLocation = OtherDeclaration->getLocation();
148 if (OtherLocation != ParameterSourceLocation) {
150 findDifferingParamsInDeclaration(ParameterSourceDeclaration,
152 OriginalDeclaration, Strict);
153 if (!DifferingParams.empty()) {
154 InconsistentDeclarations.emplace_back(OtherDeclaration->getLocation(),
155 std::move(DifferingParams));
162 std::sort(InconsistentDeclarations.begin(), InconsistentDeclarations.end(),
163 [&SM](
const InconsistentDeclarationInfo &Info1,
164 const InconsistentDeclarationInfo &Info2) {
165 return SM.isBeforeInTranslationUnit(Info1.DeclarationLocation,
166 Info2.DeclarationLocation);
168 return InconsistentDeclarations;
172 getParameterSourceDeclaration(
const FunctionDecl *OriginalDeclaration) {
173 const FunctionTemplateDecl *PrimaryTemplate =
174 OriginalDeclaration->getPrimaryTemplate();
175 if (PrimaryTemplate !=
nullptr) {
178 return PrimaryTemplate->getTemplatedDecl();
183 if (OriginalDeclaration->isThisDeclarationADefinition())
184 return OriginalDeclaration;
186 for (
const FunctionDecl *OtherDeclaration : OriginalDeclaration->redecls()) {
187 if (OtherDeclaration->isThisDeclarationADefinition()) {
188 return OtherDeclaration;
193 return OriginalDeclaration;
196 std::string joinParameterNames(
198 llvm::function_ref<StringRef(
const DifferingParamInfo &)> ChooseParamName) {
199 llvm::SmallVector<char, 40> Buffer;
200 llvm::raw_svector_ostream Str(Buffer);
202 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
208 Str <<
"'" << ChooseParamName(ParamInfo).str() <<
"'";
210 return Str.str().str();
213 void formatDifferingParamsDiagnostic(
214 InconsistentDeclarationParameterNameCheck *Check, SourceLocation
Location,
215 StringRef OtherDeclarationDescription,
216 const DifferingParamsContainer &DifferingParams) {
217 auto ChooseOtherName = [](
const DifferingParamInfo &ParamInfo) {
218 return ParamInfo.OtherName;
220 auto ChooseSourceName = [](
const DifferingParamInfo &ParamInfo) {
221 return ParamInfo.SourceName;
225 Check->diag(Location,
226 "differing parameters are named here: (%0), in %1: (%2)",
227 DiagnosticIDs::Level::Note)
228 << joinParameterNames(DifferingParams, ChooseOtherName)
229 << OtherDeclarationDescription
230 << joinParameterNames(DifferingParams, ChooseSourceName);
232 for (
const DifferingParamInfo &ParamInfo : DifferingParams) {
233 if (ParamInfo.GenerateFixItHint) {
234 ParamDiag << FixItHint::CreateReplacement(
236 ParamInfo.SourceName);
241 void formatDiagnosticsForDeclarations(
242 InconsistentDeclarationParameterNameCheck *Check,
243 const FunctionDecl *ParameterSourceDeclaration,
244 const FunctionDecl *OriginalDeclaration,
245 const InconsistentDeclarationsContainer &InconsistentDeclarations) {
247 OriginalDeclaration->getLocation(),
248 "function %q0 has %1 other declaration%s1 with different parameter names")
249 << OriginalDeclaration
250 << static_cast<int>(InconsistentDeclarations.size());
252 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
253 InconsistentDeclarations) {
254 Check->diag(InconsistentDeclaration.DeclarationLocation,
255 "the %ordinal0 inconsistent declaration seen here",
256 DiagnosticIDs::Level::Note)
259 formatDifferingParamsDiagnostic(
260 Check, InconsistentDeclaration.DeclarationLocation,
261 "the other declaration", InconsistentDeclaration.DifferingParams);
267 void formatDiagnostics(
268 InconsistentDeclarationParameterNameCheck *Check,
269 const FunctionDecl *ParameterSourceDeclaration,
270 const FunctionDecl *OriginalDeclaration,
271 const InconsistentDeclarationsContainer &InconsistentDeclarations,
272 StringRef FunctionDescription, StringRef ParameterSourceDescription) {
273 for (
const InconsistentDeclarationInfo &InconsistentDeclaration :
274 InconsistentDeclarations) {
275 Check->diag(InconsistentDeclaration.DeclarationLocation,
276 "%0 %q1 has a %2 with different parameter names")
277 << FunctionDescription << OriginalDeclaration
278 << ParameterSourceDescription;
280 Check->diag(ParameterSourceDeclaration->getLocation(),
"the %0 seen here",
281 DiagnosticIDs::Level::Note)
282 << ParameterSourceDescription;
284 formatDifferingParamsDiagnostic(
285 Check, InconsistentDeclaration.DeclarationLocation,
286 ParameterSourceDescription, InconsistentDeclaration.DifferingParams);
292 void InconsistentDeclarationParameterNameCheck::storeOptions(
294 Options.store(Opts,
"IgnoreMacros", IgnoreMacros);
295 Options.store(Opts,
"Strict", Strict);
298 void InconsistentDeclarationParameterNameCheck::registerMatchers(
299 MatchFinder *Finder) {
300 Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations())
301 .bind(
"functionDecl"),
305 void InconsistentDeclarationParameterNameCheck::check(
306 const MatchFinder::MatchResult &Result) {
307 const auto *OriginalDeclaration =
308 Result.Nodes.getNodeAs<FunctionDecl>(
"functionDecl");
310 if (VisitedDeclarations.count(OriginalDeclaration) > 0)
313 const FunctionDecl *ParameterSourceDeclaration =
314 getParameterSourceDeclaration(OriginalDeclaration);
316 InconsistentDeclarationsContainer InconsistentDeclarations =
317 findInconsistentDeclarations(OriginalDeclaration,
318 ParameterSourceDeclaration,
319 *Result.SourceManager, Strict);
320 if (InconsistentDeclarations.empty()) {
322 markRedeclarationsAsVisited(OriginalDeclaration);
326 SourceLocation StartLoc = OriginalDeclaration->getBeginLoc();
327 if (StartLoc.isMacroID() && IgnoreMacros) {
328 markRedeclarationsAsVisited(OriginalDeclaration);
332 if (OriginalDeclaration->getTemplatedKind() ==
333 FunctionDecl::TK_FunctionTemplateSpecialization) {
334 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
335 InconsistentDeclarations,
336 "function template specialization",
337 "primary template declaration");
338 }
else if (ParameterSourceDeclaration->isThisDeclarationADefinition()) {
339 formatDiagnostics(
this, ParameterSourceDeclaration, OriginalDeclaration,
340 InconsistentDeclarations,
"function",
"definition");
342 formatDiagnosticsForDeclarations(
this, ParameterSourceDeclaration,
344 InconsistentDeclarations);
347 markRedeclarationsAsVisited(OriginalDeclaration);
350 void InconsistentDeclarationParameterNameCheck::markRedeclarationsAsVisited(
351 const FunctionDecl *OriginalDeclaration) {
352 for (
const FunctionDecl *Redecl : OriginalDeclaration->redecls()) {
353 VisitedDeclarations.insert(Redecl);
SourceLocation DeclarationLocation
SourceRange OtherNameRange
AST_MATCHER(Expr, isMacroID)
DifferingParamsContainer DifferingParams
std::map< std::string, std::string > OptionMap
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//