aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/CMakeLists.txt4
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp33
-rw-r--r--libsolidity/analysis/ConstantEvaluator.h8
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp20
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp16
-rw-r--r--libsolidity/analysis/TypeChecker.cpp18
-rw-r--r--libsolidity/ast/AST.cpp6
-rw-r--r--libsolidity/ast/AST.h5
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/ast/Types.cpp9
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp11
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp11
-rw-r--r--libsolidity/formal/SMTChecker.cpp28
-rw-r--r--libsolidity/formal/SMTChecker.h4
-rw-r--r--libsolidity/formal/Z3Interface.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.cpp37
-rw-r--r--libsolidity/interface/CompilerStack.h31
17 files changed, 186 insertions, 104 deletions
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt
index f7c1a390..99612c40 100644
--- a/libsolidity/CMakeLists.txt
+++ b/libsolidity/CMakeLists.txt
@@ -6,9 +6,9 @@ find_package(Z3 QUIET)
if (${Z3_FOUND})
include_directories(${Z3_INCLUDE_DIR})
add_definitions(-DHAVE_Z3)
- message("Z3 SMT solver FOUND.")
+ message("Z3 SMT solver found. This enables optional SMT checking.")
else()
- message("Z3 SMT solver NOT found.")
+ message("Z3 SMT solver NOT found. Optional SMT checking will not be available. Please install Z3 if it is desired.")
list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
endif()
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 7057eab7..bc3b7cf1 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -22,38 +22,55 @@
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
+#include <libsolidity/interface/ErrorReporter.h>
using namespace std;
using namespace dev;
using namespace dev::solidity;
-
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
{
TypePointer const& subType = _operation.subExpression().annotation().type;
if (!dynamic_cast<RationalNumberType const*>(subType.get()))
- BOOST_THROW_EXCEPTION(_operation.subExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.subExpression().location(), "Invalid constant expression.");
TypePointer t = subType->unaryOperatorResult(_operation.getOperator());
_operation.annotation().type = t;
}
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
{
TypePointer const& leftType = _operation.leftExpression().annotation().type;
TypePointer const& rightType = _operation.rightExpression().annotation().type;
if (!dynamic_cast<RationalNumberType const*>(leftType.get()))
- BOOST_THROW_EXCEPTION(_operation.leftExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.leftExpression().location(), "Invalid constant expression.");
if (!dynamic_cast<RationalNumberType const*>(rightType.get()))
- BOOST_THROW_EXCEPTION(_operation.rightExpression().createTypeError("Invalid constant expression."));
+ m_errorReporter.fatalTypeError(_operation.rightExpression().location(), "Invalid constant expression.");
TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
- if (Token::isCompareOp(_operation.getOperator()))
- commonType = make_shared<BoolType>();
- _operation.annotation().type = commonType;
+ if (!commonType)
+ {
+ m_errorReporter.typeError(
+ _operation.location(),
+ "Operator " +
+ string(Token::toString(_operation.getOperator())) +
+ " not compatible with types " +
+ leftType->toString() +
+ " and " +
+ rightType->toString()
+ );
+ commonType = leftType;
+ }
+ _operation.annotation().commonType = commonType;
+ _operation.annotation().type =
+ Token::isCompareOp(_operation.getOperator()) ?
+ make_shared<BoolType>() :
+ commonType;
}
void ConstantEvaluator::endVisit(Literal const& _literal)
{
_literal.annotation().type = Type::forLiteral(_literal);
if (!_literal.annotation().type)
- BOOST_THROW_EXCEPTION(_literal.createTypeError("Invalid literal value."));
+ m_errorReporter.fatalTypeError(_literal.location(), "Invalid literal value.");
}
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index 9ec04ebe..90bceb5d 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -29,6 +29,7 @@ namespace dev
namespace solidity
{
+class ErrorReporter;
class TypeChecker;
/**
@@ -37,13 +38,18 @@ class TypeChecker;
class ConstantEvaluator: private ASTConstVisitor
{
public:
- ConstantEvaluator(Expression const& _expr) { _expr.accept(*this); }
+ ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter):
+ m_errorReporter(_errorReporter)
+ {
+ _expr.accept(*this);
+ }
private:
virtual void endVisit(BinaryOperation const& _operation);
virtual void endVisit(UnaryOperation const& _operation);
virtual void endVisit(Literal const& _literal);
+ ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 20016112..f22c95cc 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -147,7 +147,7 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)
if (Expression const* length = _typeName.length())
{
if (!length->annotation().type)
- ConstantEvaluator e(*length);
+ ConstantEvaluator e(*length, m_errorReporter);
auto const* lengthType = dynamic_cast<RationalNumberType const*>(length->annotation().type.get());
if (!lengthType || !lengthType->mobileType())
fatalTypeError(length->location(), "Invalid array length, expected integer literal.");
@@ -298,11 +298,19 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
{
typeLoc = DataLocation::Storage;
if (_variable.isLocalVariable())
- m_errorReporter.warning(
- _variable.location(),
- "Variable is declared as a storage pointer. "
- "Use an explicit \"storage\" keyword to silence this warning."
- );
+ {
+ if (_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ typeError(
+ _variable.location(),
+ "Storage location must be specified as either \"memory\" or \"storage\"."
+ );
+ else
+ m_errorReporter.warning(
+ _variable.location(),
+ "Variable is declared as a storage pointer. "
+ "Use an explicit \"storage\" keyword to silence this warning."
+ );
+ }
}
}
else
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index ffa538b6..bd8ee597 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -150,10 +150,18 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
if (_memberAccess.memberName() == "callcode")
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
if (type->kind() == FunctionType::Kind::BareCallCode)
- m_errorReporter.warning(
- _memberAccess.location(),
- "\"callcode\" has been deprecated in favour of \"delegatecall\"."
- );
+ {
+ if (m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ m_errorReporter.typeError(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ }
if (m_constructor && m_currentContract)
if (ContractType const* type = dynamic_cast<ContractType const*>(_memberAccess.expression().annotation().type.get()))
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index b2a88059..746e762e 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -595,8 +595,16 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
{
if (_function.isImplemented())
m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot have an implementation.");
- if (_function.visibility() < FunctionDefinition::Visibility::Public)
- m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
+ if (_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ {
+ if (_function.visibility() != FunctionDefinition::Visibility::External)
+ m_errorReporter.typeError(_function.location(), "Functions in interfaces must be declared external.");
+ }
+ else
+ {
+ if (_function.visibility() < FunctionDefinition::Visibility::Public)
+ m_errorReporter.typeError(_function.location(), "Functions in interfaces cannot be internal or private.");
+ }
if (_function.isConstructor())
m_errorReporter.typeError(_function.location(), "Constructor cannot be defined in interfaces.");
}
@@ -1285,6 +1293,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
components[i]->accept(*this);
types.push_back(type(*components[i]));
+
+ // Note: code generation will visit each of the expression even if they are not assigned from.
+ if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1)
+ if (!dynamic_cast<RationalNumberType const&>(*types[i]).mobileType())
+ m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number.");
+
if (_tuple.isInlineArray())
solAssert(!!types[i], "Inline array cannot have empty components");
if (_tuple.isInlineArray())
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index a805322b..1048b610 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -22,7 +22,6 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/AST_accept.h>
#include <libdevcore/SHA3.h>
@@ -73,11 +72,6 @@ ASTAnnotation& ASTNode::annotation() const
return *m_annotation;
}
-Error ASTNode::createTypeError(string const& _description) const
-{
- return Error(Error::Type::TypeError) << errinfo_sourceLocation(location()) << errinfo_comment(_description);
-}
-
SourceUnitAnnotation& SourceUnit::annotation() const
{
if (!m_annotation)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 75b8e946..733e7c78 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -26,7 +26,6 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/parsing/Token.h>
#include <libsolidity/ast/Types.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTEnums.h>
@@ -89,10 +88,6 @@ public:
/// Returns the source code location of this node.
SourceLocation const& location() const { return m_location; }
- /// Creates a @ref TypeError exception and decorates it with the location of the node and
- /// the given description
- Error createTypeError(std::string const& _description) const;
-
///@todo make this const-safe by providing a different way to access the annotation
virtual ASTAnnotation& annotation() const;
diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h
index 15735368..46675e51 100644
--- a/libsolidity/ast/ASTForward.h
+++ b/libsolidity/ast/ASTForward.h
@@ -57,6 +57,7 @@ class UserDefinedTypeName;
class FunctionTypeName;
class Mapping;
class ArrayTypeName;
+class InlineAssembly;
class Statement;
class Block;
class PlaceholderStatement;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index a3cbe50a..ee5f462b 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -1616,9 +1616,10 @@ string ContractType::canonicalName() const
return m_contract.annotation().canonicalName;
}
-MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) const
+MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _contract) const
{
MemberList::MemberMap members;
+ solAssert(_contract, "");
if (m_super)
{
// add the most derived of all functions which are visible in derived contracts
@@ -1660,7 +1661,9 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const*) con
&it.second->declaration()
));
}
- addNonConflictingAddressMembers(members);
+ // In 0.5.0 address members are not populated into the contract.
+ if (!_contract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ addNonConflictingAddressMembers(members);
return members;
}
@@ -2022,7 +2025,7 @@ unsigned EnumType::memberValue(ASTString const& _member) const
return index;
++index;
}
- BOOST_THROW_EXCEPTION(m_enum.createTypeError("Requested unknown enum value ." + _member));
+ solAssert(false, "Requested unknown enum value " + _member);
}
bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 429db532..74565ae4 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -251,13 +251,10 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
FunctionDefinition const* fallback = _contract.fallbackFunction();
eth::AssemblyItem notFound = m_context.newTag();
- // shortcut messages without data if we have many functions in order to be able to receive
- // ether with constant gas
- if (interfaceFunctions.size() > 5 || fallback)
- {
- m_context << Instruction::CALLDATASIZE << Instruction::ISZERO;
- m_context.appendConditionalJumpTo(notFound);
- }
+ // directly jump to fallback if the data is too short to contain a function selector
+ // also guards against short data
+ m_context << u256(4) << Instruction::CALLDATASIZE << Instruction::LT;
+ m_context.appendConditionalJumpTo(notFound);
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index fe37baac..bb8c4a94 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -858,8 +858,15 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << Instruction::DUP1 << Instruction::DUP3 << Instruction::MSTORE;
// Stack: memptr requested_length
// update free memory pointer
- m_context << Instruction::DUP1 << arrayType.baseType()->memoryHeadSize();
- m_context << Instruction::MUL << u256(32) << Instruction::ADD;
+ m_context << Instruction::DUP1;
+ // Stack: memptr requested_length requested_length
+ if (arrayType.isByteArray())
+ // Round up to multiple of 32
+ m_context << u256(31) << Instruction::ADD << u256(31) << Instruction::NOT << Instruction::AND;
+ else
+ m_context << arrayType.baseType()->memoryHeadSize() << Instruction::MUL;
+ // stacK: memptr requested_length data_size
+ m_context << u256(32) << Instruction::ADD;
m_context << Instruction::DUP3 << Instruction::ADD;
utils().storeFreeMemoryPointer();
// Stack: memptr requested_length
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index fd78e578..2d2f05ec 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -234,6 +234,16 @@ void SMTChecker::endVisit(BinaryOperation const& _op)
void SMTChecker::endVisit(FunctionCall const& _funCall)
{
+ solAssert(_funCall.annotation().kind != FunctionCallKind::Unset, "");
+ if (_funCall.annotation().kind != FunctionCallKind::FunctionCall)
+ {
+ m_errorReporter.warning(
+ _funCall.location(),
+ "Assertion checker does not yet implement this expression."
+ );
+ return;
+ }
+
FunctionType const& funType = dynamic_cast<FunctionType const&>(*_funCall.expression().annotation().type);
std::vector<ASTPointer<Expression const>> const args = _funCall.arguments();
@@ -484,10 +494,10 @@ void SMTChecker::createVariable(VariableDeclaration const& _varDecl, bool _setTo
{
solAssert(m_currentSequenceCounter.count(&_varDecl) == 0, "");
solAssert(m_nextFreeSequenceCounter.count(&_varDecl) == 0, "");
- solAssert(m_Variables.count(&_varDecl) == 0, "");
+ solAssert(m_variables.count(&_varDecl) == 0, "");
m_currentSequenceCounter[&_varDecl] = 0;
m_nextFreeSequenceCounter[&_varDecl] = 1;
- m_Variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
+ m_variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
setValue(_varDecl, _setToZero);
}
else
@@ -556,7 +566,7 @@ smt::Expression SMTChecker::maxValue(IntegerType const& _t)
smt::Expression SMTChecker::expr(Expression const& _e)
{
- if (!m_Expressions.count(&_e))
+ if (!m_expressions.count(&_e))
{
solAssert(_e.annotation().type, "");
switch (_e.annotation().type->category())
@@ -565,24 +575,24 @@ smt::Expression SMTChecker::expr(Expression const& _e)
{
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(_e.annotation().type.get()))
solAssert(!rational->isFractional(), "");
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
}
case Type::Category::Integer:
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
case Type::Category::Bool:
- m_Expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
break;
default:
solAssert(false, "Type not implemented.");
}
}
- return m_Expressions.at(&_e);
+ return m_expressions.at(&_e);
}
smt::Expression SMTChecker::var(Declaration const& _decl)
{
- solAssert(m_Variables.count(&_decl), "");
- return m_Variables.at(&_decl);
+ solAssert(m_variables.count(&_decl), "");
+ return m_variables.at(&_decl);
}
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index d23fd201..faaac639 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -103,8 +103,8 @@ private:
std::shared_ptr<smt::SolverInterface> m_interface;
std::map<Declaration const*, int> m_currentSequenceCounter;
std::map<Declaration const*, int> m_nextFreeSequenceCounter;
- std::map<Expression const*, smt::Expression> m_Expressions;
- std::map<Declaration const*, smt::Expression> m_Variables;
+ std::map<Expression const*, smt::Expression> m_expressions;
+ std::map<Declaration const*, smt::Expression> m_variables;
ErrorReporter& m_errorReporter;
FunctionDefinition const* m_currentFunction = nullptr;
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 0ceed3a7..6111b2c8 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -73,28 +73,37 @@ void Z3Interface::addAssertion(Expression const& _expr)
pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate)
{
CheckResult result;
- switch (m_solver.check())
+ vector<string> values;
+ try
{
- case z3::check_result::sat:
- result = CheckResult::SATISFIABLE;
- break;
- case z3::check_result::unsat:
- result = CheckResult::UNSATISFIABLE;
- break;
- case z3::check_result::unknown:
- result = CheckResult::UNKNOWN;
- break;
- default:
- solAssert(false, "");
+ switch (m_solver.check())
+ {
+ case z3::check_result::sat:
+ result = CheckResult::SATISFIABLE;
+ break;
+ case z3::check_result::unsat:
+ result = CheckResult::UNSATISFIABLE;
+ break;
+ case z3::check_result::unknown:
+ result = CheckResult::UNKNOWN;
+ break;
+ default:
+ solAssert(false, "");
+ }
+
+ if (result != CheckResult::UNSATISFIABLE)
+ {
+ z3::model m = m_solver.get_model();
+ for (Expression const& e: _expressionsToEvaluate)
+ values.push_back(toString(m.eval(toZ3Expr(e))));
+ }
}
-
- vector<string> values;
- if (result != CheckResult::UNSATISFIABLE)
+ catch (z3::exception const&)
{
- z3::model m = m_solver.get_model();
- for (Expression const& e: _expressionsToEvaluate)
- values.push_back(toString(m.eval(toZ3Expr(e))));
+ result = CheckResult::ERROR;
+ values.clear();
}
+
return make_pair(result, values);
}
@@ -118,8 +127,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
{">=", 2},
{"+", 2},
{"-", 2},
- {"*", 2},
- {">=", 2}
+ {"*", 2}
};
string const& n = _expr.name;
if (m_functions.count(n))
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index b99fe4ee..5713256a 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -747,22 +747,32 @@ void CompilerStack::compileContract(
}
}
+string const CompilerStack::lastContractName() const
+{
+ if (m_contracts.empty())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+ // try to find some user-supplied contract
+ string contractName;
+ for (auto const& it: m_sources)
+ for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
+ if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
+ contractName = contract->fullyQualifiedName();
+ return contractName;
+}
+
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
if (m_contracts.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
- string contractName = _contractName;
- if (_contractName.empty())
- // try to find some user-supplied contract
- for (auto const& it: m_sources)
- for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
- if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- contractName = contract->fullyQualifiedName();
- auto it = m_contracts.find(contractName);
+
+ auto it = m_contracts.find(_contractName);
+ if (it != m_contracts.end())
+ return it->second;
+
// To provide a measure of backward-compatibility, if a contract is not located by its
// fully-qualified name, a lookup will be attempted purely on the contract's name to see
// if anything will satisfy.
- if (it == m_contracts.end() && contractName.find(":") == string::npos)
+ if (_contractName.find(":") == string::npos)
{
for (auto const& contractEntry: m_contracts)
{
@@ -773,12 +783,13 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa
string foundName;
getline(ss, source, ':');
getline(ss, foundName, ':');
- if (foundName == contractName) return contractEntry.second;
+ if (foundName == _contractName)
+ return contractEntry.second;
}
- // If we get here, both lookup methods failed.
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
}
- return it->second;
+
+ // If we get here, both lookup methods failed.
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract \"" + _contractName + "\" not found."));
}
CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index c567ac2c..b377b3aa 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -155,10 +155,10 @@ public:
std::map<std::string, unsigned> sourceIndices() const;
/// @returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& scanner(std::string const& _sourceName = "") const;
+ Scanner const& scanner(std::string const& _sourceName) const;
/// @returns the parsed source unit with the supplied name.
- SourceUnit const& ast(std::string const& _sourceName = "") const;
+ SourceUnit const& ast(std::string const& _sourceName) const;
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
@@ -168,48 +168,51 @@ public:
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
+ /// @returns the name of the last contract.
+ std::string const lastContractName() const;
+
/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
std::string const filesystemFriendlyName(std::string const& _contractName) const;
/// @returns the assembled object for a contract.
- eth::LinkerObject const& object(std::string const& _contractName = "") const;
+ eth::LinkerObject const& object(std::string const& _contractName) const;
/// @returns the runtime object for the contract.
- eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& runtimeObject(std::string const& _contractName) const;
/// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
/// substituted by the actual address. Note that this sequence starts end ends in three X
/// characters but can contain anything in between.
- eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& cloneObject(std::string const& _contractName) const;
/// @returns normal contract assembly items
- eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const;
/// @returns runtime contract assembly items
- eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName) const;
/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
/// if the contract does not (yet) have bytecode.
- std::string const* sourceMapping(std::string const& _contractName = "") const;
+ std::string const* sourceMapping(std::string const& _contractName) const;
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
/// if the contract does not (yet) have bytecode.
- std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
+ std::string const* runtimeSourceMapping(std::string const& _contractName) const;
/// @return a verbose text representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- std::string assemblyString(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ std::string assemblyString(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- Json::Value assemblyJSON(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ Json::Value assemblyJSON(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
- Json::Value const& contractABI(std::string const& _contractName = "") const;
+ Json::Value const& contractABI(std::string const& _contractName) const;
/// @returns a JSON representing the contract's user documentation.
/// Prerequisite: Successful call to parse or compile.
@@ -276,8 +279,8 @@ private:
);
void link();
- Contract const& contract(std::string const& _contractName = "") const;
- Source const& source(std::string const& _sourceName = "") const;
+ Contract const& contract(std::string const& _contractName) const;
+ Source const& source(std::string const& _sourceName) const;
/// @returns the parsed contract with the supplied name. Throws an exception if the contract
/// does not exist.