clang-tools  11.0.0
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 
9 #include "NamedParameterCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 
14 using namespace clang::ast_matchers;
15 
16 namespace clang {
17 namespace tidy {
18 namespace readability {
19 
20 void NamedParameterCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
21  Finder->addMatcher(functionDecl(unless(isInstantiated())).bind("decl"), this);
22 }
23 
24 void NamedParameterCheck::check(const MatchFinder::MatchResult &Result) {
25  const SourceManager &SM = *Result.SourceManager;
26  const auto *Function = Result.Nodes.getNodeAs<FunctionDecl>("decl");
27  SmallVector<std::pair<const FunctionDecl *, unsigned>, 4> UnnamedParams;
28 
29  // Ignore implicitly generated members.
30  if (Function->isImplicit())
31  return;
32 
33  // Ignore declarations without a definition if we're not dealing with an
34  // overriden method.
35  const FunctionDecl *Definition = nullptr;
36  if ((!Function->isDefined(Definition) || Function->isDefaulted() ||
37  Function->isDeleted()) &&
38  (!isa<CXXMethodDecl>(Function) ||
39  cast<CXXMethodDecl>(Function)->size_overridden_methods() == 0))
40  return;
41 
42  // TODO: Handle overloads.
43  // TODO: We could check that all redeclarations use the same name for
44  // arguments in the same position.
45  for (unsigned I = 0, E = Function->getNumParams(); I != E; ++I) {
46  const ParmVarDecl *Parm = Function->getParamDecl(I);
47  if (Parm->isImplicit())
48  continue;
49  // Look for unnamed parameters.
50  if (!Parm->getName().empty())
51  continue;
52 
53  // Don't warn on the dummy argument on post-inc and post-dec operators.
54  if ((Function->getOverloadedOperator() == OO_PlusPlus ||
55  Function->getOverloadedOperator() == OO_MinusMinus) &&
56  Parm->getType()->isSpecificBuiltinType(BuiltinType::Int))
57  continue;
58 
59  // Sanity check the source locations.
60  if (!Parm->getLocation().isValid() || Parm->getLocation().isMacroID() ||
61  !SM.isWrittenInSameFile(Parm->getBeginLoc(), Parm->getLocation()))
62  continue;
63 
64  // Skip gmock testing::Unused parameters.
65  if (auto Typedef = Parm->getType()->getAs<clang::TypedefType>())
66  if (Typedef->getDecl()->getQualifiedNameAsString() == "testing::Unused")
67  continue;
68 
69  // Skip std::nullptr_t.
70  if (Parm->getType().getCanonicalType()->isNullPtrType())
71  continue;
72 
73  // Look for comments. We explicitly want to allow idioms like
74  // void foo(int /*unused*/)
75  const char *Begin = SM.getCharacterData(Parm->getBeginLoc());
76  const char *End = SM.getCharacterData(Parm->getLocation());
77  StringRef Data(Begin, End - Begin);
78  if (Data.find("/*") != StringRef::npos)
79  continue;
80 
81  UnnamedParams.push_back(std::make_pair(Function, I));
82  }
83 
84  // Emit only one warning per function but fixits for all unnamed parameters.
85  if (!UnnamedParams.empty()) {
86  const ParmVarDecl *FirstParm =
87  UnnamedParams.front().first->getParamDecl(UnnamedParams.front().second);
88  auto D = diag(FirstParm->getLocation(),
89  "all parameters should be named in a function");
90 
91  for (auto P : UnnamedParams) {
92  // Fallback to an unused marker.
93  StringRef NewName = "unused";
94 
95  // If the method is overridden, try to copy the name from the base method
96  // into the overrider.
97  const auto *M = dyn_cast<CXXMethodDecl>(P.first);
98  if (M && M->size_overridden_methods() > 0) {
99  const ParmVarDecl *OtherParm =
100  (*M->begin_overridden_methods())->getParamDecl(P.second);
101  StringRef Name = OtherParm->getName();
102  if (!Name.empty())
103  NewName = Name;
104  }
105 
106  // If the definition has a named parameter use that name.
107  if (Definition) {
108  const ParmVarDecl *DefParm = Definition->getParamDecl(P.second);
109  StringRef Name = DefParm->getName();
110  if (!Name.empty())
111  NewName = Name;
112  }
113 
114  // Now insert the comment. Note that getLocation() points to the place
115  // where the name would be, this allows us to also get complex cases like
116  // function pointers right.
117  const ParmVarDecl *Parm = P.first->getParamDecl(P.second);
118  D << FixItHint::CreateInsertion(Parm->getLocation(),
119  " /*" + NewName.str() + "*/");
120  }
121  }
122 }
123 
124 } // namespace readability
125 } // namespace tidy
126 } // namespace clang
E
const Expr * E
Definition: AvoidBindCheck.cpp:88
clang::ast_matchers
Definition: AbseilMatcher.h:14
NamedParameterCheck.h
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
Parm
Params Parm
Definition: ConfigCompileTests.cpp:29
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27