Warn about side-effect free statements.

This commit is contained in:
chriseth 2017-04-21 11:13:10 +02:00
parent ed64c849f5
commit 9bc9fe6af7
5 changed files with 55 additions and 17 deletions

View File

@ -7,6 +7,7 @@ Features:
* Commandline interface: Add the ``--standard-json`` parameter to process a Standard JSON I/O. * Commandline interface: Add the ``--standard-json`` parameter to process a Standard JSON I/O.
* Commandline interface: Support ``--allow-paths`` to define trusted import paths. Note: the * Commandline interface: Support ``--allow-paths`` to define trusted import paths. Note: the
path(s) of the supplied source file(s) is always trusted. path(s) of the supplied source file(s) is always trusted.
* Static analyzer: Warn about statements without effects.
Bugfixes: Bugfixes:
* Assembly output: Implement missing AssemblyItem types. * Assembly output: Implement missing AssemblyItem types.

View File

@ -57,6 +57,13 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&)
m_nonPayablePublic = false; m_nonPayablePublic = false;
} }
bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
{
if (_statement.expression().annotation().isPure)
warning(_statement.location(), "Statement has no effects.");
return true;
}
bool StaticAnalyzer::visit(MemberAccess const& _memberAccess) bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
{ {
if (m_nonPayablePublic && !m_library) if (m_nonPayablePublic && !m_library)

View File

@ -60,6 +60,8 @@ private:
virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(FunctionDefinition const& _function) override;
virtual void endVisit(FunctionDefinition const& _function) override; virtual void endVisit(FunctionDefinition const& _function) override;
virtual bool visit(ExpressionStatement const& _statement) override;
virtual bool visit(MemberAccess const& _memberAccess) override; virtual bool visit(MemberAccess const& _memberAccess) override;
ErrorList& m_errors; ErrorList& m_errors;

View File

@ -1674,8 +1674,8 @@ bool TypeChecker::visit(Identifier const& _identifier)
if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration)) if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(annotation.referencedDeclaration))
annotation.isPure = annotation.isConstant = variableDeclaration->isConstant(); annotation.isPure = annotation.isConstant = variableDeclaration->isConstant();
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration)) else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
if (auto functionType = dynamic_cast<FunctionType const*>(annotation.type.get())) if (dynamic_cast<FunctionType const*>(annotation.type.get()))
annotation.isPure = functionType->isPure(); annotation.isPure = true;
return false; return false;
} }

View File

@ -3653,54 +3653,56 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
// integers // integers
uint x; uint x;
uint y; uint y;
true ? x : y; uint g = true ? x : y;
// integer constants // integer constants
true ? 1 : 3; uint h = true ? 1 : 3;
// string literal // string literal
true ? "hello" : "world"; var i = true ? "hello" : "world";
}
function f2() {
// bool // bool
true ? true : false; bool j = true ? true : false;
// real is not there yet. // real is not there yet.
// array // array
byte[2] memory a; byte[2] memory a;
byte[2] memory b; byte[2] memory b;
true ? a : b; var k = true ? a : b;
bytes memory e; bytes memory e;
bytes memory f; bytes memory f;
true ? e : f; var l = true ? e : f;
// fixed bytes // fixed bytes
bytes2 c; bytes2 c;
bytes2 d; bytes2 d;
true ? c : d; var m = true ? c : d;
}
function f3() {
// contract doesn't fit in here // contract doesn't fit in here
// struct // struct
true ? struct_x : struct_y; struct_x = true ? struct_x : struct_y;
// function // function
true ? fun_x : fun_y; var r = true ? fun_x : fun_y;
// enum // enum
small enum_x; small enum_x;
small enum_y; small enum_y;
true ? enum_x : enum_y; enum_x = true ? enum_x : enum_y;
// tuple // tuple
true ? (1, 2) : (3, 4); var (n, o) = true ? (1, 2) : (3, 4);
// mapping // mapping
true ? table1 : table2; var p = true ? table1 : table2;
// typetype // typetype
true ? uint32(1) : uint32(2); var q = true ? uint32(1) : uint32(2);
// modifier doesn't fit in here // modifier doesn't fit in here
@ -5477,6 +5479,32 @@ BOOST_AUTO_TEST_CASE(using_interface_complex)
success(text); success(text);
} }
BOOST_AUTO_TEST_CASE(bare_revert)
{
char const* text = R"(
contract C {
function f(uint x) {
if (x > 7)
revert;
}
}
)";
CHECK_WARNING(text, "Statement has no effects.");
}
BOOST_AUTO_TEST_CASE(pure_statement_in_for_loop)
{
char const* text = R"(
contract C {
function f() {
for (uint x = 0; x < 10; true)
x++;
}
}
)";
CHECK_WARNING(text, "Statement has no effects.");
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }