Lines Matching +full:inter +full:- +full:ic

1 // MoveChecker.cpp - Check use of moved-from objects. - C++ ---------------===//
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This defines checker which checks for potential misuses of a moved-from
10 // object. That means method calls on the object or copying it in moved-from
13 //===----------------------------------------------------------------------===//
69 AK_Invalid = -1,
70 AK_KnownsOnly = 0, // Warn only about known move-unsafe classes.
72 AK_All = 2, // Warn on any use-after-move.
87 // STL smart pointers are automatically re-initialized to null when moved
96 // Not all of these are entirely move-safe, but they do provide *some*
116 // In non-aggressive mode, only warn on use-after-move of local variables in shouldBeTracked()
119 // their user to re-use the storage. The latter is possible because STL in shouldBeTracked()
121 // move and their state-reset methods are also known, which allows us to in shouldBeTracked()
122 // predict precisely when use-after-move is invalid. in shouldBeTracked()
126 // In aggressive mode, warn on any use-after-move because the user has in shouldBeTracked()
127 // intentionally asked us to completely eliminate use-after-move in shouldBeTracked()
149 // Classifies the object and dumps a user-friendly description string to
204 BugType BT{this, "Use-after-move", categories::CXXMoveSemantics};
231 // Define the inter-checker API.
236 const RegionState *RS = State->get<TrackedRegionMap>(Region); in isMovedFrom()
237 return RS && (RS->isMoved() || RS->isReported()); in isMovedFrom()
248 for (auto &E : State->get<TrackedRegionMap>()) { in removeFromState()
249 if (E.first->isSubRegionOf(Region)) in removeFromState()
250 State = State->remove<TrackedRegionMap>(E.first); in removeFromState()
257 for (auto &E : State->get<TrackedRegionMap>()) { in isAnyBaseRegionReported()
258 if (Region->isSubRegionOf(E.first) && E.second.isReported()) in isAnyBaseRegionReported()
266 SymbolRef Sym = SR->getSymbol(); in unwrapRValueReferenceIndirection()
267 if (Sym->getType()->isRValueReferenceType()) in unwrapRValueReferenceIndirection()
268 if (const MemRegion *OriginMR = Sym->getOriginRegion()) in unwrapRValueReferenceIndirection()
282 ProgramStateRef State = N->getState(); in VisitNode()
283 ProgramStateRef StatePrev = N->getFirstPred()->getState(); in VisitNode()
284 const RegionState *TrackedObject = State->get<TrackedRegionMap>(Region); in VisitNode()
286 StatePrev->get<TrackedRegionMap>(Region); in VisitNode()
293 const Stmt *S = N->getStmtForDiagnostics(); in VisitNode()
329 N->getLocationContext()); in VisitNode()
341 ProgramStateRef State = N->getState(); in getMoveLocation()
342 if (!State->get<TrackedRegionMap>(Region)) in getMoveLocation()
345 N = N->pred_empty() ? nullptr : *(N->pred_begin()); in getMoveLocation()
354 const RegionState *RS = State->get<TrackedRegionMap>(Region); in modelUse()
384 if (!N || N->isSink()) in modelUse()
387 State = State->set<TrackedRegionMap>(Region, RegionState::getReported()); in modelUse()
401 if (const Stmt *MoveStmt = MoveNode->getStmtForDiagnostics()) in tryToReportBug()
403 MoveStmt, C.getSourceManager(), MoveNode->getLocationContext()); in tryToReportBug()
410 OS << "Method called on moved-from object"; in tryToReportBug()
414 OS << "Moved-from object"; in tryToReportBug()
419 OS << "Moved-from object"; in tryToReportBug()
431 MoveNode->getLocationContext()->getDecl()); in tryToReportBug()
432 R->addVisitor(std::make_unique<MovedBugVisitor>(*this, Region, RD, MK)); in tryToReportBug()
446 const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(AFC->getDecl()); in checkPostCall()
450 // Check if an object became moved-from. in checkPostCall()
454 if (ConstructorDecl && !ConstructorDecl->isMoveConstructor()) in checkPostCall()
457 if (!ConstructorDecl && !MethodDecl->isMoveAssignmentOperator()) in checkPostCall()
460 const auto ArgRegion = AFC->getArgSVal(0).getAsRegion(); in checkPostCall()
466 if (CC && CC->getCXXThisVal().getAsRegion() == ArgRegion) in checkPostCall()
469 if (const auto *IC = dyn_cast<CXXInstanceCall>(AFC)) in checkPostCall() local
470 if (IC->getCXXThisVal().getAsRegion() == ArgRegion) in checkPostCall()
473 const MemRegion *BaseRegion = ArgRegion->getBaseRegion(); in checkPostCall()
475 if (BaseRegion->getAs<CXXTempObjectRegion>() || in checkPostCall()
476 AFC->getArgExpr(0)->isPRValue()) in checkPostCall()
480 if (State->get<TrackedRegionMap>(ArgRegion)) in checkPostCall()
483 const CXXRecordDecl *RD = MethodDecl->getParent(); in checkPostCall()
486 // Mark object as moved-from. in checkPostCall()
487 State = State->set<TrackedRegionMap>(ArgRegion, RegionState::getMoved()); in checkPostCall()
498 const Type *Tp = ConversionDec->getConversionType().getTypePtrOrNull(); in isMoveSafeMethod()
501 if (Tp->isBooleanType() || Tp->isVoidType() || Tp->isVoidPointerType()) in isMoveSafeMethod()
505 return (MethodDec && MethodDec->getDeclName().isIdentifier() && in isMoveSafeMethod()
506 (MethodDec->getName().lower() == "empty" || in isMoveSafeMethod()
507 MethodDec->getName().lower() == "isempty")); in isMoveSafeMethod()
513 if (MethodDec->hasAttr<ReinitializesAttr>()) in isStateResetMethod()
515 if (MethodDec->getDeclName().isIdentifier()) { in isStateResetMethod()
516 std::string MethodName = MethodDec->getName().lower(); in isStateResetMethod()
531 const auto *CtxDec = LC->getDecl(); in isInMoveSafeContext()
535 if (DtorDec || (CtorDec && CtorDec->isCopyOrMoveConstructor()) || in isInMoveSafeContext()
536 (MethodDec && MethodDec->isOverloadedOperator() && in isInMoveSafeContext()
537 MethodDec->getOverloadedOperator() == OO_Equal) || in isInMoveSafeContext()
540 } while ((LC = LC->getParent())); in isInMoveSafeContext()
546 const IdentifierInfo *II = RD->getIdentifier(); in belongsTo()
547 return II && Set.count(II->getName()); in belongsTo()
554 // For the purposes of this checker, we classify move-safe STL types in classifyObject()
555 // as not-"STL" types, because that's how the checker treats them. in classifyObject()
559 isa<StackSpaceRegion>(MR->getMemorySpace()); in classifyObject()
561 if (!RD || !RD->getDeclContext()->isStdNamespace()) in classifyObject()
579 const auto *RegionDecl = cast<NamedDecl>(DR->getDecl()); in explainObject()
580 OS << " '" << RegionDecl->getDeclName() << "'"; in explainObject()
595 OS << " of type '" << RD->getQualifiedNameAsString() << "'"; in explainObject()
608 State = removeFromState(State, CC->getCXXThisVal().getAsRegion()); in checkPreCall()
609 auto CtorDec = CC->getDecl(); in checkPreCall()
610 // Check for copying a moved-from object and report the bug. in checkPreCall()
611 if (CtorDec && CtorDec->isCopyOrMoveConstructor()) { in checkPreCall()
612 const MemRegion *ArgRegion = CC->getArgSVal(0).getAsRegion(); in checkPreCall()
613 const CXXRecordDecl *RD = CtorDec->getParent(); in checkPreCall()
614 MisuseKind MK = CtorDec->isMoveConstructor() ? MK_Move : MK_Copy; in checkPreCall()
620 const auto IC = dyn_cast<CXXInstanceCall>(&Call); in checkPreCall() local
621 if (!IC) in checkPreCall()
624 const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion(); in checkPreCall()
628 // The remaining part is check only for method call on a moved-from object. in checkPreCall()
629 const auto MethodDecl = dyn_cast_or_null<CXXMethodDecl>(IC->getDecl()); in checkPreCall()
637 // We want to investigate the whole object, not only sub-object of a parent in checkPreCall()
639 ThisRegion = ThisRegion->getMostDerivedObjectRegion(); in checkPreCall()
651 const CXXRecordDecl *RD = MethodDecl->getParent(); in checkPreCall()
653 if (MethodDecl->isOverloadedOperator()) { in checkPreCall()
654 OverloadedOperatorKind OOK = MethodDecl->getOverloadedOperator(); in checkPreCall()
661 if (MethodDecl->isCopyAssignmentOperator() || in checkPreCall()
662 MethodDecl->isMoveAssignmentOperator()) { in checkPreCall()
663 const MemRegion *ArgRegion = IC->getArgSVal(0).getAsRegion(); in checkPreCall()
665 MethodDecl->isMoveAssignmentOperator() ? MK_Move : MK_Copy; in checkPreCall()
685 TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>(); in checkDeadSymbols()
692 State = State->remove<TrackedRegionMap>(Region); in checkDeadSymbols()
705 // that are passed directly via non-const pointers or non-const references in checkRegionChanges()
707 // In case of an InstanceCall don't invalidate the this-region since in checkRegionChanges()
710 if (const auto *IC = dyn_cast<CXXInstanceCall>(Call)) in checkRegionChanges() local
711 ThisRegion = IC->getCXXThisVal().getAsRegion(); in checkRegionChanges()
725 State = removeFromState(State, Region->getBaseRegion()); in checkRegionChanges()
734 TrackedRegionMapTy RS = State->get<TrackedRegionMap>(); in printState()
737 Out << Sep << "Moved-from objects :" << NL; in printState()
739 I.first->dumpToStream(Out); in printState()
750 chk->setAggressiveness( in registerMoveChecker()