From f4ec9c142d2b764818a6898490caeb346f1afd7e Mon Sep 17 00:00:00 2001 From: Joseph Izang Date: Thu, 29 Jun 2023 13:03:42 +0100 Subject: [PATCH] fixed review comments --- .../src/tests/staticAnalysis.test.ts | 2 +- .../src/lib/actions/staticAnalysisActions.ts | 6 - .../src/lib/remix-ui-static-analyser.tsx | 1238 ++++++++++------- .../src/lib/components/Badge.tsx | 2 +- 4 files changed, 775 insertions(+), 473 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts index 64457204c0..446ea13622 100644 --- a/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts +++ b/apps/remix-ide-e2e/src/tests/staticAnalysis.test.ts @@ -34,7 +34,7 @@ module.exports = { 'run analysis and filter results': function (browser: NightwatchBrowser) { browser .clickLaunchIcon('filePanel') - .click('*[data-id="treeViewLitreeViewItemcontracts"]') // + .click('*[data-id="treeViewLitreeViewItemcontracts"]') .click('*[data-id="treeViewLitreeViewItemcontracts/2_Owner.sol"]') .clickLaunchIcon('solidity') .click('*[id="compileBtn"]') diff --git a/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts b/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts index 942c926feb..1ace7d5ff3 100644 --- a/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts +++ b/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts @@ -52,20 +52,14 @@ slitherEnabled: boolean, setStartAnalysis: React.Dispatch { - const [runner] = useState(new CodeAnalysis()) + const [runner] = useState(new CodeAnalysis()); const preProcessModules = (arr: any) => { return arr.map((Item, i) => { - const itemObj = new Item() - itemObj._index = i - itemObj.categoryDisplayName = itemObj.category.displayName - itemObj.categoryId = itemObj.category.id - return itemObj - }) - } + const itemObj = new Item(); + itemObj._index = i; + itemObj.categoryDisplayName = itemObj.category.displayName; + itemObj.categoryId = itemObj.category.id; + return itemObj; + }); + }; const groupedModules = util.groupBy( preProcessModules(runner.modules()), - 'categoryId' - ) + "categoryId" + ); const getIndex = (modules, array) => { - Object.values(modules).map((value: {_index}) => { + Object.values(modules).map((value: { _index }) => { if (Array.isArray(value)) { value.forEach((x) => { - array.push(x._index.toString()) - }) + array.push(x._index.toString()); + }); } else { - array.push(value._index.toString()) + array.push(value._index.toString()); } - }) - } + }); + }; const groupedModuleIndex = (modules) => { - const indexOfCategory = [] + const indexOfCategory = []; if (!_.isEmpty(modules)) { - getIndex(modules, indexOfCategory) + getIndex(modules, indexOfCategory); } - return indexOfCategory - } - 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)) - const [warningState, setWarningState] = useState({}) - const [hideWarnings, setHideWarnings] = useState(false) - const [hints, setHints] = useState([]) - const [slitherWarnings, setSlitherWarnings] = useState([]) - const [ssaWarnings, setSsaWarnings] = useState([]) - const [selectedTab, setSelectedTab] = useState('remix') - - - const warningContainer = useRef(null) - const allWarnings = useRef({}) - const [state, dispatch] = useReducer(analysisReducer, initialState) - const [runButtonTitle, setRunButtonTitle] = useState(`Run analysis`) + return indexOfCategory; + }; + 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) + ); + const [warningState, setWarningState] = useState({}); + const [hideWarnings, setHideWarnings] = useState(false); + const [hints, setHints] = useState([]); + const [slitherWarnings, setSlitherWarnings] = useState([]); + const [ssaWarnings, setSsaWarnings] = useState([]); + const [selectedTab, setSelectedTab] = useState("remix"); + const warningContainer = useRef(null); + const allWarnings = useRef({}); + const [state, dispatch] = useReducer(analysisReducer, initialState); + const [runButtonTitle, setRunButtonTitle] = useState(`Run analysis`); /** * Disable static analysis for contracts whose compiler version is @@ -99,201 +111,244 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { */ const setDisableForRun = (version: string) => { const truncateVersion = (version: string) => { - const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version) - return tmp ? tmp[1] : version - } - if (version && version != '' && !semver.gt(truncateVersion(version), '0.4.12')) { - setIsSupportedVersion(false) - setRunButtonTitle('Select Solidity compiler version greater than 0.4.12.') + const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version); + return tmp ? tmp[1] : version; + }; + if ( + version && + version != "" && + !semver.gt(truncateVersion(version), "0.4.12") + ) { + setIsSupportedVersion(false); + setRunButtonTitle( + "Select Solidity compiler version greater than 0.4.12." + ); } else { - setIsSupportedVersion(true) - setRunButtonTitle(`${state && state.data && state.file.length > 0 ? 'Run analysis': 'To run analysis tools, first compile a contract.'}`) + setIsSupportedVersion(true); + setRunButtonTitle( + `${ + state && state.data && state.file.length > 0 + ? "Run analysis" + : "To run analysis tools, first compile a contract." + }` + ); } - } + }; useEffect(() => { - compilation(props.analysisModule, dispatch) - }, [props]) + compilation(props.analysisModule, dispatch); + }, [props]); useEffect(() => { - props.analysisModule.call('solidity', 'getCompilerState').then((compilerState) => setDisableForRun(compilerState.currentVersion)) - props.event.trigger('staticAnalysisWarning', [-1]) - }, []) + props.analysisModule + .call("solidity", "getCompilerState") + .then((compilerState) => setDisableForRun(compilerState.currentVersion)); + props.event.trigger("staticAnalysisWarning", [-1]); + }, []); useEffect(() => { - props.event.trigger('staticAnalysisWarning', [-1]) - }, [state]) + props.event.trigger("staticAnalysisWarning", [-1]); + }, [state]); useEffect(() => { - props.analysisModule.on('solidity', 'compilationFinished', (fileName, source, languageVersion, data) => { - setHints([]) - setSlitherWarnings([]) - setSsaWarnings([]) - }) - }, [state]) + props.analysisModule.on( + "solidity", + "compilationFinished", + (fileName, source, languageVersion, data) => { + setHints([]); + setSlitherWarnings([]); + setSsaWarnings([]); + } + ); + }, [state]); useEffect(() => { const checkRemixdActive = async () => { - const remixdActive = await props.analysisModule.call('manager', 'isActive', 'remixd') + const remixdActive = await props.analysisModule.call( + "manager", + "isActive", + "remixd" + ); if (remixdActive) { - setSlitherEnabled(true) - setShowSlither(true) + setSlitherEnabled(true); + setShowSlither(true); } - } - checkRemixdActive() - props.event.trigger('staticAnalysisWarning', [-1]) - }, [props]) + }; + checkRemixdActive(); + props.event.trigger("staticAnalysisWarning", [-1]); + }, [props]); useEffect(() => { - props.analysisModule.on('filePanel', 'setWorkspace', (currentWorkspace) => { + props.analysisModule.on("filePanel", "setWorkspace", (currentWorkspace) => { // Reset warning state - setWarningState([]) + setWarningState([]); // Reset badge // Reset state - dispatch({ type: '', payload: initialState }) - setHints([]) - setSlitherWarnings([]) - setSsaWarnings([]) + dispatch({ type: "", payload: initialState }); + setHints([]); + setSlitherWarnings([]); + setSsaWarnings([]); // Show 'Enable Slither Analysis' checkbox if (currentWorkspace && currentWorkspace.isLocalhost === true) { - setShowSlither(true) - setSlitherEnabled(true) - } - else { - setShowSlither(false) - setSlitherEnabled(false) + setShowSlither(true); + setSlitherEnabled(true); + } else { + setShowSlither(false); + setSlitherEnabled(false); } setTimeout(() => { - props.event.trigger('staticAnalysisWarning', [-1]) - }, 500) - }) - props.analysisModule.on('manager', 'pluginDeactivated', (plugin) => { + props.event.trigger("staticAnalysisWarning", [-1]); + }, 500); + }); + props.analysisModule.on("manager", "pluginDeactivated", (plugin) => { // Hide 'Enable Slither Analysis' checkbox - if (plugin.name === 'remixd') { + if (plugin.name === "remixd") { // Reset warning state - setWarningState([]) - setHints([]) - setSlitherWarnings([]) - setSlitherEnabled(false) - setSsaWarnings([]) + setWarningState([]); + setHints([]); + setSlitherWarnings([]); + setSlitherEnabled(false); + setSsaWarnings([]); // Reset badge - props.event.trigger('staticAnalysisWarning', [-1]) + props.event.trigger("staticAnalysisWarning", [-1]); // Reset state - dispatch({ type: '', payload: initialState }) - setShowSlither(false) + dispatch({ type: "", payload: initialState }); + setShowSlither(false); } - }) + }); // eslint-disable-next-line @typescript-eslint/no-unused-vars - props.analysisModule.on('solidity', 'compilerLoaded', async (version: string, license: string) => { - setDisableForRun(version) - props.event.trigger('staticAnalysisWarning', [-1]) - }) - return () => { } - }, [props]) - - const hintErrors = hints.filter(hint => hint.type === 'error') - const noLibSlitherWarnings = slitherWarnings.filter(w => !w.options.isLibrary) - const slitherErrors = noLibSlitherWarnings.filter(slitherError => slitherError.options.type === 'error') - const remixAnalysisNoLibs = ssaWarnings.filter(ssa => ssa.options.isLibrary === false) - const remixAnalysisLessWarnings = ssaWarnings.filter(ssa => ssa.options.type !== 'warning') - -//#region PreviousCode (message, filterWarnings, showWarnings, handleCheckSingle, categoryItem, categorySection) - const message = (name: string, warning: any, more?: string, fileName?: string, locationString?: string) : string => { - return (` + props.analysisModule.on( + "solidity", + "compilerLoaded", + async (version: string, license: string) => { + setDisableForRun(version); + props.event.trigger("staticAnalysisWarning", [-1]); + } + ); + return () => {}; + }, [props]); + + const hintErrors = hints.filter((hint) => hint.type === "error"); + const noLibSlitherWarnings = slitherWarnings.filter( + (w) => !w.options.isLibrary + ); + const slitherErrors = noLibSlitherWarnings.filter( + (slitherError) => slitherError.options.type === "error" + ); + const remixAnalysisNoLibs = ssaWarnings.filter( + (ssa) => ssa.options.isLibrary === false + ); + const remixAnalysisLessWarnings = ssaWarnings.filter( + (ssa) => ssa.options.type !== "warning" + ); + + const message = ( + name: string, + warning: any, + more?: string, + fileName?: string, + locationString?: string + ): string => { + return ` ${name} ${warning} - ${more - ? (more) - : ( ) + ${ + more ? ( + + + more + + + ) : ( + + ) } Pos: ${locationString} - ` - ) - } + `; + }; const filterWarnings = () => { - let newWarningState = {} - let newWarningCount = 0 + let newWarningState = {}; + let newWarningCount = 0; if (showLibsWarning) { for (const category in allWarnings.current) - newWarningCount = newWarningCount + allWarnings.current[category].length - newWarningState = allWarnings.current - } - else { + newWarningCount = + newWarningCount + allWarnings.current[category].length; + newWarningState = allWarnings.current; + } else { for (const category in allWarnings.current) { - const warnings = allWarnings.current[category] - newWarningState[category] = [] + const warnings = allWarnings.current[category]; + newWarningState[category] = []; for (const warning of warnings) { if (!warning.options.isLibrary) { - newWarningCount++ - newWarningState[category].push(warning) + newWarningCount++; + newWarningState[category].push(warning); } } } } - props.event.trigger('staticAnaysisWarning', [newWarningCount]) - setWarningState(newWarningState) - } + props.event.trigger("staticAnaysisWarning", [newWarningCount]); + setWarningState(newWarningState); + }; const showWarnings = (warningMessage, groupByKey) => { - const resultArray = [] - warningMessage.map(x => { - resultArray.push(x) - }) - function groupBy (objectArray, property) { + const resultArray = []; + warningMessage.map((x) => { + resultArray.push(x); + }); + function groupBy(objectArray, property) { return objectArray.reduce((acc, obj) => { - const key = obj[property] + const key = obj[property]; if (!acc[key]) { - acc[key] = [] + acc[key] = []; } // Add object to list for given key's value - acc[key].push(obj) - return acc - }, {}) + acc[key].push(obj); + return acc; + }, {}); } - const groupedCategory = groupBy(resultArray, groupByKey) - allWarnings.current = groupedCategory - filterWarnings() - } - + const groupedCategory = groupBy(resultArray, groupByKey); + allWarnings.current = groupedCategory; + filterWarnings(); + }; const handleCheckAllModules = (groupedModules) => { - const index = groupedModuleIndex(groupedModules) - if (index.every(el => categoryIndex.includes(el))) { + const index = groupedModuleIndex(groupedModules); + if (index.every((el) => categoryIndex.includes(el))) { setCategoryIndex( categoryIndex.filter((el) => { - return !index.includes(el) + return !index.includes(el); }) - ) + ); } else { - setCategoryIndex(_.uniq([...categoryIndex, ...index])) + setCategoryIndex(_.uniq([...categoryIndex, ...index])); } - } + }; const handleCheckOrUncheckCategory = (category) => { - const index = groupedModuleIndex(category) - if (index.every(el => categoryIndex.includes(el))) { + const index = groupedModuleIndex(category); + if (index.every((el) => categoryIndex.includes(el))) { setCategoryIndex( categoryIndex.filter((el) => { - return !index.includes(el) + return !index.includes(el); }) - ) + ); } else { - setCategoryIndex(_.uniq([...categoryIndex, ...index])) + setCategoryIndex(_.uniq([...categoryIndex, ...index])); } - } + }; const handleCheckSingle = (event, _index) => { - _index = _index.toString() + _index = _index.toString(); if (categoryIndex.includes(_index)) { - setCategoryIndex(categoryIndex.filter(val => val !== _index)) + setCategoryIndex(categoryIndex.filter((val) => val !== _index)); } else { - setCategoryIndex(_.uniq([...categoryIndex, _index])) + setCategoryIndex(_.uniq([...categoryIndex, _index])); } - } + }; const categoryItem = (categoryId, item, i) => { return ( @@ -305,7 +360,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { name="checkSingleEntry" itemName={item.name} label={item.description} - onClick={event => handleCheckSingle(event, item._index)} + onClick={(event) => handleCheckSingle(event, item._index)} checked={categoryIndex.includes(item._index.toString())} onChange={() => {}} /> @@ -322,7 +377,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { label={