DNS320 created this revision.
DNS320 added reviewers: aaron.ballman, njames93, alexfh.
DNS320 added a project: clang-tools-extra.
Herald added subscribers: shchenz, kbarton, xazax.hun, mgorny, nemanjai.
DNS320 requested review of this revision.
Herald added a subscriber: cfe-commits.

This check tries to implement C.45 
<https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-default>
 of the C++ Core Guidelines.
During the implementation of the current state of this check, it was found that 
multiple functionalities, which the check also could use, already exists in 
other clang-tidy checks. These are:

- Lookup if the body of a constructor (only) initialize class members 
(cppcoreguidelines-prefer-member-initializer)
- Set a constructor `=default` if possible (hicpp-use-equals-default)
- If possible, move/change constructor list initializers to class member 
initializers (modernize-use-default-member-init)

I would like to ask how I could proceed, as reimplementing already existing 
functionality of other checks might not be preferred, because of reasons like 
duplication and maintainability. But I think it would be beneficial if a check 
exists that combines the mentioned functionalities under the 
`cppcoreguidelines` module.

Generally, do you see a need for this check at all or is the activation of the 
three checks mentioned above the way to go to implicitly enforce C.45?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D104112

Files:
  
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.cpp
  
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.h
  clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-init-default-constructors.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-init-default-constructors.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-init-default-constructors.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-avoid-init-default-constructors.cpp
@@ -0,0 +1,66 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-init-default-constructors %t
+
+class NoDefaultCtor {
+  int z;
+
+  NoDefaultCtor(int a) : z{1} {}
+};
+
+class HasBody {
+  int z;
+
+  HasBody() : z{1} { ; }
+};
+
+class OneParameterOneInitList {
+  int z;
+  int y;
+
+  OneParameterOneInitList(int a = 1) : z{a}, y{1} {}
+};
+
+// Test needed because class member initializations are listed as ``cxxCtorInitializer`` in clang's AST
+class OnlyInClassMemberInit {
+  int z{1};
+  int y = 1;
+
+  OnlyInClassMemberInit() {}
+};
+
+// User may wants explicitly overwrite the class member value in the constructor
+class ExplicitOverwrite {
+  int z{1};
+
+  ExplicitOverwrite() : z{2} {}
+};
+
+class HasBodyInit {
+  int z;
+
+  HasBodyInit() {
+    z = 1;
+  }
+};
+
+class OneInitList {
+  int z;
+
+  OneInitList() : z{1} {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Default constructors like 'OneInitList' can be omitted. Use in-class member initializers instead [cppcoreguidelines-avoid-init-default-constructors]
+};
+
+class OneDirectInit {
+  int z;
+
+  OneDirectInit() : z(1) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Default constructors like 'OneDirectInit' can be omitted. Use in-class member initializers instead [cppcoreguidelines-avoid-init-default-constructors]
+};
+
+class OneInitListOneDirectInit {
+  int z;
+  int y;
+  int w;
+
+  OneInitListOneDirectInit() : z{1}, y(2) {}
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Default constructors like 'OneInitListOneDirectInit' can be omitted. Use in-class member initializers instead [cppcoreguidelines-avoid-init-default-constructors]
+};
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -145,6 +145,7 @@
    `concurrency-mt-unsafe <concurrency-mt-unsafe.html>`_,
    `concurrency-thread-canceltype-asynchronous <concurrency-thread-canceltype-asynchronous.html>`_,
    `cppcoreguidelines-avoid-goto <cppcoreguidelines-avoid-goto.html>`_,
+   `cppcoreguidelines-avoid-init-default-constructors <cppcoreguidelines-avoid-init-default-constructors.html>`_,
    `cppcoreguidelines-avoid-non-const-global-variables <cppcoreguidelines-avoid-non-const-global-variables.html>`_,
    `cppcoreguidelines-init-variables <cppcoreguidelines-init-variables.html>`_, "Yes"
    `cppcoreguidelines-interfaces-global-init <cppcoreguidelines-interfaces-global-init.html>`_,
Index: clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-init-default-constructors.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines-avoid-init-default-constructors.rst
@@ -0,0 +1,26 @@
+.. title:: clang-tidy - cppcoreguidelines-avoid-init-default-constructors
+
+cppcoreguidelines-avoid-init-default-constructors
+==================================================================
+
+This check flags constructors which are only initializing class members.
+Such constructors can be omitted, because the initialization could be
+done with in-class member initializers.
+Constructors implicitly generated by the compiler could be more efficient.
+Furthermore, removing unnecessary code improves readability.
+
+.. code-block:: c++
+
+  class C {
+    int z;
+
+    C() : z{1} {} // Can be omitted
+  };
+
+  // Better
+  class C {
+    int z{1};
+  };
+
+This check implements rule `C.45 <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-default>`_  
+of the C++ Core Guidelines.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -119,6 +119,12 @@
 
   Finds calls to ``new`` with missing exception handler for ``std::bad_alloc``.
 
+- New :doc:`cppcoreguidelines-avoid-init-default-constructors
+  <clang-tidy/checks/cppcoreguidelines-avoid-init-default-constructors>` check.
+
+  Finds constructors which just initialize class members, so they can be
+  replaced with in-class member initializers.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -15,6 +15,7 @@
 #include "../modernize/UseOverrideCheck.h"
 #include "../readability/MagicNumbersCheck.h"
 #include "AvoidGotoCheck.h"
+#include "AvoidInitDefaultConstructorsCheck.h"
 #include "AvoidNonConstGlobalVariablesCheck.h"
 #include "InitVariablesCheck.h"
 #include "InterfacesGlobalInitCheck.h"
@@ -48,6 +49,8 @@
         "cppcoreguidelines-avoid-c-arrays");
     CheckFactories.registerCheck<AvoidGotoCheck>(
         "cppcoreguidelines-avoid-goto");
