Merge pull request #4430 from ethereum/enforceVisibilitySpecifier

[BREAKING] Enforce visibility specifier
This commit is contained in:
chriseth 2018-07-18 12:08:42 +02:00 committed by GitHub
commit b909df4573
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 48 additions and 53 deletions

View File

@ -3,6 +3,7 @@
How to update your code: How to update your code:
* Change every ``.call()`` to a ``.call("")`` and every ``.call(signature, a, b, c)`` to use ``.call(abi.encodeWithSignature(signature, a, b, c))`` (the last one only works for value types). * Change every ``.call()`` to a ``.call("")`` and every ``.call(signature, a, b, c)`` to use ``.call(abi.encodeWithSignature(signature, a, b, c))`` (the last one only works for value types).
* Change every ``keccak256(a, b, c)`` to ``keccak256(abi.encodePacked(a, b, c))``. * Change every ``keccak256(a, b, c)`` to ``keccak256(abi.encodePacked(a, b, c))``.
* Add ``public`` to every function and ``external`` to every fallback or interface function that does not specify its visibility already.
* Make your fallback functions ``external``. * Make your fallback functions ``external``.
* Explicitly state the storage location for local variables of struct and array types, e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``. * Explicitly state the storage location for local variables of struct and array types, e.g. change ``uint[] x = m_x`` to ``uint[] storage x = m_x``.
@ -49,6 +50,7 @@ Breaking Changes:
* Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/soldity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible. * Remove obsolete ``std`` directory from the Solidity repository. This means accessing ``https://github.com/ethereum/soldity/blob/develop/std/*.sol`` (or ``https://github.com/ethereum/solidity/std/*.sol`` in Remix) will not be possible.
* References Resolver: Turn missing storage locations into an error. This was already the case in the experimental 0.5.0 mode. * References Resolver: Turn missing storage locations into an error. This was already the case in the experimental 0.5.0 mode.
* Syntax Checker: Named return values in function types are an error. * Syntax Checker: Named return values in function types are an error.
* Syntax Checker: Strictly require visibility specifier for functions. This was already the case in the experimental 0.5.0 mode.
* Syntax Checker: Disallow unary ``+``. This was already the case in the experimental 0.5.0 mode. * Syntax Checker: Disallow unary ``+``. This was already the case in the experimental 0.5.0 mode.
* View Pure Checker: Strictly enfore state mutability. This was already the case in the experimental 0.5.0 mode. * View Pure Checker: Strictly enfore state mutability. This was already the case in the experimental 0.5.0 mode.

View File

