Browse Source

Merge branch 'develop' into v8console

cl-refactor
Marek Kotewicz 10 years ago
parent
commit
209cce445e
  1. 12
      eth/main.cpp
  2. 4
      libp2p/Host.cpp
  3. 28
      libsolidity/AST.cpp
  4. 5
      libsolidity/Compiler.cpp
  5. 42
      libsolidity/DeclarationContainer.cpp
  6. 4
      libsolidity/DeclarationContainer.h
  7. 16
      libsolidity/Exceptions.h
  8. 37
      libsolidity/NameAndTypeResolver.cpp
  9. 74
      libsolidity/SourceReferenceFormatter.cpp
  10. 10
      libsolidity/SourceReferenceFormatter.h
  11. 2
      libweb3jsonrpc/WebThreeStubServerBase.cpp
  12. 14
      mix/ClientModel.cpp
  13. 94
      mix/CodeModel.cpp
  14. 20
      mix/CodeModel.h
  15. 2
      mix/qml/StateDialog.qml
  16. 5
      mix/qml/html/codeeditor.js
  17. 3
      mix/qml/js/Debugger.js
  18. 2
      mix/test/qml/js/TestTutorial.js
  19. 45
      solc/CommandLineInterface.cpp
  20. 1
      solc/CommandLineInterface.h
  21. 46
      test/libsolidity/SolidityEndToEndTest.cpp

12
eth/main.cpp

@ -149,6 +149,7 @@ void help()
<< " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl << " --listen <port> Listen on the given port for incoming connections (default: 30303)." << endl
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl << " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << endl
<< " --port <port> Connect to remote port (default: 30303)." << endl << " --port <port> Connect to remote port (default: 30303)." << endl
<< " --network-id <n> Only connect to other hosts with this network id (default:0)." << endl
<< " --upnp <on/off> Use UPnP for NAT (default: on)." << endl << " --upnp <on/off> Use UPnP for NAT (default: on)." << endl
#if ETH_JSONRPC || !ETH_TRUE #if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl << "Work farming mode:" << endl
@ -521,6 +522,7 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303; unsigned short remotePort = 30303;
unsigned peers = 5; unsigned peers = 5;
bool bootstrap = false; bool bootstrap = false;
unsigned networkId = 0;
/// Mining params /// Mining params
unsigned mining = 0; unsigned mining = 0;
@ -677,6 +679,15 @@ int main(int argc, char** argv)
return -1; return -1;
} }
} }
else if (arg == "--network-id" && i + 1 < argc)
try {
networkId = stol(argv[++i]);
}
catch (...)
{
cerr << "Bad " << arg << " option: " << argv[i] << endl;
return -1;
}
else if (arg == "--benchmark-warmup" && i + 1 < argc) else if (arg == "--benchmark-warmup" && i + 1 < argc)
try { try {
benchmarkWarmup = stol(argv[++i]); benchmarkWarmup = stol(argv[++i]);
@ -1047,6 +1058,7 @@ int main(int argc, char** argv)
c->setForceMining(forceMining); c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU); c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase); c->setAddress(coinbase);
c->setNetworkId(networkId);
} }
cout << "Transaction Signer: " << sigKey.address() << endl; cout << "Transaction Signer: " << sigKey.address() << endl;

4
libp2p/Host.cpp

