blob: 4d7a4d99db8b86d5bd2c3c97b576a24472dac245 [file] [log] [blame]
Ted Kremenekb0a2e472008-03-27 07:25:52 +00001//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines BasicObjCFoundationChecks, a class that encapsulates
11// a set of simple checks to run on Objective-C code using Apple's Foundation
12// classes.
13//
14//===----------------------------------------------------------------------===//
15
Ted Kremenek7a681942008-03-27 17:17:22 +000016#include "BasicObjCFoundationChecks.h"
17
Ted Kremenekb0a2e472008-03-27 07:25:52 +000018#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
19#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
20#include "clang/Analysis/PathSensitive/ValueState.h"
21#include "clang/Analysis/PathSensitive/AnnotatedPath.h"
22#include "clang/Analysis/PathDiagnostic.h"
23#include "clang/AST/Expr.h"
24#include "clang/AST/ASTContext.h"
25#include "llvm/Support/Compiler.h"
26
27#include <vector>
28
29using namespace clang;
30
31namespace {
32
33class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
34
35 ASTContext &Ctx;
36 ValueStateManager* VMgr;
37 std::list<AnnotatedPath<ValueState> > Errors;
38
39 RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
40
41 bool isNSString(ObjCInterfaceType* T, const char* suffix);
42 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
43
44 void RegisterError(NodeTy* N, Expr* E, const char *msg);
45
46public:
47 BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
48 : Ctx(ctx), VMgr(vmgr) {}
49
50 virtual ~BasicObjCFoundationChecks() {}
51
52 virtual bool Audit(ExplodedNode<ValueState>* N);
53};
54
55} // end anonymous namespace
56
57
Ted Kremenek7a681942008-03-27 17:17:22 +000058GRSimpleAPICheck*
59clang::CreateBasicObjCFoundationChecks(ASTContext& Ctx,
60 ValueStateManager* VMgr) {
61
62 return new BasicObjCFoundationChecks(Ctx, VMgr);
63}
64
65
Ted Kremenekb0a2e472008-03-27 07:25:52 +000066bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
67
68 ObjCMessageExpr* ME =
69 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
70
71 Expr* Receiver = ME->getReceiver();
72
73 if (!Receiver)
74 return false;
75
76 assert (Receiver->getType()->isPointerType());
77
78 const PointerType* T = Receiver->getType()->getAsPointerType();
79
80 ObjCInterfaceType* ReceiverType =
81 dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
82
83 if (!ReceiverType)
84 return false;
85
86 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
87
88 if (name[0] != 'N' || name[1] != 'S')
89 return false;
90
91 name += 2;
92
93 // FIXME: Make all of this faster.
94
95 if (isNSString(ReceiverType, name))
96 return AuditNSString(N, ME);
97
98 return false;
99}
100
101//===----------------------------------------------------------------------===//
102// Error reporting.
103//===----------------------------------------------------------------------===//
104
105
106void BasicObjCFoundationChecks::RegisterError(NodeTy* N,
107 Expr* E, const char *msg) {
108
109 Errors.push_back(AnnotatedPath<ValueState>());
110 Errors.back().push_back(N, msg, E);
111}
112
113//===----------------------------------------------------------------------===//
114// NSString checking.
115//===----------------------------------------------------------------------===//
116
117bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
118 const char* suffix) {
119
120 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
121}
122
123bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
124 ObjCMessageExpr* ME) {
125
126 Selector S = ME->getSelector();
127
128 if (S.isUnarySelector())
129 return false;
130
131 // FIXME: This is going to be really slow doing these checks with
132 // lexical comparisons.
133
134 std::string name = S.getName();
135 ValueState* St = N->getState();
136
137 if (name == "compare:") {
138 // Check if the compared NSString is nil.
139 Expr * E = ME->getArg(0);
140 RVal X = GetRVal(St, E);
141
142 if (isa<lval::ConcreteInt>(X)) {
143 RegisterError(N, E,
144 "Argument to NSString method 'compare:' cannot be nil.");
145 }
146 }
147
148 return false;
149}