blob: 26386bc2bb6b5ec1f27324e94098d52e619baeae [file] [log] [blame]
Ted Kremenekf45d18c2008-09-18 06:33:41 +00001//=- CheckNSError.cpp - Coding conventions for uses of NSError ---*- 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 a CheckNSError, a flow-insenstive check
11// that determines if an Objective-C class interface correctly returns
12// a non-void return type.
13//
14// File under feature request PR 2600.
15//
16//===----------------------------------------------------------------------===//
17
18#include "clang/Analysis/LocalCheckers.h"
19#include "clang/Analysis/PathSensitive/BugReporter.h"
20#include "clang/AST/DeclObjC.h"
21#include "clang/AST/Type.h"
22#include "clang/AST/ASTContext.h"
23
24using namespace clang;
25
26void clang::CheckNSError(ObjCImplementationDecl* ID, BugReporter& BR) {
27 // Look at the @interface for this class.
28 ObjCInterfaceDecl* D = ID->getClassInterface();
29
30 // Get the ASTContext. Useful for querying type information.
31 ASTContext &Ctx = BR.getContext();
32
33 // Get the IdentifierInfo* for "NSError".
34 IdentifierInfo* NSErrorII = &Ctx.Idents.get("NSError");
35
36 // Scan the methods. See if any of them have an argument of type NSError**.
37 for (ObjCInterfaceDecl::instmeth_iterator I=D->instmeth_begin(),
38 E=D->instmeth_end(); I!=E; ++I) {
39
40 // Get the method declaration.
41 ObjCMethodDecl* M = *I;
42
43 // Check for a non-void return type.
44 if (M->getResultType() != Ctx.VoidTy)
45 continue;
46
47 for (ObjCMethodDecl::param_iterator PI=M->param_begin(),
48 PE=M->param_end(); PI!=PE; ++PI) {
49
50 const PointerType* PPT = (*PI)->getType()->getAsPointerType();
51 if (!PPT) continue;
52
53 const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
54 if (!PT) continue;
55
56 const ObjCInterfaceType *IT =
57 PT->getPointeeType()->getAsObjCInterfaceType();
58
59 if (!IT) continue;
60
61 // Check if IT is "NSError".
62 if (IT->getDecl()->getIdentifier() == NSErrorII) {
63 // Documentation: "Creating and Returning NSError Objects"
64 BR.EmitBasicReport("Bad return type when passing NSError**",
65 "Method accepting NSError** argument should have "
66 "non-void return value to indicate that an error occurred.",
67 M->getLocStart());
68 break;
69 }
70 }
71 }
72}