30 using namespace clang;
46 class TrustNonnullChecker :
public Checker<check::PostCall,
47 check::PostObjCMessage,
51 static unsigned constexpr ComplexityThreshold = 10;
54 Selector SetObjectForKeyedSubscriptSel;
59 : ObjectForKeyedSubscriptSel(
62 SetObjectForKeyedSubscriptSel(
68 bool Assumption)
const {
69 const SymbolRef CondS = Cond.getAsSymbol();
70 if (!CondS || CondS->computeComplexity() > ComplexityThreshold)
73 for (
auto B=CondS->symbol_begin(), E=CondS->symbol_end(); B != E; ++B) {
75 State = addImplication(Antecedent, State,
true);
76 State = addImplication(Antecedent, State,
false);
82 void checkPostCall(
const CallEvent &Call, CheckerContext &C)
const {
84 if (!Call.isInSystemHeader())
89 if (isNonNullPtr(Call, C))
90 if (
auto L = Call.getReturnValue().getAs<Loc>())
91 State = State->assume(*L,
true);
93 C.addTransition(State);
97 CheckerContext &C)
const {
106 if (interfaceHasSuperclass(ID,
"NSMutableDictionary") &&
107 (Msg.
getSelector() == SetObjectForKeyedSubscriptSel ||
109 if (
auto L = Msg.getArgSVal(1).getAs<Loc>())
110 State = State->assume(*L,
true);
114 if (interfaceHasSuperclass(ID,
"NSDictionary") &&
115 (Msg.
getSelector() == ObjectForKeyedSubscriptSel ||
117 SymbolRef ArgS = Msg.getArgSVal(0).getAsSymbol();
118 SymbolRef RetS = Msg.getReturnValue().getAsSymbol();
123 State = State->set<NonNullImplicationMap>(RetS, ArgS);
127 State = State->set<NullImplicationMap>(ArgS, RetS);
131 C.addTransition(State);
134 void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C)
const {
137 State = dropDeadFromGDM<NullImplicationMap>(SymReaper,
State);
138 State = dropDeadFromGDM<NonNullImplicationMap>(SymReaper,
State);
140 C.addTransition(State);
147 template <
typename MapName>
150 for (
const std::pair<SymbolRef, SymbolRef> &
P : State->get<MapName>())
151 if (!SymReaper.isLive(
P.first) || !SymReaper.isLive(
P.second))
152 State = State->remove<MapName>(
P.first);
158 bool isNonNullPtr(
const CallEvent &Call, CheckerContext &C)
const {
159 QualType ExprRetType = Call.getResultType();
168 if (!isa<ObjCMethodCall>(&Call))
171 const auto *MCall = cast<ObjCMethodCall>(&Call);
175 if (isa<ObjCProtocolDecl>(MD->getDeclContext()))
178 QualType DeclRetType = MD->getReturnType();
184 if (!MCall->isInstanceMessage())
188 SVal Receiver = MCall->getReceiverSVal();
189 ConditionTruthVal TV = C.getState()->isNonNull(Receiver);
190 if (TV.isConstrainedTrue())
198 StringRef ClassName)
const {
203 return interfaceHasSuperclass(Super, ClassName);
216 bool Negated)
const {
219 SValBuilder &SVB = InputState->getStateManager().getSValBuilder();
221 Negated ? InputState->get<NonNullImplicationMap>(Antecedent)
222 : InputState->get<NullImplicationMap>(Antecedent);
226 SVal AntecedentV = SVB.makeSymbolVal(Antecedent);
229 if ((Negated && InputState->isNonNull(AntecedentV).isConstrainedTrue())
230 || (!Negated && InputState->isNull(AntecedentV).isConstrainedTrue())) {
231 SVal ConsequentS = SVB.makeSymbolVal(*Consequent);
232 State = InputState->assume(ConsequentS.castAs<DefinedSVal>(), Negated);
238 State = State->remove<NonNullImplicationMap>(Antecedent);
239 State = State->remove<NullImplicationMap>(*Consequent);
241 State = State->remove<NullImplicationMap>(Antecedent);
242 State = State->remove<NonNullImplicationMap>(*Consequent);
253 void ento::registerTrustNonnullChecker(CheckerManager &Mgr) {
254 Mgr.registerChecker<TrustNonnullChecker>(Mgr.getASTContext());
Smart pointer class that efficiently represents Objective-C method names.
A (possibly-)qualified type.
const SymExpr * SymbolRef
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.
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.
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.