本文整理汇总了C++中ObjCMethodCall::getOriginExpr方法的典型用法代码示例。如果您正苦于以下问题:C++ ObjCMethodCall::getOriginExpr方法的具体用法?C++ ObjCMethodCall::getOriginExpr怎么用?C++ ObjCMethodCall::getOriginExpr使用的例子?那么, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类ObjCMethodCall
的用法示例。
在下文中一共展示了ObjCMethodCall::getOriginExpr方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: HandleNilReceiver
void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ProgramStateRef state,
const ObjCMethodCall &Msg) const {
ASTContext &Ctx = C.getASTContext();
static CheckerProgramPointTag Tag(this, "NilReceiver");
// Check the return type of the message expression. A message to nil will
// return different values depending on the return type and the architecture.
QualType RetTy = Msg.getResultType();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
const LocationContext *LCtx = C.getLocationContext();
if (CanRetTy->isStructureOrClassType()) {
// Structure returns are safe since the compiler zeroes them out.
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
// Other cases: check if sizeof(return type) > sizeof(void*)
if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
.isConsumedExpr(Msg.getOriginExpr())) {
// Compute: sizeof(void *) and sizeof(return type)
const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
if (CanRetTy.getTypePtr()->isReferenceType()||
(voidPtrSize < returnTypeSize &&
!(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
(Ctx.FloatTy == CanRetTy ||
Ctx.DoubleTy == CanRetTy ||
Ctx.LongDoubleTy == CanRetTy ||
Ctx.LongLongTy == CanRetTy ||
Ctx.UnsignedLongLongTy == CanRetTy)))) {
if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
emitNilReceiverBug(C, Msg, N);
return;
}
// Handle the safe cases where the return value is 0 if the
// receiver is nil.
//
// FIXME: For now take the conservative approach that we only
// return null values if we *know* that the receiver is nil.
// This is because we can have surprises like:
//
// ... = [[NSScreens screens] objectAtIndex:0];
//
// What can happen is that [... screens] could return nil, but
// it most likely isn't nil. We should assume the semantics
// of this case unless we have *a lot* more knowledge.
//
SVal V = C.getSValBuilder().makeZeroVal(RetTy);
C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
return;
}
C.addTransition(state);
}
示例2: checkPostObjCMessage
void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C)
const {
ProgramStateRef State = C.getState();
if (!Initialized) {
ASTContext &Ctx = C.getASTContext();
ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx);
ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx);
NullSelector = GetNullarySelector("null", Ctx);
}
// Check the receiver type.
if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) {
// Assume that object returned from '[self init]' or '[super init]' is not
// 'nil' if we are processing an inlined function/method.
//
// A defensive callee will (and should) check if the object returned by
// '[super init]' is 'nil' before doing it's own initialization. However,
// since 'nil' is rarely returned in practice, we should not warn when the
// caller to the defensive constructor uses the object in contexts where
// 'nil' is not accepted.
if (!C.inTopFrame() && M.getDecl() &&
M.getDecl()->getMethodFamily() == OMF_init &&
M.isReceiverSelfOrSuper()) {
State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
FoundationClass Cl = findKnownClass(Interface);
// Objects returned from
// [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript]
// are never 'nil'.
if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) {
Selector Sel = M.getSelector();
if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) {
// Go ahead and assume the value is non-nil.
State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
}
// Objects returned from [NSNull null] are not nil.
if (Cl == FC_NSNull) {
if (M.getSelector() == NullSelector) {
// Go ahead and assume the value is non-nil.
State = assumeExprIsNonNull(M.getOriginExpr(), State, C);
}
}
}
C.addTransition(State);
}
示例3: emitNilReceiverBug
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
const ObjCMethodCall &msg,
ExplodedNode *N) const {
if (!BT_msg_ret)
BT_msg_ret.reset(
new BuiltinBug(this, "Receiver in message expression is 'nil'"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
QualType ResTy = msg.getResultType();
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '";
ME->getSelector().print(os);
os << "' is nil";
if (ResTy->isReferenceType()) {
os << ", which results in forming a null reference";
} else {
os << " and returns a value of type '";
msg.getResultType().print(os, C.getLangOpts());
os << "' that will be garbage";
}
auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
report->addRange(ME->getReceiverRange());
// FIXME: This won't track "self" in messages to super.
if (const Expr *receiver = ME->getInstanceReceiver()) {
bugreporter::trackNullOrUndefValue(N, receiver, *report);
}
C.emitReport(std::move(report));
}
示例4: checkPostObjCMessage
void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
CheckerContext &C) const {
// When encountering a message that does initialization (init rule),
// tag the return value so that we know later on that if self has this value
// then it is properly initialized.
// FIXME: A callback should disable checkers at the start of functions.
if (!shouldRunOnFunctionOrMethod(dyn_cast<NamedDecl>(
C.getCurrentAnalysisDeclContext()->getDecl())))
return;
if (isInitMessage(Msg)) {
// Tag the return value as the result of an initializer.
ProgramStateRef state = C.getState();
// FIXME this really should be context sensitive, where we record
// the current stack frame (for IPA). Also, we need to clean this
// value out when we return from this method.
state = state->set<CalledInit>(true);
SVal V = state->getSVal(Msg.getOriginExpr(), C.getLocationContext());
addSelfFlag(state, V, SelfFlag_InitRes, C);
return;
}
// We don't check for an invalid 'self' in an obj-c message expression to cut
// down false positives where logging functions get information from self
// (like its class) or doing "invalidation" on self when the initialization
// fails.
}
示例5: checkPreObjCMessage
void ObjCSuperDeallocChecker::checkPreObjCMessage(const ObjCMethodCall &M,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
SymbolRef ReceiverSymbol = M.getReceiverSVal().getAsSymbol();
if (!ReceiverSymbol) {
diagnoseCallArguments(M, C);
return;
}
bool AlreadyCalled = State->contains<CalledSuperDealloc>(ReceiverSymbol);
if (!AlreadyCalled)
return;
StringRef Desc;
if (isSuperDeallocMessage(M)) {
Desc = "[super dealloc] should not be called multiple times";
} else {
Desc = StringRef();
}
reportUseAfterDealloc(ReceiverSymbol, Desc, M.getOriginExpr(), C);
return;
}
示例6: emitNilReceiverBug
void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
const ObjCMethodCall &msg,
ExplodedNode *N) const {
if (!BT_msg_ret)
BT_msg_ret.reset(
new BuiltinBug("Receiver in message expression is "
"'nil' and returns a garbage value"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
SmallString<200> buf;
llvm::raw_svector_ostream os(buf);
os << "The receiver of message '" << ME->getSelector().getAsString()
<< "' is nil and returns a value of type '";
msg.getResultType().print(os, C.getLangOpts());
os << "' that will be garbage";
BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
report->addRange(ME->getReceiverRange());
// FIXME: This won't track "self" in messages to super.
if (const Expr *receiver = ME->getInstanceReceiver()) {
report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
receiver,
report));
}
C.EmitReport(report);
}
示例7: isSuperDeallocMessage
/// Returns true if M is a call to '[super dealloc]'.
bool ObjCDeallocChecker::isSuperDeallocMessage(
const ObjCMethodCall &M) const {
if (M.getOriginExpr()->getReceiverKind() != ObjCMessageExpr::SuperInstance)
return false;
return M.getSelector() == DeallocSel;
}
示例8: diagnoseMistakenDealloc
/// Emits a warning if the current context is -dealloc and DeallocedValue
/// must not be directly dealloced in a -dealloc. Returns true if a diagnostic
/// was emitted.
bool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue,
const ObjCMethodCall &M,
CheckerContext &C) const {
// Find the property backing the instance variable that M
// is dealloc'ing.
const ObjCPropertyImplDecl *PropImpl =
findPropertyOnDeallocatingInstance(DeallocedValue, C);
if (!PropImpl)
return false;
if (getDeallocReleaseRequirement(PropImpl) !=
ReleaseRequirement::MustRelease) {
return false;
}
ExplodedNode *ErrNode = C.generateErrorNode();
if (!ErrNode)
return false;
std::string Buf;
llvm::raw_string_ostream OS(Buf);
OS << "'" << *PropImpl->getPropertyIvarDecl()
<< "' should be released rather than deallocated";
std::unique_ptr<BugReport> BR(
new BugReport(*MistakenDeallocBugType, OS.str(), ErrNode));
BR->addRange(M.getOriginExpr()->getSourceRange());
C.emitReport(std::move(BR));
return true;
}
示例9: checkPostObjCMessage
void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C) const {
if (!M.isInstanceMessage())
return;
const ObjCInterfaceDecl *ClassID = M.getReceiverInterface();
if (!ClassID)
return;
FoundationClass Class = findKnownClass(ClassID);
if (Class != FC_NSDictionary &&
Class != FC_NSArray &&
Class != FC_NSSet)
return;
SymbolRef ContainerS = M.getReceiverSVal().getAsSymbol();
if (!ContainerS)
return;
// If we are processing a call to "count", get the symbolic value returned by
// a call to "count" and add it to the map.
if (!isCollectionCountMethod(M, C))
return;
const Expr *MsgExpr = M.getOriginExpr();
SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
if (CountS) {
ProgramStateRef State = C.getState();
C.getSymbolManager().addSymbolDependency(ContainerS, CountS);
State = State->set<ContainerCountMap>(ContainerS, CountS);
C.addTransition(State);
}
return;
}
示例10: checkPreObjCMessage
void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
SVal recVal = msg.getReceiverSVal();
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateSink()) {
BugType *BT = 0;
switch (msg.getMessageKind()) {
case OCM_Message:
if (!BT_msg_undef)
BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
"is an uninitialized value"));
BT = BT_msg_undef.get();
break;
case OCM_PropertyAccess:
if (!BT_objc_prop_undef)
BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
"uninitialized object "
"pointer"));
BT = BT_objc_prop_undef.get();
break;
case OCM_Subscript:
if (!BT_objc_subscript_undef)
BT_objc_subscript_undef.reset(new BuiltinBug("Subscript access on an "
"uninitialized object "
"pointer"));
BT = BT_objc_subscript_undef.get();
break;
}
assert(BT && "Unknown message kind.");
BugReport *R = new BugReport(*BT, BT->getName(), N);
const ObjCMessageExpr *ME = msg.getOriginExpr();
R->addRange(ME->getReceiverRange());
// FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
if (const Expr *ReceiverE = ME->getInstanceReceiver())
R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
ReceiverE,
R));
C.EmitReport(R);
}
return;
} else {
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
ProgramStateRef state = C.getState();
ProgramStateRef notNilState, nilState;
llvm::tie(notNilState, nilState) = state->assume(receiverVal);
// Handle receiver must be nil.
if (nilState && !notNilState) {
HandleNilReceiver(C, state, msg);
return;
}
}
}
示例11: initIdentifierInfoAndSelectors
bool
ObjCSuperDeallocChecker::isSuperDeallocMessage(const ObjCMethodCall &M) const {
if (M.getOriginExpr()->getReceiverKind() != ObjCMessageExpr::SuperInstance)
return false;
ASTContext &Ctx = M.getState()->getStateManager().getContext();
initIdentifierInfoAndSelectors(Ctx);
return M.getSelector() == SELdealloc;
}
示例12: checkPreObjCMessage
void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const {
SVal recVal = msg.getReceiverSVal();
if (recVal.isUndef()) {
if (ExplodedNode *N = C.generateErrorNode()) {
BugType *BT = nullptr;
switch (msg.getMessageKind()) {
case OCM_Message:
if (!BT_msg_undef)
BT_msg_undef.reset(new BuiltinBug(this,
"Receiver in message expression "
"is an uninitialized value"));
BT = BT_msg_undef.get();
break;
case OCM_PropertyAccess:
if (!BT_objc_prop_undef)
BT_objc_prop_undef.reset(new BuiltinBug(
this, "Property access on an uninitialized object pointer"));
BT = BT_objc_prop_undef.get();
break;
case OCM_Subscript:
if (!BT_objc_subscript_undef)
BT_objc_subscript_undef.reset(new BuiltinBug(
this, "Subscript access on an uninitialized object pointer"));
BT = BT_objc_subscript_undef.get();
break;
}
assert(BT && "Unknown message kind.");
auto R = llvm::make_unique<BugReport>(*BT, BT->getName(), N);
const ObjCMessageExpr *ME = msg.getOriginExpr();
R->addRange(ME->getReceiverRange());
// FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
if (const Expr *ReceiverE = ME->getInstanceReceiver())
bugreporter::trackExpressionValue(N, ReceiverE, *R);
C.emitReport(std::move(R));
}
return;
}
}
示例13: checkPostObjCMessage
/// This callback is used to infer the types for Class variables. This info is
/// used later to validate messages that sent to classes. Class variables are
/// initialized with by invoking the 'class' method on a class.
/// This method is also used to infer the type information for the return
/// types.
// TODO: right now it only tracks generic types. Extend this to track every
// type in the DynamicTypeMap and diagnose type errors!
void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
CheckerContext &C) const {
const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
SymbolRef RetSym = M.getReturnValue().getAsSymbol();
if (!RetSym)
return;
Selector Sel = MessageExpr->getSelector();
ProgramStateRef State = C.getState();
// Inference for class variables.
// We are only interested in cases where the class method is invoked on a
// class. This method is provided by the runtime and available on all classes.
if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class &&
Sel.getAsString() == "class") {
QualType ReceiverType = MessageExpr->getClassReceiver();
const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>();
QualType ReceiverClassPointerType =
C.getASTContext().getObjCObjectPointerType(
QualType(ReceiverClassType, 0));
if (!ReceiverClassType->isSpecialized())
return;
const auto *InferredType =
ReceiverClassPointerType->getAs<ObjCObjectPointerType>();
assert(InferredType);
State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType);
C.addTransition(State);
return;
}
// Tracking for return types.
SymbolRef RecSym = M.getReceiverSVal().getAsSymbol();
if (!RecSym)
return;
const ObjCObjectPointerType *const *TrackedType =
State->get<MostSpecializedTypeArgsMap>(RecSym);
if (!TrackedType)
return;
ASTContext &ASTCtxt = C.getASTContext();
const ObjCMethodDecl *Method =
findMethodDecl(MessageExpr, *TrackedType, ASTCtxt);
if (!Method)
return;
Optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
if (!TypeArgs)
return;
QualType ResultType =
getReturnTypeForMethod(Method, *TypeArgs, *TrackedType, ASTCtxt);
// The static type is the same as the deduced type.
if (ResultType.isNull())
return;
const MemRegion *RetRegion = M.getReturnValue().getAsRegion();
ExplodedNode *Pred = C.getPredecessor();
// When there is an entry available for the return symbol in DynamicTypeMap,
// the call was inlined, and the information in the DynamicTypeMap is should
// be precise.
if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) {
// TODO: we have duplicated information in DynamicTypeMap and
// MostSpecializedTypeArgsMap. We should only store anything in the later if
// the stored data differs from the one stored in the former.
State = setDynamicTypeInfo(State, RetRegion, ResultType,
/*CanBeSubclass=*/true);
Pred = C.addTransition(State);
}
const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>();
if (!ResultPtrType || ResultPtrType->isUnspecialized())
return;
// When the result is a specialized type and it is not tracked yet, track it
// for the result symbol.
if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) {
State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType);
C.addTransition(State, Pred);
}
}
示例14: checkPreObjCMessage
/// When the receiver has a tracked type, use that type to validate the
/// argumments of the message expression and the return value.
void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
SymbolRef Sym = M.getReceiverSVal().getAsSymbol();
if (!Sym)
return;
const ObjCObjectPointerType *const *TrackedType =
State->get<MostSpecializedTypeArgsMap>(Sym);
if (!TrackedType)
return;
// Get the type arguments from tracked type and substitute type arguments
// before do the semantic check.
ASTContext &ASTCtxt = C.getASTContext();
const ObjCMessageExpr *MessageExpr = M.getOriginExpr();
const ObjCMethodDecl *Method =
findMethodDecl(MessageExpr, *TrackedType, ASTCtxt);
// It is possible to call non-existent methods in Obj-C.
if (!Method)
return;
Optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
// This case might happen when there is an unspecialized override of a
// specialized method.
if (!TypeArgs)
return;
for (unsigned i = 0; i < Method->param_size(); i++) {
const Expr *Arg = MessageExpr->getArg(i);
const ParmVarDecl *Param = Method->parameters()[i];
QualType OrigParamType = Param->getType();
if (!isObjCTypeParamDependent(OrigParamType))
continue;
QualType ParamType = OrigParamType.substObjCTypeArgs(
ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter);
// Check if it can be assigned
const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>();
const auto *ArgObjectPtrType =
stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>();
if (!ParamObjectPtrType || !ArgObjectPtrType)
continue;
// Check if we have more concrete tracked type that is not a super type of
// the static argument type.
SVal ArgSVal = M.getArgSVal(i);
SymbolRef ArgSym = ArgSVal.getAsSymbol();
if (ArgSym) {
const ObjCObjectPointerType *const *TrackedArgType =
State->get<MostSpecializedTypeArgsMap>(ArgSym);
if (TrackedArgType &&
ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) {
ArgObjectPtrType = *TrackedArgType;
}
}
// Warn when argument is incompatible with the parameter.
if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType,
ArgObjectPtrType)) {
static CheckerProgramPointTag Tag(this, "ArgTypeMismatch");
ExplodedNode *N = C.addTransition(State, &Tag);
reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg);
return;
}
}
}
示例15: diagnoseExtraRelease
/// Emits a warning if the current context is -dealloc and ReleasedValue
/// must not be directly released in a -dealloc. Returns true if a diagnostic
/// was emitted.
bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue,
const ObjCMethodCall &M,
CheckerContext &C) const {
// Try to get the region from which the released value was loaded.
// Note that, unlike diagnosing for missing releases, here we don't track
// values that must not be released in the state. This is because even if
// these values escape, it is still an error under the rules of MRR to
// release them in -dealloc.
const ObjCPropertyImplDecl *PropImpl =
findPropertyOnDeallocatingInstance(ReleasedValue, C);
if (!PropImpl)
return false;
// If the ivar belongs to a property that must not be released directly
// in dealloc, emit a warning.
if (getDeallocReleaseRequirement(PropImpl) !=
ReleaseRequirement::MustNotReleaseDirectly) {
return false;
}
// If the property is readwrite but it shadows a read-only property in its
// external interface, treat the property a read-only. If the outside
// world cannot write to a property then the internal implementation is free
// to make its own convention about whether the value is stored retained
// or not. We look up the shadow here rather than in
// getDeallocReleaseRequirement() because doing so can be expensive.
const ObjCPropertyDecl *PropDecl = findShadowedPropertyDecl(PropImpl);
if (PropDecl) {
if (PropDecl->isReadOnly())
return false;
} else {
PropDecl = PropImpl->getPropertyDecl();
}
ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
if (!ErrNode)
return false;
std::string Buf;
llvm::raw_string_ostream OS(Buf);
assert(PropDecl->getSetterKind() == ObjCPropertyDecl::Weak ||
(PropDecl->getSetterKind() == ObjCPropertyDecl::Assign &&
!PropDecl->isReadOnly()) ||
isReleasedByCIFilterDealloc(PropImpl)
);
const ObjCImplDecl *Container = getContainingObjCImpl(C.getLocationContext());
OS << "The '" << *PropImpl->getPropertyIvarDecl()
<< "' ivar in '" << *Container;
if (isReleasedByCIFilterDealloc(PropImpl)) {
OS << "' will be released by '-[CIFilter dealloc]' but also released here";
} else {
OS << "' was synthesized for ";
if (PropDecl->getSetterKind() == ObjCPropertyDecl::Weak)
OS << "a weak";
else
OS << "an assign, readwrite";
OS << " property but was released in 'dealloc'";
}
std::unique_ptr<BugReport> BR(
new BugReport(*ExtraReleaseBugType, OS.str(), ErrNode));
BR->addRange(M.getOriginExpr()->getSourceRange());
C.emitReport(std::move(BR));
return true;
}