29 using namespace clang;
45 class TrustNonnullChecker :
public Checker<check::PostCall,
46 check::PostObjCMessage,
50 static unsigned constexpr ComplexityThreshold = 10;
53 Selector SetObjectForKeyedSubscriptSel;
58 : ObjectForKeyedSubscriptSel(
61 SetObjectForKeyedSubscriptSel(
67 bool Assumption)
const {
68 const SymbolRef CondS = Cond.getAsSymbol();
69 if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
72 for (
auto B=CondS->symbol_begin(), E=CondS->symbol_end(); B != E; ++B) {
74 State = addImplication(Antecedent, State,
true);
75 State = addImplication(Antecedent, State,
false);
81 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const {
83 if (!Call.isInSystemHeader())
88 if (isNonNullPtr(Call, C))
89 if (
auto L = Call.getReturnValue().getAs<Loc>())
90 State = State->assume(*L,
true);
92 C.addTransition(State);
96 CheckerContext &C)
const {
105 if (interfaceHasSuperclass(ID,
"NSMutableDictionary") &&
106 (Msg.
getSelector() == SetObjectForKeyedSubscriptSel ||
108 if (
auto L = Msg.getArgSVal(1).getAs<Loc>())
109 State = State->assume(*L,
true);
113 if (interfaceHasSuperclass(ID,
"NSDictionary") &&
114 (Msg.
getSelector() == ObjectForKeyedSubscriptSel ||
116 SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
117 SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
122 State = State->set<NonNullImplicationMap>(RetS, ArgS);
126 State = State->set<NullImplicationMap>(ArgS, RetS);
130 C.addTransition(State);
133 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const {
136 State = dropDeadFromGDM<NullImplicationMap>(SymReaper,
State);
137 State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper,
State);
139 C.addTransition(State);
146 template <
typename MapName>
149 for (
const std::pair<SymbolRef, SymbolRef> &
P : State->get<MapName>())
150 if (!SymReaper.isLive(
P.first) || !SymReaper.isLive(
P.second))
151 State = State->remove<MapName>(
P.first);
157 bool isNonNullPtr(
const CallEvent &Call, CheckerContext &C)
const {
158 QualType ExprRetType = Call.getResultType();
167 if (!isa<ObjCMethodCall>(&Call))
170 const auto *MCall = cast<ObjCMethodCall>(&Call);
174 if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
177 QualType DeclRetType = MD->getReturnType();
183 if (!MCall->isInstanceMessage())
187 SVal Receiver = MCall->getReceiverSVal();
188 ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
189 if (TV.isConstrainedTrue())
197 StringRef ClassName)
const {
202 return interfaceHasSuperclass(Super, ClassName);
215 bool Negated)
const {
218 SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
220 Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
221 : InputState->get<NullImplicationMap>(Antecedent);
225 SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
228 if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
229 || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
230 SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
231 State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
237 State = State->remove<NonNullImplicationMap>(Antecedent);
238 State = State->remove<NullImplicationMap>(*Consequent);
240 State = State->remove<NullImplicationMap>(Antecedent);
241 State = State->remove<NonNullImplicationMap>(*Consequent);
251 void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
252 Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
255 bool ento::shouldRegisterTrustNonnullChecker(
const LangOptions &LO) {
Smart pointer class that efficiently represents Objective-C method names.
A (possibly-)qualified type.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
ObjCMethodDecl - Represents an instance or class method declaration.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
const SymExpr * SymbolRef
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ObjCInterfaceDecl * getReceiverInterface() const
Get the interface for the receiver.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Represents any expression that calls an Objective-C method.
Represents an ObjC class declaration.
ObjCInterfaceDecl * getSuperClass() const
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
static Selector getKeywordSelector(ASTContext &Ctx, IdentifierInfos *... IIs)
bool isAnyPointerType() const
StringRef getName() const
Return the actual identifier string.
Selector getSelector() const
Dataflow Directional Tag Classes.
Nullability getNullabilityAnnotation(QualType Type)
Get nullability annotation for a given type.