+    CheckFactories.registerCheck<AvoidInitDefaultConstructorsCheck>(
+        "cppcoreguidelines-avoid-init-default-constructors");
     CheckFactories.registerCheck<readability::MagicNumbersCheck>(
         "cppcoreguidelines-avoid-magic-numbers");
     CheckFactories.registerCheck<AvoidNonConstGlobalVariablesCheck>(
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 add_clang_library(clangTidyCppCoreGuidelinesModule
   AvoidGotoCheck.cpp
+  AvoidInitDefaultConstructorsCheck.cpp
   AvoidNonConstGlobalVariablesCheck.cpp
   CppCoreGuidelinesTidyModule.cpp
   InitVariablesCheck.cpp
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.h
@@ -0,0 +1,38 @@
+//===--- AvoidInitDefaultConstructorsCheck.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_AVOIDINITDEFAULTCONSTRUCTORSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDINITDEFAULTCONSTRUCTORSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Finds constructors which just initialize class members, so they can be
+/// replaced with in-class member initializers.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-init-default-constructors.html
+class AvoidInitDefaultConstructorsCheck : public ClangTidyCheck {
+public:
+  AvoidInitDefaultConstructorsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus;
+  }
+  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_AVOIDINITDEFAULTCONSTRUCTORSCHECK_H
Index: clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidInitDefaultConstructorsCheck.cpp
@@ -0,0 +1,45 @@
+//===--- AvoidInitDefaultConstructorsCheck.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 "AvoidInitDefaultConstructorsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void AvoidInitDefaultConstructorsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      cxxConstructorDecl(
+          hasBody(compoundStmt(unless(hasAnySubstatement(anything())))),
+          isDefaultConstructor(),
+          unless(hasAnyConstructorInitializer(cxxCtorInitializer(
+              withInitializer(hasDescendant(declRefExpr(to(parmVarDecl()))))))),
+          hasAnyConstructorInitializer(
+              forField(unless(hasInClassInitializer(anything())))))
+          .bind("Constructor"),
+      this);
+}
+
+void AvoidInitDefaultConstructorsCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *MatchedConstructor =
+      Result.Nodes.getNodeAs<CXXConstructorDecl>("Constructor");
+
+  diag(MatchedConstructor->getLocation(),
+       "Default constructors like %0 can be omitted. Use in-class member "
+       "initializers instead")
+      << MatchedConstructor;
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to