Index: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h =================================================================== --- include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -172,6 +172,7 @@ /// A key-value table of use-specified configuration values. // TODO: This shouldn't be public. ConfigTable Config; + AnalysisStores AnalysisStoreOpt = RegionStoreModel; AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel; AnalysisDiagClients AnalysisDiagOpt = PD_HTML; @@ -268,6 +269,18 @@ llvm::sort(AnalyzerConfigCmdFlags); } + /// Inserts a checker option with the specified default value. If the user + /// already specified this option when invoking the analyzer, nothing happens. + void registerCheckerOption(StringRef CheckerFullName, + StringRef OptionName, + StringRef DefaultValStr); + + /// Inserts a package option with the specified default value. If the user + /// already specified this option when invoking the analyzer, nothing happens. + void registerPackageOption(StringRef CheckerFullName, + StringRef OptionName, + StringRef DefaultValStr); + /// Interprets an option's string value as a boolean. The "true" string is /// interpreted as true and the "false" string is interpreted as false. /// Index: lib/StaticAnalyzer/Core/AnalyzerOptions.cpp =================================================================== --- lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -101,6 +101,20 @@ return *K >= Param; } +void AnalyzerOptions::registerCheckerOption(StringRef CheckerFullName, + StringRef OptionName, + StringRef DefaultVal) { + Config.insert({(Twine() + CheckerFullName + ":" + OptionName).str(), + DefaultVal}); +} + +void AnalyzerOptions::registerPackageOption(StringRef CheckerFullName, + StringRef OptionName, + StringRef DefaultVal) { + Config.insert({(Twine() + CheckerFullName + ":" + OptionName).str(), + DefaultVal}); +} + StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName, StringRef OptionName, StringRef DefaultVal, @@ -110,14 +124,17 @@ "bases!) if fully initialized before calling this function!"); ConfigTable::const_iterator E = Config.end(); + do { ConfigTable::const_iterator I = Config.find((Twine(CheckerName) + ":" + OptionName).str()); if (I != E) return StringRef(I->getValue()); + size_t Pos = CheckerName.rfind('.'); if (Pos == StringRef::npos) return DefaultVal; + CheckerName = CheckerName.substr(0, Pos); } while (!CheckerName.empty() && SearchInParents); return DefaultVal; @@ -163,7 +180,7 @@ bool HasFailed = getCheckerStringOption(CheckerName, OptionName, std::to_string(DefaultVal), SearchInParents) - .getAsInteger(10, Ret); + .getAsInteger(0, Ret); assert(!HasFailed && "analyzer-config option should be numeric"); (void)HasFailed; return Ret; Index: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -329,6 +329,8 @@ CheckerIt->CmdLineOptions.push_back( {OptionType, OptionName, DefaultValStr, Description}); + + AnOpts.registerCheckerOption(CheckerFullName, OptionName, DefaultValStr); } void CheckerRegistry::addPackage(StringRef FullName) { @@ -348,6 +350,8 @@ PackageIt->CmdLineOptions.push_back( {OptionType, OptionName, DefaultValStr, Description}); + + AnOpts.registerPackageOption(CheckerFullName, OptionName, DefaultValStr); } void CheckerRegistry::initializeManager(CheckerManager &checkerMgr) const { Index: test/Analysis/analyzer-config.c =================================================================== --- test/Analysis/analyzer-config.c +++ test/Analysis/analyzer-config.c @@ -3,6 +3,16 @@ // CHECK: [config] // CHECK-NEXT: aggressive-binary-operation-simplification = false +// CHECK-NEXT: alpha.clone.CloneChecker:IgnoredFilesPattern = "" +// CHECK-NEXT: alpha.clone.CloneChecker:MinimumCloneComplexity = 50 +// CHECK-NEXT: alpha.clone.CloneChecker:ReportNormalClones = true +// CHECK-NEXT: alpha.cplusplus.UninitializedObject:CheckPointeeInitialization = false +// CHECK-NEXT: alpha.cplusplus.UninitializedObject:IgnoreGuardedFields = false +// CHECK-NEXT: alpha.cplusplus.UninitializedObject:IgnoreRecordsWithField = "" +// CHECK-NEXT: alpha.cplusplus.UninitializedObject:NotesAsWarnings = false +// CHECK-NEXT: alpha.cplusplus.UninitializedObject:Pedantic = false +// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04 +// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01 // CHECK-NEXT: avoid-suppressing-null-argument-paths = false // CHECK-NEXT: c++-allocator-inlining = true // CHECK-NEXT: c++-container-inlining = false @@ -18,9 +28,26 @@ // CHECK-NEXT: cfg-rich-constructors = true // CHECK-NEXT: cfg-scopes = false // CHECK-NEXT: cfg-temporary-dtors = true +// CHECK-NEXT: cplusplus.Move:WarnOn = KnownsAndLocals // CHECK-NEXT: crosscheck-with-z3 = false // CHECK-NEXT: ctu-dir = "" // CHECK-NEXT: ctu-index-name = externalDefMap.txt +// CHECK-NEXT: debug.AnalysisOrder:* = false +// CHECK-NEXT: debug.AnalysisOrder:Bind = false +// CHECK-NEXT: debug.AnalysisOrder:EndFunction = false +// CHECK-NEXT: debug.AnalysisOrder:LiveSymbols = false +// CHECK-NEXT: debug.AnalysisOrder:NewAllocator = false +// CHECK-NEXT: debug.AnalysisOrder:PostCall = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtArraySubscriptExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtCXXNewExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtCastExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PostStmtOffsetOfExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreCall = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtArraySubscriptExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtCXXNewExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtCastExpr = false +// CHECK-NEXT: debug.AnalysisOrder:PreStmtOffsetOfExpr = false +// CHECK-NEXT: debug.AnalysisOrder:RegionChanges = false // CHECK-NEXT: display-ctu-progress = false // CHECK-NEXT: eagerly-assume = true // CHECK-NEXT: elide-constructors = true @@ -40,7 +67,16 @@ // CHECK-NEXT: mode = deep // CHECK-NEXT: model-path = "" // CHECK-NEXT: notes-as-events = false +// CHECK-NEXT: nullability:NoDiagnoseCallsToSystemHeaders = false +// CHECK-NEXT: nullability:Optimistic = false // CHECK-NEXT: objc-inlining = true +// CHECK-NEXT: optin.cplusplus.VirtualCall:PureOnly = false +// CHECK-NEXT: optin.osx.cocoa.localizability.NonLocalizedStringChecker:AggressiveReport = false +// CHECK-NEXT: optin.performance.Padding:AllowedPad = 24 +// CHECK-NEXT: osx.NumberObjectConversion:Pedantic = false +// CHECK-NEXT: osx.cocoa.RetainCount:CheckOSObject = true +// CHECK-NEXT: osx.cocoa.RetainCount:TrackNSCFStartParam = false +// CHECK-NEXT: osx.cocoa.RetainCount:leak-diagnostics-reference-allocation = false // CHECK-NEXT: prune-paths = true // CHECK-NEXT: region-store-small-struct-limit = 2 // CHECK-NEXT: report-in-main-source-file = false @@ -49,7 +85,8 @@ // CHECK-NEXT: suppress-c++-stdlib = true // CHECK-NEXT: suppress-inlined-defensive-checks = true // CHECK-NEXT: suppress-null-return-paths = true +// CHECK-NEXT: unix.DynamicMemoryModeling:Optimistic = false // CHECK-NEXT: unroll-loops = false // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 49 +// CHECK-NEXT: num-entries = 86