From 247e51898da61707a0daa72770f0e04aecef4549 Mon Sep 17 00:00:00 2001 From: tizah Date: Tue, 27 Apr 2021 17:30:40 +0100 Subject: [PATCH] refactored static analysis to improve performance --- .../lib/Checkbox/StaticAnalyserCheckedBox.tsx | 45 ----- .../static-analyser/src/lib/ErrorRenderer.tsx | 3 +- .../src/lib/actions/staticAnalysisActions.ts | 16 +- .../src/lib/reducers/staticAnalysisReducer.ts | 65 ++----- .../src/lib/remix-ui-static-analyser.tsx | 163 ++++++------------ 5 files changed, 71 insertions(+), 221 deletions(-) delete mode 100644 libs/remix-ui/static-analyser/src/lib/Checkbox/StaticAnalyserCheckedBox.tsx diff --git a/libs/remix-ui/static-analyser/src/lib/Checkbox/StaticAnalyserCheckedBox.tsx b/libs/remix-ui/static-analyser/src/lib/Checkbox/StaticAnalyserCheckedBox.tsx deleted file mode 100644 index e42caa4851..0000000000 --- a/libs/remix-ui/static-analyser/src/lib/Checkbox/StaticAnalyserCheckedBox.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react' //eslint-disable-line - -interface StaticAnalyserCheckBoxProps { - onClick?: (event) => void - onChange?: (event) => void - label?: string - inputType?: string - name?: string - checked?: boolean - id?: string - itemName?: string - categoryId?: string -} - -const StaticAnalyserCheckedBox = ({ - id, - label, - onClick, - inputType, - name, - checked, - onChange, - itemName, - categoryId -}: StaticAnalyserCheckBoxProps) => { - return ( -
- - -
- ) -} - -export default StaticAnalyserCheckedBox diff --git a/libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx b/libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx index 46dfd16a15..6f1989e3ac 100644 --- a/libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx +++ b/libs/remix-ui/static-analyser/src/lib/ErrorRenderer.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' //eslint-disable-line +import React from 'react' //eslint-disable-line interface ErrorRendererProps { message: any; @@ -32,6 +32,7 @@ const ErrorRenderer = ({ message, opt, editor }: ErrorRendererProps) => { if (!message) return let position = getPositionDetails(message) + console.log({ position }) if (!position.errFile || (opt.errorType && opt.errorType === position.errFile)) { // Updated error reported includes '-->' before file details const errorDetails = message.split('-->') 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 ab9b8d3fc9..4f55437cb6 100644 --- a/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts +++ b/libs/remix-ui/static-analyser/src/lib/actions/staticAnalysisActions.ts @@ -1,24 +1,14 @@ -import React, { useState } from 'react' //eslint-disable-line +import React from 'react' //eslint-disable-line -export const compilation = (analysisModule, state, run) => { -// const setCompilationResult = async (data, source, file) => { -// await setResult({ lastCompilationResult: data, lastCompilationSource: source, currentFile: file }) -// } +export const compilation = (analysisModule, dispatch) => { if (analysisModule) { analysisModule.on( 'solidity', 'compilationFinished', (file, source, languageVersion, data) => { if (languageVersion.indexOf('soljson') !== 0) return - setCompilationResult(data, source, file) - if (state.categoryIndex.length > 0) { - run(data, source, file) - } + dispatch({ type: 'compilationFinished', payload: { file, source, languageVersion, data } }) } ) } } - -export const setCompilationResult = async (data, source, file) => { - return await { data, source, file } -} diff --git a/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts b/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts index f2f1a8c9d0..833ef55b39 100644 --- a/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts +++ b/libs/remix-ui/static-analyser/src/lib/reducers/staticAnalysisReducer.ts @@ -1,65 +1,22 @@ -import remixLib from '@remix-project/remix-lib' -import * as _ from 'lodash' -const StaticAnalysisRunner = require('@remix-project/remix-analyzer').CodeAnalysis -const utils = remixLib.util - -const runner = new StaticAnalysisRunner() - -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 groupedModules = utils.groupBy( - preProcessModules(runner.modules()), - 'categoryId' -) - -const getIndex = (modules, array) => { - Object.values(modules).map((value: {_index}) => { - if (Array.isArray(value)) { - value.forEach((x) => { - array.push(x._index.toString()) - }) - } else { - array.push(value._index.toString()) - } - }) -} -const groupedModuleIndex = (modules) => { - const indexOfCategory = [] - if (!_.isEmpty(modules)) { - getIndex(modules, indexOfCategory) - } - return indexOfCategory +export const initialState = { + file: null, + source: null, + languageVersion: null, + data: null } -export const initialState = { categoryIndex: [] } - export const analysisReducer = (state, action) => { switch (action.type) { - case 'initialize': - return { ...state, categoryIndex: groupedModuleIndex(groupedModules) } - case 'uncheck': + case 'compilationFinished': return { ...state, - categoryIndex: state.categoryIndex.filter((el) => { - return !action.payload.includes(el) - }) + file: action.payload.file, + source: action.payload.source, + languageVersion: action.payload.languageVersion, + data: action.payload.data } - case 'check': - return { ...state, categoryIndex: _.uniq([...state.categoryIndex, ...action.payload]) } - case 'uncheckSingle': - return { ...state, categoryIndex: state.categoryIndex.filter(val => val !== action.payload) } - case 'checkSingle': - return { ...state, categoryIndex: _.uniq([...state.categoryIndex, action.payload]) } default: - return { ...state, categoryIndex: groupedModuleIndex(groupedModules) } + return initialState } } diff --git a/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx b/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx index c0c89415c9..7725321271 100644 --- a/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx +++ b/libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx @@ -1,30 +1,20 @@ import React, { useEffect, useState, useReducer } from 'react' -import ReactDOM from 'react-dom' //eslint-disable-line -import CheckBox from './Checkbox/StaticAnalyserCheckedBox' // eslint-disable-line import Button from './Button/StaticAnalyserButton' // eslint-disable-line import remixLib from '@remix-project/remix-lib' import _ from 'lodash' import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { RemixUiCheckbox } from '@remix-ui/checkbox' // eslint-disable-line import ErrorRenderer from './ErrorRenderer' // eslint-disable-line -import { compilation, setCompilationResult } from './actions/staticAnalysisActions' -import { analysisReducer, initialState } from './reducers/staticAnalysisReducer' - +import { compilation } from './actions/staticAnalysisActions' +import { initialState, analysisReducer } from './reducers/staticAnalysisReducer' const StaticAnalysisRunner = require('@remix-project/remix-analyzer').CodeAnalysis const utils = remixLib.util /* eslint-disable-next-line */ export interface RemixUiStaticAnalyserProps { - renderStaticAnalysis: any - staticanalysis: any - analysisRunner: any, - lastCompilationResult: any, - lastCompilationSource: any, registry: any, event: any, analysisModule: any - _deps: any, - emit: any } export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { @@ -65,88 +55,46 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { return indexOfCategory } const [autoRun, setAutoRun] = useState(true) - - // const initialState = { categoryIndex: [] } - - // const reducer = (state, action) => { - // console.log({ action }) - // switch (action.type) { - // case 'initialize': - // return { categoryIndex: groupedModuleIndex(groupedModules) } - // case 'uncheck': - // return { - // categoryIndex: state.categoryIndex.filter((el) => { - // return !action.payload.includes(el) - // }) - // } - // case 'check': - // return { categoryIndex: _.uniq([...state.categoryIndex, ...action.payload]) } - // case 'uncheckSingle': - // return { categoryIndex: state.categoryIndex.filter(val => val !== action.payload) } - // case 'checkSingle': - // return { categoryIndex: _.uniq([...state.categoryIndex, action.payload]) } - // default: - // return { categoryIndex: groupedModuleIndex(groupedModules) } - // } - // } - - const [state, dispatch] = useReducer(analysisReducer, initialState) + const [categoryIndex, setCategoryIndex] = useState(groupedModuleIndex(groupedModules)) const warningContainer = React.useRef(null) - const [runButtonState, setRunButtonState] = useState(true) - - const [result, setResult] = useState({ - lastCompilationResult: null, - lastCompilationSource: null, - currentFile: 'No file compiled' - }) - const [, setModuleNameResult] = useState(null) - const [, setWarning] = useState({ - options: {}, - hasWarning: false, - warningErrors: [] - }) const [warningState, setWarningState] = useState([]) + const [state, dispatch] = useReducer(analysisReducer, initialState) - // const executeCompilation = (categoryIndex) => { - // const setCompilationResult = async (data, source, file) => { - // await setResult({ lastCompilationResult: data, lastCompilationSource: source, currentFile: file }) - // } - // if (props.analysisModule) { - // props.analysisModule.on( - // 'solidity', - // 'compilationFinished', - // (file, source, languageVersion, data) => { - // if (languageVersion.indexOf('soljson') !== 0) return - // setCompilationResult(data, source, file) - // console.log(categoryIndex, ' inside execute funtions') - // if (state.categoryIndex.length > 0) { - // run(data, source, file) - // } - // } - // ) - // } - // } + useEffect(() => { + compilation(props.analysisModule, dispatch) + }, []) useEffect(() => { if (autoRun) { - if (props.analysisModule && state.categoryIndex.length > 0) { - compilation(props.analysisModule, state, run) + if (state.data !== null) { + run(state.data, state.source, state.file) } } - return () => { + return () => { } + }, [autoRun, categoryIndex, state]) + + const message = (name, warning, more, fileName, locationString) : string => { + return (` + + ${name} + ${warning} + ${more + ? (more) + : ( ) } - }, [autoRun, state, props.analysisModule, setWarning]) + Pos: ${locationString} + ` + ) + } const run = (lastCompilationResult, lastCompilationSource, currentFile) => { if (autoRun) { - setResult({ lastCompilationResult, lastCompilationSource, currentFile }) - if (lastCompilationResult && state.categoryIndex.length > 0) { - setRunButtonState(false) + if (lastCompilationResult && categoryIndex.length > 0) { let warningCount = 0 const warningMessage = [] - runner.run(lastCompilationResult, state.categoryIndex, results => { + runner.run(lastCompilationResult, categoryIndex, results => { results.map((result) => { let moduleName Object.keys(groupedModules).map(key => { @@ -156,7 +104,6 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { } }) }) - setModuleNameResult(moduleName) const warningErrors = [] result.report.map((item) => { let location: any = {} @@ -183,6 +130,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { fileName = Object.keys(lastCompilationResult.contracts)[file] } warningCount++ + const msg = message(item.name, item.warning, item.more, fileName, locationString) const options = { type: 'warning', useSpan: true, @@ -197,8 +145,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { location: location } warningErrors.push(options) - setWarning({ hasWarning: true, options, warningErrors: warningErrors }) - warningMessage.push({ options, hasWarning: true, warningModuleName: moduleName }) + warningMessage.push({ msg, options, hasWarning: true, warningModuleName: moduleName }) }) }) const resultArray = [] @@ -216,21 +163,15 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { return acc }, {}) } + const groupedCategory = groupBy(resultArray, 'warningModuleName') - console.log({ warningCount }, ' 221') - console.log({ groupedCategory }) setWarningState(groupedCategory) - console.log({ warningState }) - console.log({ warningCount }, ' 223') }) - console.log({ warningCount }, ' CategoryIndex outside function') - if (state.categoryIndex.length > 0) { - console.log(state.categoryIndex, ' CategoryIndex in execute funtions') + if (categoryIndex.length > 0) { props.event.trigger('staticAnaysisWarning', [warningCount]) } } else { - setRunButtonState(true) - if (state.categoryIndex.length) { + if (categoryIndex.length) { warningContainer.current.innerText = 'No compiled AST available' } props.event.trigger('staticAnaysisWarning', [-1]) @@ -240,19 +181,27 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { const handleCheckAllModules = (groupedModules) => { const index = groupedModuleIndex(groupedModules) - if (index.every(el => state.categoryIndex.includes(el))) { - dispatch({ type: 'uncheck', payload: index }) + if (index.every(el => categoryIndex.includes(el))) { + setCategoryIndex( + categoryIndex.filter((el) => { + return !index.includes(el) + }) + ) } else { - dispatch({ type: 'check', payload: index }) + setCategoryIndex(_.uniq([...categoryIndex, ...index])) } } const handleCheckOrUncheckCategory = (category) => { const index = groupedModuleIndex(category) - if (index.every(el => state.categoryIndex.includes(el))) { - dispatch({ type: 'uncheck', payload: index }) + if (index.every(el => categoryIndex.includes(el))) { + setCategoryIndex( + categoryIndex.filter((el) => { + return !index.includes(el) + }) + ) } else { - dispatch({ type: 'check', payload: index }) + setCategoryIndex(_.uniq([...categoryIndex, ...index])) } } @@ -266,10 +215,10 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { const handleCheckSingle = (event, _index) => { _index = _index.toString() - if (state.categoryIndex.includes(_index)) { - dispatch({ type: 'uncheckSingle', payload: _index }) + if (categoryIndex.includes(_index)) { + setCategoryIndex(categoryIndex.filter(val => val !== _index)) } else { - dispatch({ type: 'checkSingle', payload: _index }) + setCategoryIndex(_.uniq([...categoryIndex, _index])) } } @@ -284,7 +233,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { itemName={item.name} label={item.description} onClick={event => handleCheckSingle(event, item._index)} - checked={state.categoryIndex.includes(item._index.toString())} + checked={categoryIndex.includes(item._index.toString())} onChange={() => {}} /> @@ -313,7 +262,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { expand={false} >
- handleCheckOrUncheckCategory(category)} id={categoryId} inputType="checkbox" label={`Select ${category[0].categoryDisplayName}`} name='checkCategoryEntry' checked={category.map(x => x._index.toString()).every(el => state.categoryIndex.includes(el))} onChange={() => {}}/> + handleCheckOrUncheckCategory(category)} id={categoryId} inputType="checkbox" label={`Select ${category[0].categoryDisplayName}`} name='checkCategoryEntry' checked={category.map(x => x._index.toString()).every(el => categoryIndex.includes(el))} onChange={() => {}}/>
{category.map((item, i) => { @@ -340,7 +289,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { return (value.map(x => { return x._index.toString() })) - }).flat().every(el => state.categoryIndex.includes(el))} + }).flat().every(el => categoryIndex.includes(el))} label="Select all" onClick={() => handleCheckAllModules(groupedModules)} onChange={() => {}} @@ -353,7 +302,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { label="Autorun" onChange={() => {}} /> -
@@ -371,14 +320,12 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { className="text-break break-word word-break font-weight-bold" id="staticAnalysisCurrentFile" > - {result.currentFile && result.currentFile}
- { console.log({ warningState }) } - { state.categoryIndex.length > 0 && Object.entries(warningState).length > 0 && + { categoryIndex.length > 0 && Object.entries(warningState).length > 0 &&
- {/* { + { (Object.entries(warningState).map((element) => ( <> {element[0]} @@ -392,7 +339,7 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => { ))} ))) - } */} + }
}