diff --git a/eth/main.cpp b/eth/main.cpp index d4ad08529..985e74e59 100644 --- a/eth/main.cpp +++ b/eth/main.cpp @@ -146,6 +146,7 @@ void help() << " --listen Listen on the given port for incoming connections (default: 30303)." << endl << " -r,--remote (:) Connect to remote host (default: none)." << endl << " --port Connect to remote port (default: 30303)." << endl + << " --network-id Only connect to other hosts with this network id (default:0)." << endl << " --upnp Use UPnP for NAT (default: on)." << endl #if ETH_JSONRPC || !ETH_TRUE << "Work farming mode:" << endl @@ -515,6 +516,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; @@ -668,6 +670,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]); @@ -1034,6 +1045,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; diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 09f98dca3..2f98ce4f6 100644 --- a/libsolidity/AST.cpp +++ b/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> functions; for (ASTPointer 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 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> const& ContractDefinition::getInterfaceEvents() const +vector> const& ContractDefinition::getInterfaceEvents() const { if (!m_interfaceEvents) { set eventsSeen; - m_interfaceEvents.reset(new std::vector>()); + m_interfaceEvents.reset(new vector>()); for (ContractDefinition const* contract: getLinearizedBaseContracts()) for (ASTPointer 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 possibles; + vector possibles; if (m_overloadedDeclarations.size() == 1) m_referencedDeclaration = *m_overloadedDeclarations.begin(); diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index 2130f3a01..c836663c7 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/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 declarations; + if (m_declarations.count(name)) + declarations += m_declarations.at(name); + if (m_invisibleDeclarations.count(name)) + declarations += m_invisibleDeclarations.at(name); + if (dynamic_cast(&_declaration)) + { + // check that all other declarations with the same name are functions + for (Declaration const* declaration: declarations) + if (!dynamic_cast(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 declarations; - if (m_declarations.count(name)) - declarations += m_declarations.at(name); - if (m_invisibleDeclarations.count(name)) - declarations += m_invisibleDeclarations.at(name); - if (dynamic_cast(&_declaration)) - { - // check that all other declarations with the same name are functions - - for (Declaration const* declaration: declarations) - if (!dynamic_cast(declaration)) - return false; - } - else if (!declarations.empty()) - return false; - } + else if (conflictingDeclaration(_declaration)) + return false; if (_invisible) m_invisibleDeclarations[name].insert(&_declaration); diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index 35a6ea077..94545eefb 100644 --- a/libsolidity/DeclarationContainer.h +++ b/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 resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } std::map> 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; diff --git a/libsolidity/Exceptions.h b/libsolidity/Exceptions.h index 0d07c7064..a0031ba7e 100644 --- a/libsolidity/Exceptions.h +++ b/libsolidity/Exceptions.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include @@ -38,7 +39,22 @@ struct CompilerError: virtual Exception {}; struct InternalCompilerError: virtual Exception {}; struct DocstringParsingError: virtual Exception {}; +using errorSourceLocationInfo = std::pair; + +class SecondarySourceLocation +{ +public: + SecondarySourceLocation& append(std::string const& _errMsg, SourceLocation const& _sourceLocation) + { + infos.push_back(std::make_pair(_errMsg, _sourceLocation)); + return *this; + } + + std::vector infos; +}; + using errinfo_sourceLocation = boost::error_info; +using errinfo_secondarySourceLocation = boost::error_info; } } diff --git a/libsolidity/NameAndTypeResolver.cpp b/libsolidity/NameAndTypeResolver.cpp index a286934a9..9aebbf054 100644 --- a/libsolidity/NameAndTypeResolver.cpp +++ b/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 diff --git a/libsolidity/SourceReferenceFormatter.cpp b/libsolidity/SourceReferenceFormatter.cpp index b5e83b8c9..77805efc8 100644 --- a/libsolidity/SourceReferenceFormatter.cpp +++ b/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(_exception); - Scanner const* scanner; + auto secondarylocation = boost::get_error_info(_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(_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; + } } } diff --git a/libsolidity/SourceReferenceFormatter.h b/libsolidity/SourceReferenceFormatter.h index 304e6a273..ed2564f31 100644 --- a/libsolidity/SourceReferenceFormatter.h +++ b/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); }; } diff --git a/mix/ClientModel.cpp b/mix/ClientModel.cpp index 61a3dee1f..717757c70 100644 --- a/mix/ClientModel.cpp +++ b/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))); diff --git a/mix/CodeModel.cpp b/mix/CodeModel.cpp index 357ce88b9..515123de5 100644 --- a/mix/CodeModel.cpp +++ b/mix/CodeModel.cpp @@ -51,30 +51,31 @@ const std::set c_predefinedContracts = namespace { using namespace dev::solidity; -class CollectDeclarationsVisitor: public ASTConstVisitor + +class CollectLocalsVisitor: public ASTConstVisitor { public: - CollectDeclarationsVisitor(QHash* _functions, QHash* _locals): - m_functions(_functions), m_locals(_locals), m_functionScope(false) {} + CollectLocalsVisitor(QHash* _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* m_functions; QHash* 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 collectStorage(dev::solidity::ContractDefinition const& _contract) { QHash 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 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 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(); +} diff --git a/mix/CodeModel.h b/mix/CodeModel.h index 0572483c0..3c6c3abdf 100644 --- a/mix/CodeModel.h +++ b/mix/CodeModel.h @@ -97,7 +97,6 @@ public: /// @returns contract source Id QString documentId() const { return m_documentId; } - QHash const& functions() const { return m_functions; } QHash const& locals() const { return m_locals; } QHash const& storage() const { return m_storage; } @@ -110,7 +109,6 @@ private: QString m_documentId; eth::AssemblyItems m_assemblyItems; eth::AssemblyItems m_constructorAssemblyItems; - QHash m_functions; QHash m_locals; QHash m_storage; @@ -119,6 +117,17 @@ private: using ContractMap = QMap; //needs to be sorted +/// Source map +using LocationMap = QHash; + +struct SourceMap +{ + LocationMap contracts; + LocationMap functions; +}; + +using SourceMaps = QMap; //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 const& _sourceNames); std::atomic m_compiling; mutable dev::Mutex x_contractMap; ContractMap m_contractMap; + SourceMaps m_sourceMaps; std::unique_ptr m_codeHighlighterSettings; QThread m_backgroundThread; BackgroundWorker m_backgroundWorker; diff --git a/mix/qml/StateDialog.qml b/mix/qml/StateDialog.qml index 3a3a060c3..13d01d474 100644 --- a/mix/qml/StateDialog.qml +++ b/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) diff --git a/mix/qml/html/codeeditor.js b/mix/qml/html/codeeditor.js index e8504fee0..d25fbd091 100644 --- a/mix/qml/html/codeeditor.js +++ b/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; diff --git a/mix/qml/js/Debugger.js b/mix/qml/js/Debugger.js index 3f5742fde..f6900489a 100644 --- a/mix/qml/js/Debugger.js +++ b/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); } diff --git a/mix/test/qml/js/TestTutorial.js b/mix/test/qml/js/TestTutorial.js index 7f366f23b..895b5c9c1 100644 --- a/mix/test/qml/js/TestTutorial.js +++ b/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(); diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index d5ff7b297..0d5f47242 100644 --- a/solc/CommandLineInterface.cpp +++ b/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 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(); + 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()->value_name("stdout|file|both"), "Request to output the contract's Solidity ABI interface.") + (g_argSignatureHashes.c_str(), po::value()->value_name("stdout|file|both"), + "Request to output the contract's functions' signature hashes.") (g_argNatspecUserStr.c_str(), po::value()->value_name("stdout|file|both"), "Request to output the contract's Natspec user documentation.") (g_argNatspecDevStr.c_str(), po::value()->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); diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 459f17d3e..7d3a067cd 100644 --- a/solc/CommandLineInterface.h +++ b/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);