added preliminary diagnostics in scan-build results to denote whether
a CF memory leak occurred with GC enabled, etc.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50507 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/ASTConsumers.cpp b/Driver/ASTConsumers.cpp
index c01e4ed..59e477a 100644
--- a/Driver/ASTConsumers.cpp
+++ b/Driver/ASTConsumers.cpp
@@ -813,16 +813,16 @@
virtual void getTransferFunctions(std::vector<GRTransferFuncs*>& TFs) {
switch (LangOpts.getGCMode()) {
case LangOptions::NonGC:
- TFs.push_back(MakeCFRefCountTF(*Ctx, false));
+ TFs.push_back(MakeCFRefCountTF(*Ctx, false, LangOpts));
break;
case LangOptions::GCOnly:
- TFs.push_back(MakeCFRefCountTF(*Ctx, true));
+ TFs.push_back(MakeCFRefCountTF(*Ctx, true, LangOpts));
break;
case LangOptions::HybridGC:
- TFs.push_back(MakeCFRefCountTF(*Ctx, false));
- TFs.push_back(MakeCFRefCountTF(*Ctx, true));
+ TFs.push_back(MakeCFRefCountTF(*Ctx, false, LangOpts));
+ TFs.push_back(MakeCFRefCountTF(*Ctx, true, LangOpts));
break;
}
}
diff --git a/Driver/HTMLDiagnostics.cpp b/Driver/HTMLDiagnostics.cpp
index 3e3571c..cb333b9 100644
--- a/Driver/HTMLDiagnostics.cpp
+++ b/Driver/HTMLDiagnostics.cpp
@@ -187,9 +187,16 @@
<< (*D.rbegin()).getLocation().getLogicalColumnNumber()
<< "</a></td></tr>\n"
"<tr><td class=\"rowname\">Description:</td><td>"
- << D.getDescription()
- << "</td></tr>\n</table>\n"
- "<h3>Annotated Source Code</h3>\n";
+ << D.getDescription() << "</td></tr>\n";
+
+ // Output any other meta data.
+
+ for (PathDiagnostic::meta_iterator I=D.meta_begin(), E=D.meta_end();
+ I!=E; ++I) {
+ os << "<tr><td></td><td>" << html::EscapeText(*I) << "</td></tr>\n";
+ }
+
+ os << "</table>\n<h3>Annotated Source Code</h3>\n";
R.InsertStrBefore(SourceLocation::getFileLoc(FileID, 0), os.str());
}
diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h
index bf4f30a..64dc4dd 100644
--- a/include/clang/Analysis/LocalCheckers.h
+++ b/include/clang/Analysis/LocalCheckers.h
@@ -24,14 +24,16 @@
class PathDiagnosticClient;
class GRTransferFuncs;
class BugType;
-
+class LangOptions;
+
void CheckDeadStores(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags);
void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
bool FullUninitTaint=false);
GRTransferFuncs* MakeGRSimpleValsTF();
-GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled);
+GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts);
BugType* MakeDeadStoresChecker();
} // end namespace clang
diff --git a/include/clang/Analysis/PathDiagnostic.h b/include/clang/Analysis/PathDiagnostic.h
index f9bd0fd..77234e7 100644
--- a/include/clang/Analysis/PathDiagnostic.h
+++ b/include/clang/Analysis/PathDiagnostic.h
@@ -65,6 +65,7 @@
std::list<PathDiagnosticPiece*> path;
unsigned Size;
std::string Desc;
+ std::vector<std::string> OtherDesc;
public:
PathDiagnostic() : Size(0) {}
@@ -75,6 +76,13 @@
const std::string& getDescription() const { return Desc; }
+ typedef std::vector<std::string>::const_iterator meta_iterator;
+ meta_iterator meta_begin() const { return OtherDesc.begin(); }
+ meta_iterator meta_end() const { return OtherDesc.end(); }
+ void addMeta(const std::string& s) { OtherDesc.push_back(s); }
+ void addMeta(const char* s) { OtherDesc.push_back(s); }
+
+
void push_front(PathDiagnosticPiece* piece) {
path.push_front(piece);
++Size;
diff --git a/include/clang/Analysis/PathSensitive/BugReporter.h b/include/clang/Analysis/PathSensitive/BugReporter.h
index 325e1a7..5a8606f 100644
--- a/include/clang/Analysis/PathSensitive/BugReporter.h
+++ b/include/clang/Analysis/PathSensitive/BugReporter.h
@@ -41,6 +41,10 @@
virtual const char* getName() const = 0;
virtual const char* getDescription() const { return getName(); }
+
+ virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
+ return std::pair<const char**, const char**>(0, 0);
+ }
virtual void EmitWarnings(BugReporter& BR) {}
virtual void GetErrorNodes(std::vector<ExplodedNode<ValueState>*>& Nodes) {}
@@ -78,6 +82,10 @@
return getBugType().getDescription();
}
+ virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
+ return getBugType().getExtraDescriptiveText();
+ }
+
virtual PathDiagnosticPiece* getEndPath(BugReporter& BR,
ExplodedNode<ValueState>* N) const;
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index d00d329..465acf0 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -448,6 +448,13 @@
llvm::OwningPtr<PathDiagnostic> D(new PathDiagnostic(R.getName()));
GeneratePathDiagnostic(*D.get(), R);
+
+ // Get the meta data.
+
+ std::pair<const char**, const char**> Meta = R.getExtraDescriptiveText();
+
+ for (const char** s = Meta.first; s != Meta.second; ++s)
+ D->addMeta(*s);
// Emit a full diagnostic for the path if we have a PathDiagnosticClient.
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 9ed4f1d..c5f582f 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "GRSimpleVals.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Analysis/PathSensitive/ValueState.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/LocalCheckers.h"
@@ -624,7 +625,8 @@
// Instance variables.
CFRefSummaryManager Summaries;
- const bool GCEnabled;
+ const bool GCEnabled;
+ const LangOptions& LOpts;
RefBFactoryTy RefBFactory;
UseAfterReleasesTy UseAfterReleases;
@@ -670,9 +672,10 @@
public:
- CFRefCount(ASTContext& Ctx, bool gcenabled)
+ CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
: Summaries(Ctx, gcenabled),
GCEnabled(gcenabled),
+ LOpts(lopts),
RetainSelector(GetUnarySelector("retain", Ctx)),
ReleaseSelector(GetUnarySelector("release", Ctx)) {}
@@ -687,6 +690,9 @@
return &Printer;
}
+ bool isGCEnabled() const { return GCEnabled; }
+ const LangOptions& getLangOptions() const { return LOpts; }
+
// Calls.
virtual void EvalCall(ExplodedNodeSet<ValueState>& Dst,
@@ -1375,6 +1381,8 @@
public:
CFRefBug(CFRefCount& tf) : TF(tf) {}
+
+ CFRefCount& getTF() { return TF; }
};
class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
@@ -1390,7 +1398,6 @@
}
virtual void EmitWarnings(BugReporter& BR);
-
};
class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
@@ -1432,11 +1439,12 @@
class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
SymbolID Sym;
public:
- CFRefReport(BugType& D, ExplodedNode<ValueState> *n, SymbolID sym)
+ CFRefReport(CFRefBug& D, ExplodedNode<ValueState> *n, SymbolID sym)
: RangedBugReport(D, n), Sym(sym) {}
virtual ~CFRefReport() {}
+ virtual std::pair<const char**,const char**> getExtraDescriptiveText();
virtual PathDiagnosticPiece* VisitNode(ExplodedNode<ValueState>* N,
ExplodedNode<ValueState>* PrevN,
@@ -1454,6 +1462,43 @@
Eng.Register(new Leak(*this));
}
+
+static const char* Msgs[] = {
+ "Code is compiled in garbage collection only mode" // GC only
+ " (the bug occurs with garbage collection enabled).",
+
+ "Code is compiled without garbage collection.", // No GC.
+
+ "Code is compiled for use with and without garbage collection (GC)."
+ " The bug occurs with GC enabled.", // Hybrid, with GC.
+
+ "Code is compiled for use with and without garbage collection (GC)."
+ " The bug occurs in non-GC mode." // Hyrbird, without GC/
+};
+
+std::pair<const char**,const char**> CFRefReport::getExtraDescriptiveText() {
+ CFRefCount& TF = static_cast<CFRefBug&>(getBugType()).getTF();
+
+ switch (TF.getLangOptions().getGCMode()) {
+ default:
+ assert(false);
+
+ case LangOptions::NonGC:
+ assert (!TF.isGCEnabled());
+ return std::make_pair(&Msgs[0], &Msgs[0]+1);
+
+ case LangOptions::GCOnly:
+ assert (TF.isGCEnabled());
+ return std::make_pair(&Msgs[1], &Msgs[1]+1);
+
+ case LangOptions::HybridGC:
+ if (TF.isGCEnabled())
+ return std::make_pair(&Msgs[2], &Msgs[2]+1);
+ else
+ return std::make_pair(&Msgs[3], &Msgs[3]+1);
+ }
+}
+
PathDiagnosticPiece* CFRefReport::VisitNode(ExplodedNode<ValueState>* N,
ExplodedNode<ValueState>* PrevN,
ExplodedGraph<ValueState>& G,
@@ -1618,6 +1663,7 @@
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//
-GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled) {
- return new CFRefCount(Ctx, GCEnabled);
+GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
+ const LangOptions& lopts) {
+ return new CFRefCount(Ctx, GCEnabled, lopts);
}