[cfe-dev] Trouble using TextDiagnosticPrinter

Billy O'Mahony via cfe-dev cfe-dev at lists.llvm.org
Fri Oct 16 01:26:37 PDT 2020


  Hi Andrzej,

success!

The trick was that I needed to add the setForceEmit() call and only that.
But I'd already got sidetracked with rolling my own DiagConsumer. When I
removed all that it worked perfectly (but I did have to leave in the
setForceEmit() - not sure why - maybe my FEAction or ASTConsumer classes
are not doing some finalization calls that. I'll have to look closely at
the CSC example again.

Thanks for your help and clang-tutor. I will undoubtedly be referring to
clang-tutor again in the future.

On Thu, 15 Oct 2020 at 09:51, Andrzej Warzynski via cfe-dev <
cfe-dev at lists.llvm.org> wrote:

> Billy,
>
> Are you more interested in:
>    * understanding the Diagnostics API within Clang? or
>    * writing a tool that can emit diagnostics?
>
> The former will be much easier and straightforward if you use the
> clang::tooling API. Please, see example here:
> *
>
> https://github.com/banach-space/clang-tutor/blob/master/tools/CodeStyleCheckerMain.cpp#L45-L47
> With clang::tooling, DiagnosticsEngine and DiagnosticConsumer are set
> and managed for you behind the scenes (i.e. you shouldn't need to do
> anything extra). If you check a backtrace in your debugger, you'll
> notice that the driver within libclangFrontend manages that for you
> (i.e. creates a CompilerInstance, which contains DiagnosticEngine, which
> contains the default DiagnosticConsumer -> more or less ;-) ).
>
> However, if you _are_ interested in the diagnostics APIs, then like Ray
> has highlighted - managing the resources is often the root cause of most
> issues. These APIs are quite complex though and this can take a fair bit
> of trial and error. Having said that, do upload your code on GitHub and
> I can take a look if you want.
>
> -Andrzej
>
> On 14/10/2020 20:33, Ray Zhang via cfe-dev wrote:
> > Hi Billy,
> >
> > I've also run into this issue but I skirted around it by creating a
> > FixItRewriter
> > <https://clang.llvm.org/doxygen/classclang_1_1FixItRewriter.html> which
> > is actually a DiagnosticConsumer which the diagnostics engine DOESN'T
> > own. Unsure if this is the same case that you're running into, but when
> > I was experiencing segfaults I found it to be an issue with lifetime
> > management for diagnostic consumers. YMMV since the issue is within the
> > FixItRewriter impl itself, but the class stores a pointer to the current
> > diagnostic engine's client before setting the instance of FixItRewriter
> > as our own. If we tell the engine to own the FixItRewriter, then the
> > previous consumer is destroyed, and our FixItRewriter is then pointing
> > to a destroyed resource. Can you try creating a std::unique_ptr for your
> > own diagnostics consumer and tell the engine not to own it? You'd have
> > to take care of the storage lifetime in this case.
> >
> > Also, one more thing is, when the Builder object gets destroyed it
> > performs an Emit(), and if you previously Emit then it won't do a
> > double-write. At the closing curly brace of your VisitFunctionDecl, it
> > may be a good idea to check which consumer you are currently using. I
> > did a GDB backtrace in my situation at the end-curly-brace and found
> > that the diagnostics consumer used to emit the message was actually not
> > the one I thought I was using.
> >
> > Since I didn't use the Visitor pattern but rather the Matcher pattern,
> > my scope of how the two use cases differ are limited. Hope you find the
> bug!
> >
> > Best,
> > Ray
> >
> > On Wed, Oct 14, 2020 at 12:17 PM Billy O'Mahony via cfe-dev
> > <cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>> wrote:
> >
> >     Hi,
> >
> >     After much hacking I managed to write a DiagnosticConsumer that
> >     would emit some error messages for me. Kudos to Andrzej for his help.
> >
> >     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.
> >
> >     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.
> >
> >     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.
> >
> >     Thanks,
> >     Billy.
> >
> >     class MyDiagnosticConsumer : public clang::DiagnosticConsumer {
> >     public:
> >          void HandleDiagnostic(clang::DiagnosticsEngine::Level
> >     DiagLevel, const clang::Diagnostic& Info) override {
> >              llvm::SmallVector<char, 512> message;
> >              Info.FormatDiagnostic(message);
> >              llvm::errs() << message << '\n';
> >               cout << "Hello HandleDiagnostic!" << endl;
> >          }
> >     };
> >
> >     class MyVisitor : public RecursiveASTVisitor<MyVisitor> {
> >     public:
> >        explicit MyVisitor(ASTContext *context)
> >          : mContext(context) {}
> >
> >        bool VisitFunctionDecl(FunctionDecl* fnDecl) {
> >            // let's just issue an error on every function decl!
> >
> >            auto& diagEngine = mContext->getDiagnostics();
> >            const auto ID =
> >     diagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
> >                                                       "%0 declared? You
> >     insensitive clod!");
> >            auto Builder = diagEngine.Report(fnDecl->getLocation(), ID);
> >            Builder.AddString(fnDecl->getNameAsString());
> >
> >
>  Builder.AddSourceRange(clang::CharSourceRange::getCharRange(call->getSourceRange()));
> >            Builder.setForceEmit();  // <<< without this
> >     MyDiagnosticConsumer::HandleDiagnostic is never called !!
> >
> >            return true;
> >        }
> >
> >     private:
> >        ASTContext *mContext;
> >     };
> >
> >
> >     class MyConsumer : public clang::ASTConsumer {
> >     public:
> >        explicit MyConsumer(ASTContext *Context) : Visitor(Context) {
> >
> >            DiagnosticsEngine &diagEngine = Context->getDiagnostics();
> >
> >            // if I set my own DiagnosticsConsumer here it works (but no
> >     line/file info).
> >            diagEngine.setClient(new MyDiagnosticConsumer(),
> >     /*ShouldOwnClient=*/true);
> >
> >            ---- OR ----
> >
> >            // if I set a TextDiagnosticPrinter it crashes later on
> >            // At the point where I otherwise get an error like
> >     '.../include/bla.h' file not found.
> >            IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new
> >     DiagnosticOptions();
> >            TextDiagnosticPrinter *DiagClient =
> >                new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
> >            diagEngine.setClient(DiagClient, true); // true =>
> >     shouldOwnClient
> >        }
> >
> >        virtual void HandleTranslationUnit(clang::ASTContext &Context) {
> >            auto Decls = Context.getTranslationUnitDecl()->decls();
> >            auto &SM = Context.getSourceManager();
> >            for (auto &Decl : Decls) {
> >                const auto& FileID = SM.getFileID(Decl->getLocation());
> >                if (FileID != SM.getMainFileID()) {
> >                    // Skip decls coming via #incl
> >                    continue;
> >                }
> >
> >                Visitor.TraverseDecl(Decl);
> >            }
> >        }
> >
> >     private:
> >        MyVisitor Visitor;
> >     };
> >
> >
> >
> >
> >     Program received signal SIGSEGV, Segmentation fault.
> >     clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
> >     Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
> >          FixItHints=..., D=...) at
> >
>  /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95
> >     95        beginDiagnostic(D, Level);
> >     (gdb) bt
> >     #0  clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
> >     Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
> >          FixItHints=..., D=...) at
> >
>  /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95
> >     #1  0x00000000084ce036 in
> >     clang::TextDiagnosticPrinter::HandleDiagnostic (this=0x9b22430,
> >     Level=clang::DiagnosticsEngine::Fatal, Info=...)
> >          at
> >
>  /home/bomahony/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp:152
> >
> >
> >     _______________________________________________
> >     cfe-dev mailing list
> >     cfe-dev at lists.llvm.org <mailto:cfe-dev at lists.llvm.org>
> >     https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
> >
> >
> > _______________________________________________
> > cfe-dev mailing list
> > cfe-dev at lists.llvm.org
> > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
> >
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20201016/ecf6c2ce/attachment-0001.html>


More information about the cfe-dev mailing list