Merge pull request #3779 from ethereum/solhint-ssa-fix

Static Analysis Checkbox Fix
pull/5370/head
yann300 1 year ago committed by GitHub
commit 99be572939
  1. 2
      apps/remix-ide/src/app/tabs/analysis-tab.js
  2. 10
      apps/remix-ide/src/remixAppManager.js
  3. 13
      apps/solhint/src/app/SolhintPluginClient.ts
  4. 4
      libs/remix-ui/checkbox/src/lib/remix-ui-checkbox.tsx
  5. 4
      libs/remix-ui/solidity-uml-gen/src/lib/components/UmlDownload.tsx
  6. 34
      libs/remix-ui/static-analyser/src/lib/Button/StaticAnalyserButton.tsx
  7. 4
      libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx
  8. 31
      libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts
  9. 8
      libs/remix-ui/static-analyser/src/lib/components/BasicTitle.tsx
  10. 273
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  11. 17
      libs/remix-ui/vertical-icons-panel/src/lib/components/Badge.tsx
  12. 6
      libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx

@ -57,7 +57,7 @@ class AnalysisTab extends ViewPlugin {
}
})
}
setDispatch (dispatch) {
this.dispatch = dispatch
this.renderComponent()

@ -228,16 +228,6 @@ export class RemixAppManager extends PluginManager {
sticky: true,
group: 7
})
await this.call('filePanel', 'registerContextMenuItem', {
id: 'solhint',
name: 'lintContractCustomAction',
label: 'Lint Contract',
type: [],
extension: ['.sol'],
path: [],
pattern: [],
sticky: true
})
}
}