@ -226,7 +226,7 @@ void Host::startPeerSession(Public const& _id, RLP const& _rlp, RLPXFrameIO* _io
return; return;
} }
if (peerCount() > 2 * m_idealPeerCount) if (peerCount() > 9 * m_idealPeerCount)
{ {
ps->disconnect(TooManyPeers); ps->disconnect(TooManyPeers);
return; return;
@ -341,7 +341,7 @@ void Host::runAcceptor()
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService)); auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService));
m_tcp4Acceptor.async_accept(socket->ref(), [=](boost::system::error_code ec) m_tcp4Acceptor.async_accept(socket->ref(), [=](boost::system::error_code ec)
{ {
if (peerCount() > 2 * m_idealPeerCount) if (peerCount() > 9 * m_idealPeerCount)
{ {
clog(NetConnect) << "Dropping incoming connect due to maximum peer count (2 * ideal peer count): " << socket->remoteEndpoint(); clog(NetConnect) << "Dropping incoming connect due to maximum peer count (2 * ideal peer count): " << socket->remoteEndpoint();
socket->close(); socket->close();

28
libsolidity/AST.cpp

@ -96,8 +96,8 @@ void ContractDefinition::checkTypeRequirements()
FixedHash<4> const& hash = it.first; FixedHash<4> const& hash = it.first;
if (hashes.count(hash)) if (hashes.count(hash))
BOOST_THROW_EXCEPTION(createTypeError( BOOST_THROW_EXCEPTION(createTypeError(
std::string("Function signature hash collision for ") + string("Function signature hash collision for ") + it.second->externalSignature()
it.second->externalSignature())); ));
hashes.insert(hash); hashes.insert(hash);
} }
} }
@ -140,12 +140,22 @@ void ContractDefinition::checkDuplicateFunctions() const
map<string, vector<FunctionDefinition const*>> functions; map<string, vector<FunctionDefinition const*>> functions;
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions()) for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
functions[function->getName()].push_back(function.get()); functions[function->getName()].push_back(function.get());
if (functions[getName()].size() > 1) if (functions[getName()].size() > 1)
{
SecondarySourceLocation ssl;
auto it = functions[getName()].begin();
++it;
for (; it != functions[getName()].end(); ++it)
ssl.append("Another declaration is here:", (*it)->getLocation());
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
DeclarationError() << DeclarationError() <<
errinfo_sourceLocation(getLocation()) << errinfo_sourceLocation(functions[getName()].front()->getLocation()) <<
errinfo_comment("More than one constructor defined.") errinfo_comment("More than one constructor defined.") <<
errinfo_secondarySourceLocation(ssl)
); );
}
for (auto const& it: functions) for (auto const& it: functions)
{ {
vector<FunctionDefinition const*> const& overloads = it.second; vector<FunctionDefinition const*> const& overloads = it.second;
@ -155,7 +165,9 @@ void ContractDefinition::checkDuplicateFunctions() const
BOOST_THROW_EXCEPTION( BOOST_THROW_EXCEPTION(
DeclarationError() << DeclarationError() <<
errinfo_sourceLocation(overloads[j]->getLocation()) << errinfo_sourceLocation(overloads[j]->getLocation()) <<
errinfo_comment("Function with same name and arguments already defined.") errinfo_comment("Function with same name and arguments defined twice.") <<
errinfo_secondarySourceLocation(SecondarySourceLocation().append(
"Other declaration is here:", overloads[i]->getLocation()))
); );
} }
} }
@ -299,12 +311,12 @@ void ContractDefinition::checkExternalTypeClashes() const
)); ));
} }
std::vector<ASTPointer<EventDefinition>> const& ContractDefinition::getInterfaceEvents() const vector<ASTPointer<EventDefinition>> const& ContractDefinition::getInterfaceEvents() const
{ {
if (!m_interfaceEvents) if (!m_interfaceEvents)
{ {
set<string> eventsSeen; set<string> eventsSeen;
m_interfaceEvents.reset(new std::vector<ASTPointer<EventDefinition>>()); m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts()) for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<EventDefinition> const& e: contract->getEvents()) for (ASTPointer<EventDefinition> const& e: contract->getEvents())
if (eventsSeen.count(e->getName()) == 0) if (eventsSeen.count(e->getName()) == 0)
@ -944,7 +956,7 @@ void Identifier::overloadResolution(TypePointers const& _argumentTypes)
solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution."); solAssert(!m_referencedDeclaration, "Referenced declaration should be null before overload resolution.");
solAssert(!m_overloadedDeclarations.empty(), "No candidates for overload resolution found."); solAssert(!m_overloadedDeclarations.empty(), "No candidates for overload resolution found.");
std::vector<Declaration const*> possibles; vector<Declaration const*> possibles;
if (m_overloadedDeclarations.size() == 1) if (m_overloadedDeclarations.size() == 1)
m_referencedDeclaration = *m_overloadedDeclarations.begin(); m_referencedDeclaration = *m_overloadedDeclarations.begin();

5
libsolidity/Compiler.cpp

@ -431,7 +431,8 @@ bool Compiler::visit(ForStatement const& _forStatement)
CompilerContext::LocationSetter locationSetter(m_context, _forStatement); CompilerContext::LocationSetter locationSetter(m_context, _forStatement);
eth::AssemblyItem loopStart = m_context.newTag(); eth::AssemblyItem loopStart = m_context.newTag();
eth::AssemblyItem loopEnd = m_context.newTag(); eth::AssemblyItem loopEnd = m_context.newTag();
m_continueTags.push_back(loopStart); eth::AssemblyItem loopNext = m_context.newTag();
m_continueTags.push_back(loopNext);
m_breakTags.push_back(loopEnd); m_breakTags.push_back(loopEnd);
if (_forStatement.getInitializationExpression()) if (_forStatement.getInitializationExpression())
@ -449,6 +450,8 @@ bool Compiler::visit(ForStatement const& _forStatement)
_forStatement.getBody().accept(*this); _forStatement.getBody().accept(*this);
m_context << loopNext;
// for's loop expression if existing // for's loop expression if existing
if (_forStatement.getLoopExpression()) if (_forStatement.getLoopExpression())
_forStatement.getLoopExpression()->accept(*this); _forStatement.getLoopExpression()->accept(*this);

42
libsolidity/DeclarationContainer.cpp

@ -28,6 +28,28 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::solidity; using namespace dev::solidity;
Declaration const* DeclarationContainer::conflictingDeclaration(Declaration const& _declaration) const
{
ASTString const& name(_declaration.getName());
solAssert(!name.empty(), "");
vector<Declaration const*> declarations;
if (m_declarations.count(name))
declarations += m_declarations.at(name);
if (m_invisibleDeclarations.count(name))
declarations += m_invisibleDeclarations.at(name);
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
{
// check that all other declarations with the same name are functions
for (Declaration const* declaration: declarations)
if (!dynamic_cast<FunctionDefinition const*>(declaration))
return declaration;
}
else if (!declarations.empty())
return declarations.front();
return nullptr;
}
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update) bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _invisible, bool _update)
{ {
ASTString const& name(_declaration.getName()); ASTString const& name(_declaration.getName());
@ -40,24 +62,8 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration,
m_declarations.erase(name); m_declarations.erase(name);
m_invisibleDeclarations.erase(name); m_invisibleDeclarations.erase(name);
} }
else else if (conflictingDeclaration(_declaration))
{ return false;
vector<Declaration const*> declarations;
if (m_declarations.count(name))
declarations += m_declarations.at(name);
if (m_invisibleDeclarations.count(name))
declarations += m_invisibleDeclarations.at(name);
if (dynamic_cast<FunctionDefinition const*>(&_declaration))
{
// check that all other declarations with the same name are functions
for (Declaration const* declaration: declarations)
if (!dynamic_cast<FunctionDefinition const*>(declaration))
return false;
}
else if (!declarations.empty())
return false;
}
if (_invisible) if (_invisible)
m_invisibleDeclarations[name].insert(&_declaration); m_invisibleDeclarations[name].insert(&_declaration);

