diff options
author | Christian <c@ethdev.com> | 2014-10-15 20:45:51 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-10-16 00:41:29 +0800 |
commit | df142782bc3a1435f70d9f5f4c8e04ae8d7e1678 (patch) | |
tree | 363823cbff0362b1e47e8e22b8cb8c482308a49f | |
parent | 89b794f1dc15c8688526470b9d68b361dab82be3 (diff) | |
download | dexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.tar.gz dexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.tar.zst dexon-solidity-df142782bc3a1435f70d9f5f4c8e04ae8d7e1678.zip |
Added meaningful exception types.
-rw-r--r-- | AST.cpp | 36 | ||||
-rw-r--r-- | Exceptions.h | 34 | ||||
-rw-r--r-- | NameAndTypeResolver.cpp | 10 | ||||
-rw-r--r-- | Parser.cpp | 26 |
4 files changed, 77 insertions, 29 deletions
@@ -24,6 +24,7 @@ #include <libsolidity/AST.h> #include <libsolidity/ASTVisitor.h> +#include <libsolidity/Exceptions.h> namespace dev { namespace solidity { @@ -245,7 +246,9 @@ void Literal::accept(ASTVisitor& _visitor) void Statement::expectType(Expression& _expression, const Type& _expectedType) { if (!_expression.checkTypeRequirements()->isImplicitlyConvertibleTo(_expectedType)) - throw std::exception(); // @todo + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type not implicitly convertible " + "to expected type.")); + //@todo provide more information to the exception } ptr<Type> Block::checkTypeRequirements() @@ -284,7 +287,9 @@ ptr<Type> Return::checkTypeRequirements() { BOOST_ASSERT(m_returnParameters != nullptr); if (m_returnParameters->getParameters().size() != 1) - throw std::exception(); // @todo + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Different number of arguments in " + "return statement than in returns " + "declaration.")); // this could later be changed such that the paramaters type is an anonymous struct type, // but for now, we only allow one return parameter @@ -318,7 +323,7 @@ ptr<Type> Assignment::checkTypeRequirements() if (m_assigmentOperator != Token::ASSIGN) { // complex assignment if (!m_type->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_assigmentOperator))) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); } return m_type; } @@ -328,7 +333,7 @@ ptr<Type> UnaryOperation::checkTypeRequirements() // INC, DEC, NOT, BIT_NOT, DELETE m_type = m_subExpression->checkTypeRequirements(); if (m_type->acceptsUnaryOperator(m_operator)) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Unary operator not compatible with type.")); return m_type; } @@ -342,7 +347,7 @@ ptr<Type> BinaryOperation::checkTypeRequirements() else if (m_left->getType()->isImplicitlyConvertibleTo(*m_right->getType())) m_commonType = m_right->getType(); else - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("No common type found in binary operation.")); if (Token::IsCompareOp(m_operator)) { m_type = std::make_shared<BoolType>(); @@ -350,7 +355,7 @@ ptr<Type> BinaryOperation::checkTypeRequirements() BOOST_ASSERT(Token::IsBinaryOp(m_operator)); m_type = m_commonType; if (!m_commonType->acceptsBinaryOperator(Token::AssignmentToBinaryOp(m_operator))) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Operator not compatible with type.")); } return m_type; } @@ -369,9 +374,11 @@ ptr<Type> FunctionCall::checkTypeRequirements() //@todo for structs, we have to check the number of arguments to be equal to the // number of non-mapping members if (m_arguments.size() != 1) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("More than one argument for " + "explicit type conersion.")); if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type->getActualType())) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Explicit type conversion not " + "allowed.")); m_type = type->getActualType(); } else if (category == Type::Category::FUNCTION) { //@todo would be nice to create a struct type from the arguments @@ -382,10 +389,12 @@ ptr<Type> FunctionCall::checkTypeRequirements() FunctionDefinition const& fun = function->getFunction(); vecptr<VariableDeclaration> const& parameters = fun.getParameters(); if (parameters.size() != m_arguments.size()) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Wrong argument count for " + "function call.")); for (size_t i = 0; i < m_arguments.size(); ++i) { if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameters[i]->getType())) - throw std::exception(); + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Invalid type for argument in " + "function call.")); } // @todo actually the return type should be an anonymous struct, @@ -395,7 +404,7 @@ ptr<Type> FunctionCall::checkTypeRequirements() else m_type = fun.getReturnParameterList()->getParameters().front()->getType(); } else { - throw std::exception(); // type does not support invocation + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Type does not support invocation.")); } return m_type; } @@ -428,7 +437,8 @@ ptr<Type> Identifier::checkTypeRequirements() VariableDeclaration* variable = dynamic_cast<VariableDeclaration*>(m_referencedDeclaration); if (variable != nullptr) { if (variable->getType().get() == nullptr) - throw std::exception(); // variable used before type could be determined + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Variable referenced before type " + "could be determined.")); m_type = variable->getType(); return m_type; } @@ -452,7 +462,7 @@ ptr<Type> Identifier::checkTypeRequirements() m_type = std::make_shared<TypeType>(std::make_shared<ContractType>(*contractDef)); return m_type; } - throw std::exception(); // declaration reference of unknown/forbidden type + BOOST_ASSERT(false); // declaration reference of unknown/forbidden type return m_type; } diff --git a/Exceptions.h b/Exceptions.h new file mode 100644 index 00000000..5e0b1522 --- /dev/null +++ b/Exceptions.h @@ -0,0 +1,34 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. +*/ +/** + * @author Christian <c@ethdev.com> + * @date 2014 + * Solidity exception hierarchy. + */ + +#pragma once + +#include <libdevcore/Exceptions.h> + +namespace dev { +namespace solidity { + +struct ParserError : virtual Exception {}; +struct TypeError : virtual Exception {}; +struct DeclarationError : virtual Exception {}; + +} } diff --git a/NameAndTypeResolver.cpp b/NameAndTypeResolver.cpp index 33b550eb..8e769c47 100644 --- a/NameAndTypeResolver.cpp +++ b/NameAndTypeResolver.cpp @@ -23,6 +23,7 @@ #include <libsolidity/NameAndTypeResolver.h> #include <libsolidity/AST.h> +#include <libsolidity/Exceptions.h> #include <boost/assert.hpp> namespace dev { @@ -115,7 +116,7 @@ void NameAndTypeResolver::resolveReferencesInFunction(ParameterList& _returnPara virtual bool visit(Identifier& _identifier) override { Declaration* declaration = m_resolver.getNameFromCurrentScope(_identifier.getName()); if (declaration == nullptr) - throw std::exception(); // @todo + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); _identifier.setReferencedDeclaration(*declaration); return false; } @@ -151,10 +152,11 @@ void NameAndTypeResolver::registerVariableDeclarationAndResolveType(VariableDecl virtual bool visit(UserDefinedTypeName& _typeName) override { Declaration* declaration = m_resolver.getNameFromCurrentScope(_typeName.getName()); if (declaration == nullptr) - throw std::exception(); // @todo + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Undeclared identifier.")); StructDefinition* referencedStruct = dynamic_cast<StructDefinition*>(declaration); + //@todo later, contracts are also valid types if (referencedStruct == nullptr) - throw std::exception(); // @todo we only allow structs as user defined types (later also contracts) + BOOST_THROW_EXCEPTION(TypeError() << errinfo_comment("Identifier does not name a type name.")); _typeName.setReferencedStruct(*referencedStruct); return false; } @@ -176,7 +178,7 @@ void NameAndTypeResolver::registerVariableDeclarationAndResolveType(VariableDecl void NameAndTypeResolver::registerDeclaration(Declaration& _declaration) { if (!m_currentScope->registerDeclaration(_declaration)) - throw std::exception(); // @todo + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Identifier already declared.")); } Declaration* NameAndTypeResolver::getNameFromCurrentScope(ASTString const& _name, bool _recursive) @@ -20,10 +20,11 @@ * Solidity parser. */ -#include "libdevcore/Log.h" -#include "libsolidity/BaseTypes.h" -#include "libsolidity/Parser.h" -#include "libsolidity/Scanner.h" +#include <libdevcore/Log.h> +#include <libsolidity/BaseTypes.h> +#include <libsolidity/Parser.h> +#include <libsolidity/Scanner.h> +#include <libsolidity/Exceptions.h> namespace dev { namespace solidity { @@ -530,16 +531,17 @@ ptr<ASTString> Parser::getLiteralAndAdvance() void Parser::throwExpectationError(const std::string& _description) { + //@todo put some of this stuff into ParserError int line, column; std::tie(line, column) = m_scanner->translatePositionToLineColumn(getPosition()); - cwarn << "Solidity parser error: " << _description - << "at line " << (line + 1) - << ", column " << (column + 1); - cwarn << m_scanner->getLineAtPosition(getPosition()); - cwarn << std::string(column, ' ') << "^"; - - /// @todo make a proper exception hierarchy - throw std::exception(); + std::stringstream buf; + buf << "Solidity parser error: " << _description + << " at line " << (line + 1) + << ", column " << (column + 1) << "\n" + << m_scanner->getLineAtPosition(getPosition()) << "\n" + << std::string(column, ' ') << "^"; + + BOOST_THROW_EXCEPTION(ParserError() << errinfo_comment(buf.str())); } |