[PATCH] D97183: [analyzer] Add NoteTag for smart-ptr get()

Valeriy Savchenko via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu May 20 01:52:50 PDT 2021


vsavchenko added inline comments.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtr.h:36
+
+class FindWhereConstrained : public BugReporterVisitor {
+private:
----------------
nit: class name should be a noun (functions and methods are verbs)


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:84
 REGISTER_MAP_WITH_PROGRAMSTATE(TrackedRegionMap, const MemRegion *, SVal)
+// REGISTER_SET_WITH_PROGRAMSTATE(ExprsFromGet, const Stmt *)
+REGISTER_MAP_WITH_PROGRAMSTATE(ExprsFromGet, const MemRegion *,
----------------
Probably forgotten


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:136-139
+        if (StmtsCovered.contains(S)) {
+          return nullptr;
+        }
+        StmtsCovered.insert(S);
----------------
We probably should have a checker in clang-tidy (maybe we already do), for situations like this.
C++ has a long-lasting tradition that set's/map's `insert` return a pair: iterator + bool. The second part tells the user if the `insert` operation actually added the new element or it was already there.
This allows us to do 1 search instead of two.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:141-163
+        auto bugReportOnGet = [&](const Expr *E) -> auto {
+          if (const auto *MCE = llvm::dyn_cast<CXXMemberCallExpr>(E)) {
+            const auto *Method = MCE->getMethodDecl();
+            const auto *Record = MCE->getRecordDecl();
+            if (Method->getName() == "get" &&
+                Record->getDeclContext()->isStdNamespace() &&
+                Record->getName() == "unique_ptr") {
----------------
Is there any reason it's not a method of `FindWhereConstrained`?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:165
+
+        // If statement on raw pointer
+        if (const auto *E = llvm::dyn_cast<ImplicitCastExpr>(S)) {
----------------
After that you have 3 distinct cases to handle. It's a good opportunity for extracting them into separate functions.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:179-180
+              // P.get()
+              if (const auto *InnerCastExpr =
+                      llvm::dyn_cast<ImplicitCastExpr>(Sub)) {
+                Sub = InnerCastExpr->getSubExpr();
----------------
I think it's better to `IgnoreParensAndCasts` instead of manual traversal.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:216
+                // If b is a get() expression, then we can return a note
+                auto report = bugReportOnGet(RHS);
+                if (report) {
----------------
Variables are capitalized.


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:217
+                auto report = bugReportOnGet(RHS);
+                if (report) {
+                  return report;
----------------
It is a widespread pattern in LLVM to declare such variables directly in `if` statements:
```
if (auto Report = bugReportOnGet(RHS))
  return Report;
```


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:227
+        if (const auto *DS = llvm::dyn_cast<DeclStmt>(S)) {
+          const Decl *D = DS->getSingleDecl();
+          if (const auto *VD = llvm::dyn_cast<VarDecl>(D)) {
----------------
So, situations like `int *a = nullptr, *b = smart.get();` are not supported?


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:229
+          if (const auto *VD = llvm::dyn_cast<VarDecl>(D)) {
+            for (const auto *I : PtrsTrackedAndConstrained) {
+              if (I->getName() == VD->getName()) {
----------------
`llvm::find_if`


================
Comment at: clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp:238-245
+                }
+              }
+            }
+          }
+        }
+      }
+    }
----------------
This level of nestedness is frowned upon. It is a good tell that the function should be refactored.
The following code:
```
if (cond1) {
  . . .
  if (cond2) {
    . . .
    if (cond3) {
      . . .
    }
  }
}
return nullptr;
```
can be refactored into:
```
if (!cond1)
  return nullptr;

. . .
if (!cond2)
  return nullptr;

. . .
if (!cond3)
  return nullptr;

. . .
```

It is easier to follow the logic if the function is composed in this manner because from the very beginning you know that `else` with more stuff is not going to follow.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D97183



More information about the cfe-commits mailing list