276 changes: 194 additions & 82 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Large diffs are not rendered by default.

41 changes: 38 additions & 3 deletions clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ class CheckerRegistry {
using InitializationFunction = void (*)(CheckerManager &);
using ShouldRegisterFunction = bool (*)(const LangOptions &);

struct CheckerInfo;

using CheckerInfoList = std::vector<CheckerInfo>;
using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
using ConstCheckerInfoList = llvm::SmallVector<const CheckerInfo *, 0>;
using CheckerInfoSet = llvm::SetVector<const CheckerInfo *>;

struct CheckerInfo {
enum class StateFromCmdLine {
// This checker wasn't explicitly enabled or disabled.
Expand All @@ -109,20 +116,23 @@ class CheckerRegistry {
StringRef DocumentationUri;
StateFromCmdLine State = StateFromCmdLine::State_Unspecified;

ConstCheckerInfoList Dependencies;

bool isEnabled(const LangOptions &LO) const {
return State == StateFromCmdLine::State_Enabled && ShouldRegister(LO);
}

bool isDisabled(const LangOptions &LO) const {
return State == StateFromCmdLine::State_Disabled && ShouldRegister(LO);
}

CheckerInfo(InitializationFunction Fn, ShouldRegisterFunction sfn,
StringRef Name, StringRef Desc, StringRef DocsUri)
: Initialize(Fn), ShouldRegister(sfn), FullName(Name), Desc(Desc),
DocumentationUri(DocsUri) {}
};

using StateFromCmdLine = CheckerInfo::StateFromCmdLine;
using CheckerInfoList = std::vector<CheckerInfo>;
using CheckerInfoListRange = llvm::iterator_range<CheckerInfoList::iterator>;
using CheckerInfoSet = llvm::SetVector<const CheckerRegistry::CheckerInfo *>;

private:
template <typename T>
Expand Down Expand Up @@ -152,6 +162,28 @@ class CheckerRegistry {
&CheckerRegistry::returnTrue<T>, FullName, Desc, DocsUri);
}

/// Makes the checker with the full name \p fullName depends on the checker
/// called \p dependency.
void addDependency(StringRef fullName, StringRef dependency) {
auto CheckerThatNeedsDeps =
[&fullName](const CheckerInfo &Chk) { return Chk.FullName == fullName; };
auto Dependency =
[&dependency](const CheckerInfo &Chk) {
return Chk.FullName == dependency;
};

auto CheckerIt = llvm::find_if(Checkers, CheckerThatNeedsDeps);
assert(CheckerIt != Checkers.end() &&
"Failed to find the checker while attempting to set up it's "
"dependencies!");

auto DependencyIt = llvm::find_if(Checkers, Dependency);
assert(DependencyIt != Checkers.end() &&
"Failed to find the dependency of a checker!");

CheckerIt->Dependencies.push_back(&*DependencyIt);
}

// FIXME: This *really* should be added to the frontend flag descriptions.
/// Initializes a CheckerManager by calling the initialization functions for
/// all checkers specified by the given CheckerOptInfo list. The order of this
Expand All @@ -168,6 +200,9 @@ class CheckerRegistry {
void printList(raw_ostream &out) const;

private:
/// Collect all enabled checkers. The returned container preserves the order
/// of insertion, as dependencies have to be enabled before the checkers that
/// depend on them.
CheckerInfoSet getEnabledCheckers() const;

/// Return an iterator range of mutable CheckerInfos \p CmdLineArg applies to.
Expand Down
12 changes: 8 additions & 4 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2475,6 +2475,14 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(state);
}

void ento::registerCStringModeling(CheckerManager &Mgr) {
Mgr.registerChecker<CStringChecker>();
}

bool ento::shouldRegisterCStringModeling(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
CStringChecker *checker = mgr.registerChecker<CStringChecker>(); \
Expand All @@ -2490,7 +2498,3 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
REGISTER_CHECKER(CStringOutOfBounds)
REGISTER_CHECKER(CStringBufferOverlap)
REGISTER_CHECKER(CStringNotNullTerm)

void ento::registerCStringCheckerBasic(CheckerManager &Mgr) {
Mgr.registerChecker<CStringChecker>();
}
43 changes: 20 additions & 23 deletions clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ using namespace ento;

namespace {

struct ChecksFilter {
DefaultBool Check_CallAndMessageUnInitRefArg;
DefaultBool Check_CallAndMessageChecker;

CheckName CheckName_CallAndMessageUnInitRefArg;
CheckName CheckName_CallAndMessageChecker;
};

class CallAndMessageChecker
: public Checker< check::PreStmt<CallExpr>,
check::PreStmt<CXXDeleteExpr>,
Expand All @@ -56,7 +48,8 @@ class CallAndMessageChecker
mutable std::unique_ptr<BugType> BT_call_few_args;

public:
ChecksFilter Filter;
DefaultBool Check_CallAndMessageUnInitRefArg;
CheckName CheckName_CallAndMessageUnInitRefArg;

void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
Expand Down Expand Up @@ -151,7 +144,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(
CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
int ArgumentNumber) const {
if (!Filter.Check_CallAndMessageUnInitRefArg)
if (!Check_CallAndMessageUnInitRefArg)
return false;

// No parameter declaration available, i.e. variadic function argument.
Expand Down Expand Up @@ -607,17 +600,21 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
C.addTransition(state);
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
CallAndMessageChecker *Checker = \
mgr.registerChecker<CallAndMessageChecker>(); \
Checker->Filter.Check_##name = true; \
Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \
} \
\
bool ento::shouldRegister##name(const LangOptions &LO) { \
return true; \
}
void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
mgr.registerChecker<CallAndMessageChecker>();
}

bool ento::shouldRegisterCallAndMessageChecker(const LangOptions &LO) {
return true;
}

REGISTER_CHECKER(CallAndMessageUnInitRefArg)
REGISTER_CHECKER(CallAndMessageChecker)
void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) {
CallAndMessageChecker *Checker =
mgr.registerChecker<CallAndMessageChecker>();
Checker->Check_CallAndMessageUnInitRefArg = true;
Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckName();
}

bool ento::shouldRegisterCallAndMessageUnInitRefArg(const LangOptions &LO) {
return true;
}
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,14 @@ class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
};
}

