clang-tools 3.8.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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->getLocStart(), 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->getLocStart());
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
Name
StringHandle Name
Definition: PreprocessorTracker.cpp:525
Finder
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
NewName
static cl::opt< std::string > NewName("new-name", cl::desc("The new name to change the symbol to."), cl::cat(ClangRenameCategory))
SM
SourceManager & SM
Definition: IncludeOrderCheck.cpp:44
NamedParameterCheck.h
Result
const NamedDecl * Result
Definition: USRFinder.cpp:121