11 #include "clang/Basic/IdentifierTable.h" 12 #include "clang/Basic/LLVM.h" 13 #include "clang/Basic/Lambda.h" 14 #include "clang/Basic/SourceManager.h" 15 #include "clang/Basic/SourceLocation.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" 40 bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) {
41 StmtAncestors.insert(std::make_pair(Statement, StmtStack.back()));
42 StmtStack.push_back(Statement);
43 RecursiveASTVisitor<StmtAncestorASTVisitor>::TraverseStmt(Statement);
53 bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Decls) {
54 for (
const auto *decl : Decls->decls()) {
55 if (
const auto *V = dyn_cast<VarDecl>(decl))
56 DeclParents.insert(std::make_pair(V, Decls));
62 bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
63 Components.push_back(E);
68 bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) {
69 Components.push_back(Member);
75 bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *
DeclRef) {
76 if (
auto *V = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
77 return VisitVarDecl(V);
82 bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl *V) {
83 const Stmt *Curr = DeclParents->lookup(V);
85 while (Curr !=
nullptr) {
86 if (Curr == ContainingStmt) {
87 DependsOnInsideVariable =
true;
90 Curr = StmtParents->lookup(Curr);
95 for (
const auto &I : *ReplacedVars) {
97 DependsOnInsideVariable =
true;
106 bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) {
107 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop);
108 if (I != GeneratedDecls->end() && I->second ==
Name) {
117 bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) {
118 const IdentifierInfo *Ident = D->getIdentifier();
119 if (Ident && Ident->getName() ==
Name) {
128 bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
129 if (
auto *D = dyn_cast<NamedDecl>(DeclRef->getDecl()))
130 return VisitNamedDecl(D);
136 bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) {
137 QualType QType = TL.getType();
140 if (QType.getAsString() ==
Name) {
147 if (
const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) {
148 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->GetTemporaryExpr();
188 bool areSameExpr(ASTContext *Context,
const Expr *First,
const Expr *Second) {
189 if (!First || !Second)
192 llvm::FoldingSetNodeID FirstID, SecondID;
193 First->Profile(FirstID, *Context,
true);
194 Second->Profile(SecondID, *Context,
true);
195 return FirstID == SecondID;
200 return dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
205 return First && Second &&
206 First->getCanonicalDecl() == Second->getCanonicalDecl();
221 if (
const auto *Uop = dyn_cast<UnaryOperator>(E))
222 return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() :
nullptr;
224 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
225 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
234 template <
typename ContainerT>
235 static bool containsExpr(ASTContext *Context,
const ContainerT *Container,
237 llvm::FoldingSetNodeID ID;
238 E->Profile(ID, *Context,
true);
239 for (
const auto &I : *Container) {
255 const VarDecl *IndexVar) {
256 const DeclRefExpr *Idx =
getDeclRef(IndexExpr);
257 return Idx && Idx->getType()->isIntegerType() &&
289 const VarDecl *IndexVar,
const Expr *Obj,
290 const Expr *SourceExpr,
bool PermitDeref) {
294 if (
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
295 Obj->IgnoreParenImpCasts()))
299 if (PermitDeref &&
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
300 InnerObj->IgnoreParenImpCasts()))
315 const VarDecl *IndexVar) {
316 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 &&
328 const VarDecl *IndexVar) {
329 return Uop->getOpcode() == UO_Deref &&
351 const VarDecl *IndexVar) {
352 const auto *VDecl = dyn_cast<VarDecl>(TheDecl);
355 if (!VDecl->hasInit())
358 bool OnlyCasts =
true;
359 const Expr *Init = VDecl->getInit()->IgnoreParenImpCasts();
360 if (Init && isa<CXXConstructExpr>(Init)) {
370 QualType InitType = Init->getType();
371 QualType DeclarationType = VDecl->getType();
372 if (!DeclarationType.isNull() && DeclarationType->isReferenceType())
373 DeclarationType = DeclarationType.getNonReferenceType();
375 if (InitType.isNull() || DeclarationType.isNull() ||
376 !Context->hasSameUnqualifiedType(DeclarationType, InitType))
380 switch (Init->getStmtClass()) {
381 case Stmt::ArraySubscriptExprClass: {
382 const auto *E = cast<ArraySubscriptExpr>(Init);
388 case Stmt::UnaryOperatorClass:
391 case Stmt::CXXOperatorCallExprClass: {
392 const auto *OpCall = cast<CXXOperatorCallExpr>(Init);
393 if (OpCall->getOperator() == OO_Star)
395 if (OpCall->getOperator() == OO_Subscript) {
396 assert(OpCall->getNumArgs() == 2);
402 case Stmt::CXXMemberCallExprClass: {
403 const auto *MemCall = cast<CXXMemberCallExpr>(Init);
406 const auto *MDecl = MemCall->getMethodDecl();
407 if (MDecl && !isa<CXXConversionDecl>(MDecl) &&
408 MDecl->getNameAsString() ==
"at" && MemCall->getNumArgs() == 1) {
434 const QualType &ArrayType,
435 const Expr *ConditionExpr) {
436 if (!ConditionExpr || ConditionExpr->isValueDependent())
438 const ConstantArrayType *ConstType =
439 Context->getAsConstantArrayType(ArrayType);
442 llvm::APSInt ConditionSize;
443 if (!ConditionExpr->isIntegerConstantExpr(ConditionSize, *Context))
445 llvm::APSInt ArraySize(ConstType->getSize());
446 return llvm::APSInt::isSameValue(ConditionSize, ArraySize);
449 ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext *Context,
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),
458 OnlyUsedAsIndex(true), AliasDecl(nullptr),
459 ConfidenceLevel(
Confidence::CL_Safe), NextStmtParent(nullptr),
460 CurrStmtParent(nullptr), ReplaceWithAliasUse(false),
461 AliasFromForInit(false) {
463 addComponent(ContainerExpr);
467 TraverseStmt(const_cast<Stmt *>(Body));
468 return OnlyUsedAsIndex && ContainerExpr;
473 for (
const auto &I : Components)
477 void ForLoopIndexUseVisitor::addComponent(
const Expr *E) {
478 llvm::FoldingSetNodeID ID;
479 const Expr *Node = E->IgnoreParenImpCasts();
480 Node->Profile(ID, *Context,
true);
481 DependentExprs.push_back(std::make_pair(Node, ID));
485 SourceLocation Begin = U.
Range.getBegin();
486 if (Begin.isMacroID())
487 Begin = Context->getSourceManager().getSpellingLoc(Begin);
489 if (UsageLocations.insert(Begin).second)
504 bool ForLoopIndexUseVisitor::TraverseUnaryDeref(UnaryOperator *Uop) {
512 return VisitorBase::TraverseUnaryOperator(Uop);
540 bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
541 const Expr *Base = Member->getBase();
543 const Expr *ResultExpr = Member;
545 if (
const auto *Call =
546 dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
554 if (Call->getOperator() == OO_Arrow) {
555 assert(Call->getNumArgs() == 1 &&
556 "Operator-> takes more than one argument");
559 ExprType = Call->getCallReturnType(*Context);
565 if (!Member->isArrow()) {
566 OnlyUsedAsIndex =
false;
570 if (ExprType.isNull())
571 ExprType = Obj->getType();
573 if (!ExprType->isPointerType())
578 SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
579 Base->getExprLoc(), 0, Context->getSourceManager(),
580 Context->getLangOpts());
583 if (ArrowLoc.isValid()) {
585 SourceRange(Base->getExprLoc(), ArrowLoc)));
589 return VisitorBase::TraverseMemberExpr(Member);
599 bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
600 CXXMemberCallExpr *MemberCall) {
602 dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
604 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
609 const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
610 if (Ident && Ident->isStr(
"at") && MemberCall->getNumArgs() == 1) {
612 Member->getBase(), ContainerExpr,
613 ContainerNeedsDereference)) {
619 if (
containsExpr(Context, &DependentExprs, Member->getBase()))
622 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
644 bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
645 CXXOperatorCallExpr *OpCall) {
646 switch (OpCall->getOperator()) {
655 if (OpCall->getNumArgs() != 2)
658 OpCall->getArg(0), ContainerExpr,
659 ContainerNeedsDereference)) {
668 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
690 bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *E) {
691 Expr *Arr = E->getBase();
693 return VisitorBase::TraverseArraySubscriptExpr(E);
695 if ((ContainerExpr &&
697 ContainerExpr->IgnoreParenImpCasts())) ||
702 OnlyUsedAsIndex =
false;
703 return VisitorBase::TraverseArraySubscriptExpr(E);
745 bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
746 const ValueDecl *TheDecl = E->getDecl();
750 OnlyUsedAsIndex =
false;
778 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
779 const LambdaCapture *C,
781 if (C->capturesVariable()) {
782 const VarDecl *VDecl = C->getCapturedVar();
793 return VisitorBase::TraverseLambdaCapture(LE, C, Init);
800 bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
801 if (!AliasDecl && S->isSingleDecl() &&
802 isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
804 if (CurrStmtParent) {
805 if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
806 isa<SwitchStmt>(CurrStmtParent))
807 ReplaceWithAliasUse =
true;
808 else if (isa<ForStmt>(CurrStmtParent)) {
809 if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
810 ReplaceWithAliasUse =
true;
813 AliasFromForInit =
true;
821 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
826 if (
const auto *LE = dyn_cast_or_null<LambdaExpr>(NextStmtParent)) {
829 if (S != LE->getBody()) {
836 const Stmt *OldNextParent = NextStmtParent;
837 CurrStmtParent = NextStmtParent;
839 bool Result = VisitorBase::TraverseStmt(S);
840 NextStmtParent = OldNextParent;
848 std::string IteratorName;
849 StringRef ContainerName;
851 ContainerName = TheContainer->getName();
853 size_t Len = ContainerName.size();
854 if (Len > 1 && ContainerName.endswith(Style == NS_UpperCase ?
"S" :
"s")) {
855 IteratorName = ContainerName.substr(0, Len - 1);
857 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
861 if (Len > 2 && ContainerName.endswith(Style == NS_UpperCase ?
"S_" :
"s_")) {
862 IteratorName = ContainerName.substr(0, Len - 2);
864 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
868 return OldIndex->getName();
877 bool VariableNamer::declarationExists(StringRef Symbol) {
878 assert(Context !=
nullptr &&
"Expected an ASTContext");
879 IdentifierInfo &Ident = Context->Idents.get(Symbol);
882 if (!isAnyIdentifier(Ident.getTokenID()))
886 if (Ident.hasMacroDefinition())
890 for (
const Stmt *S = SourceStmt; S !=
nullptr; S = ReverseAST->lookup(S)) {
891 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
892 if (I != GeneratedDecls->end() && I->second == Symbol)
bool findUsages(const clang::Stmt *Body)
Attempts to find any usages of variables name Name in Body, returning true when it is used in Body...
static const Expr * getDereferenceOperand(const Expr *E)
If the expression is a dereference or call to operator*(), return the operand.
void addUsage(const Usage &U)
Adds the Usage if it was not added before.
A class to encapsulate lowering of the tool's confidence level.
llvm::SmallVector< const clang::Expr *, 16 > ComponentVector
A vector used to store the AST subtrees of an Expr.
const Expr * digThroughConstructors(const Expr *E)
Look through conversion/copy constructors to find the explicit initialization expression, returning it is found.
const DeclRefExpr * getDeclRef(const Expr *E)
Returns the DeclRefExpr represented by E, or NULL if there isn't one.
std::string createIndexName()
Generate a new index name.
bool areSameVariable(const ValueDecl *First, const ValueDecl *Second)
Returns true when two ValueDecls are the same variable.
static bool isDereferenceOfOpCall(const CXXOperatorCallExpr *OpCall, const VarDecl *IndexVar)
Returns true when Opcall is a call a one-parameter dereference of IndexVar.
static bool isIndexInSubscriptExpr(const Expr *IndexExpr, const VarDecl *IndexVar)
Returns true when the index expression is a declaration reference to IndexVar.
bool areSameExpr(ASTContext *Context, const Expr *First, const Expr *Second)
Returns true when two Exprs are equivalent.
static bool exprReferencesVariable(const ValueDecl *Target, const Expr *E)
Determines if an expression is a declaration reference to a particular variable.
bool findAndVerifyUsages(const Stmt *Body)
Finds all uses of IndexVar in Body, placing all usages in Usages, and returns true if IndexVar was on...
The information needed to describe a valid convertible usage of an array index or iterator...
static bool isDereferenceOfUop(const UnaryOperator *Uop, const VarDecl *IndexVar)
Returns true when Uop is a dereference of IndexVar.
void addComponents(const ComponentVector &Components)
Add a set of components that we should consider relevant to the container.
void lowerTo(Confidence::Level Level)
Lower the internal confidence level to Level, but do not raise it.
static bool isIndexInSubscriptExpr(ASTContext *Context, const Expr *IndexExpr, const VarDecl *IndexVar, const Expr *Obj, const Expr *SourceExpr, bool PermitDeref)
Returns true when the index expression is a declaration reference to IndexVar, Obj is the same expres...
Class used to determine if any declarations used in a Stmt would conflict with a particular identifie...
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 containsExpr(ASTContext *Context, const ContainerT *Container, const Expr *E)
Returns true when the Container contains an Expr equivalent to E.
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...
const DeclRefExpr * DeclRef