Skip to content

Commit 2bb0ae0

Browse files
committed
Cache functions by name.
1 parent 7d1df95 commit 2bb0ae0

File tree

4 files changed

+60
-25
lines changed

4 files changed

+60
-25
lines changed

libsolidity/ast/AST.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@
2929
#include <libsolidity/ast/TypeProvider.h>
3030
#include <libsolutil/Keccak256.h>
3131

32+
#include <range/v3/view/map.hpp>
33+
#include <range/v3/span.hpp>
34+
3235
#include <boost/algorithm/string.hpp>
3336

3437
#include <algorithm>
@@ -276,6 +279,17 @@ FunctionDefinition const* ContractDefinition::nextConstructor(ContractDefinition
276279
return nullptr;
277280
}
278281

282+
multimap<std::string, FunctionDefinition const*> const& ContractDefinition::definedFunctionsByName() const
283+
{
284+
return m_definedFunctionsByName.init([&]{
285+
std::multimap<std::string, FunctionDefinition const*> result;
286+
for (FunctionDefinition const* fun: filteredNodes<FunctionDefinition>(m_subNodes))
287+
result.insert({fun->name(), fun});
288+
return result;
289+
});
290+
}
291+
292+
279293
TypeNameAnnotation& TypeName::annotation() const
280294
{
281295
return initAnnotation<TypeNameAnnotation>();
@@ -397,6 +411,7 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
397411
) const
398412
{
399413
solAssert(!isConstructor(), "");
414+
solAssert(!name().empty(), "");
400415
// If we are not doing super-lookup and the function is not virtual, we can stop here.
401416
if (_searchStart == nullptr && !virtualSemantics())
402417
return *this;
@@ -412,10 +427,8 @@ FunctionDefinition const& FunctionDefinition::resolveVirtual(
412427
if (_searchStart != nullptr && c != _searchStart)
413428
continue;
414429
_searchStart = nullptr;
415-
for (FunctionDefinition const* function: c->definedFunctions())
430+
for (FunctionDefinition const* function: c->definedFunctions(name()))
416431
if (
417-
function->name() == name() &&
418-
!function->isConstructor() &&
419432
FunctionType(*function).asExternallyCallableFunction(false)->hasEqualParameterTypes(*functionType)
420433
)
421434
return *function;

libsolidity/ast/AST.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636

3737
#include <json/json.h>
3838

39+
#include <range/v3/view/subrange.hpp>
40+
#include <range/v3/view/map.hpp>
41+
#include <range/v3/view/transform.hpp>
42+
3943
#include <memory>
4044
#include <optional>
4145
#include <string>
@@ -496,7 +500,14 @@ class ContractDefinition: public Declaration, public StructurallyDocumented, pub
496500
std::vector<EnumDefinition const*> definedEnums() const { return filteredNodes<EnumDefinition>(m_subNodes); }
497501
std::vector<VariableDeclaration const*> stateVariables() const { return filteredNodes<VariableDeclaration>(m_subNodes); }
498502
std::vector<ModifierDefinition const*> functionModifiers() const { return filteredNodes<ModifierDefinition>(m_subNodes); }
499-
std::vector<FunctionDefinition const*> definedFunctions() const { return filteredNodes<FunctionDefinition>(m_subNodes); }
503+
/// @returns a view<FunctionDefinition const*> of all functions defined in this contract (excluding inherited functions).
504+
auto definedFunctions() const { return definedFunctionsByName() | ranges::views::values; }
505+
/// @returns a view<FunctionDefinition const*> of all functions defined in this contract of the given name (excluding inherited functions).
506+
auto definedFunctions(std::string const& _name) const
507+
{
508+
auto&& [b, e] = definedFunctionsByName().equal_range(_name);
509+
return ranges::subrange(b, e) | ranges::views::values;
510+
}
500511
std::vector<EventDefinition const*> events() const { return filteredNodes<EventDefinition>(m_subNodes); }
501512
std::vector<EventDefinition const*> const& interfaceEvents() const;
502513
/// @returns all errors defined in this contract or any base contract
@@ -546,13 +557,16 @@ class ContractDefinition: public Declaration, public StructurallyDocumented, pub
546557
FunctionDefinition const* nextConstructor(ContractDefinition const& _mostDerivedContract) const;
547558

548559
private:
560+
std::multimap<std::string, FunctionDefinition const*> const& definedFunctionsByName() const;
561+
549562
std::vector<ASTPointer<InheritanceSpecifier>> m_baseContracts;
550563
std::vector<ASTPointer<ASTNode>> m_subNodes;
551564
ContractKind m_contractKind;
552565
bool m_abstract{false};
553566

554567
util::LazyInit<std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>>> m_interfaceFunctionList[2];
555568
util::LazyInit<std::vector<EventDefinition const*>> m_interfaceEvents;
569+
util::LazyInit<std::multimap<std::string, FunctionDefinition const*>> m_definedFunctionsByName;
556570
};
557571

558572
/**

test/libsolidity/SolidityNameAndTypeResolution.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ BOOST_AUTO_TEST_CASE(function_no_implementation)
5353
ContractDefinition* contract = dynamic_cast<ContractDefinition*>(nodes[1].get());
5454
BOOST_REQUIRE(contract);
5555
BOOST_CHECK(!contract->annotation().unimplementedDeclarations->empty());
56-
BOOST_CHECK(!contract->definedFunctions()[0]->isImplemented());
56+
BOOST_CHECK(!(*contract->definedFunctions().begin())->isImplemented());
5757
}
5858

5959
BOOST_AUTO_TEST_CASE(abstract_contract)
@@ -69,10 +69,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract)
6969
ContractDefinition* derived = dynamic_cast<ContractDefinition*>(nodes[2].get());
7070
BOOST_REQUIRE(base);
7171
BOOST_CHECK(!base->annotation().unimplementedDeclarations->empty());
72-
BOOST_CHECK(!base->definedFunctions()[0]->isImplemented());
72+
BOOST_CHECK(!(*base->definedFunctions().begin())->isImplemented());
7373
BOOST_REQUIRE(derived);
7474
BOOST_CHECK(derived->annotation().unimplementedDeclarations->empty());
75-
BOOST_CHECK(derived->definedFunctions()[0]->isImplemented());
75+
BOOST_CHECK((*derived->definedFunctions().begin())->isImplemented());
7676
}
7777

7878
BOOST_AUTO_TEST_CASE(abstract_contract_with_overload)
@@ -122,7 +122,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature)
122122
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
123123
{
124124
auto functions = contract->definedFunctions();
125-
BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->externalSignature());
125+
BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", (*functions.begin())->externalSignature());
126126
}
127127
}
128128

@@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
143143
auto functions = contract->definedFunctions();
144144
if (functions.empty())
145145
continue;
146-
BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", functions[0]->externalSignature());
146+
BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", (*functions.begin())->externalSignature());
147147
}
148148
}
149149

@@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(function_external_types)
167167
auto functions = contract->definedFunctions();
168168
if (functions.empty())
169169
continue;
170-
BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address,address[])", functions[0]->externalSignature());
170+
BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8,bool[2],uint256[],address,address[])", (*functions.begin())->externalSignature());
171171
}
172172
}
173173

test/libsolidity/SolidityParser.cpp

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@
2020
* Unit tests for the solidity parser.
2121
*/
2222

23-
#include <string>
24-
#include <memory>
25-
#include <liblangutil/Scanner.h>
23+
#include <libsolidity/ast/ASTVisitor.h>
2624
#include <libsolidity/parsing/Parser.h>
25+
#include <liblangutil/Scanner.h>
2726
#include <liblangutil/ErrorReporter.h>
2827
#include <test/Common.h>
2928
#include <test/libsolidity/ErrorCheck.h>
30-
#include <libsolidity/ast/ASTVisitor.h>
3129

3230
#include <boost/test/unit_test.hpp>
3331

32+
#include <range/v3/range/conversion.hpp>
33+
34+
#include <string>
35+
#include <memory>
36+
3437
using namespace std;
3538
using namespace solidity::langutil;
3639

@@ -141,7 +144,7 @@ BOOST_AUTO_TEST_CASE(function_natspec_documentation)
141144
FunctionDefinition const* function = nullptr;
142145
auto functions = contract->definedFunctions();
143146

144-
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
147+
BOOST_REQUIRE_MESSAGE(function = *functions.begin(), "Failed to retrieve function");
145148
checkFunctionNatspec(function, "This is a test function");
146149
}
147150

