aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md2
-rw-r--r--docs/types.rst6
-rw-r--r--docs/units-and-global-variables.rst4
-rw-r--r--docs/using-the-compiler.rst13
-rw-r--r--libsolidity/analysis/PostTypeChecker.cpp3
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp45
-rw-r--r--libsolidity/analysis/StaticAnalyzer.h9
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp17
-rw-r--r--libsolidity/analysis/SyntaxChecker.h4
-rw-r--r--libsolidity/interface/CompilerStack.cpp5
-rw-r--r--libsolidity/interface/StandardCompiler.cpp30
-rw-r--r--std/StandardToken.sol4
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp231
-rw-r--r--test/libsolidity/StandardCompiler.cpp12
14 files changed, 306 insertions, 79 deletions
diff --git a/Changelog.md b/Changelog.md
index 3169bb94..f4b1e20d 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -10,6 +10,8 @@ Features:
* Inline Assembly: Storage variable access using ``_slot`` and ``_offset`` suffixes.
* Inline Assembly: Disallow blocks with unbalanced stack.
* Static analyzer: Warn about statements without effects.
+ * Static analyzer: Warn about unused local variables, parameters, and return parameters.
+ * Syntax checker: issue deprecation warning for unary '+'
Bugfixes:
* Assembly output: Implement missing AssemblyItem types.
diff --git a/docs/types.rst b/docs/types.rst
index 60235ad2..c868adc6 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -64,6 +64,12 @@ expression ``x << y`` is equivalent to ``x * 2**y`` and ``x >> y`` is
equivalent to ``x / 2**y``. This means that shifting negative numbers
sign extends. Shifting by a negative amount throws a runtime exception.
+.. warning::
+ The results produced by shift right of negative values of signed integer types is different from those produced
+ by other programming languages. In Solidity, shift right maps to division so the shifted negative values
+ are going to be rounded towards zero (truncated). In other programming languages the shift right of negative values
+ works like division with rounding down (towards negative infinity).
+
.. index:: address, balance, send, call, callcode, delegatecall, transfer
.. _address:
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index ab957c7d..246cc564 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -22,8 +22,8 @@ unit and units are considered naively in the following way:
* ``1 minutes == 60 seconds``
* ``1 hours == 60 minutes``
* ``1 days == 24 hours``
- * ``1 weeks = 7 days``
- * ``1 years = 365 days``
+ * ``1 weeks == 7 days``
+ * ``1 years == 365 days``
Take care if you perform calendar calculations using these units, because
not every year equals 365 days and not even every day has 24 hours
diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst
index b74da213..7aa997f8 100644
--- a/docs/using-the-compiler.rst
+++ b/docs/using-the-compiler.rst
@@ -121,7 +121,6 @@ Input Description
// abi - ABI
// ast - AST of all source files (not supported atm)
// legacyAST - legacy AST of all source files
- // why3 - Why3 translated output
// devdoc - Developer documentation (natspec)
// userdoc - User documentation (natspec)
// metadata - Metadata
@@ -154,9 +153,9 @@ Input Description
"*": {
"*": [ "evm.sourceMap" ]
},
- // Enable the legacy AST and Why3 output of every single file.
+ // Enable the legacy AST output of every single file.
"*": {
- "": [ "legacyAST", "why3" ]
+ "": [ "legacyAST" ]
}
}
}
@@ -180,7 +179,7 @@ Output Description
],
// Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc
type: "TypeError",
- // Mandatory: Component where the error originated, such as "general", "why3", "ewasm", etc.
+ // Mandatory: Component where the error originated, such as "general", "ewasm", etc.
component: "general",
// Mandatory ("error" or "warning")
severity: "error",
@@ -222,7 +221,7 @@ Output Description
// Assembly (string)
assembly: "",
// Old-style assembly (object)
- legacyAssembly: [],
+ legacyAssembly: {},
// Bytecode and related details.
bytecode: {
// The bytecode as a hex string.
@@ -272,7 +271,5 @@ Output Description
}
}
}
- },
- // Why3 output (string)
- why3: ""
+ }
}
diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp
index cae77c74..e8da3ca4 100644
--- a/libsolidity/analysis/PostTypeChecker.cpp
+++ b/libsolidity/analysis/PostTypeChecker.cpp
@@ -58,6 +58,9 @@ void PostTypeChecker::endVisit(ContractDefinition const&)
for (auto declaration: m_constVariables)
if (auto identifier = findCycle(declaration))
typeError(declaration->location(), "The value of the constant " + declaration->name() + " has a cyclic dependency via " + identifier->name() + ".");
+
+ m_constVariables.clear();
+ m_constVariableDependencies.clear();
}
bool PostTypeChecker::visit(VariableDeclaration const& _variable)
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index 190d2420..369376fa 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -48,13 +48,58 @@ void StaticAnalyzer::endVisit(ContractDefinition const&)
bool StaticAnalyzer::visit(FunctionDefinition const& _function)
{
+ if (_function.isImplemented())
+ m_currentFunction = &_function;
+ else
+ solAssert(!m_currentFunction, "");
+ solAssert(m_localVarUseCount.empty(), "");
m_nonPayablePublic = _function.isPublic() && !_function.isPayable();
return true;
}
void StaticAnalyzer::endVisit(FunctionDefinition const&)
{
+ m_currentFunction = nullptr;
m_nonPayablePublic = false;
+ for (auto const& var: m_localVarUseCount)
+ if (var.second == 0)
+ warning(var.first->location(), "Unused local variable");
+ m_localVarUseCount.clear();
+}
+
+bool StaticAnalyzer::visit(Identifier const& _identifier)
+{
+ if (m_currentFunction)
+ if (auto var = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration))
+ {
+ solAssert(!var->name().empty(), "");
+ if (var->isLocalVariable())
+ m_localVarUseCount[var] += 1;
+ }
+ return true;
+}
+
+bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
+{
+ if (m_currentFunction)
+ {
+ solAssert(_variable.isLocalVariable(), "");
+ if (_variable.name() != "")
+ // This is not a no-op, the entry might pre-exist.
+ m_localVarUseCount[&_variable] += 0;
+ }
+ return true;
+}
+
+bool StaticAnalyzer::visit(Return const& _return)
+{
+ // If the return has an expression, it counts as
+ // a "use" of the return parameters.
+ if (m_currentFunction && _return.expression())
+ for (auto const& var: m_currentFunction->returnParameters())
+ if (!var->name().empty())
+ m_localVarUseCount[var.get()] += 1;
+ return true;
}
bool StaticAnalyzer::visit(ExpressionStatement const& _statement)
diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h
index 84342322..ab72e7d9 100644
--- a/libsolidity/analysis/StaticAnalyzer.h
+++ b/libsolidity/analysis/StaticAnalyzer.h
@@ -61,7 +61,9 @@ private:
virtual void endVisit(FunctionDefinition const& _function) override;
virtual bool visit(ExpressionStatement const& _statement) override;
-
+ virtual bool visit(VariableDeclaration const& _variable) override;
+ virtual bool visit(Identifier const& _identifier) override;
+ virtual bool visit(Return const& _return) override;
virtual bool visit(MemberAccess const& _memberAccess) override;
ErrorList& m_errors;
@@ -71,6 +73,11 @@ private:
/// Flag that indicates whether a public function does not contain the "payable" modifier.
bool m_nonPayablePublic = false;
+
+ /// Number of uses of each (named) local variable in a function, counter is initialized with zero.
+ std::map<VariableDeclaration const*, int> m_localVarUseCount;
+
+ FunctionDefinition const* m_currentFunction = nullptr;
};
}
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index 89014133..94e82a87 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -32,6 +32,16 @@ bool SyntaxChecker::checkSyntax(ASTNode const& _astRoot)
return Error::containsOnlyWarnings(m_errors);
}
+void SyntaxChecker::warning(SourceLocation const& _location, string const& _description)
+{
+ auto err = make_shared<Error>(Error::Type::Warning);
+ *err <<
+ errinfo_sourceLocation(_location) <<
+ errinfo_comment(_description);
+
+ m_errors.push_back(err);
+}
+
void SyntaxChecker::syntaxError(SourceLocation const& _location, std::string const& _description)
{
auto err = make_shared<Error>(Error::Type::SyntaxError);
@@ -148,6 +158,13 @@ bool SyntaxChecker::visit(Break const& _breakStatement)
return true;
}
+bool SyntaxChecker::visit(UnaryOperation const& _operation)
+{
+ if (_operation.getOperator() == Token::Add)
+ warning(_operation.location(), "Use of unary + is deprecated.");
+ return true;
+}
+
bool SyntaxChecker::visit(PlaceholderStatement const&)
{
m_placeholderFound = true;
diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h
index 308e128b..8d7dcdd3 100644
--- a/libsolidity/analysis/SyntaxChecker.h
+++ b/libsolidity/analysis/SyntaxChecker.h
@@ -32,6 +32,7 @@ namespace solidity
* The module that performs syntax analysis on the AST:
* - whether continue/break is in a for/while loop.
* - whether a modifier contains at least one '_'
+ * - issues deprecation warnings for unary '+'
*/
class SyntaxChecker: private ASTConstVisitor
{
@@ -43,6 +44,7 @@ public:
private:
/// Adds a new error to the list of errors.
+ void warning(SourceLocation const& _location, std::string const& _description);
void syntaxError(SourceLocation const& _location, std::string const& _description);
virtual bool visit(SourceUnit const& _sourceUnit) override;
@@ -60,6 +62,8 @@ private:
virtual bool visit(Continue const& _continueStatement) override;
virtual bool visit(Break const& _breakStatement) override;
+ virtual bool visit(UnaryOperation const& _operation) override;
+
virtual bool visit(PlaceholderStatement const& _placeholderStatement) override;
ErrorList& m_errors;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 79855060..9c9c9614 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -80,8 +80,11 @@ void CompilerStack::setRemappings(vector<string> const& _remappings)
void CompilerStack::reset(bool _keepSources)
{
if (_keepSources)
+ {
+ m_stackState = SourcesSet;
for (auto sourcePair: m_sources)
sourcePair.second.reset();
+ }
else
{
m_sources.clear();
@@ -161,7 +164,7 @@ bool CompilerStack::parse()
bool CompilerStack::analyze()
{
- if (m_stackState < ParsingSuccessful)
+ if (m_stackState != ParsingSuccessful)
return false;
resolveImports();
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index 2b5e861b..223cc15d 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -391,10 +391,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
// ABI, documentation and metadata
Json::Value contractData(Json::objectValue);
- contractData["abi"] = dev::jsonCompactPrint(m_compilerStack.metadata(contractName, DocumentationType::ABIInterface));
+ contractData["abi"] = m_compilerStack.metadata(contractName, DocumentationType::ABIInterface);
contractData["metadata"] = m_compilerStack.onChainMetadata(contractName);
- contractData["userdoc"] = dev::jsonCompactPrint(m_compilerStack.metadata(contractName, DocumentationType::NatspecUser));
- contractData["devdoc"] = dev::jsonCompactPrint(m_compilerStack.metadata(contractName, DocumentationType::NatspecDev));
+ contractData["userdoc"] = m_compilerStack.metadata(contractName, DocumentationType::NatspecUser);
+ contractData["devdoc"] = m_compilerStack.metadata(contractName, DocumentationType::NatspecDev);
// EVM
Json::Value evmData(Json::objectValue);
@@ -425,30 +425,6 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
}
output["contracts"] = contractsOutput;
- {
- ErrorList formalErrors;
- if (m_compilerStack.prepareFormalAnalysis(&formalErrors))
- output["why3"] = m_compilerStack.formalTranslation();
-
- for (auto const& error: formalErrors)
- {
- auto err = dynamic_pointer_cast<Error const>(error);
-
- errors.append(formatErrorWithException(
- *error,
- err->type() == Error::Type::Warning,
- err->typeName(),
- "general",
- "",
- scannerFromSourceName
- ));
- }
-
- // FIXME!!
- if (!formalErrors.empty())
- output["errors"] = errors;
- }
-
return output;
}
diff --git a/std/StandardToken.sol b/std/StandardToken.sol
index 4dad8541..51f925e0 100644
--- a/std/StandardToken.sol
+++ b/std/StandardToken.sol
@@ -25,7 +25,7 @@ contract StandardToken is Token {
return doTransfer(msg.sender, _to, _value);
}
- function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
+ function transferFrom(address _from, address _to, uint256 _value) returns (bool) {
if (m_allowance[_from][msg.sender] >= _value) {
if (doTransfer(_from, _to, _value)) {
m_allowance[_from][msg.sender] -= _value;
@@ -53,7 +53,7 @@ contract StandardToken is Token {
return true;
}
- function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
+ function allowance(address _owner, address _spender) constant returns (uint256) {
return m_allowance[_owner][_spender];
}
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index f88f600a..3a9f7295 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -216,7 +216,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
char const* text = R"(
contract test {
uint256 stateVariable1;
- function fun(uint256 arg1) { uint256 y; }
+ function fun(uint256 arg1) { uint256 y; y = arg1; }
}
)";
CHECK_SUCCESS(text);
@@ -237,8 +237,8 @@ BOOST_AUTO_TEST_CASE(double_function_declaration)
{
char const* text = R"(
contract test {
- function fun() { uint x; }
- function fun() { uint x; }
+ function fun() { }
+ function fun() { }
}
)";
CHECK_ERROR(text, DeclarationError, "");
@@ -262,7 +262,7 @@ BOOST_AUTO_TEST_CASE(name_shadowing)
char const* text = R"(
contract test {
uint256 variable;
- function f() { uint32 variable; }
+ function f() { uint32 variable; variable = 2; }
}
)";
CHECK_SUCCESS(text);
@@ -273,7 +273,7 @@ BOOST_AUTO_TEST_CASE(name_references)
char const* text = R"(
contract test {
uint256 variable;
- function f(uint256 arg) returns (uint out) { f(variable); test; out; }
+ function f(uint256) returns (uint out) { f(variable); test; out; }
}
)";
CHECK_SUCCESS(text);
@@ -404,8 +404,8 @@ BOOST_AUTO_TEST_CASE(type_checking_function_call)
{
char const* text = R"(
contract test {
- function f() returns (bool r) { return g(12, true) == 3; }
- function g(uint256 a, bool b) returns (uint256 r) { }
+ function f() returns (bool) { return g(12, true) == 3; }
+ function g(uint256, bool) returns (uint256) { }
}
)";
CHECK_SUCCESS(text);
@@ -523,12 +523,12 @@ BOOST_AUTO_TEST_CASE(forward_function_reference)
{
char const* text = R"(
contract First {
- function fun() returns (bool ret) {
+ function fun() returns (bool) {
return Second(1).fun(1, true, 3) > 0;
}
}
contract Second {
- function fun(uint a, bool b, uint c) returns (uint ret) {
+ function fun(uint, bool, uint) returns (uint) {
if (First(2).fun() == true) return 1;
}
}
@@ -636,10 +636,10 @@ BOOST_AUTO_TEST_CASE(abstract_contract_constructor_args_not_provided)
{
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
- contract BaseBase { function BaseBase(uint j); }
+ contract BaseBase { function BaseBase(uint); }
contract base is BaseBase { function foo(); }
contract derived is base {
- function derived(uint i) {}
+ function derived(uint) {}
function foo() {}
}
)";
@@ -701,7 +701,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases)
ASTPointer<SourceUnit> sourceUnit;
char const* text = R"(
contract Test {
- function boo(uint arg1, bytes32 arg2, address arg3) returns (uint ret) {
+ function boo(uint, bytes32, address) returns (uint ret) {
ret = 5;
}
}
@@ -725,7 +725,7 @@ BOOST_AUTO_TEST_CASE(function_external_types)
uint a;
}
contract Test {
- function boo(uint arg2, bool arg3, bytes8 arg4, bool[2] pairs, uint[] dynamic, C carg, address[] addresses) external returns (uint ret) {
+ function boo(uint, bool, bytes8, bool[2], uint[], C, address[]) external returns (uint ret) {
ret = 5;
}
}
@@ -914,7 +914,7 @@ BOOST_AUTO_TEST_CASE(complex_inheritance)
{
char const* text = R"(
contract A { function f() { uint8 x = C(0).g(); } }
- contract B { function f() {} function g() returns (uint8 r) {} }
+ contract B { function f() {} function g() returns (uint8) {} }
contract C is A, B { }
)";
CHECK_SUCCESS(text);
@@ -1672,7 +1672,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
{
char const* sourceCode = R"(
contract test {
- function f() returns(uint d) {
+ function f() returns(uint) {
uint8 x = 100;
return 10**x;
}
@@ -1681,7 +1681,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
CHECK_WARNING(sourceCode, "might overflow");
sourceCode = R"(
contract test {
- function f() returns(uint d) {
+ function f() returns(uint) {
uint8 x = 100;
return uint8(10)**x;
}
@@ -1690,7 +1690,7 @@ BOOST_AUTO_TEST_CASE(exp_warn_literal_base)
CHECK_SUCCESS(sourceCode);
sourceCode = R"(
contract test {
- function f() returns(uint d) {
+ function f() returns(uint) {
return 2**80;
}
}
@@ -1941,10 +1941,10 @@ BOOST_AUTO_TEST_CASE(test_for_bug_override_function_with_bytearray_type)
{
char const* sourceCode = R"(
contract Vehicle {
- function f(bytes _a) external returns (uint256 r) {r = 1;}
+ function f(bytes) external returns (uint256 r) {r = 1;}
}
contract Bike is Vehicle {
- function f(bytes _a) external returns (uint256 r) {r = 42;}
+ function f(bytes) external returns (uint256 r) {r = 42;}
}
)";
ETH_TEST_CHECK_NO_THROW(parseAndAnalyse(sourceCode), "Parsing and Name Resolving failed");
@@ -2570,6 +2570,7 @@ BOOST_AUTO_TEST_CASE(storage_location_local_variables)
uint[] storage x;
uint[] memory y;
uint[] memory z;
+ x;y;z;
}
}
)";
@@ -2625,6 +2626,7 @@ BOOST_AUTO_TEST_CASE(uninitialized_mapping_variable)
contract C {
function f() {
mapping(uint => uint) x;
+ x;
}
}
)";
@@ -2637,6 +2639,7 @@ BOOST_AUTO_TEST_CASE(uninitialized_mapping_array_variable)
contract C {
function f() {
mapping(uint => uint)[] x;
+ x;
}
}
)";
@@ -2789,6 +2792,7 @@ BOOST_AUTO_TEST_CASE(literal_strings)
function f() {
string memory long = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
string memory short = "123";
+ long; short;
}
}
)";
@@ -2865,7 +2869,7 @@ BOOST_AUTO_TEST_CASE(call_to_library_function)
{
char const* text = R"(
library Lib {
- function min(uint x, uint y) returns (uint);
+ function min(uint, uint) returns (uint);
}
contract Test {
function f() {
@@ -2963,9 +2967,9 @@ BOOST_AUTO_TEST_CASE(cyclic_binary_dependency_via_inheritance)
BOOST_AUTO_TEST_CASE(multi_variable_declaration_fail)
{
char const* text = R"(
- contract C { function f() { var (x,y); } }
+ contract C { function f() { var (x,y); x = 1; y = 1;} }
)";
- CHECK_ERROR(text, TypeError, "");
+ CHECK_ERROR(text, TypeError, "Assignment necessary for type detection.");
}
BOOST_AUTO_TEST_CASE(multi_variable_declaration_wildcards_fine)
@@ -2982,6 +2986,7 @@ BOOST_AUTO_TEST_CASE(multi_variable_declaration_wildcards_fine)
var (,e,g) = two();
var (,,) = three();
var () = none();
+ a;b;c;d;e;g;
}
}
)";
@@ -3040,6 +3045,7 @@ BOOST_AUTO_TEST_CASE(tuples)
var (b,) = (1,);
var (c,d) = (1, 2 + a);
var (e,) = (1, 2, b);
+ a;b;c;d;e;
}
}
)";
@@ -3197,7 +3203,7 @@ BOOST_AUTO_TEST_CASE(using_for_overload)
library D {
struct s { uint a; }
function mul(s storage self, uint x) returns (uint) { return self.a *= x; }
- function mul(s storage self, bytes32 x) returns (bytes32) { }
+ function mul(s storage, bytes32) returns (bytes32) { }
}
contract C {
using D for D.s;
@@ -3309,6 +3315,7 @@ BOOST_AUTO_TEST_CASE(create_memory_arrays)
L.S[][] memory x = new L.S[][](10);
var y = new uint[](20);
var z = new bytes(size);
+ x;y;z;
}
}
)";
@@ -3355,8 +3362,8 @@ BOOST_AUTO_TEST_CASE(function_overload_array_type)
{
char const* text = R"(
contract M {
- function f(uint[] values);
- function f(int[] values);
+ function f(uint[]);
+ function f(int[]);
}
)";
CHECK_SUCCESS(text);
@@ -3654,16 +3661,20 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
uint x;
uint y;
uint g = true ? x : y;
+ g += 1; // Avoid unused var warning
// integer constants
uint h = true ? 1 : 3;
+ h += 1; // Avoid unused var warning
// string literal
var i = true ? "hello" : "world";
+ i = "used"; //Avoid unused var warning
}
function f2() {
// bool
bool j = true ? true : false;
+ j = j && true; // Avoid unused var warning
// real is not there yet.
@@ -3671,15 +3682,19 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
byte[2] memory a;
byte[2] memory b;
var k = true ? a : b;
+ k[0] = 0; //Avoid unused var warning
bytes memory e;
bytes memory f;
var l = true ? e : f;
+ l[0] = 0; // Avoid unused var warning
// fixed bytes
bytes2 c;
bytes2 d;
var m = true ? c : d;
+ m &= m;
+
}
function f3() {
// contract doesn't fit in here
@@ -3689,7 +3704,7 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
// function
var r = true ? fun_x : fun_y;
-
+ r(); // Avoid unused var warning
// enum
small enum_x;
small enum_y;
@@ -3697,13 +3712,13 @@ BOOST_AUTO_TEST_CASE(conditional_with_all_types)
// tuple
var (n, o) = true ? (1, 2) : (3, 4);
-
+ (n, o) = (o, n); // Avoid unused var warning
// mapping
var p = true ? table1 : table2;
-
+ p[0] = 0; // Avoid unused var warning
// typetype
var q = true ? uint32(1) : uint32(2);
-
+ q += 1; // Avoid unused var warning
// modifier doesn't fit in here
// magic doesn't fit in here
@@ -3753,6 +3768,7 @@ BOOST_AUTO_TEST_CASE(uint7_and_uintM_as_identifier)
uint7 = 5;
string memory intM;
uint bytesM = 21;
+ intM; bytesM;
}
}
)";
@@ -3804,6 +3820,7 @@ BOOST_AUTO_TEST_CASE(int10abc_is_identifier)
function f() {
uint uint10abc = 3;
int int10abc = 4;
+ uint10abc; int10abc;
}
}
)";
@@ -3888,6 +3905,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_int_conversion)
int128 b = 4;
fixed c = b;
ufixed d = a;
+ c; d;
}
}
)";
@@ -3901,6 +3919,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_rational_int_conversion)
function f() {
fixed c = 3;
ufixed d = 4;
+ c; d;
}
}
)";
@@ -3914,6 +3933,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_rational_fraction_conversion)
function f() {
fixed a = 4.5;
ufixed d = 2.5;
+ a; d;
}
}
)";
@@ -3927,6 +3947,7 @@ BOOST_AUTO_TEST_CASE(invalid_int_implicit_conversion_from_fixed)
function f() {
fixed a = 4.5;
int b = a;
+ a; b;
}
}
)";
@@ -3938,12 +3959,33 @@ BOOST_AUTO_TEST_CASE(rational_unary_operation)
char const* text = R"(
contract test {
function f() {
+ ufixed8x16 a = 3.25;
+ fixed8x16 b = -3.25;
+ a;
+ b;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract test {
+ function f() {
ufixed8x16 a = +3.25;
fixed8x16 b = -3.25;
+ a; b;
}
}
)";
- CHECK_SUCCESS(text);
+ CHECK_WARNING(text,"Use of unary + is deprecated");
+ text = R"(
+ contract test {
+ function f(uint x) {
+ uint y = +x;
+ y;
+ }
+ }
+ )";
+ CHECK_WARNING(text,"Use of unary + is deprecated");
}
BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert)
@@ -3955,6 +3997,7 @@ BOOST_AUTO_TEST_CASE(leading_zero_rationals_convert)
ufixed0x56 b = 0.0000000000000006661338147750939242541790008544921875;
fixed0x8 c = -0.5;
fixed0x56 d = -0.0000000000000006661338147750939242541790008544921875;
+ a; b; c; d;
}
}
)";
@@ -3972,6 +4015,7 @@ BOOST_AUTO_TEST_CASE(size_capabilities_of_fixed_point_types)
fixed248x8 d = -123456781234567979695948382928485849359686494864095409282048094275023098123.5;
fixed0x256 e = -0.93322335481643744342575580035176794825198893968114429702091846411734101080123092162893656820177312738451291806995868682861328125;
fixed0x256 g = -0.00011788606643744342575580035176794825198893968114429702091846411734101080123092162893656820177312738451291806995868682861328125;
+ a; b; c; d; e; g;
}
}
)";
@@ -4011,6 +4055,7 @@ BOOST_AUTO_TEST_CASE(fixed_type_valid_explicit_conversions)
ufixed0x256 a = ufixed0x256(1/3);
ufixed0x248 b = ufixed0x248(1/3);
ufixed0x8 c = ufixed0x8(1/3);
+ a; b; c;
}
}
)";
@@ -4142,6 +4187,7 @@ BOOST_AUTO_TEST_CASE(rational_to_fixed_literal_expression)
ufixed8x248 e = ufixed8x248(35.245 % 12.9);
ufixed8x248 f = ufixed8x248(1.2 % 2);
fixed g = 2 ** -2;
+ a; b; c; d; e; f; g;
}
}
)";
@@ -4252,6 +4298,7 @@ BOOST_AUTO_TEST_CASE(var_capable_of_holding_constant_rationals)
var a = 0.12345678;
var b = 12345678.352;
var c = 0.00000009;
+ a; b; c;
}
}
)";
@@ -4264,6 +4311,7 @@ BOOST_AUTO_TEST_CASE(var_and_rational_with_tuple)
contract test {
function f() {
var (a, b) = (.5, 1/3);
+ a; b;
}
}
)";
@@ -4337,6 +4385,7 @@ BOOST_AUTO_TEST_CASE(zero_handling)
function f() {
fixed8x8 a = 0;
ufixed8x8 b = 0;
+ a; b;
}
}
)";
@@ -4842,6 +4891,7 @@ BOOST_AUTO_TEST_CASE(function_type_arrays)
function(uint) returns (uint)[10] storage b = y;
function(uint) external returns (uint)[] memory c;
c = new function(uint) external returns (uint)[](200);
+ a; b;
}
}
)";
@@ -4900,8 +4950,8 @@ BOOST_AUTO_TEST_CASE(external_function_to_function_type_calldata_parameter)
// when converting to a function type.
char const* text = R"(
contract C {
- function f(function(bytes memory x) external g) { }
- function callback(bytes x) external {}
+ function f(function(bytes memory) external g) { }
+ function callback(bytes) external {}
function g() {
f(this.callback);
}
@@ -5270,6 +5320,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_checksum)
contract C {
function f() {
var x = 0xFA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ x;
}
}
)";
@@ -5282,6 +5333,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_no_checksum)
contract C {
function f() {
var x = 0xfa0bfc97e48458494ccd857e1a85dc91f7f0046e;
+ x;
}
}
)";
@@ -5294,6 +5346,7 @@ BOOST_AUTO_TEST_CASE(invalid_address_length)
contract C {
function f() {
var x = 0xA0bFc97E48458494Ccd857e1A85DC91F7F0046E;
+ x;
}
}
)";
@@ -5328,6 +5381,7 @@ BOOST_AUTO_TEST_CASE(address_methods)
bool delegatecallRet = addr.delegatecall();
bool sendRet = addr.send(1);
addr.transfer(1);
+ callRet; callcodeRet; delegatecallRet; sendRet;
}
}
)";
@@ -5554,6 +5608,119 @@ BOOST_AUTO_TEST_CASE(pure_statement_check_for_regular_for_loop)
success(text);
}
+BOOST_AUTO_TEST_CASE(warn_unused_local)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ uint a;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Unused");
+}
+
+BOOST_AUTO_TEST_CASE(warn_unused_local_assigned)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ var a = 1;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Unused");
+}
+
+BOOST_AUTO_TEST_CASE(warn_unused_param)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint a) {
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Unused");
+ text = R"(
+ contract C {
+ function f(uint a) {
+ }
+ }
+ )";
+ success(text);
+}
+
+BOOST_AUTO_TEST_CASE(warn_unused_return_param)
+{
+ char const* text = R"(
+ contract C {
+ function f() returns (uint a) {
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Unused");
+ text = R"(
+ contract C {
+ function f() returns (uint a) {
+ return;
+ }
+ }
+ )";
+ CHECK_WARNING(text, "Unused");
+ text = R"(
+ contract C {
+ function f() returns (uint) {
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f() returns (uint a) {
+ a = 1;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+ text = R"(
+ contract C {
+ function f() returns (uint a) {
+ return 1;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(no_unused_warnings)
+{
+ char const* text = R"(
+ contract C {
+ function f(uint a) returns (uint b) {
+ uint c = 1;
+ b = a + c;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(no_unused_dec_after_use)
+{
+ char const* text = R"(
+ contract C {
+ function f() {
+ a = 7;
+ uint a;
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+
+
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp
index f480ba6f..ffb0e2c6 100644
--- a/test/libsolidity/StandardCompiler.cpp
+++ b/test/libsolidity/StandardCompiler.cpp
@@ -235,12 +235,12 @@ BOOST_AUTO_TEST_CASE(basic_compilation)
BOOST_CHECK(containsAtMostWarnings(result));
Json::Value contract = getContractResult(result, "fileA", "A");
BOOST_CHECK(contract.isObject());
- BOOST_CHECK(contract["abi"].isString());
- BOOST_CHECK(contract["abi"].asString() == "[]");
- BOOST_CHECK(contract["devdoc"].isString());
- BOOST_CHECK(contract["devdoc"].asString() == "{\"methods\":{}}");
- BOOST_CHECK(contract["userdoc"].isString());
- BOOST_CHECK(contract["userdoc"].asString() == "{\"methods\":{}}");
+ BOOST_CHECK(contract["abi"].isArray());
+ BOOST_CHECK(dev::jsonCompactPrint(contract["abi"]) == "[]");
+ BOOST_CHECK(contract["devdoc"].isObject());
+ BOOST_CHECK(dev::jsonCompactPrint(contract["devdoc"]) == "{\"methods\":{}}");
+ BOOST_CHECK(contract["userdoc"].isObject());
+ BOOST_CHECK(dev::jsonCompactPrint(contract["userdoc"]) == "{\"methods\":{}}");
BOOST_CHECK(contract["evm"].isObject());
/// @TODO check evm.methodIdentifiers, legacyAssembly, bytecode, deployedBytecode
BOOST_CHECK(contract["evm"]["bytecode"].isObject());