diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy')
4 files changed, 159 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/google/CMakeLists.txt b/clang-tools-extra/clang-tidy/google/CMakeLists.txt index 3597613f04c..387e12112cd 100644 --- a/clang-tools-extra/clang-tidy/google/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/google/CMakeLists.txt @@ -8,6 +8,7 @@ add_clang_library(clangTidyGoogleModule 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 395de361afa..1281e15ff7b 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 @@ public: "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 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 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 00000000000..3adb1f9d40d --- /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 |

