pull/5370/head
filip mertens 2 years ago
parent 6e5fbed622
commit 0e2def1a6f
  1. 4
      apps/remix-ide-e2e/src/commands/executeScriptInTerminal.ts
  2. 8
      apps/remix-ide-e2e/src/tests/compiler_api.test.ts
  3. 4
      apps/remix-ide-e2e/src/tests/debugger.test.ts
  4. 2
      apps/remix-ide-e2e/src/tests/defaultLayout.test.ts
  5. 151
      apps/remix-ide-e2e/src/tests/editor.test.ts
  6. 17
      apps/remix-ide-e2e/src/tests/editorAutoComplete.test.ts
  7. 171
      apps/remix-ide-e2e/src/tests/editorHoverContext.test.ts
  8. 24
      apps/remix-ide-e2e/src/tests/fileManager_api.test.ts
  9. 4
      apps/remix-ide-e2e/src/tests/gist.test.ts
  10. 2
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  11. 2
      apps/remix-ide-e2e/src/tests/remixd.test.ts
  12. 6
      apps/remix-ide-e2e/src/tests/runAndDeploy.test.ts
  13. 4
      apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts
  14. 22
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  15. 2
      apps/remix-ide-e2e/src/tests/url.test.ts
  16. 2
      apps/remix-ide-e2e/src/types/index.d.ts
  17. 153
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  18. 10
      apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts
  19. 12
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  20. 8
      libs/remix-analyzer/src/types.ts
  21. 2
      libs/remix-astwalker/src/astWalker.ts
  22. 0
      libs/remix-ui/editor/src/lib/providers/completion/dotCompletions.ts
  23. 13
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  24. 4
      libs/remix-ui/editor/src/lib/providers/hoverProvider.ts
  25. 4
      package.json
  26. 857
      yarn.lock

