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

Reply via email to