Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 1 | //=- 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" |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 20 | #include "clang/Analysis/PathSensitive/GRExprEngine.h" |
| 21 | #include "BasicObjCFoundationChecks.h" |
| 22 | #include "llvm/Support/Compiler.h" |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 23 | #include "clang/AST/DeclObjC.h" |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 24 | #include "clang/AST/Decl.h" |
| 25 | #include "llvm/ADT/SmallVector.h" |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 26 | |
| 27 | using namespace clang; |
| 28 | |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 29 | namespace { |
| 30 | class VISIBILITY_HIDDEN NSErrorCheck : public BugTypeCacheLocation { |
| 31 | |
| 32 | void EmitGRWarnings(GRBugReporter& BR); |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 33 | |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 34 | void CheckSignature(ObjCMethodDecl& MD, QualType& ResultTy, |
| 35 | llvm::SmallVectorImpl<VarDecl*>& Params, |
| 36 | IdentifierInfo* NSErrorII); |
| 37 | |
| 38 | bool CheckArgument(QualType ArgTy, IdentifierInfo* NSErrorII); |
| 39 | |
| 40 | public: |
| 41 | void EmitWarnings(BugReporter& BR) { EmitGRWarnings(cast<GRBugReporter>(BR));} |
| 42 | const char* getName() const { return "NSError** null dereference"; } |
| 43 | }; |
| 44 | |
| 45 | } // end anonymous namespace |
| 46 | |
| 47 | BugType* clang::CreateNSErrorCheck() { |
| 48 | return new NSErrorCheck(); |
| 49 | } |
| 50 | |
| 51 | void NSErrorCheck::EmitGRWarnings(GRBugReporter& BR) { |
| 52 | // Get the analysis engine and the exploded analysis graph. |
| 53 | GRExprEngine& Eng = BR.getEngine(); |
| 54 | GRExprEngine::GraphTy& G = Eng.getGraph(); |
| 55 | |
| 56 | // Get the declaration of the method/function that was analyzed. |
| 57 | Decl& CodeDecl = G.getCodeDecl(); |
| 58 | |
| 59 | ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl); |
| 60 | if (!MD) |
| 61 | return; |
| 62 | |
| 63 | // Get the ASTContext, which is useful for querying type information. |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 64 | ASTContext &Ctx = BR.getContext(); |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 65 | |
| 66 | QualType ResultTy; |
| 67 | llvm::SmallVector<VarDecl*, 5> Params; |
| 68 | CheckSignature(*MD, ResultTy, Params, &Ctx.Idents.get("NSError")); |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 69 | |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 70 | if (Params.empty()) |
| 71 | return; |
| 72 | |
| 73 | if (ResultTy == Ctx.VoidTy) { |
| 74 | BR.EmitBasicReport("Bad return type when passing NSError**", |
| 75 | "Method accepting NSError** argument should have " |
| 76 | "non-void return value to indicate that an error occurred.", |
| 77 | CodeDecl.getLocation()); |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 78 | |
Ted Kremenek | f45d18c | 2008-09-18 06:33:41 +0000 | [diff] [blame] | 79 | } |
| 80 | } |
Ted Kremenek | cfdf9b4 | 2008-09-18 21:25:13 +0000 | [diff] [blame] | 81 | |
| 82 | void NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy, |
| 83 | llvm::SmallVectorImpl<VarDecl*>& Params, |
| 84 | IdentifierInfo* NSErrorII) { |
| 85 | |
| 86 | ResultTy = M.getResultType(); |
| 87 | |
| 88 | for (ObjCMethodDecl::param_iterator I=M.param_begin(), |
| 89 | E=M.param_end(); I!=E; ++I) |
| 90 | if (CheckArgument((*I)->getType(), NSErrorII)) |
| 91 | Params.push_back(*I); |
| 92 | } |
| 93 | |
| 94 | bool NSErrorCheck::CheckArgument(QualType ArgTy, IdentifierInfo* NSErrorII) { |
| 95 | const PointerType* PPT = ArgTy->getAsPointerType(); |
| 96 | if (!PPT) return false; |
| 97 | |
| 98 | const PointerType* PT = PPT->getPointeeType()->getAsPointerType(); |
| 99 | if (!PT) return false; |
| 100 | |
| 101 | const ObjCInterfaceType *IT = |
| 102 | PT->getPointeeType()->getAsObjCInterfaceType(); |
| 103 | |
| 104 | if (!IT) return false; |
| 105 | return IT->getDecl()->getIdentifier() == NSErrorII; |
| 106 | } |