================
@@ -0,0 +1,283 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// This checker uses a 7-step algorithm to accomplish scope analysis of a
+// variable and determine if it's in too large a scope. Note that the
+// clang-tidy framework is aimed mainly at supporting text-manipulation,
+// diagnostics, or common AST patterns. Scope reduction analysis is
+// quite specialized, and there's not much support specifically for
+// those steps. Perhaps someone else knows better and can help simplify
+// this code in a more concrete way other than simply suggesting it can
+// be simpler.
+//
+// The 7-step algorithm used by this checker for scope reduction analysis is:
+// 1) Filter out variables declared in for-loop initializations
+//    - Those variables are already in optimal scope, and can be skipped
+// 2) Collect variable uses
+//    - find all DeclRefExpr nodes that reference the variable
+// 3) Build scope chains
+//    - for each use, find all compound statements that contain it (from
+//      innermost to outermost)
+// 4) Find the innermost compound statement that contains all uses
+//    - This is the smallest scope where the variable could be declared
+// 5) Find declaration scope
+//    - Locate the compound statement containing the variable declaration
+// 6) Verify nesting
+//    - Ensure the usage scope is actually nested within the declaration scope
+// 7) Alternate analysis - check for for-loop initialization opportunity
+//    - This is only run if compound stmt analysis didn't find smaller scope
+//    - Only check local variables, not parameters
+//    - Determine if all uses are within the same for-loop and suggest
+//      for-loop initialization
+//
+// The algo works by finding the smallest scope that could contain the variable
+// declaration while still encompassing all it's uses.
+
+#include "ScopeReductionCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+// TODO: Try using utils::decl_ref_expr::allDeclRefExprs here.
+static void
+collectVariableUses(const Stmt *S, const VarDecl *Var,
+                    llvm::SmallVector<const DeclRefExpr *, 8> &Uses) {
+  if (!S)
+    return;
+
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(S)) {
+    if (DRE->getDecl() == Var)
+      Uses.push_back(DRE);
+  }
+
+  for (const Stmt *Child : S->children())
+    collectVariableUses(Child, Var, Uses);
+}
+
+void ScopeReductionCheck::registerMatchers(MatchFinder *Finder) {
+  // TODO: Try adding unless(hasParent(declStmt(hasParent(forStmt( to matcher
+  //       to simplify check code.
+  Finder->addMatcher(varDecl(hasLocalStorage()).bind("var"), this);
+}
+
+void ScopeReductionCheck::check(
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var");
+  if (!Var)
+    return;
+
+  // Step 1: Filter out variables declared in for-loop initializations
+  // These variables are already in their optimal scope and shouldn't be
+  // analyzed
+  auto &Parents = Result.Context->getParentMapContext();
+  auto ParentNodes = Parents.getParents(DynTypedNode::create(*Var));
+
+  if (!ParentNodes.empty()) {
+    if (const auto *Parent = ParentNodes[0].get<Stmt>()) {
+      if (isa<DeclStmt>(Parent)) {
+        // Check if DeclStmt's parent is ForStmt
+        auto GrandParentNodes = Parents.getParents(*Parent);
+        if (!GrandParentNodes.empty()) {
+          if (const auto *GrandParent = GrandParentNodes[0].get<Stmt>()) {
+            if (isa<ForStmt>(GrandParent))
+              return; // Skip for-loop declared variables
+          }
+        }
+      }
+    }
+  }
+
+  // auto *Context = Result.Context;
+  auto *Function = dyn_cast<FunctionDecl>(Var->getDeclContext());
+  if (!Function || !Function->hasBody())
----------------
zwuis wrote:

We can put this logic in the matcher.

https://github.com/llvm/llvm-project/pull/175429
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to