@ -1,7 +1,7 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'
class ExecuteScript extends EventEmitter {
class ExecuteScriptInTerminal extends EventEmitter {
command (this: NightwatchBrowser, script: string): NightwatchBrowser {
this.api
.clearEditableContent('*[data-id="terminalCliInput"]')
@ -17,4 +17,4 @@ class ExecuteScript extends EventEmitter {
}
}
module.exports = ExecuteScript
module.exports = ExecuteScriptInTerminal

@ -21,7 +21,7 @@ module.exports = {
'Should compile using "compileWithParamaters" API #group1': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompile.js', { content: jsCompile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '"languageversion":"0.6.8+commit.0bbfe453"', 60000)
.click('*[data-id="terminalClearConsole"]')
},
@ -29,7 +29,7 @@ module.exports = {
'Should compile using "compileWithParamaters" API with optimization On #group2': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompileWithOptimization.js', { content: jsCompileWithOptimization })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '\\"optimizer\\":{\\"enabled\\":true,\\"runs\\":300}', 60000)
.click('*[data-id="terminalClearConsole"]')
},
@ -37,7 +37,7 @@ module.exports = {
'Should compile using "compileWithParamaters" API with optimization off check default runs #group3': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsCompileWithOptimizationDefault.js', { content: jsCompileWithOptimizationDefault })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '\\"optimizer\\":{\\"enabled\\":false,\\"runs\\":200}', 60000)
.click('*[data-id="terminalClearConsole"]')
},
@ -45,7 +45,7 @@ module.exports = {
'Should update the compiler configuration with "setCompilerConfig" API #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_updateConfiguration.js', { content: updateConfiguration })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(15000)
.addFile('test_updateConfiguration.sol', { content: simpleContract })
.verifyContracts(['StorageTestUpdateConfiguration'], { wait: 5000, version: '0.6.8+commit.0bbfe453' })

@ -192,7 +192,7 @@ module.exports = {
'Should call the debugger api: getTrace #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsGetTrace.js', { content: jsGetTrace })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(3000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '{"gas":"0x575f","return":"0x0000000000000000000000000000000000000000000000000000000000000000","structLogs":', 60000)
},
@ -200,7 +200,7 @@ module.exports = {
'Should call the debugger api: debug #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsDebug.js', { content: jsDebug })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(3000)
.clickLaunchIcon('debugger')
.waitForElementVisible('*[data-id="slider"]')

@ -42,7 +42,7 @@ module.exports = {
browser.waitForElementVisible('div[data-id="remixIdeSidePanel"]')
.assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER')
.clickLaunchIcon('filePanel')
.assert.hidden('div[data-id="remixIdeSidePanel"]')
.assert.not.visible('div[data-id="remixIdeSidePanel"]')
.clickLaunchIcon('filePanel')
.assert.visible('div[data-id="remixIdeSidePanel"]')
.assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORER')

@ -89,7 +89,7 @@ module.exports = {
.addFile('sourcehighlight.js', sourcehighlightScript)
.addFile('removeAllSourcehighlightScript.js', removeAllSourcehighlightScript)
.openFile('sourcehighlight.js')
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.scrollToLine(32)
.waitForElementPresent('.highlightLine33', 60000)
.checkElementStyle('.highlightLine33', 'background-color', 'rgb(52, 152, 219)')
@ -105,7 +105,7 @@ module.exports = {
browser.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]')
.click('li[data-id="treeViewLitreeViewItemremoveSourcehighlightScript.js"]')
.pause(2000)
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts"]')
.click('li[data-id="treeViewLitreeViewItemcontracts"]')
.waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]')
@ -119,7 +119,7 @@ module.exports = {
browser.waitForElementVisible('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]')
.click('li[data-id="treeViewLitreeViewItemremoveAllSourcehighlightScript.js"]')
.pause(2000)
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementVisible('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]')
.click('li[data-id="treeViewLitreeViewItemcontracts/3_Ballot.sol"]')
.pause(2000)
@ -234,149 +234,4 @@ contract Storage {
}
}`
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const BallotWithARefToOwner = `
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "./2_Owner.sol";
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract Ballot {
Owner c;
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
struct Proposal {
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
/**
* @dev Create a new ballot to choose one of 'proposalNames'.
* @param proposalNames names of proposals
*/
constructor(bytes32[] memory proposalNames) {
c = new Owner();
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
// 'Proposal({...})' creates a temporary
// Proposal object and 'proposals.push(...)'
// appends it to the end of 'proposals'.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
/**
* @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
* @param voter address of voter
*/
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/**
* @dev Delegate your vote to the voter 'to'.
* @param to address to which vote is delegated
*/
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
/**
* @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.
* @param proposal index of proposal in the proposals array
*/
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If 'proposal' is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/**
* @dev Computes the winning proposal taking all previous votes into account.
* @return winningProposal_ index of winning proposal in the proposals array
*/
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
/**
* @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
* @return winnerName_ the name of the winner
*/
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
`

@ -0,0 +1,17 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', false)
},
'Should show hover over contract in editor #group1': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]')
.clickLaunchIcon('filePanel')
.waitForElementVisible('div[data-id="filePanelFileExplorerTree"]')
.openFile('contracts')
.openFile('contracts/1_Storage.sol')
.waitForElementVisible('#editorView')
}
}

@ -0,0 +1,171 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080', false)
},
'Should show hover over contract in editor #group1': function (browser: NightwatchBrowser) {
browser.openFile('contracts')
.openFile('contracts/3_Ballot.sol')
.waitForElementVisible('#editorView')
.setEditorValue(BallotWithARefToOwner)
.useXpath()
.waitForElementVisible("//*[contains(text(),'BallotHoverTest')]")
.click("//*[contains(text(),'BallotHoverTest')]")
.moveToElement("//*[contains(text(),'BallotHoverTest')]", 0, 0)
.useCss()
.waitForElementContainsText('.monaco-hover-content', 'contract BallotHoverTest is BallotHoverTest')
.waitForElementContainsText('.monaco-hover-content', 'contracts/3_Ballot.sol 10:0')
.waitForElementContainsText('.monaco-hover-content', '@title Ballot')
const elements = browser.findElements('.view-line')
elements.forEach(item => console.log('Element Id:', item.getText()));
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const BallotWithARefToOwner = `// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "./2_Owner.sol";
/**
* @title Ballot
* @dev Implements voting process along with vote delegation
*/
contract BallotHoverTest {
Owner c;
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
struct Proposal {
// If you can limit the length to a certain number of bytes,
// always use one of bytes1 to bytes32 because they are much cheaper
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
/**
* @dev Create a new ballot to choose one of 'proposalNames'.
* @param proposalNames names of proposals
*/
constructor(bytes32[] memory proposalNames) {
c = new Owner();
chairperson = msg.sender;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
// 'Proposal({...})' creates a temporary
// Proposal object and 'proposals.push(...)'
// appends it to the end of 'proposals'.
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
/**
* @dev Give 'voter' the right to vote on this ballot. May only be called by 'chairperson'.
* @param voter address of voter
*/
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
/**
* @dev Delegate your vote to the voter 'to'.
* @param to address to which vote is delegated
*/
function delegate(address to) public {
Voter storage sender = voters[msg.sender];
require(!sender.voted, "You already voted.");
require(to != msg.sender, "Self-delegation is disallowed.");
while (voters[to].delegate != address(0)) {
to = voters[to].delegate;
// We found a loop in the delegation, not allowed.
require(to != msg.sender, "Found loop in delegation.");
}
sender.voted = true;
sender.delegate = to;
Voter storage delegate_ = voters[to];
if (delegate_.voted) {
// If the delegate already voted,
// directly add to the number of votes
proposals[delegate_.vote].voteCount += sender.weight;
} else {
// If the delegate did not vote yet,
// add to her weight.
delegate_.weight += sender.weight;
}
}
/**
* @dev Give your vote (including votes delegated to you) to proposal 'proposals[proposal].name'.
* @param proposal index of proposal in the proposals array
*/
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
// If 'proposal' is out of the range of the array,
// this will throw automatically and revert all
// changes.
proposals[proposal].voteCount += sender.weight;
}
/**
* @dev Computes the winning proposal taking all previous votes into account.
* @return winningProposal_ index of winning proposal in the proposals array
*/
function winningProposal() public view
returns (uint winningProposal_)
{
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
}
}
}
/**
* @dev Calls winningProposal() function to get the index of the winner contained in the proposals array and then
* @return winnerName_ the name of the winner
*/
function winnerName() public view
returns (bytes32 winnerName_)
{
winnerName_ = proposals[winningProposal()].name;
}
}
`

@ -11,7 +11,7 @@ module.exports = {
'Should execute `file` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('file.js', { content: executeFile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'file.js', 60000)
},
@ -19,7 +19,7 @@ module.exports = {
'Should execute `exists` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('exists.js', { content: executeExists })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'exists.js true', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'non-exists.js false', 60000)
},
@ -27,14 +27,14 @@ module.exports = {
'Should execute `open` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('open.js', { content: executeOpen })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contracts/3_Ballot.sol', 60000)
},
'Should execute `writeFile` api from file manager external api #group1': function (browser: NightwatchBrowser) {
browser
.addFile('writeFile.js', { content: executeWriteFile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(2000)
.openFile('new_contract.sol')
.getEditorValue((content) => {
@ -45,23 +45,23 @@ module.exports = {
'Should execute `readFile` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('writeFile.js', { content: executeWriteFile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.addFile('readFile.js', { content: executeReadFile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'pragma solidity ^0.6.0', 60000)
},
'Should execute `copyFile` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('copyFile.js', { content: executeCopyFile })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'pragma solidity >=0.7.0 <0.9.0;', 60000)
},
'Should execute `rename` api from file manager external api #group2': function (browser: NightwatchBrowser) {
browser
.addFile('renameFile.js', { content: executeRename })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(2000)
.waitForElementPresent('[data-id="treeViewLitreeViewItemold_contract.sol"]', 60000)
},
@ -69,7 +69,7 @@ module.exports = {
'Should execute `mkdir` api from file manager external api #group3': function (browser: NightwatchBrowser) {
browser
.addFile('mkdirFile.js', { content: executeMkdir })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(2000)
.waitForElementPresent('[data-id="treeViewLitreeViewItemTest_Folder"]', 80000)
},
@ -77,7 +77,7 @@ module.exports = {
'Should execute `readdir` api from file manager external api #group3': function (browser: NightwatchBrowser) {
browser
.addFile('readdirFile.js', { content: executeReaddir })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Test_Folder isDirectory', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'true', 5000)
},
@ -86,7 +86,7 @@ module.exports = {
browser
.addFile('old_contract.sol', { content: 'test' })
.addFile('removeFile.js', { content: executeRemove })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(2000)
.waitForElementNotPresent('[data-id="treeViewLitreeViewItemold_contract.sol"]', 60000)
},
@ -95,7 +95,7 @@ module.exports = {
'Should execute `remove` api from file manager external api on a folder #group4': function (browser: NightwatchBrowser) {
browser
.addFile('test_jsRemoveFolder.js', { content: executeRemoveOnFolder })
.executeScript('remix.exeCurrent()')
.ExecuteScriptInTerminal('remix.exeCurrent()')
.pause(2000)
.waitForElementNotPresent('[data-id="treeViewLitreeViewItemcontracts"]', 60000)
.end()

@ -34,7 +34,7 @@ module.exports = {
.sendKeys('*[data-id$="/blank"] .remixui_items', browser.Keys.ENTER)
.waitForElementVisible('*[data-id="treeViewLitreeViewItemBrowser_Tests"]')
.addFile('File.sol', { content: '' })
.executeScript(`remix.loadgist('${gistid}')`)
.ExecuteScriptInTerminal(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)
.click(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)
@ -58,7 +58,7 @@ module.exports = {
const gistid = id[1]
browser
.click('[data-id="default_workspace-modal-footer-cancel-react"]')
.executeScript(`remix.loadgist('${gistid}')`)
.ExecuteScriptInTerminal(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)
.click(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)

@ -417,7 +417,7 @@ module.exports = {
.frameParent()
.useCss()
.addFile('test_modal.js', { content: testModalToasterApi })
.executeScript('remix.execute(\'test_modal.js\')')
.ExecuteScriptInTerminal('remix.execute(\'test_modal.js\')')
.useCss()
.waitForElementVisible('*[data-id="test_id_1_ModalDialogModalBody-react"]', 60000)
.assert.containsText('*[data-id="test_id_1_ModalDialogModalBody-react"]', 'message 1')

@ -102,7 +102,7 @@ module.exports = {
'Run git status': '' + function (browser) {
browser
.executeScript('git status')
.ExecuteScriptInTerminal('git status')
.pause(3000)
.journalLastChildIncludes('On branch ')
},

@ -39,8 +39,8 @@ module.exports = {
.waitForElementVisible('*[data-id="signMessageTextarea"]', 120000)
.click('*[data-id="signMessageTextarea"]')
.setValue('*[data-id="signMessageTextarea"]', 'Remix is cool!')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.elementNotPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.assert.not.elementPresent('*[data-id="settingsRemixRunSignMsgHash"]')
.assert.not.elementPresent('*[data-id="settingsRemixRunSignMsgSignature"]')
.pause(2000)
.waitForElementPresent('[data-id="udappNotify-modal-footer-ok-react"]')
.click('[data-id="udappNotify-modal-footer-ok-react"]')
@ -200,7 +200,7 @@ module.exports = {
'Call web3.eth.getAccounts() using Injected Provider (Metamask)': '' + function (browser: NightwatchBrowser) {
browser
.executeScript('web3.eth.getAccounts()')
.ExecuteScriptInTerminal('web3.eth.getAccounts()')
.pause(2000)
.journalLastChildIncludes('[ "0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f" ]')
.end()

@ -42,7 +42,7 @@ module.exports = {
.waitForElementPresent('#staticanalysisresult .warning', 5000)
.assert.containsText('#verticalIconsKindsolidityStaticAnalysis .remixui_status', '1') // Check warning count
.verify.elementPresent('input[name="showLibWarnings"]')
.verify.elementNotPresent('input[name="showLibWarnings"]:checked')
.verify.not.elementPresent('input[name="showLibWarnings"]:checked')
.verify.elementPresent('label[id="headingshowLibWarnings"]')
.click('label[id="headingshowLibWarnings"]')
.pause(1000)
@ -62,7 +62,7 @@ function runTests (browser: NightwatchBrowser) {
.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['TooMuchGas', 'test1', 'test2'])
.clickLaunchIcon('solidityStaticAnalysis')
.click('#staticanalysisButton button')
.waitForElementPresent('#staticanalysisresult .warning', 2000, true, function () {
.waitForElementPresent('#staticanalysisresult .warning', 2000, 500, true, function () {
listSelectorContains(['Use of tx.origin',
'Fallback function of contract TooMuchGas requires too much gas',
'TooMuchGas.() : Variables have very similar names "test" and "test1".',

@ -11,7 +11,7 @@ module.exports = {
'Should execution a simple console command #group1 #group999': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]', 10000)
.executeScript('console.log(1 + 1)')
.ExecuteScriptInTerminal('console.log(1 + 1)')
.pause(2000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '2', 60000)
},
@ -27,7 +27,7 @@ module.exports = {
'Async/Await Script #group1': function (browser: NightwatchBrowser) {
browser
.addFile('asyncAwait.js', { content: asyncAwait })
.executeScript('remix.execute("asyncAwait.js")')
.ExecuteScriptInTerminal('remix.execute("asyncAwait.js")')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Waiting Promise', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'result - ', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Promise Resolved', 60000)
@ -36,13 +36,13 @@ module.exports = {
'Call Remix File Manager from a script #group2': function (browser: NightwatchBrowser) {
browser
.addFile('asyncAwaitWithFileManagerAccess.js', { content: asyncAwaitWithFileManagerAccess })
.executeScript('remix.execute(\'asyncAwaitWithFileManagerAccess.js\')')
.ExecuteScriptInTerminal('remix.execute(\'asyncAwaitWithFileManagerAccess.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contract Ballot {', 60000)
},
'Call web3.eth.getAccounts() using Remix VM #group2': function (browser: NightwatchBrowser) {
browser
.executeScript('web3.eth.getAccounts()')
.ExecuteScriptInTerminal('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '["0x5B38Da6a701c568545dCfcB03FcB875f56beddC4","0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2","0x4B20993Bc481177ec7E8f571ceCaE8A9e22C02db","0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB","0x617F2E2fD72FD9D5503197092aC168c91465E7f2","0x17F6AD8Ef982297579C203069C1DbfFE4348c372","0x5c6B0f7Bf3E7ce046039Bd8FABdfD3f9F5021678","0x03C6FcED478cBbC9a4FAB34eF9f40767739D1Ff7","0x1aE0EA34a72D944a8C7603FfB3eC30a6669E454C","0x0A098Eda01Ce92ff4A4CCb7A4fFFb5A43EBC70DC","0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c","0x14723A09ACff6D2A60DcdF7aA4AFf308FDDC160C","0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB","0x583031D1113aD414F02576BD6afaBfb302140225","0xdD870fA1b7C4700F2BD7f44238821C26f7392148"]')
},
@ -52,7 +52,7 @@ module.exports = {
.clickLaunchIcon('udapp')
.click('*[data-id="settingsSelectEnvOptions"] *[data-id="External Http Provider"]')
.modalFooterOKClick('basic-http-provider')
.executeScript('web3.eth.getAccounts()')
.ExecuteScriptInTerminal('web3.eth.getAccounts()')
.waitForElementContainsText('*[data-id="terminalJournal"]', '["', 60000) // we check if an array is present, don't need to check for the content
.waitForElementContainsText('*[data-id="terminalJournal"]', '"]', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '","', 60000)
@ -64,7 +64,7 @@ module.exports = {
.addFile('resolveExternalUrlAndSave.js', { content: resolveExternalUrlAndSave })
.openFile('resolveExternalUrlAndSave.js')
.pause(1000)
.executeScript('remix.execute(\'resolveExternalUrlAndSave.js\')')
.ExecuteScriptInTerminal('remix.execute(\'resolveExternalUrlAndSave.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Implementation of the {IERC20} interface.', 60000)
.openFile('.deps/github/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol')
},
@ -75,7 +75,7 @@ module.exports = {
.addFile('resolveUrl.js', { content: resolveUrl })
.openFile('resolveUrl.js')
.pause(1000)
.executeScript('remix.execute(\'resolveUrl.js\')')
.ExecuteScriptInTerminal('remix.execute(\'resolveUrl.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'contract Ballot {', 60000)
},
@ -85,7 +85,7 @@ module.exports = {
.addFile('resolveExternalUrlAndSaveToaPath.js', { content: resolveExternalUrlAndSaveToaPath })
.openFile('resolveExternalUrlAndSaveToaPath.js')
.pause(1000)
.executeScript('remix.execute(\'resolveExternalUrlAndSaveToaPath.js\')')
.ExecuteScriptInTerminal('remix.execute(\'resolveExternalUrlAndSaveToaPath.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'abstract contract ERC20Burnable', 60000)
.openFile('.deps/github/newFile.sol')
@ -106,7 +106,7 @@ module.exports = {
.openFile('contracts/2_Owner.sol')
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]').pause(5000) // compile Owner
.executeScript('remix.execute(\'deployWithEthersJs.js\')')
.ExecuteScriptInTerminal('remix.execute(\'deployWithEthersJs.js\')')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Contract Address:', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', '0xd9145CCE52D386f254917e481eB44e9943F39138', 60000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Deployment successful.', 60000)
@ -128,7 +128,7 @@ module.exports = {
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]')
.pause(1000) // compile Storage
.executeScript('remix.execute(\'scripts/storage.test.js\')')
.ExecuteScriptInTerminal('remix.execute(\'scripts/storage.test.js\')')
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Running tests....')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'storage contract Address:')
@ -150,7 +150,7 @@ module.exports = {
.clickLaunchIcon('solidity')
.click('*[data-id="compilerContainerCompileBtn"]')
.pause(1000) // compile StorageWithLib
.executeScript('remix.execute(\'scripts/storageWithLib.test.js\')')
.ExecuteScriptInTerminal('remix.execute(\'scripts/storageWithLib.test.js\')')
.pause(1000)
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Running tests....')
.waitForElementContainsText('*[data-id="terminalJournal"]', 'Storage with lib')

@ -102,7 +102,7 @@ module.exports = {
// default values
.assert.containsText('#evmVersionSelector option[data-id="selected"]', 'default')
.verify.elementPresent('#optimize')
.assert.elementNotPresent('#optimize:checked')
.assert.not.elementPresent('#optimize:checked')
.verify.elementPresent('#runs:disabled')
.click('[for="optimize"')
.verify.attributeEquals('#runs', 'value', '200')

@ -21,7 +21,7 @@ declare module 'nightwatch' {
modalFooterOKClick(id?: string): NightwatchBrowser,
clickInstance(index: number): NightwatchBrowser,
journalLastChildIncludes(val: string): NightwatchBrowser,
executeScript(script: string): NightwatchBrowser,
ExecuteScriptInTerminal(script: string): NightwatchBrowser,
clearEditableContent(cssSelector: string): NightwatchBrowser,
journalChildIncludes(val: string, opts = { shouldHaveOnlyOneOccurence: boolean }): NightwatchBrowser,
debugTransaction(index: number): NightwatchBrowser,

@ -14,9 +14,12 @@ import React from 'react'
import { fileDecoration, fileDecorationType } from '@remix-ui/file-decorators'
import { Profile } from '@remixproject/plugin-utils'
import { ContractDefinitionAstNode, FunctionCallAstNode, FunctionDefinitionAstNode, ImportDirectiveAstNode, ModifierDefinitionAstNode, VariableDeclarationAstNode } from 'dist/libs/remix-analyzer/src/types'
import { lastCompilationResult } from '@remixproject/plugin-api'
import { ContractDefinitionAstNode, EventDefinitionAstNode, FunctionCallAstNode, FunctionDefinitionAstNode, IdentifierAstNode, ImportDirectiveAstNode, ModifierDefinitionAstNode, SourceUnitAstNode, StructDefinitionAstNode, VariableDeclarationAstNode } from 'dist/libs/remix-analyzer/src/types'
import { lastCompilationResult, RemixApi } from '@remixproject/plugin-api'
import { antlr } from './types'
import { ParseResult } from './types/antlr-types'
import { ConfigPlugin } from '../config'
const profile: Profile = {
name: 'codeParser',
@ -25,7 +28,7 @@ const profile: Profile = {
version: '0.0.1'
}
export function isNodeDefinition(node: AstNode) {
export function isNodeDefinition(node: genericASTNode) {
return node.nodeType === 'ContractDefinition' ||
node.nodeType === 'FunctionDefinition' ||
node.nodeType === 'ModifierDefinition' ||
@ -34,13 +37,39 @@ export function isNodeDefinition(node: AstNode) {
node.nodeType === 'EventDefinition'
}
export type genericASTNode =
ContractDefinitionAstNode
| FunctionDefinitionAstNode
| ModifierDefinitionAstNode
| VariableDeclarationAstNode
| StructDefinitionAstNode
| EventDefinitionAstNode
| IdentifierAstNode
| FunctionCallAstNode
| ImportDirectiveAstNode
| SourceUnitAstNode
interface flatReferenceIndexNode {
[id: number]: genericASTNode
}
interface declarationIndexNode {
[id: number]: genericASTNode[]
}
interface codeParserIndex {
declarations: declarationIndexNode,
flatReferences: flatReferenceIndexNode,
nodesPerFile: any
}
export class CodeParser extends Plugin {
antlrParserResult: antlr.ParseResult // contains the simple parsed AST for the current file
compilerAbstract: CompilerAbstract
currentFile: string
_index: any
nodeIndex: codeParserIndex
astWalker: any
errorState: boolean = false
@ -55,15 +84,15 @@ export class CodeParser extends Plugin {
getLastNodeInLine: (ast: string) => Promise<any>
listAstNodes: () => Promise<any>
getBlockAtPosition: (position: any, text?: string) => Promise<any>
getCurrentFileAST: (text?: string) => Promise<any>
getCurrentFileAST: (text?: string) => Promise<ParseResult>
constructor(astWalker) {
constructor(astWalker: any) {
super(profile)
this.astWalker = astWalker
this._index = {
Declarations: {},
FlatReferences: {}
}
this.nodeIndex = {
declarations: [[]],
flatReferences: [],
nodesPerFile: {} }
}
async onActivation() {
@ -79,6 +108,7 @@ export class CodeParser extends Plugin {
this.getBlockAtPosition = this.antlrService.getBlockAtPosition.bind(this.antlrService)
this.getCurrentFileAST = this.antlrService.getCurrentFileAST.bind(this.antlrService)
this.on('editor', 'didChangeFile', async (file) => {
console.log('contentChanged', file)
await this.call('editor', 'discardLineTexts')
@ -120,8 +150,12 @@ export class CodeParser extends Plugin {
}
getSubNodes<T extends genericASTNode>(node: T): number[] {
return node.nodeType=="ContractDefinition" && node.contractDependencies;
}
/**
* Builds a flat index and declarations of all the nodes in the compilation result
@ -130,14 +164,14 @@ export class CodeParser extends Plugin {
*/
_buildIndex(compilationResult: CompilationResult, source) {
if (compilationResult && compilationResult.sources) {
const callback = (node: AstNode) => {
if (node && node.referencedDeclaration) {
if (!this._index.Declarations[node.referencedDeclaration]) {
this._index.Declarations[node.referencedDeclaration] = []
const callback = (node: genericASTNode) => {
if (node && ("referencedDeclaration" in node) && node.referencedDeclaration) {
if (!this.nodeIndex.declarations[node.referencedDeclaration]) {
this.nodeIndex.declarations[node.referencedDeclaration] = []
}
this._index.Declarations[node.referencedDeclaration].push(node)
this.nodeIndex.declarations[node.referencedDeclaration].push(node)
}
this._index.FlatReferences[node.id] = node
this.nodeIndex.flatReferences[node.id] = node
}
for (const s in compilationResult.sources) {
this.astWalker.walkFull(compilationResult.sources[s].ast, callback)
@ -197,12 +231,7 @@ export class CodeParser extends Plugin {
if (name === contractName) {
const contract = contracts[name]
const estimationObj = contract.evm && contract.evm.gasEstimates
if (node.nodeType === 'ContractDefinition') {
return {
creationCost: estimationObj === null ? '-' : estimationObj.creation.totalCost,
codeDepositCost: estimationObj === null ? '-' : estimationObj.creation.codeDepositCost,
}
}
let executionCost = null
if (node.nodeType === 'FunctionDefinition') {
const visibility = node.visibility
@ -216,6 +245,11 @@ export class CodeParser extends Plugin {
executionCost = estimationObj === null ? '-' : estimationObj.internal[fn]
}
return { executionCost }
} else {
return {
creationCost: estimationObj === null ? '-' : estimationObj.creation.totalCost,
codeDepositCost: estimationObj === null ? '-' : estimationObj.creation.codeDepositCost,
}
}
}
}
@ -235,13 +269,12 @@ export class CodeParser extends Plugin {
* @param type
* @returns
*/
async nodesAtPosition(position: number, type = '') {
async nodesAtPosition(position: number, type = ''): Promise<genericASTNode[]> {
const lastCompilationResult = this.compilerAbstract
if (!lastCompilationResult) return false
if (!lastCompilationResult) return []
const urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile)
console.log('URL FROM PATH', urlFromPath)
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data && lastCompilationResult.data.sources && lastCompilationResult.data.sources[this.currentFile]) {
const nodes = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
const nodes: genericASTNode[] = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
return nodes
}
return []
@ -253,9 +286,9 @@ export class CodeParser extends Plugin {
* @returns
*/
async getNodeById(id: number) {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === id) {
return this._index.FlatReferences[key]
for (const key in this.nodeIndex.flatReferences) {
if (this.nodeIndex.flatReferences[key].id === id) {
return this.nodeIndex.flatReferences[key]
}
}
}
@ -266,7 +299,7 @@ export class CodeParser extends Plugin {
* @returns
*/
async getDeclaration(id: number) {
if (this._index.Declarations && this._index.Declarations[id]) return this._index.Declarations[id]
if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) return this.nodeIndex.declarations[id]
}
/**
@ -276,7 +309,7 @@ export class CodeParser extends Plugin {
*/
async getNodesWithScope(scope: number) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
for (const node of Object.values(this.nodeIndex.flatReferences)) {
if (node.scope === scope) nodes.push(node)
}
return nodes
@ -288,8 +321,8 @@ export class CodeParser extends Plugin {
* @returns
*/
async getNodesWithName(name: string) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
const nodes: genericASTNode[] = []
for (const node of Object.values(this.nodeIndex.flatReferences)) {
if (node.name === name) nodes.push(node)
}
return nodes
@ -299,9 +332,9 @@ export class CodeParser extends Plugin {
* @param node
* @returns
*/
declarationOf(node: AstNode) {
if (node && node.referencedDeclaration) {
return this._index.FlatReferences[node.referencedDeclaration]
declarationOf<T extends genericASTNode>(node: T) {
if (node && ('referencedDeclaration' in node) && node.referencedDeclaration) {
return this.nodeIndex.flatReferences[node.referencedDeclaration]
} else {
// console.log(this._index.FlatReferences)
}
@ -316,9 +349,9 @@ export class CodeParser extends Plugin {
async definitionAtPosition(position: number) {
const nodes = await this.nodesAtPosition(position)
console.log('nodes at position', nodes, position)
console.log(this._index.FlatReferences)
console.log(this.nodeIndex.flatReferences)
let nodeDefinition: any
let node: any
let node: genericASTNode
if (nodes && nodes.length && !this.errorState) {
node = nodes[nodes.length - 1]
nodeDefinition = node
@ -326,9 +359,9 @@ export class CodeParser extends Plugin {
nodeDefinition = await this.declarationOf(node) || node
}
if (node.nodeType === 'ImportDirective') {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === node.sourceUnit) {
nodeDefinition = this._index.FlatReferences[key]
for (const key in this.nodeIndex.flatReferences) {
if (this.nodeIndex.flatReferences[key].id === node.sourceUnit) {
nodeDefinition = this.nodeIndex.flatReferences[key]
}
}
}
@ -371,7 +404,7 @@ export class CodeParser extends Plugin {
* @param node
* @returns
*/
async positionOfDefinition(node: AstNode): Promise<any | null> {
async positionOfDefinition(node: genericASTNode): Promise<any | null> {
if (node) {
if (node.src) {
const position = sourceMappingDecoder.decode(node.src)
@ -389,11 +422,11 @@ export class CodeParser extends Plugin {
* @param imported
* @returns
*/
async resolveImports(node: AstNode, imported = {}) {
async resolveImports(node: any, imported = {}) {
if (node.nodeType === 'ImportDirective' && !imported[node.sourceUnit]) {
const importNode = await this.getNodeById(node.sourceUnit)
const importNode: any = await this.getNodeById(node.sourceUnit)
imported[importNode.id] = importNode
if (importNode.nodes) {
if (importNode.nodeType=='ImportDirective' && importNode.nodes) {
for (const child of importNode.nodes) {
imported = await this.resolveImports(child, imported)
}
@ -409,20 +442,20 @@ export class CodeParser extends Plugin {
* @param node
* @returns
*/
referencesOf(node: AstNode) {
const results = []
const highlights = (id) => {
if (this._index.Declarations && this._index.Declarations[id]) {
const refs = this._index.Declarations[id]
referencesOf(node: genericASTNode) {
const results: genericASTNode[] = []
const highlights = (id: number) => {
if (this.nodeIndex.declarations && this.nodeIndex.declarations[id]) {
const refs = this.nodeIndex.declarations[id]
for (const ref in refs) {
const node = refs[ref]
results.push(node)
}
}
}
if (node && node.referencedDeclaration) {
if (node && ("referencedDeclaration" in node) && node.referencedDeclaration) {
highlights(node.referencedDeclaration)
const current = this._index.FlatReferences[node.referencedDeclaration]
const current = this.nodeIndex.flatReferences[node.referencedDeclaration]
results.push(current)
} else {
highlights(node.id)
@ -435,7 +468,7 @@ export class CodeParser extends Plugin {
* @param position
* @returns
*/
async referrencesAtPosition(position: any) {
async referrencesAtPosition(position: any): Promise<genericASTNode[]> {
const nodes = await this.nodesAtPosition(position)
if (nodes && nodes.length) {
const node = nodes[nodes.length - 1]
@ -449,8 +482,8 @@ export class CodeParser extends Plugin {
*
* @returns
*/
async getNodes() {
return this._index.FlatReferences
async getNodes(): Promise<flatReferenceIndexNode> {
return this.nodeIndex.flatReferences
}
@ -460,7 +493,7 @@ export class CodeParser extends Plugin {
* @param node
* @returns
*/
async getNodeLink(node: AstNode) {
async getNodeLink(node: genericASTNode) {
const lineColumn = await this.getLineColumnOfNode(node)
const position = await this.positionOfDefinition(node)
if (this.compilerAbstract && this.compilerAbstract.source) {
@ -495,10 +528,10 @@ export class CodeParser extends Plugin {
* @param node
* @returns
*/
async getNodeDocumentation(node: AstNode) {
if (node.documentation && node.documentation.text) {
let text = ''
node.documentation.text.split('\n').forEach(line => {
async getNodeDocumentation(node: genericASTNode) {
if (("documentation" in node) && node.documentation && (node.documentation as any).text) {
let text = '';
(node.documentation as any).text.split('\n').forEach(line => {
text += `${line.trim()}\n`
})
return text

@ -105,8 +105,8 @@ export default class CodeParserAntlrService {
* @returns
*/
async getLastNodeInLine(ast: string) {
let lastNode
const checkLastNode = (node) => {
let lastNode: any
const checkLastNode = (node: antlr.MemberAccess | antlr.Identifier) => {
if (lastNode && lastNode.range && lastNode.range[1]) {
if (node.range[1] > lastNode.range[1]) {
lastNode = node
@ -117,10 +117,10 @@ export default class CodeParserAntlrService {
}
(SolidityParser as any).visit(ast, {
MemberAccess: function (node: any) {
MemberAccess: function (node: antlr.MemberAccess) {
checkLastNode(node)
},
Identifier: function (node) {
Identifier: function (node: antlr.Identifier) {
checkLastNode(node)
}
})
@ -146,7 +146,7 @@ export default class CodeParserAntlrService {
async getBlockAtPosition(position: any, text: string = null) {
await this.getCurrentFileAST(text)
const allowedTypes = ['SourceUnit', 'ContractDefinition', 'FunctionDefinition']
const walkAst = (node) => {
const walkAst = (node: any) => {
if (node.loc.start.line <= position.lineNumber && node.loc.end.line >= position.lineNumber) {
const children = node.children || node.subNodes
if (children && allowedTypes.indexOf(node.type) !== -1) {

@ -65,11 +65,13 @@ export default class CodeParserCompiler {
this.plugin.compilerAbstract = new CompilerAbstract('soljson', data, source, input)
console.log('ABSTRACT', this.plugin.compilerAbstract)
this.errorState = false
this.plugin._index = {
Declarations: {},
FlatReferences: {},
NodesPerFile: {},
this.plugin.nodeIndex = {
declarations: {},
flatReferences: {},
nodesPerFile: {},
}
this.plugin._buildIndex(data, source)
if (this.gastEstimateTimeOut) {
@ -80,7 +82,7 @@ export default class CodeParserCompiler {
await this.plugin.gasService.showGasEstimates()
}, 1000)
console.log("INDEX", this.plugin._index)
console.log("INDEX", this.plugin.nodeIndex)
this.plugin.emit('astFinished')
}

@ -168,7 +168,7 @@ export interface ContractDefinitionAstNode {
nodeType: 'ContractDefinition'
src: string
name: string
documentation: string | null
documentation: string | null | StructuredDocumentationAstNode
contractKind: 'interface' | 'contract' | 'library'
abstract: boolean
fullyImplemented: boolean
@ -241,7 +241,7 @@ export interface FunctionDefinitionAstNode {
nodeType: 'FunctionDefinition'
src: string
name: string
documentation: string | null
documentation: string | null | StructuredDocumentationAstNode
kind: string
stateMutability: 'pure' | 'view' | 'nonpayable' | 'payable'
visibility: string
@ -281,7 +281,7 @@ export interface ModifierDefinitionAstNode {
nodeType: 'ModifierDefinition'
src: string
name: string
documentation: Record<string, unknown> | null
documentation: Record<string, unknown> | null | StructuredDocumentationAstNode
visibility: string
parameters: ParameterListAstNode
virtual: boolean
@ -303,7 +303,7 @@ export interface EventDefinitionAstNode {
nodeType: 'EventDefinition'
src: string
name: string
documentation: Record<string, unknown> | null
documentation: Record<string, unknown> | null | StructuredDocumentationAstNode
parameters: ParameterListAstNode
anonymous: boolean
}

@ -87,6 +87,8 @@ export class AstWalker extends EventEmitter {
return normalizedNodes
}
getASTNodeChildren (ast: AstNode): AstNode[] {
let nodes = ast.nodes || // for ContractDefinition
ast.body || // for FunctionDefinition, ModifierDefinition, WhileStatement, DoWhileStatement, ForStatement

@ -13,6 +13,8 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
constructor(props: any, monaco: any) {
this.props = props
this.monaco = monaco
}
triggerCharacters = ['.', '']
@ -29,19 +31,16 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
endColumn: word.endColumn
};
console.log('WORD', word)
const line = model.getLineContent(position.lineNumber)
let nodes: AstNode[] = []
let suggestions: monaco.languages.CompletionItem[] = []
const cursorPosition = this.props.editorAPI.getCursorPosition()
console.log('cursor', cursorPosition)
const cursorPosition: number = this.props.editorAPI.getCursorPosition()
if (context.triggerCharacter === '.') {
console.clear()
console.log('TEXT', line)
const lineTextBeforeCursor = line.substring(0, position.column - 1)
const lineTextBeforeCursor: string = line.substring(0, position.column - 1)
const lastNodeInExpression = await this.getLastNodeInExpression(lineTextBeforeCursor)
console.log('lastNode found', lastNodeInExpression)
console.log(lineTextBeforeCursor)
@ -130,7 +129,6 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
// }
// brute force search in all nodes with the name
//if (!nodes.length || 1) {
const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithName', last)
console.log('NODES WITHE NAME ', last, nodesOfScope)
for (const nodeOfScope of nodesOfScope) {
@ -147,7 +145,6 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
}
}
}
//}
}
} else {

@ -152,6 +152,10 @@ export class RemixHoverProvider implements languages.HoverProvider {
// getScope(nodeAtPosition)
}
setTimeout(() => {
// eslint-disable-next-line no-debugger
// debugger
},1000)
return {
range: new this.monaco.Range(

@ -160,6 +160,7 @@
"@remixproject/plugin-utils": "^0.3.28",
"@remixproject/plugin-webview": "^0.3.28",
"@remixproject/plugin-ws": "^0.3.28",
"@types/nightwatch": "^2.0.9",
"ansi-gray": "^0.1.1",
"async": "^2.6.2",
"axios": ">=0.26.0",
@ -243,7 +244,6 @@
"@types/jest": "^27.0.2",
"@types/lodash": "^4.14.172",
"@types/mocha": "^7.0.2",
"@types/nightwatch": "1.3.4",
"@types/node": "~8.9.4",
"@types/react": "^17.0.24",
"@types/react-beautiful-dnd": "^13.1.2",
@ -305,7 +305,7 @@
"mkdirp": "^0.5.1",
"mocha": "^8.0.1",
"nanohtml": "^1.6.3",
"nightwatch": "^1.7.11",
"nightwatch": "^2.2.2",
"nodemon": "^2.0.4",
"notify-error": "^1.2.0",
"npm-link-local": "^1.1.0",

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save