void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
mgr.registerChecker<SecuritySyntaxChecker>();
}

bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
SecuritySyntaxChecker *checker = \
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/StaticAnalyzer/Checkers/InterCheckerAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ class CheckerManager;

namespace ento {

/// Register the checker which evaluates CString API calls.
void registerCStringCheckerBasic(CheckerManager &Mgr);

/// Register the part of MallocChecker connected to InnerPointerChecker.
void registerInnerPointerCheckerAux(CheckerManager &Mgr);

Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2393,6 +2393,14 @@ bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2,

} // namespace

void ento::registerIteratorModeling(CheckerManager &mgr) {
mgr.registerChecker<IteratorChecker>();
}

bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &Mgr) { \
auto *checker = Mgr.registerChecker<IteratorChecker>(); \
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,14 @@ class IvarInvalidationChecker :
};
} // end anonymous namespace

void ento::registerIvarInvalidationModeling(CheckerManager &mgr) {
mgr.registerChecker<IvarInvalidationChecker>();
}

bool ento::shouldRegisterIvarInvalidationModeling(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
IvarInvalidationChecker *checker = \
Expand Down
36 changes: 10 additions & 26 deletions clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3086,44 +3086,27 @@ markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
} // end namespace ento
} // end namespace clang

void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
registerCStringCheckerBasic(mgr);
MallocChecker *checker = mgr.registerChecker<MallocChecker>();
checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
"Optimistic", false, checker);
checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
mgr.getCurrentCheckName();
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
// checker.
if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker]) {
checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;
// FIXME: This does not set the correct name, but without this workaround
// no name will be set at all.
checker->CheckNames[MallocChecker::CK_NewDeleteChecker] =
mgr.getCurrentCheckName();
}
}

bool ento::shouldRegisterNewDeleteLeaksChecker(const LangOptions &LO) {
return true;
}

