10 #include "clang/Basic/IdentifierTable.h"
11 #include "clang/Basic/LLVM.h"
12 #include "clang/Basic/Lambda.h"
13 #include "clang/Basic/SourceLocation.h"
14 #include "clang/Basic/SourceManager.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) {
172 E =
E->IgnoreImplicit();
173 if (
const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(
E)) {
176 if (ConstructExpr->getNumArgs() != 1 ||
177 ConstructExpr->getConstructionKind() != CXXConstructExpr::CK_Complete)
179 E = ConstructExpr->getArg(0);
180 if (
const auto *Temp = dyn_cast<MaterializeTemporaryExpr>(
E))
181 E = Temp->getSubExpr();
186 if (
const auto *ME = dyn_cast<CXXMemberCallExpr>(
E))
187 if (isa<CXXConversionDecl>(ME->getMethodDecl()))
193 bool areSameExpr(ASTContext *Context,
const Expr *First,
const Expr *Second) {
194 if (!First || !Second)
197 llvm::FoldingSetNodeID FirstID, SecondID;
198 First->Profile(FirstID, *Context,
true);
199 Second->Profile(SecondID, *Context,
true);
200 return FirstID == SecondID;
205 return dyn_cast<DeclRefExpr>(
E->IgnoreParenImpCasts());
210 return First && Second &&
211 First->getCanonicalDecl() == Second->getCanonicalDecl();
226 if (
const auto *Uop = dyn_cast<UnaryOperator>(
E))
227 return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() :
nullptr;
229 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(
E)) {
230 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
239 template <
typename ContainerT>
240 static bool containsExpr(ASTContext *Context,
const ContainerT *Container,
242 llvm::FoldingSetNodeID
ID;
243 E->Profile(
ID, *Context,
true);
244 for (
const auto &I : *Container) {
260 const VarDecl *IndexVar) {
261 const DeclRefExpr *Idx =
getDeclRef(IndexExpr);
262 return Idx && Idx->getType()->isIntegerType() &&
294 const VarDecl *IndexVar,
const Expr *
Obj,
295 const Expr *SourceExpr,
bool PermitDeref) {
299 if (
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
300 Obj->IgnoreParenImpCasts()))
304 if (PermitDeref &&
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
305 InnerObj->IgnoreParenImpCasts()))
320 const VarDecl *IndexVar) {
321 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 &&
333 const VarDecl *IndexVar) {
334 return Uop->getOpcode() == UO_Deref &&
356 const VarDecl *IndexVar) {
357 const auto *VDecl = dyn_cast<VarDecl>(
TheDecl);
360 if (!VDecl->hasInit())
363 bool OnlyCasts =
true;
364 const Expr *Init = VDecl->getInit()->IgnoreParenImpCasts();
365 if (isa_and_nonnull<CXXConstructExpr>(Init)) {
375 QualType InitType = Init->getType();
376 QualType DeclarationType = VDecl->getType();
377 if (!DeclarationType.isNull() && DeclarationType->isReferenceType())
378 DeclarationType = DeclarationType.getNonReferenceType();
380 if (InitType.isNull() || DeclarationType.isNull() ||
381 !Context->hasSameUnqualifiedType(DeclarationType, InitType))
385 switch (Init->getStmtClass()) {
386 case Stmt::ArraySubscriptExprClass: {
387 const auto *
E = cast<ArraySubscriptExpr>(Init);
393 case Stmt::UnaryOperatorClass:
396 case Stmt::CXXOperatorCallExprClass: {
397 const auto *OpCall = cast<CXXOperatorCallExpr>(Init);
398 if (OpCall->getOperator() == OO_Star)
400 if (OpCall->getOperator() == OO_Subscript) {
401 return OpCall->getNumArgs() == 2 &&
407 case Stmt::CXXMemberCallExprClass: {
408 const auto *MemCall = cast<CXXMemberCallExpr>(Init);
411 const auto *MDecl = MemCall->getMethodDecl();
412 if (MDecl && !isa<CXXConversionDecl>(MDecl) &&
413 MDecl->getNameAsString() ==
"at" && MemCall->getNumArgs() == 1) {
439 const QualType &ArrayType,
440 const Expr *ConditionExpr) {
441 if (!ConditionExpr || ConditionExpr->isValueDependent())
443 const ConstantArrayType *ConstType =
444 Context->getAsConstantArrayType(ArrayType);
447 Optional<llvm::APSInt> ConditionSize =
448 ConditionExpr->getIntegerConstantExpr(*Context);
451 llvm::APSInt ArraySize(ConstType->getSize());
452 return llvm::APSInt::isSameValue(*ConditionSize, ArraySize);
455 ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext *Context,
456 const VarDecl *IndexVar,
457 const VarDecl *EndVar,
458 const Expr *ContainerExpr,
459 const Expr *ArrayBoundExpr,
460 bool ContainerNeedsDereference)
461 : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
462 ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
463 ContainerNeedsDereference(ContainerNeedsDereference),
464 OnlyUsedAsIndex(true), AliasDecl(nullptr),
465 ConfidenceLevel(
Confidence::CL_Safe), NextStmtParent(nullptr),
466 CurrStmtParent(nullptr), ReplaceWithAliasUse(false),
467 AliasFromForInit(false) {
469 addComponent(ContainerExpr);
473 TraverseStmt(
const_cast<Stmt *
>(Body));
474 return OnlyUsedAsIndex && ContainerExpr;
479 for (
const auto &I : Components)
483 void ForLoopIndexUseVisitor::addComponent(
const Expr *
E) {
484 llvm::FoldingSetNodeID
ID;
485 const Expr *Node =
E->IgnoreParenImpCasts();
486 Node->Profile(
ID, *Context,
true);
487 DependentExprs.push_back(std::make_pair(Node,
ID));
491 SourceLocation Begin = U.
Range.getBegin();
492 if (Begin.isMacroID())
493 Begin = Context->getSourceManager().getSpellingLoc(Begin);
495 if (UsageLocations.insert(Begin).second)
510 bool ForLoopIndexUseVisitor::TraverseUnaryOperator(UnaryOperator *Uop) {
518 return VisitorBase::TraverseUnaryOperator(Uop);
546 bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
547 const Expr *
Base = Member->getBase();
549 const Expr *ResultExpr = Member;
551 if (
const auto *Call =
552 dyn_cast<CXXOperatorCallExpr>(
Base->IgnoreParenImpCasts())) {
560 if (Call->getOperator() == OO_Arrow) {
561 assert(Call->getNumArgs() == 1 &&
562 "Operator-> takes more than one argument");
565 ExprType = Call->getCallReturnType(*Context);
571 if (!Member->isArrow()) {
572 OnlyUsedAsIndex =
false;
576 if (ExprType.isNull())
577 ExprType =
Obj->getType();
579 if (!ExprType->isPointerType())
584 SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
585 Base->getExprLoc(), 0, Context->getSourceManager(),
586 Context->getLangOpts());
589 if (ArrowLoc.isValid()) {
591 SourceRange(
Base->getExprLoc(), ArrowLoc)));
595 return VisitorBase::TraverseMemberExpr(Member);
605 bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
606 CXXMemberCallExpr *MemberCall) {
608 dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
610 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
615 const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
616 if (Ident && Ident->isStr(
"at") && MemberCall->getNumArgs() == 1) {
618 Member->getBase(), ContainerExpr,
619 ContainerNeedsDereference)) {
625 if (
containsExpr(Context, &DependentExprs, Member->getBase()))
628 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
650 bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
651 CXXOperatorCallExpr *OpCall) {
652 switch (OpCall->getOperator()) {
661 if (OpCall->getNumArgs() != 2)
664 OpCall->getArg(0), ContainerExpr,
665 ContainerNeedsDereference)) {
674 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
696 bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *
E) {
697 Expr *Arr =
E->getBase();
699 return VisitorBase::TraverseArraySubscriptExpr(
E);
701 if ((ContainerExpr &&
703 ContainerExpr->IgnoreParenImpCasts())) ||
708 OnlyUsedAsIndex =
false;
709 return VisitorBase::TraverseArraySubscriptExpr(
E);
751 bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *
E) {
752 const ValueDecl *
TheDecl =
E->getDecl();
756 OnlyUsedAsIndex =
false;
784 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
785 const LambdaCapture *
C,
787 if (
C->capturesVariable()) {
788 const VarDecl *VDecl =
C->getCapturedVar();
799 return VisitorBase::TraverseLambdaCapture(LE,
C, Init);
806 bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
807 if (!AliasDecl && S->isSingleDecl() &&
808 isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
810 if (CurrStmtParent) {
811 if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
812 isa<SwitchStmt>(CurrStmtParent))
813 ReplaceWithAliasUse =
true;
814 else if (isa<ForStmt>(CurrStmtParent)) {
815 if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
816 ReplaceWithAliasUse =
true;
819 AliasFromForInit =
true;
827 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
832 if (
const auto *LE = dyn_cast_or_null<LambdaExpr>(NextStmtParent)) {
835 if (S != LE->getBody()) {
842 const Stmt *OldNextParent = NextStmtParent;
843 CurrStmtParent = NextStmtParent;
845 bool Result = VisitorBase::TraverseStmt(S);
846 NextStmtParent = OldNextParent;
854 std::string IteratorName;
855 StringRef ContainerName;
857 ContainerName = TheContainer->getName();
859 size_t Len = ContainerName.size();
860 if (Len > 1 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S" :
"s")) {
861 IteratorName = std::string(ContainerName.substr(0, Len - 1));
863 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
867 if (Len > 2 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S_" :
"s_")) {
868 IteratorName = std::string(ContainerName.substr(0, Len - 2));
870 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
874 return std::string(OldIndex->getName());
883 bool VariableNamer::declarationExists(StringRef Symbol) {
884 assert(Context !=
nullptr &&
"Expected an ASTContext");
885 IdentifierInfo &Ident = Context->Idents.get(Symbol);
888 if (!isAnyIdentifier(Ident.getTokenID()))
892 if (Ident.hasMacroDefinition())
896 for (
const Stmt *S = SourceStmt; S !=
nullptr; S = ReverseAST->lookup(S)) {
897 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
898 if (I != GeneratedDecls->end() && I->second == Symbol)
909 DeclFinderASTVisitor DeclFinder(std::string(Symbol), GeneratedDecls);
910 return DeclFinder.findUsages(SourceStmt);