12 using namespace clang::ast_matchers;
13 using namespace clang::tooling;
14 using namespace clang;
27 bool StmtAncestorASTVisitor::TraverseStmt(Stmt *Statement) {
28 StmtAncestors.insert(std::make_pair(Statement, StmtStack.back()));
29 StmtStack.push_back(Statement);
30 RecursiveASTVisitor<StmtAncestorASTVisitor>::TraverseStmt(Statement);
40 bool StmtAncestorASTVisitor::VisitDeclStmt(DeclStmt *Decls) {
41 for (
const auto *decl : Decls->decls()) {
42 if (
const auto *V = dyn_cast<VarDecl>(decl))
43 DeclParents.insert(std::make_pair(V, Decls));
49 bool ComponentFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
50 Components.push_back(E);
55 bool ComponentFinderASTVisitor::VisitMemberExpr(MemberExpr *Member) {
56 Components.push_back(Member);
62 bool DependencyFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
63 if (
auto *V = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
64 return VisitVarDecl(V);
69 bool DependencyFinderASTVisitor::VisitVarDecl(VarDecl *V) {
70 const Stmt *Curr = DeclParents->lookup(V);
72 while (Curr !=
nullptr) {
73 if (Curr == ContainingStmt) {
74 DependsOnInsideVariable =
true;
77 Curr = StmtParents->lookup(Curr);
82 for (
const auto &I : *ReplacedVars) {
84 DependsOnInsideVariable =
true;
93 bool DeclFinderASTVisitor::VisitForStmt(ForStmt *TheLoop) {
94 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(TheLoop);
95 if (I != GeneratedDecls->end() && I->second ==
Name) {
104 bool DeclFinderASTVisitor::VisitNamedDecl(NamedDecl *D) {
105 const IdentifierInfo *Ident = D->getIdentifier();
106 if (Ident && Ident->getName() ==
Name) {
115 bool DeclFinderASTVisitor::VisitDeclRefExpr(DeclRefExpr *DeclRef) {
116 if (
auto *D = dyn_cast<NamedDecl>(DeclRef->getDecl()))
117 return VisitNamedDecl(D);
123 bool DeclFinderASTVisitor::VisitTypeLoc(TypeLoc TL) {
124 QualType QType = TL.getType();
127 if (QType.getAsString() ==
Name) {
134 if (
const IdentifierInfo *Ident = QType.getBaseTypeIdentifier()) {
135 if (Ident->getName() ==
Name) {
159 E = E->IgnoreParenImpCasts();
160 if (
const auto *ConstructExpr = dyn_cast<CXXConstructExpr>(E)) {
163 if (ConstructExpr->getNumArgs() != 1 ||
164 ConstructExpr->getConstructionKind() != CXXConstructExpr::CK_Complete)
166 E = ConstructExpr->getArg(0);
167 if (
const auto *Temp = dyn_cast<MaterializeTemporaryExpr>(E))
168 E = Temp->GetTemporaryExpr();
176 if (!First || !Second)
179 llvm::FoldingSetNodeID FirstID, SecondID;
180 First->Profile(FirstID, *Context,
true);
181 Second->Profile(SecondID, *Context,
true);
182 return FirstID == SecondID;
187 return dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts());
192 return First && Second &&
193 First->getCanonicalDecl() == Second->getCanonicalDecl();
208 if (
const auto *Uop = dyn_cast<UnaryOperator>(E))
209 return Uop->getOpcode() == UO_Deref ? Uop->getSubExpr() :
nullptr;
211 if (
const auto *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
212 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1
221 template <
typename ContainerT>
224 llvm::FoldingSetNodeID ID;
225 E->Profile(ID, *Context,
true);
226 for (
const auto &I : *Container) {
242 const VarDecl *IndexVar) {
243 const DeclRefExpr *Idx =
getDeclRef(IndexExpr);
244 return Idx && Idx->getType()->isIntegerType() &&
276 const VarDecl *IndexVar,
const Expr *Obj,
277 const Expr *SourceExpr,
bool PermitDeref) {
281 if (
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
282 Obj->IgnoreParenImpCasts()))
286 if (PermitDeref &&
areSameExpr(Context, SourceExpr->IgnoreParenImpCasts(),
287 InnerObj->IgnoreParenImpCasts()))
302 const VarDecl *IndexVar) {
303 return OpCall->getOperator() == OO_Star && OpCall->getNumArgs() == 1 &&
315 const VarDecl *IndexVar) {
316 return Uop->getOpcode() == UO_Deref &&
338 const VarDecl *IndexVar) {
339 const auto *VDecl = dyn_cast<VarDecl>(TheDecl);
342 if (!VDecl->hasInit())
345 bool OnlyCasts =
true;
346 const Expr *Init = VDecl->getInit()->IgnoreParenImpCasts();
347 if (Init && isa<CXXConstructExpr>(Init)) {
357 QualType InitType = Init->getType();
358 QualType DeclarationType = VDecl->getType();
359 if (!DeclarationType.isNull() && DeclarationType->isReferenceType())
360 DeclarationType = DeclarationType.getNonReferenceType();
362 if (InitType.isNull() || DeclarationType.isNull() ||
363 !Context->hasSameUnqualifiedType(DeclarationType, InitType))
367 switch (Init->getStmtClass()) {
368 case Stmt::ArraySubscriptExprClass: {
369 const auto *E = cast<ArraySubscriptExpr>(Init);
375 case Stmt::UnaryOperatorClass:
378 case Stmt::CXXOperatorCallExprClass: {
379 const auto *OpCall = cast<CXXOperatorCallExpr>(Init);
380 if (OpCall->getOperator() == OO_Star)
382 if (OpCall->getOperator() == OO_Subscript) {
383 assert(OpCall->getNumArgs() == 2);
389 case Stmt::CXXMemberCallExprClass: {
390 const auto *MemCall = cast<CXXMemberCallExpr>(Init);
393 const auto *MDecl = MemCall->getMethodDecl();
394 if (MDecl && !isa<CXXConversionDecl>(MDecl) && MDecl->getName() ==
"at") {
395 assert(MemCall->getNumArgs() == 1);
421 const QualType &ArrayType,
422 const Expr *ConditionExpr) {
423 if (!ConditionExpr || ConditionExpr->isValueDependent())
425 const ConstantArrayType *ConstType =
426 Context->getAsConstantArrayType(ArrayType);
429 llvm::APSInt ConditionSize;
430 if (!ConditionExpr->isIntegerConstantExpr(ConditionSize, *Context))
432 llvm::APSInt ArraySize(ConstType->getSize());
433 return llvm::APSInt::isSameValue(ConditionSize, ArraySize);
436 ForLoopIndexUseVisitor::ForLoopIndexUseVisitor(ASTContext *
Context,
437 const VarDecl *IndexVar,
438 const VarDecl *EndVar,
439 const Expr *ContainerExpr,
440 const Expr *ArrayBoundExpr,
441 bool ContainerNeedsDereference)
442 : Context(Context), IndexVar(IndexVar), EndVar(EndVar),
443 ContainerExpr(ContainerExpr), ArrayBoundExpr(ArrayBoundExpr),
444 ContainerNeedsDereference(ContainerNeedsDereference),
445 OnlyUsedAsIndex(true), AliasDecl(nullptr),
446 ConfidenceLevel(
Confidence::CL_Safe), NextStmtParent(nullptr),
447 CurrStmtParent(nullptr), ReplaceWithAliasUse(false),
448 AliasFromForInit(false) {
450 addComponent(ContainerExpr);
454 TraverseStmt(const_cast<Stmt *>(Body));
455 return OnlyUsedAsIndex && ContainerExpr;
460 for (
const auto &I : Components)
464 void ForLoopIndexUseVisitor::addComponent(
const Expr *E) {
466 const Expr *Node = E->IgnoreParenImpCasts();
467 Node->Profile(ID, *Context,
true);
468 DependentExprs.push_back(std::make_pair(Node, ID));
472 SourceLocation Begin = U.
Range.getBegin();
473 if (Begin.isMacroID())
474 Begin = Context->getSourceManager().getSpellingLoc(Begin);
476 if (UsageLocations.insert(Begin).second)
491 bool ForLoopIndexUseVisitor::TraverseUnaryDeref(UnaryOperator *Uop) {
499 return VisitorBase::TraverseUnaryOperator(Uop);
527 bool ForLoopIndexUseVisitor::TraverseMemberExpr(MemberExpr *Member) {
528 const Expr *Base = Member->getBase();
530 const Expr *ResultExpr = Member;
532 if (
const auto *Call =
533 dyn_cast<CXXOperatorCallExpr>(Base->IgnoreParenImpCasts())) {
541 if (Call->getOperator() == OO_Arrow) {
542 assert(Call->getNumArgs() == 1 &&
543 "Operator-> takes more than one argument");
546 ExprType = Call->getCallReturnType(*Context);
552 if (!Member->isArrow()) {
553 OnlyUsedAsIndex =
false;
557 if (ExprType.isNull())
558 ExprType = Obj->getType();
560 assert(ExprType->isPointerType() &&
"Operator-> returned non-pointer type");
563 SourceLocation ArrowLoc = Lexer::getLocForEndOfToken(
564 Base->getExprLoc(), 0, Context->getSourceManager(),
565 Context->getLangOpts());
568 if (ArrowLoc.isValid()) {
570 SourceRange(Base->getExprLoc(), ArrowLoc)));
574 return VisitorBase::TraverseMemberExpr(Member);
584 bool ForLoopIndexUseVisitor::TraverseCXXMemberCallExpr(
585 CXXMemberCallExpr *MemberCall) {
587 dyn_cast<MemberExpr>(MemberCall->getCallee()->IgnoreParenImpCasts());
589 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
594 const IdentifierInfo *Ident = Member->getMemberDecl()->getIdentifier();
595 if (Ident && Ident->isStr(
"at") && MemberCall->getNumArgs() == 1) {
597 Member->getBase(), ContainerExpr,
598 ContainerNeedsDereference)) {
604 if (
containsExpr(Context, &DependentExprs, Member->getBase()))
607 return VisitorBase::TraverseCXXMemberCallExpr(MemberCall);
629 bool ForLoopIndexUseVisitor::TraverseCXXOperatorCallExpr(
630 CXXOperatorCallExpr *OpCall) {
631 switch (OpCall->getOperator()) {
640 if (OpCall->getNumArgs() != 2)
643 OpCall->getArg(0), ContainerExpr,
644 ContainerNeedsDereference)) {
653 return VisitorBase::TraverseCXXOperatorCallExpr(OpCall);
675 bool ForLoopIndexUseVisitor::TraverseArraySubscriptExpr(ArraySubscriptExpr *E) {
676 Expr *Arr = E->getBase();
678 return VisitorBase::TraverseArraySubscriptExpr(E);
680 if ((ContainerExpr &&
682 ContainerExpr->IgnoreParenImpCasts())) ||
687 OnlyUsedAsIndex =
false;
688 return VisitorBase::TraverseArraySubscriptExpr(E);
730 bool ForLoopIndexUseVisitor::VisitDeclRefExpr(DeclRefExpr *E) {
731 const ValueDecl *TheDecl = E->getDecl();
735 OnlyUsedAsIndex =
false;
763 bool ForLoopIndexUseVisitor::TraverseLambdaCapture(LambdaExpr *LE,
764 const LambdaCapture *C) {
765 if (C->capturesVariable()) {
766 const VarDecl *VDecl = C->getCapturedVar();
777 return VisitorBase::TraverseLambdaCapture(LE, C);
784 bool ForLoopIndexUseVisitor::VisitDeclStmt(DeclStmt *S) {
785 if (!AliasDecl && S->isSingleDecl() &&
786 isAliasDecl(Context, S->getSingleDecl(), IndexVar)) {
788 if (CurrStmtParent) {
789 if (isa<IfStmt>(CurrStmtParent) || isa<WhileStmt>(CurrStmtParent) ||
790 isa<SwitchStmt>(CurrStmtParent))
791 ReplaceWithAliasUse =
true;
792 else if (isa<ForStmt>(CurrStmtParent)) {
793 if (cast<ForStmt>(CurrStmtParent)->getConditionVariableDeclStmt() == S)
794 ReplaceWithAliasUse =
true;
797 AliasFromForInit =
true;
805 bool ForLoopIndexUseVisitor::TraverseStmt(Stmt *S) {
808 const Stmt *OldNextParent = NextStmtParent;
809 CurrStmtParent = NextStmtParent;
811 bool Result = VisitorBase::TraverseStmt(S);
812 NextStmtParent = OldNextParent;
820 std::string IteratorName;
821 StringRef ContainerName;
823 ContainerName = TheContainer->getName();
825 size_t Len = ContainerName.size();
826 if (Len > 1 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S" :
"s")) {
827 IteratorName = ContainerName.substr(0, Len - 1);
829 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
833 if (Len > 2 && ContainerName.endswith(Style ==
NS_UpperCase ?
"S_" :
"s_")) {
834 IteratorName = ContainerName.substr(0, Len - 2);
836 if (!declarationExists(IteratorName) || IteratorName == OldIndex->getName())
840 return OldIndex->getName();
849 bool VariableNamer::declarationExists(StringRef Symbol) {
850 assert(Context !=
nullptr &&
"Expected an ASTContext");
851 IdentifierInfo &Ident = Context->Idents.get(Symbol);
854 if (!isAnyIdentifier(Ident.getTokenID()))
858 if (Ident.hasMacroDefinition())
862 for (
const Stmt *S = SourceStmt; S !=
nullptr; S = ReverseAST->lookup(S)) {
863 StmtGeneratedVarNameMap::const_iterator I = GeneratedDecls->find(S);
864 if (I != GeneratedDecls->end() && I->second == Symbol)
875 DeclFinderASTVisitor DeclFinder(Symbol, GeneratedDecls);
876 return DeclFinder.findUsages(SourceStmt);
879 std::string VariableNamer::AppendWithStyle(StringRef Str,
880 StringRef Suffix)
const {
881 std::string
Name = Str;
882 if (!Suffix.empty()) {
885 int SuffixStart = Name.size();
888 Name[SuffixStart] = toupper(Name[SuffixStart]);
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.
ClangTidyContext & Context
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...
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...