clang-tools  7.0.0
NonConstReferences.cpp
Go to the documentation of this file.
1 //===--- NonConstReferences.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 "NonConstReferences.h"
11 #include "../utils/OptionsUtils.h"
12 #include "clang/AST/DeclBase.h"
13 #include "clang/ASTMatchers/ASTMatchFinder.h"
14 #include "clang/ASTMatchers/ASTMatchers.h"
15 
16 using namespace clang::ast_matchers;
17 
18 namespace clang {
19 namespace tidy {
20 namespace google {
21 namespace runtime {
22 
23 NonConstReferences::NonConstReferences(StringRef Name,
24  ClangTidyContext *Context)
25  : ClangTidyCheck(Name, Context),
26  WhiteListTypes(
27  utils::options::parseStringList(Options.get("WhiteListTypes", ""))) {}
28 
30  Options.store(Opts, "WhiteListTypes",
31  utils::options::serializeStringList(WhiteListTypes));
32 }
33 
34 void NonConstReferences::registerMatchers(MatchFinder *Finder) {
35  if (!getLangOpts().CPlusPlus)
36  return;
37 
38  Finder->addMatcher(
39  parmVarDecl(
40  unless(isInstantiated()),
41  hasType(references(
42  qualType(unless(isConstQualified())).bind("referenced_type"))),
43  unless(hasType(rValueReferenceType())))
44  .bind("param"),
45  this);
46 }
47 
48 void NonConstReferences::check(const MatchFinder::MatchResult &Result) {
49  const auto *Parameter = Result.Nodes.getNodeAs<ParmVarDecl>("param");
50  const auto *Function =
51  dyn_cast_or_null<FunctionDecl>(Parameter->getParentFunctionOrMethod());
52 
53  if (Function == nullptr || Function->isImplicit())
54  return;
55 
56  if (!Function->isCanonicalDecl())
57  return;
58 
59  if (const auto *Method = dyn_cast<CXXMethodDecl>(Function)) {
60  // Don't warn on implementations of an interface using references.
61  if (Method->begin_overridden_methods() != Method->end_overridden_methods())
62  return;
63  // Don't warn on lambdas, as they frequently have to conform to the
64  // interface defined elsewhere.
65  if (Method->getParent()->isLambda())
66  return;
67  }
68 
69  auto ReferencedType = *Result.Nodes.getNodeAs<QualType>("referenced_type");
70 
71  if (std::find_if(WhiteListTypes.begin(), WhiteListTypes.end(),
72  [&](llvm::StringRef WhiteListType) {
73  return ReferencedType.getCanonicalType().getAsString(
74  Result.Context->getPrintingPolicy()) ==
75  WhiteListType;
76  }) != WhiteListTypes.end())
77  return;
78 
79  // Don't warn on function references, they shouldn't be constant.
80  if (ReferencedType->isFunctionProtoType())
81  return;
82 
83  // Don't warn on dependent types in templates.
84  if (ReferencedType->isDependentType())
85  return;
86 
87  if (Function->isOverloadedOperator()) {
88  switch (Function->getOverloadedOperator()) {
89  case clang::OO_LessLess:
90  case clang::OO_PlusPlus:
91  case clang::OO_MinusMinus:
92  case clang::OO_PlusEqual:
93  case clang::OO_MinusEqual:
94  case clang::OO_StarEqual:
95  case clang::OO_SlashEqual:
96  case clang::OO_PercentEqual:
97  case clang::OO_LessLessEqual:
98  case clang::OO_GreaterGreaterEqual:
99  case clang::OO_PipeEqual:
100  case clang::OO_CaretEqual:
101  case clang::OO_AmpEqual:
102  // Don't warn on the first parameter of operator<<(Stream&, ...),
103  // operator++, operator-- and operation+assignment operators.
104  if (Function->getParamDecl(0) == Parameter)
105  return;
106  break;
107  case clang::OO_GreaterGreater: {
108  auto isNonConstRef = [](clang::QualType T) {
109  return T->isReferenceType() &&
110  !T.getNonReferenceType().isConstQualified();
111  };
112  // Don't warn on parameters of stream extractors:
113  // Stream& operator>>(Stream&, Value&);
114  // Both parameters should be non-const references by convention.
115  if (isNonConstRef(Function->getParamDecl(0)->getType()) &&
116  (Function->getNumParams() < 2 || // E.g. member operator>>.
117  isNonConstRef(Function->getParamDecl(1)->getType())) &&
118  isNonConstRef(Function->getReturnType()))
119  return;
120  break;
121  }
122  default:
123  break;
124  }
125  }
126 
127  // Some functions use references to comply with established standards.
128  if (Function->getDeclName().isIdentifier() && Function->getName() == "swap")
129  return;
130 
131  // iostream parameters are typically passed by non-const reference.
132  if (StringRef(ReferencedType.getAsString()).endswith("stream"))
133  return;
134 
135  if (Parameter->getName().empty()) {
136  diag(Parameter->getLocation(), "non-const reference parameter at index %0, "
137  "make it const or use a pointer")
138  << Parameter->getFunctionScopeIndex();
139  } else {
140  diag(Parameter->getLocation(),
141  "non-const reference parameter %0, make it const or use a pointer")
142  << Parameter;
143  }
144 }
145 
146 } // namespace runtime
147 } // namespace google
148 } // namespace tidy
149 } // namespace clang
llvm::StringRef Name
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Definition: ClangTidy.cpp:460
std::string serializeStringList(ArrayRef< std::string > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
LangOptions getLangOpts() const
Returns the language options from the context.
Definition: ClangTidy.h:187
Base class for all clang-tidy checks.
Definition: ClangTidy.h:127
std::vector< std::string > parseStringList(StringRef Option)
Parse a semicolon separated list of strings.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
std::map< std::string, std::string > OptionMap
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidy.cpp:427