Hi klimek,
This patch depends on patches D2556 and D2557.
http://llvm-reviews.chandlerc.com/D2620
Files:
clang-tidy/ClangTidy.cpp
clang-tidy/ClangTidyDiagnosticConsumer.cpp
clang-tidy/ClangTidyDiagnosticConsumer.h
test/clang-tidy/static-analyzer.cpp
Index: clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tidy/ClangTidy.cpp
+++ clang-tidy/ClangTidy.cpp
@@ -59,6 +59,57 @@
#undef GET_CHECKERS
};
+class AnalyzerDiagnosticConsumer : public ento::PathDiagnosticConsumer {
+public:
+ AnalyzerDiagnosticConsumer(ClangTidyContext &Context) : Context(Context) {}
+
+ virtual void
+ FlushDiagnosticsImpl(std::vector<const ento::PathDiagnostic *> &Diags,
+ FilesMade *filesMade) LLVM_OVERRIDE {
+ for (std::vector<const ento::PathDiagnostic *>::iterator I = Diags.begin(),
+ E = Diags.end();
+ I != E; ++I) {
+ const ento::PathDiagnostic *PD = *I;
+ SmallString<64> CheckerName(AnalyzerCheckerNamePrefix);
+ CheckerName += PD->getCheckerName();
+ addRanges(Context.diag(CheckerName, PD->getLocation().asLocation(),
+ PD->getShortDescription()),
+ PD->path.back()->getRanges());
+
+ ento::PathPieces FlatPath =
+ PD->path.flatten(/*ShouldFlattenMacros=*/true);
+ for (ento::PathPieces::const_iterator PI = FlatPath.begin(),
+ PE = FlatPath.end();
+ PI != PE; ++PI) {
+ addRanges(Context.diag(CheckerName, (*PI)->getLocation().asLocation(),
+ (*PI)->getString(), DiagnosticsEngine::Note),
+ (*PI)->getRanges());
+ }
+ }
+ }
+
+ virtual StringRef getName() const { return "ClangTidyDiags"; }
+
+ virtual bool supportsLogicalOpControlFlow() const LLVM_OVERRIDE {
+ return true;
+ }
+ virtual bool supportsCrossFileDiagnostics() const LLVM_OVERRIDE {
+ return true;
+ }
+
+private:
+ ClangTidyContext &Context;
+
+ // FIXME: Convert to operator<<(DiagnosticBuilder&, ArrayRef<SourceRange>).
+ static const DiagnosticBuilder &addRanges(const DiagnosticBuilder &DB,
+ ArrayRef<SourceRange> Ranges) {
+ for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end();
+ I != E; ++I)
+ DB << *I;
+ return DB;
+ }
+};
+
} // namespace
ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
@@ -103,15 +154,15 @@
AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts();
Options->CheckersControlList = getCheckersControlList();
Options->AnalysisStoreOpt = RegionStoreModel;
- Options->AnalysisDiagOpt = PD_TEXT;
+ Options->AnalysisDiagOpt = PD_NONE;
Options->AnalyzeNestedBlocks = true;
Options->eagerlyAssumeBinOpBifurcation = true;
- ASTConsumer *Consumers[] = {
- Finder.newASTConsumer(),
- ento::CreateAnalysisConsumer(Compiler.getPreprocessor(),
- Compiler.getFrontendOpts().OutputFile, Options,
- Compiler.getFrontendOpts().Plugins)
- };
+ ento::AnalysisASTConsumer *AnalysisConsumer = ento::CreateAnalysisConsumer(
+ Compiler.getPreprocessor(), Compiler.getFrontendOpts().OutputFile,
+ Options, Compiler.getFrontendOpts().Plugins);
+ AnalysisConsumer->AddDiagnosticConsumer(
+ new AnalyzerDiagnosticConsumer(Context));
+ ASTConsumer *Consumers[] = { Finder.newASTConsumer(), AnalysisConsumer };
return new MultiplexConsumer(Consumers);
}
@@ -240,21 +291,16 @@
static void reportDiagnostic(const ClangTidyMessage &Message,
SourceManager &SourceMgr,
DiagnosticsEngine::Level Level,
- DiagnosticsEngine &Diags,
- StringRef CheckName = "") {
+ DiagnosticsEngine &Diags) {
SourceLocation Loc;
if (!Message.FilePath.empty()) {
const FileEntry *File =
SourceMgr.getFileManager().getFile(Message.FilePath);
FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
Loc = SourceMgr.getLocForStartOfFile(ID);
Loc = Loc.getLocWithOffset(Message.FileOffset);
}
- if (CheckName.empty())
- Diags.Report(Loc, Diags.getCustomDiagID(Level, Message.Message));
- else
- Diags.Report(Loc, Diags.getCustomDiagID(Level, (Message.Message + " [" +
- CheckName + "]").str()));
+ Diags.Report(Loc, Diags.getCustomDiagID(Level, Message.Message));
}
void handleErrors(SmallVectorImpl<ClangTidyError> &Errors, bool Fix) {
@@ -270,8 +316,7 @@
for (SmallVectorImpl<ClangTidyError>::iterator I = Errors.begin(),
E = Errors.end();
I != E; ++I) {
- reportDiagnostic(I->Message, SourceMgr, DiagnosticsEngine::Warning, Diags,
- I->CheckName);
+ reportDiagnostic(I->Message, SourceMgr, DiagnosticsEngine::Warning, Diags);
for (unsigned i = 0, e = I->Notes.size(); i != e; ++i) {
reportDiagnostic(I->Notes[i], SourceMgr, DiagnosticsEngine::Note, Diags);
}
Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp
===================================================================
--- clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -37,11 +37,11 @@
const ClangTidyMessage &Message)
: CheckName(CheckName), Message(Message) {}
-DiagnosticBuilder ClangTidyContext::diag(StringRef CheckName,
- SourceLocation Loc,
- StringRef Message) {
- unsigned ID =
- DiagEngine->getCustomDiagID(DiagnosticsEngine::Warning, Message);
+DiagnosticBuilder ClangTidyContext::diag(
+ StringRef CheckName, SourceLocation Loc, StringRef Message,
+ DiagnosticsEngine::Level Level /* = DiagnosticsEngine::Warning*/) {
+ unsigned ID = DiagEngine->getCustomDiagID(
+ Level, (Message + " [" + CheckName + "]").str());
if (CheckNamesByDiagnosticID.count(ID) == 0)
CheckNamesByDiagnosticID.insert(std::make_pair(ID, CheckName.str()));
return DiagEngine->Report(Loc, ID);
@@ -80,10 +80,6 @@
void ClangTidyDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) {
// FIXME: Demultiplex diagnostics.
- // FIXME: Ensure that we don't get notes from user code related to errors
- // from non-user code.
- if (Diags->getSourceManager().isInSystemHeader(Info.getLocation()))
- return;
if (DiagLevel != DiagnosticsEngine::Note) {
Errors.push_back(
ClangTidyError(Context.getCheckName(Info.getID()), getMessage(Info)));
@@ -93,12 +89,18 @@
Errors.back().Notes.push_back(getMessage(Info));
}
addFixes(Info, Errors.back());
+
+ RelatesToUserCode.resize(Errors.size());
+ if (!Diags->getSourceManager().isInSystemHeader(Info.getLocation())) {
+ RelatesToUserCode[Errors.size() - 1] = true;
+ }
}
// Flushes the internal diagnostics buffer to the ClangTidyContext.
void ClangTidyDiagnosticConsumer::finish() {
for (unsigned i = 0, e = Errors.size(); i != e; ++i) {
- Context.storeError(Errors[i]);
+ if (RelatesToUserCode[i])
+ Context.storeError(Errors[i]);
}
Errors.clear();
}
Index: clang-tidy/ClangTidyDiagnosticConsumer.h
===================================================================
--- clang-tidy/ClangTidyDiagnosticConsumer.h
+++ clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -74,8 +74,9 @@
/// This is still under heavy development and will likely change towards using
/// tablegen'd diagnostic IDs.
/// FIXME: Figure out a way to manage ID spaces.
- DiagnosticBuilder diag(StringRef CheckName, SourceLocation Loc,
- StringRef Message);
+ DiagnosticBuilder
+ diag(StringRef CheckName, SourceLocation Loc, StringRef Message,
+ DiagnosticsEngine::Level Level = DiagnosticsEngine::Warning);
/// \brief Sets the \c DiagnosticsEngine so that Diagnostics can be generated
/// correctly.
@@ -128,6 +129,7 @@
ClangTidyContext &Context;
OwningPtr<DiagnosticsEngine> Diags;
SmallVector<ClangTidyError, 8> Errors;
+ SmallVector<bool, 8> RelatesToUserCode;
};
} // end namespace tidy
Index: test/clang-tidy/static-analyzer.cpp
===================================================================
--- test/clang-tidy/static-analyzer.cpp
+++ test/clang-tidy/static-analyzer.cpp
@@ -1,8 +1,17 @@
-// RUN: clang-tidy %s -checks='clang-analyzer-cplusplus' -- | FileCheck %s
+// RUN: clang-tidy %s -checks='clang-analyzer-' -- | FileCheck %s
+extern void *malloc(unsigned long);
+extern void free(void *);
void f() {
int *p = new int(42);
delete p;
delete p;
- // CHECK: warning: Attempt to free released memory
+ // CHECK: warning: Attempt to free released memory [clang-analyzer-cplusplus.NewDelete]
+}
+
+void g() {
+ void *q = malloc(132);
+ free(q);
+ free(q);
+ // CHECK: warning: Attempt to free released memory [clang-analyzer-unix.Malloc]
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits