clang  19.0.0git
TextDiagnosticPrinter.cpp
Go to the documentation of this file.
1 //===--- TextDiagnosticPrinter.cpp - Diagnostic Printer -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This diagnostic client prints out their diagnostic messages.
10 //
11 //===----------------------------------------------------------------------===//
12 
17 #include "clang/Lex/Lexer.h"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/Support/ErrorHandling.h"
20 #include "llvm/Support/raw_ostream.h"
21 #include <algorithm>
22 using namespace clang;
23 
25  DiagnosticOptions *diags,
26  bool _OwnsOutputStream)
27  : OS(os), DiagOpts(diags),
28  OwnsOutputStream(_OwnsOutputStream) {
29 }
30 
32  if (OwnsOutputStream)
33  delete &OS;
34 }
35 
37  const Preprocessor *PP) {
38  // Build the TextDiagnostic utility.
39  TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts, PP));
40 }
41 
43  TextDiag.reset();
44 }
45 
46 /// Print any diagnostic option information to a raw_ostream.
47 ///
48 /// This implements all of the logic for adding diagnostic options to a message
49 /// (via OS). Each relevant option is comma separated and all are enclosed in
50 /// the standard bracketing: " [...]".
51 static void printDiagnosticOptions(raw_ostream &OS,
53  const Diagnostic &Info,
54  const DiagnosticOptions &DiagOpts) {
55  bool Started = false;
56  if (DiagOpts.ShowOptionNames) {
57  // Handle special cases for non-warnings early.
58  if (Info.getID() == diag::fatal_too_many_errors) {
59  OS << " [-ferror-limit=]";
60  return;
61  }
62 
63  // The code below is somewhat fragile because we are essentially trying to
64  // report to the user what happened by inferring what the diagnostic engine
65  // did. Eventually it might make more sense to have the diagnostic engine
66  // include some "why" information in the diagnostic.
67 
68  // If this is a warning which has been mapped to an error by the user (as
69  // inferred by checking whether the default mapping is to an error) then
70  // flag it as such. Note that diagnostics could also have been mapped by a
71  // pragma, but we don't currently have a way to distinguish this.
75  OS << " [-Werror";
76  Started = true;
77  }
78 
79  StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID());
80  if (!Opt.empty()) {
81  OS << (Started ? "," : " [")
82  << (Level == DiagnosticsEngine::Remark ? "-R" : "-W") << Opt;
83  StringRef OptValue = Info.getDiags()->getFlagValue();
84  if (!OptValue.empty())
85  OS << "=" << OptValue;
86  Started = true;
87  }
88  }
89 
90  // If the user wants to see category information, include it too.
91  if (DiagOpts.ShowCategories) {
92  unsigned DiagCategory =
94  if (DiagCategory) {
95  OS << (Started ? "," : " [");
96  Started = true;
97  if (DiagOpts.ShowCategories == 1)
98  OS << DiagCategory;
99  else {
100  assert(DiagOpts.ShowCategories == 2 && "Invalid ShowCategories value");
101  OS << DiagnosticIDs::getCategoryNameFromID(DiagCategory);
102  }
103  }
104  }
105  if (Started)
106  OS << ']';
107 }
108 
110  const Diagnostic &Info) {
111  // Default implementation (Warnings/errors count).
113 
114  // Render the diagnostic message into a temporary buffer eagerly. We'll use
115  // this later as we print out the diagnostic to the terminal.
116  SmallString<100> OutStr;
117  Info.FormatDiagnostic(OutStr);
118 
119  llvm::raw_svector_ostream DiagMessageStream(OutStr);
120  printDiagnosticOptions(DiagMessageStream, Level, Info, *DiagOpts);
121 
122  // Keeps track of the starting position of the location
123  // information (e.g., "foo.c:10:4:") that precedes the error
124  // message. We use this information to determine how long the
125  // file+line+column number prefix is.
126  uint64_t StartOfLocationInfo = OS.tell();
127 
128  if (!Prefix.empty())
129  OS << Prefix << ": ";
130 
131  // Use a dedicated, simpler path for diagnostics without a valid location.
132  // This is important as if the location is missing, we may be emitting
133  // diagnostics in a context that lacks language options, a source manager, or
134  // other infrastructure necessary when emitting more rich diagnostics.
135  if (!Info.getLocation().isValid()) {
136  TextDiagnostic::printDiagnosticLevel(OS, Level, DiagOpts->ShowColors);
138  OS, /*IsSupplemental=*/Level == DiagnosticsEngine::Note,
139  DiagMessageStream.str(), OS.tell() - StartOfLocationInfo,
140  DiagOpts->MessageLength, DiagOpts->ShowColors);
141  OS.flush();
142  return;
143  }
144 
145  // Assert that the rest of our infrastructure is setup properly.
146  assert(DiagOpts && "Unexpected diagnostic without options set");
147  assert(Info.hasSourceManager() &&
148  "Unexpected diagnostic with no source manager");
149  assert(TextDiag && "Unexpected diagnostic outside source file processing");
150 
151  TextDiag->emitDiagnostic(
153  DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
154 
155  OS.flush();
156 }
Defines the SourceManager interface.
static void printDiagnosticOptions(raw_ostream &OS, DiagnosticsEngine::Level Level, const Diagnostic &Info, const DiagnosticOptions &DiagOpts)
Print any diagnostic option information to a raw_ostream.
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
Definition: Diagnostic.cpp:560
static StringRef getCategoryNameFromID(unsigned CategoryID)
Given a category ID, return the name of the category.
static bool isDefaultMappingAsError(unsigned DiagID)
Return true if the specified diagnostic is mapped to errors by default.
static bool isBuiltinWarningOrExtension(unsigned DiagID)
Return true if the unmapped diagnostic levelof the specified diagnostic ID is a Warning or Extension.
static StringRef getWarningOptionForDiag(unsigned DiagID)
Return the lowest-level warning option that enables the specified diagnostic.
static unsigned getCategoryNumberForDiag(unsigned DiagID)
Return the category number that a specified DiagID belongs to, or 0 if no category.
Options for controlling the compiler diagnostics engine.
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
Definition: Diagnostic.h:1577
SourceManager & getSourceManager() const
Definition: Diagnostic.h:1590
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots.
Definition: Diagnostic.cpp:791
const DiagnosticsEngine * getDiags() const
Definition: Diagnostic.h:1586
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
Definition: Diagnostic.h:1668
bool hasSourceManager() const
Definition: Diagnostic.h:1589
unsigned getID() const
Definition: Diagnostic.h:1587
const SourceLocation & getLocation() const
Definition: Diagnostic.h:1588
ArrayRef< FixItHint > getFixItHints() const
Definition: Diagnostic.h:1681
StringRef getFlagValue() const
Return the value associated with this diagnostic flag.
Definition: Diagnostic.h:991
Level
The level of the diagnostic, after it has been through mapping.
Definition: Diagnostic.h:196
A SourceLocation and its associated SourceManager.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:482
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
bool isValid() const
Return true if this is a valid SourceLocation object.
void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override
Callback to inform the diagnostic client that processing of a source file is beginning.
void EndSourceFile() override
Callback to inform the diagnostic client that processing of a source file has ended.
void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
TextDiagnosticPrinter(raw_ostream &os, DiagnosticOptions *diags, bool OwnsOutputStream=false)
Class to encapsulate the logic for formatting and printing a textual diagnostic message.
static void printDiagnosticMessage(raw_ostream &OS, bool IsSupplemental, StringRef Message, unsigned CurrentColumn, unsigned Columns, bool ShowColors)
Pretty-print a diagnostic message to a raw_ostream.
static void printDiagnosticLevel(raw_ostream &OS, DiagnosticsEngine::Level Level, bool ShowColors)
Print the diagonstic level to a raw_ostream.
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t