xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp (revision e25152834cdf3b353892835a4f3b157e066a8ed4)
10b57cec5SDimitry Andric //=== CXXSelfAssignmentChecker.cpp -----------------------------*- C++ -*--===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines CXXSelfAssignmentChecker, which tests all custom defined
100b57cec5SDimitry Andric // copy and move assignment operators for the case of self assignment, thus
110b57cec5SDimitry Andric // where the parameter refers to the same location where the this pointer
120b57cec5SDimitry Andric // points to. The checker itself does not do any checks at all, but it
130b57cec5SDimitry Andric // causes the analyzer to check every copy and move assignment operator twice:
140b57cec5SDimitry Andric // once for when 'this' aliases with the parameter and once for when it may not.
150b57cec5SDimitry Andric // It is the task of the other enabled checkers to find the bugs in these two
160b57cec5SDimitry Andric // different cases.
170b57cec5SDimitry Andric //
180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric using namespace clang;
250b57cec5SDimitry Andric using namespace ento;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric namespace {
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric class CXXSelfAssignmentChecker : public Checker<check::BeginFunction> {
300b57cec5SDimitry Andric public:
310b57cec5SDimitry Andric   CXXSelfAssignmentChecker();
320b57cec5SDimitry Andric   void checkBeginFunction(CheckerContext &C) const;
330b57cec5SDimitry Andric };
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric 
CXXSelfAssignmentChecker()360b57cec5SDimitry Andric CXXSelfAssignmentChecker::CXXSelfAssignmentChecker() {}
370b57cec5SDimitry Andric 
checkBeginFunction(CheckerContext & C) const380b57cec5SDimitry Andric void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const {
390b57cec5SDimitry Andric   if (!C.inTopFrame())
400b57cec5SDimitry Andric     return;
410b57cec5SDimitry Andric   const auto *LCtx = C.getLocationContext();
420b57cec5SDimitry Andric   const auto *MD = dyn_cast<CXXMethodDecl>(LCtx->getDecl());
430b57cec5SDimitry Andric   if (!MD)
440b57cec5SDimitry Andric     return;
450b57cec5SDimitry Andric   if (!MD->isCopyAssignmentOperator() && !MD->isMoveAssignmentOperator())
460b57cec5SDimitry Andric     return;
470b57cec5SDimitry Andric   auto &State = C.getState();
480b57cec5SDimitry Andric   auto &SVB = C.getSValBuilder();
490b57cec5SDimitry Andric   auto ThisVal =
500b57cec5SDimitry Andric       State->getSVal(SVB.getCXXThis(MD, LCtx->getStackFrame()));
510b57cec5SDimitry Andric   auto Param = SVB.makeLoc(State->getRegion(MD->getParamDecl(0), LCtx));
520b57cec5SDimitry Andric   auto ParamVal = State->getSVal(Param);
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx);
550b57cec5SDimitry Andric   const NoteTag *SelfAssignTag =
56*5ffd83dbSDimitry Andric     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
570b57cec5SDimitry Andric         SmallString<256> Msg;
580b57cec5SDimitry Andric         llvm::raw_svector_ostream Out(Msg);
590b57cec5SDimitry Andric         Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this";
60*5ffd83dbSDimitry Andric         return std::string(Out.str());
610b57cec5SDimitry Andric       });
620b57cec5SDimitry Andric   C.addTransition(SelfAssignState, SelfAssignTag);
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx);
650b57cec5SDimitry Andric   const NoteTag *NonSelfAssignTag =
66*5ffd83dbSDimitry Andric     C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string {
670b57cec5SDimitry Andric         SmallString<256> Msg;
680b57cec5SDimitry Andric         llvm::raw_svector_ostream Out(Msg);
690b57cec5SDimitry Andric         Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this";
70*5ffd83dbSDimitry Andric         return std::string(Out.str());
710b57cec5SDimitry Andric       });
720b57cec5SDimitry Andric   C.addTransition(NonSelfAssignState, NonSelfAssignTag);
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric 
registerCXXSelfAssignmentChecker(CheckerManager & Mgr)750b57cec5SDimitry Andric void ento::registerCXXSelfAssignmentChecker(CheckerManager &Mgr) {
760b57cec5SDimitry Andric   Mgr.registerChecker<CXXSelfAssignmentChecker>();
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
shouldRegisterCXXSelfAssignmentChecker(const CheckerManager & mgr)79*5ffd83dbSDimitry Andric bool ento::shouldRegisterCXXSelfAssignmentChecker(const CheckerManager &mgr) {
800b57cec5SDimitry Andric   return true;
810b57cec5SDimitry Andric }
82