Merge pull request #3892 from ethereum/ssa-improvements

SSA Improvements
pull/5370/head
Joseph Izang 2 years ago committed by GitHub
commit b7f9479f1a
  1. 10
      apps/remix-ide/src/app/tabs/analysis-tab.js
  2. 88
      libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx
  3. 129
      libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts
  4. 252
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  5. 3
      libs/remix-ui/static-analyser/src/staticanalyser.d.ts

@ -38,6 +38,9 @@ class AnalysisTab extends ViewPlugin {
} }
this.dispatch = null this.dispatch = null
this.hints = [] this.hints = []
this.basicEnabled = false
this.solhintEnabled = false
this.slitherEnabled = false
} }
async onActivation () { async onActivation () {
@ -49,16 +52,15 @@ class AnalysisTab extends ViewPlugin {
this.event.register('staticAnaysisWarning', (count) => { this.event.register('staticAnaysisWarning', (count) => {
let payloadType = '' let payloadType = ''
const error = this.hints.find(hint => hint.type === 'error') const error = this.hints?.find(hint => hint.type === 'error')
const warning = this.hints.find(hints => hints.type === 'warning') if (error && this.solhintEnabled) {
if (error) {
payloadType = 'error' payloadType = 'error'
} else { } else {
payloadType = 'warning' payloadType = 'warning'
} }
if (count > 0) { if (count > 0) {
this.emit('statusChanged', { key: count, title: payloadType === 'error' ? `You have some problem${count === 1 ? '' : 's'}` : 'You have some warnings', type: payloadType }) this.emit('statusChanged', { key: count, title: payloadType === 'error' ? `You have ${count} problem${count === 1 ? '' : 's'}` : `You have ${count} warnings`, type: payloadType })
} else if (count === 0) { } else if (count === 0) {
this.emit('statusChanged', { key: 'succeed', title: 'no warnings or errors', type: 'success' }) this.emit('statusChanged', { key: 'succeed', title: 'no warnings or errors', type: 'success' })
} else { } else {

@ -1,20 +1,22 @@
import { CustomTooltip } from '@remix-ui/helper'; import { CustomTooltip } from "@remix-ui/helper"
import React from 'react' //eslint-disable-line import React from "react"; //eslint-disable-line
import { RemixUiStaticAnalyserState } from "../staticanalyser"
interface ErrorRendererProps { interface ErrorRendererProps {
message: any; message: any;
opt: any, opt: any;
warningErrors: any warningErrors: any;
editor: any, editor: any;
name: string, name: string;
ssaState: RemixUiStaticAnalyserState
} }
const ErrorRenderer = ({ message, opt, editor, name }: ErrorRendererProps) => { const ErrorRenderer = ({ message, opt, editor, name, ssaState }: ErrorRendererProps) => {
const getPositionDetails = (msg: any) => { const getPositionDetails = (msg: any) => {
const result = { } as Record<string, number | string> const result = {} as Record<string, number | string>
// To handle some compiler warning without location like SPDX license warning etc // To handle some compiler warning without location like SPDX license warning etc
if (!msg.includes(':')) return { errLine: -1, errCol: -1, errFile: msg } if (!msg.includes(":")) return { errLine: -1, errCol: -1, errFile: msg }
// extract line / column // extract line / column
let position = msg.match(/^(.*?):([0-9]*?):([0-9]*?)?/) let position = msg.match(/^(.*?):([0-9]*?):([0-9]*?)?/)
@ -23,46 +25,70 @@ const ErrorRenderer = ({ message, opt, editor, name }: ErrorRendererProps) => {
// extract file // extract file
position = msg.match(/^(https:.*?|http:.*?|.*?):/) position = msg.match(/^(https:.*?|http:.*?|.*?):/)
result.errFile = position ? position[1] : '' result.errFile = position ? position[1] : ""
return result return result;
} }
const handlePointToErrorOnClick = async (location, fileName) => { const handlePointToErrorOnClick = async (location, fileName) => {
await editor.call('editor', 'discardHighlight') await editor.call("editor", "discardHighlight")
await editor.call('editor', 'highlight', location, fileName, '', { focus: true }) await editor.call("editor", "highlight", location, fileName, "", {
focus: true,
})
} }
if (!message) return if (!message) return
let position = getPositionDetails(message) let position = getPositionDetails(message)
if (!position.errFile || (opt.errorType && opt.errorType === position.errFile)) { if (
!position.errFile ||
(opt.errorType && opt.errorType === position.errFile)
) {
// Updated error reported includes '-->' before file details // Updated error reported includes '-->' before file details
const errorDetails = message.split('-->') const errorDetails = message.split("-->")
// errorDetails[1] will have file details // errorDetails[1] will have file details
if (errorDetails.length > 1) position = getPositionDetails(errorDetails[1]) if (errorDetails.length > 1) position = getPositionDetails(errorDetails[1])
} }
opt.errLine = position.errLine opt.errLine = position.errLine
opt.errCol = position.errCol opt.errCol = position.errCol
opt.errFile = position.errFile.trim() opt.errFile = position.errFile.trim()
const classList = opt.type === 'error' ? 'alert alert-danger' : 'alert alert-warning' const classList =
opt.type === "error" ? "alert alert-danger" : "alert alert-warning"
return ( return (
<div> <div>
<div className={`sol ${opt.type} ${classList}`}> <div className={`sol ${opt.type} ${classList}`}>
<span className='d-flex flex-column' data-id={`${name}Button`} onClick={async () => await handlePointToErrorOnClick(opt.location, opt.fileName)} style={{ cursor: "pointer", overflow: 'hidden', textOverflow: 'ellipsis' }}> <div
<span className='h6 font-weight-bold'>{opt.name}</span> className="d-flex flex-column"
<span>{ opt.item.warning }</span> data-id={`${name}Button`}
{opt.item.more onClick={async () =>
? <span><a href={opt.item.more} target='_blank'>more</a></span> await handlePointToErrorOnClick(opt.location, opt.fileName)
: <span> </span>
} }
<CustomTooltip style={{
placement="right" cursor: "pointer",
tooltipId="errorTooltip" overflow: "hidden",
tooltipText={`Position in ${opt.errFile}`} textOverflow: "ellipsis",
tooltipClasses="text-nowrap" }}
> >
<span>Pos: {opt.locationString}</span> <span className="h6 font-weight-bold">{opt.name}</span>
</CustomTooltip> <span>{opt.item.warning}</span>
</span> {opt.item.more ? (
<span>
<a href={opt.item.more} target="_blank">
more
</a>
</span>
) : (
<span> </span>
)}
<div>
<CustomTooltip
placement="right"
tooltipId="errorTooltip"
tooltipText={`Position in ${ssaState.file}`}
tooltipClasses="text-nowrap"
>
<span>Pos: {opt.locationString}</span>
</CustomTooltip>
</div>
</div>
</div> </div>
</div> </div>
) )

@ -56,73 +56,82 @@ slitherEnabled: boolean, setStartAnalysis: React.Dispatch<React.SetStateAction<b
const warningErrors = [] const warningErrors = []
props.analysisModule.hints = [] props.analysisModule.hints = []
// Run solhint // Run solhint
if (solhintEnabled) {
_paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'solHint']) _paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'solHint'])
const hintsResult = await props.analysisModule.call('solhint', 'lint', state.file) const hintsResult = await props.analysisModule.call('solhint', 'lint', state.file)
props.analysisModule.hints = solhintEnabled === false ? 0 : hintsResult props.analysisModule.hints = hintsResult
setHints(hintsResult) setHints(hintsResult)
} else {
props.analysisModule.hints = []
setHints([])
}
// Remix Analysis // Remix Analysis
_paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'remixAnalyzer']) if (basicEnabled) {
const results = runner.run(lastCompilationResult, categoryIndex) _paq.push(['trackEvent', 'solidityStaticAnalyzer', 'analyze', 'remixAnalyzer'])
for (const result of results) { const results = runner.run(lastCompilationResult, categoryIndex)
let moduleName for (const result of results) {
Object.keys(groupedModules).map(key => { let moduleName
groupedModules[key].forEach(el => { Object.keys(groupedModules).map(key => {
if (el.name === result.name) { groupedModules[key].forEach(el => {
moduleName = groupedModules[key][0].categoryDisplayName if (el.name === result.name) {
} moduleName = groupedModules[key][0].categoryDisplayName
}
})
}) })
}) // iterate over the warnings and create an object
// iterate over the warnings and create an object for (const item of result.report) {
for (const item of result.report) { let location: any = {}
let location: any = {} let locationString = 'not available'
let locationString = 'not available' let column = 0
let column = 0 let row = 0
let row = 0 let fileName = currentFile
let fileName = currentFile let isLibrary = false
let isLibrary = false
if (item.location) { if (item.location) {
const split = item.location.split(':') const split = item.location.split(':')
const file = split[2] const file = split[2]
location = { location = {
start: parseInt(split[0]), start: parseInt(split[0]),
length: parseInt(split[1]) length: parseInt(split[1])
}
location = props.analysisModule._deps.offsetToLineColumnConverter.offsetToLineColumn(
location,
parseInt(file),
lastCompilationSource.sources,
lastCompilationResult.sources
)
row = location.start.line
column = location.start.column
locationString = row + 1 + ':' + column + ':'
fileName = Object.keys(lastCompilationResult.sources)[file]
} }
location = props.analysisModule._deps.offsetToLineColumnConverter.offsetToLineColumn( if (fileName !== currentFile) {
location, const { file, provider } = await props.analysisModule.call('fileManager', 'getPathFromUrl', fileName)
parseInt(file), if (file.startsWith('.deps') || (provider.type === 'localhost' && file.startsWith('localhost/node_modules'))) isLibrary = true
lastCompilationSource.sources, }
lastCompilationResult.sources const msg = message(result.name, item.warning, item.more, state.file, locationString)
) const options = {
row = location.start.line type: 'warning',
column = location.start.column useSpan: true,
locationString = row + 1 + ':' + column + ':' errFile: state.file,
fileName = Object.keys(lastCompilationResult.sources)[file] fileName,
} isLibrary,
if(fileName !== currentFile) { errLine: row,
const {file, provider} = await props.analysisModule.call('fileManager', 'getPathFromUrl', fileName) errCol: column,
if (file.startsWith('.deps') || (provider.type === 'localhost' && file.startsWith('localhost/node_modules'))) isLibrary = true item: item,
} name: result.name,
const msg = message(result.name, item.warning, item.more, fileName, locationString) locationString,
const options = { more: item.more,
type: 'warning', location: location
useSpan: true, }
errFile: fileName, warningErrors.push(options)
fileName, warningMessage.push({ msg, options, hasWarning: true, warningModuleName: moduleName })
isLibrary, setSsaWarnings(warningMessage)
errLine: row,
errCol: column,
item: item,
name: result.name,
locationString,
more: item.more,
location: location
} }
warningErrors.push(options)
warningMessage.push({ msg, options, hasWarning: true, warningModuleName: moduleName })
setSsaWarnings(warningMessage)
} }
} } else {
setSsaWarnings([])
}
// Slither Analysis // Slither Analysis
if (showSlither && slitherEnabled) { if (showSlither && slitherEnabled) {
setSlitherWarnings([]) setSlitherWarnings([])
@ -198,12 +207,12 @@ slitherEnabled: boolean, setStartAnalysis: React.Dispatch<React.SetStateAction<b
props.analysisModule.call('terminal', 'log', { type: 'error', value: '[Slither Analysis]: Error occured! See remixd console for details.' }) props.analysisModule.call('terminal', 'log', { type: 'error', value: '[Slither Analysis]: Error occured! See remixd console for details.' })
showWarnings(warningMessage, 'warningModuleName') showWarnings(warningMessage, 'warningModuleName')
} }
} else showWarnings(warningMessage, 'warningModuleName') } else setStartAnalysis(false)
setStartAnalysis(false)
} else { } else {
if (categoryIndex.length) { if (categoryIndex.length) {
warningContainer.current.innerText = 'No compiled AST available' warningContainer.current.innerText = 'No compiled AST available'
} }
props.event.trigger('staticAnaysisWarning', [-1]) props.event.trigger('staticAnaysisWarning', [-1])
} }
} }

