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

ballot.sol integration tests

parent 8ccef1c5
...@@ -174,10 +174,10 @@ export default class abstractAstView { ...@@ -174,10 +174,10 @@ export default class abstractAstView {
private getLocalVariables (funcNode: ParameterListAstNode): VariableDeclarationAstNode[] { private getLocalVariables (funcNode: ParameterListAstNode): VariableDeclarationAstNode[] {
const locals: VariableDeclarationAstNode[] = [] const locals: VariableDeclarationAstNode[] = []
new AstWalker().walk(funcNode, {'*': function (node) { new AstWalker().walkFull(funcNode, (node) => {
if (node.nodeType === "VariableDeclaration") locals.push(node) if (node.nodeType === "VariableDeclaration") locals.push(node)
return true return true
}}) })
return locals return locals
} }
} }
...@@ -55,7 +55,6 @@ export default class constantFunctions implements AnalyzerModule { ...@@ -55,7 +55,6 @@ export default class constantFunctions implements AnalyzerModule {
) )
} }
}) })
contract.functions.filter((func) => hasFunctionBody(func.node)).forEach((func) => { contract.functions.filter((func) => hasFunctionBody(func.node)).forEach((func) => {
if (isConstantFunction(func.node) !== func['potentiallyshouldBeConst']) { if (isConstantFunction(func.node) !== func['potentiallyshouldBeConst']) {
const funcName: string = getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters) const funcName: string = getFullQuallyfiedFuncDefinitionIdent(contract.node, func.node, func.parameters)
......
'use strict' 'use strict'
import { FunctionHLAst, ContractHLAst, FunctionCallGraph, ContractCallGraph } from "types" import { FunctionHLAst, ContractHLAst, FunctionCallGraph, ContractCallGraph, Context } from "types"
import { isLocalCallGraphRelevantNode, isExternalDirectCall, getFullQualifiedFunctionCallIdent, getFullQuallyfiedFuncDefinitionIdent, getContractName } from './staticAnalysisCommon' import { isLocalCallGraphRelevantNode, isExternalDirectCall, getFullQualifiedFunctionCallIdent, getFullQuallyfiedFuncDefinitionIdent, getContractName } from './staticAnalysisCommon'
function buildLocalFuncCallGraphInternal (functions: FunctionHLAst[], nodeFilter: any , extractNodeIdent: any, extractFuncDefIdent: Function): Record<string, FunctionCallGraph> { function buildLocalFuncCallGraphInternal (functions: FunctionHLAst[], nodeFilter: any , extractNodeIdent: any, extractFuncDefIdent: Function): Record<string, FunctionCallGraph> {
...@@ -61,11 +61,11 @@ export function buildGlobalFuncCallGraph (contracts: ContractHLAst[]): Record<st ...@@ -61,11 +61,11 @@ export function buildGlobalFuncCallGraph (contracts: ContractHLAst[]): Record<st
* @nodeCheck {(ASTNode, context) -> bool} applied on every relevant node in the call graph * @nodeCheck {(ASTNode, context) -> bool} applied on every relevant node in the call graph
* @return {bool} returns map from contract name to contract call graph * @return {bool} returns map from contract name to contract call graph
*/ */
export function analyseCallGraph (callGraph: Record<string, ContractCallGraph>, funcName: string, context: object, nodeCheck): boolean { export function analyseCallGraph (callGraph: Record<string, ContractCallGraph>, funcName: string, context: Context, nodeCheck: ((node: any, context: Context) => boolean)): boolean {
return analyseCallGraphInternal(callGraph, funcName, context, (a, b) => a || b, nodeCheck, {}) return analyseCallGraphInternal(callGraph, funcName, context, (a, b) => a || b, nodeCheck, {})
} }
function analyseCallGraphInternal (callGraph: Record<string, ContractCallGraph>, funcName: string, context: object, combinator: Function, nodeCheck, visited : object): boolean { function analyseCallGraphInternal (callGraph: Record<string, ContractCallGraph>, funcName: string, context: Context, combinator: Function, nodeCheck, visited : object): boolean {
const current: FunctionCallGraph | undefined = resolveCallGraphSymbol(callGraph, funcName) const current: FunctionCallGraph | undefined = resolveCallGraphSymbol(callGraph, funcName)
if (current === undefined || visited[funcName] === true) return true if (current === undefined || visited[funcName] === true) return true
......
...@@ -52,7 +52,10 @@ export default class similarVariableNames implements AnalyzerModule { ...@@ -52,7 +52,10 @@ export default class similarVariableNames implements AnalyzerModule {
const similar: Record<string, any>[] = [] const similar: Record<string, any>[] = []
const comb: Record<string, boolean> = {} const comb: Record<string, boolean> = {}
vars.map((varName1) => vars.map((varName2) => { vars.map((varName1) => vars.map((varName2) => {
if (varName1.length > 1 && varName2.length > 1 && varName2 !== varName1 && !this.isCommonPrefixedVersion(varName1, varName2) && !this.isCommonNrSuffixVersion(varName1, varName2) && !(comb[varName1 + ';' + varName2] || comb[varName2 + ';' + varName1])) { if (varName1.length > 1 && varName2.length > 1 &&
varName2 !== varName1 && !this.isCommonPrefixedVersion(varName1, varName2) &&
!this.isCommonNrSuffixVersion(varName1, varName2) &&
!(comb[varName1 + ';' + varName2] || comb[varName2 + ';' + varName1])) {
comb[varName1 + ';' + varName2] = true comb[varName1 + ';' + varName2] = true
const distance: number = get(varName1, varName2) const distance: number = get(varName1, varName2)
if (distance <= 2) similar.push({ var1: varName1, var2: varName2, distance: distance }) if (distance <= 2) similar.push({ var1: varName1, var2: varName2, distance: distance })
......
...@@ -168,10 +168,31 @@ function getFunctionCallType (func: FunctionCallAstNode): string { ...@@ -168,10 +168,31 @@ function getFunctionCallType (func: FunctionCallAstNode): string {
* @effectNode {ASTNode} Assignmnet node * @effectNode {ASTNode} Assignmnet node
* @return {string} variable name written to * @return {string} variable name written to
*/ */
function getEffectedVariableName (effectNode: AssignmentAstNode | UnaryOperationAstNode): string { function getEffectedVariableName (effectNode: AssignmentAstNode | UnaryOperationAstNode) {
if (!isEffect(effectNode)) throw new Error('staticAnalysisCommon.js: not an effect Node') if (!isEffect(effectNode)) throw new Error('staticAnalysisCommon.js: not an effect Node')
if(effectNode.nodeType === 'Assignment') return effectNode.leftHandSide.name if(effectNode.nodeType === 'Assignment' || effectNode.nodeType === 'UnaryOperation') {
else /* if(effectNode.nodeType === 'UnaryOperation') */ return effectNode.subExpression.name const IdentNode = findFirstSubNodeLTR(effectNode, exactMatch(nodeTypes.IDENTIFIER))
return IdentNode.name
}
}
// developed keeping identifier node search in mind
function findFirstSubNodeLTR (node, type) {
if(node.nodeType && nodeType(node, type))
return node
else if(node.nodeType && nodeType(node, exactMatch('Assignment')))
return findFirstSubNodeLTR(node.leftHandSide, type)
else if(node.nodeType && nodeType(node, exactMatch('MemberAccess')))
return findFirstSubNodeLTR(node.expression, type)
else if(node.nodeType && nodeType(node, exactMatch('IndexAccess')))
return findFirstSubNodeLTR(node.baseExpression, type)
else if(node.nodeType && nodeType(node, exactMatch('UnaryOperation')))
return findFirstSubNodeLTR(node.subExpression, type)
} }
/** /**
...@@ -417,7 +438,7 @@ function getFullQualifiedFunctionCallIdent (contract: ContractDefinitionAstNode, ...@@ -417,7 +438,7 @@ function getFullQualifiedFunctionCallIdent (contract: ContractDefinitionAstNode,
else if (isSuperLocalCall(func.expression)) return getContractName(contract) + '.' + getSuperLocalCallName(func) + '(' + getFunctionCallTypeParameterType(func) + ')' else if (isSuperLocalCall(func.expression)) return getContractName(contract) + '.' + getSuperLocalCallName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else if (isExternalDirectCall(func.expression)) return getExternalDirectCallContractName(func) + '.' + getExternalDirectCallMemberName(func) + '(' + getFunctionCallTypeParameterType(func) + ')' else if (isExternalDirectCall(func.expression)) return getExternalDirectCallContractName(func) + '.' + getExternalDirectCallMemberName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else if (isLibraryCall(func.expression)) return getLibraryCallContractName(func.expression) + '.' + getLibraryCallMemberName(func) + '(' + getFunctionCallTypeParameterType(func) + ')' else if (isLibraryCall(func.expression)) return getLibraryCallContractName(func.expression) + '.' + getLibraryCallMemberName(func) + '(' + getFunctionCallTypeParameterType(func) + ')'
else throw new Error('staticAnalysisCommon.js: Can not get function name form non function call node') else throw new Error('staticAnalysisCommon.js: Can not get function name from non function call node')
} }
function getFullQuallyfiedFuncDefinitionIdent (contract: ContractDefinitionAstNode, func: FunctionDefinitionAstNode, paramTypes: any[]): string { function getFullQuallyfiedFuncDefinitionIdent (contract: ContractDefinitionAstNode, func: FunctionDefinitionAstNode, paramTypes: any[]): string {
...@@ -622,7 +643,7 @@ function isEffect (node: AssignmentAstNode | UnaryOperationAstNode | InlineAssem ...@@ -622,7 +643,7 @@ function isEffect (node: AssignmentAstNode | UnaryOperationAstNode | InlineAssem
* @node {list Variable declaration} state variable declaration currently in scope * @node {list Variable declaration} state variable declaration currently in scope
* @return {bool} * @return {bool}
*/ */
function isWriteOnStateVariable (effectNode: AssignmentAstNode | InlineAssemblyAstNode | UnaryOperationAstNode, stateVariables: any[]) { function isWriteOnStateVariable (effectNode: AssignmentAstNode | InlineAssemblyAstNode | UnaryOperationAstNode, stateVariables: VariableDeclarationAstNode[]) {
return effectNode.nodeType === "InlineAssembly" || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables)) return effectNode.nodeType === "InlineAssembly" || (isEffect(effectNode) && isStateVariable(getEffectedVariableName(effectNode), stateVariables))
} }
...@@ -632,8 +653,8 @@ function isWriteOnStateVariable (effectNode: AssignmentAstNode | InlineAssemblyA ...@@ -632,8 +653,8 @@ function isWriteOnStateVariable (effectNode: AssignmentAstNode | InlineAssemblyA
* @node {list Variable declaration} state variable declaration currently in scope * @node {list Variable declaration} state variable declaration currently in scope
* @return {bool} * @return {bool}
*/ */
function isStateVariable (name: string, stateVariables: any[]): boolean { function isStateVariable (name: string, stateVariables: VariableDeclarationAstNode[]): boolean {
return stateVariables.some((item) => name === getDeclaredVariableName(item)) return stateVariables.some((item: VariableDeclarationAstNode) => item.stateVariable && name === getDeclaredVariableName(item))
} }
/** /**
......
...@@ -129,7 +129,7 @@ export interface ContractDefinitionAstNode { ...@@ -129,7 +129,7 @@ export interface ContractDefinitionAstNode {
nodeType: 'ContractDefinition' nodeType: 'ContractDefinition'
src: string src: string
name: string name: string
documentation: object | null documentation: string | null
contractKind: 'interface' | 'contract' | 'library' contractKind: 'interface' | 'contract' | 'library'
abstract: boolean abstract: boolean
fullyImplemented: boolean fullyImplemented: boolean
...@@ -202,7 +202,7 @@ export interface FunctionDefinitionAstNode { ...@@ -202,7 +202,7 @@ export interface FunctionDefinitionAstNode {
nodeType: 'FunctionDefinition' nodeType: 'FunctionDefinition'
src: string src: string
name: string name: string
documentation: object | null documentation: string | null
kind: string kind: string
stateMutability: 'pure' | 'view' | 'nonpayable' | 'payable' stateMutability: 'pure' | 'view' | 'nonpayable' | 'payable'
visibility: string visibility: string
......
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