10#include "../utils/ASTUtils.h"
11#include "clang/Basic/IdentifierTable.h"
12#include "clang/Basic/LLVM.h"
13#include "clang/Basic/Lambda.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Basic/SourceManager.h"
16#include "clang/Basic/TokenKinds.h"
17#include "clang/Lex/Lexer.h"
18#include "llvm/ADT/APSInt.h"
19#include "llvm/ADT/FoldingSet.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Casting.h"
39bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) {
40 StmtAncestors.insert(std::make_pair(Statement, StmtStack.back()));
41 StmtStack.push_back(Statement);
52bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Statement) {
53 for (
const auto *
Decl : Statement->decls()) {
54 if (
const auto *V = dyn_cast<VarDecl>(
Decl))
55 DeclParents.insert(std::make_pair(V, Statement));
61bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
E) {
62 Components.push_back(
E);
67bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) {
68 Components.push_back(Member);
74bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
75 if (
auto *V = dyn_cast_or_null<VarDecl>(
DeclRef->getDecl()))
76 return VisitVarDecl(V);
81bool 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;
105bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) {
106 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop);
107 if (I != GeneratedDecls->end() && I->second == Name) {
116bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) {
117 const IdentifierInfo *Ident = D->getIdentifier();
118 if (Ident && Ident->getName() == Name) {
127bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
128 if (
auto *D = dyn_cast<NamedDecl>(
DeclRef->getDecl()))
129 return VisitNamedDecl(D);
135bool 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() != CXXConstructionKind::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()))
193bool areSameExpr(ASTContext *Context,
const Expr *First,
const Expr *Second) {
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
233template <
typename ContainerT>
234static bool containsExpr(ASTContext *Context,
const ContainerT *Container,
236 llvm::FoldingSetNodeID
ID;
237 E->Profile(
ID, *Context,
true);
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 (isa_and_nonnull<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 return 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 std::optional<llvm::APSInt> ConditionSize =
442 ConditionExpr->getIntegerConstantExpr(*Context);
445 llvm::APSInt ArraySize(ConstType->getSize());
446 return llvm::APSInt::isSameValue(*ConditionSize, ArraySize);
450 const VarDecl *IndexVar,
451 const VarDecl *EndVar,
452 const Expr *ContainerExpr,
453 const Expr *ArrayBoundExpr,
454 bool ContainerNeedsDereference)
455 : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
456 ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
457 ContainerNeedsDereference(ContainerNeedsDereference),
461 addComponent(ContainerExpr);
465 TraverseStmt(
const_cast<Stmt *
>(Body));
466 return OnlyUsedAsIndex && ContainerExpr;
471 for (
const auto &I : Components)
475void ForLoopIndexUseVisitor::addComponent(
const Expr *
E) {
476 llvm::FoldingSetNodeID
ID;
477 const Expr *
Node =
E->IgnoreParenImpCasts();
478 Node->Profile(
ID, *Context,
true);
479 DependentExprs.push_back(std::make_pair(Node,
ID));
483 SourceLocation Begin = U.
Range.getBegin();
484 if (Begin.isMacroID())
485 Begin = Context->getSourceManager().getSpellingLoc(Begin);
487 if (UsageLocations.insert(Begin).second)
502bool ForLoopIndexUseVisitor::TraverseUnaryOperator(UnaryOperator *Uop) {
510 return VisitorBase::TraverseUnaryOperator(Uop);
538bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
539 const Expr *Base = Member->getBase();
541 const Expr *ResultExpr = Member;
543 if (
const auto *Call =
544 dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
552 if (Call->getOperator() == OO_Arrow) {
553 assert(Call->getNumArgs() == 1 &&
554 "Operator-> takes more than one argument");
557 ExprType = Call->getCallReturnType(*Context);
563 if (!Member->isArrow()) {
564 OnlyUsedAsIndex =
false;
568 if (ExprType.isNull())
569 ExprType =
Obj->getType();
571 if (!ExprType->isPointerType())
576 SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
577 Base->getExprLoc(), 0, Context->getSourceManager(),
578 Context->getLangOpts());
581 if (ArrowLoc.isValid()) {
583 SourceRange(Base->getExprLoc(), ArrowLoc)));
587 return VisitorBase::TraverseMemberExpr(Member);
597bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
598 CXXMemberCallExpr *MemberCall) {
600 dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
602 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
607 const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
608 if (Ident && Ident->isStr(
"at") && MemberCall->getNumArgs() == 1) {
610 Member->getBase(), ContainerExpr,
611 ContainerNeedsDereference)) {
617 if (
containsExpr(Context, &DependentExprs, Member->getBase()))
620 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
642bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
643 CXXOperatorCallExpr *OpCall) {
644 switch (OpCall->getOperator()) {
653 if (OpCall->getNumArgs() != 2)
656 OpCall->getArg(0), ContainerExpr,
657 ContainerNeedsDereference)) {
666 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
688bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *
E) {
689 Expr *Arr =
E->getBase();
691 return VisitorBase::TraverseArraySubscriptExpr(
E);
693 if ((ContainerExpr &&
695 ContainerExpr->IgnoreParenImpCasts())) ||
700 OnlyUsedAsIndex =
false;
701 return VisitorBase::TraverseArraySubscriptExpr(
E);
743bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *
E) {
744 const ValueDecl *
TheDecl =
E->getDecl();
748 OnlyUsedAsIndex =
false;
776bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
777 const LambdaCapture *
C,
779 if (
C->capturesVariable()) {
780 const ValueDecl *VDecl =
C->getCapturedVar();
791 return VisitorBase::TraverseLambdaCapture(LE,
C, Init);
798bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
799 if (!AliasDecl && S->isSingleDecl() &&
800 isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
802 if (CurrStmtParent) {
803 if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
804 isa<SwitchStmt>(CurrStmtParent))
805 ReplaceWithAliasUse =
true;
806 else if (isa<ForStmt>(CurrStmtParent)) {
807 if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
808 ReplaceWithAliasUse =
true;
811 AliasFromForInit =
true;
819bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
824 if (
const auto *LE = dyn_cast_or_null<LambdaExpr>(NextStmtParent)) {
827 if (S != LE->getBody()) {
834 const Stmt *OldNextParent = NextStmtParent;
835 CurrStmtParent = NextStmtParent;
837 bool Result = VisitorBase::TraverseStmt(S);
838 NextStmtParent = OldNextParent;
846 std::string IteratorName;
847 StringRef ContainerName;
849 ContainerName = TheContainer->getName();
851 size_t Len = ContainerName.size();
852 if (Len > 1 && ContainerName.ends_with(Style ==
NS_UpperCase ?
"S" :
"s")) {
853 IteratorName = std::string(ContainerName.substr(0, Len - 1));
855 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
859 if (Len > 2 && ContainerName.ends_with(Style ==
NS_UpperCase ?
"S_" :
"s_")) {
860 IteratorName = std::string(ContainerName.substr(0, Len - 2));
862 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
866 return std::string(OldIndex->getName());
875bool VariableNamer::declarationExists(StringRef Symbol) {
876 assert(Context !=
nullptr &&
"Expected an ASTContext");
877 IdentifierInfo &Ident = Context->Idents.get(Symbol);
880 if (!isAnyIdentifier(Ident.getTokenID()))
884 if (Ident.hasMacroDefinition())
888 for (
const Stmt *S = SourceStmt; S !=
nullptr; S = ReverseAST->lookup(S)) {
889 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
890 if (I != GeneratedDecls->end() && I->second == Symbol)
901 DeclFinderASTVisitor DeclFinder(std::string(Symbol), GeneratedDecls);
902 return DeclFinder.findUsages(SourceStmt);
const FunctionDecl * Decl
::clang::DynTypedNode Node
const DeclRefExpr * DeclRef
A class to encapsulate lowering of the tool's confidence level.
void lowerTo(Confidence::Level Level)
Lower the internal confidence level to Level, but do not raise it.
ForLoopIndexUseVisitor(ASTContext *Context, const VarDecl *IndexVar, const VarDecl *EndVar, const Expr *ContainerExpr, const Expr *ArrayBoundExpr, bool ContainerNeedsDereference)
bool findAndVerifyUsages(const Stmt *Body)
Finds all uses of IndexVar in Body, placing all usages in Usages, and returns true if IndexVar was on...
void addUsage(const Usage &U)
Adds the Usage if it was not added before.
void addComponents(const ComponentVector &Components)
Add a set of components that we should consider relevant to the container.
std::string createIndexName()
Generate a new index name.
static bool arrayMatchesBoundExpr(ASTContext *Context, const QualType &ArrayType, const Expr *ConditionExpr)
Determines whether the bound of a for loop condition expression is the same as the statically computa...
static bool containsExpr(ASTContext *Context, const ContainerT *Container, const Expr *E)
Returns true when the Container contains an Expr equivalent to E.
const DeclRefExpr * getDeclRef(const Expr *E)
Returns the DeclRefExpr represented by E, or NULL if there isn't one.
static bool exprReferencesVariable(const ValueDecl *Target, const Expr *E)
Determines if an expression is a declaration reference to a particular variable.
bool areSameVariable(const ValueDecl *First, const ValueDecl *Second)
Returns true when two ValueDecls are the same variable.
static const Expr * getDereferenceOperand(const Expr *E)
If the expression is a dereference or call to operator*(), return the operand.
const Expr * digThroughConstructorsConversions(const Expr *E)
Look through conversion/copy constructors and member functions to find the explicit initialization ex...
static bool isAliasDecl(ASTContext *Context, const Decl *TheDecl, const VarDecl *IndexVar)
Determines whether the given Decl defines a variable initialized to the loop object.
static bool isIndexInSubscriptExpr(const Expr *IndexExpr, const VarDecl *IndexVar)
Returns true when the index expression is a declaration reference to IndexVar.
static bool isDereferenceOfOpCall(const CXXOperatorCallExpr *OpCall, const VarDecl *IndexVar)
Returns true when Opcall is a call a one-parameter dereference of IndexVar.
bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second)
Returns true when two Exprs are equivalent.
llvm::SmallVector< const clang::Expr *, 16 > ComponentVector
A vector used to store the AST subtrees of an Expr.
static bool isDereferenceOfUop(const UnaryOperator *Uop, const VarDecl *IndexVar)
Returns true when Uop is a dereference of IndexVar.
bool areStatementsIdentical(const Stmt *FirstStmt, const Stmt *SecondStmt, const ASTContext &Context, bool Canonical)
The information needed to describe a valid convertible usage of an array index or iterator.