From febf8804ac479a15d4fd9aa99ce70efbc38d7848 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Fri, 6 Mar 2020 13:19:38 +0530 Subject: [PATCH] existing commons test cases updated --- .../modules/lowLevelCalls.ts | 24 +- .../modules/staticAnalysisCommon.ts | 95 ++--- .../astBlocks/abiNamespaceCallNodes.json | 380 ++++++++++++++++++ .../analysis/astBlocks/blockHashAccess.json | 64 ++- .../analysis/astBlocks/blockTimestamp.json | 20 + .../astBlocks/dynamicDeleteUnaryOp.json | 28 ++ .../test/analysis/astBlocks/index.js | 4 + .../astBlocks/parameterFunctionCall.json | 143 +++---- .../test/analysis/astBlocks/requireCall.json | 115 ++++++ .../analysis/staticAnalysisCommon-test.ts | 266 +++++------- .../solidity-v0.5/deleteDynamicArray.sol | 2 +- .../test-contracts/solidity-v0.5/library.sol | 4 + 12 files changed, 800 insertions(+), 345 deletions(-) create mode 100644 remix-analyzer/test/analysis/astBlocks/abiNamespaceCallNodes.json create mode 100644 remix-analyzer/test/analysis/astBlocks/blockTimestamp.json create mode 100644 remix-analyzer/test/analysis/astBlocks/dynamicDeleteUnaryOp.json create mode 100644 remix-analyzer/test/analysis/astBlocks/requireCall.json diff --git a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts index 100c817610..f32eadf4a7 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts @@ -1,6 +1,6 @@ import { default as category } from './categories' -import { isLowLevelCallInst, isLowLevelCallInst050, isLowLevelCallcodeInst, isLowLevelDelegatecallInst, - isLowLevelSendInst, isLowLevelSendInst050, isLLDelegatecallInst050, lowLevelCallTypes } from './staticAnalysisCommon' +import { isLLCall, isLLDelegatecall, + isLLSend, lowLevelCallTypes } from './staticAnalysisCommon' import { default as algorithm } from './algorithmCategories' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode} from './../../types' @@ -20,20 +20,12 @@ export default class lowLevelCalls implements AnalyzerModule { algorithm: ModuleAlgorithm = algorithm.EXACT visit (node : MemberAccessAstNode): void { - if (isLowLevelCallInst(node)) { + if (isLLCall(node)) { this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL}) - } else if (isLowLevelCallInst050(node)) { - this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL}) - } else if (isLowLevelCallcodeInst(node)) { - this.llcNodes.push({node: node, type: lowLevelCallTypes.CALLCODE}) - } else if (isLowLevelDelegatecallInst(node)) { + } else if (isLLDelegatecall(node)) { this.llcNodes.push({node: node, type: lowLevelCallTypes.DELEGATECALL}) - } else if (isLowLevelSendInst(node)) { - this.llcNodes.push({node: node, type: lowLevelCallTypes.SEND}) - } else if (isLowLevelSendInst050(node)) { + } else if (isLLSend(node)) { this.llcNodes.push({node: node, type: lowLevelCallTypes.SEND}) - } else if (isLLDelegatecallInst050(node)) { - this.llcNodes.push({node: node, type: lowLevelCallTypes.DELEGATECALL}) } } @@ -49,12 +41,6 @@ export default class lowLevelCalls implements AnalyzerModule { morehref = 'http://solidity.readthedocs.io/en/develop/control-structures.html?#external-function-calls' // http://solidity.readthedocs.io/en/develop/frequently-asked-questions.html?#why-is-the-low-level-function-call-less-favorable-than-instantiating-a-contract-with-a-variable-contractb-b-and-executing-its-functions-b-dosomething break - case lowLevelCallTypes.CALLCODE: - text = `use of "callcode": the use of low level "callcode" should be avoided whenever possible. - External code that is called can change the state of the calling contract and send ether from the caller's balance. - If this is wanted behaviour use the Solidity library feature if possible.` - morehref = 'http://solidity.readthedocs.io/en/develop/contracts.html#libraries' - break case lowLevelCallTypes.DELEGATECALL: text = `use of "delegatecall": the use of low level "delegatecall" should be avoided whenever possible. External code that is called can change the state of the calling contract and send ether from the caller's balance. diff --git a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts index 8bbc37b1ac..6acdc7747b 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts @@ -1,9 +1,8 @@ 'use strict' -import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode, IdentifierAstNode, MappingAstNode, IndexAccessAstNode, UserDefinedTypeNameAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode } from "types" +import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode, IdentifierAstNode, MappingAstNode, IndexAccessAstNode, UserDefinedTypeNameAstNode, BlockAstNode, AssignmentAstNode, InlineAssemblyAstNode, IfStatementAstNode } from "types" -const remixLib = require('remix-lib') -const util = remixLib.util +import { util } from 'remix-lib' const nodeTypes = { IDENTIFIER: 'Identifier', @@ -54,10 +53,8 @@ const basicRegex = { const basicFunctionTypes = { SEND: buildFunctionSignature([basicTypes.UINT], [basicTypes.BOOL], false), - CALL: buildFunctionSignature([], [basicTypes.BOOL], true), - 'CALL-v0.5': buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], true), - DELEGATECALL: buildFunctionSignature([], [basicTypes.BOOL], false), - 'DELEGATECALL-v0.5': buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], false), + CALL: buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], true), + DELEGATECALL: buildFunctionSignature([basicTypes.BYTES_MEM], [basicTypes.BOOL, basicTypes.BYTES_MEM], false), TRANSFER: buildFunctionSignature([basicTypes.UINT], [], false) } @@ -77,16 +74,13 @@ const builtinFunctions = { 'require(bool)': true, 'require(bool,string memory)': true, 'gasleft()': true, - 'blockhash(uint)': true, + 'blockhash(uint256)': true, 'address(address)': true } const lowLevelCallTypes = { CALL: { ident: 'call', type: basicFunctionTypes.CALL }, - 'CALL-v0.5': { ident: 'call', type: basicFunctionTypes['CALL-v0.5'] }, - CALLCODE: { ident: 'callcode', type: basicFunctionTypes.CALL }, DELEGATECALL: { ident: 'delegatecall', type: basicFunctionTypes.DELEGATECALL }, - 'DELEGATECALL-v0.5': { ident: 'delegatecall', type: basicFunctionTypes['DELEGATECALL-v0.5'] }, SEND: { ident: 'send', type: basicFunctionTypes.SEND }, TRANSFER: { ident: 'transfer', type: basicFunctionTypes.TRANSFER } } @@ -467,7 +461,7 @@ function isDeleteOfDynamicArray (node: UnaryOperationAstNode): boolean { * @return {bool} */ function isDynamicArrayAccess (node: IdentifierAstNode): boolean { - return typeDescription(node, '[] storage ref') || typeDescription(node, 'bytes storage ref') || typeDescription(node, 'string storage ref') + return getType(node).endsWith('[] storage ref') || typeDescription(node, 'bytes storage ref') || typeDescription(node, 'string storage ref') } /** @@ -579,7 +573,7 @@ function isStorageVariableDeclaration (node: VariableDeclarationAstNode): boolea * @return {bool} */ function isInteraction (node: MemberAccessAstNode): boolean { - return isLLCall(node) || isLLSend(node) || isExternalDirectCall(node) || isTransfer(node) || isLLCall050(node) || isLLSend050(node) + return isLLCall(node) || isLLSend(node) || isExternalDirectCall(node) || isTransfer(node) } /** @@ -787,8 +781,8 @@ function isBlockTimestampAccess (node: MemberAccessAstNode): boolean { * @node {ASTNode} some AstNode * @return {bool} */ -function isBlockBlockHashAccess (node: MemberAccessAstNode | FunctionCallAstNode): boolean { - return node.nodeType === 'FunctionCall' && isBuiltinFunctionCall(node) && getLocalCallName(node) === 'blockhash' +function isBlockBlockHashAccess (node: FunctionCallAstNode): boolean { + return isBuiltinFunctionCall(node) && getLocalCallName(node) === 'blockhash' } /** @@ -828,12 +822,8 @@ function isLocalCall (node: FunctionCallAstNode): boolean { */ function isLowLevelCall (node: MemberAccessAstNode): boolean { return isLLCall(node) || - isLLCallcode(node) || isLLDelegatecall(node) || - isLLSend(node) || - isLLSend050(node) || - isLLCall050(node) || - isLLDelegatecall050(node) + isLLSend(node) } /** @@ -841,11 +831,11 @@ function isLowLevelCall (node: MemberAccessAstNode): boolean { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLSend050 (node: MemberAccessAstNode): boolean { - return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), - undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) -} +// function isLLSend050 (node: MemberAccessAstNode): boolean { +// return isMemberAccess(node, +// exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), +// undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) +// } /** * True if low level send (solidity < 0.5) @@ -855,7 +845,7 @@ function isLLSend050 (node: MemberAccessAstNode): boolean { function isLLSend (node: MemberAccessAstNode): boolean { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), - undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) + undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) } /** @@ -865,8 +855,8 @@ function isLLSend (node: MemberAccessAstNode): boolean { */ function isLLCall (node: MemberAccessAstNode): boolean { return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), - undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) + exactMatch(util.escapeRegExp(lowLevelCallTypes.CALL.type)), + undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident)) } /** @@ -874,22 +864,22 @@ function isLLCall (node: MemberAccessAstNode): boolean { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLCall050 (node: MemberAccessAstNode): boolean { - return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), - undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) -} +// function isLLCall050 (node: MemberAccessAstNode): boolean { +// return isMemberAccess(node, +// exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), +// undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) +// } /** * True if low level callcode * @node {ASTNode} some AstNode * @return {bool} */ -function isLLCallcode (node: MemberAccessAstNode): boolean { - return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes.CALLCODE.type)), - undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident)) -} +// function isLLCallcode (node: MemberAccessAstNode): boolean { +// return isMemberAccess(node, +// exactMatch(util.escapeRegExp(lowLevelCallTypes.CALLCODE.type)), +// undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident)) +// } /** * True if low level delegatecall @@ -898,8 +888,8 @@ function isLLCallcode (node: MemberAccessAstNode): boolean { */ function isLLDelegatecall (node: MemberAccessAstNode): boolean { return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)), - undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident)) + exactMatch(util.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)), + undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident)) } /** @@ -907,11 +897,11 @@ function isLLDelegatecall (node: MemberAccessAstNode): boolean { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLDelegatecall050 (node: MemberAccessAstNode): boolean { - return isMemberAccess(node, - exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)), - undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident)) -} +// function isLLDelegatecall050 (node: MemberAccessAstNode): boolean { +// return isMemberAccess(node, +// exactMatch(util.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)), +// undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident)) +// } /** * True if transfer call @@ -991,11 +981,11 @@ function isSpecialVariableAccess (node: MemberAccessAstNode, varType: any): bool // return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString) // } -function expressionTypeDescription (node, typeRegex) { +function expressionTypeDescription (node: any, typeRegex: string): boolean { return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString) } -function typeDescription (node, typeRegex) { +function typeDescription (node: any, typeRegex: string): boolean { return new RegExp(typeRegex).test(node.typeDescriptions.typeString) } @@ -1126,13 +1116,10 @@ export { isStateVariable, isTransfer, isLowLevelCall, - isLLCall as isLowLevelCallInst, - isLLCall050 as isLowLevelCallInst050, - isLLSend050 as isLowLevelSendInst050, - isLLDelegatecall050 as isLLDelegatecallInst050, - isLLCallcode as isLowLevelCallcodeInst, - isLLDelegatecall as isLowLevelDelegatecallInst, - isLLSend as isLowLevelSendInst, + isLLCall, + // isLLCallcode as isLowLevelCallcodeInst, + isLLDelegatecall, + isLLSend, isExternalDirectCall, isFullyImplementedContract, isLibrary, diff --git a/remix-analyzer/test/analysis/astBlocks/abiNamespaceCallNodes.json b/remix-analyzer/test/analysis/astBlocks/abiNamespaceCallNodes.json new file mode 100644 index 0000000000..18670fb3b1 --- /dev/null +++ b/remix-analyzer/test/analysis/astBlocks/abiNamespaceCallNodes.json @@ -0,0 +1,380 @@ +{ + "encode":{ + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "id": 15, + "name": "s", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 10, + "src": "144:1:0", + "typeDescriptions": + { + "typeIdentifier": "t_array$_t_struct$_S_$4_memory_$dyn_memory_ptr", + "typeString": "struct C.S memory[] memory" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_array$_t_struct$_S_$4_memory_$dyn_memory_ptr", + "typeString": "struct C.S memory[] memory" + } + ], + "expression": + { + "argumentTypes": null, + "id": 12, + "name": "abi", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -1, + "src": "133:3:0", + "typeDescriptions": + { + "typeIdentifier": "t_magic_abi", + "typeString": "abi" + } + }, + "id": 14, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberName": "encode", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "133:10:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_abiencode_pure$__$returns$_t_bytes_memory_ptr_$", + "typeString": "function () pure returns (bytes memory)" + } + }, + "id": 16, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "133:13:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + }, + + + "encodePacked": { + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "arguments": [], + "expression": + { + "argumentTypes": [], + "id": 16, + "name": "f", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 38, + "src": "128:1:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_internal_pure$__$returns$_t_bytes_memory_ptr_$", + "typeString": "function () pure returns (bytes memory)" + } + }, + "id": 17, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "128:3:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + ], + "expression": + { + "argumentTypes": null, + "id": 14, + "name": "abi", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -1, + "src": "111:3:0", + "typeDescriptions": + { + "typeIdentifier": "t_magic_abi", + "typeString": "abi" + } + }, + "id": 15, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberName": "encodePacked", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "111:16:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$", + "typeString": "function () pure returns (bytes memory)" + } + }, + "id": 18, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "111:21:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + }, + + + "encodeWithSelector": { + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "hexValue": "30783132333435363738", + "id": 24, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "169:10:0", + "subdenomination": null, + "typeDescriptions": + { + "typeIdentifier": "t_rational_305419896_by_1", + "typeString": "int_const 305419896" + }, + "value": "0x12345678" + }, + { + "argumentTypes": null, + "hexValue": "31", + "id": 25, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "181:1:0", + "subdenomination": null, + "typeDescriptions": + { + "typeIdentifier": "t_rational_1_by_1", + "typeString": "int_const 1" + }, + "value": "1" + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_rational_305419896_by_1", + "typeString": "int_const 305419896" + }, + { + "typeIdentifier": "t_rational_1_by_1", + "typeString": "int_const 1" + } + ], + "expression": + { + "argumentTypes": null, + "id": 22, + "name": "abi", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -1, + "src": "146:3:0", + "typeDescriptions": + { + "typeIdentifier": "t_magic_abi", + "typeString": "abi" + } + }, + "id": 23, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberName": "encodeWithSelector", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "146:22:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_abiencodewithselector_pure$_t_bytes4_$returns$_t_bytes_memory_ptr_$", + "typeString": "function (bytes4) pure returns (bytes memory)" + } + }, + "id": 26, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "146:37:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + }, + + + "encodeWithSignature": { + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "hexValue": "662875696e7432353629", + "id": 32, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "string", + "lValueRequested": false, + "nodeType": "Literal", + "src": "221:12:0", + "subdenomination": null, + "typeDescriptions": + { + "typeIdentifier": "t_stringliteral_b3de648b001c08ab857afe5a9633887e7a4e2a429d1d8d4231238c1ffaeb256f", + "typeString": "literal_string \"f(uint256)\"" + }, + "value": "f(uint256)" + }, + { + "argumentTypes": null, + "hexValue": "34", + "id": 33, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "235:1:0", + "subdenomination": null, + "typeDescriptions": + { + "typeIdentifier": "t_rational_4_by_1", + "typeString": "int_const 4" + }, + "value": "4" + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_stringliteral_b3de648b001c08ab857afe5a9633887e7a4e2a429d1d8d4231238c1ffaeb256f", + "typeString": "literal_string \"f(uint256)\"" + }, + { + "typeIdentifier": "t_rational_4_by_1", + "typeString": "int_const 4" + } + ], + "expression": + { + "argumentTypes": null, + "id": 30, + "name": "abi", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -1, + "src": "197:3:0", + "typeDescriptions": + { + "typeIdentifier": "t_magic_abi", + "typeString": "abi" + } + }, + "id": 31, + "isConstant": false, + "isLValue": false, + "isPure": true, + "lValueRequested": false, + "memberName": "encodeWithSignature", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "197:23:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_abiencodewithsignature_pure$_t_string_memory_ptr_$returns$_t_bytes_memory_ptr_$", + "typeString": "function (string memory) pure returns (bytes memory)" + } + }, + "id": 34, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "197:40:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_bytes_memory_ptr", + "typeString": "bytes memory" + } + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/astBlocks/blockHashAccess.json b/remix-analyzer/test/analysis/astBlocks/blockHashAccess.json index 01de98986e..039bd33531 100644 --- a/remix-analyzer/test/analysis/astBlocks/blockHashAccess.json +++ b/remix-analyzer/test/analysis/astBlocks/blockHashAccess.json @@ -1,19 +1,61 @@ { - "argumentTypes":[ + "argumentTypes": null, + "arguments": + [ { - "typeIdentifier": "t_rational_3_by_1", - "typeString": "int_const 3" + "argumentTypes": null, + "hexValue": "33", + "id": 6, + "isConstant": false, + "isLValue": false, + "isPure": true, + "kind": "number", + "lValueRequested": false, + "nodeType": "Literal", + "src": "79:1:0", + "subdenomination": null, + "typeDescriptions": + { + "typeIdentifier": "t_rational_3_by_1", + "typeString": "int_const 3" + }, + "value": "3" } ], - "id": 5, - "name": "blockhash", - "nodeType": "Identifier", - "overloadedDeclarations": [], - "referencedDeclaration": -5, - "src": "69:9:0", + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_rational_3_by_1", + "typeString": "int_const 3" + } + ], + "id": 5, + "name": "blockhash", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -5, + "src": "69:9:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_blockhash_view$_t_uint256_$returns$_t_bytes32_$", + "typeString": "function (uint256) view returns (bytes32)" + } + }, + "id": 7, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "69:12:0", + "tryCall": false, "typeDescriptions": { - "typeIdentifier": "t_function_blockhash_view$_t_uint256_$returns$_t_bytes32_$", - "typeString": "function (uint256) view returns (bytes32)" + "typeIdentifier": "t_bytes32", + "typeString": "bytes32" } } \ No newline at end of file diff --git a/remix-analyzer/test/analysis/astBlocks/blockTimestamp.json b/remix-analyzer/test/analysis/astBlocks/blockTimestamp.json new file mode 100644 index 0000000000..61bc2be74a --- /dev/null +++ b/remix-analyzer/test/analysis/astBlocks/blockTimestamp.json @@ -0,0 +1,20 @@ +{ "argumentTypes": null, + "expression": + { "argumentTypes": null, + "id": 109, + "name": "block", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -4, + "src": "1507:5:0", + "typeDescriptions": { "typeIdentifier": "t_magic_block", "typeString": "block" } }, + "id": 110, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberName": "timestamp", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "1507:15:0", + "typeDescriptions": { "typeIdentifier": "t_uint256", "typeString": "uint256" } } \ No newline at end of file diff --git a/remix-analyzer/test/analysis/astBlocks/dynamicDeleteUnaryOp.json b/remix-analyzer/test/analysis/astBlocks/dynamicDeleteUnaryOp.json new file mode 100644 index 0000000000..98d34f7a4e --- /dev/null +++ b/remix-analyzer/test/analysis/astBlocks/dynamicDeleteUnaryOp.json @@ -0,0 +1,28 @@ +{ "argumentTypes": null, + "id": 74, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "nodeType": "UnaryOperation", + "operator": "delete", + "prefix": true, + "src": "627:12:0", + "subExpression": + { "argumentTypes": null, + "id": 73, + "name": "users", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 4, + "src": "634:5:0", + "typeDescriptions": { + "typeIdentifier": "t_array$_t_uint256_$dyn_storage", + "typeString": "uint256[] storage ref" + } + }, + "typeDescriptions": { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + } \ No newline at end of file diff --git a/remix-analyzer/test/analysis/astBlocks/index.js b/remix-analyzer/test/analysis/astBlocks/index.js index fb1d9d6114..5fe840c03d 100644 --- a/remix-analyzer/test/analysis/astBlocks/index.js +++ b/remix-analyzer/test/analysis/astBlocks/index.js @@ -2,7 +2,10 @@ module.exports = { localCall: require('./localCall.json'), contractDefinition: require('./contractDefinition.json'), unaryOperation: require('./unaryOperation.json'), + blockTimestamp: require('./blockTimestamp.json'), + dynamicDeleteUnaryOp: require('./dynamicDeleteUnaryOp.json'), nowAst: require('./nowAst.json'), + requireCall: require('./requireCall.json'), thisLocalCall: require('./thisLocalCall.json'), libCall: require('./libCall.json'), externalDirect: require('./externalDirect.json'), @@ -17,6 +20,7 @@ module.exports = { fullyQualifiedFunctionDefinition: require('./fullyQualifiedFunctionDefinition.json'), selfdestruct: require('./selfdestruct.json'), storageVariableNodes: require('./storageVariableNodes.json'), + abiNamespaceCallNodes: require('./abiNamespaceCallNodes.json'), lowlevelCall: require('./lowlevelCall.json'), parameterFunction: require('./parameterFunction.json'), parameterFunctionCall: require('./parameterFunctionCall.json'), diff --git a/remix-analyzer/test/analysis/astBlocks/parameterFunctionCall.json b/remix-analyzer/test/analysis/astBlocks/parameterFunctionCall.json index c9246dbed6..793b946a74 100644 --- a/remix-analyzer/test/analysis/astBlocks/parameterFunctionCall.json +++ b/remix-analyzer/test/analysis/astBlocks/parameterFunctionCall.json @@ -1,89 +1,56 @@ { - "attributes": { - "argumentTypes": null, - "isConstant": false, - "isLValue": false, - "isPure": false, - "isStructConstructorCall": false, - "lValueRequested": false, - "names": [ - null - ], - "type": "uint256", - "type_conversion": false - }, - "children": [ - { - "attributes": { - "argumentTypes": [ - { - "typeIdentifier": "t_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$", - "typeString": "function (uint256,uint256) pure returns (uint256)" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - }, - { - "typeIdentifier": "t_uint256", - "typeString": "uint256" - } - ], - "overloadedDeclarations": [ - null - ], - "referencedDeclaration": 40, - "type": "function (function (uint256,uint256) pure returns (uint256),uint256,uint256) pure returns (uint256)", - "value": "eval" - }, - "id": 49, - "name": "Identifier", - "src": "361:4:0" - }, - { - "attributes": { - "argumentTypes": null, - "overloadedDeclarations": [ - null - ], - "referencedDeclaration": 15, - "type": "function (uint256,uint256) pure returns (uint256)", - "value": "plus" - }, - "id": 50, - "name": "Identifier", - "src": "366:4:0" - }, - { - "attributes": { - "argumentTypes": null, - "overloadedDeclarations": [ - null - ], - "referencedDeclaration": 42, - "type": "uint256", - "value": "x" - }, - "id": 51, - "name": "Identifier", - "src": "372:1:0" - }, - { - "attributes": { - "argumentTypes": null, - "overloadedDeclarations": [ - null - ], - "referencedDeclaration": 44, - "type": "uint256", - "value": "y" - }, - "id": 52, - "name": "Identifier", - "src": "375:1:0" - } - ], - "id": 53, - "name": "FunctionCall", - "src": "361:16:0" - } \ No newline at end of file + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "id": 216, + "name": "internalPureFunc", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 12, + "src": "1636:16:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_internal_pure$_t_uint256_$returns$_t_uint256_$", + "typeString": "function (uint256) pure returns (uint256)" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_function_internal_pure$_t_uint256_$returns$_t_uint256_$", + "typeString": "function (uint256) pure returns (uint256)" + } + ], + "id": 215, + "name": "funcTakesInternalPure", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 104, + "src": "1614:21:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_internal_pure$_t_function_internal_pure$_t_uint256_$returns$_t_uint256_$_$returns$_t_uint256_$", + "typeString": "function (function (uint256) pure returns (uint256)) pure returns (uint256)" + } + }, + "id": 217, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "1614:39:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } +} \ No newline at end of file diff --git a/remix-analyzer/test/analysis/astBlocks/requireCall.json b/remix-analyzer/test/analysis/astBlocks/requireCall.json new file mode 100644 index 0000000000..4168a65520 --- /dev/null +++ b/remix-analyzer/test/analysis/astBlocks/requireCall.json @@ -0,0 +1,115 @@ +{ + "argumentTypes": null, + "arguments": + [ + { + "argumentTypes": null, + "commonType": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + }, + "id": 8, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "leftExpression": + { + "argumentTypes": null, + "expression": + { + "argumentTypes": null, + "id": 5, + "name": "msg", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -15, + "src": "56:3:0", + "typeDescriptions": + { + "typeIdentifier": "t_magic_message", + "typeString": "msg" + } + }, + "id": 6, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberName": "value", + "nodeType": "MemberAccess", + "referencedDeclaration": null, + "src": "56:9:0", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "nodeType": "BinaryOperation", + "operator": ">=", + "rightExpression": + { + "argumentTypes": null, + "id": 7, + "name": "_amount", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 2, + "src": "69:7:0", + "typeDescriptions": + { + "typeIdentifier": "t_uint256", + "typeString": "uint256" + } + }, + "src": "56:20:0", + "typeDescriptions": + { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_bool", + "typeString": "bool" + } + ], + "id": 4, + "name": "require", + "nodeType": "Identifier", + "overloadedDeclarations": + [ + -18, + -18 + ], + "referencedDeclaration": -18, + "src": "48:7:0", + "typeDescriptions": + { + "typeIdentifier": "t_function_require_pure$_t_bool_$returns$__$", + "typeString": "function (bool) pure" + } + }, + "id": 9, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "names": [], + "nodeType": "FunctionCall", + "src": "48:29:0", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + } \ 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 c1c71dc4fd..2bca5a6172 100644 --- a/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts +++ b/remix-analyzer/test/analysis/staticAnalysisCommon-test.ts @@ -1,8 +1,8 @@ import { default as test} from "tape" import * as common from '../../src/solidity-analyzer/modules/staticAnalysisCommon' -const { localCall, thisLocalCall, libCall, externalDirect, superLocal, assignment, - inlineAssembly, unaryOperation, nowAst, doWhileLoopNode, stateVariableContractNode, - functionDefinition, fullyQualifiedFunctionDefinition, selfdestruct, storageVariableNodes, +const { localCall, thisLocalCall, libCall, externalDirect, superLocal, assignment, abiNamespaceCallNodes, + inlineAssembly, unaryOperation, nowAst, blockTimestamp, stateVariableContractNode, + functionDefinition, requireCall, selfdestruct, storageVariableNodes, dynamicDeleteUnaryOp, lowlevelCall, parameterFunction, parameterFunctionCall, inheritance, blockHashAccess, contractDefinition } = require('./astBlocks') function escapeRegExp (str) { @@ -10,7 +10,7 @@ function escapeRegExp (str) { } test('staticAnalysisCommon.helpers.buildFunctionSignature', function (t) { - t.plan(9) + t.plan(8) t.equal(common.helpers.buildFunctionSignature([common.basicTypes.UINT, common.basicTypes.ADDRESS], [common.basicTypes.BOOL], false), 'function (uint256,address) returns (bool)', @@ -33,19 +33,15 @@ test('staticAnalysisCommon.helpers.buildFunctionSignature', function (t) { 'one param and two return values with payable') t.equal(common.lowLevelCallTypes.CALL.type, - 'function () payable returns (bool)', + 'function (bytes memory) payable returns (bool,bytes memory)', 'check fixed call type') - t.equal(common.lowLevelCallTypes.CALLCODE.type, - 'function () payable returns (bool)', - 'check fixed callcode type') - t.equal(common.lowLevelCallTypes.SEND.type, 'function (uint256) returns (bool)', 'check fixed send type') t.equal(common.lowLevelCallTypes.DELEGATECALL.type, - 'function () returns (bool)', + 'function (bytes memory) returns (bool,bytes memory)', 'check fixed call type') }) @@ -59,8 +55,6 @@ test('staticAnalysisCommon.helpers.name', function (t) { t.ok(common.helpers.memName(node, 'now'), 'should work for names') t.ok(common.helpers.memName(node2, 'call'), 'should work for memberName') t.ok(common.helpers.memName(node2, '.all'), 'regex should work') - - // lowlevelAccessersCommon(t, common.helpers.memName, node) }) test('staticAnalysisCommon.helpers.operator', function (t) { @@ -75,8 +69,6 @@ test('staticAnalysisCommon.helpers.operator', function (t) { t.notOk(common.helpers.operator(node2, escapedPPExact), 'should not work for +++') t.ok(common.helpers.operator(node, escapedPP), 'should work for ++') t.ok(common.helpers.operator(node2, escapedPP), 'should work for +++') - - // lowlevelAccessersCommon(t, common.helpers.operator, node) }) test('staticAnalysisCommon.helpers.nodeType', function (t) { @@ -87,8 +79,6 @@ test('staticAnalysisCommon.helpers.nodeType', function (t) { t.ok(common.helpers.nodeType(node, common.nodeTypes.IDENTIFIER), 'should work for identifier') t.ok(common.helpers.nodeType(node2, common.nodeTypes.FUNCTIONCALL), 'should work for function call') t.ok(common.helpers.nodeType(node2, '^F'), 'regex should work for function call') - - // lowlevelAccessersCommon(t, common.helpers.nodeType, node) }) test('staticAnalysisCommon.helpers.expressionTypeDescription', function (t) { @@ -126,53 +116,11 @@ test('staticAnalysisCommon.helpers.expressionTypeDescription', function (t) { } t.ok(common.helpers.expressionTypeDescription(node.expression, common.basicTypes.PAYABLE_ADDRESS), 'should work for ident') - t.ok(common.helpers.expressionTypeDescription(node, escapeRegExp(common.basicFunctionTypes['CALL-v0.5'])), 'should work for funcall') + t.ok(common.helpers.expressionTypeDescription(node, escapeRegExp(common.basicFunctionTypes.CALL)), 'should work for funcall') t.ok(common.helpers.expressionTypeDescription(node, '^function \\('), 'regex should work') - - // lowlevelAccessersCommon(t, common.helpers.expressionType, node) }) -// // test('staticAnalysisCommon.helpers.nrOfChildren', function (t) { -// // t.plan(10) -// // const node = { name: 'Identifier', children: ['a', 'b'], attributes: { value: 'now', type: 'uint256' } } -// // const node2 = { name: 'FunctionCall', children: [], attributes: { member_name: 'call', type: 'function () payable returns (bool)' } } -// // const node3 = { name: 'FunctionCall', attributes: { member_name: 'call', type: 'function () payable returns (bool)' } } - -// // t.ok(common.helpers.nrOfChildren(node, 2), 'should work for 2 children') -// // t.notOk(common.helpers.nrOfChildren(node, '1+2'), 'regex should not work') -// // t.ok(common.helpers.nrOfChildren(node2, 0), 'should work for 0 children') -// // t.ok(common.helpers.nrOfChildren(node3, 0), 'should work without children arr') - -// // lowlevelAccessersCommon(t, common.helpers.nrOfChildren, node) -// // }) - -// // test('staticAnalysisCommon.helpers.minNrOfChildren', function (t) { -// // t.plan(13) -// // const node = { name: 'Identifier', children: ['a', 'b'], attributes: { value: 'now', type: 'uint256' } } -// // const node2 = { name: 'FunctionCall', children: [], attributes: { member_name: 'call', type: 'function () payable returns (bool)' } } -// // const node3 = { name: 'FunctionCall', attributes: { member_name: 'call', type: 'function () payable returns (bool)' } } - -// // t.ok(common.helpers.minNrOfChildren(node, 2), 'should work for 2 children') -// // t.ok(common.helpers.minNrOfChildren(node, 1), 'should work for 1 children') -// // t.ok(common.helpers.minNrOfChildren(node, 0), 'should work for 0 children') -// // t.notOk(common.helpers.minNrOfChildren(node, 3), 'has less than 3 children') -// // t.notOk(common.helpers.minNrOfChildren(node, '1+2'), 'regex should not work') -// // t.ok(common.helpers.minNrOfChildren(node2, 0), 'should work for 0 children') -// // t.ok(common.helpers.minNrOfChildren(node3, 0), 'should work without children arr') - -// // lowlevelAccessersCommon(t, common.helpers.minNrOfChildren, node) -// // }) - -// function lowlevelAccessersCommon (t, f, someNode) { -// t.ok(f(someNode), 'always ok if type is undefined') -// t.ok(f(someNode, undefined), 'always ok if name is undefined 2') -// t.notOk(f(null, undefined), 'false on no node') -// t.notOk(f(null, 'call'), 'false on no node') -// t.notOk(f(undefined, null), 'false on no node') -// t.notOk(f(), 'false on no params') -// } - -// // #################### Trivial Getter Test +// #################### Trivial Getter Test test('staticAnalysisCommon.getType', function (t) { t.plan(2) @@ -189,11 +137,11 @@ test('staticAnalysisCommon.getType', function (t) { "typeString": "uint256" } } - t.ok(common.getType(blockHashAccess) === 'function (uint256) view returns (bytes32)', 'gettype should work for different nodes') + t.ok(common.getType(blockHashAccess) === 'bytes32', 'gettype should work for different nodes') t.ok(common.getType(node) === 'uint256', 'gettype should work for different nodes') }) -// // #################### Complex Getter Test +// #################### Complex Getter Test test('staticAnalysisCommon.getFunctionCallType', function (t) { t.plan(4) @@ -426,113 +374,87 @@ test('staticAnalysisCommon.isNowAccess', function (t) { t.ok(common.isNowAccess(nowAst), 'is now used should work') }) -// test('staticAnalysisCommon.isBlockTimestampAccess', function (t) { -// t.plan(3) -// const node = { name: 'MemberAccess', children: [{attributes: { value: 'block', type: 'block' }}], attributes: { value: 'timestamp', type: 'uint256' } } -// t.notOk(common.isThisLocalCall(node), 'is this.local_method() used should not work') -// t.ok(common.isBlockTimestampAccess(node), 'is block.timestamp used should work') -// t.notOk(common.isNowAccess(node), 'is now used should not work') -// }) - -// test('staticAnalysisCommon.isBlockBlockhashAccess', function (t) { -// t.plan(4) -// t.notOk(common.isThisLocalCall(blockHashAccess), 'is this.local_method() used should not work') -// t.notOk(common.isBlockTimestampAccess(blockHashAccess), 'is block.timestamp used should not work') -// t.ok(common.isBlockBlockHashAccess(blockHashAccess), 'blockhash should work') // todo: -// t.notOk(common.isNowAccess(blockHashAccess), 'is now used should not work') -// }) - -// test('staticAnalysisCommon.isThisLocalCall', function (t) { -// t.plan(3) -// t.ok(common.isThisLocalCall(thisLocalCall), 'is this.local_method() used should work') -// t.notOk(common.isBlockTimestampAccess(thisLocalCall), 'is block.timestamp used should not work') -// t.notOk(common.isNowAccess(thisLocalCall), 'is now used should not work') -// }) - -// test('staticAnalysisCommon.isSuperLocalCall', function (t) { -// t.plan(4) -// t.ok(common.isSuperLocalCall(superLocal), 'is super.local_method() used should work') -// t.notOk(common.isThisLocalCall(superLocal), 'is this.local_method() used should not work') -// t.notOk(common.isBlockTimestampAccess(superLocal), 'is block.timestamp used should not work') -// t.notOk(common.isNowAccess(superLocal), 'is now used should not work') -// }) - -// test('staticAnalysisCommon.isLibraryCall', function (t) { -// t.plan(5) -// t.ok(common.isLibraryCall(libCall), 'is lib call should not work') -// t.notOk(common.isSuperLocalCall(libCall), 'is super.local_method() used should not work') -// t.notOk(common.isThisLocalCall(libCall), 'is this.local_method() used should not work') -// t.notOk(common.isBlockTimestampAccess(libCall), 'is block.timestamp used should not work') -// t.notOk(common.isNowAccess(libCall), 'is now used should not work') -// }) - -// test('staticAnalysisCommon.isLocalCall', function (t) { -// t.plan(5) -// t.ok(common.isLocalCall(localCall), 'isLocalCall') -// t.notOk(common.isLowLevelCall(localCall), 'is not low level call') -// t.notOk(common.isExternalDirectCall(localCall), 'is not external direct call') -// t.notOk(common.isEffect(localCall), 'is not effect') -// t.notOk(common.isInteraction(localCall), 'is not interaction') -// }) - -// test('staticAnalysisCommon.isLowLevelCall', function (t) { -// t.plan(6) -// t.ok(common.isLowLevelSendInst(lowlevelCall.sendAst) && common.isLowLevelCall(lowlevelCall.sendAst), 'send is llc should work') -// t.ok(common.isLowLevelCallInst(lowlevelCall.callAst) && common.isLowLevelCall(lowlevelCall.callAst), 'call is llc should work') -// t.notOk(common.isLowLevelCallInst(lowlevelCall.callcodeAst), 'callcode is not call') -// t.ok(common.isLowLevelCallcodeInst(lowlevelCall.callcodeAst) && common.isLowLevelCall(lowlevelCall.callcodeAst), 'callcode is llc should work') -// t.notOk(common.isLowLevelCallcodeInst(lowlevelCall.callAst), 'call is not callcode') -// t.ok(common.isLowLevelDelegatecallInst(lowlevelCall.delegatecallAst) && common.isLowLevelCall(lowlevelCall.delegatecallAst), 'delegatecall is llc should work') -// }) - -// test('staticAnalysisCommon: Call of parameter function', function (t) { -// t.plan(7) -// t.ok(common.isLocalCall(parameterFunction), 'is not LocalCall') -// t.notOk(common.isThisLocalCall(parameterFunction), 'is not this local call') -// t.notOk(common.isSuperLocalCall(parameterFunction), 'is not super local call') -// t.notOk(common.isExternalDirectCall(parameterFunction), 'is not ExternalDirectCall') -// t.notOk(common.isLibraryCall(parameterFunction), 'is not LibraryCall') - -// t.equals(common.getFunctionCallType(parameterFunction), 'function (uint256,uint256) pure returns (uint256)', 'Extracts right type') -// t.equals(common.getFunctionCallTypeParameterType(parameterFunction), 'uint256,uint256', 'Extracts param right type') -// }) - -// test('staticAnalysisCommon: function call with of function with function parameter', function (t) { -// t.plan(2) -// t.equals(common.getFunctionCallType(parameterFunctionCall), 'function (function (uint256,uint256) pure returns (uint256),uint256,uint256) pure returns (uint256)', 'Extracts right type') -// t.equals(common.getFunctionCallTypeParameterType(parameterFunctionCall), 'function (uint256,uint256) pure returns (uint256),uint256,uint256', 'Extracts param right type') -// }) - -// test('staticAnalysisCommon: require call', function (t) { -// t.plan(3) -// const node = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'isStructConstructorCall': false, 'lValueRequested': false, 'names': [null], 'type': 'tuple()', 'type_conversion': false}, 'children': [{'attributes': {'argumentTypes': [{'typeIdentifier': 't_bool', 'typeString': 'bool'}, {'typeIdentifier': 't_stringliteral_80efd193f332877914d93edb0b3ef5c6a7eecd00c6251c3fd7f146b60b40e6cd', 'typeString': 'literal_string \'fuu\''}], 'overloadedDeclarations': [90, 91], 'referencedDeclaration': 91, 'type': 'function (bool,string memory) pure', 'value': 'require'}, 'id': 50, 'name': 'Identifier', 'src': '462:7:0'}, {'attributes': {'argumentTypes': null, 'commonType': {'typeIdentifier': 't_address', 'typeString': 'address'}, 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'operator': '==', 'type': 'bool'}, 'children': [{'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'member_name': 'sender', 'referencedDeclaration': null, 'type': 'address'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 87, 'type': 'msg', 'value': 'msg'}, 'id': 51, 'name': 'Identifier', 'src': '470:3:0'}], 'id': 52, 'name': 'MemberAccess', 'src': '470:10:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 10, 'type': 'address', 'value': 'owner'}, 'id': 53, 'name': 'Identifier', 'src': '484:5:0'}], 'id': 54, 'name': 'BinaryOperation', 'src': '470:19:0'}, {'attributes': {'argumentTypes': null, 'hexvalue': '667575', 'isConstant': false, 'isLValue': false, 'isPure': true, 'lValueRequested': false, 'subdenomination': null, 'token': 'string', 'type': 'literal_string \'fuu\'', 'value': 'fuu'}, 'id': 55, 'name': 'Literal', 'src': '491:5:0'}], 'id': 56, 'name': 'FunctionCall', 'src': '462:35:0'} - -// t.equals(common.isRequireCall(node), true) -// t.equals(common.getFunctionCallType(node), 'function (bool,string memory) pure', 'Extracts right type') -// t.equals(common.getFunctionCallTypeParameterType(node), 'bool,string memory', 'Extracts param right type') -// }) - -// test('staticAnalysisCommon: isDeleteOfDynamicArray', function (t) { -// t.plan(2) -// const node = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'operator': 'delete', 'prefix': true, 'type': 'tuple()'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 4, 'type': 'uint256[] storage ref', 'value': 'users'}, 'id': 58, 'name': 'Identifier', 'src': '514:5:0'}], 'id': 59, 'name': 'UnaryOperation', 'src': '507:12:0'} -// t.equals(common.isDeleteOfDynamicArray(node), true) -// t.equals(common.isDynamicArrayAccess(node.children[0]), true, 'Extracts right type') -// }) - -// test('staticAnalysisCommon: isAbiNamespaceCall', function (t) { -// t.plan(8) -// const node1 = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'isStructConstructorCall': false, 'lValueRequested': false, 'names': [null], 'type': 'bytes memory', 'type_conversion': false}, 'children': [{'attributes': {'argumentTypes': [{'typeIdentifier': 't_uint256', 'typeString': 'uint256'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}], 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'member_name': 'encode', 'referencedDeclaration': null, 'type': 'function () pure returns (bytes memory)'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 64, 'type': 'abi', 'value': 'abi'}, 'id': 26, 'name': 'Identifier', 'src': '245: 3:0'}], 'id': 28, 'name': 'MemberAccess', 'src': '245:10:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 7, 'type': 'uint256', 'value': 'a'}, 'id': 29, 'name': 'Identifier', 'src': '256:1:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 15, 'type': 'uint256', 'value': 'b'}, 'id': 30, 'name': 'Identifier', 'src': '258:1:0'}], 'id': 31, 'name': 'FunctionCall', 'src': '245:15:0'} -// const node2 = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'isStructConstructorCall': false, 'lValueRequested': false, 'names': [null], 'type': 'bytes memory', 'type_conversion': false}, 'children': [{'attributes': {'argumentTypes': [{'typeIdentifier': 't_uint256', 'typeString': 'uint256'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}], 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'member_name': 'encodePacked', 'referencedDeclaration': null, 'type': 'function () pure returns (bytes memory)'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 64, 'type': 'abi', 'value': 'abi'}, 'id': 33, 'name': 'Identifier', 'src': '279:3:0'}], 'id': 35, 'name': 'MemberAccess', 'src': '279:16:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 7, 'type': 'uint256', 'value': 'a'}, 'id': 36, 'name': 'Identifier', 'src': '296:1:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 15, 'type': 'uint256', 'value': 'b'}, 'id': 37, 'name': 'Identifier', 'src': '298:1:0'}], 'id': 38, 'name': 'FunctionCall', 'src': '279:21:0'} -// const node3 = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'isStructConstructorCall': false, 'lValueRequested': false, 'names': [null], 'type': 'bytes memory', 'type_conversion': false}, 'children': [{'attributes': {'argumentTypes': [{'typeIdentifier': 't_bytes4', 'typeString': 'bytes4'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}], 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'member_name': 'encodeWithSelector', 'referencedDeclaration': null, 'type': 'function (bytes4) pure returns (bytes memory)'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 64, 'type': 'abi', 'value': 'abi'}, 'id': 40, 'name': 'Identifier', 'src': '319:3:0'}], 'id': 42, 'name': 'MemberAccess', 'src': '319:22:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 19, 'type': 'bytes4', 'value': 'selector'}, 'id': 43, 'name': 'Identifier', 'src': '342:8:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 7, 'type': 'uint256', 'value': 'a'}, 'id': 44, 'name': 'Identifier', 'src': '352:1:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 15, 'type': 'uint256', 'value': 'b'}, 'id': 45, 'name': 'Identifier', 'src': '355:1:0'}], 'id': 46, 'name': 'FunctionCall', 'src': '319:38:0'} -// const node4 = {'attributes': {'argumentTypes': null, 'isConstant': false, 'isLValue': false, 'isPure': false, 'isStructConstructorCall': false, 'lValueRequested': false, 'names': [null], 'type': 'bytes memory', 'type_conversion': false}, 'children': [{'attributes': {'argumentTypes': [{'typeIdentifier': 't_string_memory_ptr', 'typeString': 'string memory'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}, {'typeIdentifier': 't_uint256', 'typeString': 'uint256'}], 'isConstant': false, 'isLValue': false, 'isPure': false, 'lValueRequested': false, 'member_name': 'encodeWithSignature', 'referencedDeclaration': null, 'type': 'function (string memory) pure returns (bytes memory)'}, 'children': [{'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 64, 'type': 'abi', 'value': 'abi'}, 'id': 48, 'name': 'Identifier', 'src': '367:3:0'}], 'id': 50, 'name': 'MemberAccess', 'src': '367:23:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 11, 'type': 'string memory', 'value': 'sig'}, 'id': 51, 'name': 'Identifier', 'src': '391:3:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 7, 'type': 'uint256', 'value': 'a'}, 'id': 52, 'name': 'Identifier', 'src': '396:1:0'}, {'attributes': {'argumentTypes': null, 'overloadedDeclarations': [null], 'referencedDeclaration': 15, 'type': 'uint256', 'value': 'b'}, 'id': 53, 'name': 'Identifier', 'src': '399:1:0'}], 'id': 54, 'name': 'FunctionCall', 'src': '367:34:0'} - -// t.equals(common.isAbiNamespaceCall(node1), true, 'encode abi') -// t.equals(common.isAbiNamespaceCall(node2), true, 'encodePacked abi') -// t.equals(common.isAbiNamespaceCall(node3), true, 'encodeWithSelector abi') -// t.equals(common.isAbiNamespaceCall(node4), true, 'encodeWithSignature abi') - -// t.equals(common.isBuiltinFunctionCall(node1), true, 'encode Builtin') -// t.equals(common.isBuiltinFunctionCall(node2), true, 'encodePacked Builtin') -// t.equals(common.isBuiltinFunctionCall(node3), true, 'encodeWithSelector Builtin') -// t.equals(common.isBuiltinFunctionCall(node4), true, 'encodeWithSignature Builtin') -// }) +test('staticAnalysisCommon.isBlockTimestampAccess', function (t) { + t.plan(3) + t.notOk(common.isThisLocalCall(blockTimestamp), 'is this.local_method() used should not work') + t.ok(common.isBlockTimestampAccess(blockTimestamp), 'is block.timestamp used should work') + t.notOk(common.isNowAccess(blockTimestamp), 'is now used should not work') +}) + +test('staticAnalysisCommon.isBlockBlockhashAccess', function (t) { + t.plan(2) + t.ok(common.isBlockBlockHashAccess(blockHashAccess), 'blockhash should work') + t.notOk(common.isNowAccess(blockHashAccess.expression), 'is now used should not work') +}) + +test('staticAnalysisCommon.isThisLocalCall', function (t) { + t.plan(2) + t.ok(common.isThisLocalCall(thisLocalCall.expression), 'is this.local_method() used should work') + t.notOk(common.isBlockTimestampAccess(thisLocalCall.expression), 'is block.timestamp used should not work') +}) + +test('staticAnalysisCommon.isSuperLocalCall', function (t) { + t.plan(3) + t.ok(common.isSuperLocalCall(superLocal.expression), 'is super.local_method() used should work') + t.notOk(common.isThisLocalCall(superLocal.expression), 'is this.local_method() used should not work') + t.notOk(common.isBlockTimestampAccess(superLocal.expression), 'is block.timestamp used should not work') +}) + +test('staticAnalysisCommon.isLibraryCall', function (t) { + t.plan(4) + t.ok(common.isLibraryCall(libCall.expression), 'is lib call should not work') + t.notOk(common.isSuperLocalCall(libCall.expression), 'is super.local_method() used should not work') + t.notOk(common.isThisLocalCall(libCall.expression), 'is this.local_method() used should not work') + t.notOk(common.isBlockTimestampAccess(libCall.expression), 'is block.timestamp used should not work') +}) + +test('staticAnalysisCommon.isLocalCall', function (t) { + t.plan(1) + t.ok(common.isLocalCall(localCall), 'isLocalCall') +}) + +test('staticAnalysisCommon.isLowLevelCall', function (t) { + t.plan(3) + t.ok(common.isLLSend(lowlevelCall.sendAst) && common.isLowLevelCall(lowlevelCall.sendAst), 'send is llc should work') + t.ok(common.isLLCall(lowlevelCall.callAst) && common.isLowLevelCall(lowlevelCall.callAst), 'call is llc should work') + t.ok(common.isLLDelegatecall(lowlevelCall.delegatecallAst) && common.isLowLevelCall(lowlevelCall.delegatecallAst), 'delegatecall is llc should work') +}) + +test('staticAnalysisCommon: Call of parameter function', function (t) { + t.plan(3) + t.ok(common.isLocalCall(parameterFunction), 'is not LocalCall') + t.equals(common.getFunctionCallType(parameterFunction), 'function (uint256,uint256)', 'Extracts right type') + t.equals(common.getFunctionCallTypeParameterType(parameterFunction), 'uint256,uint256', 'Extracts param right type') +}) + +test('staticAnalysisCommon: function call with of function with function parameter', function (t) { + t.plan(2) + t.equals(common.getFunctionCallType(parameterFunctionCall), 'function (function (uint256) pure returns (uint256)) pure returns (uint256)', 'Extracts right type') + t.equals(common.getFunctionCallTypeParameterType(parameterFunctionCall), 'function (uint256) pure returns (uint256)', 'Extracts param right type') +}) + +test('staticAnalysisCommon: require call', function (t) { + t.plan(3) + t.equals(common.isRequireCall(requireCall), true) + t.equals(common.getFunctionCallType(requireCall), 'function (bool) pure', 'Extracts right type') + t.equals(common.getFunctionCallTypeParameterType(requireCall), 'bool', 'Extracts param right type') +}) + +test('staticAnalysisCommon: isDeleteOfDynamicArray', function (t) { + t.plan(2) + t.ok(common.isDeleteOfDynamicArray(dynamicDeleteUnaryOp), 'is dynamic array deletion') + t.ok(common.isDynamicArrayAccess(dynamicDeleteUnaryOp.subExpression), 'Extracts right type') +}) + +test('staticAnalysisCommon: isAbiNamespaceCall', function (t) { + t.plan(8) + t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encode), true, 'encode abi') + t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodePacked), true, 'encodePacked abi') + t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodeWithSelector), true, 'encodeWithSelector abi') + t.equals(common.isAbiNamespaceCall(abiNamespaceCallNodes.encodeWithSignature), true, 'encodeWithSignature abi') + + t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encode), true, 'encode Builtin') + t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodePacked), true, 'encodePacked Builtin') + t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodeWithSelector), true, 'encodeWithSelector Builtin') + t.equals(common.isBuiltinFunctionCall(abiNamespaceCallNodes.encodeWithSignature), true, 'encodeWithSignature Builtin') +}) diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol index 3dace99902..5a21fe3c64 100644 --- a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/deleteDynamicArray.sol @@ -1,4 +1,4 @@ -pragma solidity >=0.4.9 <0.6.0; +pragma solidity >=0.4.9 <0.7.0; contract arr { uint[] users; diff --git a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol index 8294c9e46f..54a16383d2 100644 --- a/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol +++ b/remix-analyzer/test/analysis/test-contracts/solidity-v0.5/library.sol @@ -50,5 +50,9 @@ contract C { if (!Set.insert(knownValues, value)) revert(); } + + function testt() public view returns (uint) { + return block.timestamp; + } // In this contract, we can also directly access knownValues.flags, if we want. } \ No newline at end of file