Coverage Report

Created: 2022-08-24 06:55

/src/solidity/liblangutil/SourceReferenceFormatter.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * Formatting functions for errors referencing positions and locations in the source.
20
 */
21
22
#include <liblangutil/SourceReferenceFormatter.h>
23
#include <liblangutil/Exceptions.h>
24
#include <liblangutil/CharStream.h>
25
#include <liblangutil/CharStreamProvider.h>
26
#include <libsolutil/UTF8.h>
27
#include <iomanip>
28
#include <string_view>
29
30
using namespace std;
31
using namespace solidity;
32
using namespace solidity::langutil;
33
using namespace solidity::util;
34
using namespace solidity::util::formatting;
35
36
namespace
37
{
38
39
std::string replaceNonTabs(std::string_view _utf8Input, char _filler)
40
0
{
41
0
  std::string output;
42
0
  for (char const c: _utf8Input)
43
0
    if ((c & 0xc0) != 0x80)
44
0
      output.push_back(c == '\t' ? '\t' : _filler);
45
0
  return output;
46
0
}
47
48
}
49
50
std::string SourceReferenceFormatter::formatErrorInformation(Error const& _error, CharStream const& _charStream)
51
0
{
52
0
  return formatErrorInformation(
53
0
    _error,
54
0
    SingletonCharStreamProvider(_charStream)
55
0
  );
56
0
}
57
58
AnsiColorized SourceReferenceFormatter::normalColored() const
59
0
{
60
0
  return AnsiColorized(m_stream, m_colored, {WHITE});
61
0
}
62
63
AnsiColorized SourceReferenceFormatter::frameColored() const
64
0
{
65
0
  return AnsiColorized(m_stream, m_colored, {BOLD, BLUE});
66
0
}
67
68
AnsiColorized SourceReferenceFormatter::errorColored(optional<Error::Severity> _severity) const
69
0
{
70
  // We used to color messages of any severity as errors so this seems like a good default
71
  // for cases where severity cannot be determined.
72
0
  char const* textColor = RED;
73
74
0
  if (_severity.has_value())
75
0
    switch (_severity.value())
76
0
    {
77
0
    case Error::Severity::Error: textColor = RED; break;
78
0
    case Error::Severity::Warning: textColor = YELLOW; break;
79
0
    case Error::Severity::Info: textColor = WHITE; break;
80
0
    }
81
82
0
  return AnsiColorized(m_stream, m_colored, {BOLD, textColor});
83
0
}
84
85
AnsiColorized SourceReferenceFormatter::messageColored() const
86
0
{
87
0
  return AnsiColorized(m_stream, m_colored, {BOLD, WHITE});
88
0
}
89
90
AnsiColorized SourceReferenceFormatter::secondaryColored() const
91
0
{
92
0
  return AnsiColorized(m_stream, m_colored, {BOLD, CYAN});
93
0
}
94
95
AnsiColorized SourceReferenceFormatter::highlightColored() const
96
0
{
97
0
  return AnsiColorized(m_stream, m_colored, {YELLOW});
98
0
}
99
100
AnsiColorized SourceReferenceFormatter::diagColored() const
101
0
{
102
0
  return AnsiColorized(m_stream, m_colored, {BOLD, YELLOW});
103
0
}
104
105
void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
106
0
{
107
0
  if (_ref.sourceName.empty())
108
0
    return; // Nothing we can print here
109
110
0
  if (_ref.position.line < 0)
111
0
  {
112
0
    frameColored() << "-->";
113
0
    m_stream << ' ' << _ref.sourceName << '\n';
114
0
    return; // No line available, nothing else to print
115
0
  }
116
117
0
  string line = std::to_string(_ref.position.line + 1); // one-based line number as string
118
0
  string leftpad = string(line.size(), ' ');
119
120
  // line 0: source name
121
0
  m_stream << leftpad;
122
0
  frameColored() << "-->";
123
0
  m_stream << ' ' << _ref.sourceName << ':' << line << ':' << (_ref.position.column + 1) << ":\n";
124
125
0
  string_view text = _ref.text;
126
127
0
  if (m_charStreamProvider.charStream(_ref.sourceName).isImportedFromAST())
128
0
    return;
129
130
0
  if (!_ref.multiline)
131
0
  {
132
0
    size_t const locationLength = static_cast<size_t>(_ref.endColumn - _ref.startColumn);
133
134
    // line 1:
135
0
    m_stream << leftpad << ' ';
136
0
    frameColored() << '|';
137
0
    m_stream << '\n';
138
139
    // line 2:
140
0
    frameColored() << line << " |";
141
142
0
    m_stream << ' ' << text.substr(0, static_cast<size_t>(_ref.startColumn));
143
0
    highlightColored() << text.substr(static_cast<size_t>(_ref.startColumn), locationLength);
144
0
    m_stream << text.substr(static_cast<size_t>(_ref.endColumn)) << '\n';
145
146
    // line 3:
147
0
    m_stream << leftpad << ' ';
148
0
    frameColored() << '|';
149
150
0
    m_stream << ' ' << replaceNonTabs(text.substr(0, static_cast<size_t>(_ref.startColumn)), ' ');
151
0
    diagColored() << (
152
0
      locationLength == 0 ?
153
0
      "^" :
154
0
      replaceNonTabs(text.substr(static_cast<size_t>(_ref.startColumn), locationLength), '^')
155
0
    );
156
0
    m_stream << '\n';
157
0
  }
158
0
  else
159
0
  {
160
    // line 1:
161
0
    m_stream << leftpad << ' ';
162
0
    frameColored() << '|';
163
0
    m_stream << '\n';
164
165
    // line 2:
166
0
    frameColored() << line << " |";
167
0
    m_stream << ' ' << text.substr(0, static_cast<size_t>(_ref.startColumn));
168
0
    highlightColored() << text.substr(static_cast<size_t>(_ref.startColumn)) << '\n';
169
170
    // line 3:
171
0
    m_stream << leftpad << ' ';
172
0
    frameColored() << '|';
173
0
    m_stream << ' ' << replaceNonTabs(text.substr(0, static_cast<size_t>(_ref.startColumn)), ' ');
174
0
    diagColored() << "^ (Relevant source part starts here and spans across multiple lines).";
175
0
    m_stream << '\n';
176
0
  }
177
0
}
178
179
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
180
0
{
181
  // exception header line
182
0
  optional<Error::Severity> severity = Error::severityFromString(_msg.severity);
183
0
  errorColored(severity) << _msg.severity;
184
0
  if (m_withErrorIds && _msg.errorId.has_value())
185
0
    errorColored(severity) << " (" << _msg.errorId.value().error << ")";
186
0
  messageColored() << ": " << _msg.primary.message << '\n';
187
188
0
  printSourceLocation(_msg.primary);
189
190
0
  for (auto const& secondary: _msg.secondary)
191
0
  {
192
0
    secondaryColored() << "Note";
193
0
    messageColored() << ":" << (secondary.message.empty() ? "" : (" " + secondary.message)) << '\n';
194
0
    printSourceLocation(secondary);
195
0
  }
196
197
0
  m_stream << '\n';
198
0
}
199
200
void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, std::string const& _severity)
201
0
{
202
0
  printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _severity));
203
0
}
204
205
void SourceReferenceFormatter::printErrorInformation(ErrorList const& _errors)
206
0
{
207
0
  for (auto const& error: _errors)
208
0
    printErrorInformation(*error);
209
0
}
210
211
void SourceReferenceFormatter::printErrorInformation(Error const& _error)
212
0
{
213
0
  printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _error));
214
0
}