[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