Commit e9ac30cb authored by aniket-engg's avatar aniket-engg Committed by Aniket

node identification methods removed

parent d5548b62
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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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
......
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 { ...@@ -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 { ...@@ -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)
} }
......
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) && if (transferNodes.length > 0) {
child.children && this.relevantNodes.push(...transferNodes)
child.children[0].name === 'FunctionCall' &&
child.children[0].children &&
isTransfer(child.children[0].children[0])
)
)
if (transferNodes.length > 0) {
this.relevantNodes.push(...transferNodes)
}
} }
}
} }
report (compilationResults: CompilationResult): ReportObj[] { report (compilationResults: CompilationResult): ReportObj[] {
......
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]
......
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[] {
......
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 { ...@@ -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 { ...@@ -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
} }
......
...@@ -95,7 +95,7 @@ export interface ContractDefinitionAstNode { ...@@ -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 { ...@@ -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) { ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment