From: Douglas Gregor Date: Thu, 29 Sep 2011 00:38:00 +0000 (+0000) Subject: Introduce a pure virtual clone() method to DiagnosticConsumer, so that X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aee526e77657afd1600276450e9c346953ad51d7;p=clang Introduce a pure virtual clone() method to DiagnosticConsumer, so that we have the ability to create a new, distict diagnostic consumer when we go off and build a module. This avoids the currently horribleness where the same diagnostic consumer sees diagnostics for multiple translation units (and multiple SourceManagers!) causing all sorts of havok. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140743 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Diagnostic.h b/include/clang/Basic/Diagnostic.h index a1a3d44d44..d9b447947e 100644 --- a/include/clang/Basic/Diagnostic.h +++ b/include/clang/Basic/Diagnostic.h @@ -1072,6 +1072,22 @@ public: /// and errors. virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info); + + /// \brief Clone the diagnostic consumer, producing an equivalent consumer + /// that can be used in a different context. + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const = 0; +}; + +/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all +/// diags. +class IgnoringDiagConsumer : public DiagnosticConsumer { + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + // Just ignore it. + } + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IgnoringDiagConsumer(); + } }; } // end namespace clang diff --git a/include/clang/Frontend/ChainedDiagnosticConsumer.h b/include/clang/Frontend/ChainedDiagnosticConsumer.h index 125a9b2bf7..f20cf6fcf4 100644 --- a/include/clang/Frontend/ChainedDiagnosticConsumer.h +++ b/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -54,6 +54,12 @@ public: Primary->HandleDiagnostic(DiagLevel, Info); Secondary->HandleDiagnostic(DiagLevel, Info); } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new ChainedDiagnosticConsumer(Primary->clone(Diags), + Secondary->clone(Diags)); + } + }; } // end namspace clang diff --git a/include/clang/Frontend/CompilerInstance.h b/include/clang/Frontend/CompilerInstance.h index d44f507d02..881774022d 100644 --- a/include/clang/Frontend/CompilerInstance.h +++ b/include/clang/Frontend/CompilerInstance.h @@ -460,9 +460,13 @@ public: /// /// \param ShouldOwnClient If Client is non-NULL, specifies whether /// the diagnostic object should take ownership of the client. + /// + /// \param ShouldCloneClient If Client is non-NULL, specifies whether that + /// client should be cloned. void createDiagnostics(int Argc, const char* const *Argv, DiagnosticConsumer *Client = 0, - bool ShouldOwnClient = true); + bool ShouldOwnClient = true, + bool ShouldCloneClient = true); /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter. /// @@ -492,6 +496,7 @@ public: const char* const *Argv, DiagnosticConsumer *Client = 0, bool ShouldOwnClient = true, + bool ShouldCloneClient = true, const CodeGenOptions *CodeGenOpts = 0); /// Create the file manager and replace any existing one with it. diff --git a/include/clang/Frontend/LogDiagnosticPrinter.h b/include/clang/Frontend/LogDiagnosticPrinter.h index e12752b4f8..4de15f2aed 100644 --- a/include/clang/Frontend/LogDiagnosticPrinter.h +++ b/include/clang/Frontend/LogDiagnosticPrinter.h @@ -70,6 +70,8 @@ public: virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; }; } // end namespace clang diff --git a/include/clang/Frontend/TextDiagnosticBuffer.h b/include/clang/Frontend/TextDiagnosticBuffer.h index 93ac299da3..6f1c0e8aea 100644 --- a/include/clang/Frontend/TextDiagnosticBuffer.h +++ b/include/clang/Frontend/TextDiagnosticBuffer.h @@ -45,6 +45,8 @@ public: /// FlushDiagnostics - Flush the buffered diagnostics to an given /// diagnostic engine. void FlushDiagnostics(DiagnosticsEngine &Diags) const; + + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; }; } // end namspace clang diff --git a/include/clang/Frontend/TextDiagnosticPrinter.h b/include/clang/Frontend/TextDiagnosticPrinter.h index f3dec55f10..22fa18b050 100644 --- a/include/clang/Frontend/TextDiagnosticPrinter.h +++ b/include/clang/Frontend/TextDiagnosticPrinter.h @@ -59,6 +59,8 @@ public: virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; + private: void EmitDiagnosticLoc(DiagnosticsEngine::Level Level, const Diagnostic &Info, diff --git a/include/clang/Frontend/VerifyDiagnosticConsumer.h b/include/clang/Frontend/VerifyDiagnosticConsumer.h index a74c809109..28dc9de03a 100644 --- a/include/clang/Frontend/VerifyDiagnosticConsumer.h +++ b/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -88,6 +88,8 @@ public: virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info); + + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; }; } // end namspace clang diff --git a/include/clang/Rewrite/FixItRewriter.h b/include/clang/Rewrite/FixItRewriter.h index d98058134c..bf7e7911c9 100644 --- a/include/clang/Rewrite/FixItRewriter.h +++ b/include/clang/Rewrite/FixItRewriter.h @@ -97,6 +97,8 @@ public: /// \brief Emit a diagnostic via the adapted diagnostic client. void Diag(SourceLocation Loc, unsigned DiagID); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; }; } diff --git a/include/clang/Rewrite/Rewriter.h b/include/clang/Rewrite/Rewriter.h index ad46379020..f1358a0c85 100644 --- a/include/clang/Rewrite/Rewriter.h +++ b/include/clang/Rewrite/Rewriter.h @@ -154,8 +154,8 @@ public: SourceMgr = &SM; LangOpts = &LO; } - SourceManager &getSourceMgr() { return *SourceMgr; } - const LangOptions &getLangOpts() { return *LangOpts; } + SourceManager &getSourceMgr() const { return *SourceMgr; } + const LangOptions &getLangOpts() const { return *LangOpts; } /// isRewritable - Return true if this location is a raw file location, which /// is rewritable. Locations from macros, etc are not rewritable. diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 05bc150487..6e1b0e535b 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -93,7 +93,7 @@ class CaptureDiagnosticConsumer : public DiagnosticConsumer { CapturedDiagList &CapturedDiags; public: CaptureDiagnosticConsumer(DiagnosticsEngine &diags, - CapturedDiagList &capturedDiags) + CapturedDiagList &capturedDiags) : Diags(diags), CapturedDiags(capturedDiags) { } virtual void HandleDiagnostic(DiagnosticsEngine::Level level, @@ -107,6 +107,12 @@ public: // Non-ARC warnings are ignored. Diags.setLastDiagnosticIgnored(); } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; } // end anonymous namespace diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 4e8226d651..e84f8bd6e2 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -458,6 +458,12 @@ public: virtual void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + // Just drop any diagnostics that come from cloned consumers; they'll + // have different source managers anyway. + return new IgnoringDiagConsumer(); + } }; /// \brief RAII object that optionally captures diagnostics, if diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index ce5496562b..554ca352e1 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -141,9 +141,11 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, DiagnosticConsumer *Client, - bool ShouldOwnClient) { + bool ShouldOwnClient, + bool ShouldCloneClient) { Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, - ShouldOwnClient, &getCodeGenOpts()); + ShouldOwnClient, ShouldCloneClient, + &getCodeGenOpts()); } llvm::IntrusiveRefCntPtr @@ -151,6 +153,7 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, + bool ShouldCloneClient, const CodeGenOptions *CodeGenOpts) { llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); llvm::IntrusiveRefCntPtr @@ -158,9 +161,12 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, // Create the diagnostic client for reporting errors or for // implementing -verify. - if (Client) - Diags->setClient(Client, ShouldOwnClient); - else + if (Client) { + if (ShouldCloneClient) + Diags->setClient(Client->clone(*Diags), ShouldOwnClient); + else + Diags->setClient(Client, ShouldOwnClient); + } else Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. @@ -691,7 +697,8 @@ static void compileModule(CompilerInstance &ImportingInstance, Instance.setInvocation(&*Invocation); Instance.createDiagnostics(/*argc=*/0, /*argv=*/0, &ImportingInstance.getDiagnosticClient(), - /*ShouldOwnClient=*/false); + /*ShouldOwnClient=*/true, + /*ShouldCloneClient=*/true); // Construct a module-generating action. GeneratePCHAction CreateModuleAction(true); @@ -699,13 +706,6 @@ static void compileModule(CompilerInstance &ImportingInstance, // Execute the action to actually build the module in-place. // FIXME: Need to synchronize when multiple processes do this. Instance.ExecuteAction(CreateModuleAction); - - // Tell the diagnostic client that it's (re-)starting to process a source - // file. - // FIXME: This is a hack. We probably want to clone the diagnostic client. - ImportingInstance.getDiagnosticClient() - .BeginSourceFile(ImportingInstance.getLangOpts(), - &ImportingInstance.getPreprocessor()); } ModuleKey CompilerInstance::loadModule(SourceLocation ImportLoc, diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index f295acfff3..8b585be90e 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -169,3 +169,9 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, // Record the diagnostic entry. Entries.push_back(DE); } + +DiagnosticConsumer * +LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} + diff --git a/lib/Frontend/TextDiagnosticBuffer.cpp b/lib/Frontend/TextDiagnosticBuffer.cpp index cef46a27e8..f8ea9f1361 100644 --- a/lib/Frontend/TextDiagnosticBuffer.cpp +++ b/lib/Frontend/TextDiagnosticBuffer.cpp @@ -54,3 +54,7 @@ void TextDiagnosticBuffer::FlushDiagnostics(DiagnosticsEngine &Diags) const { Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Note, it->second.c_str())); } + +DiagnosticConsumer *TextDiagnosticBuffer::clone(DiagnosticsEngine &) const { + return new TextDiagnosticBuffer(); +} diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 64a5c1bc9c..378e673812 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -1264,3 +1264,8 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, OS.flush(); } + +DiagnosticConsumer * +TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { + return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); +} diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index 983dc8eebb..cf35c8edc3 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -525,6 +525,14 @@ void VerifyDiagnosticConsumer::CheckDiagnostics() { Buffer.reset(new TextDiagnosticBuffer()); } +DiagnosticConsumer * +VerifyDiagnosticConsumer::clone(DiagnosticsEngine &Diags) const { + if (!Diags.getClient()) + Diags.setClient(PrimaryClient->clone(Diags)); + + return new VerifyDiagnosticConsumer(Diags); +} + Directive* Directive::Create(bool RegexKind, const SourceLocation &Location, const std::string &Text, unsigned Count) { if (RegexKind) diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/FixItRewriter.cpp index d38179dabf..632c0de074 100644 --- a/lib/Rewrite/FixItRewriter.cpp +++ b/lib/Rewrite/FixItRewriter.cpp @@ -156,4 +156,9 @@ void FixItRewriter::Diag(SourceLocation Loc, unsigned DiagID) { Diags.setClient(this); } +DiagnosticConsumer *FixItRewriter::clone(DiagnosticsEngine &Diags) const { + return new FixItRewriter(Diags, Diags.getSourceManager(), + Rewrite.getLangOpts(), FixItOpts); +} + FixItOptions::~FixItOptions() {} diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/HTMLRewrite.cpp index dcf52f9e3c..ba39602d16 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/HTMLRewrite.cpp @@ -440,17 +440,6 @@ void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { } } -namespace { -/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all -/// diags. -class IgnoringDiagConsumer : public DiagnosticConsumer { - void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, - const Diagnostic &Info) { - // Just ignore it. - } -}; -} - /// HighlightMacros - This uses the macro table state from the end of the /// file, to re-expand macros and insert (into the HTML) information about the /// macro expansions. This won't be perfectly perfect, but it will be