pfultz2 created this revision.
pfultz2 added reviewers: aaron.ballman, alexfh.
pfultz2 added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, mgorny.
Herald added a project: All.
pfultz2 requested review of this revision.
Herald added a subscriber: cfe-commits.

This check diagnoses instances where an enum is implicitly converted to an
integer. In C++11, enums can be defined as `enum class` which will prevent
such implicit conversion, however, `enum` provides no such guarantees to
prevent bugs. There can be many reasons why `enum` cannot be replaced with
`enum class` such as compatibility with C or legacy libraries.

This check will diagnose similar implicit conversions when using `enum` to
find the same class of bugs. Currently it will only warn on function or
constructor calls as such conversions are not clear to the user, but this
could be expanded in the future.

  void foo(int i);
  void f() {
      foo(e1); // e1 is implictly converted to an int
  }


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D129570

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.h
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/bugprone/enum-to-int.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/checkers/bugprone/enum-to-int.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/enum-to-int.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/enum-to-int.cpp
@@ -0,0 +1,28 @@
+// RUN: %check_clang_tidy %s bugprone-enum-to-int %t
+
+enum A { e1,
+         e2 };
+
+struct bar {
+  bar(int);
+};
+void foo(int i);
+void f1() {
+  foo(e1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: Enum is implictly converted to an integral. [bugprone-enum-to-int]
+}
+void f2() {
+  foo(static_cast<int>(e1));
+}
+void f3() {
+  int i = e1;
+  foo(i);
+}
+void f4() {
+  bar a(e1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Enum is implictly converted to an integral. [bugprone-enum-to-int]
+}
+void f5() {
+  auto a = bar{e1};
+  // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Enum is implictly converted to an integral. [bugprone-enum-to-int]
+}
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
@@ -85,6 +85,7 @@
    `bugprone-dangling-handle <bugprone/dangling-handle.html>`_,
    `bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers.html>`_,
    `bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters.html>`_,
+   `bugprone-enum-to-int <bugprone/enum-to-int.html>`_,
    `bugprone-exception-escape <bugprone/exception-escape.html>`_,
    `bugprone-fold-init-type <bugprone/fold-init-type.html>`_,
    `bugprone-forward-declaration-namespace <bugprone/forward-declaration-namespace.html>`_,
Index: clang-tools-extra/docs/clang-tidy/checks/bugprone/enum-to-int.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone/enum-to-int.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - bugprone-enum-to-int
+
+bugprone-enum-to-int
+====================
+
+This check diagnoses instances where an enum is implicitly converted to an
+integer. In C++11, enums can be defined as ``enum class`` which will prevent
+such implicit conversion, however, ``enum`` provides no such guarantess to
+prevent bugs. There can be many reasons why ``enum`` cannot be replaced with
+``enum class`` such as compatibility with C or legacy libraries.
+
+This check will diagnose similiar implicit conversions whne using ``enum`` to
+find the same class of bugs. Currently it will only warn on function or
+constructor calls as such conversions are not clear to the usr, but this
+could be expanded in the future.
+
+Examples:
+
+.. code-block:: c++
+
+    void foo(int i);
+    void f() {
+        foo(e1); // e1 is implictly converted to an int
+    }
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -118,6 +118,11 @@
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-enum-to-int
+  <clang-tidy/checks/bugprone/enum-to-int>` check.
+
+  Finds implicit conversion of enum to an integral type.
+
 - New :doc:`bugprone-shared-ptr-array-mismatch <clang-tidy/checks/bugprone/shared-ptr-array-mismatch>` check.
 
   Finds initializations of C++ shared pointers to non-array type that are initialized with an array.
Index: clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.h
@@ -0,0 +1,34 @@
+//===--- EnumToIntCheck.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_BUGPRONE_ENUMTOINTCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ENUMTOINTCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/enum-to-int.html
+class EnumToIntCheck : public ClangTidyCheck {
+public:
+  EnumToIntCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_ENUMTOINTCHECK_H
Index: clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/EnumToIntCheck.cpp
@@ -0,0 +1,37 @@
+//===--- EnumToIntCheck.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 "EnumToIntCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void EnumToIntCheck::registerMatchers(MatchFinder *Finder) {
+  auto ImplicitEnumToInt = implicitCastExpr(
+      hasCastKind(CK_IntegralCast),
+      hasSourceExpression(expr(hasType(enumType()))),
+      anyOf(hasParent(callExpr()), hasParent(cxxConstructExpr())));
+  Finder->addMatcher(ImplicitEnumToInt.bind("x"), this);
+}
+
+void EnumToIntCheck::check(const MatchFinder::MatchResult &Result) {
+  // FIXME: Add callback implementation.
+  const auto *MatchedExpr = Result.Nodes.getNodeAs<Expr>("x");
+  diag(MatchedExpr->getBeginLoc(),
+       "Enum is implictly converted to an integral.")
+      << MatchedExpr->getSourceRange();
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -14,6 +14,7 @@
   DanglingHandleCheck.cpp
   DynamicStaticInitializersCheck.cpp
   EasilySwappableParametersCheck.cpp
+  EnumToIntCheck.cpp
   ExceptionEscapeCheck.cpp
   FoldInitTypeCheck.cpp
   ForwardDeclarationNamespaceCheck.cpp
Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -19,6 +19,7 @@
 #include "DanglingHandleCheck.h"
 #include "DynamicStaticInitializersCheck.h"
 #include "EasilySwappableParametersCheck.h"
+#include "EnumToIntCheck.h"
 #include "ExceptionEscapeCheck.h"
 #include "FoldInitTypeCheck.h"
 #include "ForwardDeclarationNamespaceCheck.h"
@@ -98,6 +99,7 @@
         "bugprone-dynamic-static-initializers");
     CheckFactories.registerCheck<EasilySwappableParametersCheck>(
         "bugprone-easily-swappable-parameters");
+    CheckFactories.registerCheck<EnumToIntCheck>("bugprone-enum-to-int");
     CheckFactories.registerCheck<ExceptionEscapeCheck>(
         "bugprone-exception-escape");
     CheckFactories.registerCheck<FoldInitTypeCheck>(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D129570: Add new cla... Paul Fultz II via Phabricator via cfe-commits

Reply via email to