4
libsolidity/DeclarationContainer.h

@ -34,7 +34,7 @@ namespace solidity
{ {
/** /**
* Container that stores mappings betwee names and declarations. It also contains a link to the * Container that stores mappings between names and declarations. It also contains a link to the
* enclosing scope. * enclosing scope.
*/ */
class DeclarationContainer class DeclarationContainer
@ -51,6 +51,8 @@ public:
std::set<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const; std::set<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
std::map<ASTString, std::set<Declaration const*>> const& getDeclarations() const { return m_declarations; } std::map<ASTString, std::set<Declaration const*>> const& getDeclarations() const { return m_declarations; }
/// @returns whether declaration is valid, and if not also returns previous declaration.
Declaration const* conflictingDeclaration(Declaration const& _declaration) const;
private: private:
Declaration const* m_enclosingDeclaration; Declaration const* m_enclosingDeclaration;

16
libsolidity/Exceptions.h

@ -23,6 +23,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include <utility>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libevmcore/SourceLocation.h> #include <libevmcore/SourceLocation.h>
@ -38,7 +39,22 @@ struct CompilerError: virtual Exception {};
struct InternalCompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {};
struct DocstringParsingError: virtual Exception {}; struct DocstringParsingError: virtual Exception {};
using errorSourceLocationInfo = std::pair<std::string, SourceLocation>;
class SecondarySourceLocation
{
public:
SecondarySourceLocation& append(std::string const& _errMsg, SourceLocation const& _sourceLocation)
{
infos.push_back(std::make_pair(_errMsg, _sourceLocation));
return *this;
}
std::vector<errorSourceLocationInfo> infos;
};
using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>; using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>;
using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>;
} }
} }

37
libsolidity/NameAndTypeResolver.cpp

@ -354,9 +354,33 @@ void DeclarationRegistrationHelper::closeCurrentScope()
void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope) void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaration, bool _opensScope)
{ {
if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract())) if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation()) {
<< errinfo_comment("Identifier already declared.")); SourceLocation firstDeclarationLocation;
//@todo the exception should also contain the location of the first declaration SourceLocation secondDeclarationLocation;
Declaration const* conflictingDeclaration = m_scopes[m_currentScope].conflictingDeclaration(_declaration);
solAssert(conflictingDeclaration, "");
if (_declaration.getLocation().start < conflictingDeclaration->getLocation().start)
{
firstDeclarationLocation = _declaration.getLocation();
secondDeclarationLocation = conflictingDeclaration->getLocation();
}
else
{
firstDeclarationLocation = conflictingDeclaration->getLocation();
secondDeclarationLocation = _declaration.getLocation();
}
BOOST_THROW_EXCEPTION(
DeclarationError() <<
errinfo_sourceLocation(secondDeclarationLocation) <<
errinfo_comment("Identifier already declared.") <<
errinfo_secondarySourceLocation(
SecondarySourceLocation().append("The previous declaration is here:", firstDeclarationLocation)
)
);
}
_declaration.setScope(m_currentScope); _declaration.setScope(m_currentScope);
if (_opensScope) if (_opensScope)
enterNewSubScope(_declaration); enterNewSubScope(_declaration);
@ -435,8 +459,11 @@ bool ReferencesResolver::visit(Identifier& _identifier)
{ {
auto declarations = m_resolver.getNameFromCurrentScope(_identifier.getName()); auto declarations = m_resolver.getNameFromCurrentScope(_identifier.getName());
if (declarations.empty()) if (declarations.empty())
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation()) BOOST_THROW_EXCEPTION(
<< errinfo_comment("Undeclared identifier.")); DeclarationError() <<
errinfo_sourceLocation(_identifier.getLocation()) <<
errinfo_comment("Undeclared identifier.")
);
else if (declarations.size() == 1) else if (declarations.size() == 1)
_identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract); _identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract);
else else

74
libsolidity/SourceReferenceFormatter.cpp

