clang-tools  3.9.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 "clang/AST/DeclBase.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 google {
20 namespace runtime {
21 
22 void NonConstReferences::registerMatchers(MatchFinder *Finder) {
23  Finder->addMatcher(
24  parmVarDecl(
25  unless(isInstantiated()),
26  hasType(references(
27  qualType(unless(isConstQualified())).bind("referenced_type"))),
28  unless(hasType(rValueReferenceType())))
29  .bind("param"),
30  this);
31 }
32 
33 void NonConstReferences::check(const MatchFinder::MatchResult &Result) {
34  const auto *Parameter = Result.Nodes.getNodeAs<ParmVarDecl>("param");
35  const auto *Function =
36  dyn_cast_or_null<FunctionDecl>(Parameter->getParentFunctionOrMethod());
37 
38  if (Function == nullptr || Function->isImplicit())
39  return;
40 
41  if (!Function->isCanonicalDecl())
42  return;
43 
44  if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
45  // Don't warn on implementations of an interface using references.
46  if (Method->begin_overridden_methods() != Method->end_overridden_methods())
47  return;
48  // Don't warn on lambdas, as they frequently have to conform to the
49  // interface defined elsewhere.
50  if (Method->getParent()->isLambda())
51  return;
52  }
53 
54  auto ReferencedType = *Result.Nodes.getNodeAs<QualType>("referenced_type");
55  // Don't warn on function references, they shouldn't be constant.
56  if (ReferencedType->isFunctionProtoType())
57  return;
58 
59  // Don't warn on dependent types in templates.
60  if (ReferencedType->isDependentType())
61  return;
62 
63  if (Function->isOverloadedOperator()) {
64  switch (Function->getOverloadedOperator()) {
65  case clang::OO_LessLess:
66  case clang::OO_PlusPlus:
67  case clang::OO_MinusMinus:
68  case clang::OO_PlusEqual:
69  case clang::OO_MinusEqual:
70  case clang::OO_StarEqual:
71  case clang::OO_SlashEqual:
72  case clang::OO_PercentEqual:
73  case clang::OO_LessLessEqual:
74  case clang::OO_GreaterGreaterEqual:
75  case clang::OO_PipeEqual:
76  case clang::OO_CaretEqual:
77  case clang::OO_AmpEqual:
78  // Don't warn on the first parameter of operator<<(Stream&, ...),
79  // operator++, operator-- and operation+assignment operators.
80  if (Function->getParamDecl(0) == Parameter)
81  return;
82  break;
83  case clang::OO_GreaterGreater: {
84  auto isNonConstRef = [](clang::QualType T) {
85  return T->isReferenceType() &&
86  !T.getNonReferenceType().isConstQualified();
87  };
88  // Don't warn on parameters of stream extractors:
89  // Stream& operator>>(Stream&, Value&);
90  // Both parameters should be non-const references by convention.
91  if (isNonConstRef(Function->getParamDecl(0)->getType()) &&
92  (Function->getNumParams() < 2 || // E.g. member operator>>.
93  isNonConstRef(Function->getParamDecl(1)->getType())) &&
94  isNonConstRef(Function->getReturnType()))
95  return;
96  break;
97  }
98  default:
99  break;
100  }
101  }
102 
103  // Some functions use references to comply with established standards.
104  if (Function->getDeclName().isIdentifier() && Function->getName() == "swap")
105  return;
106 
107  // iostream parameters are typically passed by non-const reference.
108  if (StringRef(ReferencedType.getAsString()).endswith("stream"))
109  return;
110 
111  if (Parameter->getName().empty()) {
112  diag(Parameter->getLocation(),
113  "non-const reference parameter at index %0, "
114  "make it const or use a pointer")
115  << Parameter->getFunctionScopeIndex();
116  } else {
117  diag(Parameter->getLocation(),
118  "non-const reference parameter %0, make it const or use a pointer")
119  << Parameter;
120  }
121 }
122 
123 } // namespace runtime
124 } // namespace google
125 } // namespace tidy
126 } // namespace clang
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:210
const NamedDecl * Result
Definition: USRFinder.cpp:137