Enable C99-scoping with the 0.5.0-experimental pragma.

This commit is contained in:
chriseth 2018-02-14 01:48:40 +01:00
parent e227bdbfa7
commit 6b9dda06f3
6 changed files with 98 additions and 40 deletions

View File

@ -612,26 +612,34 @@ void DeclarationRegistrationHelper::endVisit(ModifierDefinition&)
bool DeclarationRegistrationHelper::visit(Block& _block)
{
enterNewSubScope(_block);
_block.setScope(m_currentScope);
// Enable C99-scoped variables.
if (_block.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
enterNewSubScope(_block);
return true;
}
void DeclarationRegistrationHelper::endVisit(Block&)
void DeclarationRegistrationHelper::endVisit(Block& _block)
{
closeCurrentScope();
// Enable C99-scoped variables.
if (_block.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
closeCurrentScope();
}
bool DeclarationRegistrationHelper::visit(ForStatement& _for)
{
// TODO special scoping rules for the init statement - if it is a block, then it should
// not open its own scope.
enterNewSubScope(_for);
_for.setScope(m_currentScope);
if (_for.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
// TODO special scoping rules for the init statement - if it is a block, then it should
// not open its own scope.
enterNewSubScope(_for);
return true;
}
void DeclarationRegistrationHelper::endVisit(ForStatement&)
void DeclarationRegistrationHelper::endVisit(ForStatement& _for)
{
closeCurrentScope();
if (_for.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
closeCurrentScope();
}
void DeclarationRegistrationHelper::endVisit(VariableDeclarationStatement& _variableDeclarationStatement)
@ -663,9 +671,6 @@ void DeclarationRegistrationHelper::endVisit(EventDefinition&)
void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope)
{
if (auto s = dynamic_cast<Scopable*>(&_subScope))
s->setScope(m_currentScope);
map<ASTNode const*, shared_ptr<DeclarationContainer>>::iterator iter;
bool newlyAdded;
shared_ptr<DeclarationContainer> container(new DeclarationContainer(m_currentScope, m_scopes[m_currentScope].get()));
@ -701,10 +706,9 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
registerDeclaration(*m_scopes[m_currentScope], _declaration, nullptr, nullptr, warnAboutShadowing, m_errorReporter);
_declaration.setScope(m_currentScope);
if (_opensScope)
enterNewSubScope(_declaration);
else
_declaration.setScope(m_currentScope);
}
string DeclarationRegistrationHelper::currentCanonicalName() const

View File

@ -47,7 +47,10 @@ bool ReferencesResolver::visit(Block const& _block)
{
if (!m_resolveInsideCode)
return false;
m_resolver.setScope(&_block);
m_experimental050Mode = _block.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050);
// C99-scoped variables
if (m_experimental050Mode)
m_resolver.setScope(&_block);
return true;
}
@ -56,14 +59,19 @@ void ReferencesResolver::endVisit(Block const& _block)
if (!m_resolveInsideCode)
return;
m_resolver.setScope(_block.scope());
// C99-scoped variables
if (m_experimental050Mode)
m_resolver.setScope(_block.scope());
}
bool ReferencesResolver::visit(ForStatement const& _for)
{
if (!m_resolveInsideCode)
return false;
m_resolver.setScope(&_for);
m_experimental050Mode = _for.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050);
// C99-scoped variables
if (m_experimental050Mode)
m_resolver.setScope(&_for);
return true;
}
@ -71,7 +79,8 @@ void ReferencesResolver::endVisit(ForStatement const& _for)
{
if (!m_resolveInsideCode)
return;
m_resolver.setScope(_for.scope());
if (m_experimental050Mode)
m_resolver.setScope(_for.scope());
}
bool ReferencesResolver::visit(Identifier const& _identifier)

View File

@ -93,6 +93,7 @@ private:
std::vector<ParameterList const*> m_returnParameters;
bool const m_resolveInsideCode;
bool m_errorOccurred = false;
bool m_experimental050Mode = false;
};
}

View File

