10 #include "clang/Basic/IdentifierTable.h"
11 #include "clang/Basic/LLVM.h"
12 #include "clang/Basic/Lambda.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/TokenKinds.h"
16 #include "clang/Lex/Lexer.h"
17 #include "llvm/ADT/APSInt.h"
18 #include "llvm/ADT/FoldingSet.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/Casting.h"
39 bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) {
40 StmtAncestors.insert(std::make_pair(Statement, StmtStack.back()));
41 StmtStack.push_back(Statement);
42 RecursiveASTVisitor<StmtAncestorASTVisitor>::TraverseStmt(Statement);
52 bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Decls) {
53 for (
const auto *decl : Decls->decls()) {
54 if (
const auto *V = dyn_cast<VarDecl>(decl))
55 DeclParents.insert(std::make_pair(V, Decls));
61 bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
E) {
62 Components.push_back(
E);
67 bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) {
68 Components.push_back(Member);
74 bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
75 if (
auto *V = dyn_cast_or_null<VarDecl>(
DeclRef->getDecl()))
76 return VisitVarDecl(V);
81 bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl *V) {
82 const Stmt *Curr = DeclParents->lookup(V);
84 while (Curr !=
nullptr) {
85 if (Curr == ContainingStmt) {
86 DependsOnInsideVariable =
true;
89 Curr = StmtParents->lookup(Curr);
94 for (
const auto &I : *ReplacedVars) {
96 DependsOnInsideVariable =
true;
105 bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) {
106 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop);
107 if (I != GeneratedDecls->end() && I->second ==
Name) {
116 bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) {
117 const IdentifierInfo *Ident = D->getIdentifier();
118 if (Ident && Ident->getName() ==
Name) {
127 bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
128 if (
auto *D = dyn_cast<NamedDecl>(
DeclRef->getDecl()))
129 return VisitNamedDecl(D);
135 bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) {
136 QualType QType = TL.getType();
139 if (QType.getAsString() ==
Name) {
146 if (
const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) {
147 if (Ident->getName() ==
Name) {
171 E =
E->IgnoreImplicit();
172 if (
const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(
E)) {
175 if (ConstructExpr->getNumArgs() != 1 ||
176 ConstructExpr->getConstructionKind() != CXXConstructExpr::CK_Complete)
178 E = ConstructExpr->getArg(0);
179 if (
const auto *Temp = dyn_cast<MaterializeTemporaryExpr>(
E))
180 E = Temp->getSubExpr();
187 bool areSameExpr(ASTContext *Context,
const Expr *First,
const Expr *Second) {
188 if (!First || !Second)
191 llvm::FoldingSetNodeID FirstID, SecondID;
192 First->Profile(FirstID, *Context,
true);
193 Second->Profile(SecondID, *Context,
true);
194 return FirstID == SecondID;
199 return dyn_cast<DeclRefExpr>(
E->IgnoreParenImpCasts());
204 return First && Second &&
205 First->getCanonicalDecl() == Second->getCanonicalDecl();
220 if (
const auto *Uop = dyn_cast<UnaryOperator>(
E))
221 return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() :
nullptr;
223 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(
E)) {
224 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
233 template <
typename ContainerT>
234 static bool containsExpr(ASTContext *Context,
const ContainerT *Container,
236 llvm::FoldingSetNodeID ID;
237 E->Profile(ID, *Context,
true);
238 for (
const auto &I : *Container) {
254 const VarDecl *IndexVar) {
255 const DeclRefExpr *Idx =
getDeclRef(IndexExpr);
256 return Idx && Idx->getType()->isIntegerType() &&
288 const VarDecl *IndexVar,
const Expr *
Obj,
289 const Expr *SourceExpr,
bool PermitDeref) {
293 if (
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
294 Obj->IgnoreParenImpCasts()))
298 if (PermitDeref &&
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
299 InnerObj->IgnoreParenImpCasts()))
314 const VarDecl *IndexVar) {
315 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 &&
327 const VarDecl *IndexVar) {
328 return Uop->getOpcode() == UO_Deref &&
350 const VarDecl *IndexVar) {
351 const auto *VDecl = dyn_cast<VarDecl>(
TheDecl);
354 if (!VDecl->hasInit())
357 bool OnlyCasts =
true;
358 const Expr *Init = VDecl->getInit()->IgnoreParenImpCasts();
359 if (Init && isa<CXXConstructExpr>(Init)) {
369 QualType InitType = Init->getType();
370 QualType DeclarationType = VDecl->getType();
371 if (!DeclarationType.isNull() && DeclarationType->isReferenceType())
372 DeclarationType = DeclarationType.getNonReferenceType();
374 if (InitType.isNull() || DeclarationType.isNull() ||
375 !Context->hasSameUnqualifiedType(DeclarationType, InitType))
379 switch (Init->getStmtClass()) {
380 case Stmt::ArraySubscriptExprClass: {
381 const auto *
E = cast<ArraySubscriptExpr>(Init);
387 case Stmt::UnaryOperatorClass:
390 case Stmt::CXXOperatorCallExprClass: {
391 const auto *OpCall = cast<CXXOperatorCallExpr>(Init);
392 if (OpCall->getOperator() == OO_Star)
394 if (OpCall->getOperator() == OO_Subscript) {
395 assert(OpCall->getNumArgs() == 2);
401 case Stmt::CXXMemberCallExprClass: {
402 const auto *MemCall = cast<CXXMemberCallExpr>(Init);
405 const auto *MDecl = MemCall->getMethodDecl();
406 if (MDecl && !isa<CXXConversionDecl>(MDecl) &&
407 MDecl->getNameAsString() ==
"at" && MemCall->getNumArgs() == 1) {
433 const QualType &ArrayType,
434 const Expr *ConditionExpr) {
435 if (!ConditionExpr || ConditionExpr->isValueDependent())
437 const ConstantArrayType *ConstType =
438 Context->getAsConstantArrayType(ArrayType);
441 llvm::APSInt ConditionSize;
442 if (!ConditionExpr->isIntegerConstantExpr(ConditionSize, *Context))
444 llvm::APSInt ArraySize(ConstType->getSize());
445 return llvm::APSInt::isSameValue(ConditionSize, ArraySize);
448 ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext *Context,
449 const VarDecl *IndexVar,
450 const VarDecl *EndVar,
451 const Expr *ContainerExpr,
452 const Expr *ArrayBoundExpr,
453 bool ContainerNeedsDereference)
454 : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
455 ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
456 ContainerNeedsDereference(ContainerNeedsDereference),
457 OnlyUsedAsIndex(true), AliasDecl(nullptr),
458 ConfidenceLevel(
Confidence::CL_Safe), NextStmtParent(nullptr),
459 CurrStmtParent(nullptr), ReplaceWithAliasUse(false),
460 AliasFromForInit(false) {
462 addComponent(ContainerExpr);
466 TraverseStmt(const_cast<Stmt *>(Body));
467 return OnlyUsedAsIndex && ContainerExpr;
472 for (
const auto &I : Components)
476 void ForLoopIndexUseVisitor::addComponent(
const Expr *
E) {
477 llvm::FoldingSetNodeID ID;
478 const Expr *Node =
E->IgnoreParenImpCasts();
479 Node->Profile(ID, *Context,
true);
480 DependentExprs.push_back(std::make_pair(Node, ID));
484 SourceLocation Begin = U.
Range.getBegin();
485 if (Begin.isMacroID())
486 Begin = Context->getSourceManager().getSpellingLoc(Begin);
488 if (UsageLocations.insert(Begin).second)
503 bool ForLoopIndexUseVisitor::TraverseUnaryOperator(UnaryOperator *Uop) {
511 return VisitorBase::TraverseUnaryOperator(Uop);
539 bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
540 const Expr *
Base = Member->getBase();
542 const Expr *ResultExpr = Member;
544 if (
const auto *Call =
545 dyn_cast<CXXOperatorCallExpr>(
Base->IgnoreParenImpCasts())) {
553 if (Call->getOperator() == OO_Arrow) {
554 assert(Call->getNumArgs() == 1 &&
555 "Operator-> takes more than one argument");
558 ExprType = Call->getCallReturnType(*Context);
564 if (!Member->isArrow()) {
565 OnlyUsedAsIndex =
false;
569 if (ExprType.isNull())
570 ExprType =
Obj->getType();
572 if (!ExprType->isPointerType())
577 SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
578 Base->getExprLoc(), 0, Context->getSourceManager(),
579 Context->getLangOpts());
582 if (ArrowLoc.isValid()) {
584 SourceRange(
Base->getExprLoc(), ArrowLoc)));
588 return VisitorBase::TraverseMemberExpr(Member);
598 bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
599 CXXMemberCallExpr *MemberCall) {
601 dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
603 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
608 const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
609 if (Ident && Ident->isStr(
"at") && MemberCall->getNumArgs() == 1) {
611 Member->getBase(), ContainerExpr,
612 ContainerNeedsDereference)) {
618 if (
containsExpr(Context, &DependentExprs, Member->getBase()))
621 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
643 bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
644 CXXOperatorCallExpr *OpCall) {
645 switch (OpCall->getOperator()) {
654 if (OpCall->getNumArgs() != 2)
657 OpCall->getArg(0), ContainerExpr,
658 ContainerNeedsDereference)) {
667 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
689 bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *
E) {
690 Expr *Arr =
E->getBase();
692 return VisitorBase::TraverseArraySubscriptExpr(
E);
694 if ((ContainerExpr &&
696 ContainerExpr->IgnoreParenImpCasts())) ||
701 OnlyUsedAsIndex =
false;
702 return VisitorBase::TraverseArraySubscriptExpr(
E);
744 bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *
E) {
745 const ValueDecl *
TheDecl =
E->getDecl();
749 OnlyUsedAsIndex =
false;
777 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
778 const LambdaCapture *C,
780 if (C->capturesVariable()) {
781 const VarDecl *VDecl = C->getCapturedVar();
792 return VisitorBase::TraverseLambdaCapture(LE, C, Init);
799 bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
800 if (!AliasDecl && S->isSingleDecl() &&
801 isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
803 if (CurrStmtParent) {
804 if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
805 isa<SwitchStmt>(CurrStmtParent))
806 ReplaceWithAliasUse =
true;
807 else if (isa<ForStmt>(CurrStmtParent)) {
808 if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
809 ReplaceWithAliasUse =
true;
812 AliasFromForInit =
true;
820 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
825 if (
const auto *LE = dyn_cast_or_null<LambdaExpr>(NextStmtParent)) {
828 if (S != LE->getBody()) {
835 const Stmt *OldNextParent = NextStmtParent;
836 CurrStmtParent = NextStmtParent;
838 bool Result = VisitorBase::TraverseStmt(S);
839 NextStmtParent = OldNextParent;
847 std::string IteratorName;
848 StringRef ContainerName;
850 ContainerName = TheContainer->getName();
852 size_t Len = ContainerName.size();
853 if (Len > 1 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S" :
"s")) {
854 IteratorName = std::string(ContainerName.substr(0, Len - 1));
856 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
860 if (Len > 2 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S_" :
"s_")) {
861 IteratorName = std::string(ContainerName.substr(0, Len - 2));
863 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
867 return std::string(OldIndex->getName());
876 bool VariableNamer::declarationExists(StringRef Symbol) {
877 assert(Context !=
nullptr &&
"Expected an ASTContext");
878 IdentifierInfo &Ident = Context->Idents.get(Symbol);
881 if (!isAnyIdentifier(Ident.getTokenID()))
885 if (Ident.hasMacroDefinition())
889 for (
const Stmt *S = SourceStmt; S !=
nullptr; S = ReverseAST->lookup(S)) {
890 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
891 if (I != GeneratedDecls->end() && I->second == Symbol)
902 DeclFinderASTVisitor DeclFinder(std::string(Symbol), GeneratedDecls);
903 return DeclFinder.findUsages(SourceStmt);