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