<div dir="ltr">Hi,<div><br></div><div>After much hacking I managed to write a DiagnosticConsumer that would emit some error messages for me. Kudos to Andrzej for his help.</div><div><br></div><div>I was expecting that I would more or less automatically get filename, line number and some source location carets added and some nice coloured text on my console. So for that I think I might need to use TextDiagnosticPrinter? However when I try to setClient that in my ASTContext's diagEngine it segfaults when a diagnostic is emitted.</div><div><br></div><div>I've tried looking in the clang/tools files for inspiration from other FrontendAction style tools but they either don't use TextDiagnosticPrinter or else they use some other clang infra like clang/Rewrite/Core/Rewriter.h.</div><div><br></div><div>This really feels like it should be super simple but I'm finding it very frustrating. My tool is actually doing useful things to spot project-specific code defects but now adding something simple like neat error messages is turning into a total quagmire.</div><div><br></div><div>Thanks,</div><div>Billy.</div><div><br></div><div>class MyDiagnosticConsumer : public clang::DiagnosticConsumer {<br>public:<br>    void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic& Info) override {<br>        llvm::SmallVector<char, 512> message;<br>        Info.FormatDiagnostic(message);<br>        llvm::errs() << message << '\n';<br>         cout << "Hello HandleDiagnostic!" << endl;<br>    }<br>};<br><br>class MyVisitor : public RecursiveASTVisitor<MyVisitor> {<br>public:<br>  explicit MyVisitor(ASTContext *context)<br>    : mContext(context) {}<br><br>  bool VisitFunctionDecl(FunctionDecl* fnDecl) {<br>      // let's just issue an error on every function decl!<br>      <br>      auto& diagEngine = mContext->getDiagnostics();<br>      const auto ID = diagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,<br>                                                 "%0 declared? You insensitive clod!");<br>      auto Builder = diagEngine.Report(fnDecl->getLocation(), ID);<br>      Builder.AddString(fnDecl->getNameAsString());<br>      Builder.AddSourceRange(clang::CharSourceRange::getCharRange(call->getSourceRange()));<br>      Builder.setForceEmit();  // <<< without this MyDiagnosticConsumer::HandleDiagnostic is never called !!<br><br>      return true;<br>  }<br><br>private:<br>  ASTContext *mContext;<br>};<br><br><br>class MyConsumer : public clang::ASTConsumer {<br>public:<br>  explicit MyConsumer(ASTContext *Context) : Visitor(Context) {<br>      <br>      DiagnosticsEngine &diagEngine = Context->getDiagnostics();<br>      <br>      // if I set my own DiagnosticsConsumer here it works (but no line/file info).<br>      diagEngine.setClient(new MyDiagnosticConsumer(), /*ShouldOwnClient=*/true);<br>      <br>      ---- OR ----<br>      <br>      // if I set a TextDiagnosticPrinter it crashes later on <br>      // At the point where I otherwise get an error like '.../include/bla.h' file not found.<br>      IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();<br>      TextDiagnosticPrinter *DiagClient =<br>          new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);<br>      diagEngine.setClient(DiagClient, true); // true => shouldOwnClient<br>  }<br><br>  virtual void HandleTranslationUnit(clang::ASTContext &Context) {<br>      auto Decls = Context.getTranslationUnitDecl()->decls();<br>      auto &SM = Context.getSourceManager();<br>      for (auto &Decl : Decls) {<br>          const auto& FileID = SM.getFileID(Decl->getLocation());<br>          if (FileID != SM.getMainFileID()) {<br>              // Skip decls coming via #incl<br>              continue;<br>          }<br><br>          Visitor.TraverseDecl(Decl);<br>      }<br>  }<br><br>private:<br>  MyVisitor Visitor;<br>};<br><br><br><br><br>Program received signal SIGSEGV, Segmentation fault.<br>clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=..., Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,<br>    FixItHints=..., D=...) at /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95<br>95        beginDiagnostic(D, Level);<br>(gdb) bt<br>#0  clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=..., Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,<br>    FixItHints=..., D=...) at /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95<br>#1  0x00000000084ce036 in clang::TextDiagnosticPrinter::HandleDiagnostic (this=0x9b22430, Level=clang::DiagnosticsEngine::Fatal, Info=...)<br>    at /home/bomahony/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp:152<br>    <br>    <br></div></div>