18b3f9386STed Kremenek //= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- C++ -*---
28b3f9386STed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68b3f9386STed Kremenek //
78b3f9386STed Kremenek //===----------------------------------------------------------------------===//
88b3f9386STed Kremenek //
98b3f9386STed Kremenek // This file implements special handling of recognizing ObjC API hooks that
108b3f9386STed Kremenek // do not return but aren't marked as such in API headers.
118b3f9386STed Kremenek //
128b3f9386STed Kremenek //===----------------------------------------------------------------------===//
138b3f9386STed Kremenek
148b3f9386STed Kremenek #include "clang/AST/ASTContext.h"
158b3f9386STed Kremenek #include "clang/AST/ExprObjC.h"
168b3f9386STed Kremenek #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
178b3f9386STed Kremenek
188b3f9386STed Kremenek using namespace clang;
198b3f9386STed Kremenek
isSubclass(const ObjCInterfaceDecl * Class,IdentifierInfo * II)208b3f9386STed Kremenek static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
218b3f9386STed Kremenek if (!Class)
228b3f9386STed Kremenek return false;
238b3f9386STed Kremenek if (Class->getIdentifier() == II)
248b3f9386STed Kremenek return true;
258b3f9386STed Kremenek return isSubclass(Class->getSuperClass(), II);
268b3f9386STed Kremenek }
278b3f9386STed Kremenek
ObjCNoReturn(ASTContext & C)288b3f9386STed Kremenek ObjCNoReturn::ObjCNoReturn(ASTContext &C)
298b3f9386STed Kremenek : RaiseSel(GetNullarySelector("raise", C)),
308b3f9386STed Kremenek NSExceptionII(&C.Idents.get("NSException"))
318b3f9386STed Kremenek {
328b3f9386STed Kremenek // Generate selectors.
338b3f9386STed Kremenek SmallVector<IdentifierInfo*, 3> II;
348b3f9386STed Kremenek
358b3f9386STed Kremenek // raise:format:
368b3f9386STed Kremenek II.push_back(&C.Idents.get("raise"));
378b3f9386STed Kremenek II.push_back(&C.Idents.get("format"));
388b3f9386STed Kremenek NSExceptionInstanceRaiseSelectors[0] =
398b3f9386STed Kremenek C.Selectors.getSelector(II.size(), &II[0]);
408b3f9386STed Kremenek
418b3f9386STed Kremenek // raise:format:arguments:
428b3f9386STed Kremenek II.push_back(&C.Idents.get("arguments"));
438b3f9386STed Kremenek NSExceptionInstanceRaiseSelectors[1] =
448b3f9386STed Kremenek C.Selectors.getSelector(II.size(), &II[0]);
458b3f9386STed Kremenek }
468b3f9386STed Kremenek
478b3f9386STed Kremenek
isImplicitNoReturn(const ObjCMessageExpr * ME)488b3f9386STed Kremenek bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
498b3f9386STed Kremenek Selector S = ME->getSelector();
508b3f9386STed Kremenek
518b3f9386STed Kremenek if (ME->isInstanceMessage()) {
528b3f9386STed Kremenek // Check for the "raise" message.
538b3f9386STed Kremenek return S == RaiseSel;
548b3f9386STed Kremenek }
558b3f9386STed Kremenek
568b3f9386STed Kremenek if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
57*7cc8fa2dSKazu Hirata if (isSubclass(ID, NSExceptionII) &&
58*7cc8fa2dSKazu Hirata llvm::is_contained(NSExceptionInstanceRaiseSelectors, S))
598b3f9386STed Kremenek return true;
608b3f9386STed Kremenek }
618b3f9386STed Kremenek
628b3f9386STed Kremenek return false;
638b3f9386STed Kremenek }
64