Browse Source

Merge pull request #1797 from arkpar/mix_state

Mix: Bugfixes
cl-refactor
Arkadiy Paronyan 10 years ago
parent
commit
ddd8b192dc
  1. 14
      mix/ClientModel.cpp
  2. 94
      mix/CodeModel.cpp
  3. 20
      mix/CodeModel.h
  4. 2
      mix/qml/StateDialog.qml
  5. 5
      mix/qml/html/codeeditor.js
  6. 3
      mix/qml/js/Debugger.js
  7. 2
      mix/test/qml/js/TestTutorial.js

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();

Loading…
Cancel
Save