Index: include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/CheckerManager.h +++ include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -133,6 +133,8 @@ void finishedCheckerRegistration(); + unsigned getRegisteredCheckerCount() { return CheckerDtors.size(); } + const LangOptions &getLangOpts() const { return LangOpts; } AnalyzerOptions &getAnalyzerOptions() { return AOptions; } ASTContext &getASTContext() { return Context; } @@ -142,7 +144,7 @@ using CheckerDtor = CheckerFn; //===----------------------------------------------------------------------===// -// registerChecker +// Checker registration. //===----------------------------------------------------------------------===// /// Used to register checkers. @@ -154,8 +156,7 @@ CHECKER *registerChecker(AT &&... Args) { CheckerTag tag = getTag(); CheckerRef &ref = CheckerTags[tag]; - if (ref) - return static_cast(ref); // already registered. + assert(!ref && "Checker already registered, use getChecker!"); CHECKER *checker = new CHECKER(std::forward(Args)...); checker->Name = CurrentCheckName; @@ -165,8 +166,17 @@ return checker; } + template + CHECKER *getChecker() { + CheckerTag tag = getTag(); + assert(CheckerTags.count(tag) != 0 && + "Requested checker is not registered! Maybe you should add it as a " + "dependency in Checkers.td?"); + return static_cast(CheckerTags[tag]); + } + //===----------------------------------------------------------------------===// -// Functions for running checkers for AST traversing.. +// Functions for running checkers for AST traversing. //===----------------------------------------------------------------------===// /// Run checkers handling Decls. Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -2414,7 +2414,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ - CStringChecker *checker = mgr.registerChecker(); \ + CStringChecker *checker = mgr.getChecker(); \ checker->Filter.Check##name = true; \ checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \ } \ Index: lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -610,8 +610,7 @@ } void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) { - CallAndMessageChecker *Checker = - mgr.registerChecker(); + CallAndMessageChecker *Checker = mgr.getChecker(); Checker->Check_CallAndMessageUnInitRefArg = true; Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckName(); } Index: lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -915,8 +915,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ - SecuritySyntaxChecker *checker = \ - mgr.registerChecker(); \ + SecuritySyntaxChecker *checker = mgr.getChecker(); \ checker->filter.check_##name = true; \ checker->filter.checkName_##name = mgr.getCurrentCheckName(); \ } \ Index: lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -227,7 +227,7 @@ void ento::registerDirectIvarAssignmentForAnnotatedFunctions( CheckerManager &mgr) { - mgr.registerChecker()->ShouldSkipMethod = &AttrFilter; + mgr.getChecker()->ShouldSkipMethod = &AttrFilter; } bool ento::shouldRegisterDirectIvarAssignmentForAnnotatedFunctions( Index: lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -988,8 +988,7 @@ /// Register checkers. void ento::registerObjCGenericsChecker(CheckerManager &mgr) { - DynamicTypePropagation *checker = - mgr.registerChecker(); + DynamicTypePropagation *checker = mgr.getChecker(); checker->CheckGenerics = true; } Index: lib/StaticAnalyzer/Checkers/IteratorChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ lib/StaticAnalyzer/Checkers/IteratorChecker.cpp @@ -2359,7 +2359,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &Mgr) { \ - auto *checker = Mgr.registerChecker(); \ + auto *checker = Mgr.getChecker(); \ checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \ checker->CheckNames[IteratorChecker::CK_##name] = \ Mgr.getCurrentCheckName(); \ Index: lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp +++ lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -747,7 +747,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ IvarInvalidationChecker *checker = \ - mgr.registerChecker(); \ + mgr.getChecker(); \ checker->Filter.check_##name = true; \ checker->Filter.checkName_##name = mgr.getCurrentCheckName(); \ } \ Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -3090,16 +3090,16 @@ // Intended to be used in InnerPointerChecker to register the part of // MallocChecker connected to it. void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) { - MallocChecker *checker = mgr.registerChecker(); - checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption( - "Optimistic", false, checker); - checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true; - checker->CheckNames[MallocChecker::CK_InnerPointerChecker] = - mgr.getCurrentCheckName(); + MallocChecker *checker = mgr.getChecker(); + checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true; + checker->CheckNames[MallocChecker::CK_InnerPointerChecker] = + mgr.getCurrentCheckName(); } void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { - mgr.registerChecker(); + auto *checker = mgr.registerChecker(); + checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption( + "Optimistic", false, checker); } bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) { @@ -3108,9 +3108,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name(CheckerManager &mgr) { \ - MallocChecker *checker = mgr.registerChecker(); \ - checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption( \ - "Optimistic", false, checker); \ + MallocChecker *checker = mgr.getChecker(); \ checker->ChecksEnabled[MallocChecker::CK_##name] = true; \ checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \ } \ Index: lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -318,8 +318,7 @@ void ento::registerNSErrorChecker(CheckerManager &mgr) { mgr.registerChecker(); - NSOrCFErrorDerefChecker *checker = - mgr.registerChecker(); + NSOrCFErrorDerefChecker *checker = mgr.getChecker(); checker->ShouldCheckNSError = true; } @@ -329,8 +328,7 @@ void ento::registerCFErrorChecker(CheckerManager &mgr) { mgr.registerChecker(); - NSOrCFErrorDerefChecker *checker = - mgr.registerChecker(); + NSOrCFErrorDerefChecker *checker = mgr.getChecker(); checker->ShouldCheckCFError = true; } Index: lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -1192,7 +1192,7 @@ #define REGISTER_CHECKER(name, trackingRequired) \ void ento::register##name##Checker(CheckerManager &mgr) { \ - NullabilityChecker *checker = mgr.registerChecker(); \ + NullabilityChecker *checker = mgr.getChecker(); \ checker->Filter.Check##name = true; \ checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \ checker->NeedTracking = checker->NeedTracking || trackingRequired; \ Index: lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -368,11 +368,11 @@ return true; } -#define REGISTER_CHECKER(name) \ - void ento::register##name(CheckerManager &Mgr) { \ - StackAddrEscapeChecker *Chk = \ - Mgr.registerChecker(); \ - Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ +#define REGISTER_CHECKER(name) \ + void ento::register##name(CheckerManager &Mgr) { \ + StackAddrEscapeChecker *Chk = \ + Mgr.getChecker(); \ + Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true; \ } \ \ bool ento::shouldRegister##name(const LangOptions &LO) { \ Index: lib/StaticAnalyzer/Checkers/ValistChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -410,7 +410,7 @@ #define REGISTER_CHECKER(name) \ void ento::register##name##Checker(CheckerManager &mgr) { \ - ValistChecker *checker = mgr.registerChecker(); \ + ValistChecker *checker = mgr.getChecker(); \ checker->ChecksEnabled[ValistChecker::CK_##name] = true; \ checker->CheckNames[ValistChecker::CK_##name] = mgr.getCurrentCheckName(); \ } \ Index: lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -196,6 +196,7 @@ for (auto lastRelatedChecker = firstRelatedChecker+size; firstRelatedChecker != lastRelatedChecker; ++firstRelatedChecker) { if (opt.second) { + if (!firstRelatedChecker->ShouldRegister(LangOpts)) continue; @@ -245,8 +246,16 @@ // Initialize the CheckerManager with all enabled checkers. for (const auto *i : enabledCheckers) { + unsigned CurrentEnabledCheckerCount = + checkerMgr.getRegisteredCheckerCount(); + checkerMgr.setCurrentCheckName(CheckName(i->FullName)); i->Initialize(checkerMgr); + + assert(checkerMgr.getRegisteredCheckerCount() - + CurrentEnabledCheckerCount <= 1 && + "A registry function shouldn't register more than one checker!"); + (void)CurrentEnabledCheckerCount; } } Index: test/Analysis/analyzer-checker-config.c =================================================================== --- test/Analysis/analyzer-checker-config.c +++ test/Analysis/analyzer-checker-config.c @@ -4,7 +4,7 @@ // RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config ..:Optimistic=true 2>&1 | FileCheck %s // RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.:Optimistic=true 2>&1 | FileCheck %s // RUN: not %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unrelated:Optimistic=true 2>&1 | FileCheck %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.Malloc:Optimistic=true +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc -analyzer-config unix.DynamicMemoryModeling:Optimistic=true // Just to test clang is working. # foo Index: test/Analysis/free.c =================================================================== --- test/Analysis/free.c +++ test/Analysis/free.c @@ -1,5 +1,11 @@ -// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s -// RUN: %clang_analyze_cc1 -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify -analyzer-config unix.Malloc:Optimistic=true %s +// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-store=region \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix.Malloc +// +// RUN: %clang_analyze_cc1 -fblocks -verify %s -analyzer-store=region \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix.Malloc \ +// RUN: -analyzer-config unix.DynamicMemoryModeling:Optimistic=true typedef __typeof(sizeof(int)) size_t; void free(void *); void *alloca(size_t); Index: test/Analysis/outofbound.c =================================================================== --- test/Analysis/outofbound.c +++ test/Analysis/outofbound.c @@ -1,4 +1,8 @@ -// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-checker=core,unix,alpha.security.ArrayBound -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s +// RUN: %clang_analyze_cc1 -Wno-array-bounds -analyzer-store=region -verify %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix \ +// RUN: -analyzer-checker=alpha.security.ArrayBound \ +// RUN: -analyzer-config unix:Optimistic=true typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); Index: test/Analysis/undef-buffers.c =================================================================== --- test/Analysis/undef-buffers.c +++ test/Analysis/undef-buffers.c @@ -1,4 +1,9 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix,core.uninitialized -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s +// RUN: %clang_analyze_cc1 -analyzer-store=region -verify %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=unix \ +// RUN: -analyzer-checker=core.uninitialized \ +// RUN: -analyzer-config unix:Optimistic=true + typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); void free(void *);