@ -131,10 +131,9 @@ a "message call") and external
ones that do), there are four types of visibilities for ones that do), there are four types of visibilities for
functions and state variables. functions and state variables.
Functions can be specified as being ``external``, Functions have to be specified as being ``external``,
``public``, ``internal`` or ``private``, where the default is ``public``, ``internal`` or ``private``.
``public``. For state variables, ``external`` is not possible For state variables, ``external`` is not possible.
and the default is ``internal``.
``external``: ``external``:
External functions are part of the contract External functions are part of the contract
@ -850,10 +849,10 @@ Details are given in the following example.
:: ::
pragma solidity ^0.4.22; pragma solidity >0.4.24;
contract owned { contract owned {
constructor() { owner = msg.sender; } constructor() public { owner = msg.sender; }
address owner; address owner;
} }
@ -862,7 +861,7 @@ Details are given in the following example.
// internal functions and state variables. These cannot be // internal functions and state variables. These cannot be
// accessed externally via `this`, though. // accessed externally via `this`, though.
contract mortal is owned { contract mortal is owned {
function kill() { function kill() public {
if (msg.sender == owner) selfdestruct(owner); if (msg.sender == owner) selfdestruct(owner);
} }
} }
@ -884,7 +883,7 @@ Details are given in the following example.
// also a base class of `mortal`, yet there is only a single // also a base class of `mortal`, yet there is only a single
// instance of `owned` (as for virtual inheritance in C++). // instance of `owned` (as for virtual inheritance in C++).
contract named is owned, mortal { contract named is owned, mortal {
constructor(bytes32 name) { constructor(bytes32 name) public {
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970); Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
NameReg(config.lookup(1)).register(name); NameReg(config.lookup(1)).register(name);
} }

View File

@ -465,10 +465,10 @@ The following example shows how an error string can be used together with revert
:: ::
pragma solidity ^0.4.22; pragma solidity >0.4.24;
contract VendingMachine { contract VendingMachine {
function buy(uint amount) payable { function buy(uint amount) public payable {
if (amount > msg.value / 2 ether) if (amount > msg.value / 2 ether)
revert("Not enough Ether provided."); revert("Not enough Ether provided.");
// Alternative way to do it: // Alternative way to do it:

View File

@ -205,7 +205,7 @@ for the two input parameters and two returned values.
* @return s The calculated surface. * @return s The calculated surface.
* @return p The calculated perimeter. * @return p The calculated perimeter.
*/ */
function rectangle(uint w, uint h) returns (uint s, uint p) { function rectangle(uint w, uint h) public returns (uint s, uint p) {
s = w * h; s = w * h;
p = 2 * (w + h); p = 2 * (w + h);
} }

View File

@ -483,7 +483,7 @@ Another example that uses external function types::
contract OracleUser { contract OracleUser {
Oracle constant oracle = Oracle(0x1234567); // known contract Oracle constant oracle = Oracle(0x1234567); // known contract
function buySomething() { function buySomething() public {
oracle.query("USD", this.oracleResponse); oracle.query("USD", this.oracleResponse);
} }
function oracleResponse(bytes memory response) public { function oracleResponse(bytes memory response) public {
@ -979,4 +979,3 @@ converted to a matching size. This makes alignment and padding explicit::
uint16 x = 0xffff; uint16 x = 0xffff;
bytes32(uint256(x)); // pad on the left bytes32(uint256(x)); // pad on the left
bytes32(bytes2(x)); // pad on the right bytes32(bytes2(x)); // pad on the right

View File

@ -51,16 +51,6 @@ void StaticAnalyzer::endVisit(ContractDefinition const&)
bool StaticAnalyzer::visit(FunctionDefinition const& _function) bool StaticAnalyzer::visit(FunctionDefinition const& _function)
{ {
const bool isInterface = m_currentContract->contractKind() == ContractDefinition::ContractKind::Interface;
if (_function.noVisibilitySpecified())
m_errorReporter.warning(
_function.location(),
"No visibility specified. Defaulting to \"" +
Declaration::visibilityToString(_function.visibility()) +
"\"." +
(isInterface ? " In interfaces it defaults to external." : "")
);
if (_function.isImplemented()) if (_function.isImplemented())
m_currentFunction = &_function; m_currentFunction = &_function;
else else

View File

@ -197,12 +197,24 @@ bool SyntaxChecker::visit(PlaceholderStatement const&)
return true; return true;
} }
bool SyntaxChecker::visit(ContractDefinition const& _contract)
{
m_isInterface = _contract.contractKind() == ContractDefinition::ContractKind::Interface;
return true;
}
bool SyntaxChecker::visit(FunctionDefinition const& _function) bool SyntaxChecker::visit(FunctionDefinition const& _function)
{ {
bool const v050 = m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeature::V050); bool const v050 = m_sourceUnit->annotation().experimentalFeatures.count(ExperimentalFeature::V050);
if (v050 && _function.noVisibilitySpecified()) if (_function.noVisibilitySpecified())
m_errorReporter.syntaxError(_function.location(), "No visibility specified."); {
string suggestedVisibility = _function.isFallback() || m_isInterface ? "external" : "public";
m_errorReporter.syntaxError(
_function.location(),
"No visibility specified. Did you intend to add \"" + suggestedVisibility + "\"?"
);
}
if (_function.isOldStyleConstructor()) if (_function.isOldStyleConstructor())
{ {

View File

@ -66,6 +66,7 @@ private:
virtual bool visit(PlaceholderStatement const& _placeholderStatement) override; virtual bool visit(PlaceholderStatement const& _placeholderStatement) override;
virtual bool visit(ContractDefinition const& _contract) override;
virtual bool visit(FunctionDefinition const& _function) override; virtual bool visit(FunctionDefinition const& _function) override;
virtual bool visit(FunctionTypeName const& _node) override; virtual bool visit(FunctionTypeName const& _node) override;
@ -82,6 +83,7 @@ private:
bool m_versionPragmaFound = false; bool m_versionPragmaFound = false;
int m_inLoopDepth = 0; int m_inLoopDepth = 0;
bool m_isInterface = false;
SourceUnit const* m_sourceUnit = nullptr; SourceUnit const* m_sourceUnit = nullptr;
}; };

View File

@ -670,7 +670,7 @@ BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars)
// and free local variables properly // and free local variables properly
char const* sourceCode = R"( char const* sourceCode = R"(
contract test { contract test {
function f(uint x) returns(uint y) { function f(uint x) public returns(uint y) {
while (x > 0) { while (x > 0) {
uint z = x + 10; uint z = x + 10;
uint k = z + 1; uint k = z + 1;
@ -9536,7 +9536,7 @@ BOOST_AUTO_TEST_CASE(continue_in_modifier)
_; _;
} }
} }
function f() run { function f() run public {
uint k = x; uint k = x;
uint t = k + 1; uint t = k + 1;
x = t; x = t;
@ -9560,7 +9560,7 @@ BOOST_AUTO_TEST_CASE(return_in_modifier)
_; _;
} }
} }
function f() run { function f() run public {
uint k = x; uint k = x;
uint t = k + 1; uint t = k + 1;
x = t; x = t;

View File

@ -1,3 +1,3 @@
contract A { constructor() {} } contract A { constructor() {} }
// ---- // ----
// Warning: (13-29): No visibility specified. Defaulting to "public". // SyntaxError: (13-29): No visibility specified. Did you intend to add "public"?

View File

@ -1,4 +0,0 @@
pragma experimental "v0.5.0";
contract A { constructor() {} }
// ----
// SyntaxError: (43-59): No visibility specified.

View File

@ -3,4 +3,5 @@ contract C {
function() {} function() {}
} }
// ---- // ----
// SyntaxError: (90-103): No visibility specified. Did you intend to add "external"?
// TypeError: (90-103): Fallback function must be defined as "external". // TypeError: (90-103): Fallback function must be defined as "external".

View File

@ -1,6 +0,0 @@
pragma experimental "v0.5.0";
contract C {
function f() pure { }
}
// ----
// SyntaxError: (47-68): No visibility specified.

View File

@ -2,4 +2,4 @@ contract C {
function f() pure { } function f() pure { }
} }
// ---- // ----
// Warning: (17-38): No visibility specified. Defaulting to "public". // SyntaxError: (17-38): No visibility specified. Did you intend to add "public"?

View File

@ -1,6 +0,0 @@
pragma experimental "v0.5.0";
contract C {
function f() pure { }
}
// ----
// SyntaxError: (47-68): No visibility specified.

View File

@ -2,4 +2,5 @@ interface I {
function f(); function f();
} }
// ---- // ----
// SyntaxError: (15-28): No visibility specified. Did you intend to add "external"?
// TypeError: (15-28): Functions in interfaces must be declared external. // TypeError: (15-28): Functions in interfaces must be declared external.

View File

@ -1,7 +0,0 @@
pragma experimental "v0.5.0";
interface I {
function f();
}
// ----
// SyntaxError: (45-58): No visibility specified.
// TypeError: (45-58): Functions in interfaces must be declared external.

View File

@ -0,0 +1,12 @@
// State of the syntax checker has to be reset after the interface
// was visited. The suggested visibility for g() should not be external.
interface I {
function f();
}
contract C {
function g();
}
// ----
// SyntaxError: (158-171): No visibility specified. Did you intend to add "external"?
// SyntaxError: (191-204): No visibility specified. Did you intend to add "public"?
// TypeError: (158-171): Functions in interfaces must be declared external.