From 219a83bf067138606810d5c5dd482ad36419f338 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Wed, 20 May 2020 18:03:11 +0530 Subject: [PATCH] unit test for bytes array and no params --- .../src/solidity-analyzer/modules/gasCosts.ts | 4 +- .../modules/staticAnalysisCommon.ts | 80 ++++++++--------- remix-analyzer/src/types.ts | 1 + .../astBlocks/funcDefForComplexParams.json | 90 ++++++++++++++++++- .../analysis/staticAnalysisCommon-test.ts | 6 +- 5 files changed, 136 insertions(+), 45 deletions(-) diff --git a/remix-analyzer/src/solidity-analyzer/modules/gasCosts.ts b/remix-analyzer/src/solidity-analyzer/modules/gasCosts.ts index 96df272f75..7151f61b94 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/gasCosts.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/gasCosts.ts @@ -1,6 +1,6 @@ import { default as category } from './categories' import { default as algorithm } from './algorithmCategories' -import { getFunctionDefinitionName, helpers, isVariableTurnedIntoGetter, getSplittedTypeDesc } from './staticAnalysisCommon' +import { getFunctionDefinitionName, helpers, isVariableTurnedIntoGetter, getMethodParamsSplittedTypeDesc } from './staticAnalysisCommon' import { ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, CompiledContract, AnalyzerModule, FunctionDefinitionAstNode, VariableDeclarationAstNode } from './../../types' @@ -23,7 +23,7 @@ export default class gasCosts implements AnalyzerModule { let signature: string; if(node.nodeType === 'FunctionDefinition'){ const functionName: string = getFunctionDefinitionName(node) - signature = helpers.buildAbiSignature(functionName, getSplittedTypeDesc(node, compilationResults.contracts)) + signature = helpers.buildAbiSignature(functionName, getMethodParamsSplittedTypeDesc(node, compilationResults.contracts)) } else signature = node.name + '()' diff --git a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts index ed3731cd2b..0b7e5ae793 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts @@ -3,7 +3,7 @@ import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode, - IdentifierAstNode, IndexAccessAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode, CompiledContractObj } from "types" + IdentifierAstNode, IndexAccessAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode, CompiledContractObj, ABIParameter } from "types" import { util } from 'remix-lib' type SpecialObjDetail = { @@ -1078,49 +1078,49 @@ function buildAbiSignature (funName: string, paramTypes: any[]): string { } // To create the method signature similar to contract.evm.gasEstimates.external object - // For address payable, return address - function getSplittedTypeDesc(node: FunctionDefinitionAstNode, contracts: CompiledContractObj): string[] { - return node.parameters.parameters.map((varNode, varIndex) => { - let finalTypeString; - const typeString = varNode.typeDescriptions.typeString - if(typeString.includes('struct')) { - const fnName = node.name - for (const filename in contracts) { - for (const contractName in contracts[filename]) { - const methodABI = contracts[filename][contractName].abi - .find(e => e.name === fnName && e.inputs?.length && - e.inputs[varIndex]['type'].includes('tuple') && - e.inputs[varIndex]['internalType'] === typeString) - if(methodABI && methodABI.inputs) { - const inputs = methodABI.inputs[varIndex] - let typeStr = getTypeStringFromComponents(inputs['components']) - finalTypeString = typeStr + inputs['type'].replace('tuple', '') - } +// For address payable, return address +function getMethodParamsSplittedTypeDesc(node: FunctionDefinitionAstNode, contracts: CompiledContractObj): string[] { + return node.parameters.parameters.map((varNode, varIndex) => { + let finalTypeString; + const typeString = varNode.typeDescriptions.typeString + if(typeString.includes('struct')) { + const fnName = node.name + for (const filename in contracts) { + for (const contractName in contracts[filename]) { + const methodABI = contracts[filename][contractName].abi + .find(e => e.name === fnName && e.inputs?.length && + e.inputs[varIndex]['type'].includes('tuple') && + e.inputs[varIndex]['internalType'] === typeString) + if(methodABI && methodABI.inputs) { + const inputs = methodABI.inputs[varIndex] + let typeStr = getTypeStringFromComponents(inputs['components']) + finalTypeString = typeStr + inputs['type'].replace('tuple', '') } } - } else - finalTypeString = typeString.split(' ')[0] - return finalTypeString - }) - } - - function getTypeStringFromComponents(components: any[]) { - let typeString = '(' - for(var i=0; i < components.length; i++) { - const param = components[i] - if(param.type.includes('tuple') && param.components && param.components.length > 0){ - typeString = typeString + getTypeStringFromComponents(param.components) - typeString = typeString + param.type.replace('tuple', '') } - else - typeString = typeString + param.type - - if(i !== components.length - 1) - typeString = typeString + ',' + } else + finalTypeString = typeString.split(' ')[0] + return finalTypeString + }) +} + +function getTypeStringFromComponents(components: ABIParameter[]) { + let typeString = '(' + for(var i=0; i < components.length; i++) { + const param = components[i] + if(param.type.includes('tuple') && param.components && param.components.length > 0){ + typeString = typeString + getTypeStringFromComponents(param.components) + typeString = typeString + param.type.replace('tuple', '') } - typeString = typeString + ')' - return typeString + else + typeString = typeString + param.type + + if(i !== components.length - 1) + typeString = typeString + ',' } + typeString = typeString + ')' + return typeString +} const helpers = { expressionTypeDescription, @@ -1157,7 +1157,7 @@ export { getFunctionOrModifierDefinitionParameterPart, getFunctionDefinitionReturnParameterPart, getUnAssignedTopLevelBinOps, - getSplittedTypeDesc, + getMethodParamsSplittedTypeDesc, // #################### Complex Node Identification isDeleteOfDynamicArray, diff --git a/remix-analyzer/src/types.ts b/remix-analyzer/src/types.ts index e010b0d27b..71ee35e289 100644 --- a/remix-analyzer/src/types.ts +++ b/remix-analyzer/src/types.ts @@ -837,6 +837,7 @@ export interface CommonYulAstNode { } export interface ABIParameter { + internalType: string /** The name of the parameter */ name: string /** The canonical type of the parameter */ diff --git a/remix-analyzer/test/analysis/astBlocks/funcDefForComplexParams.json b/remix-analyzer/test/analysis/astBlocks/funcDefForComplexParams.json index 975e17f8ce..14551bce74 100644 --- a/remix-analyzer/test/analysis/astBlocks/funcDefForComplexParams.json +++ b/remix-analyzer/test/analysis/astBlocks/funcDefForComplexParams.json @@ -79,5 +79,93 @@ "stateMutability": "nonpayable", "superFunction": null, "visibility": "public" - } + }, + "bytesArray": { + "body": + { + "id": 287, + "nodeType": "Block", + "src": "4988:2:0", + "statements": [] + }, + "documentation": null, + "id": 288, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "testWithArray", + "nodeType": "FunctionDefinition", + "parameters": + { "id": 285, + "nodeType": "ParameterList", + "parameters": [ + { + "constant": false, + "id": 284, + "name": "param", + "nodeType": "VariableDeclaration", + "scope": 288, + "src": "4957:22:0", + "stateVariable": false, + "storageLocation": "memory", + "typeDescriptions": + { "typeIdentifier": "t_array$_t_bytes32_$dyn_memory_ptr", + "typeString": "bytes32[]" }, + "typeName": + { "baseType": "[Object]", + "id": 283, + "length": null, + "nodeType": "ArrayTypeName", + "src": "4957:9:0", + "typeDescriptions": "[Object]" + }, + "value": null, + "visibility": "internal" + } + ], + "src": "4956:24:0" + }, + "returnParameters": + { "id": 286, + "nodeType": "ParameterList", + "parameters": [], + "src": "4988:0:0" }, + "scope": 289, + "src": "4933:57:0", + "stateMutability": "nonpayable", + "superFunction": null, + "visibility": "public" + }, + "withoutParams" : { + "body": + { + "id": 280, + "nodeType": "Block", + "src": "4864:63:0", + "statements": "[ [Object] ]" + }, + "documentation": null, + "id": 281, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "winnerName", + "nodeType": "FunctionDefinition", + "parameters": + { "id": 268, + "nodeType": "ParameterList", + "parameters": [], + "src": "4804:2:0" + }, + "returnParameters": + { "id": 271, + "nodeType": "ParameterList", + "parameters": "[ [Object] ]", + "src": "4839:20:0" + }, + "scope": 289, + "src": "4785:142:0", + "stateMutability": "view", + "superFunction": null, + "visibility": "public" } } \ No newline at end of file diff --git a/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts b/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts index b6a57fba86..4734ece218 100644 --- a/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts +++ b/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts @@ -292,8 +292,10 @@ test('staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent', function (t) { }) test('staticAnalysisCommon.getSplittedTypeDesc', function (t) { - t.plan(1) - t.ok(common.getSplittedTypeDesc(funcDefForComplexParams.nestedStruct, compiledContractObj)[0] === '(bytes32,uint256,uint256[],address,(bytes32,uint256)[])[][]', 'creates right params type signature') + t.plan(3) + t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.withoutParams, compiledContractObj).length === 0, 'no params, no params type signature') + t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.bytesArray, compiledContractObj)[0] === 'bytes32[]', 'creates right params type signature') + t.ok(common.getMethodParamsSplittedTypeDesc(funcDefForComplexParams.nestedStruct, compiledContractObj)[0] === '(bytes32,uint256,uint256[],address,(bytes32,uint256)[])[][]', 'creates right params type signature') }) // #################### Complex Node Identification