// Intended to be used in InnerPointerChecker to register the part of
// MallocChecker connected to it.
void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {
registerCStringCheckerBasic(mgr);
MallocChecker *checker = mgr.registerChecker<MallocChecker>();
checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption(
"Optimistic", false, checker);
"Optimistic", false, checker);
checker->ChecksEnabled[MallocChecker::CK_InnerPointerChecker] = true;
checker->CheckNames[MallocChecker::CK_InnerPointerChecker] =
mgr.getCurrentCheckName();
}

void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
mgr.registerChecker<MallocChecker>();
}

bool ento::shouldRegisterDynamicMemoryModeling(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &mgr) { \
registerCStringCheckerBasic(mgr); \
MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \
checker->IsOptimistic = mgr.getAnalyzerOptions().getCheckerBooleanOption( \
"Optimistic", false, checker); \
Expand All @@ -3137,4 +3120,5 @@ void ento::registerInnerPointerCheckerAux(CheckerManager &mgr) {

REGISTER_CHECKER(MallocChecker)
REGISTER_CHECKER(NewDeleteChecker)
REGISTER_CHECKER(NewDeleteLeaksChecker)
REGISTER_CHECKER(MismatchedDeallocatorChecker)
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ static bool IsCFError(QualType T, IdentifierInfo *II) {
return TT->getDecl()->getIdentifier() == II;
}

void ento::registerNSOrCFErrorDerefChecker(CheckerManager &mgr) {
mgr.registerChecker<NSOrCFErrorDerefChecker>();
}

bool ento::shouldRegisterNSOrCFErrorDerefChecker(const LangOptions &LO) {
return true;
}

void ento::registerNSErrorChecker(CheckerManager &mgr) {
mgr.registerChecker<NSErrorMethodChecker>();
NSOrCFErrorDerefChecker *checker =
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,14 @@ void NullabilityChecker::printState(raw_ostream &Out, ProgramStateRef State,
}
}

void ento::registerNullabilityBase(CheckerManager &mgr) {
mgr.registerChecker<NullabilityChecker>();
}

bool ento::shouldRegisterNullabilityBase(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name, trackingRequired) \
void ento::register##name##Checker(CheckerManager &mgr) { \
NullabilityChecker *checker = mgr.registerChecker<NullabilityChecker>(); \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,14 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State,
// Checker registration.
//===----------------------------------------------------------------------===//

void ento::registerRetainCountBase(CheckerManager &Mgr) {
Mgr.registerChecker<RetainCountChecker>();
}

bool ento::shouldRegisterRetainCountBase(const LangOptions &LO) {
return true;
}

void ento::registerRetainCountChecker(CheckerManager &Mgr) {
auto *Chk = Mgr.registerChecker<RetainCountChecker>();
Chk->TrackObjCAndCFObjects = true;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,14 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
}
}

void ento::registerStackAddrEscapeBase(CheckerManager &mgr) {
mgr.registerChecker<StackAddrEscapeChecker>();
}

bool ento::shouldRegisterStackAddrEscapeBase(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name(CheckerManager &Mgr) { \
StackAddrEscapeChecker *Chk = \
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,14 @@ std::shared_ptr<PathDiagnosticPiece> ValistChecker::ValistBugVisitor::VisitNode(
return std::make_shared<PathDiagnosticEventPiece>(Pos, Msg, true);
}

void ento::registerValistBase(CheckerManager &mgr) {
mgr.registerChecker<ValistChecker>();
}

bool ento::shouldRegisterValistBase(const LangOptions &LO) {
return true;
}

#define REGISTER_CHECKER(name) \
void ento::register##name##Checker(CheckerManager &mgr) { \
ValistChecker *checker = mgr.registerChecker<ValistChecker>(); \
Expand Down
70 changes: 67 additions & 3 deletions clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ CheckerRegistry::CheckerRegistry(
// that's ASCIIbetically last?
llvm::sort(Checkers, checkerNameLT);

#define GET_CHECKER_DEPENDENCIES

#define CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY) \
addDependency(FULLNAME, DEPENDENCY);

#include "clang/StaticAnalyzer/Checkers/Checkers.inc"
#undef CHECKER_DEPENDENCY
#undef GET_CHECKER_DEPENDENCIES

// Parse '-analyzer-checker' and '-analyzer-disable-checker' options from the
// command line.
for (const std::pair<std::string, bool> &opt : AnOpts.CheckersControlList) {
Expand All @@ -169,13 +178,69 @@ CheckerRegistry::CheckerRegistry(
}
}

/// Collects dependencies in \p ret, returns false on failure.
static bool collectDependenciesImpl(
const CheckerRegistry::ConstCheckerInfoList &deps,
const LangOptions &LO,
CheckerRegistry::CheckerInfoSet &ret);

/// Collects dependenies in \p enabledCheckers. Return None on failure.
LLVM_NODISCARD
static llvm::Optional<CheckerRegistry::CheckerInfoSet> collectDependencies(
const CheckerRegistry::CheckerInfo &checker, const LangOptions &LO) {

CheckerRegistry::CheckerInfoSet ret;
// Add dependencies to the enabled checkers only if all of them can be
// enabled.
if (!collectDependenciesImpl(checker.Dependencies, LO, ret))
return None;

return ret;
}

static bool collectDependenciesImpl(
const CheckerRegistry::ConstCheckerInfoList &deps,
const LangOptions &LO,
CheckerRegistry::CheckerInfoSet &ret) {

for (const CheckerRegistry::CheckerInfo *dependency : deps) {

if (dependency->isDisabled(LO))
return false;

// Collect dependencies recursively.
if (!collectDependenciesImpl(dependency->Dependencies, LO, ret))
return false;

ret.insert(dependency);
}

return true;
}

CheckerRegistry::CheckerInfoSet CheckerRegistry::getEnabledCheckers() const {

CheckerInfoSet enabledCheckers;

for (const CheckerInfo &checker : Checkers) {
if (checker.isEnabled(LangOpts))
enabledCheckers.insert(&checker);
if (!checker.isEnabled(LangOpts))
continue;

// Recursively enable it's dependencies.
llvm::Optional<CheckerInfoSet> deps =
collectDependencies(checker, LangOpts);

if (!deps) {
// If we failed to enable any of the dependencies, don't enable this
// checker.
continue;
}

// Note that set_union also preserves the order of insertion.
enabledCheckers.set_union(*deps);

// Enable the checker.
enabledCheckers.insert(&checker);
}

return enabledCheckers;
Expand All @@ -196,7 +261,6 @@ void CheckerRegistry::addChecker(InitializationFunction Rfn,
}

void CheckerRegistry::initializeManager(CheckerManager &checkerMgr) const {

// Collect checkers enabled by the options.
CheckerInfoSet enabledCheckers = getEnabledCheckers();

Expand Down
14 changes: 6 additions & 8 deletions clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -2120,9 +2119,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;value&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>29a10ca4af622b6146ca082e49d919d6</string>
<key>issue_hash_content_of_line_in_context</key><string>b2b15a95787e594ff79f02c600e9d357</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>rdar8331641</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand Down Expand Up @@ -11219,9 +11218,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>f533db5cbb9c20d171f9f92105789dc4</string>
<key>issue_hash_content_of_line_in_context</key><string>ef342aeb2f2719117ddd4ef1b72f5ba7</string>
<key>issue_context_kind</key><string>Objective-C method</string>
<key>issue_context</key><string>test2</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand Down Expand Up @@ -21065,9 +21064,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>5616a7601faa1a8c2ac56fa1b595b172</string>
<key>issue_hash_content_of_line_in_context</key><string>f81f51dd154d0a11cab412a1cd1cd095</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>longLines</string>
<key>issue_hash_function_offset</key><string>1</string>
Expand Down Expand Up @@ -21446,7 +21445,6 @@
</array>
<key>files</key>
<array>
<string>/clang/test/Analysis/edges-new.mm</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,9 @@
<key>description</key><string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
<key>category</key><string>Memory error</string>
<key>type</key><string>Nullability</string>
<key>check_name</key><string>nullability.NullPassedToNonnull</string>
<key>check_name</key><string>nullability.NullabilityBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>b6bc8126de8e6eb3375483a656fe858d</string>
<key>issue_hash_content_of_line_in_context</key><string>ff735bea0eb12d4d172b139143c32365</string>
<key>issue_context_kind</key><string>Objective-C method</string>
<key>issue_context</key><string>method</string>
<key>issue_hash_function_offset</key><string>3</string>
Expand Down
26 changes: 12 additions & 14 deletions clang/test/Analysis/Inputs/expected-plists/objc-arc.m.plist
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -313,9 +312,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;date&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>61d185b2522d15fb327f6784e0217adf</string>
<key>issue_hash_content_of_line_in_context</key><string>7bd4a6e187407677b2d9e717576818bf</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>test_cf_leak</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand Down Expand Up @@ -844,9 +843,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;obj5&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>5baa7d5f38420d0a035aa61607675f3e</string>
<key>issue_hash_content_of_line_in_context</key><string>0aed4f65cb3dba7331f9319fd1ceb003</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>from_cf</string>
<key>issue_hash_function_offset</key><string>7</string>
Expand Down Expand Up @@ -990,9 +989,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;obj6&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>4665e04694fd55e7c4ed7a67860b3b74</string>
<key>issue_hash_content_of_line_in_context</key><string>0851961d40a4c8331ebe713f4a3e05f4</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>from_cf</string>
<key>issue_hash_function_offset</key><string>8</string>
Expand Down Expand Up @@ -1424,9 +1423,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;date&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>798e65f80df0526369f9bb240e3d91fd</string>
<key>issue_hash_content_of_line_in_context</key><string>00045bff3b7c26fe7cb80a71f512575c</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>test_objc_unretainedObject</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand Down Expand Up @@ -1735,9 +1734,9 @@
<key>description</key><string>Potential leak of an object of type &apos;CFStringRef&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>e1fbcc142b678b3c2c43737ee35b64d9</string>
<key>issue_hash_content_of_line_in_context</key><string>9f258122568ea8763047e98db8a52647</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>test_objc_arrays</string>
<key>issue_hash_function_offset</key><string>24</string>
Expand Down Expand Up @@ -1929,9 +1928,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;o&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>e300a279615a384d2b310329651d3978</string>
<key>issue_hash_content_of_line_in_context</key><string>8187b0ba5cadd42594120fe05d871502</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>rdar11059275_positive</string>
<key>issue_hash_function_offset</key><string>1</string>
Expand Down Expand Up @@ -2083,7 +2082,6 @@
</array>
<key>files</key>
<array>
<string>/clang/test/Analysis/objc-arc.m</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -1268,9 +1267,9 @@
<key>description</key><string>Potential leak of an object of type &apos;NSNumber *&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>500e2bbda41c8086771ad98b6bcfdc50</string>
<key>issue_hash_content_of_line_in_context</key><string>c204ce6cce660a7714c801bdf9183431</string>
<key>location</key>
<dict>
<key>line</key><integer>53</integer>
Expand Down Expand Up @@ -1303,7 +1302,6 @@
</array>
<key>files</key>
<array>
<string>/Volumes/Transcend/code/monorepo/llvm-project/clang/test/Analysis/objc-radar17039661.m</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -1486,9 +1485,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;value&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>29a10ca4af622b6146ca082e49d919d6</string>
<key>issue_hash_content_of_line_in_context</key><string>b2b15a95787e594ff79f02c600e9d357</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>rdar8331641</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand All @@ -1514,7 +1513,6 @@
</array>
<key>files</key>
<array>
<string>/clang/test/Analysis/plist-output-alternate.m</string>
</array>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -2373,9 +2372,9 @@
<key>description</key><string>Potential leak of an object stored into &apos;foo&apos;</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Leak</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>f533db5cbb9c20d171f9f92105789dc4</string>
<key>issue_hash_content_of_line_in_context</key><string>ef342aeb2f2719117ddd4ef1b72f5ba7</string>
<key>issue_context_kind</key><string>Objective-C method</string>
<key>issue_context</key><string>test2</string>
<key>issue_hash_function_offset</key><string>2</string>
Expand Down Expand Up @@ -6214,7 +6213,6 @@
</array>
<key>files</key>
<array>
<string>/clang/test/Analysis/plist-output.m</string>
</array>
</dict>
</plist>

Large diffs are not rendered by default.

422 changes: 210 additions & 212 deletions clang/test/Analysis/Inputs/expected-plists/retain-release.m.objc.plist

Large diffs are not rendered by default.

422 changes: 210 additions & 212 deletions clang/test/Analysis/Inputs/expected-plists/retain-release.m.objcpp.plist

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,unix.MismatchedDeallocator -std=c++11 -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,unix.MismatchedDeallocator -DLEAKS -std=c++11 -verify %s
// RUN: %clang_analyze_cc1 -std=c++11 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=unix.MismatchedDeallocator
//
// RUN: %clang_analyze_cc1 -std=c++11 -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \
// RUN: -analyzer-checker=unix.MismatchedDeallocator

// expected-no-diagnostics

typedef __typeof(sizeof(int)) size_t;
Expand Down
47 changes: 39 additions & 8 deletions clang/test/Analysis/NewDelete-checker-test.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,42 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -analyzer-config c++-allocator-inlining=true -DTEST_INLINABLE_ALLOCATORS -verify %s
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete
//
// RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
//
// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-config c++-allocator-inlining=true
//
// RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \
// RUN: -analyzer-config c++-allocator-inlining=true
//
// RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \
// RUN: -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete
//
// RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \
// RUN: -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks
//
// RUN: %clang_analyze_cc1 -DTEST_INLINABLE_ALLOCATORS \
// RUN: -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDelete \
// RUN: -analyzer-config c++-allocator-inlining=true
//
// RUN: %clang_analyze_cc1 -DLEAKS -DTEST_INLINABLE_ALLOCATORS \
// RUN: -std=c++11 -fblocks -verify %s \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=cplusplus.NewDeleteLeaks \
// RUN: -analyzer-config c++-allocator-inlining=true

#include "Inputs/system-header-simulator-cxx.h"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<plist version="1.0">
<dict>
<key>clang_version</key>
<string>clang version 8.0.0 </string>
<key>diagnostics</key>
<array>
<dict>
Expand Down Expand Up @@ -1966,9 +1965,9 @@
<key>description</key><string>Object autoreleased too many times</string>
<key>category</key><string>Memory (Core Foundation/Objective-C/OSObject)</string>
<key>type</key><string>Object autoreleased too many times</string>
<key>check_name</key><string>osx.cocoa.RetainCount</string>
<key>check_name</key><string>osx.cocoa.RetainCountBase</string>
<!-- This hash is experimental and going to change! -->
<key>issue_hash_content_of_line_in_context</key><string>a3c91a7a52619d81ebe032dcc49ebb93</string>
<key>issue_hash_content_of_line_in_context</key><string>b6a556c71184371a9567489c8477c2f7</string>
<key>issue_context_kind</key><string>function</string>
<key>issue_context</key><string>testAutoreleaseTakesEffectInDispatch</string>
<key>issue_hash_function_offset</key><string>11</string>
Expand All @@ -1995,7 +1994,6 @@
</array>
<key>files</key>
<array>
<string>/clang/test/Analysis/inlining/path-notes.m</string>
</array>
</dict>
</plist>
8 changes: 5 additions & 3 deletions clang/test/Analysis/malloc-annotations.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// RUN: %clang_analyze_cc1 -analyzer-store=region -verify %s \
// RUN: %clang_analyze_cc1 -analyzer-store=region -verify \
// RUN: -analyzer-checker=core \
// RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \
// RUN: -analyzer-checker=alpha.core.CastSize,unix.Malloc \
// RUN: -analyzer-config unix.Malloc:Optimistic=true
// RUN: -analyzer-checker=alpha.core.CastSize \
// RUN: -analyzer-checker=unix.Malloc \
// RUN: -analyzer-config unix.DynamicMemoryModeling:Optimistic=true %s

typedef __typeof(sizeof(int)) size_t;
void *malloc(size_t);
void free(void *);
Expand Down
14 changes: 11 additions & 3 deletions clang/test/Analysis/test-separate-retaincount.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.cocoa.RetainCount -DNO_CF_OBJECT -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-disable-checker osx.OSObjectRetainCount -DNO_OS_OBJECT -verify %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false" -DNO_OS_OBJECT -verify %s
// RUN: %clang_analyze_cc1 -DNO_CF_OBJECT -verify %s \
// RUN: -analyzer-checker=core,osx \
// RUN: -analyzer-disable-checker osx.cocoa.RetainCount
//
// RUN: %clang_analyze_cc1 -DNO_OS_OBJECT -verify %s \
// RUN: -analyzer-checker=core,osx \
// RUN: -analyzer-disable-checker osx.OSObjectRetainCount
//
// RUN: %clang_analyze_cc1 -DNO_OS_OBJECT -verify %s \
// RUN: -analyzer-checker=core,osx \
// RUN: -analyzer-config "osx.cocoa.RetainCount:CheckOSObject=false"

#include "os_object_base.h"

Expand Down
76 changes: 60 additions & 16 deletions clang/utils/TableGen/ClangSACheckersEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@ static std::string getCheckerDocs(const Record &R) {
.str();
}

static void printChecker(llvm::raw_ostream &OS, const Record &R) {
OS << "CHECKER(" << "\"";
OS.write_escaped(getCheckerFullName(&R)) << "\", ";
OS << R.getName() << ", ";
OS << "\"";
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
OS << "\"";
OS.write_escaped(getCheckerDocs(R));
OS << "\"";
}

namespace clang {
void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
Expand All @@ -100,7 +111,12 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "// This file is automatically generated. Do not edit this file by "
"hand.\n";

OS << "\n#ifdef GET_PACKAGES\n";
// Emit packages.
//
// PACKAGE(PACKAGENAME)
// - PACKAGENAME: The name of the package.
OS << "\n"
"#ifdef GET_PACKAGES\n";
{
SortedRecords sortedPackages;
for (unsigned i = 0, e = packages.size(); i != e; ++i)
Expand All @@ -115,22 +131,50 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << ")\n";
}
}
OS << "#endif // GET_PACKAGES\n\n";

OS << "\n#ifdef GET_CHECKERS\n";
for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
const Record &R = *checkers[i];

OS << "CHECKER(" << "\"";
OS.write_escaped(getCheckerFullName(&R)) << "\", ";
OS << R.getName() << ", ";
OS << "\"";
OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
OS << "\"";
OS.write_escaped(getCheckerDocs(R));
OS << "\"";
OS << "#endif // GET_PACKAGES\n"
"\n";

// Emit checkers.
//
// CHECKER(FULLNAME, CLASS, HELPTEXT)
// - FULLNAME: The full name of the checker, including packages, e.g.:
// alpha.cplusplus.UninitializedObject
// - CLASS: The name of the checker, with "Checker" appended, e.g.:
// UninitializedObjectChecker
// - HELPTEXT: The description of the checker.
OS << "\n"
"#ifdef GET_CHECKERS\n"
"\n";
for (const Record *checker : checkers) {
printChecker(OS, *checker);
OS << ")\n";
}
OS << "#endif // GET_CHECKERS\n\n";
OS << "\n"
"#endif // GET_CHECKERS\n"
"\n";

// Emit dependencies.
//
// CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
// - FULLNAME: The full name of the checker that depends on another checker.
// - DEPENDENCY: The full name of the checker FULLNAME depends on.
OS << "\n"
"#ifdef GET_CHECKER_DEPENDENCIES\n";
for (const Record *checker : checkers) {
if (checker->isValueUnset("Dependencies"))
continue;

for (const Record *Dependency :
checker->getValueAsListOfDefs("Dependencies")) {
OS << "CHECKER_DEPENDENCY(";
OS << '\"';
OS.write_escaped(getCheckerFullName(checker)) << "\", ";
OS << '\"';
OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
OS << ")\n";
}
}
OS << "\n"
"#endif // GET_CHECKER_DEPENDENCIES\n";
}
} // end namespace clang