Skip to content

Commit 073b03d

Browse files
Christian Parpartchriseth
Christian Parpart
authored andcommitted
liblangutil: refactor SourceReferenceFormatter, splitting out retrieval and making use of new SourceLocation's CharStream knowledge
1 parent 6efe2a5 commit 073b03d

16 files changed

+234
-126
lines changed

liblangutil/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ set(sources
55
Exceptions.cpp
66
ParserBase.cpp
77
Scanner.cpp
8+
SourceReferenceExtractor.cpp
89
SourceReferenceFormatter.cpp
910
Token.cpp
1011
)
+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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+
#include <liblangutil/SourceReferenceExtractor.h>
18+
#include <liblangutil/CharStream.h>
19+
#include <liblangutil/Exceptions.h>
20+
21+
#include <cmath>
22+
#include <iomanip>
23+
24+
using namespace std;
25+
using namespace dev;
26+
using namespace langutil;
27+
28+
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Exception const& _exception, string _category)
29+
{
30+
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
31+
32+
string const* message = boost::get_error_info<errinfo_comment>(_exception);
33+
SourceReference primary = extract(location, message ? *message : "");
34+
35+
std::vector<SourceReference> secondary;
36+
auto secondaryLocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
37+
if (secondaryLocation && !secondaryLocation->infos.empty())
38+
for (auto const& info: secondaryLocation->infos)
39+
secondary.emplace_back(extract(&info.second, info.first));
40+
41+
return Message{std::move(primary), _category, std::move(secondary)};
42+
}
43+
44+
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message)
45+
{
46+
if (!_location || !_location->source.get()) // Nothing we can extract here
47+
return SourceReference::MessageOnly(std::move(message));
48+
49+
shared_ptr<CharStream> const& source = _location->source;
50+
51+
LineColumn const interest = source->translatePositionToLineColumn(_location->start);
52+
LineColumn start = interest;
53+
LineColumn end = source->translatePositionToLineColumn(_location->end);
54+
bool const isMultiline = start.line != end.line;
55+
56+
string line = source->lineAtPosition(_location->start);
57+
58+
int locationLength = isMultiline ? line.length() - start.column : end.column - start.column;
59+
if (locationLength > 150)
60+
{
61+
line = line.substr(0, start.column + 35) + " ... " + line.substr(end.column - 35);
62+
end.column = start.column + 75;
63+
locationLength = 75;
64+
}
65+
66+
if (line.length() > 150)
67+
{
68+
int const len = line.length();
69+
line = line.substr(max(0, start.column - 35), min(start.column, 35) + min(locationLength + 35, len - start.column));
70+
if (start.column + locationLength + 35 < len)
71+
line += " ...";
72+
if (start.column > 35)
73+
{
74+
line = " ... " + line;
75+
start.column = 40;
76+
}
77+
end.column = start.column + locationLength;
78+
}
79+
80+
return SourceReference{
81+
std::move(message),
82+
source->name(),
83+
interest,
84+
isMultiline,
85+
line,
86+
start.column,
87+
end.column,
88+
};
89+
}
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
#pragma once
18+
19+
#include <iosfwd>
20+
#include <string>
21+
#include <tuple>
22+
#include <vector>
23+
24+
namespace dev
25+
{
26+
struct Exception;
27+
}
28+
29+
namespace langutil
30+
{
31+
32+
struct LineColumn
33+
{
34+
int line;
35+
int column;
36+
37+
LineColumn(std::tuple<int, int> const& _t): line{std::get<0>(_t)}, column{std::get<1>(_t)} {}
38+
LineColumn(int _line, int _column): line{_line}, column{_column} {}
39+
LineColumn(): line{-1}, column{-1} {}
40+
};
41+
42+
struct SourceReference
43+
{
44+
std::string message; ///< A message that relates to this source reference (such as a warning or an error message).
45+
std::string sourceName; ///< Underlying source name (for example the filename).
46+
LineColumn position; ///< Actual (error) position this source reference is surrounding.
47+
bool multiline; ///< Indicates whether the actual SourceReference is truncated to one line.
48+
std::string text; ///< Extracted source code text (potentially truncated if multiline or too long).
49+
int startColumn; ///< Highlighting range-start of text field.
50+
int endColumn; ///< Highlighting range-end of text field.
51+
52+
/// Constructs a SourceReference containing a message only.
53+
static SourceReference MessageOnly(std::string _msg)
54+
{
55+
return SourceReference{std::move(_msg), "", LineColumn{-1, -1}, false, "", -1, -1};
56+
}
57+
};
58+
59+
struct SourceLocation;
60+
61+
namespace SourceReferenceExtractor
62+
{
63+
struct Message
64+
{
65+
SourceReference primary;
66+
std::string category; // "Error", "Warning", ...
67+
std::vector<SourceReference> secondary;
68+
};
69+
70+
Message extract(dev::Exception const& _exception, std::string _category);
71+
SourceReference extract(SourceLocation const* _location, std::string message = "");
72+
}
73+
74+
}