@ -96,21 +96,6 @@ set<SourceUnit const*> SourceUnit::referencedSourceUnits(bool _recurse, set<Sour
return sourceUnits;
}
SourceUnit const& Declaration::sourceUnit() const
{
ASTNode const* s = scope();
solAssert(s, "");
// will not always be a declaratoion
while (dynamic_cast<Scopable const*>(s) && dynamic_cast<Scopable const*>(s)->scope())
s = dynamic_cast<Scopable const*>(s)->scope();
return dynamic_cast<SourceUnit const&>(*s);
}
string Declaration::sourceUnitName() const
{
return sourceUnit().annotation().path;
}
ImportAnnotation& ImportDirective::annotation() const
{
if (!m_annotation)
@ -409,6 +394,21 @@ UserDefinedTypeNameAnnotation& UserDefinedTypeName::annotation() const
return dynamic_cast<UserDefinedTypeNameAnnotation&>(*m_annotation);
}
SourceUnit const& Scopable::sourceUnit() const
{
ASTNode const* s = scope();
solAssert(s, "");
// will not always be a declaratoion
while (dynamic_cast<Scopable const*>(s) && dynamic_cast<Scopable const*>(s)->scope())
s = dynamic_cast<Scopable const*>(s)->scope();
return dynamic_cast<SourceUnit const&>(*s);
}
string Scopable::sourceUnitName() const
{
return sourceUnit().annotation().path;
}
bool VariableDeclaration::isLValue() const
{
// External function parameters and constant declared variables are Read-Only

View File

@ -151,6 +151,13 @@ public:
ASTNode const* scope() const { return m_scope; }
void setScope(ASTNode const* _scope) { m_scope = _scope; }
/// @returns the source unit this scopable is present in.
SourceUnit const& sourceUnit() const;
/// @returns the source name this scopable is present in.
/// Can be combined with annotation().canonicalName (if present) to form a globally unique name.
std::string sourceUnitName() const;
protected:
ASTNode const* m_scope = nullptr;
};
@ -197,12 +204,6 @@ public:
virtual bool isVisibleInContract() const { return visibility() != Visibility::External; }
bool isVisibleInDerivedContracts() const { return isVisibleInContract() && visibility() >= Visibility::Internal; }
/// @returns the source unit this declaration is present in.
SourceUnit const& sourceUnit() const;
/// @returns the source name this declaration is present in.
/// Can be combined with annotation().canonicalName to form a globally unique name.
std::string sourceUnitName() const;
std::string fullyQualifiedName() const { return sourceUnitName() + ":" + name(); }
virtual bool isLValue() const { return false; }

View File

@ -84,16 +84,45 @@ BOOST_AUTO_TEST_CASE(double_variable_declaration)
}
}
)";
CHECK_ERROR(text, DeclarationError, "Identifier already declared");
}
BOOST_AUTO_TEST_CASE(double_variable_declaration_050)
{
string text = R"(
pragma experimental "v0.5.0";
contract test {
function f() pure public {
uint256 x;
if (true) { uint256 x; }
}
}
)";
CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
"This declaration shadows an existing declaration.",
"Experimental features",
"Unused local variable",
"Unused local variable"
}));
}
BOOST_AUTO_TEST_CASE(scoping_old)
{
char const* text = R"(
contract test {
function f() pure public {
x = 4;
uint256 x = 2;
}
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
}
BOOST_AUTO_TEST_CASE(scoping)
{
char const* text = R"(
pragma experimental "v0.5.0";
contract test {
function f() public {
{
@ -109,6 +138,7 @@ BOOST_AUTO_TEST_CASE(scoping)
BOOST_AUTO_TEST_CASE(scoping_for)
{
char const* text = R"(
pragma experimental "v0.5.0";
contract test {
function f() public {
for (uint x = 0; x < 10; x ++){
@ -123,6 +153,7 @@ BOOST_AUTO_TEST_CASE(scoping_for)
BOOST_AUTO_TEST_CASE(scoping_for2)
{
char const* text = R"(
pragma experimental "v0.5.0";
contract test {
function f() public {
for (uint x = 0; x < 10; x ++){
@ -1052,7 +1083,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation)
{
char const* text = R"(
contract B {
function f() mod1(2, true) mod2("0123456") public { }
function f() mod1(2, true) mod2("0123456") pure public { }
modifier mod1(uint a, bool b) { if (b) _; }
modifier mod2(bytes7 a) { while (a == "1234567") _; }
}
@ -1087,7 +1118,19 @@ BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables)
{
char const* text = R"(
contract B {
function f() mod(x) public { uint x = 7; }
function f() mod(x) pure public { uint x = 7; }
modifier mod(uint a) { if (a > 0) _; }
}
)";
CHECK_SUCCESS_NO_WARNINGS(text);
}
BOOST_AUTO_TEST_CASE(function_modifier_invocation_local_variables050)
{
char const* text = R"(
pragma experimental "v0.5.0";
contract B {
function f() mod(x) pure public { uint x = 7; }
modifier mod(uint a) { if (a > 0) _; }
}
)";