[PATCH] D153298: [clang-tidy] Extend bugprone-exception-escape diagnostics

Domján Dániel via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 19 11:12:43 PDT 2023


isuckatcs added inline comments.


================
Comment at: clang-tools-extra/clang-tidy/bugprone/ExceptionEscapeCheck.cpp:88
+
+  for (auto [ThrowType, ThrowLoc] : AnalyzeResult.getExceptionTypes())
+    diag(ThrowLoc, "may throw %0 here", DiagnosticIDs::Note)
----------------



================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:14
 void ExceptionAnalyzer::ExceptionInfo::registerException(
-    const Type *ExceptionType) {
+    const Type *ExceptionType, const SourceLocation Loc) {
   assert(ExceptionType != nullptr && "Only valid types are accepted");
----------------
Is there any particular reason for taking `SourceLocation` by value? A `const SourceLocation &` would avoid an unnecessary copy.


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:21
 void ExceptionAnalyzer::ExceptionInfo::registerExceptions(
-    const Throwables &Exceptions) {
-  if (Exceptions.size() == 0)
+    const Throwables &Exceptions, const SourceLocation Loc) {
+  if (Exceptions.empty())
----------------
Same question here regarding the argument type.


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:25
   Behaviour = State::Throwing;
-  ThrownExceptions.insert(Exceptions.begin(), Exceptions.end());
+  for (const auto [ThrowType, ThrowLoc] : Exceptions)
+    ThrownExceptions.emplace(ThrowType, ThrowLoc.isInvalid() ? Loc : ThrowLoc);
----------------



================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:26
+  for (const auto [ThrowType, ThrowLoc] : Exceptions)
+    ThrownExceptions.emplace(ThrowType, ThrowLoc.isInvalid() ? Loc : ThrowLoc);
 }
----------------
There shouldn't be any invalid location in the container. An exception is thrown by a statement, so we know where in source that happens.


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:352
+
+  auto ShouldRemoveFnt = [HandlerTy, &Context](const Type *ExceptionTy) {
     CanQualType ExceptionCanTy = ExceptionTy->getCanonicalTypeUnqualified();
----------------
For a moment it wasn't entirely clear for me what `Fnt` meant, I suggest using naming like `FnType` or `FunctionType`.


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:391
+        return true;
+      return false;
     }
----------------



================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:408
 
-  for (const Type *T : TypesToDelete)
-    ThrownExceptions.erase(T);
+    CaughtExceptions.emplace(*It);
+    It = ThrownExceptions.erase(It);
----------------
This introduces a side effect to this function and makes it do 2 things at the same time. Besides filtering the caught exceptions, it also collects and returns them through a reference parameter.

I don't mind the latter, but in that case I'd like to see the caught exceptions returned from the function as a part of the return statement. Also notice that if `CaughtExceptions` is not empty, `Result` is `true`, which makes the latter redundant. I suggest dropping the `bool` return type and returning the `Throwables` instead.




================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:428
+            (IgnoredTypes.count(TD->getName()) > 0)) {
+          It = ThrownExceptions.erase(It);
+          continue;
----------------
You are erasing something from a container on which you're iteration over. Are you sure the iterators are not invalidated, when the internal representation changes?


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:542
+                                   CaughtExceptions)) {
+          CaughtExceptions.emplace(CaughtType, SourceLocation());
           ExceptionInfo Rethrown = throwsException(Catch->getHandlerBlock(),
----------------
Here we rethrow something from a `try` block if I understand it correctly.

```lang=c++
void foo() {
    throw 3;
}

void bar() {
    try {
        foo();
    } catch(short) {
    }
}
```

The best way would be to set the `SourceLocation` to the point, where `foo()` is called.
I think you would need to create a new `struct` called `ThrowableInfo`, which contains, 
every information that we need to know about the `Throwable` e.g.: type, location, parent
context, etc. That would also be more extensible.

If there's no way to deduce this location for some reason, you can still set the location 
to the `try` block and create messages like `rethrown from try here`, etc. Just don't create
invalid `SourceLocation`s please, because besides them being incorrect, they are also
a source of bugs and crashes.


================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp:573
                                   Excs.getExceptionTypes(), CallStack));
-    for (const Type *Throwable : Excs.getExceptionTypes()) {
+    for (auto [Throwable, ThrowLoc] : Excs.getExceptionTypes()) {
       if (const auto ThrowableRec = Throwable->getAsCXXRecordDecl()) {
----------------



================
Comment at: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.h:40
   /// exception at runtime.
+
   class ExceptionInfo {
----------------
Remove this `\n` please, we don't have an additional new line above the `ExceptionAnalyzer` class either, so please keep it consistent.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D153298/new/

https://reviews.llvm.org/D153298



More information about the cfe-commits mailing list