node identification methods removed

pull/7/head
aniket-engg 5 years ago committed by Aniket
parent d5548b6201
commit e9ac30cbed
  1. 22
      remix-analyzer/src/solidity-analyzer/modules/abstractAstView.ts
  2. 14
      remix-analyzer/src/solidity-analyzer/modules/constantFunctions.ts
  3. 27
      remix-analyzer/src/solidity-analyzer/modules/etherTransferInLoop.ts
  4. 8
      remix-analyzer/src/solidity-analyzer/modules/forLoopIteratesOverDynamicArray.ts
  5. 9
      remix-analyzer/src/solidity-analyzer/modules/inlineAssembly.ts
  6. 12
      remix-analyzer/src/solidity-analyzer/modules/noReturn.ts
  7. 153
      remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts
  8. 4
      remix-analyzer/src/types.ts
  9. 138
      remix-analyzer/test/analysis/staticAnalysisCommon-test.ts

@ -1,9 +1,9 @@
import { isContractDefinition, getStateVariableDeclarationsFormContractNode, isInheritanceSpecifier, import { getStateVariableDeclarationsFormContractNode,
getInheritsFromName, isModifierDefinition, isModifierInvocation, getContractName, getInheritsFromName, getContractName,
getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName, isVariableDeclaration, getFunctionOrModifierDefinitionParameterPart, getType, getDeclaredVariableName,
getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon' getFunctionDefinitionReturnParameterPart } from './staticAnalysisCommon'
import { AstWalker } from 'remix-astwalker' import { AstWalker } from 'remix-astwalker'
import { CommonAstNode } from 'types' import { CommonAstNode, FunctionDefinitionAstNode, ParameterListAstNode } from 'types'
export default class abstractAstView { export default class abstractAstView {
contracts = [] contracts = []
@ -49,7 +49,7 @@ export default class abstractAstView {
*/ */
build_visit (relevantNodeFilter) { build_visit (relevantNodeFilter) {
var that = this var that = this
return function (node: CommonAstNode) { return function (node: any) {
if (node.nodeType === "ContractDefinition") { if (node.nodeType === "ContractDefinition") {
that.setCurrentContract(that, { that.setCurrentContract(that, {
node: node, node: node,
@ -59,7 +59,7 @@ export default class abstractAstView {
inheritsFrom: [], inheritsFrom: [],
stateVariables: getStateVariableDeclarationsFormContractNode(node) stateVariables: getStateVariableDeclarationsFormContractNode(node)
}) })
} else if (isInheritanceSpecifier(node)) { } else if (node.nodeType === "InheritanceSpecifier") {
const currentContract = that.getCurrentContract(that) const currentContract = that.getCurrentContract(that)
const inheritsFromName = getInheritsFromName(node) const inheritsFromName = getInheritsFromName(node)
currentContract.inheritsFrom.push(inheritsFromName) currentContract.inheritsFrom.push(inheritsFromName)
@ -78,14 +78,14 @@ export default class abstractAstView {
that.getCurrentFunction(that).relevantNodes.push(item.node) that.getCurrentFunction(that).relevantNodes.push(item.node)
} }
}) })
} else if (isModifierDefinition(node)) { } else if (node.nodeType === "ModifierDefinition") {
that.setCurrentModifier(that, { that.setCurrentModifier(that, {
node: node, node: node,
relevantNodes: [], relevantNodes: [],
localVariables: that.getLocalVariables(node), localVariables: that.getLocalVariables(node),
parameters: that.getLocalParameters(node) parameters: that.getLocalParameters(node)
}) })
} else if (isModifierInvocation(node)) { } else if (node.nodeType === "ModifierInvocation") {
if (!that.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.') if (!that.isFunctionNotModifier) throw new Error('abstractAstView.js: Found modifier invocation outside of function scope.')
that.getCurrentFunction(that).modifierInvocations.push(node) that.getCurrentFunction(that).modifierInvocations.push(node)
} else if (relevantNodeFilter(node)) { } else if (relevantNodeFilter(node)) {
@ -160,7 +160,7 @@ export default class abstractAstView {
} }
private getLocalParameters (funcNode) { private getLocalParameters (funcNode) {
return this.getLocalVariables(getFunctionOrModifierDefinitionParameterPart(funcNode)).map(getType) return getFunctionOrModifierDefinitionParameterPart(funcNode).parameters.map(getType)
} }
private getReturnParameters (funcNode) { private getReturnParameters (funcNode) {
@ -172,10 +172,10 @@ export default class abstractAstView {
}) })
} }
private getLocalVariables (funcNode) { private getLocalVariables (funcNode: ParameterListAstNode) {
const locals: any[] = [] const locals: any[] = []
new AstWalker().walk(funcNode, {'*': function (node) { new AstWalker().walk(funcNode, {'*': function (node) {
if (isVariableDeclaration(node)) locals.push(node) if (node.nodeType === "VariableDeclaration") locals.push(node)
return true return true
}}) }})
return locals return locals

@ -1,12 +1,12 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isLowLevelCall, isTransfer, isExternalDirectCall, isEffect, isLocalCallGraphRelevantNode, import { isLowLevelCall, isTransfer, isExternalDirectCall, isEffect, isLocalCallGraphRelevantNode,
isInlineAssembly, isNewExpression, isSelfdestructCall, isDeleteUnaryOperation, isPayableFunction, isSelfdestructCall, isDeleteUnaryOperation, isPayableFunction,
isConstructor, getFullQuallyfiedFuncDefinitionIdent, hasFunctionBody, isConstantFunction, isWriteOnStateVariable, isConstructor, getFullQuallyfiedFuncDefinitionIdent, hasFunctionBody, isConstantFunction, isWriteOnStateVariable,
isStorageVariableDeclaration, isCallToNonConstLocalFunction, getFullQualifiedFunctionCallIdent} from './staticAnalysisCommon' isStorageVariableDeclaration, isCallToNonConstLocalFunction, getFullQualifiedFunctionCallIdent} from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { buildGlobalFuncCallGraph, resolveCallGraphSymbol, analyseCallGraph } from './functionCallGraph' import { buildGlobalFuncCallGraph, resolveCallGraphSymbol, analyseCallGraph } from './functionCallGraph'
import AbstractAst from './abstractAstView' import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, CommonAstNode} from './../../types'
export default class constantFunctions implements AnalyzerModule { export default class constantFunctions implements AnalyzerModule {
name: string = 'Constant functions: ' name: string = 'Constant functions: '
@ -17,13 +17,13 @@ export default class constantFunctions implements AnalyzerModule {
abstractAst: AbstractAst = new AbstractAst() abstractAst: AbstractAst = new AbstractAst()
visit = this.abstractAst.build_visit( visit = this.abstractAst.build_visit(
(node: AstNodeLegacy) => isLowLevelCall(node) || (node: CommonAstNode) => isLowLevelCall(node) ||
isTransfer(node) || isTransfer(node) ||
isExternalDirectCall(node) || isExternalDirectCall(node) ||
isEffect(node) || isEffect(node) ||
isLocalCallGraphRelevantNode(node) || isLocalCallGraphRelevantNode(node) ||
isInlineAssembly(node) || node.nodeType === "InlineAssembly" ||
isNewExpression(node) || node.nodeType === "NewExpression" ||
isSelfdestructCall(node) || isSelfdestructCall(node) ||
isDeleteUnaryOperation(node) isDeleteUnaryOperation(node)
) )
@ -98,8 +98,8 @@ export default class constantFunctions implements AnalyzerModule {
isTransfer(node) || isTransfer(node) ||
this.isCallOnNonConstExternalInterfaceFunction(node, context) || this.isCallOnNonConstExternalInterfaceFunction(node, context) ||
isCallToNonConstLocalFunction(node) || isCallToNonConstLocalFunction(node) ||
isInlineAssembly(node) || node.nodeType === "InlineAssembly" ||
isNewExpression(node) || node.nodeType === "NewExpression" ||
isSelfdestructCall(node) || isSelfdestructCall(node) ||
isDeleteUnaryOperation(node) isDeleteUnaryOperation(node)
} }

@ -1,36 +1,27 @@
import { default as category } from './categories' import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { isLoop, isBlock, getLoopBlockStartIndex, isExpressionStatement, isTransfer } from './staticAnalysisCommon' import { getLoopBlockStartIndex, isTransfer } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, ForStatementAstNode, WhileStatementAstNode, CommonAstNode, ExpressionStatementAstNode} from './../../types'
export default class etherTransferInLoop implements AnalyzerModule { export default class etherTransferInLoop implements AnalyzerModule {
relevantNodes: AstNodeLegacy[] = [] relevantNodes: CommonAstNode[] = []
name: string = 'Ether transfer in a loop: ' name: string = 'Ether transfer in a loop: '
description: string = 'Avoid transferring Ether to multiple addresses in a loop' description: string = 'Avoid transferring Ether to multiple addresses in a loop'
category: ModuleCategory = category.GAS category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: ForStatementAstNode | WhileStatementAstNode): void {
if (isLoop(node)) { let transferNodes: CommonAstNode[] = []
let transferNodes: AstNodeLegacy[] = [] transferNodes = node.body.statements.filter(child => (
const loopBlockStartIndex: number | undefined = getLoopBlockStartIndex(node) child.nodeType === 'ExpressionStatement' &&
if (loopBlockStartIndex && node.children && isBlock(node.children[loopBlockStartIndex])) { child.expression.nodeType === 'FunctionCall' &&
const childrenNodes: AstNodeLegacy[] | undefined = node.children[loopBlockStartIndex].children isTransfer(child.expression.expression)
if(childrenNodes)
transferNodes = childrenNodes.filter(child => (
isExpressionStatement(child) &&
child.children &&
child.children[0].name === 'FunctionCall' &&
child.children[0].children &&
isTransfer(child.children[0].children[0])
) )
) )
if (transferNodes.length > 0) { if (transferNodes.length > 0) {
this.relevantNodes.push(...transferNodes) this.relevantNodes.push(...transferNodes)
} }
} }
}
}
report (compilationResults: CompilationResult): ReportObj[] { report (compilationResults: CompilationResult): ReportObj[] {
return this.relevantNodes.map((node) => { return this.relevantNodes.map((node) => {

@ -1,17 +1,17 @@
import { default as category } from './categories' import { default as category } from './categories'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } from './staticAnalysisCommon' import { isForLoop, isDynamicArrayLengthAccess, isBinaryOperation } from './staticAnalysisCommon'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, CommonAstNode} from './../../types'
export default class forLoopIteratesOverDynamicArray implements AnalyzerModule { export default class forLoopIteratesOverDynamicArray implements AnalyzerModule {
relevantNodes: AstNodeLegacy[] = [] relevantNodes: CommonAstNode[] = []
name: string = 'For loop iterates over dynamic array: ' name: string = 'For loop iterates over dynamic array: '
description: string = 'The number of \'for\' loop iterations depends on dynamic array\'s size' description: string = 'The number of \'for\' loop iterations depends on dynamic array\'s size'
category: ModuleCategory = category.GAS category: ModuleCategory = category.GAS
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: CommonAstNode): void {
if (isForLoop(node) && node.children) { if (node.nodeType === "Forstatement" && node.children) {
let conditionChildrenNode: AstNodeLegacy | null = null let conditionChildrenNode: AstNodeLegacy | null = null
// Access 'condition' node of 'for' loop statement // Access 'condition' node of 'for' loop statement
const forLoopConditionNode: AstNodeLegacy = node.children[1] const forLoopConditionNode: AstNodeLegacy = node.children[1]

@ -1,17 +1,16 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isInlineAssembly } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, InlineAssemblyAstNode} from './../../types'
export default class inlineAssembly implements AnalyzerModule { export default class inlineAssembly implements AnalyzerModule {
inlineAssNodes: AstNodeLegacy[] = [] inlineAssNodes: InlineAssemblyAstNode[] = []
name: string = 'Inline assembly: ' name: string = 'Inline assembly: '
description: string = 'Use of Inline Assembly' description: string = 'Use of Inline Assembly'
category: ModuleCategory = category.SECURITY category: ModuleCategory = category.SECURITY
algorithm: ModuleAlgorithm = algorithm.EXACT algorithm: ModuleAlgorithm = algorithm.EXACT
visit (node: AstNodeLegacy): void { visit (node: InlineAssemblyAstNode): void {
if (isInlineAssembly(node)) this.inlineAssNodes.push(node) this.inlineAssNodes.push(node)
} }
report (compilationResults: CompilationResult): ReportObj[] { report (compilationResults: CompilationResult): ReportObj[] {

@ -1,8 +1,8 @@
import { default as category } from './categories' import { default as category } from './categories'
import { isReturn, isAssignment, hasFunctionBody, getFullQuallyfiedFuncDefinitionIdent, getEffectedVariableName } from './staticAnalysisCommon' import { hasFunctionBody, getFullQuallyfiedFuncDefinitionIdent, getEffectedVariableName } from './staticAnalysisCommon'
import { default as algorithm } from './algorithmCategories' import { default as algorithm } from './algorithmCategories'
import AbstractAst from './abstractAstView' import AbstractAst from './abstractAstView'
import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult} from './../../types' import { AnalyzerModule, ModuleAlgorithm, ModuleCategory, ReportObj, AstNodeLegacy, CompilationResult, CommonAstNode, FunctionDefinitionAstNode} from './../../types'
export default class noReturn implements AnalyzerModule { export default class noReturn implements AnalyzerModule {
name: string = 'no return: ' name: string = 'no return: '
@ -13,7 +13,7 @@ export default class noReturn implements AnalyzerModule {
abstractAst: AbstractAst = new AbstractAst() abstractAst: AbstractAst = new AbstractAst()
visit = this.abstractAst.build_visit( visit = this.abstractAst.build_visit(
(node: AstNodeLegacy) => isReturn(node) || isAssignment(node) (node: CommonAstNode) => node.nodeType === "Return" || node.nodeType === "Assignment"
) )
report = this.abstractAst.build_report(this._report.bind(this)) report = this.abstractAst.build_report(this._report.bind(this))
@ -44,13 +44,13 @@ export default class noReturn implements AnalyzerModule {
return func.returns.length > 0 return func.returns.length > 0
} }
private hasReturnStatement (func): boolean { private hasReturnStatement (func: CommonAstNode): boolean {
return func.relevantNodes.filter(isReturn).length > 0 return func.relevantNodes.filter(n => n.nodeType === "Return").length > 0
} }
private hasAssignToAllNamedReturns (func): boolean { private hasAssignToAllNamedReturns (func): boolean {
const namedReturns = func.returns.filter((n) => n.name.length > 0).map((n) => n.name) const namedReturns = func.returns.filter((n) => n.name.length > 0).map((n) => n.name)
const assignedVars = func.relevantNodes.filter(isAssignment).map(getEffectedVariableName) const assignedVars = func.relevantNodes.filter(n => n.nodeType === "Assignment").map(getEffectedVariableName)
const diff = namedReturns.filter(e => !assignedVars.includes(e)) const diff = namedReturns.filter(e => !assignedVars.includes(e))
return diff.length === 0 return diff.length === 0
} }

@ -1,6 +1,6 @@
'use strict' 'use strict'
import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode } from "types" import { FunctionDefinitionAstNode, ModifierDefinitionAstNode, ParameterListAstNode, CommonAstNode, ForStatementAstNode, WhileStatementAstNode, VariableDeclarationAstNode, ContractDefinitionAstNode, InheritanceSpecifierAstNode, MemberAccessAstNode } from "types"
const remixLib = require('remix-lib') const remixLib = require('remix-lib')
const util = remixLib.util const util = remixLib.util
@ -125,8 +125,8 @@ const abiNamespace = {
// #################### Trivial Getters // #################### Trivial Getters
function getType (node) { function getType (node: CommonAstNode) {
return node.attributes.type return node.nodeType
} }
// #################### Complex Getters // #################### Complex Getters
@ -149,7 +149,7 @@ function getFunctionCallType (func) {
* @return {string} variable name written to * @return {string} variable name written to
*/ */
function getEffectedVariableName (effectNode) { function getEffectedVariableName (effectNode) {
if (!isEffect(effectNode) || isInlineAssembly(effectNode)) throw new Error('staticAnalysisCommon.js: not an effect Node or inline assembly') if (!isEffect(effectNode) || effectNode.nodeType === "InlineAssembly") throw new Error('staticAnalysisCommon.js: not an effect Node or inline assembly')
return findFirstSubNodeLTR(effectNode, exactMatch(nodeTypes.IDENTIFIER)).attributes.value return findFirstSubNodeLTR(effectNode, exactMatch(nodeTypes.IDENTIFIER)).attributes.value
} }
@ -234,9 +234,8 @@ function getExternalDirectCallMemberName (extDirectCall) {
* @contract {ASTNode} Contract Definition node * @contract {ASTNode} Contract Definition node
* @return {string} name of a contract defined * @return {string} name of a contract defined
*/ */
function getContractName (contract) { function getContractName (contract: ContractDefinitionAstNode) {
if (!isContractDefinition(contract)) throw new Error('staticAnalysisCommon.js: not an contractDefinition Node') return contract.name
return contract.attributes.name
} }
/** /**
@ -258,9 +257,8 @@ function getFunctionDefinitionName (funcDef: FunctionDefinitionAstNode): string
* @func {ASTNode} Inheritance specifier * @func {ASTNode} Inheritance specifier
* @return {string} name of contract inherited from * @return {string} name of contract inherited from
*/ */
function getInheritsFromName (inheritsNode) { function getInheritsFromName (inheritsNode: InheritanceSpecifierAstNode) {
if (!isInheritanceSpecifier(inheritsNode)) throw new Error('staticAnalysisCommon.js: not an InheritanceSpecifier Node') return inheritsNode.baseName
return inheritsNode.children[0].attributes.name
} }
/** /**
@ -270,9 +268,8 @@ function getInheritsFromName (inheritsNode) {
* @varDeclNode {ASTNode} Variable declaration node * @varDeclNode {ASTNode} Variable declaration node
* @return {string} variable name * @return {string} variable name
*/ */
function getDeclaredVariableName (varDeclNode) { function getDeclaredVariableName (varDeclNode: VariableDeclarationAstNode) {
if (!isVariableDeclaration(varDeclNode)) throw new Error('staticAnalysisCommon.js: not a variable declaration') return varDeclNode.name
return varDeclNode.attributes.name
} }
/** /**
@ -282,9 +279,8 @@ function getDeclaredVariableName (varDeclNode) {
* @varDeclNode {ASTNode} Variable declaration node * @varDeclNode {ASTNode} Variable declaration node
* @return {string} variable type * @return {string} variable type
*/ */
function getDeclaredVariableType (varDeclNode) { function getDeclaredVariableType (varDeclNode: VariableDeclarationAstNode) {
if (!isVariableDeclaration(varDeclNode)) throw new Error('staticAnalysisCommon.js: not a variable declaration') return varDeclNode.typeName
return varDeclNode.attributes.type
} }
/** /**
@ -297,10 +293,8 @@ function getDeclaredVariableType (varDeclNode) {
* @contractNode {ASTNode} Contract Definition node * @contractNode {ASTNode} Contract Definition node
* @return {list variable declaration} state variable node list * @return {list variable declaration} state variable node list
*/ */
function getStateVariableDeclarationsFormContractNode (contractNode) { function getStateVariableDeclarationsFormContractNode (contractNode: ContractDefinitionAstNode): CommonAstNode[] {
if (!isContractDefinition(contractNode)) throw new Error('staticAnalysisCommon.js: not a contract definition declaration') return contractNode.nodes.filter(el => el.nodeType === "VariableDeclaration")
if (!contractNode.children) return []
return contractNode.children.filter((el) => isVariableDeclaration(el))
} }
/** /**
@ -380,7 +374,7 @@ function getLibraryCallContractName (funcCall) {
* @return {string} name of function called on the library * @return {string} name of function called on the library
*/ */
function getLibraryCallMemberName (funcCall) { function getLibraryCallMemberName (funcCall) {
if (!isLibraryCall(funcCall)) throw new Error('staticAnalysisCommon.js: not an library call Node') // if (!isLibraryCall(funcCall)) throw new Error('staticAnalysisCommon.js: not an library call Node')
return funcCall.attributes.member_name return funcCall.attributes.member_name
} }
@ -413,73 +407,14 @@ function getUnAssignedTopLevelBinOps (subScope) {
return subScope.children.filter(isBinaryOpInExpression) return subScope.children.filter(isBinaryOpInExpression)
} }
function getLoopBlockStartIndex (node) { function getLoopBlockStartIndex (node: ForStatementAstNode | WhileStatementAstNode): 3|1 {
if (isLoop(node)) { return node.nodeType === "ForStatement" ? 3 : 1
if (nodeType(node, exactMatch(nodeTypes.FORSTATEMENT))) {
return 3 // For 'for' loop
} else {
return 1 // For 'while' and 'do-while' loop
}
}
} }
// #################### Trivial Node Identification // #################### Trivial Node Identification
// function isFunctionDefinition (node) { function isStatement (node: CommonAstNode) {
// return nodeType(node, exactMatch(nodeTypes.FUNCTIONDEFINITION)) return nodeType(node, 'Statement$') || node.nodeType === "Block" || node.nodeType === "Return"
// }
function isStatement (node) {
return nodeType(node, 'Statement$') || isBlock(node) || isReturn(node)
}
function isBlock (node) {
return nodeType(node, exactMatch(nodeTypes.BLOCK))
}
function isModifierDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.MODIFIERDEFINITION))
}
function isModifierInvocation (node) {
return nodeType(node, exactMatch(nodeTypes.MODIFIERINVOCATION))
}
function isVariableDeclaration (node) {
return nodeType(node, exactMatch(nodeTypes.VARIABLEDECLARATION))
}
function isReturn (node) {
return nodeType(node, exactMatch(nodeTypes.RETURN))
}
function isInheritanceSpecifier (node) {
return nodeType(node, exactMatch(nodeTypes.INHERITANCESPECIFIER))
}
function isAssignment (node) {
return nodeType(node, exactMatch(nodeTypes.ASSIGNMENT))
}
function isContractDefinition (node) {
return nodeType(node, exactMatch(nodeTypes.CONTRACTDEFINITION))
}
function isInlineAssembly (node) {
return nodeType(node, exactMatch(nodeTypes.INLINEASSEMBLY))
}
function isNewExpression (node) {
return nodeType(node, exactMatch(nodeTypes.NEWEXPRESSION))
}
/**
* True if is Expression
* @node {ASTNode} some AstNode
* @return {bool}
*/
function isExpressionStatement (node) {
return nodeType(node, exactMatch(nodeTypes.EXPRESSIONSTATEMENT))
} }
/** /**
@ -618,8 +553,8 @@ function isRequireCall (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isStorageVariableDeclaration (node) { function isStorageVariableDeclaration (node: VariableDeclarationAstNode): boolean {
return isVariableDeclaration(node) && expressionType(node, basicRegex.REFTYPE) return expressionType(node, basicRegex.REFTYPE)
} }
/** /**
@ -637,7 +572,7 @@ function isInteraction (node) {
* @return {bool} * @return {bool}
*/ */
function isEffect (node) { function isEffect (node) {
return isAssignment(node) || isPlusPlusUnaryOperation(node) || isMinusMinusUnaryOperation(node) || isInlineAssembly(node) return node.nodeType === "Assignment" || isPlusPlusUnaryOperation(node) || isMinusMinusUnaryOperation(node) || node.nodeType === "InlineAssembly"
} }
/** /**
@ -647,7 +582,7 @@ function isEffect (node) {
* @return {bool} * @return {bool}
*/ */
function isWriteOnStateVariable (effectNode, stateVariables) { function isWriteOnStateVariable (effectNode, stateVariables) {
return isInlineAssembly(effectNode) || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables)) return effectNode.nodeType === "InlineAssembly" || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables))
} }
/** /**
@ -720,7 +655,7 @@ function isSubScopeStatement (node) {
* @return {bool} * @return {bool}
*/ */
function isBinaryOpInExpression (node) { function isBinaryOpInExpression (node) {
return isExpressionStatement(node) && nrOfChildren(node, 1) && isBinaryOperation(node.children[0]) return node.nodeType === "ExpressionStatement" && nrOfChildren(node, 1) && isBinaryOperation(node.children[0])
} }
/** /**
@ -978,16 +913,17 @@ function isBytesLengthCheck (node) {
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
*/ */
function isLoop (node) { // function isLoop (node) {
return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) || // return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) || // nodeType(node, exactMatch(nodeTypes.WHILESTATEMENT)) ||
nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT)) // nodeType(node, exactMatch(nodeTypes.DOWHILESTATEMENT))
} // }
/** /**
* True if it is a 'for' loop * True if it is a 'for' loop
* @node {ASTNode} some AstNode * @node {ASTNode} some AstNode
* @return {bool} * @return {bool}
* TODO: This should be removed once for loop iterates Over dynamic array fixed
*/ */
function isForLoop (node) { function isForLoop (node) {
return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT)) return nodeType(node, exactMatch(nodeTypes.FORSTATEMENT))
@ -995,13 +931,13 @@ function isForLoop (node) {
// #################### Complex Node Identification - Private // #################### Complex Node Identification - Private
function isMemberAccess (node, retType, accessor, accessorType, memberName) { function isMemberAccess (node: MemberAccessAstNode, retType, accessor, accessorType, memberName) {
return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) && return nodeType(node, exactMatch(nodeTypes.MEMBERACCESS)) &&
expressionType(node, retType) && expressionType(node, retType) &&
memName(node, memberName) && memName(node, memberName) &&
nrOfChildren(node, 1) && nrOfChildren(node, 1) &&
memName(node.children[0], accessor) && memName(node.expression, accessor) &&
expressionType(node.children[0], accessorType) expressionType(node.expression, accessorType)
} }
function isSpecialVariableAccess (node, varType) { function isSpecialVariableAccess (node, varType) {
@ -1168,28 +1104,27 @@ export {
isIntDivision, isIntDivision,
isStringToBytesConversion, isStringToBytesConversion,
isBytesLengthCheck, isBytesLengthCheck,
isLoop,
isForLoop, isForLoop,
// #################### Trivial Node Identification // #################### Trivial Node Identification
isDeleteUnaryOperation, isDeleteUnaryOperation,
// isFunctionDefinition, // isFunctionDefinition,
isModifierDefinition, // isModifierDefinition,
isInheritanceSpecifier, // isInheritanceSpecifier,
isModifierInvocation, // isModifierInvocation,
isVariableDeclaration, // isVariableDeclaration,
isStorageVariableDeclaration, isStorageVariableDeclaration,
isAssignment, // isAssignment,
isContractDefinition, // isContractDefinition,
isConstantFunction, isConstantFunction,
isPayableFunction, isPayableFunction,
isConstructor, isConstructor,
isInlineAssembly, // isInlineAssembly,
isNewExpression, // isNewExpression,
isReturn, // isReturn,
isStatement, isStatement,
isExpressionStatement, // isExpressionStatement,
isBlock, // isBlock,
isBinaryOperation, isBinaryOperation,
// #################### Constants // #################### Constants

@ -95,7 +95,7 @@ export interface ContractDefinitionAstNode {
linearizedBaseContracts: Array<number> linearizedBaseContracts: Array<number>
baseContracts: Array<InheritanceSpecifierAstNode> baseContracts: Array<InheritanceSpecifierAstNode>
contractDependencies: Array<number> contractDependencies: Array<number>
nodes: Array<any> nodes: Array<CommonAstNode>
scope: number scope: number
} }
@ -298,7 +298,7 @@ export interface BlockAstNode {
id: number id: number
nodeType: 'Block' nodeType: 'Block'
src: string src: string
statements: Array<object> statements: Array<CommonAstNode>
} }
export interface PlaceholderStatementAstNode { export interface PlaceholderStatementAstNode {

@ -317,89 +317,89 @@ test('staticAnalysisCommon.getLoopBlockStartIndex', function (t) {
// t.notOk(common.isFunctionDefinition(node3), 'substring should not work') // t.notOk(common.isFunctionDefinition(node3), 'substring should not work')
// }) // })
test('staticAnalysisCommon.isModifierDefinition', function (t) { // test('staticAnalysisCommon.isModifierDefinition', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'ModifierDefinition' } // const node1 = { name: 'ModifierDefinition' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'ModifierDefinitionBLABLA' } // const node3 = { name: 'ModifierDefinitionBLABLA' }
t.ok(common.isModifierDefinition(node1), 'is exact match should work') // t.ok(common.isModifierDefinition(node1), 'is exact match should work')
t.notOk(common.isModifierDefinition(node2), 'different node should not work') // t.notOk(common.isModifierDefinition(node2), 'different node should not work')
t.notOk(common.isModifierDefinition(node3), 'substring should not work') // t.notOk(common.isModifierDefinition(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isModifierInvocation', function (t) { // test('staticAnalysisCommon.isModifierInvocation', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'ModifierInvocation' } // const node1 = { name: 'ModifierInvocation' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'ModifierInvocationBLABLA' } // const node3 = { name: 'ModifierInvocationBLABLA' }
t.ok(common.isModifierInvocation(node1), 'is exact match should work') // t.ok(common.isModifierInvocation(node1), 'is exact match should work')
t.notOk(common.isModifierInvocation(node2), 'different node should not work') // t.notOk(common.isModifierInvocation(node2), 'different node should not work')
t.notOk(common.isModifierInvocation(node3), 'substring should not work') // t.notOk(common.isModifierInvocation(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isVariableDeclaration', function (t) { // test('staticAnalysisCommon.isVariableDeclaration', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'VariableDeclaration' } // const node1 = { name: 'VariableDeclaration' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'VariableDeclarationBLABLA' } // const node3 = { name: 'VariableDeclarationBLABLA' }
t.ok(common.isVariableDeclaration(node1), 'is exact match should work') // t.ok(common.isVariableDeclaration(node1), 'is exact match should work')
t.notOk(common.isVariableDeclaration(node2), 'different node should not work') // t.notOk(common.isVariableDeclaration(node2), 'different node should not work')
t.notOk(common.isVariableDeclaration(node3), 'substring should not work') // t.notOk(common.isVariableDeclaration(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isInheritanceSpecifier', function (t) { // test('staticAnalysisCommon.isInheritanceSpecifier', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'InheritanceSpecifier' } // const node1 = { name: 'InheritanceSpecifier' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'InheritanceSpecifierBLABLA' } // const node3 = { name: 'InheritanceSpecifierBLABLA' }
t.ok(common.isInheritanceSpecifier(node1), 'is exact match should work') // t.ok(common.isInheritanceSpecifier(node1), 'is exact match should work')
t.notOk(common.isInheritanceSpecifier(node2), 'different node should not work') // t.notOk(common.isInheritanceSpecifier(node2), 'different node should not work')
t.notOk(common.isInheritanceSpecifier(node3), 'substring should not work') // t.notOk(common.isInheritanceSpecifier(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isAssignment', function (t) { // test('staticAnalysisCommon.isAssignment', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'Assignment' } // const node1 = { name: 'Assignment' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'AssignmentBLABLA' } // const node3 = { name: 'AssignmentBLABLA' }
t.ok(common.isAssignment(node1), 'is exact match should work') // t.ok(common.isAssignment(node1), 'is exact match should work')
t.notOk(common.isAssignment(node2), 'different node should not work') // t.notOk(common.isAssignment(node2), 'different node should not work')
t.notOk(common.isAssignment(node3), 'substring should not work') // t.notOk(common.isAssignment(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isContractDefinition', function (t) { // test('staticAnalysisCommon.isContractDefinition', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'ContractDefinition' } // const node1 = { name: 'ContractDefinition' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'ContractDefinitionBLABLA' } // const node3 = { name: 'ContractDefinitionBLABLA' }
t.ok(common.isContractDefinition(node1), 'is exact match should work') // t.ok(common.isContractDefinition(node1), 'is exact match should work')
t.notOk(common.isContractDefinition(node2), 'different node should not work') // t.notOk(common.isContractDefinition(node2), 'different node should not work')
t.notOk(common.isContractDefinition(node3), 'substring should not work') // t.notOk(common.isContractDefinition(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isInlineAssembly', function (t) { // test('staticAnalysisCommon.isInlineAssembly', function (t) {
t.plan(3) // t.plan(3)
const node1 = { name: 'InlineAssembly' } // const node1 = { name: 'InlineAssembly' }
const node2 = { name: 'MemberAccess' } // const node2 = { name: 'MemberAccess' }
const node3 = { name: 'InlineAssemblyBLABLA' } // const node3 = { name: 'InlineAssemblyBLABLA' }
t.ok(common.isInlineAssembly(node1), 'is exact match should work') // t.ok(common.isInlineAssembly(node1), 'is exact match should work')
t.notOk(common.isInlineAssembly(node2), 'different node should not work') // t.notOk(common.isInlineAssembly(node2), 'different node should not work')
t.notOk(common.isInlineAssembly(node3), 'substring should not work') // t.notOk(common.isInlineAssembly(node3), 'substring should not work')
}) // })
test('staticAnalysisCommon.isLoop', function (t) { // test('staticAnalysisCommon.isLoop', function (t) {
t.plan(3) // t.plan(3)
t.equal(common.isLoop(forLoopNode), true) // t.equal(common.isLoop(forLoopNode), true)
t.equal(common.isLoop(doWhileLoopNode), true) // t.equal(common.isLoop(doWhileLoopNode), true)
t.equal(common.isLoop(whileLoopNode), true) // t.equal(common.isLoop(whileLoopNode), true)
}) // })
// #################### Complex Node Identification // #################### Complex Node Identification

Loading…
Cancel
Save