Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:20

0001 //===--- LoopConvertUtils.h - clang-tidy ------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
0010 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H
0011 
0012 #include "clang/AST/ASTContext.h"
0013 #include "clang/AST/RecursiveASTVisitor.h"
0014 #include "clang/ASTMatchers/ASTMatchFinder.h"
0015 #include "clang/Basic/SourceLocation.h"
0016 #include "llvm/ADT/DenseMap.h"
0017 #include "llvm/ADT/SmallSet.h"
0018 #include "llvm/ADT/SmallVector.h"
0019 #include "llvm/ADT/StringRef.h"
0020 #include <algorithm>
0021 #include <memory>
0022 #include <string>
0023 #include <utility>
0024 
0025 namespace clang::tidy::modernize {
0026 
0027 enum LoopFixerKind {
0028   LFK_Array,
0029   LFK_Iterator,
0030   LFK_ReverseIterator,
0031   LFK_PseudoArray
0032 };
0033 
0034 /// A map used to walk the AST in reverse: maps child Stmt to parent Stmt.
0035 using StmtParentMap = llvm::DenseMap<const clang::Stmt *, const clang::Stmt *>;
0036 
0037 /// A map used to walk the AST in reverse:
0038 ///  maps VarDecl to the to parent DeclStmt.
0039 using DeclParentMap =
0040     llvm::DenseMap<const clang::VarDecl *, const clang::DeclStmt *>;
0041 
0042 /// A map used to track which variables have been removed by a refactoring pass.
0043 /// It maps the parent ForStmt to the removed index variable's VarDecl.
0044 using ReplacedVarsMap =
0045     llvm::DenseMap<const clang::ForStmt *, const clang::VarDecl *>;
0046 
0047 /// A map used to remember the variable names generated in a Stmt
0048 using StmtGeneratedVarNameMap =
0049     llvm::DenseMap<const clang::Stmt *, std::string>;
0050 
0051 /// A vector used to store the AST subtrees of an Expr.
0052 using ComponentVector = llvm::SmallVector<const clang::Expr *, 16>;
0053 
0054 /// Class used build the reverse AST properties needed to detect
0055 /// name conflicts and free variables.
0056 class StmtAncestorASTVisitor
0057     : public clang::RecursiveASTVisitor<StmtAncestorASTVisitor> {
0058 public:
0059   StmtAncestorASTVisitor() { StmtStack.push_back(nullptr); }
0060 
0061   /// Run the analysis on the AST.
0062   ///
0063   /// In case we're running this analysis multiple times, don't repeat the work.
0064   void gatherAncestors(ASTContext &Ctx) {
0065     if (StmtAncestors.empty())
0066       TraverseAST(Ctx);
0067   }
0068 
0069   /// Accessor for StmtAncestors.
0070   const StmtParentMap &getStmtToParentStmtMap() { return StmtAncestors; }
0071 
0072   /// Accessor for DeclParents.
0073   const DeclParentMap &getDeclToParentStmtMap() { return DeclParents; }
0074 
0075   friend class clang::RecursiveASTVisitor<StmtAncestorASTVisitor>;
0076 
0077 private:
0078   StmtParentMap StmtAncestors;
0079   DeclParentMap DeclParents;
0080   llvm::SmallVector<const clang::Stmt *, 16> StmtStack;
0081 
0082   bool TraverseStmt(clang::Stmt *Statement);
0083   bool VisitDeclStmt(clang::DeclStmt *Statement);
0084 };
0085 
0086 /// Class used to find the variables and member expressions on which an
0087 /// arbitrary expression depends.
0088 class ComponentFinderASTVisitor
0089     : public clang::RecursiveASTVisitor<ComponentFinderASTVisitor> {
0090 public:
0091   ComponentFinderASTVisitor() = default;
0092 
0093   /// Find the components of an expression and place them in a ComponentVector.
0094   void findExprComponents(const clang::Expr *SourceExpr) {
0095     TraverseStmt(const_cast<clang::Expr *>(SourceExpr));
0096   }
0097 
0098   /// Accessor for Components.
0099   const ComponentVector &getComponents() { return Components; }
0100 
0101   friend class clang::RecursiveASTVisitor<ComponentFinderASTVisitor>;
0102 
0103 private:
0104   ComponentVector Components;
0105 
0106   bool VisitDeclRefExpr(clang::DeclRefExpr *E);
0107   bool VisitMemberExpr(clang::MemberExpr *Member);
0108 };
0109 
0110 /// Class used to determine if an expression is dependent on a variable declared
0111 /// inside of the loop where it would be used.
0112 class DependencyFinderASTVisitor
0113     : public clang::RecursiveASTVisitor<DependencyFinderASTVisitor> {
0114 public:
0115   DependencyFinderASTVisitor(const StmtParentMap *StmtParents,
0116                              const DeclParentMap *DeclParents,
0117                              const ReplacedVarsMap *ReplacedVars,
0118                              const clang::Stmt *ContainingStmt)
0119       : StmtParents(StmtParents), DeclParents(DeclParents),
0120         ContainingStmt(ContainingStmt), ReplacedVars(ReplacedVars) {}
0121 
0122   /// Run the analysis on Body, and return true iff the expression
0123   /// depends on some variable declared within ContainingStmt.
0124   ///
0125   /// This is intended to protect against hoisting the container expression
0126   /// outside of an inner context if part of that expression is declared in that
0127   /// inner context.
0128   ///
0129   /// For example,
0130   /// \code
0131   ///   const int N = 10, M = 20;
0132   ///   int arr[N][M];
0133   ///   int getRow();
0134   ///
0135   ///   for (int i = 0; i < M; ++i) {
0136   ///     int k = getRow();
0137   ///     printf("%d:", arr[k][i]);
0138   ///   }
0139   /// \endcode
0140   /// At first glance, this loop looks like it could be changed to
0141   /// \code
0142   ///   for (int elem : arr[k]) {
0143   ///     int k = getIndex();
0144   ///     printf("%d:", elem);
0145   ///   }
0146   /// \endcode
0147   /// But this is malformed, since `k` is used before it is defined!
0148   ///
0149   /// In order to avoid this, this class looks at the container expression
0150   /// `arr[k]` and decides whether or not it contains a sub-expression declared
0151   /// within the loop body.
0152   bool dependsOnInsideVariable(const clang::Stmt *Body) {
0153     DependsOnInsideVariable = false;
0154     TraverseStmt(const_cast<clang::Stmt *>(Body));
0155     return DependsOnInsideVariable;
0156   }
0157 
0158   friend class clang::RecursiveASTVisitor<DependencyFinderASTVisitor>;
0159 
0160 private:
0161   const StmtParentMap *StmtParents;
0162   const DeclParentMap *DeclParents;
0163   const clang::Stmt *ContainingStmt;
0164   const ReplacedVarsMap *ReplacedVars;
0165   bool DependsOnInsideVariable;
0166 
0167   bool VisitVarDecl(clang::VarDecl *V);
0168   bool VisitDeclRefExpr(clang::DeclRefExpr *D);
0169 };
0170 
0171 /// Class used to determine if any declarations used in a Stmt would conflict
0172 /// with a particular identifier. This search includes the names that don't
0173 /// actually appear in the AST (i.e. created by a refactoring tool) by including
0174 /// a map from Stmts to generated names associated with those stmts.
0175 class DeclFinderASTVisitor
0176     : public clang::RecursiveASTVisitor<DeclFinderASTVisitor> {
0177 public:
0178   DeclFinderASTVisitor(const StringRef &Name,
0179                        const StmtGeneratedVarNameMap *GeneratedDecls)
0180       : Name(Name), GeneratedDecls(GeneratedDecls) {}
0181 
0182   /// Attempts to find any usages of variables name Name in Body, returning
0183   /// true when it is used in Body. This includes the generated loop variables
0184   /// of ForStmts which have already been transformed.
0185   bool findUsages(const clang::Stmt *Body) {
0186     Found = false;
0187     TraverseStmt(const_cast<clang::Stmt *>(Body));
0188     return Found;
0189   }
0190 
0191   friend class clang::RecursiveASTVisitor<DeclFinderASTVisitor>;
0192 
0193 private:
0194   std::string Name;
0195   /// GeneratedDecls keeps track of ForStmts which have been transformed,
0196   /// mapping each modified ForStmt to the variable generated in the loop.
0197   const StmtGeneratedVarNameMap *GeneratedDecls;
0198   bool Found = false;
0199 
0200   bool VisitForStmt(clang::ForStmt *);
0201   bool VisitNamedDecl(clang::NamedDecl *);
0202   bool VisitDeclRefExpr(clang::DeclRefExpr *);
0203   bool VisitTypeLoc(clang::TypeLoc);
0204 };
0205 
0206 /// The information needed to describe a valid convertible usage
0207 /// of an array index or iterator.
0208 struct Usage {
0209   enum UsageKind {
0210     // Regular usages of the loop index (the ones not specified below). Some
0211     // examples:
0212     // \code
0213     //   int X = 8 * Arr[i];
0214     //               ^~~~~~
0215     //   f(param1, param2, *It);
0216     //                     ^~~
0217     //   if (Vec[i].SomeBool) {}
0218     //       ^~~~~~
0219     // \endcode
0220     UK_Default,
0221     // Indicates whether this is an access to a member through the arrow
0222     // operator on pointers or iterators.
0223     UK_MemberThroughArrow,
0224     // If the variable is being captured by a lambda, indicates whether the
0225     // capture was done by value or by reference.
0226     UK_CaptureByCopy,
0227     UK_CaptureByRef
0228   };
0229   // The expression that is going to be converted. Null in case of lambda
0230   // captures.
0231   const Expr *Expression;
0232 
0233   UsageKind Kind;
0234 
0235   // Range that covers this usage.
0236   SourceRange Range;
0237 
0238   explicit Usage(const Expr *E)
0239       : Expression(E), Kind(UK_Default), Range(Expression->getSourceRange()) {}
0240   Usage(const Expr *E, UsageKind Kind, SourceRange Range)
0241       : Expression(E), Kind(Kind), Range(std::move(Range)) {}
0242 };
0243 
0244 /// A class to encapsulate lowering of the tool's confidence level.
0245 class Confidence {
0246 public:
0247   enum Level {
0248     // Transformations that are likely to change semantics.
0249     CL_Risky,
0250 
0251     // Transformations that might change semantics.
0252     CL_Reasonable,
0253 
0254     // Transformations that will not change semantics.
0255     CL_Safe
0256   };
0257   /// Initialize confidence level.
0258   explicit Confidence(Confidence::Level Level) : CurrentLevel(Level) {}
0259 
0260   /// Lower the internal confidence level to Level, but do not raise it.
0261   void lowerTo(Confidence::Level Level) {
0262     CurrentLevel = std::min(Level, CurrentLevel);
0263   }
0264 
0265   /// Return the internal confidence level.
0266   Level getLevel() const { return CurrentLevel; }
0267 
0268 private:
0269   Level CurrentLevel;
0270 };
0271 
0272 // The main computational result of ForLoopIndexVisitor.
0273 using UsageResult = llvm::SmallVector<Usage, 8>;
0274 
0275 // General functions used by ForLoopIndexUseVisitor and LoopConvertCheck.
0276 const Expr *digThroughConstructorsConversions(const Expr *E);
0277 bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second);
0278 const DeclRefExpr *getDeclRef(const Expr *E);
0279 bool areSameVariable(const ValueDecl *First, const ValueDecl *Second);
0280 
0281 /// Discover usages of expressions consisting of index or iterator
0282 /// access.
0283 ///
0284 /// Given an index variable, recursively crawls a for loop to discover if the
0285 /// index variable is used in a way consistent with range-based for loop access.
0286 class ForLoopIndexUseVisitor
0287     : public RecursiveASTVisitor<ForLoopIndexUseVisitor> {
0288 public:
0289   ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar,
0290                          const VarDecl *EndVar, const Expr *ContainerExpr,
0291                          const Expr *ArrayBoundExpr,
0292                          bool ContainerNeedsDereference);
0293 
0294   /// Finds all uses of IndexVar in Body, placing all usages in Usages,
0295   /// and returns true if IndexVar was only used in a way consistent with a
0296   /// range-based for loop.
0297   ///
0298   /// The general strategy is to reject any DeclRefExprs referencing IndexVar,
0299   /// with the exception of certain acceptable patterns.
0300   /// For arrays, the DeclRefExpr for IndexVar must appear as the index of an
0301   /// ArraySubscriptExpression. Iterator-based loops may dereference
0302   /// IndexVar or call methods through operator-> (builtin or overloaded).
0303   /// Array-like containers may use IndexVar as a parameter to the at() member
0304   /// function and in overloaded operator[].
0305   bool findAndVerifyUsages(const Stmt *Body);
0306 
0307   /// Add a set of components that we should consider relevant to the
0308   /// container.
0309   void addComponents(const ComponentVector &Components);
0310 
0311   /// Accessor for Usages.
0312   const UsageResult &getUsages() const { return Usages; }
0313 
0314   /// Adds the Usage if it was not added before.
0315   void addUsage(const Usage &U);
0316 
0317   /// Get the container indexed by IndexVar, if any.
0318   const Expr *getContainerIndexed() const { return ContainerExpr; }
0319 
0320   /// Returns the statement declaring the variable created as an alias
0321   /// for the loop element, if any.
0322   const DeclStmt *getAliasDecl() const { return AliasDecl; }
0323 
0324   /// Accessor for ConfidenceLevel.
0325   Confidence::Level getConfidenceLevel() const {
0326     return ConfidenceLevel.getLevel();
0327   }
0328 
0329   /// Indicates if the alias declaration was in a place where it cannot
0330   /// simply be removed but rather replaced with a use of the alias variable.
0331   /// For example, variables declared in the condition of an if, switch, or for
0332   /// stmt.
0333   bool aliasUseRequired() const { return ReplaceWithAliasUse; }
0334 
0335   /// Indicates if the alias declaration came from the init clause of a
0336   /// nested for loop. SourceRanges provided by Clang for DeclStmts in this
0337   /// case need to be adjusted.
0338   bool aliasFromForInit() const { return AliasFromForInit; }
0339 
0340 private:
0341   /// Typedef used in CRTP functions.
0342   using VisitorBase = RecursiveASTVisitor<ForLoopIndexUseVisitor>;
0343   friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
0344 
0345   /// Overriden methods for RecursiveASTVisitor's traversal.
0346   bool TraverseArraySubscriptExpr(ArraySubscriptExpr *E);
0347   bool TraverseCXXMemberCallExpr(CXXMemberCallExpr *MemberCall);
0348   bool TraverseCXXOperatorCallExpr(CXXOperatorCallExpr *OpCall);
0349   bool TraverseLambdaCapture(LambdaExpr *LE, const LambdaCapture *C,
0350                              Expr *Init);
0351   bool TraverseMemberExpr(MemberExpr *Member);
0352   bool TraverseUnaryOperator(UnaryOperator *Uop);
0353   bool VisitDeclRefExpr(DeclRefExpr *E);
0354   bool VisitDeclStmt(DeclStmt *S);
0355   bool TraverseStmt(Stmt *S);
0356 
0357   bool TraverseStmtImpl(Stmt *S);
0358 
0359   /// Add an expression to the list of expressions on which the container
0360   /// expression depends.
0361   void addComponent(const Expr *E);
0362 
0363   // Input member variables:
0364   ASTContext *Context;
0365   /// The index variable's VarDecl.
0366   const VarDecl *IndexVar;
0367   /// The loop's 'end' variable, which cannot be mentioned at all.
0368   const VarDecl *EndVar;
0369   /// The Expr which refers to the container.
0370   const Expr *ContainerExpr;
0371   /// The Expr which refers to the terminating condition for array-based loops.
0372   const Expr *ArrayBoundExpr;
0373   bool ContainerNeedsDereference;
0374 
0375   // Output member variables:
0376   /// A container which holds all usages of IndexVar as the index of
0377   /// ArraySubscriptExpressions.
0378   UsageResult Usages;
0379   llvm::SmallSet<SourceLocation, 8> UsageLocations;
0380   bool OnlyUsedAsIndex = true;
0381   /// The DeclStmt for an alias to the container element.
0382   const DeclStmt *AliasDecl = nullptr;
0383   Confidence ConfidenceLevel;
0384   /// A list of expressions on which ContainerExpr depends.
0385   ///
0386   /// If any of these expressions are encountered outside of an acceptable usage
0387   /// of the loop element, lower our confidence level.
0388   llvm::SmallVector<std::pair<const Expr *, llvm::FoldingSetNodeID>, 16>
0389       DependentExprs;
0390 
0391   /// The parent-in-waiting. Will become the real parent once we traverse down
0392   /// one level in the AST.
0393   const Stmt *NextStmtParent = nullptr;
0394   /// The actual parent of a node when Visit*() calls are made. Only the
0395   /// parentage of DeclStmt's to possible iteration/selection statements is of
0396   /// importance.
0397   const Stmt *CurrStmtParent = nullptr;
0398 
0399   /// \see aliasUseRequired().
0400   bool ReplaceWithAliasUse = false;
0401   /// \see aliasFromForInit().
0402   bool AliasFromForInit = false;
0403 };
0404 
0405 struct TUTrackingInfo {
0406   /// Reset and initialize per-TU tracking information.
0407   ///
0408   /// Must be called before using container accessors.
0409   TUTrackingInfo() : ParentFinder(new StmtAncestorASTVisitor) {}
0410 
0411   StmtAncestorASTVisitor &getParentFinder() { return *ParentFinder; }
0412   StmtGeneratedVarNameMap &getGeneratedDecls() { return GeneratedDecls; }
0413   ReplacedVarsMap &getReplacedVars() { return ReplacedVars; }
0414 
0415 private:
0416   std::unique_ptr<StmtAncestorASTVisitor> ParentFinder;
0417   StmtGeneratedVarNameMap GeneratedDecls;
0418   ReplacedVarsMap ReplacedVars;
0419 };
0420 
0421 /// Create names for generated variables within a particular statement.
0422 ///
0423 /// VariableNamer uses a DeclContext as a reference point, checking for any
0424 /// conflicting declarations higher up in the context or within SourceStmt.
0425 /// It creates a variable name using hints from a source container and the old
0426 /// index, if they exist.
0427 class VariableNamer {
0428 public:
0429   // Supported naming styles.
0430   enum NamingStyle {
0431     NS_CamelBack,
0432     NS_CamelCase,
0433     NS_LowerCase,
0434     NS_UpperCase,
0435   };
0436 
0437   VariableNamer(StmtGeneratedVarNameMap *GeneratedDecls,
0438                 const StmtParentMap *ReverseAST, const clang::Stmt *SourceStmt,
0439                 const clang::VarDecl *OldIndex,
0440                 const clang::ValueDecl *TheContainer,
0441                 const clang::ASTContext *Context, NamingStyle Style)
0442       : GeneratedDecls(GeneratedDecls), ReverseAST(ReverseAST),
0443         SourceStmt(SourceStmt), OldIndex(OldIndex), TheContainer(TheContainer),
0444         Context(Context), Style(Style) {}
0445 
0446   /// Generate a new index name.
0447   ///
0448   /// Generates the name to be used for an inserted iterator. It relies on
0449   /// declarationExists() to determine that there are no naming conflicts, and
0450   /// tries to use some hints from the container name and the old index name.
0451   std::string createIndexName();
0452 
0453 private:
0454   StmtGeneratedVarNameMap *GeneratedDecls;
0455   const StmtParentMap *ReverseAST;
0456   const clang::Stmt *SourceStmt;
0457   const clang::VarDecl *OldIndex;
0458   const clang::ValueDecl *TheContainer;
0459   const clang::ASTContext *Context;
0460   const NamingStyle Style;
0461 
0462   // Determine whether or not a declaration that would conflict with Symbol
0463   // exists in an outer context or in any statement contained in SourceStmt.
0464   bool declarationExists(llvm::StringRef Symbol);
0465 };
0466 
0467 } // namespace clang::tidy::modernize
0468 
0469 #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_LOOP_CONVERT_UTILS_H