@ -32,9 +32,11 @@ namespace dev
namespace solidity namespace solidity
{ {
void SourceReferenceFormatter::printSourceLocation(ostream& _stream, void SourceReferenceFormatter::printSourceLocation(
SourceLocation const& _location, ostream& _stream,
Scanner const& _scanner) SourceLocation const& _location,
Scanner const& _scanner
)
{ {
int startLine; int startLine;
int startColumn; int startColumn;
@ -46,11 +48,11 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
{ {
string line = _scanner.getLineAtPosition(_location.start); string line = _scanner.getLineAtPosition(_location.start);
_stream << line << endl; _stream << line << endl;
std::for_each(line.cbegin(), line.cbegin() + startColumn, for_each(
[&_stream](char const& ch) line.cbegin(),
{ line.cbegin() + startColumn,
_stream << (ch == '\t' ? '\t' : ' '); [&_stream](char const& ch) { _stream << (ch == '\t' ? '\t' : ' '); }
}); );
_stream << "^"; _stream << "^";
if (endColumn > startColumn + 2) if (endColumn > startColumn + 2)
_stream << string(endColumn - startColumn - 2, '-'); _stream << string(endColumn - startColumn - 2, '-');
@ -59,33 +61,65 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
_stream << endl; _stream << endl;
} }
else else
_stream << _scanner.getLineAtPosition(_location.start) << endl _stream <<
<< string(startColumn, ' ') << "^\n" _scanner.getLineAtPosition(_location.start) <<
<< "Spanning multiple lines.\n"; endl <<
string(startColumn, ' ') <<
"^\n" <<
"Spanning multiple lines.\n";
} }
void SourceReferenceFormatter::printExceptionInformation(ostream& _stream, void SourceReferenceFormatter::printSourceName(
Exception const& _exception, ostream& _stream,
string const& _name, SourceLocation const& _location,
CompilerStack const& _compiler) Scanner const& _scanner
)
{
int startLine;
int startColumn;
tie(startLine, startColumn) = _scanner.translatePositionToLineColumn(_location.start);
_stream << *_location.sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
}
void SourceReferenceFormatter::printExceptionInformation(
ostream& _stream,
Exception const& _exception,
string const& _name,
CompilerStack const& _compiler
)
{ {
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception); SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
Scanner const* scanner; auto secondarylocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
Scanner const* scanner = nullptr;
if (location) if (location)
{ {
scanner = &_compiler.getScanner(*location->sourceName); scanner = &_compiler.getScanner(*location->sourceName);
int startLine; printSourceName(_stream, *location, *scanner);
int startColumn;
tie(startLine, startColumn) = scanner->translatePositionToLineColumn(location->start);
_stream << *location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
} }
_stream << _name; _stream << _name;
if (string const* description = boost::get_error_info<errinfo_comment>(_exception)) if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
_stream << ": " << *description << endl; _stream << ": " << *description << endl;
if (location) if (location)
{
scanner = &_compiler.getScanner(*location->sourceName);
printSourceLocation(_stream, *location, *scanner); printSourceLocation(_stream, *location, *scanner);
}
if (secondarylocation && !secondarylocation->infos.empty())
{
for (auto info: secondarylocation->infos)
{
scanner = &_compiler.getScanner(*info.second.sourceName);
_stream << info.first << " ";
printSourceName(_stream, info.second, *scanner);
_stream << endl;
printSourceLocation(_stream, info.second, *scanner);
}
_stream << endl;
}
} }
} }

10
libsolidity/SourceReferenceFormatter.h

@ -40,8 +40,14 @@ struct SourceReferenceFormatter
{ {
public: public:
static void printSourceLocation(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner); static void printSourceLocation(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner);
static void printExceptionInformation(std::ostream& _stream, Exception const& _exception, static void printExceptionInformation(
std::string const& _name, CompilerStack const& _compiler); std::ostream& _stream,
Exception const& _exception,
std::string const& _name,
CompilerStack const& _compiler
);
private:
static void printSourceName(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner);
}; };
} }

2
libweb3jsonrpc/WebThreeStubServerBase.cpp

