================
@@ -0,0 +1,526 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 9-step algorithm to accomplish scope analysis of a
+// variable and determine if it can be declared in a smaller 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 9-step algorithm used by this checker for scope reduction analysis is:
+// 1) AST Matcher Filtering
+//    - Only match variables within functions (hasAncestor(functionDecl())
+//    - Exclude for-loop declared variables
+//       (unless(hasParent(declStmt(hasParent(forStmt))))))
+//    - Exclude variables with function call initializers
+//       (unless(hasInitializer(...)))
+//    - Exclude parameters from analysis
+//       (unless(parmVarDecl())
+//    - Exclude try-catch variables (unless(hasParent(cxxCatchStmt())))
+// 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) Check for modification detection
+//    - Skip analysis for initialized variables modified with unary operators
+//    - Skip analysis for initialized variables moved into switch bodies
+//    - This prevents moving variables where initialization would be lost or
+//    conditional
+// 6) Check for loop body placement
+//    - Skip analysis if suggested scope would place variable inside loop body
+//    - This prevents suggesting moving variables into loop bodies 
(inefficient)
+// 7) Switch case analysis
+//    - Check if variable uses span multiple case labels in the same switch
+//    - Skip analysis if so, as variables cannot be declared in switch body
+// 8) Verify scope nesting and report
+//    - Find the compound statement containing the variable declaration
+//    - Only report if the usage scope is nested within the declaration scope
+//    - This ensures we only suggest moving variables to smaller scopes
+// 9) Alternative analysis - check for for-loop initialization opportunity
+//    - Only runs if compound statement analysis didn't find a smaller scope
+//    - Only check local variables, not parameters
+//    - Determine if all uses are within the same for-loop and suggest
+//      for-loop initialization, but only if for-loop is in smaller scope
+//
+// The algorithm works by finding the smallest scope that could contain the
+// variable declaration while still encompassing all its uses, but only reports
+// when that scope is smaller than the current declaration scope.
+
+#include "ScopeReductionCheck.h"
+#include "../utils/DeclRefExprUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+static void
+collectVariableUses(const clang::Stmt *S, const clang::VarDecl *Var,
+                    llvm::SmallVector<const clang::DeclRefExpr *, 8> &Uses) {
+  if (!S || !Var)
+    return;
+
+  const llvm::SmallPtrSet<const clang::DeclRefExpr *, 16> DREs =
+      clang::tidy::utils::decl_ref_expr::allDeclRefExprs(*Var, *S,
+                                                         Var->getASTContext());
+
+  // Copy the results into the provided SmallVector
+  Uses.clear();
+  Uses.append(DREs.begin(), DREs.end());
+}
+
+void ScopeReductionCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      varDecl(hasLocalStorage(), unless(hasGlobalStorage()),
+              hasAncestor(functionDecl()), unless(parmVarDecl()),
+              unless(hasParent(declStmt(hasParent(forStmt())))),
+              unless(hasParent(declStmt(hasParent(cxxForRangeStmt())))),
+              unless(hasParent(cxxCatchStmt())),
+              unless(hasInitializer(anyOf(
+                  hasDescendant(callExpr()), 
hasDescendant(cxxMemberCallExpr()),
+                  hasDescendant(cxxOperatorCallExpr()), callExpr(),
+                  cxxMemberCallExpr(), cxxOperatorCallExpr()))))
----------------
zwuis wrote:

`CXXMemberCallExpr` and `CXXOperatorCallExpr` are derived class of `CallExpr`. 
No need to use these 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