15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===// 25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// The LLVM Compiler Infrastructure 45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source 60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details. 75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// This diagnostic client prints out their diagnostic messages. 115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// 125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===// 135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 14e1bd4e6d7c5b13462f83245865f7d9e9b6ea8486Daniel Dunbar#include "clang/Frontend/TextDiagnosticPrinter.h" 1502c23ebf41ae2f70da0ba7337e05c51fbfe35f7fDouglas Gregor#include "clang/Basic/DiagnosticOptions.h" 1604331169f04198eb769925fa17696a21989c9d8bAxel Naumann#include "clang/Basic/FileManager.h" 175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Basic/SourceManager.h" 18db463bb2e4a9751f4cbe53996db751e1985ee966Chandler Carruth#include "clang/Frontend/TextDiagnostic.h" 195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Lex/Lexer.h" 2055fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/ADT/SmallString.h" 2155fc873017f10f6f566b182b70f6fc22aefa3464Chandler Carruth#include "llvm/Support/ErrorHandling.h" 22037fb7f3691966aa66f2b878a149fba57b947355Chris Lattner#include "llvm/Support/MemoryBuffer.h" 23a03a5b5a84989b1cbd3917b967e8fe64f99cfa80Chris Lattner#include "llvm/Support/raw_ostream.h" 244b2d3f7bcc4df31157df443af1b80bcaa9b58bbaDouglas Gregor#include <algorithm> 255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerusing namespace clang; 265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 275f9e272e632e951b1efe824cd16acb4d96077930Chris LattnerTextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, 2802c23ebf41ae2f70da0ba7337e05c51fbfe35f7fDouglas Gregor DiagnosticOptions *diags, 29aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar bool _OwnsOutputStream) 3002c23ebf41ae2f70da0ba7337e05c51fbfe35f7fDouglas Gregor : OS(os), DiagOpts(diags), 31aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar OwnsOutputStream(_OwnsOutputStream) { 32aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar} 33aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar 34aea364195b81f933515e8968b5254a1195eb0337Daniel DunbarTextDiagnosticPrinter::~TextDiagnosticPrinter() { 35aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar if (OwnsOutputStream) 36aea364195b81f933515e8968b5254a1195eb0337Daniel Dunbar delete &OS; 37eace8743030d2979251a0c5ae247371cfd9056e5Daniel Dunbar} 38eace8743030d2979251a0c5ae247371cfd9056e5Daniel Dunbar 3921a869aace45586125238fde88c477b330618a0bChandler Carruthvoid TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO, 4021a869aace45586125238fde88c477b330618a0bChandler Carruth const Preprocessor *PP) { 4116afdf76b6f12e41ff6f6e6828bfb1d4732523baArgyrios Kyrtzidis // Build the TextDiagnostic utility. 4202c23ebf41ae2f70da0ba7337e05c51fbfe35f7fDouglas Gregor TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts)); 4321a869aace45586125238fde88c477b330618a0bChandler Carruth} 4421a869aace45586125238fde88c477b330618a0bChandler Carruth 4521a869aace45586125238fde88c477b330618a0bChandler Carruthvoid TextDiagnosticPrinter::EndSourceFile() { 466bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines TextDiag.reset(nullptr); 4721a869aace45586125238fde88c477b330618a0bChandler Carruth} 4821a869aace45586125238fde88c477b330618a0bChandler Carruth 49a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruth/// \brief Print any diagnostic option information to a raw_ostream. 50a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruth/// 51a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruth/// This implements all of the logic for adding diagnostic options to a message 52a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruth/// (via OS). Each relevant option is comma separated and all are enclosed in 53a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruth/// the standard bracketing: " [...]". 54a3ba6bbac30a3bec488ee7071d203df9d8bcd05dChandler Carruthstatic void printDiagnosticOptions(raw_ostream &OS, 5553a529ee614d6a854814273ac49587a03b71a46bChandler Carruth DiagnosticsEngine::Level Level, 5640847cfb58acc3cac7d68727df9455ac45f2e118David Blaikie const Diagnostic &Info, 5753a529ee614d6a854814273ac49587a03b71a46bChandler Carruth const DiagnosticOptions &DiagOpts) { 58253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth bool Started = false; 5953a529ee614d6a854814273ac49587a03b71a46bChandler Carruth if (DiagOpts.ShowOptionNames) { 60253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth // Handle special cases for non-warnings early. 61253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth if (Info.getID() == diag::fatal_too_many_errors) { 62253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth OS << " [-ferror-limit=]"; 63253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth return; 64253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth } 65253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth 6676101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // The code below is somewhat fragile because we are essentially trying to 6776101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // report to the user what happened by inferring what the diagnostic engine 6876101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // did. Eventually it might make more sense to have the diagnostic engine 6976101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // include some "why" information in the diagnostic. 7076101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar 7176101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // If this is a warning which has been mapped to an error by the user (as 7276101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // inferred by checking whether the default mapping is to an error) then 7376101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // flag it as such. Note that diagnostics could also have been mapped by a 7476101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar // pragma, but we don't currently have a way to distinguish this. 75d6471f7c1921c7802804ce3ff6fe9768310f72b9David Blaikie if (Level == DiagnosticsEngine::Error && 7676101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) && 7776101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar !DiagnosticIDs::isDefaultMappingAsError(Info.getID())) { 7876101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar OS << " [-Werror"; 7976101cfe52d1b56974bf0e316247b3201f87c463Daniel Dunbar Started = true; 80253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth } 81253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth 825f9e272e632e951b1efe824cd16acb4d96077930Chris Lattner StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); 83477aab6782795e7472055a54108d2df270ce1a89Argyrios Kyrtzidis if (!Opt.empty()) { 846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines OS << (Started ? "," : " [") 85ef8225444452a1486bd721f3285301fe84643b00Stephen Hines << (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt; 86ef8225444452a1486bd721f3285301fe84643b00Stephen Hines StringRef OptValue = Info.getDiags()->getFlagValue(); 876bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines if (!OptValue.empty()) 886bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines OS << "=" << OptValue; 89253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth Started = true; 90fffd93f38340d4d2ca7ee78a8c91c890b2ff3fa0Douglas Gregor } 918d2ea4ea7b28ee4eed97182bf7866ef918d20813Chris Lattner } 92253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth 93c9b889044c8e1e2d6ab194e34e8b74f6998094faChris Lattner // If the user wants to see category information, include it too. 94253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth if (DiagOpts.ShowCategories) { 95253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth unsigned DiagCategory = 96253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); 97c9b889044c8e1e2d6ab194e34e8b74f6998094faChris Lattner if (DiagCategory) { 98253d41d74cd449742fd8642753c3076514fb99c5Chandler Carruth OS << (Started ? "," : " ["); 99a65cb0ced55c8a382e8d42881983f84793b4d5b6Benjamin Kramer Started = true; 10053a529ee614d6a854814273ac49587a03b71a46bChandler Carruth if (DiagOpts.ShowCategories == 1) 101a65cb0ced55c8a382e8d42881983f84793b4d5b6Benjamin Kramer OS << DiagCategory; 1026fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner else { 10353a529ee614d6a854814273ac49587a03b71a46bChandler Carruth assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value"); 10453a529ee614d6a854814273ac49587a03b71a46bChandler Carruth OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory); 1056fbe8398ba1680ffc5daa7395850ff8765b7905bChris Lattner } 106c9b889044c8e1e2d6ab194e34e8b74f6998094faChris Lattner } 107c9b889044c8e1e2d6ab194e34e8b74f6998094faChris Lattner } 108a65cb0ced55c8a382e8d42881983f84793b4d5b6Benjamin Kramer if (Started) 109a65cb0ced55c8a382e8d42881983f84793b4d5b6Benjamin Kramer OS << ']'; 11053a529ee614d6a854814273ac49587a03b71a46bChandler Carruth} 11153a529ee614d6a854814273ac49587a03b71a46bChandler Carruth 11253a529ee614d6a854814273ac49587a03b71a46bChandler Carruthvoid TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, 11340847cfb58acc3cac7d68727df9455ac45f2e118David Blaikie const Diagnostic &Info) { 11453a529ee614d6a854814273ac49587a03b71a46bChandler Carruth // Default implementation (Warnings/errors count). 11553a529ee614d6a854814273ac49587a03b71a46bChandler Carruth DiagnosticConsumer::HandleDiagnostic(Level, Info); 11653a529ee614d6a854814273ac49587a03b71a46bChandler Carruth 1170ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth // Render the diagnostic message into a temporary buffer eagerly. We'll use 1180ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth // this later as we print out the diagnostic to the terminal. 119f7ccbad5d9949e7ddd1cbef43d482553b811e026Dylan Noblesmith SmallString<100> OutStr; 1200ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth Info.FormatDiagnostic(OutStr); 1210ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth 1220ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth llvm::raw_svector_ostream DiagMessageStream(OutStr); 1230ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts); 1240ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth 125bed28ac1d1463adca3ecf24fca5c30646fa9dbb2Sylvestre Ledru // Keeps track of the starting position of the location 12653a529ee614d6a854814273ac49587a03b71a46bChandler Carruth // information (e.g., "foo.c:10:4:") that precedes the error 12753a529ee614d6a854814273ac49587a03b71a46bChandler Carruth // message. We use this information to determine how long the 12853a529ee614d6a854814273ac49587a03b71a46bChandler Carruth // file+line+column number prefix is. 12953a529ee614d6a854814273ac49587a03b71a46bChandler Carruth uint64_t StartOfLocationInfo = OS.tell(); 13053a529ee614d6a854814273ac49587a03b71a46bChandler Carruth 13153a529ee614d6a854814273ac49587a03b71a46bChandler Carruth if (!Prefix.empty()) 13253a529ee614d6a854814273ac49587a03b71a46bChandler Carruth OS << Prefix << ": "; 13353a529ee614d6a854814273ac49587a03b71a46bChandler Carruth 1340ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth // Use a dedicated, simpler path for diagnostics without a valid location. 135e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth // This is important as if the location is missing, we may be emitting 136e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth // diagnostics in a context that lacks language options, a source manager, or 137e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth // other infrastructure necessary when emitting more rich diagnostics. 1380ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth if (!Info.getLocation().isValid()) { 13989e32745123c02159fa1d1f19f96bdd4173029f0Hans Wennborg TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors, 14089e32745123c02159fa1d1f19f96bdd4173029f0Hans Wennborg DiagOpts->CLFallbackMode); 1411f3839e2574292ced2e629f758d8d697aa50719aChandler Carruth TextDiagnostic::printDiagnosticMessage(OS, Level, DiagMessageStream.str(), 1421f3839e2574292ced2e629f758d8d697aa50719aChandler Carruth OS.tell() - StartOfLocationInfo, 1431f3839e2574292ced2e629f758d8d697aa50719aChandler Carruth DiagOpts->MessageLength, 1441f3839e2574292ced2e629f758d8d697aa50719aChandler Carruth DiagOpts->ShowColors); 1450ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth OS.flush(); 1460ef898865aaec8c99addee23d01e03c7abdbd2b3Chandler Carruth return; 14753a529ee614d6a854814273ac49587a03b71a46bChandler Carruth } 14853a529ee614d6a854814273ac49587a03b71a46bChandler Carruth 149e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth // Assert that the rest of our infrastructure is setup properly. 150e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth assert(DiagOpts && "Unexpected diagnostic without options set"); 151e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth assert(Info.hasSourceManager() && 152e6d1dff47d17154e99a98c499ee399df70a4bcf1Chandler Carruth "Unexpected diagnostic with no source manager"); 15316afdf76b6f12e41ff6f6e6828bfb1d4732523baArgyrios Kyrtzidis assert(TextDiag && "Unexpected diagnostic outside source file processing"); 15421a869aace45586125238fde88c477b330618a0bChandler Carruth 15521a869aace45586125238fde88c477b330618a0bChandler Carruth TextDiag->emitDiagnostic(Info.getLocation(), Level, DiagMessageStream.str(), 15621a869aace45586125238fde88c477b330618a0bChandler Carruth Info.getRanges(), 1576bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines Info.getFixItHints(), 15816afdf76b6f12e41ff6f6e6828bfb1d4732523baArgyrios Kyrtzidis &Info.getSourceManager()); 159cbff0dc7fefe37bcef9044ec89e9f1131f3c76a9Daniel Dunbar 160a03a5b5a84989b1cbd3917b967e8fe64f99cfa80Chris Lattner OS.flush(); 1615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 162