#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/FormatVariadic.h"
#include <optional>
using namespace clang;
using namespace ento;
using llvm::formatv;
namespace {
class ReturnValueChecker : public Checker<check::PostCall> {
public:
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
private:
const CallDescriptionSet Methods = {
{CDM::CXXMethod, {"ARMAsmParser", "Error"}},
{CDM::CXXMethod, {"HexagonAsmParser", "Error"}},
{CDM::CXXMethod, {"LLLexer", "Error"}},
{CDM::CXXMethod, {"LLParser", "Error"}},
{CDM::CXXMethod, {"MCAsmParser", "Error"}},
{CDM::CXXMethod, {"MCAsmParserExtension", "Error"}},
{CDM::CXXMethod, {"TGParser", "Error"}},
{CDM::CXXMethod, {"X86AsmParser", "Error"}},
{CDM::CXXMethod, {"LLParser", "TokError"}},
{CDM::CXXMethod, {"MCAsmParser", "TokError"}},
{CDM::CXXMethod, {"MCAsmParserExtension", "TokError"}},
{CDM::CXXMethod, {"TGParser", "TokError"}},
{CDM::CXXMethod, {"MIParser", "error"}},
{CDM::CXXMethod, {"WasmAsmParser", "error"}},
{CDM::CXXMethod, {"WebAssemblyAsmParser", "error"}},
{CDM::CXXMethod, {"AsmParser", "printError"}}};
};
}
static std::string getName(const CallEvent &Call) {
std::string Name;
if (const auto *MD = dyn_cast<CXXMethodDecl>(Call.getDecl()))
if (const CXXRecordDecl *RD = MD->getParent())
Name += RD->getNameAsString() + "::";
Name += Call.getCalleeIdentifier()->getName();
return Name;
}
void ReturnValueChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Methods.contains(Call))
return;
auto ReturnV = Call.getReturnValue().getAs<DefinedOrUnknownSVal>();
if (!ReturnV)
return;
ProgramStateRef State = C.getState();
if (ProgramStateRef StTrue = State->assume(*ReturnV, true)) {
std::string Msg =
formatv("'{0}' returns true (by convention)", getName(Call));
C.addTransition(StTrue, C.getNoteTag(Msg, true));
return;
}
std::string Msg = formatv("'{0}' returned false, breaking the convention "
"that it always returns true",
getName(Call));
C.addTransition(State, C.getNoteTag(Msg, true));
}
void ento::registerReturnValueChecker(CheckerManager &Mgr) {
Mgr.registerChecker<ReturnValueChecker>();
}
bool ento::shouldRegisterReturnValueChecker(const CheckerManager &mgr) {
return true;
}