Hi chandlerc,
This is immediately useful for generating macro expansion notes, and
may be useful for other things later on.
http://llvm-reviews.chandlerc.com/D2950
Files:
clang-tidy/ClangTidyDiagnosticConsumer.cpp
clang-tidy/ClangTidyDiagnosticConsumer.h
test/clang-tidy/diagnostic.cpp
test/clang-tidy/macros.cpp
Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp
===================================================================
--- clang-tidy/ClangTidyDiagnosticConsumer.cpp
+++ clang-tidy/ClangTidyDiagnosticConsumer.cpp
@@ -18,24 +18,96 @@
#include "ClangTidyDiagnosticConsumer.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
namespace clang {
namespace tidy {
+class ClangTidyDiagnosticRenderer : public DiagnosticRenderer {
+public:
+ ClangTidyDiagnosticRenderer(const LangOptions &LangOpts,
+ DiagnosticOptions *DiagOpts,
+ ClangTidyError &Output)
+ : DiagnosticRenderer(LangOpts, DiagOpts), Output(Output) {}
+
+protected:
+ void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level, StringRef Message,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager *SM,
+ DiagOrStoredDiag Info) override {
+ if (Level == DiagnosticsEngine::Ignored)
+ return;
+ ClangTidyMessage TidyMessage = Loc.isValid()
+ ? ClangTidyMessage(Message, *SM, Loc)
+ : ClangTidyMessage(Message);
+ if (Level == DiagnosticsEngine::Note) {
+ Output.Notes.push_back(TidyMessage);
+ return;
+ }
+ assert(Output.Message.Message.empty() &&
+ "Overwriting a diagnostic message");
+ Output.Message = TidyMessage;
+ }
+
+ void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+ DiagnosticsEngine::Level Level,
+ ArrayRef<CharSourceRange> Ranges,
+ const SourceManager &SM) override {}
+
+ void emitBasicNote(StringRef Message) override {
+ Output.Notes.push_back(ClangTidyMessage(Message));
+ }
+
+ void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level,
+ SmallVectorImpl<CharSourceRange> &Ranges,
+ ArrayRef<FixItHint> Hints,
+ const SourceManager &SM) override {
+ assert(Loc.isValid());
+ for (auto FixIt : Hints) {
+ // FIXME: Find out if const_cast is valid here.
+ Output.Fix.insert(tooling::Replacement(const_cast<SourceManager &>(SM),
+ FixIt.RemoveRange.getBegin(), 0,
+ FixIt.CodeToInsert));
+ }
+ }
+
+ void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc,
+ const SourceManager &SM) override {}
+
+ void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) override {}
+
+ void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc,
+ StringRef ModuleName,
+ const SourceManager &SM) override {}
+
+ void endDiagnostic(DiagOrStoredDiag D,
+ DiagnosticsEngine::Level Level) override {
+ assert(!Output.Message.Message.empty() && "Message has not been set");
+ }
+
+private:
+ ClangTidyError &Output;
+};
+
ClangTidyMessage::ClangTidyMessage(StringRef Message) : Message(Message) {}
ClangTidyMessage::ClangTidyMessage(StringRef Message,
const SourceManager &Sources,
SourceLocation Loc)
: Message(Message) {
+ assert(Loc.isValid() && Loc.isFileID());
FilePath = Sources.getFilename(Loc);
FileOffset = Sources.getFileOffset(Loc);
}
-ClangTidyError::ClangTidyError(StringRef CheckName,
- const ClangTidyMessage &Message)
- : CheckName(CheckName), Message(Message) {}
+ClangTidyError::ClangTidyError(StringRef CheckName)
+ : CheckName(CheckName) {}
DiagnosticBuilder ClangTidyContext::diag(
StringRef CheckName, SourceLocation Loc, StringRef Description,
@@ -102,13 +174,24 @@
if (DiagLevel == DiagnosticsEngine::Note) {
assert(!Errors.empty() &&
"A diagnostic note can only be appended to a message.");
- Errors.back().Notes.push_back(getMessage(Info));
} else {
finalizeLastError();
- Errors.push_back(
- ClangTidyError(Context.getCheckName(Info.getID()), getMessage(Info)));
+ Errors.push_back(ClangTidyError(Context.getCheckName(Info.getID())));
}
- addFixes(Info, Errors.back());
+
+ // FIXME: Provide correct LangOptions for each file.
+ LangOptions LangOpts;
+ ClangTidyDiagnosticRenderer Converter(
+ LangOpts, &Context.DiagEngine->getDiagnosticOptions(), Errors.back());
+ SmallString<100> Message;
+ Info.FormatDiagnostic(Message);
+ SourceManager *Sources = nullptr;
+ if (Info.hasSourceManager())
+ Sources = &Info.getSourceManager();
+ Converter.emitDiagnostic(
+ Info.getLocation(), DiagLevel, Message, Info.getRanges(),
+ llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()),
+ Sources);
// Let argument parsing-related warnings through.
if (!Diags->hasSourceManager() ||
@@ -125,29 +208,5 @@
Errors.clear();
}
-void ClangTidyDiagnosticConsumer::addFixes(const Diagnostic &Info,
- ClangTidyError &Error) {
- if (!Info.hasSourceManager())
- return;
- SourceManager &SourceMgr = Info.getSourceManager();
- tooling::Replacements Replacements;
- for (unsigned i = 0, e = Info.getNumFixItHints(); i != e; ++i) {
- Error.Fix.insert(tooling::Replacement(
- SourceMgr, Info.getFixItHint(i).RemoveRange.getBegin(), 0,
- Info.getFixItHint(i).CodeToInsert));
- }
-}
-
-ClangTidyMessage
-ClangTidyDiagnosticConsumer::getMessage(const Diagnostic &Info) const {
- SmallString<100> Buf;
- Info.FormatDiagnostic(Buf);
- if (!Info.hasSourceManager()) {
- return ClangTidyMessage(Buf.str());
- }
- return ClangTidyMessage(Buf.str(), Info.getSourceManager(),
- Info.getLocation());
-}
-
} // namespace tidy
} // namespace clang
Index: clang-tidy/ClangTidyDiagnosticConsumer.h
===================================================================
--- clang-tidy/ClangTidyDiagnosticConsumer.h
+++ clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -47,7 +47,7 @@
///
/// FIXME: Make Diagnostics flexible enough to support this directly.
struct ClangTidyError {
- ClangTidyError(StringRef CheckName, const ClangTidyMessage &Message);
+ ClangTidyError(StringRef CheckName);
std::string CheckName;
ClangTidyMessage Message;
@@ -123,8 +123,6 @@
void finish() override;
private:
- void addFixes(const Diagnostic &Info, ClangTidyError &Error);
- ClangTidyMessage getMessage(const Diagnostic &Info) const;
void finalizeLastError();
ClangTidyContext &Context;
Index: test/clang-tidy/diagnostic.cpp
===================================================================
--- test/clang-tidy/diagnostic.cpp
+++ test/clang-tidy/diagnostic.cpp
@@ -1,5 +1,2 @@
-// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
-// RUN: clang-tidy %t.cpp -- -fan-unknown-option > %t2.cpp
-// RUN: FileCheck -input-file=%t2.cpp %s
-
+// RUN: clang-tidy %s -- -fan-unknown-option | FileCheck %s
// CHECK: warning: unknown argument: '-fan-unknown-option'
Index: test/clang-tidy/macros.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/macros.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-tidy -checks=google-explicit-constructor %s -- | FileCheck %s
+
+#define Q(name) class name { name(int i); }
+
+Q(A);
+// CHECK: :[[@LINE-1]]:3: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: :3:30: note: expanded from macro 'Q'
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits