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
<< " -r,--remote <host>(:<port>) Connect to remote host (default: none)." << 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
#if ETH_JSONRPC || !ETH_TRUE
<< "Work farming mode:" << endl
@ -521,6 +522,7 @@ int main(int argc, char** argv)
unsigned short remotePort = 30303;
unsigned peers = 5;
bool bootstrap = false;
unsigned networkId = 0;
/// Mining params
unsigned mining = 0;
@ -677,6 +679,15 @@ int main(int argc, char** argv)
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)
try {
benchmarkWarmup = stol(argv[++i]);
@ -1047,6 +1058,7 @@ int main(int argc, char** argv)
c->setForceMining(forceMining);
c->setTurboMining(minerType == MinerType::GPU);
c->setAddress(coinbase);
c->setNetworkId(networkId);
}
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;
}
if (peerCount() > 2 * m_idealPeerCount)
if (peerCount() > 9 * m_idealPeerCount)
{
ps->disconnect(TooManyPeers);
return;
@ -341,7 +341,7 @@ void Host::runAcceptor()
auto socket = make_shared<RLPXSocket>(new bi::tcp::socket(m_ioService));
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();
socket->close();

28
libsolidity/AST.cpp

@ -96,8 +96,8 @@ void ContractDefinition::checkTypeRequirements()
FixedHash<4> const& hash = it.first;
if (hashes.count(hash))
BOOST_THROW_EXCEPTION(createTypeError(
std::string("Function signature hash collision for ") +
it.second->externalSignature()));
string("Function signature hash collision for ") + it.second->externalSignature()
));
hashes.insert(hash);
}
}
@ -140,12 +140,22 @@ void ContractDefinition::checkDuplicateFunctions() const
map<string, vector<FunctionDefinition const*>> functions;
for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
functions[function->getName()].push_back(function.get());
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(
DeclarationError() <<
errinfo_sourceLocation(getLocation()) <<
errinfo_comment("More than one constructor defined.")
errinfo_sourceLocation(functions[getName()].front()->getLocation()) <<
errinfo_comment("More than one constructor defined.") <<
errinfo_secondarySourceLocation(ssl)
);
}
for (auto const& it: functions)
{
vector<FunctionDefinition const*> const& overloads = it.second;
@ -155,7 +165,9 @@ void ContractDefinition::checkDuplicateFunctions() const
BOOST_THROW_EXCEPTION(
DeclarationError() <<
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)
{
set<string> eventsSeen;
m_interfaceEvents.reset(new std::vector<ASTPointer<EventDefinition>>());
m_interfaceEvents.reset(new vector<ASTPointer<EventDefinition>>());
for (ContractDefinition const* contract: getLinearizedBaseContracts())
for (ASTPointer<EventDefinition> const& e: contract->getEvents())
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_overloadedDeclarations.empty(), "No candidates for overload resolution found.");
std::vector<Declaration const*> possibles;
vector<Declaration const*> possibles;
if (m_overloadedDeclarations.size() == 1)
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);
eth::AssemblyItem loopStart = 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);
if (_forStatement.getInitializationExpression())
@ -449,6 +450,8 @@ bool Compiler::visit(ForStatement const& _forStatement)
_forStatement.getBody().accept(*this);
m_context << loopNext;
// for's loop expression if existing
if (_forStatement.getLoopExpression())
_forStatement.getLoopExpression()->accept(*this);

42
libsolidity/DeclarationContainer.cpp

@ -28,6 +28,28 @@ using namespace std;
using namespace dev;
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)
{
ASTString const& name(_declaration.getName());
@ -40,24 +62,8 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration,
m_declarations.erase(name);
m_invisibleDeclarations.erase(name);
}
else
{
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;
}
else if (conflictingDeclaration(_declaration))
return false;
if (_invisible)
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.
*/
class DeclarationContainer
@ -51,6 +51,8 @@ public:
std::set<Declaration const*> resolveName(ASTString const& _name, bool _recursive = false) const;
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }
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:
Declaration const* m_enclosingDeclaration;

16
libsolidity/Exceptions.h

@ -23,6 +23,7 @@
#pragma once
#include <string>
#include <utility>
#include <libdevcore/Exceptions.h>
#include <libevmcore/SourceLocation.h>
@ -38,7 +39,22 @@ struct CompilerError: virtual Exception {};
struct InternalCompilerError: 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_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)
{
if (!m_scopes[m_currentScope].registerDeclaration(_declaration, !_declaration.isVisibleInContract()))
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_declaration.getLocation())
<< errinfo_comment("Identifier already declared."));
//@todo the exception should also contain the location of the first declaration
{
SourceLocation firstDeclarationLocation;
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);
if (_opensScope)
enterNewSubScope(_declaration);
@ -435,8 +459,11 @@ bool ReferencesResolver::visit(Identifier& _identifier)
{
auto declarations = m_resolver.getNameFromCurrentScope(_identifier.getName());
if (declarations.empty())
BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_sourceLocation(_identifier.getLocation())
<< errinfo_comment("Undeclared identifier."));
BOOST_THROW_EXCEPTION(
DeclarationError() <<
errinfo_sourceLocation(_identifier.getLocation()) <<
errinfo_comment("Undeclared identifier.")
);
else if (declarations.size() == 1)
_identifier.setReferencedDeclaration(**declarations.begin(), m_currentContract);
else

74
libsolidity/SourceReferenceFormatter.cpp

@ -32,9 +32,11 @@ namespace dev
namespace solidity
{
void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
SourceLocation const& _location,
Scanner const& _scanner)
void SourceReferenceFormatter::printSourceLocation(
ostream& _stream,
SourceLocation const& _location,
Scanner const& _scanner
)
{
int startLine;
int startColumn;
@ -46,11 +48,11 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
{
string line = _scanner.getLineAtPosition(_location.start);
_stream << line << endl;
std::for_each(line.cbegin(), line.cbegin() + startColumn,
[&_stream](char const& ch)
{
_stream << (ch == '\t' ? '\t' : ' ');
});
for_each(
line.cbegin(),
line.cbegin() + startColumn,
[&_stream](char const& ch) { _stream << (ch == '\t' ? '\t' : ' '); }
);
_stream << "^";
if (endColumn > startColumn + 2)
_stream << string(endColumn - startColumn - 2, '-');
@ -59,33 +61,65 @@ void SourceReferenceFormatter::printSourceLocation(ostream& _stream,
_stream << endl;
}
else
_stream << _scanner.getLineAtPosition(_location.start) << endl
<< string(startColumn, ' ') << "^\n"
<< "Spanning multiple lines.\n";
_stream <<
_scanner.getLineAtPosition(_location.start) <<
endl <<
string(startColumn, ' ') <<
"^\n" <<
"Spanning multiple lines.\n";
}
void SourceReferenceFormatter::printExceptionInformation(ostream& _stream,
Exception const& _exception,
string const& _name,
CompilerStack const& _compiler)
void SourceReferenceFormatter::printSourceName(
ostream& _stream,
SourceLocation const& _location,
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);
Scanner const* scanner;
auto secondarylocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
Scanner const* scanner = nullptr;
if (location)
{
scanner = &_compiler.getScanner(*location->sourceName);
int startLine;
int startColumn;
tie(startLine, startColumn) = scanner->translatePositionToLineColumn(location->start);
_stream << *location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
printSourceName(_stream, *location, *scanner);
}
_stream << _name;
if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
_stream << ": " << *description << endl;
if (location)
{
scanner = &_compiler.getScanner(*location->sourceName);
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:
static void printSourceLocation(std::ostream& _stream, SourceLocation const& _location, Scanner const& _scanner);
static void printExceptionInformation(std::ostream& _stream, Exception const& _exception,
std::string const& _name, CompilerStack const& _compiler);
static void printExceptionInformation(
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
const unsigned dev::SensibleHttpThreads = 4;
#endif
const unsigned dev::SensibleHttpPort = 8080;
const unsigned dev::SensibleHttpPort = 8545;
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
auto nameIter = m_contractNames.find(code.address);
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();
codes.back()->setDocument(compilerRes->documentId());
@ -467,9 +467,9 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
{
//track calls into functions
AssemblyItem const& prevInstruction = codeItems[s.codeIndex][prevInstructionIndex];
auto functionIter = contract->functions().find(LocationPair(instruction.getLocation().start, instruction.getLocation().end));
if (functionIter != contract->functions().end() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty()))
solCallStack.push_front(QVariant::fromValue(functionIter.value()));
QString functionName = m_codeModel->resolveFunctionName(instruction.getLocation());
if (!functionName.isEmpty() && ((prevInstruction.getJumpType() == AssemblyItem::JumpType::IntoFunction) || solCallStack.empty()))
solCallStack.push_front(QVariant::fromValue(functionName));
else if (prevInstruction.getJumpType() == AssemblyItem::JumpType::OutOfFunction && !solCallStack.empty())
solCallStack.pop_front();
}
@ -521,11 +521,13 @@ void ClientModel::showDebuggerForTransaction(ExecutionResult const& _t)
prevInstructionIndex = instructionIndex;
// filter out locations that match whole function or contract
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);
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)));