liblangutil/SourceReferenceFormatter.cpp

+33-70
Original file line numberDiff line numberDiff line change
@@ -30,100 +30,63 @@ using namespace langutil;
3030

3131
void SourceReferenceFormatter::printSourceLocation(SourceLocation const* _location)
3232
{
33-
if (!_location || !_location->source)
34-
return; // Nothing we can print here
35-
auto const& scanner = m_scannerFromSourceName(_location->source->name());
36-
int startLine;
37-
int startColumn;
38-
tie(startLine, startColumn) = scanner.translatePositionToLineColumn(_location->start);
39-
int endLine;
40-
int endColumn;
41-
tie(endLine, endColumn) = scanner.translatePositionToLineColumn(_location->end);
42-
if (startLine == endLine)
43-
{
44-
string line = scanner.lineAtPosition(_location->start);
33+
printSourceLocation(SourceReferenceExtractor::extract(_location));
34+
}
4535

46-
int locationLength = endColumn - startColumn;
47-
if (locationLength > 150)
48-
{
49-
line = line.substr(0, startColumn + 35) + " ... " + line.substr(endColumn - 35);
50-
endColumn = startColumn + 75;
51-
locationLength = 75;
52-
}
53-
if (line.length() > 150)
54-
{
55-
int len = line.length();
56-
line = line.substr(max(0, startColumn - 35), min(startColumn, 35) + min(locationLength + 35, len - startColumn));
57-
if (startColumn + locationLength + 35 < len)
58-
line += " ...";
59-
if (startColumn > 35)
60-
{
61-
line = " ... " + line;
62-
startColumn = 40;
63-
}
64-
endColumn = startColumn + locationLength;
65-
}
36+
void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
37+
{
38+
if (_ref.position.line < 0)
39+
return; // Nothing we can print here
6640

67-
m_stream << line << endl;
41+
if (!_ref.multiline)
42+
{
43+
m_stream << _ref.text << endl;
6844

45+
// mark the text-range like this: ^-----^
6946
for_each(
70-
line.cbegin(),
71-
line.cbegin() + startColumn,
72-
[this](char const& ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
47+
_ref.text.cbegin(),
48+
_ref.text.cbegin() + _ref.startColumn,
49+
[this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
7350
);
7451
m_stream << "^";
75-
if (endColumn > startColumn + 2)
76-
m_stream << string(endColumn - startColumn - 2, '-');
77-
if (endColumn > startColumn + 1)
52+
if (_ref.endColumn > _ref.startColumn + 2)
53+
m_stream << string(_ref.endColumn - _ref.startColumn - 2, '-');
54+
if (_ref.endColumn > _ref.startColumn + 1)
7855
m_stream << "^";
7956
m_stream << endl;
8057
}
8158
else
8259
m_stream <<
83-
scanner.lineAtPosition(_location->start) <<
60+
_ref.text <<
8461
endl <<
85-
string(startColumn, ' ') <<
62+
string(_ref.startColumn, ' ') <<
8663
"^ (Relevant source part starts here and spans across multiple lines)." <<
8764
endl;
8865
}
8966

90-
void SourceReferenceFormatter::printSourceName(SourceLocation const* _location)
67+
void SourceReferenceFormatter::printSourceName(SourceReference const& _ref)
9168
{
92-
if (!_location || !_location->source)
93-
return; // Nothing we can print here
94-
auto const& scanner = m_scannerFromSourceName(_location->source->name());
95-
int startLine;
96-
int startColumn;
97-
tie(startLine, startColumn) = scanner.translatePositionToLineColumn(_location->start);
98-
m_stream << _location->source->name() << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
69+
if (_ref.position.line != -1)
70+
m_stream << _ref.sourceName << ":" << (_ref.position.line + 1) << ":" << (_ref.position.column + 1) << ": ";
9971
}
10072

101-
void SourceReferenceFormatter::printExceptionInformation(
102-
dev::Exception const& _exception,
103-
string const& _name
104-
)
73+
void SourceReferenceFormatter::printExceptionInformation(dev::Exception const& _error, std::string const& _category)
10574
{
106-
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
107-
auto secondarylocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
75+
printExceptionInformation(SourceReferenceExtractor::extract(_error, _category));
76+
}
10877

109-
printSourceName(location);
78+
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
79+
{
80+
printSourceName(_msg.primary);
11081

111-
m_stream << _name;
112-
if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
113-
m_stream << ": " << *description << endl;
114-
else
115-
m_stream << endl;
82+
m_stream << _msg.category << ": " << _msg.primary.message << endl;
11683

117-
printSourceLocation(location);
84+
printSourceLocation(_msg.primary);
11885

119-
if (secondarylocation && !secondarylocation->infos.empty())
86+
for (auto const& ref: _msg.secondary)
12087
{
121-
for (auto info: secondarylocation->infos)
122-
{
123-
printSourceName(&info.second);
124-
m_stream << info.first << endl;
125-
printSourceLocation(&info.second);
126-
}
127-
m_stream << endl;
88+
printSourceName(ref);
89+
m_stream << ref.message << endl;
90+
printSourceLocation(ref);
12891
}
12992
}

liblangutil/SourceReferenceFormatter.h

+11-15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <ostream>
2626
#include <sstream>
2727
#include <functional>
28+
#include <liblangutil/SourceReferenceExtractor.h>
2829

2930
namespace dev
3031
{
@@ -39,38 +40,33 @@ class Scanner;
3940
class SourceReferenceFormatter
4041
{
4142
public:
42-
using ScannerFromSourceNameFun = std::function<langutil::Scanner const&(std::string const&)>;
43-
44-
explicit SourceReferenceFormatter(
45-
std::ostream& _stream,
46-
ScannerFromSourceNameFun _scannerFromSourceName
47-
):
48-
m_stream(_stream),
49-
m_scannerFromSourceName(std::move(_scannerFromSourceName))
43+
explicit SourceReferenceFormatter(std::ostream& _stream):
44+
m_stream(_stream)
5045
{}
5146

5247
/// Prints source location if it is given.
53-
void printSourceLocation(langutil::SourceLocation const* _location);
54-
void printExceptionInformation(dev::Exception const& _exception, std::string const& _name);
48+
void printSourceLocation(SourceLocation const* _location);
49+
void printSourceLocation(SourceReference const& _ref);
50+
void printExceptionInformation(dev::Exception const& _error, std::string const& _category);
51+
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg);
5552

5653
static std::string formatExceptionInformation(
5754
dev::Exception const& _exception,
58-
std::string const& _name,
59-
ScannerFromSourceNameFun const& _scannerFromSourceName
55+
std::string const& _name
6056
)
6157
{
6258
std::ostringstream errorOutput;
6359

64-
SourceReferenceFormatter formatter(errorOutput, _scannerFromSourceName);
60+
SourceReferenceFormatter formatter(errorOutput);
6561
formatter.printExceptionInformation(_exception, _name);
6662
return errorOutput.str();
6763
}
64+
6865
private:
6966
/// Prints source name if location is given.
70-
void printSourceName(langutil::SourceLocation const* _location);
67+
void printSourceName(SourceReference const& _ref);
7168

7269
std::ostream& m_stream;
73-
ScannerFromSourceNameFun m_scannerFromSourceName;
7470
};
7571

7672
}

libsolidity/codegen/CompilerContext.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,7 @@ void CompilerContext::appendInlineAssembly(
386386
for (auto const& error: errorReporter.errors())
387387
message += SourceReferenceFormatter::formatExceptionInformation(
388388
*error,
389-
(error->type() == Error::Type::Warning) ? "Warning" : "Error",
390-
[&](string const&) -> Scanner const& { return *scanner; }
389+
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
391390
);
392391
message += "-------------------------------------------\n";
393392

0 commit comments

Comments
 (0)