diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.h @@ -0,0 +1,34 @@ +//===--- AvoidConstOrRefDataMembersCheck.h - clang-tidy ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCONSTORREFDATAMEMBERSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCONSTORREFDATAMEMBERSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-const-or-ref-data-members.html +class AvoidConstOrRefDataMembersCheck : public ClangTidyCheck { +public: + AvoidConstOrRefDataMembersCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCONSTORREFDATAMEMBERSCHECK_H diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidConstOrRefDataMembersCheck.cpp @@ -0,0 +1,35 @@ +//===--- AvoidConstOrRefDataMembersCheck.cpp - clang-tidy -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AvoidConstOrRefDataMembersCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace cppcoreguidelines { + +void AvoidConstOrRefDataMembersCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(fieldDecl().bind("x"), this); +} + +void AvoidConstOrRefDataMembersCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *MatchedDecl = Result.Nodes.getNodeAs("x"); + if (MatchedDecl->getType().getTypePtr()->isReferenceType()) + diag(MatchedDecl->getLocation(), "member %0 is a reference") << MatchedDecl; + if (MatchedDecl->getType().isConstQualified()) + diag(MatchedDecl->getLocation(), "member %0 is const qualified") + << MatchedDecl; +} + +} // namespace cppcoreguidelines +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt @@ -4,6 +4,7 @@ ) add_clang_library(clangTidyCppCoreGuidelinesModule + AvoidConstOrRefDataMembersCheck.cpp AvoidGotoCheck.cpp AvoidNonConstGlobalVariablesCheck.cpp CppCoreGuidelinesTidyModule.cpp diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp @@ -14,6 +14,7 @@ #include "../modernize/AvoidCArraysCheck.h" #include "../modernize/UseOverrideCheck.h" #include "../readability/MagicNumbersCheck.h" +#include "AvoidConstOrRefDataMembersCheck.h" #include "AvoidGotoCheck.h" #include "AvoidNonConstGlobalVariablesCheck.h" #include "InitVariablesCheck.h" @@ -47,6 +48,8 @@ void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { CheckFactories.registerCheck( "cppcoreguidelines-avoid-c-arrays"); + CheckFactories.registerCheck( + "cppcoreguidelines-avoid-const-or-ref-data-members"); CheckFactories.registerCheck( "cppcoreguidelines-avoid-goto"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -123,6 +123,11 @@ Warns when the code is unwrapping a `std::optional`, `absl::optional`, or `base::Optional` object without assuring that it contains a value. +- New :doc:`cppcoreguidelines-avoid-const-or-ref-data-members + ` check. + + Warns when a struct or class uses const or reference (lvalue or rvalue) data members. + - New :doc:`modernize-macro-to-enum ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-const-or-ref-data-members.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-const-or-ref-data-members.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-const-or-ref-data-members.rst @@ -0,0 +1,48 @@ +.. title:: clang-tidy - cppcoreguidelines-avoid-const-or-ref-data-members + +cppcoreguidelines-avoid-const-or-ref-data-members +================================================= + +This check warns when structs or classes have const-qualified or reference +(lvalue or rvalue) data members. Having such members is rarely useful, and +makes the class only copy-constructible but not copy-assignable. + +The check implements +`C.12 of C++ Core Guidelines `_. + +Further reading: +`Data members: Never const `_. + +Examples: + +.. code-block:: c++ + + // Bad, const-qualified member + struct Const { + const int x; + } + + // Good: + class Foo { + public: + int get() const { return x; } + private: + int x; + }; + + // Bad, lvalue reference member + struct Ref { + int& x; + }; + + // Good: + struct Foo { + int* x; // Alternative 1 + gsl::not_null x; // Alternative 2 + std::reference_wrapper x; // Alternative 3 + }; + + // Bad, rvalue reference member + struct RefRef { + int&& x; + }; diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -151,6 +151,7 @@ `clang-analyzer-valist.Unterminated `_, `concurrency-mt-unsafe `_, `concurrency-thread-canceltype-asynchronous `_, + `cppcoreguidelines-avoid-const-or-ref-data-members `_, `cppcoreguidelines-avoid-goto `_, `cppcoreguidelines-avoid-non-const-global-variables `_, `cppcoreguidelines-init-variables `_, "Yes" diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-const-or-ref-data-members.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-const-or-ref-data-members.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-const-or-ref-data-members.cpp @@ -0,0 +1,121 @@ +// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-const-or-ref-data-members %t +namespace std { +template +struct reference_wrapper {}; +} // namespace std + +namespace gsl { +template +struct not_null {}; +} // namespace gsl + +struct Ok { + int i; + int *p; + const int *pc; + std::reference_wrapper r; + gsl::not_null n; +}; + +struct ConstMember { + const int c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members] +}; + +struct RefMember { + int &r; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'r' is a reference +}; + +struct RefRefMember { + int &&rr; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' is a reference +}; + +struct ConstRefMember { + const int &r; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'r' is a reference +}; + +struct ConstAndRefMember { + int const c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' is const qualified + int &r; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'r' is a reference + int &&rr; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' is a reference +}; + +struct Foo {}; + +struct Ok2 { + Foo i; + Foo *p; + const Foo *pc; + std::reference_wrapper r; + gsl::not_null n; +}; + +struct ConstMember2 { + const Foo c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members] +}; + +struct RefMember2 { + Foo &r; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'r' is a reference +}; + +struct RefRefMember2 { + Foo &&rr; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' is a reference +}; + +struct ConstRefMember2 { + const Foo &r; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'r' is a reference +}; + +struct ConstAndRefMember2 { + const Foo c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' is const qualified + Foo &r; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'r' is a reference + Foo &&rr; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' is a reference +}; + +using ConstType = const int; +using RefType = int &; +using RefRefType = int &&; + +struct WithAlias { + ConstType c; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' is const qualified + RefType r; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: member 'r' is a reference + RefRefType rr; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' is a reference +}; + +template +struct TemplatedConst { + T t; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' is const qualified +}; + +template +struct TemplatedRef { + T t; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' is a reference +}; + +template +struct TemplatedOk { + T t; +}; + +TemplatedConst t1{123}; +TemplatedRef t2{123}; +TemplatedRef t3{123}; +TemplatedOk t4{};