@ -11,7 +11,7 @@ import deprecations from 'solhint/lib/rules/deprecations'
import miscellaneous from 'solhint/lib/rules/miscellaneous'
import { customAction } from '@remixproject/plugin-api'
type Report = {
type Report = {
line: number,
column: number,
severity: string,
@ -53,7 +53,7 @@ export class SolHint extends PluginClient {
this.triggerLinter = false
}
/**
* method to handle context menu action in file explorer for
* method to handle context menu action in file explorer for
* solhint plugin
* @param action interface CustomAction
*/
@ -65,7 +65,6 @@ export class SolHint extends PluginClient {
async lintContract(file: string) {
const hints = await this.lint(file)
console.log({ hints })
this.emit('lintingFinished', hints)
}
@ -92,6 +91,8 @@ export class SolHint extends PluginClient {
line: report.line - 1
}
})
this.emit('lintingFinished', hints)
return hints
}
@ -99,7 +100,7 @@ export class SolHint extends PluginClient {
2: 'error',
3: 'warning'
}
rules = {
'solhint:recommended': () => {
const enabledRules = {}
@ -129,7 +130,7 @@ export class SolHint extends PluginClient {
return enabledRules
}
}
coreRules() {
return [
...bestPractises(),
@ -140,6 +141,6 @@ export class SolHint extends PluginClient {
...security()
]
}
}

@ -37,7 +37,7 @@ export const RemixUiCheckbox = ({
visibility,
optionalClassName = '',
display = 'flex',
disabled = false,
disabled,
tooltipPlacement = 'right',
}: RemixUiCheckboxProps) => {
@ -58,7 +58,7 @@ export const RemixUiCheckbox = ({
checked={checked}
disabled={disabled}
/>
<label className="form-check-label custom-control-label" id={`heading${categoryId}`} style={{ paddingTop: '0.15rem' }}>
<label className="form-check-label custom-control-label" id={`heading${categoryId}`} style={{ paddingTop: '0.15rem' }} aria-disabled={disabled}>
{name ? <div className="font-weight-bold">{itemName}</div> : ''}
{label}
</label>

@ -86,7 +86,7 @@ export default function UmlDownload(props: UmlDownloadProps) {
_paq.push([
"trackEvent",
"solidityumlgen",
"download",
"umlpngdownload",
"downloadAsPng",
]);
props.download("png")
@ -115,7 +115,7 @@ export default function UmlDownload(props: UmlDownloadProps) {
_paq.push([
"trackEvent",
"solUmlgen",
"download",
"umlpdfdownload",
"downloadAsPdf",
]);
props.download("pdf")

@ -19,20 +19,32 @@ const StaticAnalyserButton = ({
const defaultStyle = "btn btn-sm w-25 btn-primary"
const newclassList = disabled && classList.length > 0 ? `${classList} disabled` :
classList.length === 0 && disabled ? `${defaultStyle} disabled` : classList.length > 0 ? `${classList}` : defaultStyle
return (
const buttonWithoutTooltip = () => (
<button id="staticAnalysisRunBtn" className={newclassList} disabled={disabled} onClick={onClick}>
<CustomTooltip
placement="right"
tooltipId="ssaRunButtonTooltip"
tooltipClasses="text-nowrap"
tooltipText={title}
>
<span className="pl-3 pr-4">
{buttonText}
</span>
</CustomTooltip>
<span className="pl-3 pr-4">
{buttonText}
</span>
</button>
)
const buttonWithTooltip = () => (
<button id="staticAnalysisRunBtn" className={newclassList} disabled={disabled} onClick={onClick}>
<CustomTooltip
placement="right"
tooltipId="ssaRunButtonTooltip"
tooltipClasses="text-nowrap"
tooltipText={title}
>
<span className="pl-3 pr-4">
{buttonText}
</span>
</CustomTooltip>
</button>)
return (
title && title.length > 0 ? buttonWithTooltip() : buttonWithoutTooltip()
)
}
export default StaticAnalyserButton

@ -47,9 +47,9 @@ const ErrorRenderer = ({ message, opt, editor, name }: ErrorRendererProps) => {
return (
<div>
<div className={`sol ${opt.type} ${classList}`}>
<span className='d-flex flex-column' data-id={`${name}Button`} onClick={async () => await handlePointToErrorOnClick(opt.location, opt.fileName)}>
<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' }}>
<span className='h6 font-weight-bold'>{opt.name}</span>
{ opt.item.warning }
<span>{ opt.item.warning }</span>
{opt.item.more
? <span><a href={opt.item.more} target='_blank'>more</a></span>
: <span> </span>

@ -1,10 +1,11 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CompilationResult, SourceWithTarget } from '@remixproject/plugin-api'
import React from 'react' //eslint-disable-line
import { AnalysisTab, RemixUiStaticAnalyserReducerActionType, RemixUiStaticAnalyserState, SolHintReport, SlitherAnalysisResults } from '../../staticanalyser'
import { RemixUiStaticAnalyserProps } from '@remix-ui/static-analyser'
/**
*
*
* @param analysisModule { AnalysisTab } AnalysisTab ViewPlugin
* @param dispatch { React.Dispatch<any> } analysisReducer function's dispatch method
*/
@ -24,8 +25,8 @@ export const compilation = (analysisModule: AnalysisTab,
/**
* Run the analysis on the currently compiled contract
* @param lastCompilationResult
* @param lastCompilationSource
* @param lastCompilationResult
* @param lastCompilationSource
* @param currentFile {string} current file path
* @param state { RemixUiStaticAnalyserState}
* @param props {RemixUiStaticAnalyserProps}
@ -42,8 +43,12 @@ export const compilation = (analysisModule: AnalysisTab,
* @returns {Promise<void>}
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function run (lastCompilationResult, lastCompilationSource, currentFile: string, state: RemixUiStaticAnalyserState, props: RemixUiStaticAnalyserProps, isSupportedVersion, showSlither, categoryIndex: number[], groupedModules, runner, _paq, message, showWarnings, allWarnings: React.RefObject<any>, warningContainer: React.RefObject<any>, calculateWarningStateEntries: (e:[string, any][]) => {length: number, errors: any[] }, warningState, setHints: React.Dispatch<React.SetStateAction<SolHintReport[]>>, hints: SolHintReport[], setSlitherWarnings: React.Dispatch<React.SetStateAction<any[]>>, setSsaWarnings: React.Dispatch<React.SetStateAction<any[]>>) {
export async function run (lastCompilationResult, lastCompilationSource, currentFile: string, state: RemixUiStaticAnalyserState, props: RemixUiStaticAnalyserProps, isSupportedVersion, showSlither, categoryIndex: number[], groupedModules, runner, _paq, message, showWarnings, allWarnings: React.RefObject<any>, warningContainer: React.RefObject<any>, calculateWarningStateEntries: (e:[string, any][]) => {length: number, errors: any[] }, warningState, setHints: React.Dispatch<React.SetStateAction<SolHintReport[]>>, hints: SolHintReport[], setSlitherWarnings: React.Dispatch<React.SetStateAction<any[]>>, setSsaWarnings: React.Dispatch<React.SetStateAction<any[]>>,
slitherEnabled: boolean, setStartAnalysis: React.Dispatch<React.SetStateAction<boolean>>) {
setStartAnalysis(true)
setHints([])
setSsaWarnings([])
setSlitherWarnings([])
if (!isSupportedVersion) return
if (state.data !== null) {
if (lastCompilationResult && (categoryIndex.length > 0 || showSlither)) {
@ -54,7 +59,7 @@ export async function run (lastCompilationResult, lastCompilationSource, current
const hintsResult = await props.analysisModule.call('solhint', 'lint', state.file)
setHints(hintsResult)
const warningResult = calculateWarningStateEntries(Object.entries(warningState))
props.analysisModule.emit('statusChanged', { key: hints.length+warningResult.length,
props.analysisModule.emit('statusChanged', { key: hints.length+warningResult.length,
title: `${hints.length+warningResult.length} warning${hints.length+warningResult.length === 1 ? '' : 's'}`, type: 'warning'})
// Remix Analysis
@ -117,11 +122,12 @@ export async function run (lastCompilationResult, lastCompilationSource, current
}
warningErrors.push(options)
warningMessage.push({ msg, options, hasWarning: true, warningModuleName: moduleName })
setSsaWarnings(warningErrors)
setSsaWarnings(warningMessage)
}
}
// Slither Analysis
if (showSlither) {
if (showSlither && slitherEnabled) {
setSlitherWarnings([])
try {
const compilerState = await props.analysisModule.call('solidity', 'getCompilerState')
const { currentVersion, optimize, evmVersion } = compilerState
@ -169,7 +175,7 @@ export async function run (lastCompilationResult, lastCompilationSource, current
}
const msg = message(item.title, item.description, item.more ?? '', fileName, locationString)
const options = {
type: item.sourceMap[0].type,
type: item.sourceMap && item.sourceMap.length > 0 ? item.sourceMap[0].type : '',
useSpan: true,
errFile: fileName,
fileName,
@ -183,11 +189,9 @@ export async function run (lastCompilationResult, lastCompilationSource, current
location: location
}
const slitherwarnings = []
setSlitherWarnings((prev) => {
slitherwarnings.push(...prev)
slitherwarnings.push({ msg, options, hasWarning: true, warningModuleName: 'Slither Analysis' })
return slitherwarnings
prev.push({ msg, options, hasWarning: true, warningModuleName: 'Slither Analysis' })
return prev
})
}
showWarnings(warningMessage, 'warningModuleName')
@ -197,6 +201,7 @@ export async function run (lastCompilationResult, lastCompilationSource, current
showWarnings(warningMessage, 'warningModuleName')
}
} else showWarnings(warningMessage, 'warningModuleName')
setStartAnalysis(false)
} else {
if (categoryIndex.length) {
warningContainer.current.innerText = 'No compiled AST available'

@ -32,13 +32,13 @@ export function calculateWarningStateEntries(entries: [string, any][]) {
export function BasicTitle(props: BasicTitleProps) {
return (
<span>Remix{props.warningStateEntries.length > 0 && !props.hideWarnings ? <i data-id="StaticAnalysisErrorCount" className="badge badge-info rounded-circle ml-1">{calculateWarningStateEntries(props.warningStateEntries).length}</i>: (
<i className="badge badge-info rounded-circle ml-1">
<span>Remix{props.warningStateEntries.length > 0 ? !props.hideWarnings ? <i data-id="StaticAnalysisErrorCount" className={`badge ${calculateWarningStateEntries(props.warningStateEntries).length > 0 ? 'badge-warning' : 'badge-danger'} rounded-circle ml-1 text-center`}>{calculateWarningStateEntries(props.warningStateEntries).length}</i>: (
<i className="badge badge-warning rounded-circle ml-1 text-center">
{
calculateWarningStateEntries(props.warningStateEntries).errors.length
}
</i>
)}
) : null}
</span>
)
}
}

@ -1,3 +1,5 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useEffect, useState, useReducer, useRef, Fragment } from 'react' // eslint-disable-line
import Button from './Button/StaticAnalyserButton' // eslint-disable-line
import { util } from '@remix-project/remix-lib'
@ -69,6 +71,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
const [basicEnabled, setBasicEnabled] = useState(true)
const [solhintEnabled, setSolhintEnabled] = useState(true) // assuming that solhint is always enabled
const [showSlither, setShowSlither] = useState(false)
const [slitherEnabled, setSlitherEnabled] = useState(false)
const [startAnalysis, setStartAnalysis] = useState(false)
const [isSupportedVersion, setIsSupportedVersion] = useState(false)
let [showLibsWarning, setShowLibsWarning] = useState(false) // eslint-disable-line prefer-const
const [categoryIndex, setCategoryIndex] = useState(groupedModuleIndex(groupedModules))
@ -77,7 +81,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
const [hints, setHints] = useState<SolHintReport[]>([])
const [slitherWarnings, setSlitherWarnings] = useState([])
const [ssaWarnings, setSsaWarnings] = useState([])
const warningContainer = useRef(null)
const allWarnings = useRef({})
const [state, dispatch] = useReducer(analysisReducer, initialState)
@ -109,16 +113,9 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
useEffect(() => {
setWarningState({})
const runAnalysis = async () => {
await run(state.data, state.source, state.file, state, props, isSupportedVersion, showSlither, categoryIndex, groupedModules, runner,_paq, message, showWarnings, allWarnings, warningContainer,calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings)
await run(state.data, state.source, state.file, state, props, isSupportedVersion, showSlither, categoryIndex, groupedModules, runner,_paq, message, showWarnings, allWarnings, warningContainer,calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings, slitherEnabled, setStartAnalysis)
}
props.event.trigger('staticAnaysisWarning', [])
// if (basicEnabled) {
// if (state.data !== null) {
// runAnalysis().catch(console.error);
// }
// } else {
// props.event.trigger('staticAnaysisWarning', [])
// }
return () => { }
}, [state])
@ -126,6 +123,17 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
props.analysisModule.call('solidity', 'getCompilerState').then((compilerState) => setDisableForRun(compilerState.currentVersion))
}, [])
useEffect(() => {
const checkRemixdActive = async () => {
const remixdActive = await props.analysisModule.call('manager', 'isActive', 'remixd')
if (remixdActive) {
setSlitherEnabled(true)
setShowSlither(true)
}
}
checkRemixdActive()
}, [props])
useEffect(() => {
props.analysisModule.on('filePanel', 'setWorkspace', (currentWorkspace) => {
// Reset warning state
@ -138,9 +146,13 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
setSlitherWarnings([])
setSsaWarnings([])
// Show 'Enable Slither Analysis' checkbox
if (currentWorkspace && currentWorkspace.isLocalhost === true) setShowSlither(true)
if (currentWorkspace && currentWorkspace.isLocalhost === true) {
setShowSlither(true)
setSlitherEnabled(true)
}
else {
setShowSlither(false)
setSlitherEnabled(false)
}
})
props.analysisModule.on('manager', 'pluginDeactivated', (plugin) => {
@ -150,6 +162,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
setWarningState([])
setHints([])
setSlitherWarnings([])
setSlitherEnabled(false)
setSsaWarnings([])
// Reset badge
props.event.trigger('staticAnaysisWarning', [])
@ -203,6 +216,12 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
setWarningState(newWarningState)
}
useEffect(() => {
if(hints.length > 0) {
props.event.trigger('staticAnaysisWarning', [hints.length])
}
},[hints.length, state])
const showWarnings = (warningMessage, groupByKey) => {
const resultArray = []
warningMessage.map(x => {
@ -225,7 +244,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
filterWarnings()
}
const handleCheckAllModules = (groupedModules) => {
const index = groupedModuleIndex(groupedModules)
if (index.every(el => categoryIndex.includes(el))) {
@ -256,7 +275,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
const checkRemixd = await props.analysisModule.call('manager', 'isActive', 'remixd')
if (showSlither) {
setShowSlither(false)
}
}
if(!showSlither) {
setShowSlither(true)
}
@ -359,7 +378,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
}
const hintErrors = hints.filter(hint => hint.type === 'error')
const slitherErrors = slitherWarnings.filter(slitherError => slitherError.options.type === 'error')
const noLibSlitherWarnings = slitherWarnings.filter(w => !w.options.isLibrary)
const slitherErrors = noLibSlitherWarnings.filter(slitherError => slitherError.options.type === 'error')
const tabKeys = [
{
@ -379,33 +399,32 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
? "alert alert-warning"
: "alert alert-danger"
}`}
style={{ cursor: "pointer" }}
>
<div
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,
},
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,
},
state.file,
"",
{ focus: true }
);
}}
>
start: {
line: hint.line,
column: hint.column,
},
},
state.file,
"",
{ focus: true }
);
}}
>
<div>
<span className="text-wrap">
{hint.formattedMessage}
</span>
@ -419,36 +438,36 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<div
key={index}
className="alert alert-danger"
style={{ cursor: "pointer" }}
>
<div
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,
},
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,
},
state.file,
"",
{ focus: true }
);
}}
>
<span className="text-wrap">
start: {
line: hint.line,
column: hint.column,
},
},
state.file,
"",
{ focus: true }
);
}}
>
<div>
<span className="text-wrap" style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>
{hint.formattedMessage}
</span>
<br />
<span>{hint.type}</span>
<br />
<span>{`${hint.column}:${hint.line}`}</span>
@ -458,7 +477,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</Fragment>
</div>
</div>
) : <span className="display-6">No Results.</span>}
) : state.data && state.file.length > 0 && state.source && startAnalysis && hints.length > 0 ? <span className="ml-4 spinner-grow-sm d-flex justify-content-center">Loading...</span> : <span className="display-6 text-center">Nothing to report</span>}
</>
),
title: (
@ -466,11 +485,13 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
Linter
{hints.length > 0 ? (
hideWarnings ? (
<i className="badge badge-info rounded-circle ml-1">
<i className={`badge ${hints.filter(x => x.type === 'error').length > 0
? `badge-danger` : 'badge-warning'} rounded-circle ml-1 text-center`}>
{hintErrors.length}
</i>
) : (
<i className="badge badge-info rounded-circle ml-1">
<i className={`badge ${hints.filter(x => x.type === 'error').length > 0
? `badge-danger` : 'badge-warning'} rounded-circle ml-1 text-center`}>
{hints.length}
</i>
)
@ -493,9 +514,10 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<div className="mb-4 pt-2">
{Object.entries(warningState).map((element, index) => (
<div key={index}>
{element[1]["map"](
{ !hideWarnings && element[1]['length'] > 0 ? <span className="text-dark h6">{element[0]}</span> : null}
{!hideWarnings ? element[1]["map"](
(x,i) => // eslint-disable-line dot-notation
x.hasWarning && !hideWarnings
x.hasWarning
? ( // eslint-disable-next-line dot-notation
<div
data-id={`staticAnalysisModule${x.warningModuleName}${i}`}
@ -511,13 +533,30 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
/>
</div>
) : null
)}
) : element[1]["map"](
(x,i) => // eslint-disable-line dot-notation
!x.hasWarning
? ( // eslint-disable-next-line dot-notation
<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={x.warningErrors}
editor={props.analysisModule}
/>
</div>
) : null)}
{}
</div>
))}
</div>
</div>
) : <span className="display-6">No Results.</span>}
) : state.data && state.file.length > 0 && state.source && startAnalysis && Object.entries(warningState).length > 0 ? <span className="ml-4 spinner-grow-sm d-flex justify-content-center">Loading...</span> : <span className="display-6 text-center">Nothing to report</span>}
</>
),
},
@ -528,12 +567,16 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
Slither
{slitherWarnings.length > 0 ? (
hideWarnings ? (
<i className="badge badge-info rounded-circle ml-1">
<i className="badge badge-warning rounded-circle ml-1">
{slitherErrors.length}
</i>
) : (
<i className="badge badge-info rounded-circle ml-1">
{slitherWarnings.length}
) : showLibsWarning === true && hideWarnings === false ? (
<i className={`badge ${slitherErrors.length > 0 ? `badge-danger` : 'badge-warning'} rounded-circle ml-1 text-center`}>
{slitherWarnings.length}
</i>
) : (
<i className={`badge ${slitherErrors.length > 0 ? `badge-danger` : 'badge-warning'} rounded-circle ml-1 text-center`}>
{noLibSlitherWarnings.length}
</i>
)
) : null}
@ -545,8 +588,8 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<div id="solhintlintingresult" className="mb-5">
<div className="mb-4 pt-2">
<Fragment>
{!hideWarnings
? showLibsWarning ? slitherWarnings.filter(warning => warning.isLibrary).map((warning, index) => (
{!hideWarnings
? showLibsWarning ? slitherWarnings.map((warning, index) => (
<div
data-id={`staticAnalysisModule${warning.warningModuleName}${index}`}
id={`staticAnalysisModule${warning.warningModuleName}${index}`}
@ -560,7 +603,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
editor={props.analysisModule}
/>
</div>
)) : slitherWarnings.map((warning, index) => (
)) : noLibSlitherWarnings.map((warning, index) => (
<div
data-id={`staticAnalysisModule${warning.warningModuleName}${index}`}
id={`staticAnalysisModule${warning.warningModuleName}${index}`}
@ -580,7 +623,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
data-id={`staticAnalysisModule${warning.warningModuleName}${index}`}
id={`staticAnalysisModule${warning.warningModuleName}${index}`}
key={index}
>
>
<ErrorRenderer
name={`staticAnalysisModule${warning.warningModuleName}${index}`}
message={warning.msg}
@ -593,7 +636,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
</Fragment>
</div>
</div>
) : <span className="display-6">No Result</span>}
) : state.data && state.file.length > 0 && state.source && startAnalysis && slitherWarnings.length > 0 ? <span className="ml-4 spinner-grow-sm d-flex justify-content-center">Loading...</span> : <span className="display-6 text-center">Nothing to report</span>}
</>
),
},
@ -615,7 +658,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<RemixUiCheckbox
id="checkAllEntries"
inputType="checkbox"
title="Remix analysis is a basic analysis tool for Remix Ide."
title="Remix analysis runs a basic analysis."
checked={Object.values(groupedModules).map((value: any) => {
return (value.map(x => {
return x._index.toString()
@ -629,55 +672,63 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
tooltipPlacement={'bottom-start'}
optionalClassName="mr-3"
/>
<RemixUiCheckbox
id="solhintstaticanalysis"
inputType="checkbox"
title="Run solhint static analysis."
title="Linter runs SolHint static analysis."
onClick={handleLinterEnabled}
checked={solhintEnabled}
checked={solhintEnabled }
label="Linter"
onChange={() => {}}
tooltipPlacement={'top-start'}
tooltipPlacement={'bottom-start'}
optionalClassName="mr-3"
/>
<RemixUiCheckbox
id="enableSlither"
inputType="checkbox"
onClick={handleSlitherEnabled}
checked={showSlither}
disabled={true}
checked={showSlither && slitherEnabled}
disabled={slitherEnabled === false}
tooltipPlacement="bottom-start"
label="Slither"
onChange={() => {}}
optionalClassName="mr-3"
title="To run Slither analysis, Remix IDE must be connected to your local filesystem with remixd."
title={slitherEnabled ? "Slither runs Slither static analysis." : "To run Slither analysis, Remix IDE must be connected to your local filesystem with Remixd."}
/>
</div>
<Button
{state.data && state.file.length > 0 && state.source ? <Button
buttonText={`Analyse ${state.file}`}
classList="btn btn-sm btn-primary btn-block"
onClick={async () => await run(state.data, state.source, state.file, state , props, isSupportedVersion, showSlither, categoryIndex, groupedModules, runner,_paq,
message, showWarnings, allWarnings, warningContainer, calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings, slitherEnabled, setStartAnalysis)}
disabled={(state.data === null || !isSupportedVersion) || (!solhintEnabled && !basicEnabled) }
/> : <Button
buttonText={`Analyze ${state.file}`}
title={`${runButtonTitle}`}
classList="btn btn-sm btn-primary btn-block"
onClick={async () => await run(state.data, state.source, state.file, state , props, isSupportedVersion, showSlither, categoryIndex, groupedModules, runner,_paq,
message, showWarnings, allWarnings, warningContainer, calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings)}
message, showWarnings, allWarnings, warningContainer, calculateWarningStateEntries, warningState, setHints, hints, setSlitherWarnings, setSsaWarnings, slitherEnabled, setStartAnalysis)}
disabled={(state.data === null || !isSupportedVersion) || (!solhintEnabled && !basicEnabled) }
/>
/>}
{state && state.data !== null && state.source !== null && state.file.length > 0 ? (<div className="d-flex border-top flex-column">
<div className="mt-4 p-2 d-flex border-top flex-column">
<span>Last results for:</span>
<span
className="text-break break-word word-break font-weight-bold"
id="staticAnalysisCurrentFile"
>
{state.file}
</span>
{slitherWarnings.length > 0 || hints.length > 0 || Object.entries(warningState).length > 0 ? (
<div className={`mt-4 p-2 d-flex ${slitherWarnings.length > 0 || hints.length > 0 || Object.entries(warningState).length > 0 ? 'border-top' : ''} flex-column`}>
<span>Last results for:</span>
<span
className="text-break break-word word-break font-weight-bold"
id="staticAnalysisCurrentFile"
>
{state.file}
</span>
</div>
<div className="border-top mt-3 pt-2 mb-2" id="staticanalysisresult">
) : null}
<div className="border-top mt-2 pt-2 mb-2" id="staticanalysisresult">
<RemixUiCheckbox
id="showLibWarnings"
name="showLibWarnings"
categoryId="showLibWarnings"
title="When checked, the results are also displayed for external contract libraries."
inputType="checkbox"
checked={showLibsWarning}
label="Show warnings for external libraries"
@ -688,7 +739,6 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
<RemixUiCheckbox
id="hideWarnings"
name="hideWarnings"
title="When checked, general warnings from analysis are hidden."
inputType="checkbox"
checked={hideWarnings}
label="Hide warnings"
@ -696,13 +746,16 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
onChange={() => {}}
/>
</div>
<Tabs defaultActiveKey={tabKeys[0].tabKey}>
<Tabs
defaultActiveKey={tabKeys[0].tabKey}
className="px-1"
>
{
checkBasicStatus() ? <Tab
key={tabKeys[1].tabKey}
title={tabKeys[1].title}
eventKey={tabKeys[1].tabKey}
tabClassName="text-decoration-none font-weight-bold"
tabClassName="text-decoration-none font-weight-bold px-2"
>
{tabKeys[1].child}
</Tab> : null
@ -711,15 +764,15 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
key={tabKeys[0].tabKey}
title={tabKeys[0].title}
eventKey={tabKeys[0].tabKey}
tabClassName="text-decoration-none font-weight-bold"
tabClassName="text-decoration-none font-weight-bold px-2"
>
{tabKeys[0].child}
</Tab> : null}
{ showSlither ? <Tab
{ showSlither && slitherEnabled ? <Tab
key={tabKeys[2].tabKey}
title={tabKeys[2].title}
eventKey={tabKeys[2].tabKey}
tabClassName="text-decoration-none font-weight-bold"
tabClassName="text-decoration-none font-weight-bold px-2"
>
{tabKeys[2].child}
</Tab> : null }

@ -1,4 +1,6 @@
import React from 'react'
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import React, { useEffect } from 'react'
import { BadgeStatus } from './Icon'
import { CustomTooltip } from '@remix-ui/helper'
import { FormattedMessage } from 'react-intl'
@ -48,23 +50,18 @@ function Badge ({ badgeStatus }: BadgeProps) {
<>
{
badgeStatus && checkStatusKeyValue(badgeStatus.key, badgeStatus.type) ? (
<CustomTooltip
placement={'right'}
tooltipClasses="text-nowrap"
tooltipId="verticalItemsbadge"
tooltipText={badgeStatus.pluginName && badgeStatus.pluginName === 'solidityStaticAnalysis' ? 'There are multiple warnings or errors that might need to be fixed.' :badgeStatus.title}
>
<i
className={`${resolveClasses(badgeStatus.key, badgeStatus.type!)}`}
aria-hidden="true"
>
{ badgeStatus.pluginName && badgeStatus.pluginName === 'solidityStaticAnalysis' ? <span>&nbsp;</span> : badgeStatus.text }
{ badgeStatus.pluginName && badgeStatus.pluginName === 'solidityStaticAnalysis' ? badgeStatus.type === 'warning' || badgeStatus.type === 'error' ? <span>
<i className="far fa-exclamation-triangle"></i></span>
: <span>&nbsp;</span> : badgeStatus.text }
</i>
</CustomTooltip>
) : null
}
</>
)
}
export default Badge
export default Badge

@ -40,7 +40,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
* for example : 'downloadAsZip' with type ['file','folder'] will work on files and folders when multiple are selected
**/
const nonRootFocus = focus.filter((el) => { return !(el.key === '' && el.type === 'folder') })
if(focus[0].key === "contextMenu"){
return true
}
@ -175,7 +175,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
publishFolderToGist(path, type)
break
default:
_paq.push(['trackEvent', 'fileExplorer', 'customAction', `${item.id}/${item.name}`])
_paq.push(['trackEvent', 'fileExplorer', 'contextMenu', `${item.id}/${item.name}`])
emit && emit({ ...item, path: [path] } as customAction)
break
}
@ -183,7 +183,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
}}>{intl.formatMessage({id: `filePanel.${item.id}`, defaultMessage: item.label || item.name})}</li>
}))
}
return (
<div
id="menuItemsContainer"

Loading…
Cancel
Save