blob: 5667bd1950201d154d9f4343b2f841fa2f5e1673 [file] [log] [blame]
Alexander Kornienko26e46d82016-02-02 17:27:01 +00001//===--- 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
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
19namespace google {
20namespace runtime {
21
22void 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
33void 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
Haojian Wu4d67ec32016-02-04 14:06:49 +0000111 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(),
Benjamin Kramera62e2232016-04-07 14:55:25 +0000118 "non-const reference parameter %0, make it const or use a pointer")
119 << Parameter;
Haojian Wu4d67ec32016-02-04 14:06:49 +0000120 }
Alexander Kornienko26e46d82016-02-02 17:27:01 +0000121}
122
123} // namespace runtime
124} // namespace google
125} // namespace tidy
126} // namespace clang