clang-tools 10.0.0

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