blob: 58abd670395f92e36467d92c55d7cb1638971b56 [file] [log] [blame]
//== RetainCountDiagnostics.h - Checks for leaks and other issues -*- C++ -*--//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines diagnostics for RetainCountChecker, which implements
// a reference count checker for Core Foundation and Cocoa on (Mac OS X).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
namespace clang {
namespace ento {
namespace retaincountchecker {
class CFRefBug : public BugType {
protected:
CFRefBug(const CheckerBase *checker, StringRef name)
: BugType(checker, name, categories::MemoryCoreFoundationObjectiveC) {}
public:
// FIXME: Eventually remove.
virtual const char *getDescription() const = 0;
virtual bool isLeak() const { return false; }
};
class UseAfterRelease : public CFRefBug {
public:
UseAfterRelease(const CheckerBase *checker)
: CFRefBug(checker, "Use-after-release") {}
const char *getDescription() const override {
return "Reference-counted object is used after it is released";
}
};
class BadRelease : public CFRefBug {
public:
BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {}
const char *getDescription() const override {
return "Incorrect decrement of the reference count of an object that is "
"not owned at this point by the caller";
}
};
class DeallocNotOwned : public CFRefBug {
public:
DeallocNotOwned(const CheckerBase *checker)
: CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {}
const char *getDescription() const override {
return "-dealloc sent to object that may be referenced elsewhere";
}
};
class OverAutorelease : public CFRefBug {
public:
OverAutorelease(const CheckerBase *checker)
: CFRefBug(checker, "Object autoreleased too many times") {}
const char *getDescription() const override {
return "Object autoreleased too many times";
}
};
class ReturnedNotOwnedForOwned : public CFRefBug {
public:
ReturnedNotOwnedForOwned(const CheckerBase *checker)
: CFRefBug(checker, "Method should return an owned object") {}
const char *getDescription() const override {
return "Object with a +0 retain count returned to caller where a +1 "
"(owning) retain count is expected";
}
};
class Leak : public CFRefBug {
public:
Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
// Leaks should not be reported if they are post-dominated by a sink.
setSuppressOnSink(true);
}
const char *getDescription() const override { return ""; }
bool isLeak() const override { return true; }
};
typedef ::llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
SummaryLogTy;
/// Visitors.
class CFRefReportVisitor : public BugReporterVisitor {
protected:
SymbolRef Sym;
const SummaryLogTy &SummaryLog;
public:
CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
: Sym(sym), SummaryLog(log) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int x = 0;
ID.AddPointer(&x);
ID.AddPointer(Sym);
}
std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
BugReport &BR) override;
std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR) override;
};
class CFRefLeakReportVisitor : public CFRefReportVisitor {
public:
CFRefLeakReportVisitor(SymbolRef sym,
const SummaryLogTy &log)
: CFRefReportVisitor(sym, log) {}
std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
const ExplodedNode *N,
BugReport &BR) override;
};
class CFRefReport : public BugReport {
public:
CFRefReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
bool registerVisitor = true)
: BugReport(D, D.getDescription(), n) {
if (registerVisitor)
addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
}
CFRefReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
StringRef endText)
: BugReport(D, D.getDescription(), endText, n) {
addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
}
llvm::iterator_range<ranges_iterator> getRanges() override {
const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
if (!BugTy.isLeak())
return BugReport::getRanges();
return llvm::make_range(ranges_iterator(), ranges_iterator());
}
};
class CFRefLeakReport : public CFRefReport {
const MemRegion* AllocBinding;
const Stmt *AllocStmt;
// Finds the function declaration where a leak warning for the parameter
// 'sym' should be raised.
void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
// Finds the location where a leak warning for 'sym' should be raised.
void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
// Produces description of a leak warning which is printed on the console.
void createDescription(CheckerContext &Ctx, bool IncludeAllocationLine);
public:
CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
CheckerContext &Ctx,
bool IncludeAllocationLine);
PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
assert(Location.isValid());
return Location;
}
};
} // end namespace retaincountchecker
} // end namespace ento
} // end namespace clang
#endif