typo, type mismatch error, unit tests, types

pull/7/head
aniket-engg 5 years ago committed by Aniket
parent 035082741e
commit 5681ff8ba9
  1. 11
      remix-analyzer/src/solidity-analyzer/index.ts
  2. 67
      remix-analyzer/src/solidity-analyzer/modules/staticAnalysisCommon.ts
  3. 9
      remix-analyzer/src/types.ts
  4. 74
      remix-analyzer/test/analysis/staticAnalysisCommon-test.ts
  5. 18
      remix-analyzer/test/analysis/staticAnalysisIssues-test-0.4.24.ts
  6. 18
      remix-analyzer/test/analysis/staticAnalysisIssues-test-0.5.0.ts

@ -1,22 +1,13 @@
'use strict' 'use strict'
import { AstWalker } from 'remix-astwalker' import { AstWalker } from 'remix-astwalker'
import list from './modules/list' import list from './modules/list'
import { CompilationResult, AnalyzerModule, ReportObj } from 'types' import { CompilationResult, AnalyzerModule, AnalysisReportObj, AnalysisReport } from 'types'
type ModuleObj = { type ModuleObj = {
name: string name: string
mod: AnalyzerModule mod: AnalyzerModule
} }
interface AnalysisReportObj extends ReportObj {
error? : string
}
type AnalysisReport = {
name: string
report: AnalysisReportObj[]
}
export default class staticAnalysisRunner { export default class staticAnalysisRunner {
run (compilationResult: CompilationResult, toRun: any[], callback: ((reports: AnalysisReport[]) => void)): void { run (compilationResult: CompilationResult, toRun: any[], callback: ((reports: AnalysisReport[]) => void)): void {

@ -190,30 +190,6 @@ function getEffectedVariableName (effectNode: AssignmentAstNode | UnaryOperation
} else throw new Error('staticAnalysisCommon.js: wrong node type') } else throw new Error('staticAnalysisCommon.js: wrong node type')
} }
/**
* Finds first node of a certain type under a specific node.
* @node {AstNode} node to start form
* @type {String} Type the ast node should have
* @return {AstNode} null or node found
* Note: developed keeping identifier node search in mind to get first identifier node from left in subscope
*/
function findFirstSubNodeLTR (node: any, type: string): any {
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)
}
/** /**
* Returns the identifier of a local call, Throws on wrong node. * Returns the identifier of a local call, Throws on wrong node.
* Example: f(103) => f * Example: f(103) => f
@ -221,7 +197,7 @@ function findFirstSubNodeLTR (node: any, type: string): any {
* @return {string} name of the function called * @return {string} name of the function called
*/ */
function getLocalCallName (localCallNode: FunctionCallAstNode): string { function getLocalCallName (localCallNode: FunctionCallAstNode): string {
if (!isLocalCall(localCallNode) && !isAbiNamespaceCall(localCallNode)) throw new Error('staticAnalysisCommon.js: not an local call Node') if (!isLocalCall(localCallNode) && !isAbiNamespaceCall(localCallNode)) throw new Error('staticAnalysisCommon.js: not a local call Node')
return localCallNode.expression.name return localCallNode.expression.name
} }
@ -232,7 +208,7 @@ function getLocalCallName (localCallNode: FunctionCallAstNode): string {
* @return {string} name of the function called * @return {string} name of the function called
*/ */
function getThisLocalCallName (thisLocalCallNode: FunctionCallAstNode): string { function getThisLocalCallName (thisLocalCallNode: FunctionCallAstNode): string {
if (!isThisLocalCall(thisLocalCallNode.expression)) throw new Error('staticAnalysisCommon.js: not an this local call Node') if (!isThisLocalCall(thisLocalCallNode.expression)) throw new Error('staticAnalysisCommon.js: not a this local call Node')
return thisLocalCallNode.expression.memberName return thisLocalCallNode.expression.memberName
} }
@ -243,7 +219,7 @@ function getThisLocalCallName (thisLocalCallNode: FunctionCallAstNode): string {
* @return {string} name of the function called * @return {string} name of the function called
*/ */
function getSuperLocalCallName (superLocalCallNode: FunctionCallAstNode): string { function getSuperLocalCallName (superLocalCallNode: FunctionCallAstNode): string {
if (!isSuperLocalCall(superLocalCallNode.expression)) throw new Error('staticAnalysisCommon.js: not an super local call Node') if (!isSuperLocalCall(superLocalCallNode.expression)) throw new Error('staticAnalysisCommon.js: not a super local call Node')
return superLocalCallNode.expression.memberName return superLocalCallNode.expression.memberName
} }
@ -271,7 +247,7 @@ function getExternalDirectCallContractName (extDirectCall: FunctionCallAstNode):
* @return {string} name of the contract the function is defined in * @return {string} name of the contract the function is defined in
*/ */
function getThisLocalCallContractName (thisLocalCall: FunctionCallAstNode): string { function getThisLocalCallContractName (thisLocalCall: FunctionCallAstNode): string {
if (!isThisLocalCall(thisLocalCall.expression)) throw new Error('staticAnalysisCommon.js: not an this local call Node') if (!isThisLocalCall(thisLocalCall.expression)) throw new Error('staticAnalysisCommon.js: not a this local call Node')
return thisLocalCall.expression.expression.typeDescriptions.typeString.replace(new RegExp(basicRegex.CONTRACTTYPE), '') return thisLocalCall.expression.expression.typeDescriptions.typeString.replace(new RegExp(basicRegex.CONTRACTTYPE), '')
} }
@ -296,6 +272,7 @@ function getExternalDirectCallMemberName (extDirectCall: FunctionCallAstNode): s
* @return {string} name of a contract defined * @return {string} name of a contract defined
*/ */
function getContractName (contract: ContractDefinitionAstNode): string { function getContractName (contract: ContractDefinitionAstNode): string {
if (!nodeType(contract, exactMatch(nodeTypes.CONTRACTDEFINITION))) throw new Error('staticAnalysisCommon.js: not a ContractDefinition Node')
return contract.name return contract.name
} }
@ -307,6 +284,7 @@ function getContractName (contract: ContractDefinitionAstNode): string {
* @return {string} name of a function defined * @return {string} name of a function defined
*/ */
function getFunctionDefinitionName (funcDef: FunctionDefinitionAstNode): string { function getFunctionDefinitionName (funcDef: FunctionDefinitionAstNode): string {
if (!nodeType(funcDef, exactMatch(nodeTypes.FUNCTIONDEFINITION))) throw new Error('staticAnalysisCommon.js: not a FunctionDefinition Node')
return funcDef.name return funcDef.name
} }
@ -318,6 +296,7 @@ function getFunctionDefinitionName (funcDef: FunctionDefinitionAstNode): string
* @return {string} name of contract inherited from * @return {string} name of contract inherited from
*/ */
function getInheritsFromName (inheritsNode: InheritanceSpecifierAstNode): string { function getInheritsFromName (inheritsNode: InheritanceSpecifierAstNode): string {
if (!nodeType(inheritsNode, exactMatch(nodeTypes.INHERITANCESPECIFIER))) throw new Error('staticAnalysisCommon.js: not an InheritanceSpecifier Node')
return inheritsNode.baseName.name return inheritsNode.baseName.name
} }
@ -329,6 +308,7 @@ function getInheritsFromName (inheritsNode: InheritanceSpecifierAstNode): string
* @return {string} variable name * @return {string} variable name
*/ */
function getDeclaredVariableName (varDeclNode: VariableDeclarationAstNode): string { function getDeclaredVariableName (varDeclNode: VariableDeclarationAstNode): string {
if (!nodeType(varDeclNode, exactMatch(nodeTypes.VARIABLEDECLARATION))) throw new Error('staticAnalysisCommon.js: not a VariableDeclaration Node')
return varDeclNode.name return varDeclNode.name
} }
@ -365,6 +345,7 @@ function getStateVariableDeclarationsFromContractNode (contractNode: ContractDef
* @return {parameterlist node} parameterlist node * @return {parameterlist node} parameterlist node
*/ */
function getFunctionOrModifierDefinitionParameterPart (funcNode: FunctionDefinitionAstNode | ModifierDefinitionAstNode): ParameterListAstNode { function getFunctionOrModifierDefinitionParameterPart (funcNode: FunctionDefinitionAstNode | ModifierDefinitionAstNode): ParameterListAstNode {
if (!nodeTypeIn(funcNode, [exactMatch(nodeTypes.FUNCTIONDEFINITION), exactMatch(nodeTypes.MODIFIERDEFINITION)])) throw new Error('staticAnalysisCommon.js: not a FunctionDefinition or ModifierDefinition Node')
return funcNode.parameters return funcNode.parameters
} }
@ -415,7 +396,7 @@ function getFunctionCallTypeParameterType (func: FunctionCallAstNode): string |
* @return {string} name of the lib defined * @return {string} name of the lib defined
*/ */
function getLibraryCallContractName (node: FunctionCallAstNode): string | undefined { function getLibraryCallContractName (node: FunctionCallAstNode): string | undefined {
if (!isLibraryCall(node.expression)) throw new Error('staticAnalysisCommon.js: not an this library call Node') if (!isLibraryCall(node.expression)) throw new Error('staticAnalysisCommon.js: not a library call Node')
const types: RegExpExecArray | null = new RegExp(basicRegex.LIBRARYTYPE).exec(node.expression.expression.typeDescriptions.typeString) const types: RegExpExecArray | null = new RegExp(basicRegex.LIBRARYTYPE).exec(node.expression.expression.typeDescriptions.typeString)
if(types) if(types)
return types[1] return types[1]
@ -432,7 +413,7 @@ function getLibraryCallContractName (node: FunctionCallAstNode): string | undefi
* @return {string} name of function called on the library * @return {string} name of function called on the library
*/ */
function getLibraryCallMemberName (funcCall: FunctionCallAstNode): string { function getLibraryCallMemberName (funcCall: FunctionCallAstNode): string {
// if (!isLibraryCall(funcCall)) throw new Error('staticAnalysisCommon.js: not an library call Node') if (!isLibraryCall(funcCall.expression)) throw new Error('staticAnalysisCommon.js: not a library call Node')
return funcCall.expression.memberName return funcCall.expression.memberName
} }
@ -1047,7 +1028,31 @@ function matches (...fnArgs: any[]): string {
} }
/** /**
* Builds an function signature as used in the AST of the solc-json AST * Finds first node of a certain type under a specific node.
* @node {AstNode} node to start form
* @type {String} Type the ast node should have
* @return {AstNode} null or node found
* Note: developed keeping identifier node search in mind to get first identifier node from left in subscope
*/
function findFirstSubNodeLTR (node: any, type: string): any {
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)
}
/**
* Builds a function signature as used in the AST of the solc-json AST
* @param {Array} paramTypes * @param {Array} paramTypes
* list of parameter type names * list of parameter type names
* @param {Array} returnTypes * @param {Array} returnTypes

@ -24,6 +24,15 @@ export interface ReportObj {
more?: string more?: string
} }
export interface AnalysisReportObj extends ReportObj {
error? : string
}
export type AnalysisReport = {
name: string
report: AnalysisReportObj[]
}
export interface CompilationResult { export interface CompilationResult {
error?: CompilationError, error?: CompilationError,
/** not present if no errors/warnings were encountered */ /** not present if no errors/warnings were encountered */

@ -135,7 +135,7 @@ test('staticAnalysisCommon.helpers.expressionTypeDescription', function (t) {
// #################### Trivial Getter Test // #################### Trivial Getter Test
test('staticAnalysisCommon.getType', function (t) { test('staticAnalysisCommon.getType', function (t) {
t.plan(2) t.plan(3)
const node = { "argumentTypes": null, const node = { "argumentTypes": null,
"id": 3, "id": 3,
"name": "a", "name": "a",
@ -151,6 +151,7 @@ test('staticAnalysisCommon.getType', function (t) {
} }
t.ok(common.getType(blockHashAccess) === 'bytes32', 'gettype should work for different nodes') t.ok(common.getType(blockHashAccess) === 'bytes32', 'gettype should work for different nodes')
t.ok(common.getType(node) === 'uint256', 'gettype should work for different nodes') t.ok(common.getType(node) === 'uint256', 'gettype should work for different nodes')
t.ok(common.getType(assignment) === 'uint256', 'gettype should work for different nodes')
}) })
// #################### Complex Getter Test // #################### Complex Getter Test
@ -165,114 +166,127 @@ test('staticAnalysisCommon.getFunctionCallType', function (t) {
test('staticAnalysisCommon.getEffectedVariableName', function (t) { test('staticAnalysisCommon.getEffectedVariableName', function (t) {
t.plan(3) t.plan(3)
t.throws(() => common.getEffectedVariableName(inlineAssembly), Error, 'staticAnalysisCommon.js: not an effect Node or inline assembly, get from inline assembly should throw')
t.ok(common.getEffectedVariableName(assignment) === 'a', 'get right name for assignment') t.ok(common.getEffectedVariableName(assignment) === 'a', 'get right name for assignment')
t.throws(() => common.getEffectedVariableName(externalDirect), Error, 'should throw on all other nodes') t.throws(() => common.getEffectedVariableName(inlineAssembly), new RegExp('staticAnalysisCommon.js: wrong node type'), 'staticAnalysisCommon.js: not an effect Node or inline assembly, get from inline assembly should throw')
t.throws(() => common.getEffectedVariableName(externalDirect), new RegExp('staticAnalysisCommon.js: not an effect Node'), 'should throw on all other nodes')
}) })
test('staticAnalysisCommon.getLocalCallName', function (t) { test('staticAnalysisCommon.getLocalCallName', function (t) {
t.plan(3) t.plan(3)
t.ok(common.getLocalCallName(localCall) === 'e', 'getLocal call name from node') t.ok(common.getLocalCallName(localCall) === 'e', 'getLocal call name from node')
t.throws(() => common.getLocalCallName(externalDirect), Error, 'throws on other nodes') t.throws(() => common.getLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a local call Node'), 'throws for externalDirect nodes')
t.throws(() => common.getLocalCallName(thisLocalCall), Error, 'throws on other nodes') t.throws(() => common.getLocalCallName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a local call Node'), 'throws for this local call nodes')
}) })
test('staticAnalysisCommon.getThisLocalCallName', function (t) { test('staticAnalysisCommon.getThisLocalCallName', function (t) {
t.plan(3) t.plan(3)
t.ok(common.getThisLocalCallName(thisLocalCall) === 'f', 'get this Local call name from node') t.ok(common.getThisLocalCallName(thisLocalCall) === 'f', 'get this Local call name from node')
t.throws(() => common.getThisLocalCallName(externalDirect), Error, 'throws on other nodes') t.throws(() => common.getThisLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on externalDirect nodes')
t.throws(() => common.getThisLocalCallName(localCall), Error, 'throws on other nodes') t.throws(() => common.getThisLocalCallName(localCall), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on localCall nodes')
}) })
test('staticAnalysisCommon.getSuperLocalCallName', function (t) { test('staticAnalysisCommon.getSuperLocalCallName', function (t) {
t.plan(4) t.plan(4)
t.equal(common.getSuperLocalCallName(superLocal), 'x', 'get local name from super local call') t.equal(common.getSuperLocalCallName(superLocal), 'x', 'get local name from super local call')
t.throws(() => common.getSuperLocalCallName(thisLocalCall), 'throws on other nodes') t.throws(() => common.getSuperLocalCallName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a super local call Node'), 'throws on other nodes')
t.throws(() => common.getSuperLocalCallName(externalDirect), 'throws on other nodes') t.throws(() => common.getSuperLocalCallName(externalDirect), new RegExp('staticAnalysisCommon.js: not a super local call Node'),' throws on other nodes')
t.throws(() => common.getSuperLocalCallName(localCall), 'throws on other nodes') t.throws(() => common.getSuperLocalCallName(localCall), new RegExp('staticAnalysisCommon.js: not a super local call Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getExternalDirectCallContractName', function (t) { test('staticAnalysisCommon.getExternalDirectCallContractName', function (t) {
t.plan(3) t.plan(3)
t.ok(common.getExternalDirectCallContractName(externalDirect) === 'c', 'external direct call contract name from node') t.ok(common.getExternalDirectCallContractName(externalDirect) === 'c', 'external direct call contract name from node')
t.throws(() => common.getExternalDirectCallContractName(thisLocalCall), Error, 'throws on other nodes') t.throws(() => common.getExternalDirectCallContractName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
t.throws(() => common.getExternalDirectCallContractName(localCall), Error, 'throws on other nodes') t.throws(() => common.getExternalDirectCallContractName(localCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getThisLocalCallContractName', function (t) { test('staticAnalysisCommon.getThisLocalCallContractName', function (t) {
t.plan(3) t.plan(3)
t.ok(common.getThisLocalCallContractName(thisLocalCall) === 'C', 'this local call contract name from node') t.ok(common.getThisLocalCallContractName(thisLocalCall) === 'C', 'this local call contract name from node')
t.throws(() => common.getThisLocalCallContractName(localCall), Error, 'throws on other nodes') t.throws(() => common.getThisLocalCallContractName(localCall), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on other nodes')
t.throws(() => common.getThisLocalCallContractName(externalDirect), Error, 'throws on other nodes') t.throws(() => common.getThisLocalCallContractName(externalDirect), new RegExp('staticAnalysisCommon.js: not a this local call Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getExternalDirectCallMemberName', function (t) { test('staticAnalysisCommon.getExternalDirectCallMemberName', function (t) {
t.plan(3) t.plan(3)
t.ok(common.getExternalDirectCallMemberName(externalDirect) === 'f', 'external direct call name from node') t.ok(common.getExternalDirectCallMemberName(externalDirect) === 'f', 'external direct call name from node')
t.throws(() => common.getExternalDirectCallMemberName(thisLocalCall), Error, 'throws on other nodes') t.throws(() => common.getExternalDirectCallMemberName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
t.throws(() => common.getExternalDirectCallMemberName(localCall), Error, 'throws on other nodes') t.throws(() => common.getExternalDirectCallMemberName(localCall), new RegExp('staticAnalysisCommon.js: not an external direct call Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getContractName', function (t) { test('staticAnalysisCommon.getContractName', function (t) {
t.plan(1) t.plan(2)
t.ok(common.getContractName(contractDefinition) === 'C', 'returns right contract name') t.ok(common.getContractName(contractDefinition) === 'C', 'returns right contract name')
t.throws(() => common.getContractName(inheritance), new RegExp('staticAnalysisCommon.js: not a ContractDefinition Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getFunctionDefinitionName', function (t) { test('staticAnalysisCommon.getFunctionDefinitionName', function (t) {
t.plan(1) t.plan(2)
t.ok(common.getFunctionDefinitionName(functionDefinition) === 'f', 'returns right function name') t.ok(common.getFunctionDefinitionName(functionDefinition) === 'f', 'returns right function name')
t.throws(() => common.getFunctionDefinitionName(inheritance), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getInheritsFromName', function (t) { test('staticAnalysisCommon.getInheritsFromName', function (t) {
t.plan(1) t.plan(2)
t.ok(common.getInheritsFromName(inheritance) === 'A', 'returns right contract name') t.ok(common.getInheritsFromName(inheritance) === 'A', 'returns right contract name')
t.throws(() => common.getInheritsFromName(functionDefinition), new RegExp('staticAnalysisCommon.js: not an InheritanceSpecifier Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getDeclaredVariableName', function (t) { test('staticAnalysisCommon.getDeclaredVariableName', function (t) {
t.plan(1) t.plan(2)
t.ok(common.getDeclaredVariableName(storageVariableNodes.node1) === 'c', 'extract right variable name') t.ok(common.getDeclaredVariableName(storageVariableNodes.node1) === 'c', 'extract right variable name')
let node1 = JSON.parse(JSON.stringify(storageVariableNodes))
node1.node1.nodeType = 'FunctionCall'
t.throws(() => common.getDeclaredVariableName(node1) === 'x', new RegExp('staticAnalysisCommon.js: not a VariableDeclaration Node'), 'throw if wrong node')
}) })
test('staticAnalysisCommon.getStateVariableDeclarationsFromContractNode', function (t) { test('staticAnalysisCommon.getStateVariableDeclarationsFromContractNode', function (t) {
t.plan(3) t.plan(3)
const res = common.getStateVariableDeclarationsFromContractNode(stateVariableContractNode).map(common.getDeclaredVariableName) const res = common.getStateVariableDeclarationsFromContractNode(stateVariableContractNode).map(common.getDeclaredVariableName)
t.ok(res[0] === 'x', 'var 1 should be ') t.ok(res[0] === 'x', 'var 1 should be x')
t.ok(res[1] === 'b', 'var 2 should be ') t.ok(res[1] === 'b', 'var 2 should be b')
t.ok(res[2] === 's', 'var 3 should be ') t.ok(res[2] === 's', 'var 3 should be s')
}) })
test('staticAnalysisCommon.getFunctionOrModifierDefinitionParameterPart', function (t) { test('staticAnalysisCommon.getFunctionOrModifierDefinitionParameterPart', function (t) {
t.plan(1) t.plan(2)
t.ok(common.helpers.nodeType(common.getFunctionOrModifierDefinitionParameterPart(functionDefinition), 'ParameterList'), 'should return a parameterList') t.ok(common.helpers.nodeType(common.getFunctionOrModifierDefinitionParameterPart(functionDefinition), 'ParameterList'), 'should return a parameterList')
t.throws(() => common.getFunctionOrModifierDefinitionParameterPart(contractDefinition), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition or ModifierDefinition Node'), 'throws on other nodes')
}) })
test('staticAnalysisCommon.getFunctionCallTypeParameterType', function (t) { test('staticAnalysisCommon.getFunctionCallTypeParameterType', function (t) {
t.plan(3) t.plan(4)
t.ok(common.getFunctionCallTypeParameterType(thisLocalCall) === '', 'this local call returns correct type') t.ok(common.getFunctionCallTypeParameterType(thisLocalCall) === '', 'this local call returns correct type')
t.ok(common.getFunctionCallTypeParameterType(externalDirect) === '', 'external direct call returns correct type') t.ok(common.getFunctionCallTypeParameterType(externalDirect) === '', 'external direct call returns correct type')
t.ok(common.getFunctionCallTypeParameterType(localCall) === 'uint256,string memory', 'local call returns correct type') t.ok(common.getFunctionCallTypeParameterType(localCall) === 'uint256,string memory', 'local call returns correct type')
t.throws(() => common.getFunctionCallTypeParameterType(thisLocalCall.expression), new RegExp('staticAnalysisCommon.js: cannot extract parameter types from function call'), 'throws on wrong type')
}) })
test('staticAnalysisCommon.getLibraryCallContractName', function (t) { test('staticAnalysisCommon.getLibraryCallContractName', function (t) {
t.plan(1) t.plan(2)
t.equal(common.getLibraryCallContractName(libCall), 'Set', 'should return correct contract name') t.equal(common.getLibraryCallContractName(libCall), 'Set', 'should return correct contract name')
t.throws(() => common.getLibraryCallContractName(contractDefinition), new RegExp('staticAnalysisCommon.js: not a library call Node'), 'should throw on wrong node')
}) })
test('staticAnalysisCommon.getLibraryCallMemberName', function (t) { test('staticAnalysisCommon.getLibraryCallMemberName', function (t) {
t.plan(1) t.plan(2)
t.equal(common.getLibraryCallMemberName(libCall), 'insert', 'should return correct member name') t.equal(common.getLibraryCallMemberName(libCall), 'insert', 'should return correct member name')
t.throws(() => common.getLibraryCallMemberName(thisLocalCall), new RegExp('staticAnalysisCommon.js: not a library call Node'), 'should throw on wrong node')
}) })
test('staticAnalysisCommon.getFullQualifiedFunctionCallIdent', function (t) { test('staticAnalysisCommon.getFullQualifiedFunctionCallIdent', function (t) {
t.plan(3) t.plan(4)
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, thisLocalCall) === 'C.f()', 'this local call returns correct type') t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, thisLocalCall) === 'C.f()', 'this local call returns correct type')
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, externalDirect) === 'c.f()', 'external direct call returns correct type') t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, externalDirect) === 'c.f()', 'external direct call returns correct type')
t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, localCall) === 'C.e(uint256,string memory)', 'local call returns correct type') t.ok(common.getFullQualifiedFunctionCallIdent(contractDefinition, localCall) === 'C.e(uint256,string memory)', 'local call returns correct type')
t.throws(() => common.getFullQualifiedFunctionCallIdent(contractDefinition, assignment), new RegExp('staticAnalysisCommon.js: Can not get function name from non function call node'), 'throws on wrong type')
}) })
test('staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent', function (t) { test('staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent', function (t) {
t.plan(1) t.plan(3)
t.ok(common.getFullQuallyfiedFuncDefinitionIdent(contractDefinition, functionDefinition, ['uint256', 'bool']) === 'C.f(uint256,bool)', 'creates right signature') t.ok(common.getFullQuallyfiedFuncDefinitionIdent(contractDefinition, functionDefinition, ['uint256', 'bool']) === 'C.f(uint256,bool)', 'creates right signature')
t.throws(() => common.getFullQuallyfiedFuncDefinitionIdent(contractDefinition, parameterFunctionCall, ['uint256', 'bool']), new RegExp('staticAnalysisCommon.js: not a FunctionDefinition Node'), 'throws on wrong nodes')
t.throws(() => common.getFullQuallyfiedFuncDefinitionIdent(parameterFunctionCall, functionDefinition, ['uint256', 'bool']), new RegExp('staticAnalysisCommon.js: not a ContractDefinition Node'), 'throws on wrong nodes')
}) })
// #################### Complex Node Identification // #################### Complex Node Identification
@ -376,7 +390,7 @@ test('staticAnalysisCommon.isExternalDirectCall', function (t) {
t.notOk(common.isBlockTimestampAccess(externalDirect), 'is block.timestamp used should not work') t.notOk(common.isBlockTimestampAccess(externalDirect), 'is block.timestamp used should not work')
t.notOk(common.isNowAccess(externalDirect), 'is now used should not work') t.notOk(common.isNowAccess(externalDirect), 'is now used should not work')
t.ok(common.isExternalDirectCall(externalDirect), 'c.f() should be external direct call') t.ok(common.isExternalDirectCall(externalDirect), 'c.f() should be external direct call')
t.notOk(common.isExternalDirectCall(thisLocalCall.expression), 'this local call is not an exernal call') t.notOk(common.isExternalDirectCall(thisLocalCall.expression), 'this local call is not an external call')
}) })
test('staticAnalysisCommon.isNowAccess', function (t) { test('staticAnalysisCommon.isNowAccess', function (t) {

@ -3,30 +3,30 @@ import { helpers } from 'remix-lib'
import { readFileSync } from 'fs' import { readFileSync } from 'fs'
import { join } from 'path' import { join } from 'path'
import { default as StatRunner } from '../../dist/src/solidity-analyzer' import { default as StatRunner } from '../../dist/src/solidity-analyzer'
import { CompilationResult, AnalysisReportObj, AnalysisReport } from '../../src/types'
import { install, require as requireNPMmodule } from 'npm-install-version' import { install, require as requireNPMmodule } from 'npm-install-version'
install('solc@0.4.24') install('solc@0.4.24')
const compiler = requireNPMmodule('solc@0.4.24') const compiler = requireNPMmodule('solc@0.4.24')
const { compilerInput } = helpers.compiler const { compilerInput } = helpers.compiler
const folder = 'solidity-v0.4.24' const folder: string = 'solidity-v0.4.24'
function compile (fileName) { function compile (fileName: string): CompilationResult {
const content = readFileSync(join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') const content: string = readFileSync(join(__dirname, 'test-contracts/' + folder, fileName), 'utf8')
return JSON.parse(compiler.compileStandardWrapper(compilerInput(content))) return JSON.parse(compiler.compileStandardWrapper(compilerInput(content)))
} }
test('staticAnalysisIssues.functionParameterPassingError', function (t) { test('staticAnalysisIssues.functionParameterPassingError', function (t) {
// https://github.com/ethereum/remix-ide/issues/889#issuecomment-351746474 // https://github.com/ethereum/remix-ide/issues/889#issuecomment-351746474
t.plan(2) t.plan(2)
const res = compile('functionParameters.sol') const res: CompilationResult = compile('functionParameters.sol')
const Module = require('../../dist/src/solidity-analyzer/modules/checksEffectsInteraction').default const Module = require('../../dist/src/solidity-analyzer/modules/checksEffectsInteraction').default
const statRunner = new StatRunner() const statRunner: StatRunner = new StatRunner()
t.doesNotThrow(() => { t.doesNotThrow(() => {
statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports) => { statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports: AnalysisReport[]) => {})
})
}, 'Analysis should not throw') }, 'Analysis should not throw')
statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports) => { statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports: AnalysisReport[]) => {
t.ok(!reports.some((mod) => mod.report.some((rep) => rep.warning.includes('INTERNAL ERROR')), 'Should not have internal errors')) t.ok(!reports.some((mod: AnalysisReport) => mod.report.some((rep: AnalysisReportObj) => rep.warning.includes('INTERNAL ERROR')), 'Should not have internal errors'))
}) })
}) })

@ -3,30 +3,30 @@ import { helpers } from 'remix-lib'
import { readFileSync } from 'fs' import { readFileSync } from 'fs'
import { join } from 'path' import { join } from 'path'
import { default as StatRunner } from '../../dist/src/solidity-analyzer' import { default as StatRunner } from '../../dist/src/solidity-analyzer'
import { CompilationResult, AnalysisReportObj, AnalysisReport } from '../../src/types'
import { install, require as requireNPMmodule } from 'npm-install-version' import { install, require as requireNPMmodule } from 'npm-install-version'
install('solc@0.5.0') install('solc@0.5.0')
const compiler = requireNPMmodule('solc@0.5.0') const compiler = requireNPMmodule('solc@0.5.0')
const {compilerInput } = helpers.compiler const {compilerInput } = helpers.compiler
const folder = 'solidity-v0.5' const folder: string = 'solidity-v0.5'
function compile (fileName) { function compile (fileName): CompilationResult {
const content = readFileSync(join(__dirname, 'test-contracts/' + folder, fileName), 'utf8') const content: string = readFileSync(join(__dirname, 'test-contracts/' + folder, fileName), 'utf8')
return JSON.parse(compiler.compile(compilerInput(content))) return JSON.parse(compiler.compile(compilerInput(content)))
} }
test('staticAnalysisIssues.functionParameterPassingError', function (t) { test('staticAnalysisIssues.functionParameterPassingError', function (t) {
// https://github.com/ethereum/remix-ide/issues/889#issuecomment-351746474 // https://github.com/ethereum/remix-ide/issues/889#issuecomment-351746474
t.plan(2) t.plan(2)
const res = compile('functionParameters.sol') const res: CompilationResult = compile('functionParameters.sol')
const Module = require('../../dist/src/solidity-analyzer/modules/checksEffectsInteraction').default const Module = require('../../dist/src/solidity-analyzer/modules/checksEffectsInteraction').default
const statRunner = new StatRunner() const statRunner: StatRunner = new StatRunner()
t.doesNotThrow(() => { t.doesNotThrow(() => {
statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports) => { statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports: AnalysisReport[]) => {})
})
}, 'Analysis should not throw') }, 'Analysis should not throw')
statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports) => { statRunner.runWithModuleList(res, [{ name: new Module().name, mod: new Module() }], (reports: AnalysisReport[]) => {
t.ok(!reports.some((mod) => mod.report.some((rep) => rep.warning.includes('INTERNAL ERROR')), 'Should not have internal errors')) t.ok(!reports.some((mod: AnalysisReport) => mod.report.some((rep: AnalysisReportObj) => rep.warning.includes('INTERNAL ERROR')), 'Should not have internal errors'))
}) })
}) })

Loading…
Cancel
Save