@@ -159,9 +162,11 @@ BOOST_AUTO_TEST_CASE(function_normal_comments)
159162
ErrorList errors;
160163
ASTPointer<ContractDefinition> contract = parseText(text, errors);
161164
auto functions = contract->definedFunctions();
162-
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
163-
BOOST_CHECK_MESSAGE(function->documentation() == nullptr,
164-
"Should not have gotten a Natspecc comment for this function");
165+
BOOST_REQUIRE_MESSAGE(function = *functions.begin(), "Failed to retrieve function");
166+
BOOST_CHECK_MESSAGE(
167+
function->documentation() == nullptr,
168+
"Should not have gotten a Natspecc comment for this function"
169+
);
165170
}
166171

167172
BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
@@ -183,7 +188,7 @@ BOOST_AUTO_TEST_CASE(multiple_functions_natspec_documentation)
183188
BOOST_CHECK(successParse(text));
184189
ErrorList errors;
185190
ASTPointer<ContractDefinition> contract = parseText(text, errors);
186-
auto functions = contract->definedFunctions();
191+
auto functions = contract->definedFunctions() | ranges::to<vector<FunctionDefinition const*>>();
187192

188193
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
189194
checkFunctionNatspec(function, "This is test function 1");
@@ -214,9 +219,12 @@ BOOST_AUTO_TEST_CASE(multiline_function_documentation)
214219
ErrorList errors;
215220
ASTPointer<ContractDefinition> contract = parseText(text, errors);
216221
auto functions = contract->definedFunctions();
217-
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
218-
checkFunctionNatspec(function, "This is a test function\n"
219-
" and it has 2 lines");
222+
BOOST_REQUIRE_MESSAGE(function = *functions.begin(), "Failed to retrieve function");
223+
checkFunctionNatspec(
224+
function,
225+
"This is a test function\n"
226+
" and it has 2 lines"
227+
);
220228
}
221229

