-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[analyzer] Move alpha checker EnumCastOutOfRange to optin #67157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang-static-analyzer-1 @llvm/pr-subscribers-clang ChangesThe checker EnumCastOutOfRange verifies the (helpful, but not standard-mandated) design rule that integer to enum casts should not produce values that don't have a corresponding enumerator. As it was improved and cleaned up by recent changes, this commit renames it from As this checker handles a basic language feature (which is also present in plain C), I moved it to a "core" subpackage within "optin". In addition to the renaming, this commit cleans up the documentation in Full diff: https://github.com/llvm/llvm-project/pull/67157.diff 6 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 477a40630f11097..522272a81c088f1 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -491,6 +491,9 @@ Static Analyzer
Read the PR for the details.
(`#66086 <https://github.com/llvm/llvm-project/pull/66086>`_)
+- Move checker ``alpha.cplusplus.EnumCastOutOfRange`` out of the ``alpha``
+ package to ``optin.core.EnumCastOutOfRange``.
+
.. _release-notes-sanitizers:
Sanitizers
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index dbd6d7787823530..552f7676a328371 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -535,6 +535,28 @@ optin
Checkers for portability, performance or coding style specific rules.
+.. _optin-core-EnumCastOutOfRange:
+
+optin.core.EnumCastOutOfRange (C, C++)
+""""""""""""""""""""""""""""""""""""""
+Check for integer to enumeration casts that would produce a value with no
+corresponding enumerator. This is not necessarily undefined behavior, but can
+lead to nasty surprises, so projects may decide to use a coding standard that
+disallows these "unusual" conversions.
+
+Note that no warnings are produced when the enum type (e.g. `std::byte`) has no
+enumerators at all.
+
+.. code-block:: cpp
+
+ enum WidgetKind { A=1, B, C, X=99 };
+
+ void foo() {
+ WidgetKind c = static_cast<WidgetKind>(3); // OK
+ WidgetKind x = static_cast<WidgetKind>(99); // OK
+ WidgetKind d = static_cast<WidgetKind>(4); // warn
+ }
+
.. _optin-cplusplus-UninitializedObject:
optin.cplusplus.UninitializedObject (C++)
@@ -1853,23 +1875,6 @@ Reports destructions of polymorphic objects with a non-virtual destructor in the
// destructor
}
-.. _alpha-cplusplus-EnumCastOutOfRange:
-
-alpha.cplusplus.EnumCastOutOfRange (C++)
-""""""""""""""""""""""""""""""""""""""""
-Check for integer to enumeration casts that could result in undefined values.
-
-.. code-block:: cpp
-
- enum TestEnum {
- A = 0
- };
-
- void foo() {
- TestEnum t = static_cast(-1);
- // warn: the value provided to the cast expression is not in
- // the valid range of values for the enum
-
.. _alpha-cplusplus-InvalidatedIterator:
alpha.cplusplus.InvalidatedIterator (C++)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index 65c1595eb6245dd..1c859c39cf44d91 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -36,6 +36,7 @@ def CoreAlpha : Package<"core">, ParentPackage<Alpha>;
// Note: OptIn is *not* intended for checkers that are too noisy to be on by
// default. Such checkers belong in the alpha package.
def OptIn : Package<"optin">;
+def CoreOptIn : Package<"core">, ParentPackage<OptIn>;
// In the Portability package reside checkers for finding code that relies on
// implementation-defined behavior. Such checks are wanted for cross-platform
@@ -433,6 +434,18 @@ def UndefinedNewArraySizeChecker : Checker<"NewArraySize">,
} // end "core.uninitialized"
+//===----------------------------------------------------------------------===//
+// Optin checkers for core language features
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = CoreOptIn in {
+
+def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
+ HelpText<"Check integer to enumeration casts for out of range values">,
+ Documentation<HasDocumentation>;
+
+} // end "optin.core"
+
//===----------------------------------------------------------------------===//
// Unix API checkers.
//===----------------------------------------------------------------------===//
@@ -763,10 +776,6 @@ def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
"destructor in their base class">,
Documentation<HasDocumentation>;
-def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">,
- HelpText<"Check integer to enumeration casts for out of range values">,
- Documentation<HasDocumentation>;
-
def IteratorModeling : Checker<"IteratorModeling">,
HelpText<"Models iterators of C++ containers">,
Dependencies<[ContainerModeling]>,
diff --git a/clang/test/Analysis/enum-cast-out-of-range.c b/clang/test/Analysis/enum-cast-out-of-range.c
index 3282cba653d7125..328b8b28ca70003 100644
--- a/clang/test/Analysis/enum-cast-out-of-range.c
+++ b/clang/test/Analysis/enum-cast-out-of-range.c
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 \
-// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
+// RUN: -analyzer-checker=core,optin.core.EnumCastOutOfRange \
// RUN: -verify %s
enum En_t {
diff --git a/clang/test/Analysis/enum-cast-out-of-range.cpp b/clang/test/Analysis/enum-cast-out-of-range.cpp
index abc1431e5be140f..33790f726c5ff8a 100644
--- a/clang/test/Analysis/enum-cast-out-of-range.cpp
+++ b/clang/test/Analysis/enum-cast-out-of-range.cpp
@@ -1,5 +1,5 @@
// RUN: %clang_analyze_cc1 \
-// RUN: -analyzer-checker=core,alpha.cplusplus.EnumCastOutOfRange \
+// RUN: -analyzer-checker=core,optin.core.EnumCastOutOfRange \
// RUN: -std=c++11 -verify %s
enum unscoped_unspecified_t {
@@ -215,3 +215,14 @@ void empty_enums_init_with_zero_should_not_warn() {
ignore_unused(eu, ef, efu);
}
+
+//Test the example from checkers.rst:
+enum WidgetKind { A=1, B, C, X=99 };
+
+void foo() {
+ WidgetKind c = static_cast<WidgetKind>(3); // OK
+ WidgetKind x = static_cast<WidgetKind>(99); // OK
+ WidgetKind d = static_cast<WidgetKind>(4); // expected-warning {{The value provided to the cast expression is not in the valid range of values for the enum}}
+
+ ignore_unused(c, x, d);
+}
diff --git a/clang/www/analyzer/alpha_checks.html b/clang/www/analyzer/alpha_checks.html
index 181ce1b9de591b3..a00e330a4e99579 100644
--- a/clang/www/analyzer/alpha_checks.html
+++ b/clang/www/analyzer/alpha_checks.html
@@ -350,25 +350,6 @@ <h3 id="cplusplus_alpha_checkers">C++ Alpha Checkers</h3>
}
</pre></div></div></td></tr>
-<tr><td><a id="alpha.cplusplus.EnumCastOutOfRange"><div class="namedescr expandable"><span class="name">
-alpha.cplusplus.EnumCastOutOfRange</span><span class="lang">
-(C++)</span><div class="descr">
- Check for integer to enumeration casts that could result in undefined values.
-</div></div></a></td>
- <td><div class="exampleContainer expandable">
- <div class="example"><pre>
-enum TestEnum {
- A = 0
-};
-
-void foo() {
- TestEnum t = static_cast<TestEnum>(-1);
- // warn: the value provided to the cast expression is not in
- the valid range of values for the enum
-}
-</pre></div></div></td></tr>
-
-
<tr><td><a id="alpha.cplusplus.InvalidatedIterator"><div class="namedescr expandable"><span class="name">
alpha.cplusplus.InvalidatedIterator</span><span class="lang">
(C++)</span><div class="descr">
|
I have run this checker on OS projects, and evaluated the results.
|
Before merging this PR, the diagnostics of the EnumCast checker should be updated to mention the name of the |
Yes, it should call out the enum, call out the value, and then track the value (with |
How well does this check work with bitwise enums? People often write code like:
Would this warning emit false positives for these patterns? If yes, can/should we suppress them? |
@Xazax-hun This checker doesn't accept the use of bitwise enums (like the one in your example), so projects that use bitwise enums should not enable this checker. (Perhaps this limitation should be mentioned in the docs? @gamesh411) It would be possible to write a more complex checker that recognizes and accepts enums that are used as flags; but I'm not sure that it's a good investment of developer-hours and I think that the current simple&stupid checker is already useful for some projects. |
The checker EnumCastOutOfRange verifies the (helpful, but not standard-mandated) design rule that integer to enum casts should not produce values that don't have a corresponding enumerator. As it was improved and cleaned up by recent changes, this commit renames it from `alpha.cplusplus.EnumCastOutOfRange` to `optin.core.EnumCastOutOfRange` to reflect that it's no longer alpha quality. As this checker handles a basic language feature (which is also present in plain C), I moved it to a "core" subpackage within "optin". In addition to the renaming, this commit cleans up the documentation in `checkers.rst` and adds the new example code to a test file to ensure that it's indeed producing the behavior claimend in the documentation.
9fd8def
to
5c42d3e
Compare
(Force pushed the branch because I wanted to rebase it onto a recent main and fix the merge conflicts. Is there a better workflow than this?) |
I think git also offers conflict resolution for |
These suggestions were mostly implemented in #68191, I created PR #74503 to implement the last missing part ("call out the value"). |
PR #74503 was merged, so I think all the review comments are addressed. @haoNoQ @Xazax-hun What do you think about merging this? |
I am a bit concerned about the bad user experience with bitwise enums, but I think that is probably OK since this is an optin check. That being said, I think:
|
The limitation is emphasized in the documentation, and I also added a I'll merge this change as it is now (because I don't want to leave it open for even more time), but @whisperity is interested in this "bitflag enum" case and he'll address these issues when he'll have time for it (in January?). |
Sounds good! |
This breaks check-clang everywhere, e.g.: https://lab.llvm.org/buildbot/#/builders/139/builds/55404 Please take a look and revert for now if it takes a while to fix. (Also, please run tests before committing.) |
The issue was really trivial to fix, I created a PR for it: #75216. Sorry for breaking check-clang, I did ran the tests before pressing merge on the github GUI, but I forgot to consider that the GUI button rebases the commit onto the current main tip before merging it, and while the testcase was passing locally, it started to fail when it was rebased onto a version that contained #74503 (which was also added by me by the way, but I forgot to consider its effect on this commit). |
* main: (5908 commits) [readtapi] Cleanup printing command line options (llvm#75106) [flang] Fix compilation error due to variable no being used (llvm#75210) [C API] Add getters and setters for fast-math flags on relevant instructions (llvm#75123) [libc++][CI] Tests the no RTTI configuration. (llvm#65518) [RemoveDIs] Fold variable into assert, it's only used once. NFC [RemoveDI] Handle DPValues in SROA (llvm#74089) [AArch64][GlobalISel] Test Pre-Commit for Look into array's element [mlir][tensor] Fix bug in `tensor.extract(tensor.from_elements)` folder (llvm#75109) [analyzer] Move alpha checker EnumCastOutOfRange to optin (llvm#67157) [RemoveDIs] Handle DPValues in replaceDbgDeclare (llvm#73507) [SHT_LLVM_BB_ADDR_MAP] Implements PGOAnalysisMap in Object and ObjectYAML with tests. [X86][GlobalISel] Add instruction selection for G_SELECT (llvm#70753) [AMDGPU] Remove unused function splitScalar64BitAddSub [LLVM][DWARF] Add compilation directory and dwo name to TU in dwo section (llvm#74909) [clang][Interp] Implement __builtin_ffs (llvm#72988) [RemoveDIs] Update ConvertDebugDeclareToDebugValue after llvm#72276 (llvm#73508) [libc][NFC] Reuse `FloatProperties` constant instead of creating new ones (llvm#75187) [RemoveDIs] Fix removeRedundantDdbgInstrs utils for dbg.declares (llvm#74102) Reapply "[RemoveDIs][NFC] Find DPValues using findDbgDeclares (llvm#73500)" [GitHub] Remove author association print from new-prs workflow ...
The checker EnumCastOutOfRange verifies the (helpful, but not standard-mandated) design rule that integer to enum casts should not produce values that don't have a corresponding enumerator. As it was improved and cleaned up by recent changes, this commit renames it from
alpha.cplusplus.EnumCastOutOfRange
tooptin.core.EnumCastOutOfRange
to reflect that it's no longer alpha quality.As this checker handles a basic language feature (which is also present in plain C), I moved it to a "core" subpackage within "optin".
In addition to the renaming, this commit cleans up the documentation in
checkers.rst
and adds the new example code to a test file to ensure that it's indeed producing the behavior claimend in the documentation.