@ -54,7 +54,7 @@ const unsigned dev::SensibleHttpThreads = 1;
#else #else
const unsigned dev::SensibleHttpThreads = 4; const unsigned dev::SensibleHttpThreads = 4;
#endif #endif
const unsigned dev::SensibleHttpPort = 8080; const unsigned dev::SensibleHttpPort = 8545;
static Json::Value toJson(dev::eth::BlockInfo const& _bi) static Json::Value toJson(dev::eth::BlockInfo const& _bi)
{ {

14
mix/ClientModel.cpp

@ -422,7 +422,7 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
//try to resolve contract for source level debugging //try to resolve contract for source level debugging
auto nameIter = m_contractNames.find(code.address); auto nameIter = m_contractNames.find(code.address);
CompiledContract const* compilerRes = nullptr; CompiledContract const* compilerRes = nullptr;
if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(nameIter->second))) if (nameIter != m_contractNames.end() && (compilerRes = m_codeModel->tryGetContract(nameIter->second))) //returned object is guaranteed to live till the end of event handler in main thread
{ {
eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems(); eth::AssemblyItems assemblyItems = !_t.isConstructor() ? compilerRes->assemblyItems() : compilerRes->constructorAssemblyItems();
codes.back()->setDocument(compilerRes->documentId()); codes.back()->setDocument(compilerRes->documentId());
@ -467,9 +467,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
{ {
//track calls into functions //track calls into functions
AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex]; AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex];
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end)); QString functionName = m_codeModel->resolveFunctionName(instruction.getLocation());
if (functionIter != contract->functions().end() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty())) if (!functionName.isEmpty() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty()))
solCallStack.push_front(QVariant::fromValue(functionIter.value())); solCallStack.push_front(QVariant::fromValue(functionName));
else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty()) else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty())
solCallStack.pop_front(); solCallStack.pop_front();
} }
@ -521,11 +521,13 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
prevInstructionIndex = instructionIndex; prevInstructionIndex = instructionIndex;
// filter out locations that match whole function or contract
SourceLocation location = instruction.getLocation(); SourceLocation location = instruction.getLocation();
if (contract->contract()->location() == location || contract->functions().contains(LocationPair(location.start, location.end))) QString source = QString::fromUtf8(location.sourceName->c_str());
if (m_codeModel->isContractOrFunctionLocation(location))
location = dev::SourceLocation(-1, -1, location.sourceName); location = dev::SourceLocation(-1, -1, location.sourceName);
solState = new QSolState(debugData, move(storage), move(solCallStack), move(locals), location.start, location.end, QString::fromUtf8(location.sourceName->c_str())); solState = new QSolState(debugData, move(storage), move(solCallStack), move(locals), location.start, location.end, source);
} }
states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState))); states.append(QVariant::fromValue(new QMachineState(debugData, instructionIndex, s, codes[s.codeIndex], data[s.dataIndex], solState)));

94
mix/CodeModel.cpp

@ -51,30 +51,31 @@ const std::set<std::string> c_predefinedContracts =
namespace namespace
{ {
using namespace dev::solidity; using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor
class CollectLocalsVisitor: public ASTConstVisitor
{ {
public: public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals): CollectLocalsVisitor(QHash<LocationPair, SolidityDeclaration>* _locals):
m_functions(_functions), m_locals(_locals), m_functionScope(false) {} m_locals(_locals), m_functionScope(false) {}
private: private:
LocationPair nodeLocation(ASTNode const& _node) LocationPair nodeLocation(ASTNode const& _node)
{ {
return LocationPair(_node.getLocation().start, _node.getLocation().end); return LocationPair(_node.getLocation().start, _node.getLocation().end);
} }
virtual bool visit(FunctionDefinition const& _node) virtual bool visit(FunctionDefinition const&)
{ {
m_functions->insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
m_functionScope = true; m_functionScope = true;
return true; return true;
} }
virtual void endVisit(FunctionDefinition const&) virtual void endVisit(FunctionDefinition const&) override
{ {
m_functionScope = false; m_functionScope = false;
} }
virtual bool visit(VariableDeclaration const& _node) virtual bool visit(VariableDeclaration const& _node) override
{ {
SolidityDeclaration decl; SolidityDeclaration decl;
decl.type = CodeModel::nodeType(_node.getType().get()); decl.type = CodeModel::nodeType(_node.getType().get());
@ -87,11 +88,38 @@ private:
} }
private: private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals; QHash<LocationPair, SolidityDeclaration>* m_locals;
bool m_functionScope; bool m_functionScope;
}; };
class CollectLocationsVisitor: public ASTConstVisitor
{
public:
CollectLocationsVisitor(SourceMap* _sourceMap):
m_sourceMap(_sourceMap) {}
private:
LocationPair nodeLocation(ASTNode const& _node)
{
return LocationPair(_node.getLocation().start, _node.getLocation().end);
}
virtual bool visit(FunctionDefinition const& _node) override
{
m_sourceMap->functions.insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
return true;
}
virtual bool visit(ContractDefinition const& _node) override
{
m_sourceMap->contracts.insert(nodeLocation(_node), QString::fromStdString(_node.getName()));
return true;
}
private:
SourceMap* m_sourceMap;
};
QHash<unsigned, SolidityDeclarations> collectStorage(dev::solidity::ContractDefinition const& _contract) QHash<unsigned, SolidityDeclarations> collectStorage(dev::solidity::ContractDefinition const& _contract)
{ {
QHash<unsigned, SolidityDeclarations> result; QHash<unsigned, SolidityDeclarations> result;
@ -132,7 +160,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
if (contractDefinition.getLocation().sourceName.get()) if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName); m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
CollectDeclarationsVisitor visitor(&m_functions, &m_locals); CollectLocalsVisitor visitor(&m_locals);
m_storage = collectStorage(contractDefinition); m_storage = collectStorage(contractDefinition);
contractDefinition.accept(visitor); contractDefinition.accept(visitor);
m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name); m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name);
@ -243,6 +271,7 @@ void CodeModel::releaseContracts()
for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c) for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c)
c.value()->deleteLater(); c.value()->deleteLater();
m_contractMap.clear(); m_contractMap.clear();
m_sourceMaps.clear();
} }
void CodeModel::runCompilationJob(int _jobId) void CodeModel::runCompilationJob(int _jobId)
@ -253,13 +282,17 @@ void CodeModel::runCompilationJob(int _jobId)
try try
{ {
cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})"); cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})");
std::vector<std::string> sourceNames;
{ {
Guard l(x_pendingContracts); Guard l(x_pendingContracts);
for (auto const& c: m_pendingContracts) for (auto const& c: m_pendingContracts)
{
cs.addSource(c.first.toStdString(), c.second.toStdString()); cs.addSource(c.first.toStdString(), c.second.toStdString());
sourceNames.push_back(c.first.toStdString());
}
} }
cs.compile(false); cs.compile(false);
collectContracts(cs); collectContracts(cs, sourceNames);
} }
catch (dev::Exception const& _exception) catch (dev::Exception const& _exception)
{ {
@ -281,11 +314,20 @@ void CodeModel::runCompilationJob(int _jobId)
emit stateChanged(); emit stateChanged();
} }
void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs) void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs, std::vector<std::string> const& _sourceNames)
{ {
Guard pl(x_pendingContracts); Guard pl(x_pendingContracts);
Guard l(x_contractMap); Guard l(x_contractMap);
ContractMap result; ContractMap result;
SourceMaps sourceMaps;
for (std::string const& sourceName: _sourceNames)
{
dev::solidity::SourceUnit const& source = _cs.getAST(sourceName);
SourceMap sourceMap;
CollectLocationsVisitor collector(&sourceMap);
source.accept(collector);
sourceMaps.insert(QString::fromStdString(sourceName), std::move(sourceMap));
}
for (std::string n: _cs.getContractNames()) for (std::string n: _cs.getContractNames())
{ {
if (c_predefinedContracts.count(n) != 0) if (c_predefinedContracts.count(n) != 0)
@ -326,6 +368,7 @@ void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs)
} }
releaseContracts(); releaseContracts();
m_contractMap.swap(result); m_contractMap.swap(result);
m_sourceMaps.swap(sourceMaps);
emit codeChanged(); emit codeChanged();
emit compilationComplete(); emit compilationComplete();
} }
@ -431,3 +474,32 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
return r; return r;
} }
bool CodeModel::isContractOrFunctionLocation(dev::SourceLocation const& _location)
{
if (!_location.sourceName)
return false;
Guard l(x_contractMap);
auto sourceMapIter = m_sourceMaps.find(QString::fromStdString(*_location.sourceName));
if (sourceMapIter != m_sourceMaps.cend())
{
LocationPair location(_location.start, _location.end);
return sourceMapIter.value().contracts.contains(location) || sourceMapIter.value().functions.contains(location);
}
return false;
}
QString CodeModel::resolveFunctionName(dev::SourceLocation const& _location)
{
if (!_location.sourceName)
return QString();
Guard l(x_contractMap);
auto sourceMapIter = m_sourceMaps.find(QString::fromStdString(*_location.sourceName));
if (sourceMapIter != m_sourceMaps.cend())
{
LocationPair location(_location.start, _location.end);
auto functionNameIter = sourceMapIter.value().functions.find(location);
if (functionNameIter != sourceMapIter.value().functions.cend())
return functionNameIter.value();
}
return QString();
}

