45class TrustNonnullChecker :
public Checker<check::PostCall,
46 check::PostObjCMessage,
50 static unsigned constexpr ComplexityThreshold = 10;
51 Selector ObjectForKeyedSubscriptSel;
52 Selector ObjectForKeySel;
53 Selector SetObjectForKeyedSubscriptSel;
54 Selector SetObjectForKeySel;
57 TrustNonnullChecker(ASTContext &Ctx)
58 : ObjectForKeyedSubscriptSel(
61 SetObjectForKeyedSubscriptSel(
67 bool Assumption)
const {
73 State = addImplication(Antecedent, State,
true);
74 State = addImplication(Antecedent, State,
false);
80 void checkPostCall(
const CallEvent &
Call, CheckerContext &
C)
const {
82 if (!
Call.isInSystemHeader())
87 if (isNonNullPtr(
Call,
C))
88 if (
auto L =
Call.getReturnValue().getAs<Loc>())
89 State = State->assume(*L,
true);
91 C.addTransition(State);
94 void checkPostObjCMessage(
const ObjCMethodCall &Msg,
95 CheckerContext &
C)
const {
104 if (interfaceHasSuperclass(ID,
"NSMutableDictionary") &&
105 (Msg.
getSelector() == SetObjectForKeyedSubscriptSel ||
108 State = State->assume(*L,
true);
112 if (interfaceHasSuperclass(ID,
"NSDictionary") &&
113 (Msg.
getSelector() == ObjectForKeyedSubscriptSel ||
121 State = State->set<NonNullImplicationMap>(RetS, ArgS);
125 State = State->set<NullImplicationMap>(ArgS, RetS);
129 C.addTransition(State);
132 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &
C)
const {
135 State = dropDeadFromGDM<NullImplicationMap>(SymReaper, State);
136 State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper, State);
138 C.addTransition(State);
145 template <
typename MapName>
148 for (
const std::pair<SymbolRef, SymbolRef> &P : State->get<MapName>())
149 if (!SymReaper.
isLive(P.first) || !SymReaper.
isLive(P.second))
150 State = State->remove<MapName>(P.first);
156 bool isNonNullPtr(
const CallEvent &
Call, CheckerContext &
C)
const {
157 QualType ExprRetType =
Call.getResultType();
170 const ObjCMethodDecl *MD = MCall->getDecl();
182 if (!MCall->isInstanceMessage())
186 SVal Receiver = MCall->getReceiverSVal();
187 ConditionTruthVal TV =
C.getState()->isNonNull(Receiver);
195 bool interfaceHasSuperclass(
const ObjCInterfaceDecl *ID,
196 StringRef ClassName)
const {
197 if (
ID->getIdentifier()->getName() == ClassName)
200 if (
const ObjCInterfaceDecl *Super =
ID->getSuperClass())
201 return interfaceHasSuperclass(Super, ClassName);
214 bool Negated)
const {
217 SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
219 Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
220 : InputState->get<NullImplicationMap>(Antecedent);
227 if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
228 || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
229 SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
230 State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
236 State = State->remove<NonNullImplicationMap>(Antecedent);
237 State = State->remove<NullImplicationMap>(*Consequent);
239 State = State->remove<NullImplicationMap>(Antecedent);
240 State = State->remove<NonNullImplicationMap>(*Consequent);
254bool ento::shouldRegisterTrustNonnullChecker(
const CheckerManager &mgr) {
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
DeclContext * getDeclContext()
QualType getReturnType() const
bool isAnyPointerType() const
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
SVal getReturnValue() const
Returns the return value of the call.
ASTContext & getASTContext() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
bool isConstrainedTrue() const
Return true if the constraint is perfectly constrained to 'true'.
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Selector getSelector() const
DefinedSVal makeSymbolVal(SymbolRef Sym)
Make an SVal that represents the given symbol.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
llvm::iterator_range< symbol_iterator > symbols() const
virtual unsigned computeComplexity() const =0
bool isLive(SymbolRef sym)
Nullability getNullabilityAnnotation(QualType Type)
Get nullability annotation for a given type.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
The JSON file list parser is used to communicate input to InstallAPI.
static Selector getKeywordSelector(ASTContext &Ctx, const IdentifierInfos *...IIs)
bool isa(CodeGen::Address addr)
U cast(CodeGen::Address addr)