void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Render the diagnostic message into a temporary buffer eagerly. We'll use // this later as we print out the diagnostic to the terminal. llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); llvm::raw_svector_ostream DiagMessageStream(OutStr); if (DiagOpts->ShowNames) printDiagnosticName(DiagMessageStream, Info); printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error // message. We use this information to determine how long the // file+line+column number prefix is. uint64_t StartOfLocationInfo = OS.tell(); if (!Prefix.empty()) OS << Prefix << ": "; // Use a dedicated, simpler path for diagnostics without a valid location. // This is important as if the location is missing, we may be emitting // diagnostics in a context that lacks language options, a source manager, or // other infrastructure necessary when emitting more rich diagnostics. if (!Info.getLocation().isValid()) { TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(), OS.tell() - StartOfLocationInfo, DiagOpts->MessageLength, DiagOpts->ShowColors); OS.flush(); return; } // Assert that the rest of our infrastructure is setup properly. assert(LangOpts && "Unexpected diagnostic outside source file processing"); assert(DiagOpts && "Unexpected diagnostic without options set"); assert(Info.hasSourceManager() && "Unexpected diagnostic with no source manager"); // Rebuild the TextDiagnostic utility if missing or the source manager has // changed. if (!TextDiag || SM != &Info.getSourceManager()) { SM = &Info.getSourceManager(); TextDiag.reset(new TextDiagnostic(OS, *SM, *LangOpts, *DiagOpts)); } TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints())); OS.flush(); }
void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Initialize the main file name, if we haven't already fetched it. if (MainFilename.empty() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); FileID FID = SM.getMainFileID(); if (!FID.isInvalid()) { const FileEntry *FE = SM.getFileEntryForID(FID); if (FE && FE->getName()) MainFilename = FE->getName(); } } // Create the diag entry. DiagEntry DE; DE.DiagnosticID = Info.getID(); DE.DiagnosticLevel = Level; // Format the message. SmallString<100> MessageStr; Info.FormatDiagnostic(MessageStr); DE.Message = MessageStr.str(); // Set the location information. DE.Filename = ""; DE.Line = DE.Column = 0; if (Info.getLocation().isValid() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = SM.getFileID(Info.getLocation()); if (!FID.isInvalid()) { const FileEntry *FE = SM.getFileEntryForID(FID); if (FE && FE->getName()) DE.Filename = FE->getName(); } } else { DE.Filename = PLoc.getFilename(); DE.Line = PLoc.getLine(); DE.Column = PLoc.getColumn(); } } // Record the diagnostic entry. Entries.push_back(DE); }
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { if (DiagLevel != DiagnosticsEngine::Note) { if (inNonNoteDiagnostic) { // We have encountered a non-note diagnostic. Finish up the previous // diagnostic block before starting a new one. Stream.ExitBlock(); } inNonNoteDiagnostic = true; } // Compute the diagnostic text. diagBuf.clear(); Info.FormatDiagnostic(diagBuf); const SourceManager * SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0; SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), SM, &Info); }
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override { if (Info.hasSourceManager() && LangOpts) { SourceManager &SM = Info.getSourceManager(); if (Info.getLocation().isValid()) { Info.getLocation().print(llvm::errs(), SM); llvm::errs() << ": "; } SmallString<16> DiagText; Info.FormatDiagnostic(DiagText); llvm::errs() << DiagText << '\n'; if (Info.getLocation().isValid()) { PrintSourceForLocation(Info.getLocation(), SM); } for (const CharSourceRange &Range : Info.getRanges()) { bool Invalid = true; StringRef Ref = Lexer::getSourceText(Range, SM, *LangOpts, &Invalid); if (!Invalid) { llvm::errs() << Ref.str() << '\n'; } } } DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); }
void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { if (Info.hasSourceManager()) setSourceManager(Info.getSourceManager()); #ifndef NDEBUG // Debug build tracks unparsed files for possible // unparsed expected-* directives. if (SrcManager) { SourceLocation Loc = Info.getLocation(); if (Loc.isValid()) { ParsedStatus PS = IsUnparsed; Loc = SrcManager->getExpansionLoc(Loc); FileID FID = SrcManager->getFileID(Loc); const FileEntry *FE = SrcManager->getFileEntryForID(FID); if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) { // If the file is a modules header file it shall not be parsed // for expected-* directives. HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); if (HS.findModuleForHeader(FE)) PS = IsUnparsedNoDirectives; } UpdateParsedFileStatus(*SrcManager, FID, PS); } } #endif // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); }
void VerifyDiagnosticConsumer::handleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) { if (Info.hasSourceManager()) setSourceManager(Info.getSourceManager()); // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->handleDiagnostic(Level, Info); }
void ClangTidyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { if (DiagLevel == DiagnosticsEngine::Note) { assert(!Errors.empty() && "A diagnostic note can only be appended to a message."); } else { finalizeLastError(); StringRef WarningOption = Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag( Info.getID()); std::string CheckName = !WarningOption.empty() ? ("clang-diagnostic-" + WarningOption).str() : Context.getCheckName(Info.getID()).str(); if (CheckName.empty()) { // This is a compiler diagnostic without a warning option. Assign check // name based on its level. switch (DiagLevel) { case DiagnosticsEngine::Error: case DiagnosticsEngine::Fatal: CheckName = "clang-diagnostic-error"; break; case DiagnosticsEngine::Warning: CheckName = "clang-diagnostic-warning"; break; default: CheckName = "clang-diagnostic-unknown"; break; } } ClangTidyError::Level Level = ClangTidyError::Warning; if (DiagLevel == DiagnosticsEngine::Error || DiagLevel == DiagnosticsEngine::Fatal) { // Force reporting of Clang errors regardless of filters and non-user // code. Level = ClangTidyError::Error; LastErrorRelatesToUserCode = true; LastErrorPassesLineFilter = true; } Errors.push_back(ClangTidyError(CheckName, Level)); } // 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(), Info.getFixItHints(), Sources); checkFilters(Info.getLocation()); }
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()); }
void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { if (Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); FilesWithDiagnostics.insert(SM.getFileID(Info.getLocation())); } // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); }
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)); } }
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) : ID(Info.getID()), Level(Level) { assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && "Valid source location without setting a source manager for diagnostic"); if (Info.getLocation().isValid()) Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); SmallString<64> Message; Info.FormatDiagnostic(Message); this->Message.assign(Message.begin(), Message.end()); this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end()); this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end()); }
void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { // Enter the block for a non-note diagnostic immediately, rather than waiting // for beginDiagnostic, in case associated notes are emitted before we get // there. if (DiagLevel != DiagnosticsEngine::Note) { if (State->EmittedAnyDiagBlocks) ExitDiagBlock(); EnterDiagBlock(); State->EmittedAnyDiagBlocks = true; } // Compute the diagnostic text. State->diagBuf.clear(); Info.FormatDiagnostic(State->diagBuf); if (Info.getLocation().isInvalid()) { // Special-case diagnostics with no location. We may not have entered a // source file in this case, so we can't use the normal DiagnosticsRenderer // machinery. // Make sure we bracket all notes as "sub-diagnostics". This matches // the behavior in SDiagsRenderer::emitDiagnostic(). if (DiagLevel == DiagnosticsEngine::Note) EnterDiagBlock(); EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, State->diagBuf, 0, &Info); if (DiagLevel == DiagnosticsEngine::Note) ExitDiagBlock(); return; } assert(Info.hasSourceManager() && LangOpts && "Unexpected diagnostic with valid location outside of a source file"); SDiagsRenderer Renderer(*this, *LangOpts, &*State->DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, State->diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), &Info.getSourceManager(), &Info); }
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) : ID(Info.getID()), Level(Level) { assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) && "Valid source location without setting a source manager for diagnostic"); if (Info.getLocation().isValid()) Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); SmallString<64> Message; Info.FormatDiagnostic(Message); this->Message.assign(Message.begin(), Message.end()); Ranges.reserve(Info.getNumRanges()); for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I) Ranges.push_back(Info.getRange(I)); FixIts.reserve(Info.getNumFixItHints()); for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I) FixIts.push_back(Info.getFixItHint(I)); }
/// \brief Based on the way the client configured the Diagnostic /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticClient. /// /// \param Loc The source location we are interested in finding out the /// diagnostic state. Can be null in order to query the latest state. DiagnosticIDs::Level DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, SourceLocation Loc, const Diagnostic &Diag, diag::Mapping *mapping) const { // Specific non-error diagnostics may be mapped to various levels from ignored // to error. Errors can only be mapped to fatal. DiagnosticIDs::Level Result = DiagnosticIDs::Fatal; Diagnostic::DiagStatePointsTy::iterator Pos = Diag.GetDiagStatePointForLoc(Loc); Diagnostic::DiagState *State = Pos->State; // Get the mapping information, if unset, compute it lazily. unsigned MappingInfo = Diag.getDiagnosticMappingInfo((diag::kind)DiagID, State); if (MappingInfo == 0) { MappingInfo = GetDefaultDiagMapping(DiagID); Diag.setDiagnosticMappingInternal(DiagID, MappingInfo, State, false, false); } if (mapping) *mapping = (diag::Mapping) (MappingInfo & 7); bool ShouldEmitInSystemHeader = false; switch (MappingInfo & 7) { default: assert(0 && "Unknown mapping!"); case diag::MAP_IGNORE: // Ignore this, unless this is an extension diagnostic and we're mapping // them onto warnings or errors. if (!isBuiltinExtensionDiag(DiagID) || // Not an extension Diag.ExtBehavior == Diagnostic::Ext_Ignore || // Ext ignored (MappingInfo & 8) != 0) // User explicitly mapped it. return DiagnosticIDs::Ignored; Result = DiagnosticIDs::Warning; if (Diag.ExtBehavior == Diagnostic::Ext_Error) Result = DiagnosticIDs::Error; if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) Result = DiagnosticIDs::Fatal; break; case diag::MAP_ERROR: Result = DiagnosticIDs::Error; if (Diag.ErrorsAsFatal) Result = DiagnosticIDs::Fatal; break; case diag::MAP_FATAL: Result = DiagnosticIDs::Fatal; break; case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER: ShouldEmitInSystemHeader = true; // continue as MAP_WARNING. case diag::MAP_WARNING: // If warnings are globally mapped to ignore or error, do it. if (Diag.IgnoreAllWarnings) return DiagnosticIDs::Ignored; Result = DiagnosticIDs::Warning; // If this is an extension diagnostic and we're in -pedantic-error mode, and // if the user didn't explicitly map it, upgrade to an error. if (Diag.ExtBehavior == Diagnostic::Ext_Error && (MappingInfo & 8) == 0 && isBuiltinExtensionDiag(DiagID)) Result = DiagnosticIDs::Error; if (Diag.WarningsAsErrors) Result = DiagnosticIDs::Error; if (Result == DiagnosticIDs::Error && Diag.ErrorsAsFatal) Result = DiagnosticIDs::Fatal; break; case diag::MAP_WARNING_NO_WERROR: // Diagnostics specified with -Wno-error=foo should be set to warnings, but // not be adjusted by -Werror or -pedantic-errors. Result = DiagnosticIDs::Warning; // If warnings are globally mapped to ignore or error, do it. if (Diag.IgnoreAllWarnings) return DiagnosticIDs::Ignored; break; case diag::MAP_ERROR_NO_WFATAL: // Diagnostics specified as -Wno-fatal-error=foo should be errors, but // unaffected by -Wfatal-errors. Result = DiagnosticIDs::Error; break; } // Okay, we're about to return this as a "diagnostic to emit" one last check: // if this is any sort of extension warning, and if we're in an __extension__ // block, silence it. if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) return DiagnosticIDs::Ignored; // If we are in a system header, we ignore it. // We also want to ignore extensions and warnings in -Werror and // -pedantic-errors modes, which *map* warnings/extensions to errors. if (Result >= DiagnosticIDs::Warning && DiagClass != CLASS_ERROR && // Custom diagnostics always are emitted in system headers. DiagID < diag::DIAG_UPPER_LIMIT && !ShouldEmitInSystemHeader && Diag.SuppressSystemWarnings && Loc.isValid() && Diag.getSourceManager().isInSystemHeader( Diag.getSourceManager().getInstantiationLoc(Loc))) return DiagnosticIDs::Ignored; return Result; }
/// ProcessDiag - This is the method used to report a diagnostic that is /// finally fully formed. bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { DiagnosticInfo Info(&Diag); if (Diag.SuppressAllDiagnostics) return false; assert(Diag.getClient() && "DiagnosticClient not set!"); // Figure out the diagnostic level of this message. DiagnosticIDs::Level DiagLevel; unsigned DiagID = Info.getID(); // ShouldEmitInSystemHeader - True if this diagnostic should be produced even // in a system header. bool ShouldEmitInSystemHeader; if (DiagID >= diag::DIAG_UPPER_LIMIT) { // Handle custom diagnostics, which cannot be mapped. DiagLevel = CustomDiagInfo->getLevel(DiagID); // Custom diagnostics always are emitted in system headers. ShouldEmitInSystemHeader = true; } else { // Get the class of the diagnostic. If this is a NOTE, map it onto whatever // the diagnostic level was for the previous diagnostic so that it is // filtered the same as the previous diagnostic. unsigned DiagClass = getBuiltinDiagClass(DiagID); if (DiagClass == CLASS_NOTE) { DiagLevel = DiagnosticIDs::Note; ShouldEmitInSystemHeader = false; // extra consideration is needed } else { // If this is not an error and we are in a system header, we ignore it. // Check the original Diag ID here, because we also want to ignore // extensions and warnings in -Werror and -pedantic-errors modes, which // *map* warnings/extensions to errors. ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR; DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(), Diag); } } if (DiagLevel != DiagnosticIDs::Note) { // Record that a fatal error occurred only when we see a second // non-note diagnostic. This allows notes to be attached to the // fatal error, but suppresses any diagnostics that follow those // notes. if (Diag.LastDiagLevel == DiagnosticIDs::Fatal) Diag.FatalErrorOccurred = true; Diag.LastDiagLevel = DiagLevel; } // If a fatal error has already been emitted, silence all subsequent // diagnostics. if (Diag.FatalErrorOccurred) { if (DiagLevel >= DiagnosticIDs::Error && Diag.Client->IncludeInDiagnosticCounts()) { ++Diag.NumErrors; ++Diag.NumErrorsSuppressed; } return false; } // If the client doesn't care about this message, don't issue it. If this is // a note and the last real diagnostic was ignored, ignore it too. if (DiagLevel == DiagnosticIDs::Ignored || (DiagLevel == DiagnosticIDs::Note && Diag.LastDiagLevel == DiagnosticIDs::Ignored)) return false; // If this diagnostic is in a system header and is not a clang error, suppress // it. if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader && Info.getLocation().isValid() && Diag.getSourceManager().isInSystemHeader( Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) && (DiagLevel != DiagnosticIDs::Note || Diag.LastDiagLevel == DiagnosticIDs::Ignored)) { Diag.LastDiagLevel = DiagnosticIDs::Ignored; return false; } if (DiagLevel >= DiagnosticIDs::Error) { if (Diag.Client->IncludeInDiagnosticCounts()) { Diag.ErrorOccurred = true; ++Diag.NumErrors; } // If we've emitted a lot of errors, emit a fatal error after it to stop a // flood of bogus errors. if (Diag.ErrorLimit && Diag.NumErrors >= Diag.ErrorLimit && DiagLevel == DiagnosticIDs::Error) Diag.SetDelayedDiagnostic(diag::fatal_too_many_errors); } // If we have any Fix-Its, make sure that all of the Fix-Its point into // source locations that aren't macro instantiations. If any point into // macro instantiations, remove all of the Fix-Its. for (unsigned I = 0, N = Diag.NumFixItHints; I != N; ++I) { const FixItHint &FixIt = Diag.FixItHints[I]; if (FixIt.RemoveRange.isInvalid() || FixIt.RemoveRange.getBegin().isMacroID() || FixIt.RemoveRange.getEnd().isMacroID()) { Diag.NumFixItHints = 0; break; } } // Finally, report it. Diag.Client->HandleDiagnostic((Diagnostic::Level)DiagLevel, Info); if (Diag.Client->IncludeInDiagnosticCounts()) { if (DiagLevel == DiagnosticIDs::Warning) ++Diag.NumWarnings; } Diag.CurDiagID = ~0U; return true; }
void ClangTidyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { if (LastErrorWasIgnored && DiagLevel == DiagnosticsEngine::Note) return; if (Info.getLocation().isValid() && DiagLevel != DiagnosticsEngine::Error && DiagLevel != DiagnosticsEngine::Fatal && LineIsMarkedWithNOLINTinMacro(Diags->getSourceManager(), Info.getLocation())) { ++Context.Stats.ErrorsIgnoredNOLINT; // Ignored a warning, should ignore related notes as well LastErrorWasIgnored = true; return; } LastErrorWasIgnored = false; // Count warnings/errors. DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); if (DiagLevel == DiagnosticsEngine::Note) { assert(!Errors.empty() && "A diagnostic note can only be appended to a message."); } else { finalizeLastError(); StringRef WarningOption = Context.DiagEngine->getDiagnosticIDs()->getWarningOptionForDiag( Info.getID()); std::string CheckName = !WarningOption.empty() ? ("clang-diagnostic-" + WarningOption).str() : Context.getCheckName(Info.getID()).str(); if (CheckName.empty()) { // This is a compiler diagnostic without a warning option. Assign check // name based on its level. switch (DiagLevel) { case DiagnosticsEngine::Error: case DiagnosticsEngine::Fatal: CheckName = "clang-diagnostic-error"; break; case DiagnosticsEngine::Warning: CheckName = "clang-diagnostic-warning"; break; default: CheckName = "clang-diagnostic-unknown"; break; } } ClangTidyError::Level Level = ClangTidyError::Warning; if (DiagLevel == DiagnosticsEngine::Error || DiagLevel == DiagnosticsEngine::Fatal) { // Force reporting of Clang errors regardless of filters and non-user // code. Level = ClangTidyError::Error; LastErrorRelatesToUserCode = true; LastErrorPassesLineFilter = true; } bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning && Context.getWarningAsErrorFilter().contains(CheckName); Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(), IsWarningAsError); } ClangTidyDiagnosticRenderer Converter( Context.getLangOpts(), &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(), Info.getFixItHints(), Sources); checkFilters(Info.getLocation()); }