blob: 0fae7ddcd38f4ec84485b4f6842bd32e394248d6 [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
16#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
17#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
18#include "clang/Analysis/PathSensitive/ValueState.h"
19#include "clang/Analysis/PathSensitive/AnnotatedPath.h"
20#include "clang/Analysis/PathDiagnostic.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/ASTContext.h"
23#include "llvm/Support/Compiler.h"
24
25#include <vector>
26
27using namespace clang;
28
29namespace {
30
31class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
32
33 ASTContext &Ctx;
34 ValueStateManager* VMgr;
35 std::list<AnnotatedPath<ValueState> > Errors;
36
37 RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
38
39 bool isNSString(ObjCInterfaceType* T, const char* suffix);
40 bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
41
42 void RegisterError(NodeTy* N, Expr* E, const char *msg);
43
44public:
45 BasicObjCFoundationChecks(ASTContext& ctx, ValueStateManager* vmgr)
46 : Ctx(ctx), VMgr(vmgr) {}
47
48 virtual ~BasicObjCFoundationChecks() {}
49
50 virtual bool Audit(ExplodedNode<ValueState>* N);
51};
52
53} // end anonymous namespace
54
55
56bool BasicObjCFoundationChecks::Audit(ExplodedNode<ValueState>* N) {
57
58 ObjCMessageExpr* ME =
59 cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
60
61 Expr* Receiver = ME->getReceiver();
62
63 if (!Receiver)
64 return false;
65
66 assert (Receiver->getType()->isPointerType());
67
68 const PointerType* T = Receiver->getType()->getAsPointerType();
69
70 ObjCInterfaceType* ReceiverType =
71 dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
72
73 if (!ReceiverType)
74 return false;
75
76 const char* name = ReceiverType->getDecl()->getIdentifier()->getName();
77
78 if (name[0] != 'N' || name[1] != 'S')
79 return false;
80
81 name += 2;
82
83 // FIXME: Make all of this faster.
84
85 if (isNSString(ReceiverType, name))
86 return AuditNSString(N, ME);
87
88 return false;
89}
90
91//===----------------------------------------------------------------------===//
92// Error reporting.
93//===----------------------------------------------------------------------===//
94
95
96void BasicObjCFoundationChecks::RegisterError(NodeTy* N,
97 Expr* E, const char *msg) {
98
99 Errors.push_back(AnnotatedPath<ValueState>());
100 Errors.back().push_back(N, msg, E);
101}
102
103//===----------------------------------------------------------------------===//
104// NSString checking.
105//===----------------------------------------------------------------------===//
106
107bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
108 const char* suffix) {
109
110 return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
111}
112
113bool BasicObjCFoundationChecks::AuditNSString(NodeTy* N,
114 ObjCMessageExpr* ME) {
115
116 Selector S = ME->getSelector();
117
118 if (S.isUnarySelector())
119 return false;
120
121 // FIXME: This is going to be really slow doing these checks with
122 // lexical comparisons.
123
124 std::string name = S.getName();
125 ValueState* St = N->getState();
126
127 if (name == "compare:") {
128 // Check if the compared NSString is nil.
129 Expr * E = ME->getArg(0);
130 RVal X = GetRVal(St, E);
131
132 if (isa<lval::ConcreteInt>(X)) {
133 RegisterError(N, E,
134 "Argument to NSString method 'compare:' cannot be nil.");
135 }
136 }
137
138 return false;
139}