From 04dccc9254075194a9d1b046ee19073fb275fab5 Mon Sep 17 00:00:00 2001 From: aniket-engg Date: Wed, 26 Feb 2020 19:22:29 +0530 Subject: [PATCH] method updates --- .../modules/abstractAstView.ts | 6 +- .../modules/constantFunctions.ts | 2 +- .../modules/deleteDynamicArrays.ts | 6 +- .../forLoopIteratesOverDynamicArray.ts | 26 ++- .../modules/intDivisionTruncate.ts | 6 +- .../modules/lowLevelCalls.ts | 6 +- .../modules/staticAnalysisCommon.ts | 153 +++++++++--------- .../solidity-analyzer/modules/thisLocal.ts | 6 +- remix-analyzer/src/types.ts | 14 +- 9 files changed, 108 insertions(+), 117 deletions(-) diff --git a/remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts b/remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts index d3f4540de0..bca139cee4 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts @@ -3,7 +3,7 @@ import { getStateVariableDeclarationsFormContractNode, getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName, getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon' import { AstWalker } from 'remix-astwalker' -import { CommonAstNode, FunctionDefinitionAstNode, ParameterListAstNode } from 'types' +import { CommonAstNode, FunctionDefinitionAstNode, ParameterListAstNode, ModifierDefinitionAstNode } from 'types' export default class abstractAstView { contracts = [] @@ -159,11 +159,11 @@ export default class abstractAstView { return that.getCurrentContract(that).modifiers[that.currentModifierIndex] } - private getLocalParameters (funcNode) { + private getLocalParameters (funcNode: FunctionDefinitionAstNode | ModifierDefinitionAstNode) { return getFunctionOrModifierDefinitionParameterPart(funcNode).parameters.map(getType) } - private getReturnParameters (funcNode) { + private getReturnParameters (funcNode: FunctionDefinitionAstNode) { return this.getLocalVariables(getFunctionDefinitionReturnParameterPart(funcNode)).map((n) => { return { type: getType(n), diff --git a/remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts b/remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts index b55d40a925..30762c28f5 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts @@ -17,7 +17,7 @@ export default class constantFunctions implements AnalyzerModule { abstractAst: AbstractAst = new AbstractAst() visit = this.abstractAst.build_visit( - (node: CommonAstNode) => isLowLevelCall(node) || + (node: any) => isLowLevelCall(node) || isTransfer(node) || isExternalDirectCall(node) || isEffect(node) || diff --git a/remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts b/remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts index 11428a78f4..3463c0eee4 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/deleteDynamicArrays.ts @@ -1,16 +1,16 @@ import { default as category } from './categories' import { isDeleteOfDynamicArray } from './staticAnalysisCommon' import { default as algorithm } from './algorithmCategories' -import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' +import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, UnaryOperationAstNode} from './../../types' export default class deleteDynamicArrays implements AnalyzerModule { - rel: AstNodeLegacy[] = [] + rel: UnaryOperationAstNode[] = [] name: string = 'Delete on dynamic Array: ' description: string = 'Use require and appropriately' category: ModuleCategory = category.GAS algorithm: ModuleAlgorithm = algorithm.EXACT - visit (node: AstNodeLegacy): void { + visit (node: UnaryOperationAstNode): void { if (isDeleteOfDynamicArray(node)) this.rel.push(node) } diff --git a/remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts b/remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts index 4192ca31d5..a16820568a 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts @@ -1,31 +1,23 @@ import { default as category } from './categories' import { default as algorithm } from './algorithmCategories' -import { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } from './staticAnalysisCommon' -import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, CommonAstNode} from './../../types' +import { isDynamicArrayLengthAccess } from './staticAnalysisCommon' +import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, ForStatementAstNode} from './../../types' export default class forLoopIteratesOverDynamicArray implements AnalyzerModule { - relevantNodes: CommonAstNode[] = [] + relevantNodes: ForStatementAstNode[] = [] name: string = 'For loop iterates over dynamic array: ' description: string = 'The number of \'for\' loop iterations depends on dynamic array\'s size' category: ModuleCategory = category.GAS algorithm: ModuleAlgorithm = algorithm.EXACT - visit (node: CommonAstNode): void { - if (node.nodeType === "Forstatement" && node.children) { - let conditionChildrenNode: AstNodeLegacy | null = null - // Access 'condition' node of 'for' loop statement - const forLoopConditionNode: AstNodeLegacy = node.children[1] - // Access right side of condition as its children - if(forLoopConditionNode && forLoopConditionNode.children){ - conditionChildrenNode = forLoopConditionNode.children[1] - } - // Check if it is a binary operation. if yes, check if its children node access length of dynamic array - if (conditionChildrenNode && conditionChildrenNode.children && isBinaryOperation(conditionChildrenNode) && isDynamicArrayLengthAccess(conditionChildrenNode.children[0])) { - this.relevantNodes.push(node) - } else if (isDynamicArrayLengthAccess(conditionChildrenNode)) { // else check if condition node itself access length of dynamic array + visit (node: ForStatementAstNode): void { + const { condition } = node + // Check if condition is `i < array.length - 1` + if ((condition.nodeType === "BinaryOperation" && condition.rightExpression.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression.leftExpression)) || + // or condition is `i < array.length` + (condition.nodeType === "BinaryOperation" && isDynamicArrayLengthAccess(condition.rightExpression))) { this.relevantNodes.push(node) } - } } report (compilationResults: CompilationResult): ReportObj[] { diff --git a/remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts b/remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts index e0ef80a269..108c81e480 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/intDivisionTruncate.ts @@ -1,16 +1,16 @@ import { default as category } from './categories' import { isIntDivision } from './staticAnalysisCommon' import { default as algorithm } from './algorithmCategories' -import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' +import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, BinaryOperationAstNode} from './../../types' export default class intDivisionTruncate implements AnalyzerModule { - warningNodes: AstNodeLegacy[] = [] + warningNodes: BinaryOperationAstNode[] = [] name: string = 'Data Truncated: ' description: string = 'Division on int/uint values truncates the result.' category: ModuleCategory = category.MISC algorithm: ModuleAlgorithm = algorithm.EXACT - visit (node: AstNodeLegacy): void { + visit (node: BinaryOperationAstNode): void { if (isIntDivision(node)) this.warningNodes.push(node) } diff --git a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts index 409e99a08d..100c817610 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/lowLevelCalls.ts @@ -2,10 +2,10 @@ import { default as category } from './categories' import { isLowLevelCallInst, isLowLevelCallInst050, isLowLevelCallcodeInst, isLowLevelDelegatecallInst, isLowLevelSendInst, isLowLevelSendInst050, isLLDelegatecallInst050, lowLevelCallTypes } from './staticAnalysisCommon' import { default as algorithm } from './algorithmCategories' -import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' +import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, CompilationResult, MemberAccessAstNode} from './../../types' interface llcNode { - node: AstNodeLegacy + node: MemberAccessAstNode type: { ident: string, type: string @@ -19,7 +19,7 @@ export default class lowLevelCalls implements AnalyzerModule { category: ModuleCategory = category.SECURITY algorithm: ModuleAlgorithm = algorithm.EXACT - visit (node : AstNodeLegacy): void { + visit (node : MemberAccessAstNode): void { if (isLowLevelCallInst(node)) { this.llcNodes.push({node: node, type: lowLevelCallTypes.CALL}) } else if (isLowLevelCallInst050(node)) { diff --git a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts index 5df07b50d7..162418afe1 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts @@ -1,6 +1,6 @@ 'use strict' -import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode } from "types" +import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode, BinaryOperationAstNode, FunctionCallAstNode, ExpressionStatementAstNode, UnaryOperationAstNode, IdentifierAstNode, MappingAstNode, IndexAccessAstNode } from "types" const remixLib = require('remix-lib') const util = remixLib.util @@ -433,8 +433,8 @@ function isBinaryOperation (node) { * @funcNode {ASTNode} function defintion node * @return {bool} */ -function hasFunctionBody (funcNode) { - return findFirstSubNodeLTR(funcNode, exactMatch(nodeTypes.BLOCK)) != null +function hasFunctionBody (funcNode: FunctionDefinitionAstNode) { + return funcNode.body != null } /** @@ -442,8 +442,8 @@ function hasFunctionBody (funcNode) { * @node {ASTNode} node to check for * @return {bool} */ -function isDeleteOfDynamicArray (node) { - return isDeleteUnaryOperation(node) && isDynamicArrayAccess(node.children[0]) +function isDeleteOfDynamicArray (node: UnaryOperationAstNode) { + return isDeleteUnaryOperation(node) && isDynamicArrayAccess(node.subExpression) } /** @@ -451,8 +451,8 @@ function isDeleteOfDynamicArray (node) { * @node {ASTNode} node to check for * @return {bool} */ -function isDynamicArrayAccess (node) { - return node && nodeType(node, exactMatch(nodeTypes.IDENTIFIER)) && (node.attributes.type.endsWith('[] storage ref') || node.attributes.type === 'bytes storage ref' || node.attributes.type === 'string storage ref') +function isDynamicArrayAccess (node: IdentifierAstNode) { + return typeDescription(node, '[] storage ref') || typeDescription(node, 'bytes storage ref') || typeDescription(node, 'string storage ref') } /** @@ -460,11 +460,9 @@ function isDynamicArrayAccess (node) { * @node {ASTNode} node to check for * @return {bool} */ -function isDynamicArrayLengthAccess (node) { - return node && // if node exists - nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) && // is memberAccess Node - (node.attributes.member_name === 'length') && // accessing 'length' member - node.children[0].attributes.type.indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number +function isDynamicArrayLengthAccess (node: MemberAccessAstNode) { + return (node.memberName === 'length') && // accessing 'length' member + node.expression['typeDescriptions']['typeString'].indexOf('[]') !== -1 // member is accessed from dynamic array, notice [] without any number } /** @@ -627,8 +625,8 @@ function isConstructor (node: FunctionDefinitionAstNode): boolean { * @node {ASTNode} some AstNode * @return {bool} */ -function isIntDivision (node) { - return isBinaryOperation(node) && operator(node, exactMatch(util.escapeRegExp('/'))) && expressionType(node, util.escapeRegExp('int')) +function isIntDivision (node: BinaryOperationAstNode) { + return operator(node, exactMatch(util.escapeRegExp('/'))) && typeDescription(node.rightExpression, util.escapeRegExp('int')) } /** @@ -646,7 +644,7 @@ function isSubScopeStatement (node) { nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) || nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) || nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT))) && - minNrOfChildren(node, 2) && !nodeType(node.children[1], exactMatch(nodeTypes.BLOCK)) + !nodeType(node.children[1], exactMatch(nodeTypes.BLOCK)) } /** @@ -654,8 +652,8 @@ function isSubScopeStatement (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isBinaryOpInExpression (node) { - return node.nodeType === "ExpressionStatement" && nrOfChildren(node, 1) && isBinaryOperation(node.children[0]) +function isBinaryOpInExpression (node: ExpressionStatementAstNode) { + return node.nodeType === "ExpressionStatement" && node.expression.nodeType === "BinaryOperation" } /** @@ -663,8 +661,8 @@ function isBinaryOpInExpression (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isPlusPlusUnaryOperation (node) { - return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('++'))) +function isPlusPlusUnaryOperation (node: UnaryOperationAstNode) { + return node.operator === '++' } /** @@ -672,8 +670,8 @@ function isPlusPlusUnaryOperation (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isDeleteUnaryOperation (node) { - return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('delete'))) +function isDeleteUnaryOperation (node: UnaryOperationAstNode) { + return node.operator === 'delete' } /** @@ -681,8 +679,8 @@ function isDeleteUnaryOperation (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isMinusMinusUnaryOperation (node) { - return nodeType(node, exactMatch(nodeTypes.UNARYOPERATION)) && operator(node, exactMatch(util.escapeRegExp('--'))) +function isMinusMinusUnaryOperation (node: UnaryOperationAstNode) { + return node.operator === '--' } /** @@ -690,8 +688,8 @@ function isMinusMinusUnaryOperation (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isFullyImplementedContract (node) { - return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION)) && node.attributes.fullyImplemented === true +function isFullyImplementedContract (node: ContractDefinitionAstNode) { + return node.fullyImplemented === true } /** @@ -699,8 +697,8 @@ function isFullyImplementedContract (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLibrary (node) { - return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION)) && node.attributes.isLibrary === true +function isLibrary (node: ContractDefinitionAstNode) { + return node.contractKind === 'library' } /** @@ -708,8 +706,8 @@ function isLibrary (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isCallToNonConstLocalFunction (node) { - return isLocalCall(node) && !expressionType(node.children[0], basicRegex.CONSTANTFUNCTIONTYPE) +function isCallToNonConstLocalFunction (node: FunctionCallAstNode) { + return isLocalCall(node) && !expressionType(node, basicRegex.CONSTANTFUNCTIONTYPE) } /** @@ -717,7 +715,7 @@ function isCallToNonConstLocalFunction (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLibraryCall (node) { +function isLibraryCall (node: MemberAccessAstNode) { return isMemberAccess(node, basicRegex.FUNCTIONTYPE, undefined, basicRegex.LIBRARYTYPE, undefined) } @@ -726,7 +724,7 @@ function isLibraryCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isExternalDirectCall (node) { +function isExternalDirectCall (node: MemberAccessAstNode) { return isMemberAccess(node, basicRegex.EXTERNALFUNCTIONTYPE, undefined, basicRegex.CONTRACTTYPE, undefined) && !isThisLocalCall(node) && !isSuperLocalCall(node) } @@ -735,10 +733,8 @@ function isExternalDirectCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isNowAccess (node) { - return nodeType(node, exactMatch(nodeTypes.IDENTIFIER)) && - expressionType(node, exactMatch(basicTypes.UINT)) && - memName(node, exactMatch('now')) +function isNowAccess (node: IdentifierAstNode) { + return node.name === "now" && typeDescription(node, exactMatch(basicTypes.UINT)) } /** @@ -746,7 +742,7 @@ function isNowAccess (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isBlockTimestampAccess (node) { +function isBlockTimestampAccess (node: MemberAccessAstNode) { return isSpecialVariableAccess(node, specialVariables.BLOCKTIMESTAMP) } @@ -755,7 +751,7 @@ function isBlockTimestampAccess (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isBlockBlockHashAccess (node) { +function isBlockBlockHashAccess (node: MemberAccessAstNode) { return isSpecialVariableAccess(node, specialVariables.BLOCKHASH) || isBuiltinFunctionCall(node) && getLocalCallName(node) === 'blockhash' } @@ -764,7 +760,7 @@ function isBlockBlockHashAccess (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isThisLocalCall (node) { +function isThisLocalCall (node: MemberAccessAstNode) { return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('this'), basicRegex.CONTRACTTYPE, undefined) } @@ -773,7 +769,7 @@ function isThisLocalCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isSuperLocalCall (node) { +function isSuperLocalCall (node: MemberAccessAstNode) { return isMemberAccess(node, basicRegex.FUNCTIONTYPE, exactMatch('super'), basicRegex.CONTRACTTYPE, undefined) } @@ -782,13 +778,11 @@ function isSuperLocalCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLocalCall (node) { - return nodeType(node, exactMatch(nodeTypes.FUNCTIONCALL)) && - minNrOfChildren(node, 1) && - nodeType(node.children[0], exactMatch(nodeTypes.IDENTIFIER)) && - expressionType(node.children[0], basicRegex.FUNCTIONTYPE) && - !expressionType(node.children[0], basicRegex.EXTERNALFUNCTIONTYPE) && - nrOfChildren(node.children[0], 0) +function isLocalCall (node: FunctionCallAstNode) { + return node.kind === 'functionCall' && + node.expression.nodeType === 'Identifier' && + expressionTypeDescription(node, basicRegex.FUNCTIONTYPE) && + !expressionTypeDescription(node, basicRegex.FUNCTIONTYPE) } /** @@ -811,7 +805,7 @@ function isLowLevelCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLSend050 (node) { +function isLLSend050 (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) @@ -822,7 +816,7 @@ function isLLSend050 (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLSend (node) { +function isLLSend (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.SEND.type)), undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.SEND.ident)) @@ -833,7 +827,7 @@ function isLLSend (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLCall (node) { +function isLLCall (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.CALL.type)), undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALL.ident)) @@ -844,7 +838,7 @@ function isLLCall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLCall050 (node) { +function isLLCall050 (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes['CALL-v0.5'].type)), undefined, exactMatch(basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes['CALL-v0.5'].ident)) @@ -855,7 +849,7 @@ function isLLCall050 (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLCallcode (node) { +function isLLCallcode (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.CALLCODE.type)), undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.CALLCODE.ident)) @@ -866,7 +860,7 @@ function isLLCallcode (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLDelegatecall (node) { +function isLLDelegatecall (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.DELEGATECALL.type)), undefined, exactMatch(basicTypes.ADDRESS), exactMatch(lowLevelCallTypes.DELEGATECALL.ident)) @@ -877,7 +871,7 @@ function isLLDelegatecall (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isLLDelegatecall050 (node) { +function isLLDelegatecall050 (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes['DELEGATECALL-v0.5'].type)), undefined, matches(basicTypes.PAYABLE_ADDRESS, basicTypes.ADDRESS), exactMatch(lowLevelCallTypes['DELEGATECALL-v0.5'].ident)) @@ -888,7 +882,7 @@ function isLLDelegatecall050 (node) { * @node {ASTNode} some AstNode * @return {bool} */ -function isTransfer (node) { +function isTransfer (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(lowLevelCallTypes.TRANSFER.type)), undefined, matches(basicTypes.ADDRESS, basicTypes.PAYABLE_ADDRESS), exactMatch(lowLevelCallTypes.TRANSFER.ident)) @@ -898,13 +892,13 @@ function isStringToBytesConversion (node) { return isExplicitCast(node, util.escapeRegExp('string *'), util.escapeRegExp('bytes')) } -function isExplicitCast (node, castFromType, castToType) { - return nodeType(node, exactMatch(nodeTypes.FUNCTIONCALL)) && nrOfChildren(node, 2) && - nodeType(node.children[0], exactMatch(nodeTypes.ELEMENTARYTYPENAMEEXPRESSION)) && memName(node.children[0], castToType) && - nodeType(node.children[1], exactMatch(nodeTypes.IDENTIFIER)) && expressionType(node.children[1], castFromType) +function isExplicitCast (node: FunctionCallAstNode, castFromType: string, castToType: string) { + return node.kind === "typeConversion" && + nodeType(node.expression, exactMatch(nodeTypes.ELEMENTARYTYPENAMEEXPRESSION)) && node.expression.typeName.name === castToType && + nodeType(node.arguments[0], exactMatch(nodeTypes.IDENTIFIER)) && typeDescription(node.arguments[0], castFromType) } -function isBytesLengthCheck (node) { +function isBytesLengthCheck (node: MemberAccessAstNode) { return isMemberAccess(node, exactMatch(util.escapeRegExp(basicTypes.UINT)), undefined, util.escapeRegExp('bytes *'), 'length') } @@ -925,41 +919,48 @@ function isBytesLengthCheck (node) { * @return {bool} * TODO: This should be removed once for loop iterates Over dynamic array fixed */ -function isForLoop (node) { - return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) -} +// function isForLoop (node) { +// return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) +// } // #################### Complex Node Identification - Private -function isMemberAccess (node: MemberAccessAstNode, retType, accessor, accessorType, memberName) { +function isMemberAccess (node: MemberAccessAstNode, retType: string, accessor: string| undefined, accessorType, memberName: string | undefined) { return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) && expressionType(node, retType) && memName(node, memberName) && - nrOfChildren(node, 1) && memName(node.expression, accessor) && expressionType(node.expression, accessorType) } -function isSpecialVariableAccess (node, varType) { +function isSpecialVariableAccess (node: MemberAccessAstNode, varType) { return isMemberAccess(node, exactMatch(util.escapeRegExp(varType.type)), varType.obj, varType.obj, varType.member) } // #################### Node Identification Primitives -function nrOfChildren (node, nr) { - return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length === nr) +// function nrOfChildren (node, nr) { +// return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length === nr) +// } + +// function minNrOfChildren (node, nr) { +// return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length >= nr) +// } + +function expressionType (node, typeRegex) { + return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString) } -function minNrOfChildren (node, nr) { - return (node && (nr === undefined || nr === null)) || (node && nr === 0 && !node.children) || (node && node.children && node.children.length >= nr) +function expressionTypeDescription (node, typeRegex) { + return new RegExp(typeRegex).test(node.expression.typeDescriptions.typeString) } -function expressionType (node, typeRegex) { - return (node && !typeRegex) || (node && node.attributes && new RegExp(typeRegex).test(node.attributes.type)) +function typeDescription (node, typeRegex) { + return new RegExp(typeRegex).test(node.typeDescriptions.typeString) } function nodeType (node, typeRegex) { - return (node && !typeRegex) || (node && new RegExp(typeRegex).test(node.name)) + return new RegExp(typeRegex).test(node.nodeType) } function memName (node, memNameRegex) { @@ -968,7 +969,7 @@ function memName (node, memNameRegex) { } function operator (node, opRegex) { - return (node && !opRegex) || (node && new RegExp(opRegex).test(node.attributes.operator)) + return new RegExp(opRegex).test(node.operator) } // #################### Helpers @@ -1021,8 +1022,8 @@ function findFirstSubNodeLTR (node, type) { } const helpers = { - nrOfChildren, - minNrOfChildren, + // nrOfChildren, + // minNrOfChildren, expressionType, nodeType, memName, @@ -1104,7 +1105,7 @@ export { isIntDivision, isStringToBytesConversion, isBytesLengthCheck, - isForLoop, + // isForLoop, // #################### Trivial Node Identification isDeleteUnaryOperation, diff --git a/remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts b/remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts index 76ebdcb1d8..8592886570 100644 --- a/remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts +++ b/remix-analyzer/src/solidity-analyzer/modules/thisLocal.ts @@ -1,16 +1,16 @@ import { default as category } from './categories' import { isThisLocalCall } from './staticAnalysisCommon' import { default as algorithm } from './algorithmCategories' -import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' +import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, MemberAccessAstNode} from './../../types' export default class thisLocal implements AnalyzerModule { - warningNodes: AstNodeLegacy[] = [] + warningNodes: MemberAccessAstNode[] = [] name: string = 'This on local calls: ' description: string = 'Invocation of local functions via this' category: ModuleCategory = category.GAS algorithm: ModuleAlgorithm = algorithm.EXACT - visit (node: AstNodeLegacy): void { + visit (node: MemberAccessAstNode): void { if (isThisLocalCall(node)) this.warningNodes.push(node) } diff --git a/remix-analyzer/src/types.ts b/remix-analyzer/src/types.ts index e2027bf7c5..8ff2fca3b2 100644 --- a/remix-analyzer/src/types.ts +++ b/remix-analyzer/src/types.ts @@ -337,7 +337,7 @@ export interface WhileStatementAstNode { id: number nodeType: 'WhileStatement' | 'DoWhileStatement' src: string - condition: object + condition: any body: BlockAstNode } @@ -346,7 +346,7 @@ export interface ForStatementAstNode { nodeType: 'ForStatement' src: string initializationExpression: VariableDeclarationStatementAstNode - condition: object + condition: any loopExpression: ExpressionStatementAstNode body: BlockAstNode } @@ -397,7 +397,7 @@ export interface ExpressionStatementAstNode { id: number nodeType: 'ExpressionStatement' src: string - expression: object + expression: any } interface ExpressionAttributes { @@ -441,7 +441,7 @@ export interface UnaryOperationAstNode extends ExpressionAttributes { src: string prefix: boolean operator: string - subExpression: object + subExpression: any } export interface BinaryOperationAstNode extends ExpressionAttributes { @@ -458,7 +458,7 @@ export interface FunctionCallAstNode extends ExpressionAttributes { id: number nodeType: 'FunctionCall' src: string - expression: object + expression: any names: Array arguments: object tryCall: boolean @@ -481,10 +481,8 @@ export interface NewExpressionAstNode extends ExpressionAttributes { typeName: UserDefinedTypeNameAstNode | ElementaryTypeNameAstNode } -export interface MemberAccessAstNode extends ExpressionAttributes { - id: number +export interface MemberAccessAstNode extends CommonAstNode, ExpressionAttributes { nodeType: 'MemberAccess' - src: string memberName: string expression: object referencedDeclaration: number | null