File indexing completed on 2026-05-10 08:36:20
0001
0002
0003
0004
0005
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
0035 using StmtParentMap = llvm::DenseMap<const clang::Stmt *, const clang::Stmt *>;
0036
0037
0038
0039 using DeclParentMap =
0040 llvm::DenseMap<const clang::VarDecl *, const clang::DeclStmt *>;
0041
0042
0043
0044 using ReplacedVarsMap =
0045 llvm::DenseMap<const clang::ForStmt *, const clang::VarDecl *>;
0046
0047
0048 using StmtGeneratedVarNameMap =
0049 llvm::DenseMap<const clang::Stmt *, std::string>;
0050
0051
0052 using ComponentVector = llvm::SmallVector<const clang::Expr *, 16>;
0053
0054
0055
0056 class StmtAncestorASTVisitor
0057 : public clang::RecursiveASTVisitor<StmtAncestorASTVisitor> {
0058 public:
0059 StmtAncestorASTVisitor() { StmtStack.push_back(nullptr); }
0060
0061
0062
0063
0064 void gatherAncestors(ASTContext &Ctx) {
0065 if (StmtAncestors.empty())
0066 TraverseAST(Ctx);
0067 }
0068
0069
0070 const StmtParentMap &getStmtToParentStmtMap() { return StmtAncestors; }
0071
0072
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
0087
0088 class ComponentFinderASTVisitor
0089 : public clang::RecursiveASTVisitor<ComponentFinderASTVisitor> {
0090 public:
0091 ComponentFinderASTVisitor() = default;
0092
0093
0094 void findExprComponents(const clang::Expr *SourceExpr) {
0095 TraverseStmt(const_cast<clang::Expr *>(SourceExpr));
0096 }
0097
0098
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
0111
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
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
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
0172
0173
0174
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
0183
0184
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
0196
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
0207
0208 struct Usage {
0209 enum UsageKind {
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220 UK_Default,
0221
0222
0223 UK_MemberThroughArrow,
0224
0225
0226 UK_CaptureByCopy,
0227 UK_CaptureByRef
0228 };
0229
0230
0231 const Expr *Expression;
0232
0233 UsageKind Kind;
0234
0235
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
0245 class Confidence {
0246 public:
0247 enum Level {
0248
0249 CL_Risky,
0250
0251
0252 CL_Reasonable,
0253
0254
0255 CL_Safe
0256 };
0257
0258 explicit Confidence(Confidence::Level Level) : CurrentLevel(Level) {}
0259
0260
0261 void lowerTo(Confidence::Level Level) {
0262 CurrentLevel = std::min(Level, CurrentLevel);
0263 }
0264
0265
0266 Level getLevel() const { return CurrentLevel; }
0267
0268 private:
0269 Level CurrentLevel;
0270 };
0271
0272
0273 using UsageResult = llvm::SmallVector<Usage, 8>;
0274
0275
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
0282
0283
0284
0285
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
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305 bool findAndVerifyUsages(const Stmt *Body);
0306
0307
0308
0309 void addComponents(const ComponentVector &Components);
0310
0311
0312 const UsageResult &getUsages() const { return Usages; }
0313
0314
0315 void addUsage(const Usage &U);
0316
0317
0318 const Expr *getContainerIndexed() const { return ContainerExpr; }
0319
0320
0321
0322 const DeclStmt *getAliasDecl() const { return AliasDecl; }
0323
0324
0325 Confidence::Level getConfidenceLevel() const {
0326 return ConfidenceLevel.getLevel();
0327 }
0328
0329
0330
0331
0332
0333 bool aliasUseRequired() const { return ReplaceWithAliasUse; }
0334
0335
0336
0337
0338 bool aliasFromForInit() const { return AliasFromForInit; }
0339
0340 private:
0341
0342 using VisitorBase = RecursiveASTVisitor<ForLoopIndexUseVisitor>;
0343 friend class RecursiveASTVisitor<ForLoopIndexUseVisitor>;
0344
0345
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
0360
0361 void addComponent(const Expr *E);
0362
0363
0364 ASTContext *Context;
0365
0366 const VarDecl *IndexVar;
0367
0368 const VarDecl *EndVar;
0369
0370 const Expr *ContainerExpr;
0371
0372 const Expr *ArrayBoundExpr;
0373 bool ContainerNeedsDereference;
0374
0375
0376
0377
0378 UsageResult Usages;
0379 llvm::SmallSet<SourceLocation, 8> UsageLocations;
0380 bool OnlyUsedAsIndex = true;
0381
0382 const DeclStmt *AliasDecl = nullptr;
0383 Confidence ConfidenceLevel;
0384
0385
0386
0387
0388 llvm::SmallVector<std::pair<const Expr *, llvm::FoldingSetNodeID>, 16>
0389 DependentExprs;
0390
0391
0392
0393 const Stmt *NextStmtParent = nullptr;
0394
0395
0396
0397 const Stmt *CurrStmtParent = nullptr;
0398
0399
0400 bool ReplaceWithAliasUse = false;
0401
0402 bool AliasFromForInit = false;
0403 };
0404
0405 struct TUTrackingInfo {
0406
0407
0408
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
0422
0423
0424
0425
0426
0427 class VariableNamer {
0428 public:
0429
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
0447
0448
0449
0450
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
0463
0464 bool declarationExists(llvm::StringRef Symbol);
0465 };
0466
0467 }
0468
0469 #endif