222230
BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
@@ -240,7 +248,7 @@ BOOST_AUTO_TEST_CASE(natspec_comment_in_function_body)
240248
BOOST_CHECK(successParse(text));
241249
ErrorList errors;
242250
ASTPointer<ContractDefinition> contract = parseText(text, errors);
243-
auto functions = contract->definedFunctions();
251+
auto functions = contract->definedFunctions() | ranges::to<vector<FunctionDefinition const*>>();
244252

245253
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
246254
checkFunctionNatspec(function, "fun1 description");
@@ -269,7 +277,7 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_between_keyword_and_signature)
269277
BOOST_CHECK(successParse(text));
270278
ErrorList errors;
271279
ASTPointer<ContractDefinition> contract = parseText(text, errors);
272-
auto functions = contract->definedFunctions();
280+
auto functions = contract->definedFunctions() | ranges::to<vector<FunctionDefinition const*>>();
273281

274282
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
275283
BOOST_CHECK_MESSAGE(!function->documentation(),
@@ -295,7 +303,7 @@ BOOST_AUTO_TEST_CASE(natspec_docstring_after_signature)
295303
BOOST_CHECK(successParse(text));
296304
ErrorList errors;
297305
ASTPointer<ContractDefinition> contract = parseText(text, errors);
298-
auto functions = contract->definedFunctions();
306+
auto functions = contract->definedFunctions() | ranges::to<vector<FunctionDefinition const*>>();
299307

300308
BOOST_REQUIRE_MESSAGE(function = functions.at(0), "Failed to retrieve function");
301309
BOOST_CHECK_MESSAGE(!function->documentation(),

0 commit comments

Comments
 (0)