diff --git a/clang/lib/Analysis/CalledOnceCheck.cpp b/clang/lib/Analysis/CalledOnceCheck.cpp --- a/clang/lib/Analysis/CalledOnceCheck.cpp +++ b/clang/lib/Analysis/CalledOnceCheck.cpp @@ -57,6 +57,7 @@ "WithReplyTo", "WithReply"}; constexpr llvm::StringLiteral CONVENTIONAL_CONDITIONS[] = { "error", "cancel", "shouldCall", "done", "OK", "success"}; +constexpr llvm::StringLiteral INIT_PREFIX = "init"; struct KnownCalledOnceParameter { llvm::StringLiteral FunctionName; @@ -1011,11 +1012,16 @@ return llvm::None; } + /// Return true if the specified selector represents init method. + static bool isInitMethod(Selector MethodSelector) { + return MethodSelector.getNameForSlot(0).startswith_lower(INIT_PREFIX); + } + /// Return true if the specified selector piece matches conventions. static bool isConventionalSelectorPiece(Selector MethodSelector, unsigned PieceIndex, QualType PieceType) { - if (!isConventional(PieceType)) { + if (!isConventional(PieceType) || isInitMethod(MethodSelector)) { return false; } diff --git a/clang/test/SemaObjC/warn-called-once.m b/clang/test/SemaObjC/warn-called-once.m --- a/clang/test/SemaObjC/warn-called-once.m +++ b/clang/test/SemaObjC/warn-called-once.m @@ -13,6 +13,7 @@ @protocol NSObject @end @interface NSObject +- (instancetype)init; - (id)copy; - (id)class; - autorelease; @@ -1235,4 +1236,13 @@ handler(); // expected-warning{{completion handler is called twice}} } +- (void)initWithAdditions:(int)cond + withCompletion:(void (^)(void))handler { + self = [self init]; + if (self) { + escape(handler); + } + // no-warning +} + @end