/// Inline C functions and blocks when their definitions are available.
IPAK_BasicInlining = 2,
- /// Inline callees when their definitions are available.
- // TODO: How is this different from BasicInlining?
+ /// Inline callees(C, C++, ObjC) when their definitions are available.
IPAK_Inlining = 3,
/// Enable inlining of dynamically dispatched methods.
AnalysisInliningMode InliningMode;
private:
+ /// \brief Describes the kinds for high-level analyzer mode.
+ enum UserModeKind {
+ UMK_NotSet = 0,
+ /// Perform shallow but fast analyzes.
+ UMK_Shallow = 1,
+ /// Perform deep analyzes.
+ UMK_Deep = 2
+ };
+
+ /// Controls the high-level analyzer mode, which influences the default
+ /// settings for some of the lower-level config options (such as IPAMode).
+ /// \sa getUserMode
+ UserModeKind UserMode;
+
/// Controls the mode of inter-procedural analysis.
IPAKind IPAMode;
int getOptionAsInteger(StringRef Name, int DefaultVal);
public:
+ /// \brief Retrieves and sets the UserMode. This is a high-level option,
+ /// which is used to set other low-level options. It is not accessible
+ /// outside of AnalyzerOptions.
+ UserModeKind getUserMode();
+
/// \brief Returns the inter-procedural analysis mode.
IPAKind getIPAMode();
using namespace clang;
using namespace llvm;
+AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
+ if (UserMode == UMK_NotSet) {
+ StringRef ModeStr(Config.GetOrCreateValue("mode", "deep").getValue());
+ UserMode = llvm::StringSwitch<UserModeKind>(ModeStr)
+ .Case("shallow", UMK_Shallow)
+ .Case("deep", UMK_Deep)
+ .Default(UMK_NotSet);
+ assert(UserMode != UMK_NotSet && "User mode is not set or invalid.");
+ }
+ return UserMode;
+}
+
IPAKind AnalyzerOptions::getIPAMode() {
if (IPAMode == IPAK_NotSet) {
+ // Use the User Mode to set the default IPA value.
+ // Note, we have to add the string to the Config map for the ConfigDumper
+ // checker to function properly.
+ const char *DefaultIPA = 0;
+ UserModeKind HighLevelMode = getUserMode();
+ if (HighLevelMode == UMK_Shallow)
+ DefaultIPA = "basic-inlining";
+ else if (HighLevelMode == UMK_Deep)
+ DefaultIPA = "dynamic-bifurcate";
+ assert(DefaultIPA);
+
// Lookup the ipa configuration option, use the default from User Mode.
- StringRef ModeStr(Config.GetOrCreateValue("ipa",
- "dynamic-bifurcate").getValue());
+ StringRef ModeStr(Config.GetOrCreateValue("ipa", DefaultIPA).getValue());
IPAKind IPAConfig = llvm::StringSwitch<IPAKind>(ModeStr)
.Case("none", IPAK_None)
.Case("basic-inlining", IPAK_BasicInlining)
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: max-times-inline-large = 32
+// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 6
+// CHECK-NEXT: num-entries = 7
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: max-times-inline-large = 32
+// CHECK-NEXT: mode = deep
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 9
+// CHECK-NEXT: num-entries = 10
--- /dev/null
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config mode=shallow -verify %s
+// expected-no-diagnostics
+
+void clang_analyzer_checkInlined(unsigned);
+
+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 <NSObject> {}
++(id)alloc;
+-(id)init;
+@end
+
+@interface MyClass : NSObject
++ (void)callee;
++ (void)caller;
+@end
+
+@implementation MyClass
++ (void)caller {
+ [MyClass callee];
+}
++ (void)callee {
+ clang_analyzer_checkInlined(0); // The call is not inlined.
+}
+@end
\ No newline at end of file