aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--docs/contributing.rst79
-rw-r--r--docs/miscellaneous.rst20
-rw-r--r--docs/units-and-global-variables.rst4
-rw-r--r--libsolidity/analysis/GlobalContext.cpp1
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp15
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp9
-rw-r--r--libsolidity/codegen/CompilerUtils.h3
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp22
-rwxr-xr-xscripts/extract_test_cases.py49
-rw-r--r--test/libsolidity/SolidityCompiler.cpp60
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp12
-rw-r--r--test/libsolidity/SolidityExpressionCompiler.cpp9
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp250
-rw-r--r--test/libsolidity/ViewPureChecker.cpp31
-rw-r--r--test/libsolidity/syntaxTests/scoping/double_function_declaration.sol6
-rw-r--r--test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope.sol8
-rw-r--r--test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_050.sol10
-rw-r--r--test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation.sol8
-rw-r--r--test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation_050.sol10
-rw-r--r--test/libsolidity/syntaxTests/scoping/name_shadowing.sol7
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping.sol11
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_activation.sol9
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_activation_old.sol6
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_for.sol8
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_for2.sol7
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_for3.sol11
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_for_decl_in_body.sol10
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_old.sol6
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_self_use.sol5
-rw-r--r--test/libsolidity/syntaxTests/scoping/scoping_self_use_050.sol8
31 files changed, 452 insertions, 243 deletions
diff --git a/Changelog.md b/Changelog.md
index 7a4149f3..9235ed3a 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -6,6 +6,7 @@ Features:
Bugfixes:
* Code Generator: Allow ``block.blockhash`` without being called.
+ * Code Generator: Do not include internal functions in the runtime bytecode which are only referenced in the constructor.
* Code Generator: Properly skip unneeded storage array cleanup when not reducing length.
* Code Generator: Bugfix in modifier lookup in libraries.
* Commandline interface: Support ``--evm-version constantinople`` properly.
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 8b4695e4..1bcaed7c 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -91,6 +91,85 @@ Alternatively, there is a testing script at ``scripts/test.sh`` which executes a
Travis CI even runs some additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target.
+Writing and running syntax tests
+--------------------------------
+
+As mentioned above, syntax tests are stored in individual contracts. These files must contain annotations, stating the expected result(s) of the respective test.
+The test suite will compile and check them against the given expectations.
+
+Example: ``./test/libsolidity/syntaxTests/double_stateVariable_declaration.sol``
+
+::
+
+ contract test {
+ uint256 variable;
+ uint128 variable;
+ }
+ // ----
+ // DeclarationError: Identifier already declared.
+
+A syntax test must contain at least the contract under test itself, followed by the seperator ``----``. The additional comments above are used to describe the
+expected compiler errors or warnings. This section can be empty in case that the contract should compile without any errors or warnings.
+
+In the above example, the state variable ``variable`` was declared twice, which is not allowed. This will result in a ``DeclarationError`` stating that the identifer was already declared.
+
+The tool that is being used for those tests is called ``isoltest`` and can be found under ``./test/tools/``. It is an interactive tool which allows
+editing of failing contracts using your prefered text editor. Let's try to break this test by removing the second declaration of ``variable``:
+
+::
+
+ contract test {
+ uint256 variable;
+ }
+ // ----
+ // DeclarationError: Identifier already declared.
+
+Running ``./test/isoltest`` again will result in a test failure:
+
+::
+
+ syntaxTests/double_stateVariable_declaration.sol: FAIL
+ Contract:
+ contract test {
+ uint256 variable;
+ }
+
+ Expected result:
+ DeclarationError: Identifier already declared.
+ Obtained result:
+ Success
+
+
+which prints the expected result next to the obtained result, but also provides a way to change edit / update / skip the current contract or to even quit.
+``isoltest`` offers several options for failing tests:
+
+- edit: ``isoltest`` will try to open the editor that was specified before using ``isoltest --editor /path/to/editor``. If no path was set, this will result in a runtime error. In case an editor was specified, this will open it such that the contract can be adjusted.
+- update: Updates the contract under test. This will either remove the annotation which contains the exception not met or will add missing expectations. The test will then be run again.
+- skip: Skips the execution of this particular test.
+- quit: Quits ``isoltest``.
+
+Automatically updating the test above will change it to
+
+::
+
+ contract test {
+ uint256 variable;
+ }
+ // ----
+
+and re-run the test. It will now pass again:
+
+::
+
+ Re-running test case...
+ syntaxTests/double_stateVariable_declaration.sol: OK
+
+
+.. note::
+
+ Please choose a name for the contract file, that is self-explainatory in the sense of what is been tested, e.g. ``double_variable_declaration.sol``.
+ Do not put more than one contract into a single file. ``isoltest`` is currently not able to recognize them individually.
+
Whiskers
========
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index a7d5c445..01154854 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -314,7 +314,7 @@ The following is the order of precedence for operators, listed in order of evalu
Global Variables
================
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks
+- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``.
- ``block.coinbase`` (``address``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
@@ -331,6 +331,7 @@ Global Variables
- ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error)
- ``require(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for malformed input or error in external component)
- ``revert()``: abort execution and revert state changes
+- ``blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks
- ``keccak256(...) returns (bytes32)``: compute the Ethereum-SHA-3 (Keccak-256) hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
- ``sha3(...) returns (bytes32)``: an alias to ``keccak256``
- ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the :ref:`(tightly packed) arguments <abi_packed_mode>`
@@ -346,6 +347,23 @@ Global Variables
- ``<address>.send(uint256 amount) returns (bool)``: send given amount of Wei to :ref:`address`, returns ``false`` on failure
- ``<address>.transfer(uint256 amount)``: send given amount of Wei to :ref:`address`, throws on failure
+.. note::
+ Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness,
+ unless you know what you are doing.
+
+ Both the timestamp and the block hash can be influenced by miners to some degree.
+ Bad actors in the mining community can for example run a casino payout function on a chosen hash
+ and just retry a different hash if they did not receive any money.
+
+ The current block timestamp must be strictly larger than the timestamp of the last block,
+ but the only guarantee is that it will be somewhere between the timestamps of two
+ consecutive blocks in the canonical chain.
+
+.. note::
+ The block hashes are not available for all blocks for scalability reasons.
+ You can only access the hashes of the most recent 256 blocks, all other
+ values will be zero.
+
.. index:: visibility, public, private, external, internal
Function Visibility Specifiers
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index d789e87f..2571f20a 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -52,7 +52,7 @@ namespace and are mainly used to provide information about the blockchain.
Block and Transaction Properties
--------------------------------
-- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent blocks excluding current
+- ``block.blockhash(uint blockNumber) returns (bytes32)``: hash of the given block - only works for 256 most recent, excluding current, blocks - deprecated in version 0.4.22 and replaced by ``blockhash(uint blockNumber)``.
- ``block.coinbase`` (``address``): current block miner's address
- ``block.difficulty`` (``uint``): current block difficulty
- ``block.gaslimit`` (``uint``): current block gaslimit
@@ -74,7 +74,7 @@ Block and Transaction Properties
This includes calls to library functions.
.. note::
- Do not rely on ``block.timestamp``, ``now`` and ``block.blockhash`` as a source of randomness,
+ Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness,
unless you know what you are doing.
Both the timestamp and the block hash can be influenced by miners to some degree.
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index 34cb61d8..6a858d36 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -38,6 +38,7 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
make_shared<MagicVariableDeclaration>("addmod", make_shared<FunctionType>(strings{"uint256", "uint256", "uint256"}, strings{"uint256"}, FunctionType::Kind::AddMod, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("assert", make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Kind::Assert, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block)),
+ make_shared<MagicVariableDeclaration>("blockhash", make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"}, FunctionType::Kind::BlockHash, false, StateMutability::View)),
make_shared<MagicVariableDeclaration>("ecrecover", make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Kind::ECRecover, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("gasleft", make_shared<FunctionType>(strings(), strings{"uint256"}, FunctionType::Kind::GasLeft, false, StateMutability::View)),
make_shared<MagicVariableDeclaration>("keccak256", make_shared<FunctionType>(strings(), strings{"bytes32"}, FunctionType::Kind::SHA3, true, StateMutability::Pure)),
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index d4de219a..6aee260e 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -142,6 +142,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
bool const v050 = m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050);
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type.get()))
+ {
if (type->kind() == MagicType::Kind::Message && _memberAccess.memberName() == "gas")
{
if (v050)
@@ -155,6 +156,20 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
"\"msg.gas\" has been deprecated in favor of \"gasleft()\""
);
}
+ if (type->kind() == MagicType::Kind::Block && _memberAccess.memberName() == "blockhash")
+ {
+ if (v050)
+ m_errorReporter.typeError(
+ _memberAccess.location(),
+ "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\""
+ );
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\""
+ );
+ }
+ }
if (m_nonPayablePublic && !m_library)
if (MagicType const* type = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type.get()))
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 1bd1103b..68f0b3a1 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -585,7 +585,7 @@ void CompilerUtils::combineExternalFunctionType(bool _leftAligned)
leftShiftNumberOnStack(64);
}
-void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function)
+void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function, bool _runtimeOnly)
{
m_context << m_context.functionEntryLabel(_function).pushTag();
// If there is a runtime context, we have to merge both labels into the same
@@ -593,9 +593,10 @@ void CompilerUtils::pushCombinedFunctionEntryLabel(Declaration const& _function)
if (CompilerContext* rtc = m_context.runtimeContext())
{
leftShiftNumberOnStack(32);
- m_context <<
- rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) <<
- Instruction::OR;
+ if (_runtimeOnly)
+ m_context <<
+ rtc->functionEntryLabel(_function).toSubAssemblyTag(m_context.runtimeSub()) <<
+ Instruction::OR;
}
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 76670d47..389673ef 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -188,7 +188,8 @@ public:
/// Appends code that combines the construction-time (if available) and runtime function
/// entry label of the given function into a single stack slot.
/// Note: This might cause the compilation queue of the runtime context to be extended.
- void pushCombinedFunctionEntryLabel(Declaration const& _function);
+ /// If @a _runtimeOnly, the entry label will include the runtime assembly tag.
+ void pushCombinedFunctionEntryLabel(Declaration const& _function, bool _runtimeOnly = true);
/// Appends code for an implicit or explicit type conversion. This includes erasing higher
/// order bits (@see appendHighBitCleanup) when widening integer but also copy to memory
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 37069c3e..9e2d30d5 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -518,7 +518,23 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
arguments[i]->accept(*this);
utils().convertType(*arguments[i]->annotation().type, *function.parameterTypes()[i]);
}
- _functionCall.expression().accept(*this);
+
+ {
+ bool shortcutTaken = false;
+ if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
+ if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
+ {
+ // Do not directly visit the identifier, because this way, we can avoid
+ // the runtime entry label to be created at the creation time context.
+ CompilerContext::LocationSetter locationSetter2(m_context, *identifier);
+ utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef), false);
+ shortcutTaken = true;
+ }
+
+ if (!shortcutTaken)
+ _functionCall.expression().accept(*this);
+ }
+
unsigned parameterSize = CompilerUtils::sizeOnStack(function.parameterTypes());
if (function.bound())
{
@@ -1359,6 +1375,10 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
}
}
else if (FunctionDefinition const* functionDef = dynamic_cast<FunctionDefinition const*>(declaration))
+ // If the identifier is called right away, this code is executed in visit(FunctionCall...), because
+ // we want to avoid having a reference to the runtime function entry point in the
+ // constructor context, since this would force the compiler to include unreferenced
+ // internal functions in the runtime contex.
utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef));
else if (auto variable = dynamic_cast<VariableDeclaration const*>(declaration))
appendVariable(*variable, static_cast<Expression const&>(_identifier));
diff --git a/scripts/extract_test_cases.py b/scripts/extract_test_cases.py
new file mode 100755
index 00000000..07ef9a96
--- /dev/null
+++ b/scripts/extract_test_cases.py
@@ -0,0 +1,49 @@
+#!/usr/bin/python
+#
+# This script reads C++ or RST source files and writes all
+# multi-line strings into individual files.
+# This can be used to extract the Solidity test cases
+# into files for e.g. fuzz testing as
+# scripts/isolate_tests.py test/libsolidity/*
+
+import sys
+import re
+import os
+import hashlib
+from os.path import join
+
+def extract_test_cases(path):
+ lines = open(path, 'rb').read().splitlines()
+
+ inside = False
+ delimiter = ''
+ test = ''
+
+ ctr = 1
+ test_name = ''
+
+ for l in lines:
+ if inside:
+ if l.strip().endswith(')' + delimiter + '";'):
+ open('%03d_%s.sol' % (ctr, test_name), 'wb').write(test)
+ ctr += 1
+ inside = False
+ test = ''
+ else:
+ l = re.sub('^\t\t', '', l)
+ l = l.replace('\t', ' ')
+ test += l + '\n'
+ else:
+ m = re.search(r'BOOST_AUTO_TEST_CASE\(([^(]*)\)', l.strip())
+ if m:
+ test_name = m.group(1)
+ m = re.search(r'R"([^(]*)\($', l.strip())
+ if m:
+ inside = True
+ delimiter = m.group(1)
+
+
+if __name__ == '__main__':
+ path = sys.argv[1]
+ extract_test_cases(path)
+
diff --git a/test/libsolidity/SolidityCompiler.cpp b/test/libsolidity/SolidityCompiler.cpp
new file mode 100644
index 00000000..e87ab603
--- /dev/null
+++ b/test/libsolidity/SolidityCompiler.cpp
@@ -0,0 +1,60 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Unit tests for the compiler itself.
+ */
+
+#include <test/libsolidity/AnalysisFramework.h>
+
+#include <test/Options.h>
+
+using namespace std;
+
+namespace dev
+{
+namespace solidity
+{
+namespace test
+{
+
+BOOST_FIXTURE_TEST_SUITE(Compiler, AnalysisFramework)
+
+BOOST_AUTO_TEST_CASE(does_not_include_creation_time_only_internal_functions)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint x;
+ function C() { f(); }
+ function f() internal { for (uint i = 0; i < 10; ++i) x += 3 + i; }
+ }
+ )";
+ BOOST_REQUIRE(success(sourceCode));
+ m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
+ BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
+ bytes const& creationBytecode = m_compiler.object("C").bytecode;
+ bytes const& runtimeBytecode = m_compiler.runtimeObject("C").bytecode;
+ BOOST_CHECK(creationBytecode.size() >= 120);
+ BOOST_CHECK(creationBytecode.size() <= 150);
+ BOOST_CHECK(runtimeBytecode.size() >= 50);
+ BOOST_CHECK(runtimeBytecode.size() <= 70);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+}
+}
+}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 44dc40f7..a866e46c 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1805,6 +1805,18 @@ BOOST_AUTO_TEST_CASE(uncalled_blockhash)
BOOST_CHECK(result[0] != 0 || result[1] != 0 || result[2] != 0);
}
+BOOST_AUTO_TEST_CASE(blockhash_shadow_resolution)
+{
+ char const* code = R"(
+ contract C {
+ function blockhash(uint256 blockNumber) public returns(bytes32) { bytes32 x; return x; }
+ function f() public returns(bytes32) { return blockhash(3); }
+ }
+ )";
+ compileAndRun(code, 0, "C");
+ ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
+}
+
BOOST_AUTO_TEST_CASE(log0)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp
index c8adfc6e..90d8265c 100644
--- a/test/libsolidity/SolidityExpressionCompiler.cpp
+++ b/test/libsolidity/SolidityExpressionCompiler.cpp
@@ -503,12 +503,15 @@ BOOST_AUTO_TEST_CASE(blockhash)
char const* sourceCode = R"(
contract test {
function f() {
- block.blockhash(3);
+ blockhash(3);
}
}
)";
- bytes code = compileFirstExpression(sourceCode, {}, {},
- {make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::Block))});
+
+ auto blockhashFun = make_shared<FunctionType>(strings{"uint256"}, strings{"bytes32"},
+ FunctionType::Kind::BlockHash, false, StateMutability::View);
+
+ bytes code = compileFirstExpression(sourceCode, {}, {}, {make_shared<MagicVariableDeclaration>("blockhash", blockhashFun)});
bytes expectation({byte(Instruction::PUSH1), 0x03,
byte(Instruction::BLOCKHASH)});
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index e30ea8a4..c5abac03 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -43,229 +43,6 @@ namespace test
BOOST_FIXTURE_TEST_SUITE(SolidityNameAndTypeResolution, AnalysisFramework)
-
-BOOST_AUTO_TEST_CASE(double_function_declaration)
-{
- char const* text = R"(
- contract test {
- function fun() public { }
- function fun() public { }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Function with same name and arguments defined twice.");
-}
-
-BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope)
-{
- string text = R"(
- contract test {
- function f() pure public {
- { uint x; }
- { uint x; }
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Identifier already declared");
-}
-
-BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_050)
-{
- string text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- { uint x; }
- { uint x; }
- }
- }
- )";
- CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
- "Unused local variable",
- "Unused local variable"
- }));
-}
-
-BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_activation)
-{
- string text = R"(
- contract test {
- function f() pure public {
- { uint x; }
- uint x;
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Identifier already declared");
-}
-
-BOOST_AUTO_TEST_CASE(double_variable_declaration_disjoint_scope_activation_050)
-{
- string text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- { uint x; }
- uint x;
- }
- }
- )";
- CHECK_WARNING_ALLOW_MULTI(text, (vector<string>{
- "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 {
- {
- uint256 x;
- }
- x = 2;
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
-}
-
-BOOST_AUTO_TEST_CASE(scoping_activation_old)
-{
- char const* text = R"(
- contract test {
- function f() pure public {
- x = 3;
- uint x;
- }
- }
- )";
- CHECK_SUCCESS_NO_WARNINGS(text);
-}
-
-BOOST_AUTO_TEST_CASE(scoping_activation)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- x = 3;
- uint x;
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
-}
-
-BOOST_AUTO_TEST_CASE(scoping_self_use)
-{
- char const* text = R"(
- contract test {
- function f() pure public {
- uint a = a;
- }
- }
- )";
- CHECK_SUCCESS_NO_WARNINGS(text);
-}
-
-BOOST_AUTO_TEST_CASE(scoping_self_use_050)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- uint a = a;
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
-}
-
-BOOST_AUTO_TEST_CASE(scoping_for)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- for (uint x = 0; x < 10; x ++){
- x = 2;
- }
- }
- }
- )";
- CHECK_SUCCESS_NO_WARNINGS(text);
-}
-
-BOOST_AUTO_TEST_CASE(scoping_for2)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- for (uint x = 0; x < 10; x ++)
- x = 2;
- }
- }
- )";
- CHECK_SUCCESS_NO_WARNINGS(text);
-}
-
-BOOST_AUTO_TEST_CASE(scoping_for3)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- for (uint x = 0; x < 10; x ++){
- x = 2;
- }
- x = 4;
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
-}
-
-BOOST_AUTO_TEST_CASE(scoping_for_decl_in_body)
-{
- char const* text = R"(
- pragma experimental "v0.5.0";
- contract test {
- function f() pure public {
- for (;; y++){
- uint y = 3;
- }
- }
- }
- )";
- CHECK_ERROR(text, DeclarationError, "Undeclared identifier");
-}
-
-BOOST_AUTO_TEST_CASE(name_shadowing)
-{
- char const* text = R"(
- contract test {
- uint256 variable;
- function f() public { uint32 variable; variable = 2; }
- }
- )";
- CHECK_SUCCESS(text);
-}
-
BOOST_AUTO_TEST_CASE(name_references)
{
char const* text = R"(
@@ -8569,6 +8346,33 @@ BOOST_AUTO_TEST_CASE(require_visibility_specifiers)
CHECK_ERROR(text, SyntaxError, "No visibility specified.");
}
+BOOST_AUTO_TEST_CASE(blockhash)
+{
+ char const* code = R"(
+ contract C {
+ function f() public view returns (bytes32) {
+ return block.blockhash(3);
+ }
+ }
+ )";
+ CHECK_WARNING(code, "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\"");
+
+ code = R"(
+ contract C {
+ function f() public view returns (bytes32) { return blockhash(3); }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(code);
+
+ code = R"(
+ pragma experimental "v0.5.0";
+ contract C {
+ function f() public returns (bytes32) { return block.blockhash(3); }
+ }
+ )";
+ CHECK_ERROR(code, TypeError, "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\"");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index a6ce6d91..cd0a0b01 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -25,6 +25,7 @@
#include <boost/test/unit_test.hpp>
#include <string>
+#include <tuple>
using namespace std;
@@ -111,6 +112,7 @@ BOOST_AUTO_TEST_CASE(environment_access)
"block.difficulty",
"block.number",
"block.gaslimit",
+ "blockhash(7)",
"gasleft()",
"msg.gas",
"msg.value",
@@ -120,11 +122,12 @@ BOOST_AUTO_TEST_CASE(environment_access)
"this",
"address(1).balance"
};
+ // ``block.blockhash`` and ``blockhash`` are tested seperately below because their usage will
+ // produce warnings that can't be handled in a generic way.
vector<string> pure{
"msg.data",
"msg.data[0]",
"msg.sig",
- "block.blockhash", // Not evaluating the function
"msg",
"block",
"tx"
@@ -132,20 +135,32 @@ BOOST_AUTO_TEST_CASE(environment_access)
for (string const& x: view)
{
CHECK_ERROR(
- "contract C { function f() pure public { var x = " + x + "; x; } }",
+ "contract C { function f() pure public { " + x + "; } }",
TypeError,
"Function declared as pure, but this expression (potentially) reads from the environment or state and thus requires \"view\""
);
}
for (string const& x: pure)
{
- CHECK_WARNING_ALLOW_MULTI(
- "contract C { function f() view public { var x = " + x + "; x; } }",
- (std::vector<std::string>{
- "Function state mutability can be restricted to pure",
- "Use of the \"var\" keyword is deprecated."
- }));
+ CHECK_WARNING(
+ "contract C { function f() view public { " + x + "; } }",
+ "Function state mutability can be restricted to pure"
+ );
}
+
+ CHECK_WARNING_ALLOW_MULTI(
+ "contract C { function f() view public { blockhash; } }",
+ (std::vector<std::string>{
+ "Function state mutability can be restricted to pure",
+ "Statement has no effect."
+ }));
+
+ CHECK_WARNING_ALLOW_MULTI(
+ "contract C { function f() view public { block.blockhash; } }",
+ (std::vector<std::string>{
+ "Function state mutability can be restricted to pure",
+ "\"block.blockhash()\" has been deprecated in favor of \"blockhash()\""
+ }));
}
BOOST_AUTO_TEST_CASE(view_error_for_050)
diff --git a/test/libsolidity/syntaxTests/scoping/double_function_declaration.sol b/test/libsolidity/syntaxTests/scoping/double_function_declaration.sol
new file mode 100644
index 00000000..2841fd38
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/double_function_declaration.sol
@@ -0,0 +1,6 @@
+contract test {
+ function fun() public { }
+ function fun() public { }
+}
+// ----
+// DeclarationError: Function with same name and arguments defined twice.
diff --git a/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope.sol b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope.sol
new file mode 100644
index 00000000..ea61d0f3
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope.sol
@@ -0,0 +1,8 @@
+contract test {
+ function f() pure public {
+ { uint x; }
+ { uint x; }
+ }
+}
+// ----
+// DeclarationError: Identifier already declared.
diff --git a/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_050.sol b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_050.sol
new file mode 100644
index 00000000..22195963
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_050.sol
@@ -0,0 +1,10 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ { uint x; }
+ { uint x; }
+ }
+}
+// ----
+// Warning: Unused local variable.
+// Warning: Unused local variable.
diff --git a/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation.sol b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation.sol
new file mode 100644
index 00000000..6af89c93
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation.sol
@@ -0,0 +1,8 @@
+contract test {
+ function f() pure public {
+ { uint x; }
+ uint x;
+ }
+}
+// ----
+// DeclarationError: Identifier already declared.
diff --git a/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation_050.sol b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation_050.sol
new file mode 100644
index 00000000..73cddfed
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/double_variable_declaration_disjoint_scope_activation_050.sol
@@ -0,0 +1,10 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ { uint x; }
+ uint x;
+ }
+}
+// ----
+// Warning: Unused local variable.
+// Warning: Unused local variable.
diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing.sol
new file mode 100644
index 00000000..d16877f9
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/name_shadowing.sol
@@ -0,0 +1,7 @@
+contract test {
+ uint256 variable;
+ function f() pure public { uint32 variable; variable = 2; }
+}
+// ----
+// Warning: This declaration shadows an existing declaration.
+
diff --git a/test/libsolidity/syntaxTests/scoping/scoping.sol b/test/libsolidity/syntaxTests/scoping/scoping.sol
new file mode 100644
index 00000000..f47a3e99
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping.sol
@@ -0,0 +1,11 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() public {
+ {
+ uint256 x;
+ }
+ x = 2;
+ }
+}
+// ----
+// DeclarationError: Undeclared identifier.
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_activation.sol b/test/libsolidity/syntaxTests/scoping/scoping_activation.sol
new file mode 100644
index 00000000..0ed74a00
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_activation.sol
@@ -0,0 +1,9 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ x = 3;
+ uint x;
+ }
+}
+// ----
+// DeclarationError: Undeclared identifier. Did you mean "x"?
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_activation_old.sol b/test/libsolidity/syntaxTests/scoping/scoping_activation_old.sol
new file mode 100644
index 00000000..d893a889
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_activation_old.sol
@@ -0,0 +1,6 @@
+contract test {
+ function f() pure public {
+ x = 3;
+ uint x;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_for.sol b/test/libsolidity/syntaxTests/scoping/scoping_for.sol
new file mode 100644
index 00000000..6e5b7095
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_for.sol
@@ -0,0 +1,8 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++){
+ x = 2;
+ }
+ }
+}
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_for2.sol b/test/libsolidity/syntaxTests/scoping/scoping_for2.sol
new file mode 100644
index 00000000..eb74b8ab
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_for2.sol
@@ -0,0 +1,7 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++)
+ x = 2;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_for3.sol b/test/libsolidity/syntaxTests/scoping/scoping_for3.sol
new file mode 100644
index 00000000..9bc7d569
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_for3.sol
@@ -0,0 +1,11 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ for (uint x = 0; x < 10; x ++){
+ x = 2;
+ }
+ x = 4;
+ }
+}
+// ----
+// DeclarationError: Undeclared identifier.
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_for_decl_in_body.sol b/test/libsolidity/syntaxTests/scoping/scoping_for_decl_in_body.sol
new file mode 100644
index 00000000..07503983
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_for_decl_in_body.sol
@@ -0,0 +1,10 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ for (;; y++){
+ uint y = 3;
+ }
+ }
+}
+// ----
+// DeclarationError: Undeclared identifier.
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_old.sol b/test/libsolidity/syntaxTests/scoping/scoping_old.sol
new file mode 100644
index 00000000..83f6b60b
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_old.sol
@@ -0,0 +1,6 @@
+contract test {
+ function f() pure public {
+ x = 4;
+ uint256 x = 2;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_self_use.sol b/test/libsolidity/syntaxTests/scoping/scoping_self_use.sol
new file mode 100644
index 00000000..9e2c0171
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_self_use.sol
@@ -0,0 +1,5 @@
+contract test {
+ function f() pure public {
+ uint a = a;
+ }
+}
diff --git a/test/libsolidity/syntaxTests/scoping/scoping_self_use_050.sol b/test/libsolidity/syntaxTests/scoping/scoping_self_use_050.sol
new file mode 100644
index 00000000..e942020e
--- /dev/null
+++ b/test/libsolidity/syntaxTests/scoping/scoping_self_use_050.sol
@@ -0,0 +1,8 @@
+pragma experimental "v0.5.0";
+contract test {
+ function f() pure public {
+ uint a = a;
+ }
+}
+// ----
+// DeclarationError: Undeclared identifier. Did you mean "a"?