clang-tools 19.0.0git
NamedParameterCheck.cpp
Go to the documentation of this file.
1//===--- NamedParameterCheck.cpp - clang-tidy -------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/ASTMatchers/ASTMatchers.h"
13
14using namespace clang::ast_matchers;
15
17
18void NamedParameterCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
19 Finder->addMatcher(functionDecl().bind("decl"), this);
20}
21
22void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
23 const SourceManager &SM = *Result.SourceManager;
24 const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("decl");
25 SmallVector<std::pair<const FunctionDecl *, unsigned>, 4> UnnamedParams;
26
27 // Ignore declarations without a definition if we're not dealing with an
28 // overriden method.
29 const FunctionDecl *Definition = nullptr;
30 if ((!Function->isDefined(Definition) || Function->isDefaulted() ||
31 Definition->isDefaulted() || Function->isDeleted()) &&
32 (!isa<CXXMethodDecl>(Function) ||
33 cast<CXXMethodDecl>(Function)->size_overridden_methods() == 0))
34 return;
35
36 // TODO: Handle overloads.
37 // TODO: We could check that all redeclarations use the same name for
38 // arguments in the same position.
39 for (unsigned I = 0, E = Function->getNumParams(); I != E; ++I) {
40 const ParmVarDecl *Parm = Function->getParamDecl(I);
41 if (Parm->isImplicit())
42 continue;
43 // Look for unnamed parameters.
44 if (!Parm->getName().empty())
45 continue;
46
47 // Don't warn on the dummy argument on post-inc and post-dec operators.
48 if ((Function->getOverloadedOperator() == OO_PlusPlus ||
49 Function->getOverloadedOperator() == OO_MinusMinus) &&
50 Parm->getType()->isSpecificBuiltinType(BuiltinType::Int))
51 continue;
52
53 // Sanity check the source locations.
54 if (!Parm->getLocation().isValid() || Parm->getLocation().isMacroID() ||
55 !SM.isWrittenInSameFile(Parm->getBeginLoc(), Parm->getLocation()))
56 continue;
57
58 // Skip gmock testing::Unused parameters.
59 if (const auto *Typedef = Parm->getType()->getAs<clang::TypedefType>())
60 if (Typedef->getDecl()->getQualifiedNameAsString() == "testing::Unused")
61 continue;
62
63 // Skip std::nullptr_t.
64 if (Parm->getType().getCanonicalType()->isNullPtrType())
65 continue;
66
67 // Look for comments. We explicitly want to allow idioms like
68 // void foo(int /*unused*/)
69 const char *Begin = SM.getCharacterData(Parm->getBeginLoc());
70 const char *End = SM.getCharacterData(Parm->getLocation());
71 StringRef Data(Begin, End - Begin);
72 if (Data.contains("/*"))
73 continue;
74
75 UnnamedParams.push_back(std::make_pair(Function, I));
76 }
77
78 // Emit only one warning per function but fixits for all unnamed parameters.
79 if (!UnnamedParams.empty()) {
80 const ParmVarDecl *FirstParm =
81 UnnamedParams.front().first->getParamDecl(UnnamedParams.front().second);
82 auto D = diag(FirstParm->getLocation(),
83 "all parameters should be named in a function");
84
85 for (auto P : UnnamedParams) {
86 // Fallback to an unused marker.
87 StringRef NewName = "unused";
88
89 // If the method is overridden, try to copy the name from the base method
90 // into the overrider.
91 const auto *M = dyn_cast<CXXMethodDecl>(P.first);
92 if (M && M->size_overridden_methods() > 0) {
93 const ParmVarDecl *OtherParm =
94 (*M->begin_overridden_methods())->getParamDecl(P.second);
95 StringRef Name = OtherParm->getName();
96 if (!Name.empty())
97 NewName = Name;
98 }
99
100 // If the definition has a named parameter use that name.
101 if (Definition) {
102 const ParmVarDecl *DefParm = Definition->getParamDecl(P.second);
103 StringRef Name = DefParm->getName();
104 if (!Name.empty())
105 NewName = Name;
106 }
107
108 // Now insert the comment. Note that getLocation() points to the place
109 // where the name would be, this allows us to also get complex cases like
110 // function pointers right.
111 const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
112 D << FixItHint::CreateInsertion(Parm->getLocation(),
113 " /*" + NewName.str() + "*/");
114 }
115 }
116}
117
118} // namespace clang::tidy::readability
const Expr * E
llvm::SmallString< 256U > Name
Params Parm
const google::protobuf::Message & M
Definition: Server.cpp:309
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.