diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 72e614d3e769e9118fc7937f614ff148f99da2a9..718f54c75aaf0944094e9848e89ecbc3ff98b548 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -178,6 +178,9 @@ private: /// \sa mayInlineTemplateFunctions llvm::Optional InlineTemplateFunctions; + /// \sa mayInlineObjCMethod + llvm::Optional ObjCInliningMode; + // Cache of the "ipa-always-inline-size" setting. // \sa getAlwaysInlineSize llvm::Optional AlwaysInlineSize; @@ -200,6 +203,9 @@ public: /// \sa CXXMemberInliningMode bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const; + /// Returns true if ObjectiveC inlining is enabled, false otherwise. + bool mayInlineObjCMethod() const; + /// Returns whether or not the destructors for C++ temporary objects should /// be included in the CFG. /// diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 5cbbb8d46285fed9d54142b5cf6954d63ff1902a..9e029c7e298a0554deba502ce4bb3ffb38a6b1e2 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -82,6 +82,14 @@ bool AnalyzerOptions::mayInlineTemplateFunctions() const { return *InlineTemplateFunctions; } +bool AnalyzerOptions::mayInlineObjCMethod() const { + if (!ObjCInliningMode.hasValue()) + const_cast &>(ObjCInliningMode) = + getBooleanOption("objc-inlining", /*Default=*/true); + + return *ObjCInliningMode; +} + int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) const { std::string OptStr = Config.lookup(Name); if (OptStr.empty()) @@ -97,9 +105,8 @@ int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) const { unsigned AnalyzerOptions::getAlwaysInlineSize() const { if (!AlwaysInlineSize.hasValue()) { unsigned DefaultSize = 3; - Optional &MutableOption = - const_cast &>(AlwaysInlineSize); - MutableOption = getOptionAsInteger("ipa-always-inline-size", DefaultSize); + const_cast &>(AlwaysInlineSize) = + getOptionAsInteger("ipa-always-inline-size", DefaultSize); } return AlwaysInlineSize.getValue(); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index a4e1eb2f4ccb86b14bced5a76bbbcb1d047900f4..54c66d37ba7f229af3edaada8beab66a7548dbb2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -448,6 +448,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_ObjCMessage: + if (!Opts.mayInlineObjCMethod()) + return false; if (!(getAnalysisManager().options.IPAMode == DynamicDispatch || getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate)) return false; diff --git a/clang/test/Analysis/inlining/test_objc_inlining_option.m b/clang/test/Analysis/inlining/test_objc_inlining_option.m new file mode 100644 index 0000000000000000000000000000000000000000..963b572b1e3f56c3078e759daac8847096ec3bf2 --- /dev/null +++ b/clang/test/Analysis/inlining/test_objc_inlining_option.m @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-ipa=dynamic-bifurcate -analyzer-config objc-inlining=false -verify %s + +typedef signed char BOOL; +typedef struct objc_class *Class; +typedef struct objc_object { + Class isa; +} *id; +@protocol NSObject - (BOOL)isEqual:(id)object; @end +@interface NSObject {} ++(id)alloc; +-(id)init; +-(id)autorelease; +-(id)copy; +- (Class)class; +-(id)retain; +@end + +// Vanila: ObjC class method is called by name. +@interface MyParent : NSObject ++ (int)getInt; +@end +@interface MyClass : MyParent ++ (int)getInt; +@end +@implementation MyClass ++ (int)testClassMethodByName { + int y = [MyClass getInt]; + return 5/y; // no-warning +} ++ (int)getInt { + return 0; +} +@end \ No newline at end of file