aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis/StaticAnalyzer.cpp
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-04-17 05:03:49 +0800
committerGitHub <noreply@github.com>2018-04-17 05:03:49 +0800
commit4cb486ee993cadde5564fb6c611d2bcf4fc44414 (patch)
tree6b971913021037cf28141c38af97c7ecda77719f /libsolidity/analysis/StaticAnalyzer.cpp
parentdfe3193c7382c80f1814247a162663a97c3f5e67 (diff)
parentb8431c5c4a6795db8c42a1a3389047658bb87301 (diff)
downloaddexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar.gz
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar.bz2
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar.lz
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar.xz
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.tar.zst
dexon-solidity-4cb486ee993cadde5564fb6c611d2bcf4fc44414.zip
Merge pull request #3892 from ethereum/develop
Merge develop into release for 0.4.22
Diffstat (limited to 'libsolidity/analysis/StaticAnalyzer.cpp')
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp111
1 files changed, 100 insertions, 11 deletions
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index d4de219a..00a581d0 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -21,6 +21,7 @@
*/
#include <libsolidity/analysis/StaticAnalyzer.h>
+#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/interface/ErrorReporter.h>
#include <memory>
@@ -50,6 +51,16 @@ void StaticAnalyzer::endVisit(ContractDefinition const&)
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())
m_currentFunction = &_function;
else
@@ -68,13 +79,13 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&)
for (auto const& var: m_localVarUseCount)
if (var.second == 0)
{
- if (var.first->isCallableParameter())
+ if (var.first.second->isCallableParameter())
m_errorReporter.warning(
- var.first->location(),
+ var.first.second->location(),
"Unused function parameter. Remove or comment out the variable name to silence this warning."
);
else
- m_errorReporter.warning(var.first->location(), "Unused local variable.");
+ m_errorReporter.warning(var.first.second->location(), "Unused local variable.");
}
m_localVarUseCount.clear();
@@ -87,7 +98,7 @@ bool StaticAnalyzer::visit(Identifier const& _identifier)
{
solAssert(!var->name().empty(), "");
if (var->isLocalVariable())
- m_localVarUseCount[var] += 1;
+ m_localVarUseCount[make_pair(var->id(), var)] += 1;
}
return true;
}
@@ -99,7 +110,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
solAssert(_variable.isLocalVariable(), "");
if (_variable.name() != "")
// This is not a no-op, the entry might pre-exist.
- m_localVarUseCount[&_variable] += 0;
+ m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0;
}
else if (_variable.isStateVariable())
{
@@ -122,7 +133,7 @@ bool StaticAnalyzer::visit(Return const& _return)
if (m_currentFunction && _return.expression())
for (auto const& var: m_currentFunction->returnParameters())
if (!var->name().empty())
- m_localVarUseCount[var.get()] += 1;
+ m_localVarUseCount[make_pair(var->id(), var.get())] += 1;
return true;
}
@@ -142,6 +153,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 +167,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()))
@@ -180,10 +206,32 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
);
}
- if (m_constructor && m_currentContract)
- if (ContractType const* type = dynamic_cast<ContractType const*>(_memberAccess.expression().annotation().type.get()))
- if (type->contractDefinition() == *m_currentContract)
- m_errorReporter.warning(_memberAccess.location(), "\"this\" used in constructor.");
+ if (m_constructor)
+ {
+ auto const* expr = &_memberAccess.expression();
+ while(expr)
+ {
+ if (auto id = dynamic_cast<Identifier const*>(expr))
+ {
+ if (id->name() == "this")
+ m_errorReporter.warning(
+ id->location(),
+ "\"this\" used in constructor. "
+ "Note that external functions of a contract "
+ "cannot be called while it is being constructed.");
+ break;
+ }
+ else if (auto tuple = dynamic_cast<TupleExpression const*>(expr))
+ {
+ if (tuple->components().size() == 1)
+ expr = tuple->components().front().get();
+ else
+ break;
+ }
+ else
+ break;
+ }
+ }
return true;
}
@@ -199,13 +247,54 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
{
solAssert(!var->name().empty(), "");
if (var->isLocalVariable())
- m_localVarUseCount[var] += 1;
+ m_localVarUseCount[make_pair(var->id(), var)] += 1;
}
}
return true;
}
+bool StaticAnalyzer::visit(BinaryOperation const& _operation)
+{
+ if (
+ _operation.rightExpression().annotation().isPure &&
+ (_operation.getOperator() == Token::Div || _operation.getOperator() == Token::Mod)
+ )
+ if (auto rhs = dynamic_pointer_cast<RationalNumberType const>(
+ ConstantEvaluator(m_errorReporter).evaluate(_operation.rightExpression())
+ ))
+ if (rhs->isZero())
+ m_errorReporter.typeError(
+ _operation.location(),
+ (_operation.getOperator() == Token::Div) ? "Division by zero." : "Modulo zero."
+ );
+
+ return true;
+}
+
+bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
+{
+ if (_functionCall.annotation().kind == FunctionCallKind::FunctionCall)
+ {
+ auto functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.expression().annotation().type);
+ solAssert(functionType, "");
+ if (functionType->kind() == FunctionType::Kind::AddMod || functionType->kind() == FunctionType::Kind::MulMod)
+ {
+ solAssert(_functionCall.arguments().size() == 3, "");
+ if (_functionCall.arguments()[2]->annotation().isPure)
+ if (auto lastArg = dynamic_pointer_cast<RationalNumberType const>(
+ ConstantEvaluator(m_errorReporter).evaluate(*(_functionCall.arguments())[2])
+ ))
+ if (lastArg->isZero())
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "Arithmetic modulo zero."
+ );
+ }
+ }
+ return true;
+}
+
bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
{
switch (_type.category())