@ -29,6 +29,7 @@ import {
calculateWarningStateEntries, calculateWarningStateEntries,
} from "./components/BasicTitle"; } from "./components/BasicTitle";
import { Nav, TabContainer } from "react-bootstrap"; import { Nav, TabContainer } from "react-bootstrap";
import { CustomTooltip } from "@remix-ui/helper";
declare global { declare global {
interface Window { interface Window {
@ -365,8 +366,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
onChange={() => {}} onChange={() => {}}
/> />
</div> </div>
) );
} };
const categorySection = (category, categoryId, i) => { const categorySection = (category, categoryId, i) => {
return ( return (
@ -416,8 +417,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</TreeView> </TreeView>
</div> </div>
</div> </div>
) );
} };
useEffect(() => { useEffect(() => {
if (!hideWarnings && !showLibsWarning) { if (!hideWarnings && !showLibsWarning) {
@ -436,85 +437,95 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
props.event.trigger("staticAnaysisWarning", [ props.event.trigger("staticAnaysisWarning", [
slitherTotal + ssaTotal + hintsTotal === 0 slitherTotal + ssaTotal + hintsTotal === 0
? -1 ? -1
: slitherTotal + ssaTotal + hintsTotal, : !solhintEnabled && !basicEnabled && !slitherEnabled ? -1 : slitherTotal + ssaTotal + hintsTotal,
]) ]);
} }
if (!hideWarnings && showLibsWarning) { if (!hideWarnings && showLibsWarning) {
props.event.trigger("staticAnaysisWarning", [ props.event.trigger("staticAnaysisWarning", [
slitherWarnings.length + ssaWarnings.length + hints.length === 0 slitherWarnings.length + ssaWarnings.length + hints.length === 0
? -1 ? -1
: slitherWarnings.length + ssaWarnings.length + hints.length, : !solhintEnabled && !basicEnabled && !slitherEnabled ? -1 : slitherWarnings.length + ssaWarnings.length + hints.length,
]) ]);
} }
if (hideWarnings) { if (hideWarnings) {
const slitherTotal = const slitherTotal =
slitherWarnings && state.data && state.source !== null slitherWarnings && state.data && state.source !== null
? slitherWarnings.filter((x) => x.options.type === "error").length ? slitherWarnings.filter((x) => x.options.type === "error").length
: 0 : 0;
const ssaTotal = const ssaTotal =
ssaWarnings && state.data && state.source !== null ssaWarnings && state.data && state.source !== null
? ssaWarnings.filter((x) => x.options.type === "error").length ? ssaWarnings.filter((x) => x.options.type === "error").length
: 0 : 0;
const hintsTotal = const hintsTotal =
hints && state.data && state.source !== null hints && state.data && state.source !== null
? hints.filter((x) => x.type === "error").length ? hints.filter((x) => x.type === "error").length
: 0 : 0;
props.event.trigger("staticAnaysisWarning", [ props.event.trigger("staticAnaysisWarning", [
slitherTotal + ssaTotal + hintsTotal === 0 slitherTotal + ssaTotal + hintsTotal === 0
? -1 ? -1
: slitherTotal + ssaTotal + hintsTotal, : slitherTotal + ssaTotal + hintsTotal,
]) ]);
}
if (hideWarnings && !solhintEnabled && !slitherEnabled && !basicEnabled) {
props.event.trigger("staticAnaysisWarning", [-1])
} }
}, [hideWarnings, showLibsWarning]) }, [hideWarnings, showLibsWarning])
useEffect(() => { useEffect(() => {
const slitherTotal = let slitherTotal = 0
slitherEnabled && if (slitherEnabled &&
showSlither && showSlither &&
slitherWarnings && slitherWarnings &&
state.data && state.data &&
state.source !== null state.source !== null) {
? slitherWarnings.filter((x) => !x.options.isLibrary && x.hasWarning) slitherTotal = slitherWarnings.filter((x) => !x.options.isLibrary && x.hasWarning).length
.length props.analysisModule.slitherEnabled = true
: 0 }
const ssaTotal = let ssaTotal = 0
basicEnabled && ssaWarnings && state.data && state.source !== null if (basicEnabled && ssaWarnings && state.data && state.source !== null) {
? ssaWarnings.filter((x) => !x.options.isLibrary && x.hasWarning).length ssaTotal = ssaWarnings.filter((x) => !x.options.isLibrary && x.hasWarning).length
: 0 props.analysisModule.basicEnabled = true
const hintsTotal = }
solhintEnabled && hints && state.data && state.source !== null
? hints.length let hintsTotal = 0
: 0 if (solhintEnabled && hints && state.data && state.source !== null) {
hintsTotal = hints.length
props.analysisModule.solhintEnabled = true
}
props.event.trigger("staticAnaysisWarning", [ props.event.trigger("staticAnaysisWarning", [
slitherTotal + ssaTotal + hintsTotal === 0 slitherTotal + ssaTotal + hintsTotal === 0
? -1 ? -1
: slitherTotal + ssaTotal + hintsTotal, : slitherTotal + ssaTotal + hintsTotal,
]) ]);
}, [hints.length, slitherWarnings.length, ssaWarnings.length]) }, [hints.length, slitherWarnings.length, ssaWarnings.length])
useEffect(() => { useEffect(() => {
const slitherTotal = let slitherTotal = 0
slitherWarnings && if (slitherWarnings &&
slitherEnabled && slitherEnabled &&
showSlither && showSlither &&
state.data && state.data &&
state.source !== null state.source !== null) {
? slitherWarnings.filter((x) => !x.options.isLibrary && x.hasWarning) slitherTotal = slitherWarnings.filter((x) => !x.options.isLibrary && x.hasWarning)
.length .length
: 0 props.analysisModule.slitherEnabled = true
const ssaTotal = }
ssaWarnings && basicEnabled && state.data && state.source !== null
? ssaWarnings.filter((x) => !x.options.isLibrary && x.hasWarning).length let ssaTotal = 0
: 0 if (ssaWarnings && basicEnabled && state.data && state.source !== null) {
const hintsTotal = ssaTotal = ssaWarnings.filter((x) => !x.options.isLibrary && x.hasWarning).length
hints && solhintEnabled && state.data && state.source !== null props.analysisModule.basicEnabled = true
? hints.length }
: 0
let hintsTotal = 0
if (hints && solhintEnabled && state.data && state.source !== null) {
hintsTotal = hints.length
}
props.event.trigger("staticAnaysisWarning", [ props.event.trigger("staticAnaysisWarning", [
slitherTotal + ssaTotal + hintsTotal === 0 slitherTotal + ssaTotal + hintsTotal === 0
? -1 ? -1
: slitherTotal + ssaTotal + hintsTotal, : slitherTotal + ssaTotal + hintsTotal,
]); ])
}, [solhintEnabled, basicEnabled, slitherEnabled, showSlither]) }, [solhintEnabled, basicEnabled, slitherEnabled, showSlither])
const handleSlitherEnabled = async () => { const handleSlitherEnabled = async () => {
@ -524,36 +535,42 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
"remixd" "remixd"
); );
if (showSlither) { if (showSlither) {
setShowSlither(false); setShowSlither(false)
props.analysisModule.slitherEnabled = false
} }
if (!showSlither) { if (!showSlither) {
setShowSlither(true); setShowSlither(true)
props.analysisModule.slitherEnabled = true
} }
}; };
const handleBasicEnabled = () => { const handleBasicEnabled = () => {
if (basicEnabled) { if (basicEnabled) {
setBasicEnabled(false); setBasicEnabled(false)
props.analysisModule.basicEnabled = false
if (solhintEnabled) { if (solhintEnabled) {
setSelectedTab("solhint"); setSelectedTab("solhint")
} }
props.event.trigger("staticAnalysisWarning", [-1]); props.event.trigger("staticAnalysisWarning", [-1])
} else { } else {
setBasicEnabled(true); setBasicEnabled(true)
props.event.trigger("staticAnalysisWarning", [-1]); props.analysisModule.basicEnabled = true
props.event.trigger("staticAnalysisWarning", [-1])
} }
}; };
const handleLinterEnabled = () => { const handleLinterEnabled = () => {
if (solhintEnabled) { if (solhintEnabled) {
setSolhintEnabled(false); setSolhintEnabled(false);
props.analysisModule.solhintEnabled = false
if (basicEnabled) { if (basicEnabled) {
setSelectedTab("remix"); setSelectedTab("remix")
} }
props.event.trigger("staticAnalysisWarning", [-1]); props.event.trigger("staticAnalysisWarning", [-1])
} else { } else {
setSolhintEnabled(true); setSolhintEnabled(true)
props.event.trigger("staticAnalysisWarning", [-1]); props.analysisModule.solhintEnabled = true
props.event.trigger("staticAnalysisWarning", [-1])
} }
}; };
@ -623,11 +640,70 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
{hint.formattedMessage} {hint.formattedMessage}
</span> </span>
<br /> <br />
<span>{`${hint.column}:${hint.line}`}</span> <CustomTooltip
placement="right"
tooltipId="errorTooltip"
tooltipText={`Position in ${state.file}`}
tooltipClasses="text-nowrap"
>
<span>{`Pos: ${hint.column}:${hint.line}`}</span>
</CustomTooltip>
</div> </div>
</div> </div>
)) ))
: hintErrors.map((hint, index) => ( : !hideWarnings && !showLibsWarning && !basicEnabled && solhintEnabled ? hints.map((hint, index) => (
<div
key={index}
className={`${
hint.type === "warning"
? "alert alert-warning"
: "alert alert-danger"
}`}
style={{
cursor: "pointer",
overflow: "hidden",
textOverflow: "ellipsis",
}}
onClick={async () => {
await props.analysisModule.call(
"editor",
"discardHighlight"
);
await props.analysisModule.call(
"editor",
"highlight",
{
end: {
line: hint.line,
column: hint.column + 1,
},
start: {
line: hint.line,
column: hint.column,
},
},
state.file,
"",
{ focus: true }
);
}}
>
<div>
<span className="text-wrap">
{hint.formattedMessage}
</span>
<br />
<CustomTooltip
placement="right"
tooltipId="errorTooltip"
tooltipText={`Position in ${state.file}`}
tooltipClasses="text-nowrap"
>
<span>{`Pos: ${hint.column}:${hint.line}`}</span>
</CustomTooltip>
</div>
</div>
)) : hintErrors.map((hint, index) => (
<div <div
key={index} key={index}
className="alert alert-danger" className="alert alert-danger"
@ -671,7 +747,14 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
{hint.formattedMessage} {hint.formattedMessage}
</span> </span>
<br /> <br />
<span>{`${hint.column}:${hint.line}`}</span> <CustomTooltip
placement="right"
tooltipId="errorTooltip"
tooltipText={`Position in ${state.file}`}
tooltipClasses="text-nowrap"
>
<span>{`Pos: ${hint.column}:${hint.line}`}</span>
</CustomTooltip>
</div> </div>
</div> </div>
))} ))}
@ -733,7 +816,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
), ),
child: ( child: (
<> <>
{Object.entries(warningState).length > 0 ? ( {ssaWarnings.length > 0 ? (
<div id="staticanalysisresult"> <div id="staticanalysisresult">
<div className="mb-4 pt-2"> <div className="mb-4 pt-2">
<div> <div>
@ -751,6 +834,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
message={x.msg} message={x.msg}
opt={x.options} opt={x.options}
warningErrors={""} warningErrors={""}
ssaState={state}
editor={props.analysisModule} editor={props.analysisModule}
/> />
</div> </div>
@ -767,11 +851,29 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
message={x.msg} message={x.msg}
opt={x.options} opt={x.options}
warningErrors={""} warningErrors={""}
ssaState={state}
editor={props.analysisModule} editor={props.analysisModule}
/> />
</div> </div>
)) ))
: null} : !hideWarnings && !showLibsWarning && basicEnabled
? ssaWarnings.filter((x) => !x.options.isLibrary && x.hasWarning)
.map((x, i) => (
<div
data-id={`staticAnalysisModule${x.warningModuleName}${i}`}
id={`staticAnalysisModule${x.warningModuleName}${i}`}
key={i}
>
<ErrorRenderer
name={`staticAnalysisModule${x.warningModuleName}${i}`}
message={x.msg}
opt={x.options}
warningErrors={""}
ssaState={state}
editor={props.analysisModule}
/>
</div>
)) : null}
</div> </div>
</div> </div>
</div> </div>
@ -838,6 +940,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
name={`staticAnalysisModule${warning.warningModuleName}${index}`} name={`staticAnalysisModule${warning.warningModuleName}${index}`}
message={warning.msg} message={warning.msg}
opt={warning.options} opt={warning.options}
ssaState={state}
warningErrors={""} warningErrors={""}
editor={props.analysisModule} editor={props.analysisModule}
/> />
@ -854,6 +957,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
message={warning.msg} message={warning.msg}
opt={warning.options} opt={warning.options}
warningErrors={""} warningErrors={""}
ssaState={state}
editor={props.analysisModule} editor={props.analysisModule}
/> />
</div> </div>
@ -870,6 +974,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
name={`staticAnalysisModule${warning.warningModuleName}${index}`} name={`staticAnalysisModule${warning.warningModuleName}${index}`}
message={warning.msg} message={warning.msg}
opt={warning.options} opt={warning.options}
ssaState={state}
warningErrors={""} warningErrors={""}
editor={props.analysisModule} editor={props.analysisModule}
/> />
@ -919,7 +1024,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
.map((value: any) => { .map((value: any) => {
return value.map((x) => { return value.map((x) => {
return x._index.toString(); return x._index.toString();
}) });
}) })
.flat() .flat()
.every((el) => categoryIndex.includes(el)) .every((el) => categoryIndex.includes(el))
@ -1007,7 +1112,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
buttonText={`Analyze ${state.file}`} buttonText={`Analyze ${state.file}`}
title={`${runButtonTitle}`} title={`${runButtonTitle}`}
classList="btn btn-sm btn-primary btn-block" classList="btn btn-sm btn-primary btn-block"
onClick={async () => onClick={async () => {
await run( await run(
state.data, state.data,
state.source, state.source,
@ -1035,7 +1140,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
solhintEnabled, solhintEnabled,
basicEnabled basicEnabled
) )
} }}
disabled={ disabled={
state.data === null || state.data === null ||
!isSupportedVersion || !isSupportedVersion ||
@ -1043,10 +1148,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
} }
/> />
)} )}
{state && {ssaWarnings.length > 0 || hints.length > 0 ? (
state.data !== null &&
state.source !== null &&
state.file.length > 0 ? (
<div className="d-flex border-top flex-column"> <div className="d-flex border-top flex-column">
{slitherWarnings.length > 0 || {slitherWarnings.length > 0 ||
hints.length > 0 || hints.length > 0 ||
@ -1070,7 +1172,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</div> </div>
) : null} ) : null}
<div <div
className="border-top mt-2 pt-2 mb-2" className="border-top mt-2 pt-2 mb-3"
id="staticanalysisresult" id="staticanalysisresult"
> >
<RemixUiCheckbox <RemixUiCheckbox
@ -1089,7 +1191,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
name="hideWarnings" name="hideWarnings"
inputType="checkbox" inputType="checkbox"
checked={hideWarnings} checked={hideWarnings}
label="Hide warnings" label="Show errors only"
onClick={handleHideWarnings} onClick={handleHideWarnings}
onChange={() => {}} onChange={() => {}}
/> />
@ -1101,7 +1203,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
setSelectedTab(tabKey); setSelectedTab(tabKey);
}} }}
> >
<Nav variant="tabs" className="px-1"> <Nav variant="tabs">
{checkBasicStatus() ? ( {checkBasicStatus() ? (
<Nav.Item> <Nav.Item>
<Nav.Link <Nav.Link
@ -1113,7 +1215,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</Nav.Item> </Nav.Item>
) : null} ) : null}
{solhintEnabled ? ( {solhintEnabled ? (
<Nav.Item className="text-decoration-none font-weight-bold px-2"> <Nav.Item>
<Nav.Link <Nav.Link
className="text-decoration-none font-weight-bold px-2" className="text-decoration-none font-weight-bold px-2"
eventKey={tabKeys[0].tabKey} eventKey={tabKeys[0].tabKey}
@ -1123,7 +1225,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</Nav.Item> </Nav.Item>
) : null} ) : null}
{slitherEnabled && showSlither ? ( {slitherEnabled && showSlither ? (
<Nav.Item className="text-decoration-none font-weight-bold px-2"> <Nav.Item>
<Nav.Link <Nav.Link
className="text-decoration-none font-weight-bold px-2" className="text-decoration-none font-weight-bold px-2"
eventKey={tabKeys[2].tabKey} eventKey={tabKeys[2].tabKey}
@ -1136,13 +1238,13 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<Tab.Content> <Tab.Content>
<Tab.Pane eventKey={tabKeys[1].tabKey}> <Tab.Pane eventKey={tabKeys[1].tabKey}>
{tabKeys[1].child} {basicEnabled ? tabKeys[1].child : null}
</Tab.Pane> </Tab.Pane>
<Tab.Pane eventKey={tabKeys[0].tabKey}> <Tab.Pane eventKey={tabKeys[0].tabKey}>
{tabKeys[0].child} {solhintEnabled ? tabKeys[0].child : null}
</Tab.Pane> </Tab.Pane>
<Tab.Pane eventKey={tabKeys[2].tabKey}> <Tab.Pane eventKey={tabKeys[2].tabKey}>
{tabKeys[2].child} {slitherEnabled && showSlither ? tabKeys[2].child : null}
</Tab.Pane> </Tab.Pane>
</Tab.Content> </Tab.Content>
</TabContainer> </TabContainer>
@ -1151,7 +1253,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</div> </div>
</div> </div>
</div> </div>
); )
}; }
export default RemixUiStaticAnalyser; export default RemixUiStaticAnalyser;

@ -12,6 +12,9 @@ export declare class AnalysisTab extends ViewPlugin {
column: number; column: number;
line: number; line: number;
}[] }[]
basicEnabled: boolean;
solhintEnabled: boolean;
slitherEnabled: boolean;
internalCount: number internalCount: number
registry: Registry; registry: Registry;
element: HTMLDivElement; element: HTMLDivElement;

Loading…
Cancel
Save