Skip to content

Commit 75f2802

Browse files
author
Christian Parpart
committed
liblangutil: adds SourceReferenceExtractor.
1 parent 463951e commit 75f2802

File tree

3 files changed

+202
-0
lines changed

3 files changed

+202
-0
lines changed

liblangutil/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
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
)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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+
/* TODO
29+
* - see if we can get rid of the GETTER fn by adding that functionality to SourceLocation
30+
* - SourceLocation: sourceName* with CharStream&
31+
* - CharStream: add sourceName*
32+
* - Scanner: remove m_sourceName
33+
* - base SourceReferenceFormatter on top of that logic
34+
* - make sure tests are running
35+
* - write tests for SourceReferenceExtractor
36+
* - Scanner::reset(CharStream _source, string _sourceName): drop 2nd param
37+
*/
38+
39+
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
40+
Exception const& _exception,
41+
string _category,
42+
CharStreamGetter _getter
43+
)
44+
{
45+
SourceReferenceExtractor extractor{std::move(_getter)};
46+
return extractor.extract(_exception, std::move(_category));
47+
}
48+
49+
SourceReference SourceReferenceExtractor::extract(
50+
SourceLocation const* _location,
51+
string description,
52+
CharStreamGetter _getter
53+
)
54+
{
55+
return SourceReferenceExtractor{std::move(_getter)}.extract(_location, std::move(description));
56+
}
57+
58+
SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
59+
Exception const& _exception,
60+
string _category
61+
)
62+
{
63+
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
64+
65+
string const* description = boost::get_error_info<errinfo_comment>(_exception);
66+
SourceReference primary = extract(location, description ? *description : "");
67+
68+
std::vector<SourceReference> secondary;
69+
auto secondaryLocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
70+
if (secondaryLocation && !secondaryLocation->infos.empty())
71+
for (auto const& info: secondaryLocation->infos)
72+
secondary.emplace_back(std::move(extract(&info.second, info.first)));
73+
74+
return Message{std::move(primary), _category, std::move(secondary)};
75+
}
76+
77+
SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string description)
78+
{
79+
if (!_location || !_location->sourceName) // Nothing we can extract here
80+
return SourceReference{"", "", 0, 0, 0, 0, 0, std::move(description)};
81+
82+
auto const& source = m_charStreamGetter(*_location->sourceName);
83+
84+
int startLine;
85+
int startColumn;
86+
tie(startLine, startColumn) = source.translatePositionToLineColumn(_location->start);
87+
88+
int endLine;
89+
int endColumn;
90+
tie(endLine, endColumn) = source.translatePositionToLineColumn(_location->end);
91+
92+
string line = source.lineAtPosition(_location->start);
93+
94+
int locationLength = endColumn - startColumn;
95+
if (locationLength > 150)
96+
{
97+
line = line.substr(0, startColumn + 35) + " ... " + line.substr(endColumn - 35);
98+
endColumn = startColumn + 75;
99+
locationLength = 75;
100+
}
101+
102+
if (line.length() > 150)
103+
{
104+
int len = line.length();
105+
line = line.substr(max(0, startColumn - 35), min(startColumn, 35) + min(locationLength + 35, len - startColumn));
106+
if (startColumn + locationLength + 35 < len)
107+
line += " ...";
108+
if (startColumn > 35)
109+
{
110+
line = " ... " + line;
111+
startColumn = 40;
112+
}
113+
endColumn = startColumn + locationLength;
114+
}
115+
116+
return SourceReference{
117+
*_location->sourceName,
118+
line,
119+
startLine,
120+
startColumn,
121+
endLine,
122+
endColumn,
123+
locationLength,
124+
std::move(description),
125+
};
126+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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 <string>
20+
#include <vector>
21+
#include <functional>
22+
23+
namespace dev
24+
{
25+
struct Exception;
26+
}
27+
28+
namespace langutil
29+
{
30+
31+
struct SourceReference
32+
{
33+
std::string filename;
34+
std::string line;
35+
int startLine;
36+
int startColumn;
37+
int endLine;
38+
int endColumn;
39+
int locationLength;
40+
std::string description;
41+
};
42+
43+
class CharStream;
44+
struct SourceLocation;
45+
46+
class SourceReferenceExtractor
47+
{
48+
public:
49+
using CharStreamGetter = std::function<CharStream const&(std::string const /*filename*/&)>;
50+
51+
struct Message
52+
{
53+
SourceReference primary;
54+
std::string category; // "Error", "Warning", ... (TODO: use an enum class)
55+
std::vector<SourceReference> secondary;
56+
};
57+
58+
explicit SourceReferenceExtractor(CharStreamGetter getter): m_charStreamGetter{std::move(getter)} {}
59+
SourceReferenceExtractor(SourceReferenceExtractor const&) = default;
60+
SourceReferenceExtractor(SourceReferenceExtractor&&) = default;
61+
SourceReferenceExtractor& operator=(SourceReferenceExtractor const&) = default;
62+
SourceReferenceExtractor& operator=(SourceReferenceExtractor&&) = default;
63+
~SourceReferenceExtractor() = default;
64+
65+
static Message extract(dev::Exception const& _exception, std::string _category, CharStreamGetter _getter);
66+
static SourceReference extract(SourceLocation const* _location, std::string description, CharStreamGetter _getter);
67+
68+
Message extract(dev::Exception const& _exception, std::string _category);
69+
SourceReference extract(SourceLocation const* _location, std::string description = "");
70+
71+
private:
72+
CharStreamGetter m_charStreamGetter;
73+
};
74+
75+
}

0 commit comments

Comments
 (0)