20
mix/CodeModel.h

@ -97,7 +97,6 @@ public:
/// @returns contract source Id /// @returns contract source Id
QString documentId() const { return m_documentId; } QString documentId() const { return m_documentId; }
QHash<LocationPair, QString> const& functions() const { return m_functions; }
QHash<LocationPair, SolidityDeclaration> const& locals() const { return m_locals; } QHash<LocationPair, SolidityDeclaration> const& locals() const { return m_locals; }
QHash<unsigned, SolidityDeclarations> const& storage() const { return m_storage; } QHash<unsigned, SolidityDeclarations> const& storage() const { return m_storage; }
@ -110,7 +109,6 @@ private:
QString m_documentId; QString m_documentId;
eth::AssemblyItems m_assemblyItems; eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems; eth::AssemblyItems m_constructorAssemblyItems;
QHash<LocationPair, QString> m_functions;
QHash<LocationPair, SolidityDeclaration> m_locals; QHash<LocationPair, SolidityDeclaration> m_locals;
QHash<unsigned, SolidityDeclarations> m_storage; QHash<unsigned, SolidityDeclarations> m_storage;
@ -119,6 +117,17 @@ private:
using ContractMap = QMap<QString, CompiledContract*>; //needs to be sorted using ContractMap = QMap<QString, CompiledContract*>; //needs to be sorted
/// Source map
using LocationMap = QHash<LocationPair, QString>;
struct SourceMap
{
LocationMap contracts;
LocationMap functions;
};
using SourceMaps = QMap<QString, SourceMap>; //by source id
/// Code compilation model. Compiles contracts in background an provides compiled contract data /// Code compilation model. Compiles contracts in background an provides compiled contract data
class CodeModel: public QObject class CodeModel: public QObject
{ {
@ -153,6 +162,10 @@ public:
Q_INVOKABLE void reset() { reset(QVariantMap()); } Q_INVOKABLE void reset() { reset(QVariantMap()); }
/// Convert solidity type info to mix type /// Convert solidity type info to mix type
static SolidityType nodeType(dev::solidity::Type const* _type); static SolidityType nodeType(dev::solidity::Type const* _type);
/// Check if given location belongs to contract or function
bool isContractOrFunctionLocation(dev::SourceLocation const& _location);
/// Get funciton name by location
QString resolveFunctionName(dev::SourceLocation const& _location);
signals: signals:
/// Emited on compilation state change /// Emited on compilation state change
@ -182,11 +195,12 @@ private:
void runCompilationJob(int _jobId); void runCompilationJob(int _jobId);
void stop(); void stop();
void releaseContracts(); void releaseContracts();
void collectContracts(solidity::CompilerStack const& _cs); void collectContracts(dev::solidity::CompilerStack const& _cs, std::vector<std::string> const& _sourceNames);
std::atomic<bool> m_compiling; std::atomic<bool> m_compiling;
mutable dev::Mutex x_contractMap; mutable dev::Mutex x_contractMap;
ContractMap m_contractMap; ContractMap m_contractMap;
SourceMaps m_sourceMaps;
std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings; std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings;
QThread m_backgroundThread; QThread m_backgroundThread;
BackgroundWorker m_backgroundWorker; BackgroundWorker m_backgroundWorker;

2
mix/qml/StateDialog.qml

@ -158,7 +158,7 @@ Dialog {
id: importJsonFileDialog id: importJsonFileDialog
visible: false visible: false
title: qsTr("Select State File") title: qsTr("Select State File")
nameFilters: [qsTr("JSON files (*.json)", "All files (*)")] nameFilters: Qt.platform.os === "osx" ? [] : [qsTr("JSON files (*.json)", "All files (*)")] //qt 5.4 segfaults with filter string on OSX
onAccepted: { onAccepted: {
var path = importJsonFileDialog.fileUrl.toString() var path = importJsonFileDialog.fileUrl.toString()
var jsonData = fileIo.readFile(path) var jsonData = fileIo.readFile(path)

5
mix/qml/html/codeeditor.js

@ -126,7 +126,10 @@ highlightExecution = function(start, end) {
executionMark.clear(); executionMark.clear();
if (debugWarning) if (debugWarning)
debugWarning.clear(); debugWarning.clear();
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" }); if (start > 0 && end > start) {
executionMark = editor.markText(editor.posFromIndex(start), editor.posFromIndex(end), { className: "CodeMirror-exechighlight" });
editor.scrollIntoView(editor.posFromIndex(start));
}
} }
var changeId; var changeId;

3
mix/qml/js/Debugger.js

@ -183,7 +183,8 @@ function selectState(stateIndex)
function highlightSelection(index) function highlightSelection(index)
{ {
statesList.positionViewAtRow(index, ListView.Center); if (statesList.visible)
statesList.positionViewAtRow(index, ListView.Visible);
statesList.selection.clear(); statesList.selection.clear();
statesList.selection.select(index); statesList.selection.select(index);
} }

2
mix/test/qml/js/TestTutorial.js

@ -52,7 +52,7 @@ function test_tutorial()
transactionDialog.selectFunction("setRating"); transactionDialog.selectFunction("setRating");
clickElement(transactionDialog, 200, 310); clickElement(transactionDialog, 200, 310);
ts.typeString("Titanic", transactionDialog); ts.typeString("Titanic", transactionDialog);
clickElement(transactionDialog, 200, 350); clickElement(transactionDialog, 200, 330);
ts.typeString("2", transactionDialog); ts.typeString("2", transactionDialog);
transactionDialog.acceptAndClose(); transactionDialog.acceptAndClose();
mainApplication.projectModel.stateDialog.acceptAndClose(); mainApplication.projectModel.stateDialog.acceptAndClose();

45
solc/CommandLineInterface.cpp

@ -51,19 +51,18 @@ namespace dev
namespace solidity namespace solidity
{ {
// LTODO: Maybe some argument class pairing names with static string const g_argAbiStr = "json-abi";
// extensions and other attributes would be a better choice here? static string const g_argSolAbiStr = "sol-abi";
static string const g_argAbiStr = "json-abi"; static string const g_argSignatureHashes = "hashes";
static string const g_argSolAbiStr = "sol-abi"; static string const g_argAsmStr = "asm";
static string const g_argAsmStr = "asm"; static string const g_argAsmJsonStr = "asm-json";
static string const g_argAsmJsonStr = "asm-json"; static string const g_argAstStr = "ast";
static string const g_argAstStr = "ast"; static string const g_argAstJson = "ast-json";
static string const g_argAstJson = "ast-json"; static string const g_argBinaryStr = "binary";
static string const g_argBinaryStr = "binary"; static string const g_argOpcodesStr = "opcodes";
static string const g_argOpcodesStr = "opcodes"; static string const g_argNatspecDevStr = "natspec-dev";
static string const g_argNatspecDevStr = "natspec-dev";
static string const g_argNatspecUserStr = "natspec-user"; static string const g_argNatspecUserStr = "natspec-user";
static string const g_argAddStandard = "add-std"; static string const g_argAddStandard = "add-std";
/// Possible arguments to for --combined-json /// Possible arguments to for --combined-json
static set<string> const g_combinedJsonArgs{ static set<string> const g_combinedJsonArgs{
@ -96,6 +95,7 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
return return
humanTargetedStdout(_args, g_argAbiStr) || humanTargetedStdout(_args, g_argAbiStr) ||
humanTargetedStdout(_args, g_argSolAbiStr) || humanTargetedStdout(_args, g_argSolAbiStr) ||
humanTargetedStdout(_args, g_argSignatureHashes) ||
humanTargetedStdout(_args, g_argNatspecUserStr) || humanTargetedStdout(_args, g_argNatspecUserStr) ||
humanTargetedStdout(_args, g_argAstJson) || humanTargetedStdout(_args, g_argAstJson) ||
humanTargetedStdout(_args, g_argNatspecDevStr) || humanTargetedStdout(_args, g_argNatspecDevStr) ||
@ -173,6 +173,24 @@ void CommandLineInterface::handleBytecode(string const& _contract)
handleBinary(_contract); handleBinary(_contract);
} }
void CommandLineInterface::handleSignatureHashes(string const& _contract)
{
string out;
for (auto const& it: m_compiler->getContractDefinition(_contract).getInterfaceFunctions())
out += toHex(it.first.ref()) + ": " + it.second->externalSignature() + "\n";
auto choice = m_args[g_argSignatureHashes].as<OutputType>();
if (outputToStdout(choice))
cout << "Function signatures: " << endl << out;
if (outputToFile(choice))
{
ofstream outFile(_contract + ".signatures");
outFile << out;
outFile.close();
}
}
void CommandLineInterface::handleMeta(DocumentationType _type, string const& _contract) void CommandLineInterface::handleMeta(DocumentationType _type, string const& _contract)
{ {
std::string argName; std::string argName;
@ -254,6 +272,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
"Request to output the contract's JSON ABI interface.") "Request to output the contract's JSON ABI interface.")
(g_argSolAbiStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argSolAbiStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's Solidity ABI interface.") "Request to output the contract's Solidity ABI interface.")
(g_argSignatureHashes.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's functions' signature hashes.")
(g_argNatspecUserStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argNatspecUserStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"Request to output the contract's Natspec user documentation.") "Request to output the contract's Natspec user documentation.")
(g_argNatspecDevStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"), (g_argNatspecDevStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
@ -516,6 +536,7 @@ void CommandLineInterface::actOnInput()
} }
handleBytecode(contract); handleBytecode(contract);
handleSignatureHashes(contract);
handleMeta(DocumentationType::ABIInterface, contract); handleMeta(DocumentationType::ABIInterface, contract);
handleMeta(DocumentationType::ABISolidityInterface, contract); handleMeta(DocumentationType::ABISolidityInterface, contract);
handleMeta(DocumentationType::NatspecDev, contract); handleMeta(DocumentationType::NatspecDev, contract);

1
solc/CommandLineInterface.h

@ -58,6 +58,7 @@ private:
void handleBinary(std::string const& _contract); void handleBinary(std::string const& _contract);
void handleOpcode(std::string const& _contract); void handleOpcode(std::string const& _contract);
void handleBytecode(std::string const& _contract); void handleBytecode(std::string const& _contract);
void handleSignatureHashes(std::string const& _contract);
void handleMeta(DocumentationType _type, void handleMeta(DocumentationType _type,
std::string const& _contract); std::string const& _contract);

46
test/libsolidity/SolidityEndToEndTest.cpp

@ -300,6 +300,52 @@ BOOST_AUTO_TEST_CASE(for_loop_simple_init_expr)
testSolidityAgainstCppOnRange("f(uint256)", for_loop_simple_init_expr_cpp, 0, 5); testSolidityAgainstCppOnRange("f(uint256)", for_loop_simple_init_expr_cpp, 0, 5);
} }
BOOST_AUTO_TEST_CASE(for_loop_break_continue)
{
char const* sourceCode = R"(
contract test {
function f(uint n) returns (uint r)
{
uint i = 1;
uint k = 0;
for (i *= 5; k < n; i *= 7)
{
k++;
i += 4;
if (n % 3 == 0)
break;
i += 9;
if (n % 2 == 0)
continue;
i += 19;
}
return i;
}
}
)";
compileAndRun(sourceCode);
auto breakContinue = [](u256 const& n) -> u256
{
u256 i = 1;
u256 k = 0;
for (i *= 5; k < n; i *= 7)
{
k++;
i += 4;
if (n % 3 == 0)
break;
i += 9;
if (n % 2 == 0)
continue;
i += 19;
}
return i;
};
testSolidityAgainstCppOnRange("f(uint256)", breakContinue, 0, 10);
}
BOOST_AUTO_TEST_CASE(calling_other_functions) BOOST_AUTO_TEST_CASE(calling_other_functions)
{ {
char const* sourceCode = "contract collatz {\n" char const* sourceCode = "contract collatz {\n"

Loading…
Cancel
Save