94
mix/CodeModel.cpp

@ -51,30 +51,31 @@ const std::set<std::string> c_predefinedContracts =
namespace
{
using namespace dev::solidity;
class CollectDeclarationsVisitor: public ASTConstVisitor
class CollectLocalsVisitor: public ASTConstVisitor
{
public:
CollectDeclarationsVisitor(QHash<LocationPair, QString>* _functions, QHash<LocationPair, SolidityDeclaration>* _locals):
m_functions(_functions), m_locals(_locals), m_functionScope(false) {}
CollectLocalsVisitor(QHash<LocationPair, SolidityDeclaration>* _locals):
m_locals(_locals), m_functionScope(false) {}
private:
LocationPair nodeLocation(ASTNode const& _node)
{
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;
return true;
}
virtual void endVisit(FunctionDefinition const&)
virtual void endVisit(FunctionDefinition const&) override
{
m_functionScope = false;
}
virtual bool visit(VariableDeclaration const& _node)
virtual bool visit(VariableDeclaration const& _node) override
{
SolidityDeclaration decl;
decl.type = CodeModel::nodeType(_node.getType().get());
@ -87,11 +88,38 @@ private:
}
private:
QHash<LocationPair, QString>* m_functions;
QHash<LocationPair, SolidityDeclaration>* m_locals;
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> result;
@ -132,7 +160,7 @@ CompiledContract::CompiledContract(const dev::solidity::CompilerStack& _compiler
if (contractDefinition.getLocation().sourceName.get())
m_documentId = QString::fromStdString(*contractDefinition.getLocation().sourceName);
CollectDeclarationsVisitor visitor(&m_functions, &m_locals);
CollectLocalsVisitor visitor(&m_locals);
m_storage = collectStorage(contractDefinition);
contractDefinition.accept(visitor);
m_assemblyItems = *_compiler.getRuntimeAssemblyItems(name);
@ -243,6 +271,7 @@ void CodeModel::releaseContracts()
for (ContractMap::iterator c = m_contractMap.begin(); c != m_contractMap.end(); ++c)
c.value()->deleteLater();
m_contractMap.clear();
m_sourceMaps.clear();
}
void CodeModel::runCompilationJob(int _jobId)
@ -253,13 +282,17 @@ void CodeModel::runCompilationJob(int _jobId)
try
{
cs.addSource("configUser", R"(contract configUser{function configAddr()constant returns(address a){ return 0xf025d81196b72fba60a1d4dddad12eeb8360d828;}})");
std::vector<std::string> sourceNames;
{
Guard l(x_pendingContracts);
for (auto const& c: m_pendingContracts)
{
cs.addSource(c.first.toStdString(), c.second.toStdString());
sourceNames.push_back(c.first.toStdString());
}
}
cs.compile(false);
collectContracts(cs);
collectContracts(cs, sourceNames);
}
catch (dev::Exception const& _exception)
{
@ -281,11 +314,20 @@ void CodeModel::runCompilationJob(int _jobId)
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 l(x_contractMap);
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())
{
if (c_predefinedContracts.count(n) != 0)
@ -326,6 +368,7 @@ void CodeModel::collectContracts(dev::solidity::CompilerStack const& _cs)
}
releaseContracts();
m_contractMap.swap(result);
m_sourceMaps.swap(sourceMaps);
emit codeChanged();
emit compilationComplete();
}
@ -431,3 +474,32 @@ SolidityType CodeModel::nodeType(dev::solidity::Type const* _type)
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
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<unsigned, SolidityDeclarations> const& storage() const { return m_storage; }
@ -110,7 +109,6 @@ private:
QString m_documentId;
eth::AssemblyItems m_assemblyItems;
eth::AssemblyItems m_constructorAssemblyItems;
QHash<LocationPair, QString> m_functions;
QHash<LocationPair, SolidityDeclaration> m_locals;
QHash<unsigned, SolidityDeclarations> m_storage;
@ -119,6 +117,17 @@ private:
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
class CodeModel: public QObject
{
@ -153,6 +162,10 @@ public:
Q_INVOKABLE void reset() { reset(QVariantMap()); }
/// Convert solidity type info to mix 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:
/// Emited on compilation state change
@ -182,11 +195,12 @@ private:
void runCompilationJob(int _jobId);
void stop();
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;
mutable dev::Mutex x_contractMap;
ContractMap m_contractMap;
SourceMaps m_sourceMaps;
std::unique_ptr<CodeHighlighterSettings> m_codeHighlighterSettings;
QThread m_backgroundThread;
BackgroundWorker m_backgroundWorker;

2
mix/qml/StateDialog.qml

@ -158,7 +158,7 @@ Dialog {
id: importJsonFileDialog
visible: false
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: {
var path = importJsonFileDialog.fileUrl.toString()
var jsonData = fileIo.readFile(path)

5
mix/qml/html/codeeditor.js

@ -126,7 +126,10 @@ highlightExecution = function(start, end) {
executionMark.clear();
if (debugWarning)
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;

3
mix/qml/js/Debugger.js

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

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

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

45
solc/CommandLineInterface.cpp

@ -51,19 +51,18 @@ namespace dev
namespace solidity
{
// LTODO: Maybe some argument class pairing names with
// extensions and other attributes would be a better choice here?
static string const g_argAbiStr = "json-abi";
static string const g_argSolAbiStr = "sol-abi";
static string const g_argAsmStr = "asm";
static string const g_argAsmJsonStr = "asm-json";
static string const g_argAstStr = "ast";
static string const g_argAstJson = "ast-json";
static string const g_argBinaryStr = "binary";
static string const g_argOpcodesStr = "opcodes";
static string const g_argNatspecDevStr = "natspec-dev";
static string const g_argAbiStr = "json-abi";
static string const g_argSolAbiStr = "sol-abi";
static string const g_argSignatureHashes = "hashes";
static string const g_argAsmStr = "asm";
static string const g_argAsmJsonStr = "asm-json";
static string const g_argAstStr = "ast";
static string const g_argAstJson = "ast-json";
static string const g_argBinaryStr = "binary";
static string const g_argOpcodesStr = "opcodes";
static string const g_argNatspecDevStr = "natspec-dev";
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
static set<string> const g_combinedJsonArgs{
@ -96,6 +95,7 @@ static bool needsHumanTargetedStdout(po::variables_map const& _args)
return
humanTargetedStdout(_args, g_argAbiStr) ||
humanTargetedStdout(_args, g_argSolAbiStr) ||
humanTargetedStdout(_args, g_argSignatureHashes) ||
humanTargetedStdout(_args, g_argNatspecUserStr) ||
humanTargetedStdout(_args, g_argAstJson) ||
humanTargetedStdout(_args, g_argNatspecDevStr) ||
@ -173,6 +173,24 @@ void CommandLineInterface::handleBytecode(string const& _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)
{
std::string argName;
@ -254,6 +272,8 @@ bool CommandLineInterface::parseArguments(int argc, char** argv)
"Request to output the contract's JSON ABI interface.")
(g_argSolAbiStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
"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"),
"Request to output the contract's Natspec user documentation.")
(g_argNatspecDevStr.c_str(), po::value<OutputType>()->value_name("stdout|file|both"),
@ -516,6 +536,7 @@ void CommandLineInterface::actOnInput()
}
handleBytecode(contract);
handleSignatureHashes(contract);
handleMeta(DocumentationType::ABIInterface, contract);
handleMeta(DocumentationType::ABISolidityInterface, contract);
handleMeta(DocumentationType::NatspecDev, contract);

1
solc/CommandLineInterface.h

@ -58,6 +58,7 @@ private:
void handleBinary(std::string const& _contract);
void handleOpcode(std::string const& _contract);
void handleBytecode(std::string const& _contract);
void handleSignatureHashes(std::string const& _contract);
void handleMeta(DocumentationType _type,
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);
}
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)
{
char const* sourceCode = "contract collatz {\n"

Loading…
Cancel
Save