diff options
author | Alexander Kornienko <alexfh@google.com> | 2016-02-02 17:27:01 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2016-02-02 17:27:01 +0000 |
commit | 26e46d8fae7f3f38f1d86bcb20473b262c835d77 (patch) | |
tree | 45954b70c35ca0fbe58558a1e3f867e387fb2737 /clang-tools-extra/clang-tidy/google/NonConstReferences.cpp | |
parent | 3131074723a0928ba02acb4cd0d0840498637c53 (diff) | |
download | bcm5719-llvm-26e46d8fae7f3f38f1d86bcb20473b262c835d77.tar.gz bcm5719-llvm-26e46d8fae7f3f38f1d86bcb20473b262c835d77.zip |
[clang-tidy] Add non-constant references in function parameters check.
Summary: This is implemented originally by Alexander Kornienko.
Reviewers: alexfh
Subscribers: cfe-commits
Patch by Haojian Wu!
Differential Revision: http://reviews.llvm.org/D16717
llvm-svn: 259530
Diffstat (limited to 'clang-tools-extra/clang-tidy/google/NonConstReferences.cpp')
-rw-r--r-- | clang-tools-extra/clang-tidy/google/NonConstReferences.cpp | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp b/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp new file mode 100644 index 00000000000..a56d93792ed --- /dev/null +++ b/clang-tools-extra/clang-tidy/google/NonConstReferences.cpp @@ -0,0 +1,119 @@ +//===--- NonConstReferences.cpp - clang-tidy --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "NonConstReferences.h" +#include "clang/AST/DeclBase.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace google { +namespace runtime { + +void NonConstReferences::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + parmVarDecl( + unless(isInstantiated()), + hasType(references( + qualType(unless(isConstQualified())).bind("referenced_type"))), + unless(hasType(rValueReferenceType()))) + .bind("param"), + this); +} + +void NonConstReferences::check(const MatchFinder::MatchResult &Result) { + const auto *Parameter = Result.Nodes.getNodeAs<ParmVarDecl>("param"); + const auto *Function = + dyn_cast_or_null<FunctionDecl>(Parameter->getParentFunctionOrMethod()); + + if (Function == nullptr || Function->isImplicit()) + return; + + if (!Function->isCanonicalDecl()) + return; + + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) { + // Don't warn on implementations of an interface using references. + if (Method->begin_overridden_methods() != Method->end_overridden_methods()) + return; + // Don't warn on lambdas, as they frequently have to conform to the + // interface defined elsewhere. + if (Method->getParent()->isLambda()) + return; + } + + auto ReferencedType = *Result.Nodes.getNodeAs<QualType>("referenced_type"); + // Don't warn on function references, they shouldn't be constant. + if (ReferencedType->isFunctionProtoType()) + return; + + // Don't warn on dependent types in templates. + if (ReferencedType->isDependentType()) + return; + + if (Function->isOverloadedOperator()) { + switch (Function->getOverloadedOperator()) { + case clang::OO_LessLess: + case clang::OO_PlusPlus: + case clang::OO_MinusMinus: + case clang::OO_PlusEqual: + case clang::OO_MinusEqual: + case clang::OO_StarEqual: + case clang::OO_SlashEqual: + case clang::OO_PercentEqual: + case clang::OO_LessLessEqual: + case clang::OO_GreaterGreaterEqual: + case clang::OO_PipeEqual: + case clang::OO_CaretEqual: + case clang::OO_AmpEqual: + // Don't warn on the first parameter of operator<<(Stream&, ...), + // operator++, operator-- and operation+assignment operators. + if (Function->getParamDecl(0) == Parameter) + return; + break; + case clang::OO_GreaterGreater: { + auto isNonConstRef = [](clang::QualType T) { + return T->isReferenceType() && + !T.getNonReferenceType().isConstQualified(); + }; + // Don't warn on parameters of stream extractors: + // Stream& operator>>(Stream&, Value&); + // Both parameters should be non-const references by convention. + if (isNonConstRef(Function->getParamDecl(0)->getType()) && + (Function->getNumParams() < 2 || // E.g. member operator>>. + isNonConstRef(Function->getParamDecl(1)->getType())) && + isNonConstRef(Function->getReturnType())) + return; + break; + } + default: + break; + } + } + + // Some functions use references to comply with established standards. + if (Function->getDeclName().isIdentifier() && Function->getName() == "swap") + return; + + // iostream parameters are typically passed by non-const reference. + if (StringRef(ReferencedType.getAsString()).endswith("stream")) + return; + + diag(Parameter->getLocation(), + "non-const reference parameter '%0', make it const or use a pointer") + << Parameter->getName(); +} + +} // namespace runtime +} // namespace google +} // namespace tidy +} // namespace clang |