Bug Summary

File:tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp
Location:line 488, column 24
Description:Called C++ object pointer is null

Annotated Source Code

1//===--- LoopConvertCheck.cpp - clang-tidy---------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "LoopConvertCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
14using namespace clang;
15using namespace clang::ast_matchers;
16using namespace llvm;
17
18namespace clang {
19namespace tidy {
20namespace modernize {
21
22const char LoopNameArray[] = "forLoopArray";
23const char LoopNameIterator[] = "forLoopIterator";
24const char LoopNamePseudoArray[] = "forLoopPseudoArray";
25const char ConditionBoundName[] = "conditionBound";
26const char ConditionVarName[] = "conditionVar";
27const char IncrementVarName[] = "incrementVar";
28const char InitVarName[] = "initVar";
29const char BeginCallName[] = "beginCall";
30const char EndCallName[] = "endCall";
31const char ConditionEndVarName[] = "conditionEndVar";
32const char EndVarName[] = "endVar";
33const char DerefByValueResultName[] = "derefByValueResult";
34const char DerefByRefResultName[] = "derefByRefResult";
35
36// shared matchers
37static const TypeMatcher AnyType = anything();
38
39static const StatementMatcher IntegerComparisonMatcher =
40 expr(ignoringParenImpCasts(
41 declRefExpr(to(varDecl(hasType(isInteger())).bind(ConditionVarName)))));
42
43static const DeclarationMatcher InitToZeroMatcher =
44 varDecl(hasInitializer(ignoringParenImpCasts(integerLiteral(equals(0)))))
45 .bind(InitVarName);
46
47static const StatementMatcher IncrementVarMatcher =
48 declRefExpr(to(varDecl(hasType(isInteger())).bind(IncrementVarName)));
49
50/// \brief The matcher for loops over arrays.
51///
52/// In this general example, assuming 'j' and 'k' are of integral type:
53/// \code
54/// for (int i = 0; j < 3 + 2; ++k) { ... }
55/// \endcode
56/// The following string identifiers are bound to these parts of the AST:
57/// ConditionVarName: 'j' (as a VarDecl)
58/// ConditionBoundName: '3 + 2' (as an Expr)
59/// InitVarName: 'i' (as a VarDecl)
60/// IncrementVarName: 'k' (as a VarDecl)
61/// LoopName: The entire for loop (as a ForStmt)
62///
63/// Client code will need to make sure that:
64/// - The three index variables identified by the matcher are the same
65/// VarDecl.
66/// - The index variable is only used as an array index.
67/// - All arrays indexed by the loop are the same.
68StatementMatcher makeArrayLoopMatcher() {
69 StatementMatcher ArrayBoundMatcher =
70 expr(hasType(isInteger())).bind(ConditionBoundName);
71
72 return forStmt(
73 unless(isInTemplateInstantiation()),
74 hasLoopInit(declStmt(hasSingleDecl(InitToZeroMatcher))),
75 hasCondition(anyOf(
76 binaryOperator(hasOperatorName("<"),
77 hasLHS(IntegerComparisonMatcher),
78 hasRHS(ArrayBoundMatcher)),
79 binaryOperator(hasOperatorName(">"), hasLHS(ArrayBoundMatcher),
80 hasRHS(IntegerComparisonMatcher)))),
81 hasIncrement(unaryOperator(hasOperatorName("++"),
82 hasUnaryOperand(IncrementVarMatcher))))
83 .bind(LoopNameArray);
84}
85
86/// \brief The matcher used for iterator-based for loops.
87///
88/// This matcher is more flexible than array-based loops. It will match
89/// catch loops of the following textual forms (regardless of whether the
90/// iterator type is actually a pointer type or a class type):
91///
92/// Assuming f, g, and h are of type containerType::iterator,
93/// \code
94/// for (containerType::iterator it = container.begin(),
95/// e = createIterator(); f != g; ++h) { ... }
96/// for (containerType::iterator it = container.begin();
97/// f != anotherContainer.end(); ++h) { ... }
98/// \endcode
99/// The following string identifiers are bound to the parts of the AST:
100/// InitVarName: 'it' (as a VarDecl)
101/// ConditionVarName: 'f' (as a VarDecl)
102/// LoopName: The entire for loop (as a ForStmt)
103/// In the first example only:
104/// EndVarName: 'e' (as a VarDecl)
105/// ConditionEndVarName: 'g' (as a VarDecl)
106/// In the second example only:
107/// EndCallName: 'container.end()' (as a CXXMemberCallExpr)
108///
109/// Client code will need to make sure that:
110/// - The iterator variables 'it', 'f', and 'h' are the same.
111/// - The two containers on which 'begin' and 'end' are called are the same.
112/// - If the end iterator variable 'g' is defined, it is the same as 'f'.
113StatementMatcher makeIteratorLoopMatcher() {
114 StatementMatcher BeginCallMatcher =
115 memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("begin"))))
116 .bind(BeginCallName);
117
118 DeclarationMatcher InitDeclMatcher =
119 varDecl(hasInitializer(anyOf(ignoringParenImpCasts(BeginCallMatcher),
120 materializeTemporaryExpr(
121 ignoringParenImpCasts(BeginCallMatcher)),
122 hasDescendant(BeginCallMatcher))))
123 .bind(InitVarName);
124
125 DeclarationMatcher EndDeclMatcher =
126 varDecl(hasInitializer(anything())).bind(EndVarName);
127
128 StatementMatcher EndCallMatcher =
129 memberCallExpr(argumentCountIs(0), callee(methodDecl(hasName("end"))));
130
131 StatementMatcher IteratorBoundMatcher =
132 expr(anyOf(ignoringParenImpCasts(
133 declRefExpr(to(varDecl().bind(ConditionEndVarName)))),
134 ignoringParenImpCasts(expr(EndCallMatcher).bind(EndCallName)),
135 materializeTemporaryExpr(ignoringParenImpCasts(
136 expr(EndCallMatcher).bind(EndCallName)))));
137
138 StatementMatcher IteratorComparisonMatcher = expr(
139 ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ConditionVarName)))));
140
141 StatementMatcher OverloadedNEQMatcher =
142 operatorCallExpr(hasOverloadedOperatorName("!="), argumentCountIs(2),
143 hasArgument(0, IteratorComparisonMatcher),
144 hasArgument(1, IteratorBoundMatcher));
145
146 // This matcher tests that a declaration is a CXXRecordDecl that has an
147 // overloaded operator*(). If the operator*() returns by value instead of by
148 // reference then the return type is tagged with DerefByValueResultName.
149 internal::Matcher<VarDecl> TestDerefReturnsByValue =
150 hasType(recordDecl(hasMethod(allOf(
151 hasOverloadedOperatorName("*"),
152 anyOf(
153 // Tag the return type if it's by value.
154 returns(qualType(unless(hasCanonicalType(referenceType())))
155 .bind(DerefByValueResultName)),
156 returns(
157 // Skip loops where the iterator's operator* returns an
158 // rvalue reference. This is just weird.
159 qualType(unless(hasCanonicalType(rValueReferenceType())))
160 .bind(DerefByRefResultName)))))));
161
162 return forStmt(
163 unless(isInTemplateInstantiation()),
164 hasLoopInit(anyOf(declStmt(declCountIs(2),
165 containsDeclaration(0, InitDeclMatcher),
166 containsDeclaration(1, EndDeclMatcher)),
167 declStmt(hasSingleDecl(InitDeclMatcher)))),
168 hasCondition(
169 anyOf(binaryOperator(hasOperatorName("!="),
170 hasLHS(IteratorComparisonMatcher),
171 hasRHS(IteratorBoundMatcher)),
172 binaryOperator(hasOperatorName("!="),
173 hasLHS(IteratorBoundMatcher),
174 hasRHS(IteratorComparisonMatcher)),
175 OverloadedNEQMatcher)),
176 hasIncrement(anyOf(
177 unaryOperator(hasOperatorName("++"),
178 hasUnaryOperand(declRefExpr(
179 to(varDecl(hasType(pointsTo(AnyType)))
180 .bind(IncrementVarName))))),
181 operatorCallExpr(
182 hasOverloadedOperatorName("++"),
183 hasArgument(
184 0, declRefExpr(to(varDecl(TestDerefReturnsByValue)
185 .bind(IncrementVarName))))))))
186 .bind(LoopNameIterator);
187}
188
189/// \brief The matcher used for array-like containers (pseudoarrays).
190///
191/// This matcher is more flexible than array-based loops. It will match
192/// loops of the following textual forms (regardless of whether the
193/// iterator type is actually a pointer type or a class type):
194///
195/// Assuming f, g, and h are of type containerType::iterator,
196/// \code
197/// for (int i = 0, j = container.size(); f < g; ++h) { ... }
198/// for (int i = 0; f < container.size(); ++h) { ... }
199/// \endcode
200/// The following string identifiers are bound to the parts of the AST:
201/// InitVarName: 'i' (as a VarDecl)
202/// ConditionVarName: 'f' (as a VarDecl)
203/// LoopName: The entire for loop (as a ForStmt)
204/// In the first example only:
205/// EndVarName: 'j' (as a VarDecl)
206/// ConditionEndVarName: 'g' (as a VarDecl)
207/// In the second example only:
208/// EndCallName: 'container.size()' (as a CXXMemberCallExpr)
209///
210/// Client code will need to make sure that:
211/// - The index variables 'i', 'f', and 'h' are the same.
212/// - The containers on which 'size()' is called is the container indexed.
213/// - The index variable is only used in overloaded operator[] or
214/// container.at().
215/// - If the end iterator variable 'g' is defined, it is the same as 'j'.
216/// - The container's iterators would not be invalidated during the loop.
217StatementMatcher makePseudoArrayLoopMatcher() {
218 // Test that the incoming type has a record declaration that has methods
219 // called 'begin' and 'end'. If the incoming type is const, then make sure
220 // these methods are also marked const.
221 //
222 // FIXME: To be completely thorough this matcher should also ensure the
223 // return type of begin/end is an iterator that dereferences to the same as
224 // what operator[] or at() returns. Such a test isn't likely to fail except
225 // for pathological cases.
226 //
227 // FIXME: Also, a record doesn't necessarily need begin() and end(). Free
228 // functions called begin() and end() taking the container as an argument
229 // are also allowed.
230 TypeMatcher RecordWithBeginEnd = qualType(
231 anyOf(qualType(isConstQualified(),
232 hasDeclaration(recordDecl(
233 hasMethod(methodDecl(hasName("begin"), isConst())),
234 hasMethod(methodDecl(hasName("end"),
235 isConst())))) // hasDeclaration
236 ), // qualType
237 qualType(unless(isConstQualified()),
238 hasDeclaration(
239 recordDecl(hasMethod(hasName("begin")),
240 hasMethod(hasName("end"))))) // qualType
241 ));
242
243 StatementMatcher SizeCallMatcher = memberCallExpr(
244 argumentCountIs(0),
245 callee(methodDecl(anyOf(hasName("size"), hasName("length")))),
246 on(anyOf(hasType(pointsTo(RecordWithBeginEnd)),
247 hasType(RecordWithBeginEnd))));
248
249 StatementMatcher EndInitMatcher =
250 expr(anyOf(ignoringParenImpCasts(expr(SizeCallMatcher).bind(EndCallName)),
251 explicitCastExpr(hasSourceExpression(ignoringParenImpCasts(
252 expr(SizeCallMatcher).bind(EndCallName))))));
253
254 DeclarationMatcher EndDeclMatcher =
255 varDecl(hasInitializer(EndInitMatcher)).bind(EndVarName);
256
257 StatementMatcher IndexBoundMatcher =
258 expr(anyOf(ignoringParenImpCasts(declRefExpr(to(
259 varDecl(hasType(isInteger())).bind(ConditionEndVarName)))),
260 EndInitMatcher));
261
262 return forStmt(
263 unless(isInTemplateInstantiation()),
264 hasLoopInit(
265 anyOf(declStmt(declCountIs(2),
266 containsDeclaration(0, InitToZeroMatcher),
267 containsDeclaration(1, EndDeclMatcher)),
268 declStmt(hasSingleDecl(InitToZeroMatcher)))),
269 hasCondition(anyOf(
270 binaryOperator(hasOperatorName("<"),
271 hasLHS(IntegerComparisonMatcher),
272 hasRHS(IndexBoundMatcher)),
273 binaryOperator(hasOperatorName(">"), hasLHS(IndexBoundMatcher),
274 hasRHS(IntegerComparisonMatcher)))),
275 hasIncrement(unaryOperator(hasOperatorName("++"),
276 hasUnaryOperand(IncrementVarMatcher))))
277 .bind(LoopNamePseudoArray);
278}
279
280/// \brief Determine whether Init appears to be an initializing an iterator.
281///
282/// If it is, returns the object whose begin() or end() method is called, and
283/// the output parameter isArrow is set to indicate whether the initialization
284/// is called via . or ->.
285static const Expr *getContainerFromBeginEndCall(const Expr *Init, bool IsBegin,
286 bool *IsArrow) {
287 // FIXME: Maybe allow declaration/initialization outside of the for loop.
288 const auto *TheCall =
289 dyn_cast_or_null<CXXMemberCallExpr>(digThroughConstructors(Init));
290 if (!TheCall || TheCall->getNumArgs() != 0)
291 return nullptr;
292
293 const auto *Member = dyn_cast<MemberExpr>(TheCall->getCallee());
294 if (!Member)
295 return nullptr;
296 StringRef Name = Member->getMemberDecl()->getName();
297 StringRef TargetName = IsBegin ? "begin" : "end";
298 if (Name != TargetName)
299 return nullptr;
300
301 const Expr *SourceExpr = Member->getBase();
302 if (!SourceExpr)
303 return nullptr;
304
305 *IsArrow = Member->isArrow();
306 return SourceExpr;
307}
308
309/// \brief Determines the container whose begin() and end() functions are called
310/// for an iterator-based loop.
311///
312/// BeginExpr must be a member call to a function named "begin()", and EndExpr
313/// must be a member.
314static const Expr *findContainer(ASTContext *Context, const Expr *BeginExpr,
315 const Expr *EndExpr,
316 bool *ContainerNeedsDereference) {
317 // Now that we know the loop variable and test expression, make sure they are
318 // valid.
319 bool BeginIsArrow = false;
320 bool EndIsArrow = false;
321 const Expr *BeginContainerExpr =
322 getContainerFromBeginEndCall(BeginExpr, /*IsBegin=*/true, &BeginIsArrow);
323 if (!BeginContainerExpr)
324 return nullptr;
325
326 const Expr *EndContainerExpr =
327 getContainerFromBeginEndCall(EndExpr, /*IsBegin=*/false, &EndIsArrow);
328 // Disallow loops that try evil things like this (note the dot and arrow):
329 // for (IteratorType It = Obj.begin(), E = Obj->end(); It != E; ++It) { }
330 if (!EndContainerExpr || BeginIsArrow != EndIsArrow ||
331 !areSameExpr(Context, EndContainerExpr, BeginContainerExpr))
332 return nullptr;
333
334 *ContainerNeedsDereference = BeginIsArrow;
335 return BeginContainerExpr;
336}
337
338/// \brief Obtain the original source code text from a SourceRange.
339static StringRef getStringFromRange(SourceManager &SourceMgr,
340 const LangOptions &LangOpts,
341 SourceRange Range) {
342 if (SourceMgr.getFileID(Range.getBegin()) !=
343 SourceMgr.getFileID(Range.getEnd())) {
344 return StringRef(); // Empty string.
345 }
346
347 return Lexer::getSourceText(CharSourceRange(Range, true), SourceMgr,
348 LangOpts);
349}
350
351/// \brief If the given expression is actually a DeclRefExpr, find and return
352/// the underlying VarDecl; otherwise, return NULL.
353static const VarDecl *getReferencedVariable(const Expr *E) {
354 if (const DeclRefExpr *DRE = getDeclRef(E))
355 return dyn_cast<VarDecl>(DRE->getDecl());
356 return nullptr;
357}
358
359/// \brief Returns true when the given expression is a member expression
360/// whose base is `this` (implicitly or not).
361static bool isDirectMemberExpr(const Expr *E) {
362 if (const auto *Member = dyn_cast<MemberExpr>(E->IgnoreParenImpCasts()))
363 return isa<CXXThisExpr>(Member->getBase()->IgnoreParenImpCasts());
364 return false;
365}
366
367LoopConvertCheck::LoopConvertCheck(StringRef Name, ClangTidyContext *Context)
368 : ClangTidyCheck(Name, Context), TUInfo(new TUTrackingInfo),
369 MinConfidence(StringSwitch<Confidence::Level>(
370 Options.get("MinConfidence", "reasonable"))
371 .Case("safe", Confidence::CL_Safe)
372 .Case("risky", Confidence::CL_Risky)
373 .Default(Confidence::CL_Reasonable)) {}
374
375void LoopConvertCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
376 SmallVector<std::string, 3> Confs{"risky", "reasonable", "safe"};
377 Options.store(Opts, "MinConfidence", Confs[static_cast<int>(MinConfidence)]);
378}
379
380/// \brief Computes the changes needed to convert a given for loop, and
381/// applies it.
382void LoopConvertCheck::doConversion(
383 ASTContext *Context, const VarDecl *IndexVar, const VarDecl *MaybeContainer,
384 StringRef ContainerString, const UsageResult &Usages,
385 const DeclStmt *AliasDecl, bool AliasUseRequired, bool AliasFromForInit,
386 const ForStmt *TheLoop, bool ContainerNeedsDereference, bool DerefByValue,
387 bool DerefByConstRef) {
388 auto Diag = diag(TheLoop->getForLoc(), "use range-based for loop instead");
389
390 std::string VarName;
391 bool VarNameFromAlias = (Usages.size() == 1) && AliasDecl;
392 bool AliasVarIsRef = false;
393
394 if (VarNameFromAlias) {
395 const auto *AliasVar = cast<VarDecl>(AliasDecl->getSingleDecl());
396 VarName = AliasVar->getName().str();
397 AliasVarIsRef = AliasVar->getType()->isReferenceType();
398
399 // We keep along the entire DeclStmt to keep the correct range here.
400 const SourceRange &ReplaceRange = AliasDecl->getSourceRange();
401
402 std::string ReplacementText;
403 if (AliasUseRequired) {
404 ReplacementText = VarName;
405 } else if (AliasFromForInit) {
406 // FIXME: Clang includes the location of the ';' but only for DeclStmt's
407 // in a for loop's init clause. Need to put this ';' back while removing
408 // the declaration of the alias variable. This is probably a bug.
409 ReplacementText = ";";
410 }
411
412 Diag << FixItHint::CreateReplacement(
413 CharSourceRange::getTokenRange(ReplaceRange), ReplacementText);
414 // No further replacements are made to the loop, since the iterator or index
415 // was used exactly once - in the initialization of AliasVar.
416 } else {
417 VariableNamer Namer(&TUInfo->getGeneratedDecls(),
418 &TUInfo->getParentFinder().getStmtToParentStmtMap(),
419 TheLoop, IndexVar, MaybeContainer, Context);
420 VarName = Namer.createIndexName();
421 // First, replace all usages of the array subscript expression with our new
422 // variable.
423 for (const auto &I : Usages) {
424 std::string ReplaceText = I.IsArrow ? VarName + "." : VarName;
425 TUInfo->getReplacedVars().insert(std::make_pair(TheLoop, IndexVar));
426 Diag << FixItHint::CreateReplacement(
427 CharSourceRange::getTokenRange(I.Range), ReplaceText);
428 }
429 }
430
431 // Now, we need to construct the new range expression.
432 SourceRange ParenRange(TheLoop->getLParenLoc(), TheLoop->getRParenLoc());
433
434 QualType AutoRefType = Context->getAutoDeductType();
435
436 // If the new variable name is from the aliased variable, then the reference
437 // type for the new variable should only be used if the aliased variable was
438 // declared as a reference.
439 if (!VarNameFromAlias || AliasVarIsRef) {
440 // If an iterator's operator*() returns a 'T&' we can bind that to 'auto&'.
441 // If operator*() returns 'T' we can bind that to 'auto&&' which will deduce
442 // to 'T&&&'.
443 if (DerefByValue) {
444 AutoRefType = Context->getRValueReferenceType(AutoRefType);
445 } else {
446 if (DerefByConstRef)
447 AutoRefType = Context->getConstType(AutoRefType);
448 AutoRefType = Context->getLValueReferenceType(AutoRefType);
449 }
450 }
451
452 StringRef MaybeDereference = ContainerNeedsDereference ? "*" : "";
453 std::string TypeString = AutoRefType.getAsString();
454 std::string Range = ("(" + TypeString + " " + VarName + " : " +
455 MaybeDereference + ContainerString + ")").str();
456 Diag << FixItHint::CreateReplacement(
457 CharSourceRange::getTokenRange(ParenRange), Range);
458 TUInfo->getGeneratedDecls().insert(make_pair(TheLoop, VarName));
459}
460
461/// \brief Determine if the change should be deferred or rejected, returning
462/// text which refers to the container iterated over if the change should
463/// proceed.
464StringRef LoopConvertCheck::checkRejections(ASTContext *Context,
465 const Expr *ContainerExpr,
466 const ForStmt *TheLoop) {
467 // If we already modified the reange of this for loop, don't do any further
468 // updates on this iteration.
469 if (TUInfo->getReplacedVars().count(TheLoop))
8
Taking false branch
470 return "";
471
472 Context->getTranslationUnitDecl();
473 TUInfo->getParentFinder();
474 TUInfo->getParentFinder().gatherAncestors(Context->getTranslationUnitDecl());
475 // Ensure that we do not try to move an expression dependent on a local
476 // variable declared inside the loop outside of it.
477 DependencyFinderASTVisitor DependencyFinder(
478 &TUInfo->getParentFinder().getStmtToParentStmtMap(),
479 &TUInfo->getParentFinder().getDeclToParentStmtMap(),
480 &TUInfo->getReplacedVars(), TheLoop);
481
482 // FIXME: Determine when the external dependency isn't an expression converted
483 // by another loop.
484 if (DependencyFinder.dependsOnInsideVariable(ContainerExpr))
9
Taking false branch
485 return "";
486
487 StringRef ContainerString;
488 if (isa<CXXThisExpr>(ContainerExpr->IgnoreParenImpCasts())) {
10
Called C++ object pointer is null
489 ContainerString = "this";
490 } else {
491 ContainerString =
492 getStringFromRange(Context->getSourceManager(), Context->getLangOpts(),
493 ContainerExpr->getSourceRange());
494 }
495
496 return ContainerString;
497}
498
499/// \brief Given a loop header that would be convertible, discover all usages
500/// of the index variable and convert the loop if possible.
501void LoopConvertCheck::findAndVerifyUsages(
502 ASTContext *Context, const VarDecl *LoopVar, const VarDecl *EndVar,
503 const Expr *ContainerExpr, const Expr *BoundExpr,
504 bool ContainerNeedsDereference, bool DerefByValue, bool DerefByConstRef,
505 const ForStmt *TheLoop, LoopFixerKind FixerKind) {
506 ForLoopIndexUseVisitor Finder(Context, LoopVar, EndVar, ContainerExpr,
507 BoundExpr, ContainerNeedsDereference);
508
509 if (ContainerExpr) {
1
Assuming 'ContainerExpr' is null
2
Taking false branch
510 ComponentFinderASTVisitor ComponentFinder;
511 ComponentFinder.findExprComponents(ContainerExpr->IgnoreParenImpCasts());
512 Finder.addComponents(ComponentFinder.getComponents());
513 }
514
515 if (!Finder.findAndVerifyUsages(TheLoop->getBody()))
3
Taking false branch
516 return;
517
518 Confidence ConfidenceLevel(Finder.getConfidenceLevel());
519 if (FixerKind == LFK_Array) {
4
Assuming 'FixerKind' is not equal to LFK_Array
5
Taking false branch
520 // The array being indexed by IndexVar was discovered during traversal.
521 ContainerExpr = Finder.getContainerIndexed()->IgnoreParenImpCasts();
522 // Very few loops are over expressions that generate arrays rather than
523 // array variables. Consider loops over arrays that aren't just represented
524 // by a variable to be risky conversions.
525 if (!getReferencedVariable(ContainerExpr) &&
526 !isDirectMemberExpr(ContainerExpr))
527 ConfidenceLevel.lowerTo(Confidence::CL_Risky);
528 }
529
530 StringRef ContainerString = checkRejections(Context, ContainerExpr, TheLoop);
6
Passing null pointer value via 2nd parameter 'ContainerExpr'
7
Calling 'LoopConvertCheck::checkRejections'
531
532 if (ContainerString.empty() || ConfidenceLevel.getLevel() < MinConfidence)
533 return;
534
535 doConversion(Context, LoopVar, getReferencedVariable(ContainerExpr),
536 ContainerString, Finder.getUsages(), Finder.getAliasDecl(),
537 Finder.aliasUseRequired(), Finder.aliasFromForInit(), TheLoop,
538 ContainerNeedsDereference, DerefByValue, DerefByConstRef);
539}
540
541void LoopConvertCheck::registerMatchers(MatchFinder *Finder) {
542 // Only register the matchers for C++. Because this checker is used for
543 // modernization, it is reasonable to run it on any C++ standard with the
544 // assumption the user is trying to modernize their codebase.
545 if (getLangOpts().CPlusPlus) {
546 Finder->addMatcher(makeArrayLoopMatcher(), this);
547 Finder->addMatcher(makeIteratorLoopMatcher(), this);
548 Finder->addMatcher(makePseudoArrayLoopMatcher(), this);
549 }
550}
551
552void LoopConvertCheck::check(const MatchFinder::MatchResult &Result) {
553 const BoundNodes &Nodes = Result.Nodes;
554 Confidence ConfidenceLevel(Confidence::CL_Safe);
555 ASTContext *Context = Result.Context;
556
557 const ForStmt *TheLoop;
558 LoopFixerKind FixerKind;
559
560 if ((TheLoop = Nodes.getStmtAs<ForStmt>(LoopNameArray))) {
561 FixerKind = LFK_Array;
562 } else if ((TheLoop = Nodes.getStmtAs<ForStmt>(LoopNameIterator))) {
563 FixerKind = LFK_Iterator;
564 } else {
565 TheLoop = Nodes.getStmtAs<ForStmt>(LoopNamePseudoArray);
566 assert(TheLoop && "Bad Callback. No for statement")((TheLoop && "Bad Callback. No for statement") ? static_cast
<void> (0) : __assert_fail ("TheLoop && \"Bad Callback. No for statement\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp"
, 566, __PRETTY_FUNCTION__))
;
567 FixerKind = LFK_PseudoArray;
568 }
569
570 // Check that we have exactly one index variable and at most one end variable.
571 const auto *LoopVar = Nodes.getDeclAs<VarDecl>(IncrementVarName);
572 const auto *CondVar = Nodes.getDeclAs<VarDecl>(ConditionVarName);
573 const auto *InitVar = Nodes.getDeclAs<VarDecl>(InitVarName);
574 if (!areSameVariable(LoopVar, CondVar) || !areSameVariable(LoopVar, InitVar))
575 return;
576 const auto *EndVar = Nodes.getDeclAs<VarDecl>(EndVarName);
577 const auto *ConditionEndVar = Nodes.getDeclAs<VarDecl>(ConditionEndVarName);
578 if (EndVar && !areSameVariable(EndVar, ConditionEndVar))
579 return;
580
581 // If the end comparison isn't a variable, we can try to work with the
582 // expression the loop variable is being tested against instead.
583 const auto *EndCall = Nodes.getStmtAs<CXXMemberCallExpr>(EndCallName);
584 const auto *BoundExpr = Nodes.getStmtAs<Expr>(ConditionBoundName);
585 // If the loop calls end()/size() after each iteration, lower our confidence
586 // level.
587 if (FixerKind != LFK_Array && !EndVar)
588 ConfidenceLevel.lowerTo(Confidence::CL_Reasonable);
589
590 const Expr *ContainerExpr = nullptr;
591 bool DerefByValue = false;
592 bool DerefByConstRef = false;
593 bool ContainerNeedsDereference = false;
594 // FIXME: Try to put most of this logic inside a matcher. Currently, matchers
595 // don't allow the ight-recursive checks in digThroughConstructors.
596 if (FixerKind == LFK_Iterator) {
597 ContainerExpr = findContainer(Context, LoopVar->getInit(),
598 EndVar ? EndVar->getInit() : EndCall,
599 &ContainerNeedsDereference);
600
601 QualType InitVarType = InitVar->getType();
602 QualType CanonicalInitVarType = InitVarType.getCanonicalType();
603
604 const auto *BeginCall = Nodes.getNodeAs<CXXMemberCallExpr>(BeginCallName);
605 assert(BeginCall && "Bad Callback. No begin call expression")((BeginCall && "Bad Callback. No begin call expression"
) ? static_cast<void> (0) : __assert_fail ("BeginCall && \"Bad Callback. No begin call expression\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp"
, 605, __PRETTY_FUNCTION__))
;
606 QualType CanonicalBeginType =
607 BeginCall->getMethodDecl()->getReturnType().getCanonicalType();
608 if (CanonicalBeginType->isPointerType() &&
609 CanonicalInitVarType->isPointerType()) {
610 QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
611 QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
612 // If the initializer and the variable are both pointers check if the
613 // un-qualified pointee types match otherwise we don't use auto.
614 if (!Context->hasSameUnqualifiedType(InitPointeeType, BeginPointeeType))
615 return;
616 } else {
617 // Check for qualified types to avoid conversions from non-const to const
618 // iterator types.
619 if (!Context->hasSameType(CanonicalInitVarType, CanonicalBeginType))
620 return;
621 }
622
623 DerefByValue = Nodes.getNodeAs<QualType>(DerefByValueResultName) != nullptr;
624 if (!DerefByValue) {
625 if (const auto *DerefType =
626 Nodes.getNodeAs<QualType>(DerefByRefResultName)) {
627 // A node will only be bound with DerefByRefResultName if we're dealing
628 // with a user-defined iterator type. Test the const qualification of
629 // the reference type.
630 DerefByConstRef = (*DerefType)
631 ->getAs<ReferenceType>()
632 ->getPointeeType()
633 .isConstQualified();
634 } else {
635 // By nature of the matcher this case is triggered only for built-in
636 // iterator types (i.e. pointers).
637 assert(isa<PointerType>(CanonicalInitVarType) &&((isa<PointerType>(CanonicalInitVarType) && "Non-class iterator type is not a pointer type"
) ? static_cast<void> (0) : __assert_fail ("isa<PointerType>(CanonicalInitVarType) && \"Non-class iterator type is not a pointer type\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp"
, 638, __PRETTY_FUNCTION__))
638 "Non-class iterator type is not a pointer type")((isa<PointerType>(CanonicalInitVarType) && "Non-class iterator type is not a pointer type"
) ? static_cast<void> (0) : __assert_fail ("isa<PointerType>(CanonicalInitVarType) && \"Non-class iterator type is not a pointer type\""
, "/tmp/buildd/llvm-toolchain-snapshot-3.8~svn246424/tools/clang/tools/extra/clang-tidy/modernize/LoopConvertCheck.cpp"
, 638, __PRETTY_FUNCTION__))
;
639 QualType InitPointeeType = CanonicalInitVarType->getPointeeType();
640 QualType BeginPointeeType = CanonicalBeginType->getPointeeType();
641 // If the initializer and variable have both the same type just use auto
642 // otherwise we test for const qualification of the pointed-at type.
643 if (!Context->hasSameType(InitPointeeType, BeginPointeeType))
644 DerefByConstRef = InitPointeeType.isConstQualified();
645 }
646 } else {
647 // If the dereference operator returns by value then test for the
648 // canonical const qualification of the init variable type.
649 DerefByConstRef = CanonicalInitVarType.isConstQualified();
650 }
651 } else if (FixerKind == LFK_PseudoArray) {
652 if (!EndCall)
653 return;
654 ContainerExpr = EndCall->getImplicitObjectArgument();
655 const auto *Member = dyn_cast<MemberExpr>(EndCall->getCallee());
656 if (!Member)
657 return;
658 ContainerNeedsDereference = Member->isArrow();
659 }
660
661 // We must know the container or an array length bound.
662 if (!ContainerExpr && !BoundExpr)
663 return;
664
665 if (ConfidenceLevel.getLevel() < MinConfidence)
666 return;
667
668 findAndVerifyUsages(Context, LoopVar, EndVar, ContainerExpr, BoundExpr,
669 ContainerNeedsDereference, DerefByValue, DerefByConstRef,
670 TheLoop, FixerKind);
671}
672
673} // namespace modernize
674} // namespace tidy
675} // namespace clang