Fixes #4718: High CPU usage when using large variable names

This commit is contained in:
bakaoh 2018-08-10 17:31:19 +07:00 committed by chriseth
parent f82893450d
commit 3fa8829845
7 changed files with 27 additions and 4 deletions

View File

@ -98,6 +98,7 @@ Bugfixes:
* References Resolver: Enforce ``storage`` as data location for mappings.
* References Resolver: Properly handle invalid references used together with ``_slot`` and ``_offset``.
* References Resolver: Report error instead of assertion fail when FunctionType has an undeclared type as parameter.
* References Resolver: Fix high CPU usage when using large variable names issue. Only suggest similar name if identifiers shorter than 80 characters.
* Type Checker: Default data location for type conversions (e.g. from literals) is memory and not storage.
* Type Checker: Disallow assignments to mappings within tuple assignments as well.
* Type Checker: Disallow packed encoding of arrays of structs.

View File

@ -29,13 +29,16 @@
using namespace std;
using namespace dev;
bool dev::stringWithinDistance(string const& _str1, string const& _str2, size_t _maxDistance)
bool dev::stringWithinDistance(string const& _str1, string const& _str2, size_t _maxDistance, size_t _lenThreshold)
{
if (_str1 == _str2)
return true;
size_t n1 = _str1.size();
size_t n2 = _str2.size();
if (_lenThreshold > 0 && n1 * n2 > _lenThreshold)
return false;
size_t distance = stringDistance(_str1, _str2);
// if distance is not greater than _maxDistance, and distance is strictly less than length of both names, they can be considered similar

View File

@ -30,7 +30,8 @@ namespace dev
{
// Calculates the DamerauLevenshtein distance between _str1 and _str2 and returns true if that distance is not greater than _maxDistance
bool stringWithinDistance(std::string const& _str1, std::string const& _str2, size_t _maxDistance);
// if _lenThreshold > 0 and the product of the strings length is greater than _lenThreshold, the function will return false
bool stringWithinDistance(std::string const& _str1, std::string const& _str2, size_t _maxDistance, size_t _lenThreshold = 0);
// Calculates the DamerauLevenshtein distance between _str1 and _str2
size_t stringDistance(std::string const& _str1, std::string const& _str2);
// Return a string having elements of suggestions as quoted, alternative suggestions. e.g. "a", "b" or "c"

View File

@ -138,19 +138,22 @@ vector<Declaration const*> DeclarationContainer::resolveName(ASTString const& _n
vector<ASTString> DeclarationContainer::similarNames(ASTString const& _name) const
{
static size_t const MAXIMUM_EDIT_DISTANCE = 2;
// because the function below has quadratic runtime - it will not magically improve once a better algorithm is discovered ;)
// since 80 is the suggested line length limit, we use 80^2 as length threshold
static size_t const MAXIMUM_LENGTH_THRESHOLD = 80 * 80;
vector<ASTString> similar;
for (auto const& declaration: m_declarations)
{
string const& declarationName = declaration.first;
if (stringWithinDistance(_name, declarationName, MAXIMUM_EDIT_DISTANCE))
if (stringWithinDistance(_name, declarationName, MAXIMUM_EDIT_DISTANCE, MAXIMUM_LENGTH_THRESHOLD))
similar.push_back(declarationName);
}
for (auto const& declaration: m_invisibleDeclarations)
{
string const& declarationName = declaration.first;
if (stringWithinDistance(_name, declarationName, MAXIMUM_EDIT_DISTANCE))
if (stringWithinDistance(_name, declarationName, MAXIMUM_EDIT_DISTANCE, MAXIMUM_LENGTH_THRESHOLD))
similar.push_back(declarationName);
}

View File

@ -48,6 +48,7 @@ BOOST_AUTO_TEST_CASE(test_similarity)
BOOST_CHECK_EQUAL(stringWithinDistance("abc", "abcdef", 2), false);
BOOST_CHECK_EQUAL(stringWithinDistance("abcd", "wxyz", 2), false);
BOOST_CHECK_EQUAL(stringWithinDistance("", "", 2), true);
BOOST_CHECK_EQUAL(stringWithinDistance("YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY", "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYZ", 2, 6400), false);
}
BOOST_AUTO_TEST_CASE(test_dldistance)

View File

@ -0,0 +1,7 @@
contract test {
function f() public {
int YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY;
}
}
// ----
// DeclarationError: (146-236): Undeclared identifier.

View File

@ -0,0 +1,7 @@
contract test {
function f() public {
int YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY;
}
}
// ----
// DeclarationError: (137-216): Undeclared identifier. Did you mean "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"?