add analyze with slither

pull/3181/head
yann300 2 years ago
parent 6578135447
commit 29f4bd72c6
  1. 3
      apps/remix-ide/src/app/plugins/solhint.ts
  2. 4
      apps/remix-ide/src/app/tabs/compile-tab.js
  3. 80
      apps/solidity-compiler/src/app/compiler-api.ts
  4. 3
      libs/remix-lib/src/types/ICompilerApi.ts
  5. 10
      libs/remix-ui/renderer/src/lib/renderer.tsx
  6. 47
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  7. 18
      libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx

@ -60,9 +60,8 @@ export class Solhint extends Plugin {
return reports.map((report: Report) => {
return {
severity: severity[report.severity] || 'error',
formattedMessage: `${report.message}\n${report.fix ? report.fix : ''}`,
type: report.ruleId,
type: severity[report.severity] || 'error',
column: report.column,
line: report.line - 1
}

@ -70,6 +70,10 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA
this.renderComponent()
}
onSlitherFinished () {
this.renderComponent()
}
onFileClosed () {
this.renderComponent()
}

@ -1,5 +1,5 @@
import React from 'react';
import { compile, helper } from '@remix-project/remix-solidity'
import { compile, helper, CompilerAbstract } from '@remix-project/remix-solidity'
import { CompileTabLogic, parseContracts } from '@remix-ui/solidity-compiler' // eslint-disable-line
import type { ConfigurationSettings, CompileErrors, CompileError } from '@remix-project/remix-lib-ts'
@ -14,6 +14,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
}
compileErrors: CompileErrors
linterErrors: CompileError[]
slitherErrors: CompileError[]
compileTabLogic: CompileTabLogic
configurationSettings: ConfigurationSettings
@ -23,6 +24,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
onFileRemoved: (path: string) => void
onNoFileSelected: () => void
onLintingFinished: () => void
onSlitherFinished: () => void
onCompilationFinished: (compilationDetails: { contractMap: { file: string } | Record<string, any>, contractsDetails: Record<string, any> }) => void
onSessionSwitched: () => void
onContentChanged: () => void
@ -52,6 +54,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
errors: []
}
this.linterErrors = []
this.slitherErrors = []
this.compiledFileName = ''
this.currentFile = ''
}
@ -113,6 +116,80 @@ export const CompilerApiMixin = (Base) => class extends Base {
this.onLintingFinished()
}
async runSlither () {
this.slitherErrors = []
const conf = {
currentVersion: this.compiler.state.currentVersion,
optimize: this.compiler.state.optimize,
evmVersion: this.compiler.state.evmVersion
}
const result = await this.call('slither', 'analyse', this.currentFile, conf)
if (!result.status) {
this.call('notification', 'toast', 'slither analysis failed.')
return
}
const lastCompilationResult: CompilerAbstract = await this.call('compilerArtefacts', 'get', '__last')
const data = lastCompilationResult.getData()
const sourceCode = lastCompilationResult.getSourceCode()
const report = result.data
const mapType = {
'informational': 'info',
'low': 'warning',
'medium': 'error',
'high': 'error',
'optimization': 'info'
}
for (const item of report) {
console.log(item)
const type = mapType[item.severity.toLowerCase()] ? mapType[item.severity.toLowerCase()] : 'error'
if (item.sourceMap.length > 0) {
let location: any = {}
let path = item.sourceMap[0].source_mapping.filename_relative
let fileIndex = Object.keys(data.sources).indexOf(path)
if (fileIndex === -1) {
path = await this.call('fileManager', 'getUrlFromPath', path)
fileIndex = Object.keys(data.sources).indexOf(path.file)
}
if (fileIndex >= 0) {
location = {
start: item.sourceMap[0].source_mapping.start,
length: item.sourceMap[0].source_mapping.length
}
location = await this.call('offsetToLineColumnConverter', 'offsetToLineColumn',
location,
fileIndex,
sourceCode.sources,
data.sources
)
const msg = `${item.title} : ${path} - ${item.description} - ${item.more ? item.more : ''}`
const fileName = Object.keys(data.sources)[fileIndex]
this.slitherErrors.push({
column: location.start.column,
line: location.start.line,
file: fileName,
formattedMessage: msg,
type: type
})
} else {
const msg = `${item.title} : ${item.description} - ${item.more}`
this.slitherErrors.push({
column: -1,
line: -1,
file: null,
formattedMessage: msg,
type: type
})
}
}
}
this.onSlitherFinished()
}
compileWithHardhat (configFile) {
return this.call('hardhat', 'compile', configFile)
}
@ -291,6 +368,7 @@ export const CompilerApiMixin = (Base) => class extends Base {
this.data.eventHandlers.onCompilationFinished = async (success, data, source, input, version) => {
this.compileErrors = data
this.linterErrors = []
this.slitherErrors = []
if (success) {
// forwarding the event to the appManager infra
this.emit('compilationFinished', source.target, source, 'soljson', data, input, version)

@ -9,6 +9,7 @@ export interface ICompilerApi {
}
compileErrors: CompileErrors
linterErrors: CompileError[]
slitherErrors: CompileError[]
compileTabLogic: any
configurationSettings: ConfigurationSettings
@ -29,6 +30,7 @@ export interface ICompilerApi {
onFileRemoved: (path: string) => void
onNoFileSelected: () => void
onLintingFinished: () => void
onSlitherFinished: () => void
onCompilationFinished: (contractsDetails: any, contractMap: any) => void
onSessionSwitched: () => void
onContentChanged: () => void
@ -42,6 +44,7 @@ export interface ICompilerApi {
saveCurrentFile: () => void
runScriptAfterCompilation: (fileName: string) => void,
runLinter: (fileName: string) => void,
runSlither: () => void,
logToTerminal: (log: terminalLog) => void

@ -10,6 +10,12 @@ interface RendererProps {
errFile?: string
}
const classType = {
'error': 'alert alert-danger',
'warning': 'alert alert-warning',
'info': 'alert alert-info'
}
export const Renderer = ({ message, opt = {}, plugin, errColumn, errLine, errFile }: RendererProps) => {
const [messageText, setMessageText] = useState(null)
const [editorOptions, setEditorOptions] = useState({
@ -17,7 +23,7 @@ export const Renderer = ({ message, opt = {}, plugin, errColumn, errLine, errFil
type: '',
errFile: ''
})
const [classList, setClassList] = useState(opt.type === 'error' ? 'alert alert-danger' : 'alert alert-warning')
const [classList, setClassList] = useState('alert alert-warning')
const [close, setClose] = useState(false)
useEffect(() => {
@ -48,7 +54,7 @@ export const Renderer = ({ message, opt = {}, plugin, errColumn, errLine, errFil
setMessageText(text)
setEditorOptions(opt)
setClose(close !== undefined ? close : false)
setClassList(opt.type === 'error' ? 'alert alert-danger' : 'alert alert-warning')
setClassList(classType[opt.type] ? classType[opt.type] : 'alert alert-warning')
}, [message, opt])

@ -536,6 +536,13 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
api.runLinter(currentFile)
}
const slither = () => {
const currentFile = api.currentFile
if (!isSolFileSelected()) return
api.runSlither()
}
const _updateVersionSelector = (version, customUrl = '') => {
// update selectedversion of previous one got filtered out
let selectedVersion = version
@ -1038,26 +1045,42 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
<CustomTooltip
placement="right"
tooltipId="overlay-tooltip-compile-run"
tooltipText={<div className="text-left">Lint the current file</div>}
tooltipText={<div className="text-left">Analyze with Solhint</div>}
>
<span>
<FormattedMessage id='solidity.lint' defaultMessage='Lint' />
<span className="ml-1">
{typeof state.compiledFileName === 'string'
? extractNameFromKey(state.compiledFileName) ||
`<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`
: `<${intl.formatMessage({
id: 'solidity.noFileSelected',
defaultMessage: 'no file selected',
})}>`}
Analyze with Solhint
</span>
</span>
</CustomTooltip>
</button>
</div>
</div>
<div className='d-flex align-items-center'>
<button
id="slitherButton"
data-id="compilerContainerLinter"
className="btn btn-secondary btn-block d-block w-100 text-break remixui_soliditySlitherButton d-inline-block remixui_disabled mb-1 mt-3"
onClick={slither}
disabled={(configFilePath === '' && state.useFileConfiguration) || disableCompileButton}
>
<CustomTooltip
placement="right"
tooltipId="overlay-tooltip-compile-run"
tooltipText={<div className="text-left">Analyze with Slither</div>}
>
<span>
<FormattedMessage id='solidity.lint' defaultMessage='Lint' />
<span className="ml-1">
Analyze with Slither
</span>
</span>
</CustomTooltip>
</button>
</div>
</div>
</article>
</section>

@ -37,6 +37,7 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
const [hideWarnings, setHideWarnings] = useState<boolean>(false)
const [compileErrors, setCompileErrors] = useState<Record<string, CompileErrors>>({ [currentFile]: api.compileErrors })
const [linterErrors, setLinterErrors] = useState<Record<string, Array<CompileError>>>({ [currentFile]: api.linterErrors })
const [slitherErrors, setSlitherErrors] = useState<Record<string, Array<CompileError>>>({ [currentFile]: api.slitherErrors })
const [badgeStatus, setBadgeStatus] = useState<Record<string, { key: string, title?: string, type?: string }>>({})
const [contractsFile, setContractsFile] = useState<ContractsFile>({})
@ -104,6 +105,7 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
setContractsFile({ ...contractsFile, [target]: { contractList, contractsDetails } })
setCompileErrors({ ...compileErrors, [currentFile]: api.compileErrors })
setLinterErrors({ [currentFile]: api.linterErrors })
setSlitherErrors({ [currentFile]: api.slitherErrors })
}
api.onLintingFinished = () => {
@ -111,10 +113,16 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
setLinterErrors({ [currentFile]: api.linterErrors })
}
api.onSlitherFinished = () => {
setCompileErrors({} as Record<string, CompileErrors>)
setSlitherErrors({ [currentFile]: api.slitherErrors })
}
api.onFileClosed = (name) => {
if (name === currentFile) {
setCompileErrors({ ...compileErrors, [currentFile]: {} as CompileErrors })
setLinterErrors({ ...linterErrors, [currentFile]: [] as CompileError[] })
setSlitherErrors({ ...slitherErrors, [currentFile]: [] as CompileError[] })
setBadgeStatus({ ...badgeStatus, [currentFile]: { key: 'none' } })
}
}
@ -214,7 +222,15 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => {
linterErrors[currentFile] &&
<div className="remixui_errorBlobs p-4" data-id="linterErrors">
{
linterErrors[currentFile].map((err, index) => <Renderer key={index} message={err.formattedMessage} plugin={api} errColumn={err.column} errLine={err.line} errFile={currentFile} opt={{ close: false, useSpan: true, type: err.severity, errorType: err.type }}></Renderer>)
linterErrors[currentFile].map((err, index) => <Renderer key={index} message={err.formattedMessage} plugin={api} errColumn={err.column} errLine={err.line} errFile={currentFile} opt={{ close: false, useSpan: true, type: err.type }}></Renderer>)
}
</div>
}
{
slitherErrors[currentFile] &&
<div className="remixui_errorBlobs p-4" data-id="slitherErrors">
{
slitherErrors[currentFile].map((err, index) => <Renderer key={index} message={err.formattedMessage} plugin={api} errColumn={err.column} errLine={err.line} errFile={currentFile} opt={{ close: false, useSpan: true, type: err.type }}></Renderer>)
}
</div>
}

Loading…
Cancel
Save