[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
diff --git a/clang-tools-extra/clang-tidy/google/CMakeLists.txt b/clang-tools-extra/clang-tidy/google/CMakeLists.txt
index 3597613..387e121 100644
--- a/clang-tools-extra/clang-tidy/google/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/google/CMakeLists.txt
@@ -8,6 +8,7 @@
GoogleTidyModule.cpp
IntegerTypesCheck.cpp
MemsetZeroLengthCheck.cpp
+ NonConstReferences.cpp
OverloadedUnaryAndCheck.cpp
StringReferenceMemberCheck.cpp
TodoCommentCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
index 395de36..1281e15 100644
--- a/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/google/GoogleTidyModule.cpp
@@ -21,6 +21,7 @@
#include "IntegerTypesCheck.h"
#include "MemsetZeroLengthCheck.h"
#include "OverloadedUnaryAndCheck.h"
+#include "NonConstReferences.h"
#include "StringReferenceMemberCheck.h"
#include "TodoCommentCheck.h"
#include "UnnamedNamespaceInHeaderCheck.h"
@@ -47,6 +48,8 @@
"google-runtime-int");
CheckFactories.registerCheck<runtime::OverloadedUnaryAndCheck>(
"google-runtime-operator");
+ CheckFactories.registerCheck<runtime::NonConstReferences>(
+ "google-runtime-references");
CheckFactories.registerCheck<runtime::StringReferenceMemberCheck>(
"google-runtime-member-string-references");
CheckFactories.registerCheck<runtime::MemsetZeroLengthCheck>(
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 0000000..a56d937
--- /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
diff --git a/clang-tools-extra/clang-tidy/google/NonConstReferences.h b/clang-tools-extra/clang-tidy/google/NonConstReferences.h
new file mode 100644
index 0000000..3adb1f9
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/google/NonConstReferences.h
@@ -0,0 +1,36 @@
+//===--- NonConstReferences.h - clang-tidy ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace google {
+namespace runtime {
+
+/// \brief Checks the usage of non-constant references in function parameters.
+///
+/// https://google.github.io/styleguide/cppguide.html#Reference_Arguments
+class NonConstReferences : public ClangTidyCheck {
+public:
+ NonConstReferences(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace runtime
+} // namespace google
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_GOOGLE_NON_CONST_REFERENCES_H