Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Frontend/TextDiagnosticPrinter.cpp
35233 views
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
13
#include "clang/Frontend/TextDiagnosticPrinter.h"
14
#include "clang/Basic/DiagnosticOptions.h"
15
#include "clang/Basic/SourceManager.h"
16
#include "clang/Frontend/TextDiagnostic.h"
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
24
TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os,
25
DiagnosticOptions *diags,
26
bool _OwnsOutputStream)
27
: OS(os), DiagOpts(diags),
28
OwnsOutputStream(_OwnsOutputStream) {
29
}
30
31
TextDiagnosticPrinter::~TextDiagnosticPrinter() {
32
if (OwnsOutputStream)
33
delete &OS;
34
}
35
36
void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO,
37
const Preprocessor *PP) {
38
// Build the TextDiagnostic utility.
39
TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts, PP));
40
}
41
42
void TextDiagnosticPrinter::EndSourceFile() {
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,
52
DiagnosticsEngine::Level Level,
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.
72
if (Level == DiagnosticsEngine::Error &&
73
DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID()) &&
74
!DiagnosticIDs::isDefaultMappingAsError(Info.getID())) {
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 =
93
DiagnosticIDs::getCategoryNumberForDiag(Info.getID());
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
109
void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level,
110
const Diagnostic &Info) {
111
// Default implementation (Warnings/errors count).
112
DiagnosticConsumer::HandleDiagnostic(Level, Info);
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);
137
TextDiagnostic::printDiagnosticMessage(
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(
152
FullSourceLoc(Info.getLocation(), Info.getSourceManager()), Level,
153
DiagMessageStream.str(), Info.getRanges(), Info.getFixItHints());
154
155
OS.flush();
156
}
157
158