diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index b9be4d91b..800f102ba 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -1546,7 +1546,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
{
char const* sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
uint8 x = 100;
return 10**x;
}
@@ -1555,7 +1555,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
CHECK_WARNING(sourceCode, "might overflow");
sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
uint8 x = 100;
return uint8(10)**x;
}
@@ -1564,7 +1564,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
CHECK_SUCCESS(sourceCode);
sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
return 2**80;
}
}
@@ -1576,7 +1576,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base)
{
char const* sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
uint8 x = 100;
return 10 << x;
}
@@ -1585,7 +1585,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base)
CHECK_WARNING(sourceCode, "might overflow");
sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
uint8 x = 100;
return uint8(10) << x;
}
@@ -1594,7 +1594,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base)
CHECK_SUCCESS(sourceCode);
sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
return 2 << 80;
}
}
@@ -1602,7 +1602,7 @@ BOOST_AUTO_TEST_CASE(shift_warn_literal_base)
CHECK_SUCCESS(sourceCode);
sourceCode = R"(
contract test {
- function f() returns(uint) {
+ function f() pure returns(uint) {
uint8 x = 100;
return 10 >> x;
}
@@ -1624,7 +1624,7 @@ BOOST_AUTO_TEST_CASE(warn_var_from_zero)
CHECK_WARNING(sourceCode, "uint8, which can hold values between 0 and 255");
sourceCode = R"(
contract test {
- function f() {
+ function f() pure {
var i = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
i;
}
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
new file mode 100644
index 000000000..7099ffd7a
--- /dev/null
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -0,0 +1,323 @@
+/*
+ This file is part of solidity.
+
+ solidity is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ solidity is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with solidity. If not, see .
+*/
+/**
+ * Unit tests for the view and pure checker.
+ */
+
+#include
+
+#include
+
+#include
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+BOOST_FIXTURE_TEST_SUITE(ViewPureChecker, AnalysisFramework)
+
+BOOST_AUTO_TEST_CASE(smoke_test)
+{
+ char const* text = R"(
+ contract C {
+ uint x;
+ function g() pure {}
+ function f() view returns (uint) { return now; }
+ function h() { x = 2; }
+ function i() payable { x = 2; }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(call_internal_functions_success)
+{
+ char const* text = R"(
+ contract C {
+ function g() pure { g(); }
+ function f() view returns (uint) { f(); g(); }
+ function h() { h(); g(); f(); }
+ function i() payable { i(); h(); g(); f(); }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(suggest_pure)
+{
+ char const* text = R"(
+ contract C {
+ function g() view { }
+ }
+ )";
+ CHECK_WARNING(text, "can be restricted to pure");
+}
+
+BOOST_AUTO_TEST_CASE(suggest_view)
+{
+ char const* text = R"(
+ contract C {
+ uint x;
+ function g() returns (uint) { return x; }
+ }
+ )";
+ CHECK_WARNING(text, "can be restricted to view");
+}
+
+BOOST_AUTO_TEST_CASE(call_internal_functions_fail)
+{
+ CHECK_ERROR(
+ "contract C{ function f() pure { g(); } function g() view {} }",
+ TypeError,
+ "Function declared as pure, but this expression reads from the environment or state and thus requires \"view\""
+ );
+}
+
+BOOST_AUTO_TEST_CASE(write_storage_fail)
+{
+ CHECK_WARNING(
+ "contract C{ uint x; function f() view { x = 2; } }",
+ "Function declared as view, but this expression modifies the state and thus requires non-payable (the default) or payable."
+ );
+}
+
+BOOST_AUTO_TEST_CASE(environment_access)
+{
+ vector view{
+ "block.coinbase",
+ "block.timestamp",
+ "block.blockhash(7)",
+ "block.difficulty",
+ "block.number",
+ "block.gaslimit",
+ "msg.gas",
+ "msg.value",
+ "msg.sender",
+ "tx.origin",
+ "tx.gasprice",
+ "this",
+ "address(1).balance"
+ };
+ vector pure{
+ "msg.data",
+ "msg.data[0]",
+ "msg.sig",
+ "block.blockhash", // Not evaluating the function
+ "msg",
+ "block",
+ "tx"
+ };
+ for (string const& x: view)
+ {
+ CHECK_ERROR(
+ "contract C { function f() pure { var x = " + x + "; x; } }",
+ TypeError,
+ "Function declared as pure, but this expression reads from the environment or state and thus requires \"view\""
+ );
+ }
+ for (string const& x: pure)
+ {
+ CHECK_WARNING(
+ "contract C { function f() view { var x = " + x + "; x; } }",
+ "restricted to pure"
+ );
+ }
+}
+
+BOOST_AUTO_TEST_CASE(modifiers)
+{
+ string text = R"(
+ contract D {
+ uint x;
+ modifier purem(uint) { _; }
+ modifier viewm(uint) { uint a = x; _; a; }
+ modifier nonpayablem(uint) { x = 2; _; }
+ }
+ contract C is D {
+ function f() purem(0) pure {}
+ function g() viewm(0) view {}
+ function h() nonpayablem(0) {}
+ function i() purem(x) view {}
+ function j() viewm(x) view {}
+ function k() nonpayablem(x) {}
+ function l() purem(x = 2) {}
+ function m() viewm(x = 2) {}
+ function n() nonpayablem(x = 2) {}
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(interface)
+{
+ string text = R"(
+ interface D {
+ function f() view;
+ }
+ contract C is D {
+ function f() view {}
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(overriding)
+{
+ string text = R"(
+ contract D {
+ uint x;
+ function f() { x = 2; }
+ }
+ contract C is D {
+ function f() {}
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(returning_structs)
+{
+ string text = R"(
+ contract C {
+ struct S { uint x; }
+ S s;
+ function f() view internal returns (S storage) {
+ return s;
+ }
+ function g()
+ {
+ f().x = 2;
+ }
+ function h() view
+ {
+ f();
+ f().x;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(mappings)
+{
+ string text = R"(
+ contract C {
+ mapping(uint => uint) a;
+ function f() view {
+ a;
+ }
+ function g() view {
+ a[2];
+ }
+ function h() {
+ a[2] = 3;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(local_storage_variables)
+{
+ string text = R"(
+ contract C {
+ struct S { uint a; }
+ S s;
+ function f() view {
+ S storage x = s;
+ x;
+ }
+ function g() view {
+ S storage x = s;
+ x = s;
+ }
+ function i() {
+ s.a = 2;
+ }
+ function h() {
+ S storage x = s;
+ x.a = 2;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(builtin_functions)
+{
+ string text = R"(
+ contract C {
+ function f() {
+ this.transfer(1);
+ require(this.send(2));
+ selfdestruct(this);
+ require(this.delegatecall());
+ require(this.call());
+ }
+ function g() pure {
+ var x = keccak256("abc");
+ var y = sha256("abc");
+ var z = ecrecover(1, 2, 3, 4);
+ require(true);
+ assert(true);
+ x; y; z;
+ }
+ function() payable {}
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(function_types)
+{
+ string text = R"(
+ contract C {
+ function f() pure {
+ function () external nonpayFun;
+ function () external view viewFun;
+ function () external pure pureFun;
+
+ nonpayFun;
+ viewFun;
+ pureFun;
+ pureFun();
+ }
+ function g() view {
+ function () external view viewFun;
+
+ viewFun();
+ }
+ function h() {
+ function () external nonpayFun;
+
+ nonpayFun();
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+}