var test = require ( 'tape' )
var common = require ( '../../src/solidity-analyzer/modules/staticAnalysisCommon' )
function escapeRegExp ( str ) {
return str . replace ( /[-[\]/{}()+?.\\^$|]/g , '\\$&' )
}
test ( 'staticAnalysisCommon.helpers.buildFunctionSignature' , function ( t ) {
t . plan ( 9 )
t . equal ( common . helpers . buildFunctionSignature ( [ common . basicTypes . UINT , common . basicTypes . ADDRESS ] , [ common . basicTypes . BOOL ] , false ) ,
'function (uint256,address) returns (bool)' ,
'two params and return value without payable' )
t . equal ( common . helpers . buildFunctionSignature ( [ common . basicTypes . UINT , common . basicTypes . ADDRESS ] , [ common . basicTypes . BOOL ] , false , 'pure' ) ,
'function (uint256,address) pure returns (bool)' ,
'two params and return value without payable but pure' )
t . equal ( common . helpers . buildFunctionSignature ( [ common . basicTypes . UINT , common . basicTypes . ADDRESS ] , [ common . basicTypes . BOOL ] , true , 'pure' ) ,
'function (uint256,address) payable pure returns (bool)' ,
'two params and return value without payable but pure' )
t . equal ( common . helpers . buildFunctionSignature ( [ common . basicTypes . UINT , common . basicTypes . BYTES32 , common . basicTypes . BYTES32 ] , [ ] , true ) ,
'function (uint256,bytes32,bytes32) payable' ,
'three params and no return with payable' )
t . equal ( common . helpers . buildFunctionSignature ( [ common . basicTypes . BOOL ] , [ common . basicTypes . BYTES32 , common . basicTypes . ADDRESS ] , true ) ,
'function (bool) payable returns (bytes32,address)' ,
'one param and two return values with payable' )
t . equal ( common . lowLevelCallTypes . CALL . type ,
'function () payable returns (bool)' ,
'check fixed call type' )
t . equal ( common . lowLevelCallTypes . CALLCODE . type ,
'function () payable returns (bool)' ,
'check fixed callcode type' )
t . equal ( common . lowLevelCallTypes . SEND . type ,
'function (uint256) returns (bool)' ,
'check fixed send type' )
t . equal ( common . lowLevelCallTypes . DELEGATECALL . type ,
'function () returns (bool)' ,
'check fixed call type' )
} )
// #################### Node Identification Primitives
test ( 'staticAnalysisCommon.helpers.name' , function ( t ) {
t . plan ( 9 )
var node = { attributes : { value : 'now' } }
var node2 = { attributes : { member _name : 'call' } }
t . ok ( common . helpers . name ( node , 'now' ) , 'should work for values' )
t . ok ( common . helpers . name ( node2 , 'call' ) , 'should work for member_name' )
t . ok ( common . helpers . name ( node2 , '.all' ) , 'regex should work' )
lowlevelAccessersCommon ( t , common . helpers . name , node )
} )
test ( 'staticAnalysisCommon.helpers.operator' , function ( t ) {
t . plan ( 10 )
var node = { attributes : { operator : '++' } }
var node2 = { attributes : { operator : '+++' } }
var escapedPP = escapeRegExp ( '++' )
var escapedPPExact = ` ^ ${ escapedPP } $ `
t . ok ( common . helpers . operator ( node , escapedPPExact ) , 'should work for ++' )
t . notOk ( common . helpers . operator ( node2 , escapedPPExact ) , 'should not work for +++' )
t . ok ( common . helpers . operator ( node , escapedPP ) , 'should work for ++' )
t . ok ( common . helpers . operator ( node2 , escapedPP ) , 'should work for +++' )
lowlevelAccessersCommon ( t , common . helpers . operator , node )
} )
test ( 'staticAnalysisCommon.helpers.nodeType' , function ( t ) {
t . plan ( 9 )
var node = { name : 'Identifier' , attributes : { name : 'now' } }
var node2 = { name : 'FunctionCall' , attributes : { member _name : 'call' } }
t . ok ( common . helpers . nodeType ( node , common . nodeTypes . IDENTIFIER ) , 'should work for ident' )
t . ok ( common . helpers . nodeType ( node2 , common . nodeTypes . FUNCTIONCALL ) , 'should work for funcall' )
t . ok ( common . helpers . nodeType ( node2 , '^F' ) , 'regex should work for funcall' )
lowlevelAccessersCommon ( t , common . helpers . nodeType , node )
} )
test ( 'staticAnalysisCommon.helpers.expressionType' , function ( t ) {
t . plan ( 9 )
var node = { name : 'Identifier' , attributes : { value : 'now' , type : 'uint256' } }
var node2 = { name : 'FunctionCall' , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
t . ok ( common . helpers . expressionType ( node , common . basicTypes . UINT ) , 'should work for ident' )
t . ok ( common . helpers . expressionType ( node2 , escapeRegExp ( common . basicFunctionTypes . CALL ) ) , 'should work for funcall' )
t . ok ( common . helpers . expressionType ( node2 , '^function \\(' ) , 'regex should work' )
lowlevelAccessersCommon ( t , common . helpers . expressionType , node )
} )
test ( 'staticAnalysisCommon.helpers.nrOfChildren' , function ( t ) {
t . plan ( 10 )
var node = { name : 'Identifier' , children : [ 'a' , 'b' ] , attributes : { value : 'now' , type : 'uint256' } }
var node2 = { name : 'FunctionCall' , children : [ ] , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
var node3 = { name : 'FunctionCall' , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
t . ok ( common . helpers . nrOfChildren ( node , 2 ) , 'should work for 2 children' )
t . notOk ( common . helpers . nrOfChildren ( node , '1+2' ) , 'regex should not work' )
t . ok ( common . helpers . nrOfChildren ( node2 , 0 ) , 'should work for 0 children' )
t . ok ( common . helpers . nrOfChildren ( node3 , 0 ) , 'should work without children arr' )
lowlevelAccessersCommon ( t , common . helpers . nrOfChildren , node )
} )
test ( 'staticAnalysisCommon.helpers.minNrOfChildren' , function ( t ) {
t . plan ( 13 )
var node = { name : 'Identifier' , children : [ 'a' , 'b' ] , attributes : { value : 'now' , type : 'uint256' } }
var node2 = { name : 'FunctionCall' , children : [ ] , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
var node3 = { name : 'FunctionCall' , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
t . ok ( common . helpers . minNrOfChildren ( node , 2 ) , 'should work for 2 children' )
t . ok ( common . helpers . minNrOfChildren ( node , 1 ) , 'should work for 1 children' )
t . ok ( common . helpers . minNrOfChildren ( node , 0 ) , 'should work for 0 children' )
t . notOk ( common . helpers . minNrOfChildren ( node , 3 ) , 'has less than 3 children' )
t . notOk ( common . helpers . minNrOfChildren ( node , '1+2' ) , 'regex should not work' )
t . ok ( common . helpers . minNrOfChildren ( node2 , 0 ) , 'should work for 0 children' )
t . ok ( common . helpers . minNrOfChildren ( node3 , 0 ) , 'should work without children arr' )
lowlevelAccessersCommon ( t , common . helpers . minNrOfChildren , node )
} )
function lowlevelAccessersCommon ( t , f , someNode ) {
t . ok ( f ( someNode ) , 'always ok if type is undefinded' )
t . ok ( f ( someNode , undefined ) , 'always ok if name is undefinded 2' )
t . notOk ( f ( null , undefined ) , 'false on no node' )
t . notOk ( f ( null , 'call' ) , 'false on no node' )
t . notOk ( f ( undefined , null ) , 'false on no node' )
t . notOk ( f ( ) , 'false on no params' )
}
// #################### Trivial Getter Test
test ( 'staticAnalysisCommon.getType' , function ( t ) {
t . plan ( 3 )
var node = { name : 'Identifier' , children : [ 'a' , 'b' ] , attributes : { value : 'now' , type : 'uint256' } }
var node2 = { name : 'FunctionCall' , children : [ ] , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
var node3 = { name : 'FunctionCall' , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
t . ok ( common . getType ( node ) === 'uint256' , 'gettype should work for different nodes' )
t . ok ( common . getType ( node2 ) === 'function () payable returns (bool)' , 'gettype should work for different nodes' )
t . ok ( common . getType ( node3 ) === 'function () payable returns (bool)' , 'gettype should work for different nodes' )
} )
// #################### Complex Getter Test
test ( 'staticAnalysisCommon.getFunctionCallType' , function ( t ) {
t . plan ( 5 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
var libCall = {
'attributes' : {
'member_name' : 'insert' ,
'type' : 'function (struct Set.Data storage pointer,uint256) returns (bool)'
} ,
'children' : [
{
'attributes' : {
'type' : 'type(library Set)' ,
'value' : 'Set'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . equal ( common . getFunctionCallType ( libCall ) , 'function (struct Set.Data storage pointer,uint256) returns (bool)' , 'this lib call returns correct type' )
t . equal ( common . getFunctionCallType ( thisLocalCall ) , 'function (bytes32,address) returns (bool)' , 'this local call returns correct type' )
t . equal ( common . getFunctionCallType ( externalDirect ) , 'function () payable external returns (uint256)' , 'external direct call returns correct type' )
t . equal ( common . getFunctionCallType ( localCall ) , 'function (struct Ballot.Voter storage pointer)' , 'local call returns correct type' )
t . throws ( ( ) => common . getFunctionCallType ( { name : 'MemberAccess' } ) , undefined , 'throws on wrong type' )
} )
test ( 'staticAnalysisCommon.getEffectedVariableName' , function ( t ) {
t . plan ( 3 )
var assignment = {
'attributes' : {
'operator' : '=' ,
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'mapping(address => uint256)' ,
'value' : 'c'
} ,
'id' : 61 ,
'name' : 'Identifier' ,
'src' : '873:1:0'
} ,
{
'attributes' : {
'member_name' : 'sender' ,
'type' : 'address'
} ,
'children' : [
{
'attributes' : {
'type' : 'msg' ,
'value' : 'msg'
} ,
'id' : 62 ,
'name' : 'Identifier' ,
'src' : '875:3:0'
}
] ,
'id' : 63 ,
'name' : 'MemberAccess' ,
'src' : '875:10:0'
}
] ,
'id' : 64 ,
'name' : 'IndexAccess' ,
'src' : '873:13:0'
} ,
{
'attributes' : {
'hexvalue' : '30' ,
'subdenomination' : null ,
'token' : null ,
'type' : 'int_const 0' ,
'value' : '0'
} ,
'id' : 65 ,
'name' : 'Literal' ,
'src' : '889:1:0'
}
] ,
'id' : 66 ,
'name' : 'Assignment' ,
'src' : '873:17:0'
}
var inlineAssembly = {
'children' : [
] ,
'id' : 21 ,
'name' : 'InlineAssembly' ,
'src' : '809:41:0'
}
t . throws ( ( ) => common . getEffectedVariableName ( inlineAssembly ) , 'staticAnalysisCommon.js: not an effect Node or inline assembly' , 'get from inline assembly should throw' )
t . ok ( common . getEffectedVariableName ( assignment ) === 'c' , 'get right name for assignment' )
t . throws ( ( ) => common . getEffectedVariableName ( { name : 'MemberAccess' } ) , undefined , 'should throw on all other nodes' )
} )
test ( 'staticAnalysisCommon.getLocalCallName' , function ( t ) {
t . plan ( 3 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getLocalCallName ( localCall ) === 'bli' , 'getLocal call name from node' )
t . throws ( ( ) => common . getLocalCallName ( externalDirect ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getLocalCallName ( thisLocalCall ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getThisLocalCallName' , function ( t ) {
t . plan ( 3 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getThisLocalCallName ( thisLocalCall ) === 'b' , 'get this Local call name from node' )
t . throws ( ( ) => common . getThisLocalCallName ( externalDirect ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getThisLocalCallName ( localCall ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getSuperLocalCallName' , function ( t ) {
t . plan ( 4 )
var superLocal = {
'attributes' : {
'member_name' : 'duper' ,
'type' : 'function ()'
} ,
'children' : [
{
'attributes' : {
'type' : 'contract super a' ,
'value' : 'super'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . equal ( common . getSuperLocalCallName ( superLocal ) , 'duper' , 'get local name from super local call' )
t . throws ( ( ) => common . getSuperLocalCallName ( thisLocalCall ) , 'throws on other nodes' )
t . throws ( ( ) => common . getSuperLocalCallName ( externalDirect ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getSuperLocalCallName ( localCall ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getExternalDirectCallContractName' , function ( t ) {
t . plan ( 3 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getExternalDirectCallContractName ( externalDirect ) === 'InfoFeed' , 'external direct call contract name from node' )
t . throws ( ( ) => common . getExternalDirectCallContractName ( thisLocalCall ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getExternalDirectCallContractName ( localCall ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getThisLocalCallContractName' , function ( t ) {
t . plan ( 3 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getThisLocalCallContractName ( thisLocalCall ) === 'test' , 'this local call contract name from node' )
t . throws ( ( ) => common . getThisLocalCallContractName ( localCall ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getThisLocalCallContractName ( externalDirect ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getExternalDirectCallMemberName' , function ( t ) {
t . plan ( 3 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getExternalDirectCallMemberName ( externalDirect ) === 'info' , 'external direct call name from node' )
t . throws ( ( ) => common . getExternalDirectCallMemberName ( thisLocalCall ) , undefined , 'throws on other nodes' )
t . throws ( ( ) => common . getExternalDirectCallMemberName ( localCall ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getContractName' , function ( t ) {
t . plan ( 2 )
var contract = { name : 'ContractDefinition' , attributes : { name : 'baz' } }
t . ok ( common . getContractName ( contract ) === 'baz' , 'returns right contract name' )
t . throws ( ( ) => common . getContractName ( { name : 'InheritanceSpecifier' } ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getFunctionDefinitionName' , function ( t ) {
t . plan ( 2 )
var func = { name : 'FunctionDefinition' , attributes : { name : 'foo' } }
t . ok ( common . getFunctionDefinitionName ( func ) === 'foo' , 'returns right contract name' )
t . throws ( ( ) => common . getFunctionDefinitionName ( { name : 'InlineAssembly' } ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getInheritsFromName' , function ( t ) {
t . plan ( 2 )
var inh = {
'children' : [
{
'attributes' : {
'name' : 'r'
} ,
'id' : 7 ,
'name' : 'UserDefinedTypeName' ,
'src' : '84:1:0'
}
] ,
'id' : 8 ,
'name' : 'InheritanceSpecifier' ,
'src' : '84:1:0'
}
t . ok ( common . getInheritsFromName ( inh ) === 'r' , 'returns right contract name' )
t . throws ( ( ) => common . getInheritsFromName ( { name : 'ElementaryTypeName' } ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getDeclaredVariableName' , function ( t ) {
t . plan ( 2 )
var node1 = {
'attributes' : {
'name' : 'x' ,
'type' : 'struct Ballot.Voter storage pointer'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'id' : 43 ,
'name' : 'UserDefinedTypeName' ,
'src' : '604:5:0'
}
] ,
'id' : 44 ,
'name' : 'VariableDeclaration' ,
'src' : '604:15:0'
}
t . ok ( common . getDeclaredVariableName ( node1 ) === 'x' , 'extract right variable name' )
node1 . name = 'FunctionCall'
t . throws ( ( ) => common . getDeclaredVariableName ( node1 ) === 'x' , undefined , 'throw if wrong node' )
} )
test ( 'staticAnalysisCommon.getStateVariableDeclarationsFormContractNode' , function ( t ) {
t . plan ( 4 )
var contract = {
'attributes' : {
'fullyImplemented' : true ,
'isLibrary' : false ,
'linearizedBaseContracts' : [
274
] ,
'name' : 'Ballot'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'children' : [ ] ,
'name' : 'StructDefinition'
} ,
{
'attributes' : {
'name' : 'Proposal'
} ,
'children' : [ ] ,
'name' : 'StructDefinition'
} ,
{
'attributes' : {
'name' : 'chairperson' ,
'type' : 'address'
} ,
'children' : [
{
'attributes' : {
'name' : 'address'
} ,
'name' : 'ElementaryTypeName'
}
] ,
'name' : 'VariableDeclaration'
} ,
{
'attributes' : {
'name' : 'voters' ,
'type' : 'mapping(address => struct Ballot.Voter storage ref)'
} ,
'children' : [
{
'children' : [
{
'attributes' : {
'name' : 'address'
} ,
'name' : 'ElementaryTypeName'
} ,
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'Mapping'
}
] ,
'name' : 'VariableDeclaration'
} ,
{
'attributes' : {
'name' : 'proposals' ,
'type' : 'struct Ballot.Proposal storage ref[] storage ref'
} ,
'children' : [
{
'children' : [
{
'attributes' : {
'name' : 'Proposal'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'ArrayTypeName'
}
] ,
'name' : 'VariableDeclaration'
} ,
{
'attributes' : {
'constant' : false ,
'name' : 'Ballot' ,
'payable' : false ,
'visibility' : 'public'
} ,
'children' : [ ] ,
'name' : 'FunctionDefinition'
} ,
{
'attributes' : {
'constant' : false ,
'name' : 'giveRightToVote' ,
'payable' : false ,
'visibility' : 'public'
} ,
'children' : [ ] ,
'name' : 'FunctionDefinition'
}
] ,
'name' : 'ContractDefinition'
}
var res = common . getStateVariableDeclarationsFormContractNode ( contract ) . map ( common . getDeclaredVariableName )
t . ok ( res [ 0 ] === 'chairperson' , 'var 1 should be ' )
t . ok ( res [ 1 ] === 'voters' , 'var 2 should be ' )
t . ok ( res [ 2 ] === 'proposals' , 'var 3 should be ' )
t . ok ( res [ 3 ] === undefined , 'var 4 should be undefined' )
} )
test ( 'staticAnalysisCommon.getFunctionOrModifierDefinitionParameterPart' , function ( t ) {
t . plan ( 2 )
var funDef = {
'attributes' : {
'constant' : true ,
'name' : 'winnerName' ,
'payable' : false ,
'visibility' : 'public'
} ,
'children' : [
{
'children' : [
] ,
'name' : 'ParameterList'
} ,
{
'children' : [ ] ,
'name' : 'ParameterList'
} ,
{
'children' : [ ] ,
'name' : 'Block'
}
] ,
'name' : 'FunctionDefinition'
}
t . ok ( common . helpers . nodeType ( common . getFunctionOrModifierDefinitionParameterPart ( funDef ) , 'ParameterList' ) , 'should return a parameterList' )
t . throws ( ( ) => common . getFunctionOrModifierDefinitionParameterPart ( { name : 'SourceUnit' } ) , undefined , 'throws on other nodes' )
} )
test ( 'staticAnalysisCommon.getFunctionCallTypeParameterType' , function ( t ) {
t . plan ( 4 )
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getFunctionCallTypeParameterType ( thisLocalCall ) === 'bytes32,address' , 'this local call returns correct type' )
t . ok ( common . getFunctionCallTypeParameterType ( externalDirect ) === '' , 'external direct call returns correct type' )
t . ok ( common . getFunctionCallTypeParameterType ( localCall ) === 'struct Ballot.Voter storage pointer' , 'local call returns correct type' )
t . throws ( ( ) => common . getFunctionCallTypeParameterType ( { name : 'MemberAccess' } ) , undefined , 'throws on wrong type' )
} )
test ( 'staticAnalysisCommon.getLibraryCallContractName' , function ( t ) {
t . plan ( 2 )
var node = {
'attributes' : {
'member_name' : 'insert' ,
'type' : 'function (struct Set.Data storage pointer,uint256) returns (bool)'
} ,
'children' : [
{
'attributes' : {
'type' : 'type(library Set)' ,
'value' : 'Set'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . equal ( common . getLibraryCallContractName ( node ) , 'Set' , 'should return correct contract name' )
t . throws ( ( ) => common . getLibraryCallContractName ( { name : 'Identifier' } ) , undefined , 'should throw on wrong node' )
} )
test ( 'staticAnalysisCommon.getLibraryCallMemberName' , function ( t ) {
t . plan ( 2 )
var node = {
'attributes' : {
'member_name' : 'insert' ,
'type' : 'function (struct Set.Data storage pointer,uint256) returns (bool)'
} ,
'children' : [
{
'attributes' : {
'type' : 'type(library Set)' ,
'value' : 'Set'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . equal ( common . getLibraryCallMemberName ( node ) , 'insert' , 'should return correct member name' )
t . throws ( ( ) => common . getLibraryCallMemberName ( { name : 'Identifier' } ) , undefined , 'should throw on wrong node' )
} )
test ( 'staticAnalysisCommon.getFullQualifiedFunctionCallIdent' , function ( t ) {
t . plan ( 4 )
var contract = { name : 'ContractDefinition' , attributes : { name : 'baz' } }
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
var thisLocalCall = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } , name : 'Identifier' } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
var externalDirect = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
t . ok ( common . getFullQualifiedFunctionCallIdent ( contract , thisLocalCall ) === 'test.b(bytes32,address)' , 'this local call returns correct type' )
t . ok ( common . getFullQualifiedFunctionCallIdent ( contract , externalDirect ) === 'InfoFeed.info()' , 'external direct call returns correct type' )
t . ok ( common . getFullQualifiedFunctionCallIdent ( contract , localCall ) === 'baz.bli(struct Ballot.Voter storage pointer)' , 'local call returns correct type' )
t . throws ( ( ) => common . getFullQualifiedFunctionCallIdent ( contract , { name : 'MemberAccess' } ) , undefined , 'throws on wrong type' )
} )
test ( 'staticAnalysisCommon.getFullQuallyfiedFuncDefinitionIdent' , function ( t ) {
t . plan ( 3 )
var contract = { name : 'ContractDefinition' , attributes : { name : 'baz' } }
var funDef = {
'attributes' : {
'constant' : false ,
'name' : 'getY' ,
'payable' : false ,
'visibility' : 'public'
} ,
'children' : [
{
'children' : [
{
'attributes' : {
'name' : 'z' ,
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'name' : 'uint'
} ,
'name' : 'ElementaryTypeName'
}
] ,
'name' : 'VariableDeclaration'
} ,
{
'attributes' : {
'name' : 'r' ,
'type' : 'bool'
} ,
'children' : [
{
'attributes' : {
'name' : 'bool'
} ,
'name' : 'ElementaryTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
] ,
'name' : 'ParameterList'
} ,
{
'children' : [
{
'attributes' : {
'name' : '' ,
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'name' : 'uint'
} ,
'id' : 34 ,
'name' : 'ElementaryTypeName' ,
'src' : '285:4:0'
}
] ,
'id' : 35 ,
'name' : 'VariableDeclaration' ,
'src' : '285:4:0'
}
] ,
'name' : 'ParameterList'
} ,
{
'children' : [ ] ,
'name' : 'Block'
}
] ,
'name' : 'FunctionDefinition'
}
t . ok ( common . getFullQuallyfiedFuncDefinitionIdent ( contract , funDef , [ 'uint256' , 'bool' ] ) === 'baz.getY(uint256,bool)' , 'creates right signature' )
t . throws ( ( ) => common . getFullQuallyfiedFuncDefinitionIdent ( contract , { name : 'MemberAccess' } , [ 'uint256' , 'bool' ] ) , undefined , 'throws on wrong nodes' )
t . throws ( ( ) => common . getFullQuallyfiedFuncDefinitionIdent ( { name : 'FunctionCall' } , funDef , [ 'uint256' , 'bool' ] ) , undefined , 'throws on wrong nodes' )
} )
test ( 'staticAnalysisCommon.getLoopBlockStartIndex' , function ( t ) {
t . plan ( 3 )
var node1 = {
'children' :
[
{
'attributes' :
{
'assignments' :
[
21
]
} ,
'children' :
[
{
'attributes' :
{
'constant' : false ,
'name' : 'i' ,
'scope' : 39 ,
'stateVariable' : false ,
'storageLocation' : 'default' ,
'type' : 'uint256' ,
'value' : null ,
'visibility' : 'internal'
} ,
'children' :
[
{
'attributes' :
{
'name' : 'uint' ,
'type' : 'uint256'
} ,
'id' : 20 ,
'name' : 'ElementaryTypeName' ,
'src' : '207:4:0'
}
] ,
'id' : 21 ,
'name' : 'VariableDeclaration' ,
'src' : '207:6:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 17 ,
'type' : 'uint256' ,
'value' : 'index'
} ,
'id' : 22 ,
'name' : 'Identifier' ,
'src' : '216:5:0'
}
] ,
'id' : 23 ,
'name' : 'VariableDeclarationStatement' ,
'src' : '207:14:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 24 ,
'name' : 'Identifier' ,
'src' : '223:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 25 ,
'name' : 'Literal' ,
'src' : '227:2:0'
}
] ,
'id' : 26 ,
'name' : 'BinaryOperation' ,
'src' : '223:6:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 27 ,
'name' : 'Identifier' ,
'src' : '231:1:0'
}
] ,
'id' : 28 ,
'name' : 'UnaryOperation' ,
'src' : '231:3:0'
}
] ,
'id' : 29 ,
'name' : 'ExpressionStatement' ,
'src' : '231:3:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 30 ,
'name' : 'Identifier' ,
'src' : '250:5:0'
}
] ,
'id' : 32 ,
'name' : 'MemberAccess' ,
'src' : '250:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 33 ,
'name' : 'Identifier' ,
'src' : '261:1:0'
}
] ,
'id' : 34 ,
'name' : 'FunctionCall' ,
'src' : '250:13:0'
}
] ,
'id' : 35 ,
'name' : 'ExpressionStatement' ,
'src' : '250:13:0'
}
] ,
'id' : 36 ,
'name' : 'Block' ,
'src' : '236:38:0'
}
] ,
'id' : 37 ,
'name' : 'ForStatement' ,
'src' : '202:72:0'
}
var node2 = {
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 82 ,
'name' : 'Identifier' ,
'src' : '592:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 83 ,
'name' : 'Literal' ,
'src' : '596:2:0'
}
] ,
'id' : 84 ,
'name' : 'BinaryOperation' ,
'src' : '592:6:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 72 ,
'name' : 'Identifier' ,
'src' : '544:5:0'
}
] ,
'id' : 74 ,
'name' : 'MemberAccess' ,
'src' : '544:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 75 ,
'name' : 'Identifier' ,
'src' : '555:1:0'
}
] ,
'id' : 76 ,
'name' : 'FunctionCall' ,
'src' : '544:13:0'
}
] ,
'id' : 77 ,
'name' : 'ExpressionStatement' ,
'src' : '544:13:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 78 ,
'name' : 'Identifier' ,
'src' : '571:1:0'
}
] ,
'id' : 79 ,
'name' : 'UnaryOperation' ,
'src' : '571:3:0'
}
] ,
'id' : 80 ,
'name' : 'ExpressionStatement' ,
'src' : '571:3:0'
}
] ,
'id' : 81 ,
'name' : 'Block' ,
'src' : '530:55:0'
}
] ,
'id' : 85 ,
'name' : 'DoWhileStatement' ,
'src' : '528:72:0'
}
var node3 = {
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 48 ,
'name' : 'Identifier' ,
'src' : '372:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 49 ,
'name' : 'Literal' ,
'src' : '376:2:0'
}
] ,
'id' : 50 ,
'name' : 'BinaryOperation' ,
'src' : '372:6:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 51 ,
'name' : 'Identifier' ,
'src' : '394:5:0'
}
] ,
'id' : 53 ,
'name' : 'MemberAccess' ,
'src' : '394:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 54 ,
'name' : 'Identifier' ,
'src' : '405:1:0'
}
] ,
'id' : 55 ,
'name' : 'FunctionCall' ,
'src' : '394:13:0'
}
] ,
'id' : 56 ,
'name' : 'ExpressionStatement' ,
'src' : '394:13:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 57 ,
'name' : 'Identifier' ,
'src' : '421:1:0'
}
] ,
'id' : 58 ,
'name' : 'UnaryOperation' ,
'src' : '421:3:0'
}
] ,
'id' : 59 ,
'name' : 'ExpressionStatement' ,
'src' : '421:3:0'
}
] ,
'id' : 60 ,
'name' : 'Block' ,
'src' : '380:55:0'
}
] ,
'id' : 61 ,
'name' : 'WhileStatement' ,
'src' : '365:70:0'
}
t . equal ( common . getLoopBlockStartIndex ( node1 ) , 3 ) // 'for' loop
t . equal ( common . getLoopBlockStartIndex ( node2 ) , 1 ) // 'do-while' loop
t . equal ( common . getLoopBlockStartIndex ( node3 ) , 1 ) // 'while' loop
} )
// #################### Trivial Node Identification
test ( 'staticAnalysisCommon.isFunctionDefinition' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'FunctionDefinition' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'FunctionDefinitionBLABLA' }
t . ok ( common . isFunctionDefinition ( node1 ) , 'is exact match should work' )
t . notOk ( common . isFunctionDefinition ( node2 ) , 'different node should not work' )
t . notOk ( common . isFunctionDefinition ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isModifierDefinition' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'ModifierDefinition' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'ModifierDefinitionBLABLA' }
t . ok ( common . isModifierDefinition ( node1 ) , 'is exact match should work' )
t . notOk ( common . isModifierDefinition ( node2 ) , 'different node should not work' )
t . notOk ( common . isModifierDefinition ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isModifierInvocation' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'ModifierInvocation' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'ModifierInvocationBLABLA' }
t . ok ( common . isModifierInvocation ( node1 ) , 'is exact match should work' )
t . notOk ( common . isModifierInvocation ( node2 ) , 'different node should not work' )
t . notOk ( common . isModifierInvocation ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isVariableDeclaration' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'VariableDeclaration' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'VariableDeclarationBLABLA' }
t . ok ( common . isVariableDeclaration ( node1 ) , 'is exact match should work' )
t . notOk ( common . isVariableDeclaration ( node2 ) , 'different node should not work' )
t . notOk ( common . isVariableDeclaration ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isInheritanceSpecifier' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'InheritanceSpecifier' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'InheritanceSpecifierBLABLA' }
t . ok ( common . isInheritanceSpecifier ( node1 ) , 'is exact match should work' )
t . notOk ( common . isInheritanceSpecifier ( node2 ) , 'different node should not work' )
t . notOk ( common . isInheritanceSpecifier ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isAssignment' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'Assignment' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'AssignmentBLABLA' }
t . ok ( common . isAssignment ( node1 ) , 'is exact match should work' )
t . notOk ( common . isAssignment ( node2 ) , 'different node should not work' )
t . notOk ( common . isAssignment ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isContractDefinition' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'ContractDefinition' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'ContractDefinitionBLABLA' }
t . ok ( common . isContractDefinition ( node1 ) , 'is exact match should work' )
t . notOk ( common . isContractDefinition ( node2 ) , 'different node should not work' )
t . notOk ( common . isContractDefinition ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isInlineAssembly' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'InlineAssembly' }
var node2 = { name : 'MemberAccess' }
var node3 = { name : 'InlineAssemblyBLABLA' }
t . ok ( common . isInlineAssembly ( node1 ) , 'is exact match should work' )
t . notOk ( common . isInlineAssembly ( node2 ) , 'different node should not work' )
t . notOk ( common . isInlineAssembly ( node3 ) , 'substring should not work' )
} )
test ( 'staticAnalysisCommon.isLoop' , function ( t ) {
t . plan ( 3 )
var node1 = {
'children' :
[
{
'attributes' :
{
'assignments' :
[
21
]
} ,
'children' :
[
{
'attributes' :
{
'constant' : false ,
'name' : 'i' ,
'scope' : 39 ,
'stateVariable' : false ,
'storageLocation' : 'default' ,
'type' : 'uint256' ,
'value' : null ,
'visibility' : 'internal'
} ,
'children' :
[
{
'attributes' :
{
'name' : 'uint' ,
'type' : 'uint256'
} ,
'id' : 20 ,
'name' : 'ElementaryTypeName' ,
'src' : '207:4:0'
}
] ,
'id' : 21 ,
'name' : 'VariableDeclaration' ,
'src' : '207:6:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 17 ,
'type' : 'uint256' ,
'value' : 'index'
} ,
'id' : 22 ,
'name' : 'Identifier' ,
'src' : '216:5:0'
}
] ,
'id' : 23 ,
'name' : 'VariableDeclarationStatement' ,
'src' : '207:14:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 24 ,
'name' : 'Identifier' ,
'src' : '223:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 25 ,
'name' : 'Literal' ,
'src' : '227:2:0'
}
] ,
'id' : 26 ,
'name' : 'BinaryOperation' ,
'src' : '223:6:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 27 ,
'name' : 'Identifier' ,
'src' : '231:1:0'
}
] ,
'id' : 28 ,
'name' : 'UnaryOperation' ,
'src' : '231:3:0'
}
] ,
'id' : 29 ,
'name' : 'ExpressionStatement' ,
'src' : '231:3:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 30 ,
'name' : 'Identifier' ,
'src' : '250:5:0'
}
] ,
'id' : 32 ,
'name' : 'MemberAccess' ,
'src' : '250:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 21 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 33 ,
'name' : 'Identifier' ,
'src' : '261:1:0'
}
] ,
'id' : 34 ,
'name' : 'FunctionCall' ,
'src' : '250:13:0'
}
] ,
'id' : 35 ,
'name' : 'ExpressionStatement' ,
'src' : '250:13:0'
}
] ,
'id' : 36 ,
'name' : 'Block' ,
'src' : '236:38:0'
}
] ,
'id' : 37 ,
'name' : 'ForStatement' ,
'src' : '202:72:0'
}
var node2 = {
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 82 ,
'name' : 'Identifier' ,
'src' : '592:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 83 ,
'name' : 'Literal' ,
'src' : '596:2:0'
}
] ,
'id' : 84 ,
'name' : 'BinaryOperation' ,
'src' : '592:6:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 72 ,
'name' : 'Identifier' ,
'src' : '544:5:0'
}
] ,
'id' : 74 ,
'name' : 'MemberAccess' ,
'src' : '544:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 75 ,
'name' : 'Identifier' ,
'src' : '555:1:0'
}
] ,
'id' : 76 ,
'name' : 'FunctionCall' ,
'src' : '544:13:0'
}
] ,
'id' : 77 ,
'name' : 'ExpressionStatement' ,
'src' : '544:13:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 69 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 78 ,
'name' : 'Identifier' ,
'src' : '571:1:0'
}
] ,
'id' : 79 ,
'name' : 'UnaryOperation' ,
'src' : '571:3:0'
}
] ,
'id' : 80 ,
'name' : 'ExpressionStatement' ,
'src' : '571:3:0'
}
] ,
'id' : 81 ,
'name' : 'Block' ,
'src' : '530:55:0'
}
] ,
'id' : 85 ,
'name' : 'DoWhileStatement' ,
'src' : '528:72:0'
}
var node3 = {
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'commonType' :
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '<' ,
'type' : 'bool'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 48 ,
'name' : 'Identifier' ,
'src' : '372:1:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'hexvalue' : '3130' ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : true ,
'lValueRequested' : false ,
'subdenomination' : null ,
'token' : 'number' ,
'type' : 'int_const 10' ,
'value' : '10'
} ,
'id' : 49 ,
'name' : 'Literal' ,
'src' : '376:2:0'
}
] ,
'id' : 50 ,
'name' : 'BinaryOperation' ,
'src' : '372:6:0'
} ,
{
'children' :
[
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' :
[
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' :
[
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'member_name' : 'push' ,
'referencedDeclaration' : null ,
'type' : 'function (uint256) returns (uint256)'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 4 ,
'type' : 'uint256[] storage ref' ,
'value' : 'array'
} ,
'id' : 51 ,
'name' : 'Identifier' ,
'src' : '394:5:0'
}
] ,
'id' : 53 ,
'name' : 'MemberAccess' ,
'src' : '394:10:0'
} ,
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 54 ,
'name' : 'Identifier' ,
'src' : '405:1:0'
}
] ,
'id' : 55 ,
'name' : 'FunctionCall' ,
'src' : '394:13:0'
}
] ,
'id' : 56 ,
'name' : 'ExpressionStatement' ,
'src' : '394:13:0'
} ,
{
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'lValueRequested' : false ,
'operator' : '++' ,
'prefix' : false ,
'type' : 'uint256'
} ,
'children' :
[
{
'attributes' :
{
'argumentTypes' : null ,
'overloadedDeclarations' :
[
null
] ,
'referencedDeclaration' : 45 ,
'type' : 'uint256' ,
'value' : 'i'
} ,
'id' : 57 ,
'name' : 'Identifier' ,
'src' : '421:1:0'
}
] ,
'id' : 58 ,
'name' : 'UnaryOperation' ,
'src' : '421:3:0'
}
] ,
'id' : 59 ,
'name' : 'ExpressionStatement' ,
'src' : '421:3:0'
}
] ,
'id' : 60 ,
'name' : 'Block' ,
'src' : '380:55:0'
}
] ,
'id' : 61 ,
'name' : 'WhileStatement' ,
'src' : '365:70:0'
}
t . equal ( common . isLoop ( node1 ) , true )
t . equal ( common . isLoop ( node2 ) , true )
t . equal ( common . isLoop ( node3 ) , true )
} )
// #################### Complex Node Identification
test ( 'staticAnalysisCommon.isBuiltinFunctionCall' , function ( t ) {
t . plan ( 2 )
var selfdestruct = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (address)' ,
'value' : 'selfdestruct'
} ,
'name' : 'Identifier'
} ,
{
'attributes' : {
'type' : 'address' ,
'value' : 'a'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'FunctionCall'
}
var localCall = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'name' : 'Identifier'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'FunctionCall'
}
t . ok ( common . isBuiltinFunctionCall ( selfdestruct ) , 'selfdestruct is builtin' )
t . notOk ( common . isBuiltinFunctionCall ( localCall ) , 'local call is not builtin' )
} )
test ( 'staticAnalysisCommon.isStorageVariableDeclaration' , function ( t ) {
t . plan ( 3 )
var node1 = {
'attributes' : {
'name' : 'x' ,
'type' : 'struct Ballot.Voter storage pointer'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'id' : 43 ,
'name' : 'UserDefinedTypeName' ,
'src' : '604:5:0'
}
] ,
'id' : 44 ,
'name' : 'VariableDeclaration' ,
'src' : '604:15:0'
}
var node2 = {
'attributes' : {
'name' : 'voters' ,
'type' : 'mapping(address => struct Ballot.Voter storage ref)'
} ,
'children' : [
{
'children' : [
{
'attributes' : {
'name' : 'address'
} ,
'id' : 16 ,
'name' : 'ElementaryTypeName' ,
'src' : '235:7:0'
} ,
{
'attributes' : {
'name' : 'Voter'
} ,
'id' : 17 ,
'name' : 'UserDefinedTypeName' ,
'src' : '246:5:0'
}
] ,
'id' : 18 ,
'name' : 'Mapping' ,
'src' : '227:25:0'
}
] ,
'id' : 19 ,
'name' : 'VariableDeclaration' ,
'src' : '227:32:0'
}
var node3 = {
'attributes' : {
'name' : 'voters' ,
'type' : 'bytes32'
} ,
'children' : [
{
'attributes' : {
'name' : 'bytes'
} ,
'id' : 16 ,
'name' : 'ElementaryTypeName' ,
'src' : '235:7:0'
}
] ,
'id' : 19 ,
'name' : 'VariableDeclaration' ,
'src' : '227:32:0'
}
t . ok ( common . isStorageVariableDeclaration ( node1 ) , 'struct storage pointer param is storage' )
t . ok ( common . isStorageVariableDeclaration ( node2 ) , 'struct storage pointer mapping param is storage' )
t . notOk ( common . isStorageVariableDeclaration ( node3 ) , 'bytes is not storage' )
} )
test ( 'staticAnalysisCommon.isInteraction' , function ( t ) {
t . plan ( 6 )
var sendAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'd' , type : 'address' } } ] , attributes : { value : 'send' , type : 'function (uint256) returns (bool)' } }
var callAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'f' , type : 'address' } } ] , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
var callcodeAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'f' , type : 'address' } } ] , attributes : { member _name : 'callcode' , type : 'function () payable returns (bool)' } }
var delegatecallAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'g' , type : 'address' } } ] , attributes : { member _name : 'delegatecall' , type : 'function () returns (bool)' } }
var nodeExtDir = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
var nodeNot = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
t . ok ( common . isInteraction ( sendAst ) , 'send is interaction' )
t . ok ( common . isInteraction ( callAst ) , 'call is interaction' )
t . ok ( common . isInteraction ( nodeExtDir ) , 'ExternalDirecCall is interaction' )
t . notOk ( common . isInteraction ( callcodeAst ) , 'callcode is not interaction' )
t . notOk ( common . isInteraction ( delegatecallAst ) , 'callcode is not interaction' )
t . notOk ( common . isInteraction ( nodeNot ) , 'local call is not interaction' )
} )
test ( 'staticAnalysisCommon.isEffect' , function ( t ) {
t . plan ( 5 )
var inlineAssembly = {
'children' : [
] ,
'id' : 21 ,
'name' : 'InlineAssembly' ,
'src' : '809:41:0'
}
var assignment = {
'attributes' : {
'operator' : '=' ,
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'mapping(address => uint256)' ,
'value' : 'c'
} ,
'id' : 61 ,
'name' : 'Identifier' ,
'src' : '873:1:0'
} ,
{
'attributes' : {
'member_name' : 'sender' ,
'type' : 'address'
} ,
'children' : [
{
'attributes' : {
'type' : 'msg' ,
'value' : 'msg'
} ,
'id' : 62 ,
'name' : 'Identifier' ,
'src' : '875:3:0'
}
] ,
'id' : 63 ,
'name' : 'MemberAccess' ,
'src' : '875:10:0'
}
] ,
'id' : 64 ,
'name' : 'IndexAccess' ,
'src' : '873:13:0'
} ,
{
'attributes' : {
'hexvalue' : '30' ,
'subdenomination' : null ,
'token' : null ,
'type' : 'int_const 0' ,
'value' : '0'
} ,
'id' : 65 ,
'name' : 'Literal' ,
'src' : '889:1:0'
}
] ,
'id' : 66 ,
'name' : 'Assignment' ,
'src' : '873:17:0'
}
var unaryOp = { name : 'UnaryOperation' , attributes : { operator : '++' } }
t . ok ( common . isEffect ( inlineAssembly ) , 'inline assembly is treated as effect' )
t . ok ( common . isEffect ( assignment ) , 'assignment is treated as effect' )
t . ok ( common . isEffect ( unaryOp ) , '++ is treated as effect' )
unaryOp . attributes . operator = '--'
t . ok ( common . isEffect ( unaryOp ) , '-- is treated as effect' )
t . notOk ( common . isEffect ( { name : 'MemberAccess' , attributes : { operator : '++' } } ) , 'MemberAccess not treated as effect' )
} )
test ( 'staticAnalysisCommon.isWriteOnStateVariable' , function ( t ) {
t . plan ( 3 )
var inlineAssembly = {
'children' : [
] ,
'id' : 21 ,
'name' : 'InlineAssembly' ,
'src' : '809:41:0'
}
var assignment = {
'attributes' : {
'operator' : '=' ,
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'uint256'
} ,
'children' : [
{
'attributes' : {
'type' : 'mapping(address => uint256)' ,
'value' : 'c'
} ,
'id' : 61 ,
'name' : 'Identifier' ,
'src' : '873:1:0'
} ,
{
'attributes' : {
'member_name' : 'sender' ,
'type' : 'address'
} ,
'children' : [
{
'attributes' : {
'type' : 'msg' ,
'value' : 'msg'
} ,
'id' : 62 ,
'name' : 'Identifier' ,
'src' : '875:3:0'
}
] ,
'id' : 63 ,
'name' : 'MemberAccess' ,
'src' : '875:10:0'
}
] ,
'id' : 64 ,
'name' : 'IndexAccess' ,
'src' : '873:13:0'
} ,
{
'attributes' : {
'hexvalue' : '30' ,
'subdenomination' : null ,
'token' : null ,
'type' : 'int_const 0' ,
'value' : '0'
} ,
'id' : 65 ,
'name' : 'Literal' ,
'src' : '889:1:0'
}
] ,
'id' : 66 ,
'name' : 'Assignment' ,
'src' : '873:17:0'
}
var node1 = {
'attributes' : {
'name' : 'x' ,
'type' : 'struct Ballot.Voter storage pointer'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
var node2 = {
'attributes' : {
'name' : 'y' ,
'type' : 'uint'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
var node3 = {
'attributes' : {
'name' : 'xx' ,
'type' : 'uint'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
t . ok ( common . isWriteOnStateVariable ( inlineAssembly , [ node1 , node2 , node3 ] ) , 'inline Assembly is write on state' )
t . notOk ( common . isWriteOnStateVariable ( assignment , [ node1 , node2 , node3 ] ) , 'assignment on non state is not write on state' )
node3 . attributes . name = 'c'
t . ok ( common . isWriteOnStateVariable ( assignment , [ node1 , node2 , node3 ] ) , 'assignment on state is not write on state' )
} )
test ( 'staticAnalysisCommon.isStateVariable' , function ( t ) {
t . plan ( 3 )
var node1 = {
'attributes' : {
'name' : 'x' ,
'type' : 'struct Ballot.Voter storage pointer'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
var node2 = {
'attributes' : {
'name' : 'y' ,
'type' : 'uint'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
var node3 = {
'attributes' : {
'name' : 'xx' ,
'type' : 'uint'
} ,
'children' : [
{
'attributes' : {
'name' : 'Voter'
} ,
'name' : 'UserDefinedTypeName'
}
] ,
'name' : 'VariableDeclaration'
}
t . ok ( common . isStateVariable ( 'x' , [ node1 , node2 ] ) , 'is contained' )
t . ok ( common . isStateVariable ( 'x' , [ node2 , node1 , node1 ] ) , 'is contained twice' )
t . notOk ( common . isStateVariable ( 'x' , [ node2 , node3 ] ) , 'not contained' )
} )
test ( 'staticAnalysisCommon.isConstantFunction' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'FunctionDefinition' , attributes : { constant : true } }
var node2 = { name : 'FunctionDefinition' , attributes : { constant : false } }
var node3 = { name : 'MemberAccess' , attributes : { constant : true } }
t . ok ( common . isConstantFunction ( node1 ) , 'should be const func definition' )
t . notOk ( common . isConstantFunction ( node2 ) , 'should not be const func definition' )
t . notOk ( common . isConstantFunction ( node3 ) , 'wrong node should not be const func definition' )
} )
test ( 'staticAnalysisCommon.isPlusPlusUnaryOperation' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'UnaryOperation' , attributes : { operator : '++' } }
var node2 = { name : 'UnaryOperation' , attributes : { operator : '--' } }
var node3 = { name : 'FunctionDefinition' , attributes : { operator : '++' } }
t . ok ( common . isPlusPlusUnaryOperation ( node1 ) , 'should be unary ++' )
t . notOk ( common . isPlusPlusUnaryOperation ( node2 ) , 'should not be unary ++' )
t . notOk ( common . isPlusPlusUnaryOperation ( node3 ) , 'wrong node should not be unary ++' )
} )
test ( 'staticAnalysisCommon.isMinusMinusUnaryOperation' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'UnaryOperation' , attributes : { operator : '--' } }
var node2 = { name : 'UnaryOperation' , attributes : { operator : '++' } }
var node3 = { name : 'FunctionDefinition' , attributes : { operator : '--' } }
t . ok ( common . isMinusMinusUnaryOperation ( node1 ) , 'should be unary --' )
t . notOk ( common . isMinusMinusUnaryOperation ( node2 ) , 'should not be unary --' )
t . notOk ( common . isMinusMinusUnaryOperation ( node3 ) , 'wrong node should not be unary --' )
} )
test ( 'staticAnalysisCommon.isFullyImplementedContract' , function ( t ) {
t . plan ( 3 )
var node1 = { name : 'ContractDefinition' , attributes : { fullyImplemented : true } }
var node2 = { name : 'ContractDefinition' , attributes : { fullyImplemented : false } }
var node3 = { name : 'FunctionDefinition' , attributes : { operator : '--' } }
t . ok ( common . isFullyImplementedContract ( node1 ) , 'should be fully implemented contract' )
t . notOk ( common . isFullyImplementedContract ( node2 ) , 'should not be fully implemented contract' )
t . notOk ( common . isFullyImplementedContract ( node3 ) , 'wrong node should not be fully implemented contract' )
} )
test ( 'staticAnalysisCommon.isCallToNonConstLocalFunction' , function ( t ) {
t . plan ( 2 )
var node1 = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'name' : 'Identifier'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'FunctionCall'
}
t . ok ( common . isCallToNonConstLocalFunction ( node1 ) , 'should be call to non const Local func' )
node1 . children [ 0 ] . attributes . type = 'function (struct Ballot.Voter storage pointer) constant payable (uint256)'
t . notok ( common . isCallToNonConstLocalFunction ( node1 ) , 'should no longer be call to non const Local func' )
} )
test ( 'staticAnalysisCommon.isExternalDirectCall' , function ( t ) {
t . plan ( 5 )
var node = {
attributes : {
member _name : 'info' ,
type : 'function () payable external returns (uint256)'
} ,
children : [
{
attributes : {
type : 'contract InfoFeed' ,
value : 'f'
} ,
id : 30 ,
name : 'Identifier' ,
src : '405:1:0'
}
] ,
id : 32 ,
name : 'MemberAccess' ,
src : '405:6:0'
}
var node2 = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
t . ok ( common . isExternalDirectCall ( node ) , 'f.info() should be external direct call' )
t . notOk ( common . isExternalDirectCall ( node2 ) , 'local call is not an exernal call' )
} )
test ( 'staticAnalysisCommon.isNowAccess' , function ( t ) {
t . plan ( 3 )
var node = { name : 'Identifier' , attributes : { value : 'now' , type : 'uint256' } }
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . ok ( common . isNowAccess ( node ) , 'is now used should work' )
} )
test ( 'staticAnalysisCommon.isBlockTimestampAccess' , function ( t ) {
t . plan ( 3 )
var node = { name : 'MemberAccess' , children : [ { attributes : { value : 'block' , type : 'block' } } ] , attributes : { value : 'timestamp' , type : 'uint256' } }
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . ok ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should work' )
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
} )
test ( 'staticAnalysisCommon.isBlockBlockhashAccess' , function ( t ) {
t . plan ( 4 )
var node = {
'attributes' : {
'member_name' : 'blockhash' ,
'type' : 'function (uint256) returns (bytes32)'
} ,
'children' : [
{
'attributes' : {
'type' : 'block' ,
'value' : 'block'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . ok ( common . isBlockBlockHashAccess ( node ) , 'blockhash should work' ) // todo:
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
} )
test ( 'staticAnalysisCommon.isThisLocalCall' , function ( t ) {
t . plan ( 3 )
var node = { name : 'MemberAccess' , children : [ { attributes : { value : 'this' , type : 'contract test' } } ] , attributes : { value : 'b' , type : 'function (bytes32,address) returns (bool)' } }
t . ok ( common . isThisLocalCall ( node ) , 'is this.local_method() used should work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
} )
test ( 'staticAnalysisCommon.isSuperLocalCall' , function ( t ) {
t . plan ( 4 )
var node = {
'attributes' : {
'member_name' : 'duper' ,
'type' : 'function ()'
} ,
'children' : [
{
'attributes' : {
'type' : 'contract super a' ,
'value' : 'super'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . ok ( common . isSuperLocalCall ( node ) , 'is super.local_method() used should work' )
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
} )
test ( 'staticAnalysisCommon.isLibraryCall' , function ( t ) {
t . plan ( 5 )
var node = {
'attributes' : {
'member_name' : 'insert' ,
'type' : 'function (struct Set.Data storage pointer,uint256) returns (bool)'
} ,
'children' : [
{
'attributes' : {
'type' : 'type(library Set)' ,
'value' : 'Set'
} ,
'name' : 'Identifier'
}
] ,
'name' : 'MemberAccess'
}
t . ok ( common . isLibraryCall ( node ) , 'is lib call should not work' )
t . notOk ( common . isSuperLocalCall ( node ) , 'is super.local_method() used should not work' )
t . notOk ( common . isThisLocalCall ( node ) , 'is this.local_method() used should not work' )
t . notOk ( common . isBlockTimestampAccess ( node ) , 'is block.timestamp used should not work' )
t . notOk ( common . isNowAccess ( node ) , 'is now used should not work' )
} )
test ( 'staticAnalysisCommon.isLocalCall' , function ( t ) {
t . plan ( 5 )
var node1 = {
'attributes' : {
'type' : 'tuple()' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'type' : 'function (struct Ballot.Voter storage pointer)' ,
'value' : 'bli'
} ,
'id' : 37 ,
'name' : 'Identifier' ,
'src' : '540:3:0'
} ,
{
'attributes' : {
'type' : 'struct Ballot.Voter storage pointer' ,
'value' : 'x'
} ,
'id' : 38 ,
'name' : 'Identifier' ,
'src' : '544:1:0'
}
] ,
'id' : 39 ,
'name' : 'FunctionCall' ,
'src' : '540:6:0'
}
t . ok ( common . isLocalCall ( node1 ) , 'isLocalCall' )
t . notOk ( common . isLowLevelCall ( node1 ) , 'is not low level call' )
t . notOk ( common . isExternalDirectCall ( node1 ) , 'is not external direct call' )
t . notOk ( common . isEffect ( node1 ) , 'is not effect' )
t . notOk ( common . isInteraction ( node1 ) , 'is not interaction' )
} )
test ( 'staticAnalysisCommon.isLowLevelCall' , function ( t ) {
t . plan ( 6 )
var sendAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'd' , type : 'address' } } ] , attributes : { value : 'send' , type : 'function (uint256) returns (bool)' } }
var callAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'f' , type : 'address' } } ] , attributes : { member _name : 'call' , type : 'function () payable returns (bool)' } }
var callcodeAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'f' , type : 'address' } } ] , attributes : { member _name : 'callcode' , type : 'function () payable returns (bool)' } }
var delegatecallAst = { name : 'MemberAccess' , children : [ { attributes : { value : 'g' , type : 'address' } } ] , attributes : { member _name : 'delegatecall' , type : 'function () returns (bool)' } }
t . ok ( common . isLowLevelSendInst ( sendAst ) && common . isLowLevelCall ( sendAst ) , 'send is llc should work' )
t . ok ( common . isLowLevelCallInst ( callAst ) && common . isLowLevelCall ( callAst ) , 'call is llc should work' )
t . notOk ( common . isLowLevelCallInst ( callcodeAst ) , 'callcode is not call' )
t . ok ( common . isLowLevelCallcodeInst ( callcodeAst ) && common . isLowLevelCall ( callcodeAst ) , 'callcode is llc should work' )
t . notOk ( common . isLowLevelCallcodeInst ( callAst ) , 'call is not callcode' )
t . ok ( common . isLowLevelDelegatecallInst ( delegatecallAst ) && common . isLowLevelCall ( delegatecallAst ) , 'delegatecall is llc should work' )
} )
test ( 'staticAnalysisCommon: Call of parameter function' , function ( t ) {
t . plan ( 7 )
var node1 = {
'attributes' : {
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' : [
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'argumentTypes' : [
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 25 ,
'type' : 'function (uint256,uint256) pure returns (uint256)' ,
'value' : 'f'
} ,
'id' : 34 ,
'name' : 'Identifier' ,
'src' : '267:1:0'
} ,
{
'attributes' : {
'argumentTypes' : null ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 27 ,
'type' : 'uint256' ,
'value' : 'x'
} ,
'id' : 35 ,
'name' : 'Identifier' ,
'src' : '269:1:0'
} ,
{
'attributes' : {
'argumentTypes' : null ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 29 ,
'type' : 'uint256' ,
'value' : 'y'
} ,
'id' : 36 ,
'name' : 'Identifier' ,
'src' : '272:1:0'
}
] ,
'id' : 37 ,
'name' : 'FunctionCall' ,
'src' : '267:7:0'
}
t . ok ( common . isLocalCall ( node1 ) , 'is not LocalCall' )
t . notOk ( common . isThisLocalCall ( node1 ) , 'is not this local call' )
t . notOk ( common . isSuperLocalCall ( node1 ) , 'is not super local call' )
t . notOk ( common . isExternalDirectCall ( node1 ) , 'is not ExternalDirectCall' )
t . notOk ( common . isLibraryCall ( node1 ) , 'is not LibraryCall' )
t . equals ( common . getFunctionCallType ( node1 ) , 'function (uint256,uint256) pure returns (uint256)' , 'Extracts right type' )
t . equals ( common . getFunctionCallTypeParameterType ( node1 ) , 'uint256,uint256' , 'Extracts param right type' )
} )
test ( 'staticAnalysisCommon: function call with of function with function parameter' , function ( t ) {
t . plan ( 2 )
var node1 = {
'attributes' : {
'argumentTypes' : null ,
'isConstant' : false ,
'isLValue' : false ,
'isPure' : false ,
'isStructConstructorCall' : false ,
'lValueRequested' : false ,
'names' : [
null
] ,
'type' : 'uint256' ,
'type_conversion' : false
} ,
'children' : [
{
'attributes' : {
'argumentTypes' : [
{
'typeIdentifier' : 't_function_internal_pure$_t_uint256_$_t_uint256_$returns$_t_uint256_$' ,
'typeString' : 'function (uint256,uint256) pure returns (uint256)'
} ,
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
} ,
{
'typeIdentifier' : 't_uint256' ,
'typeString' : 'uint256'
}
] ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 40 ,
'type' : 'function (function (uint256,uint256) pure returns (uint256),uint256,uint256) pure returns (uint256)' ,
'value' : 'eval'
} ,
'id' : 49 ,
'name' : 'Identifier' ,
'src' : '361:4:0'
} ,
{
'attributes' : {
'argumentTypes' : null ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 15 ,
'type' : 'function (uint256,uint256) pure returns (uint256)' ,
'value' : 'plus'
} ,
'id' : 50 ,
'name' : 'Identifier' ,
'src' : '366:4:0'
} ,
{
'attributes' : {
'argumentTypes' : null ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 42 ,
'type' : 'uint256' ,
'value' : 'x'
} ,
'id' : 51 ,
'name' : 'Identifier' ,
'src' : '372:1:0'
} ,
{
'attributes' : {
'argumentTypes' : null ,
'overloadedDeclarations' : [
null
] ,
'referencedDeclaration' : 44 ,
'type' : 'uint256' ,
'value' : 'y'
} ,
'id' : 52 ,
'name' : 'Identifier' ,
'src' : '375:1:0'
}
] ,
'id' : 53 ,
'name' : 'FunctionCall' ,
'src' : '361:16:0'
}
t . equals ( common . getFunctionCallType ( node1 ) , 'function (function (uint256,uint256) pure returns (uint256),uint256,uint256) pure returns (uint256)' , 'Extracts right type' )
t . equals ( common . getFunctionCallTypeParameterType ( node1 ) , 'function (uint256,uint256) pure returns (uint256),uint256,uint256' , 'Extracts param right type' )
} )
test ( 'staticAnalysisCommon: require call' , function ( t ) {
t . plan ( 3 )
var node = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'isStructConstructorCall' : false , 'lValueRequested' : false , 'names' : [ null ] , 'type' : 'tuple()' , 'type_conversion' : false } , 'children' : [ { 'attributes' : { 'argumentTypes' : [ { 'typeIdentifier' : 't_bool' , 'typeString' : 'bool' } , { 'typeIdentifier' : 't_stringliteral_80efd193f332877914d93edb0b3ef5c6a7eecd00c6251c3fd7f146b60b40e6cd' , 'typeString' : 'literal_string \'fuu\'' } ] , 'overloadedDeclarations' : [ 90 , 91 ] , 'referencedDeclaration' : 91 , 'type' : 'function (bool,string memory) pure' , 'value' : 'require' } , 'id' : 50 , 'name' : 'Identifier' , 'src' : '462:7:0' } , { 'attributes' : { 'argumentTypes' : null , 'commonType' : { 'typeIdentifier' : 't_address' , 'typeString' : 'address' } , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'operator' : '==' , 'type' : 'bool' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'member_name' : 'sender' , 'referencedDeclaration' : null , 'type' : 'address' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 87 , 'type' : 'msg' , 'value' : 'msg' } , 'id' : 51 , 'name' : 'Identifier' , 'src' : '470:3:0' } ] , 'id' : 52 , 'name' : 'MemberAccess' , 'src' : '470:10:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 10 , 'type' : 'address' , 'value' : 'owner' } , 'id' : 53 , 'name' : 'Identifier' , 'src' : '484:5:0' } ] , 'id' : 54 , 'name' : 'BinaryOperation' , 'src' : '470:19:0' } , { 'attributes' : { 'argumentTypes' : null , 'hexvalue' : '667575' , 'isConstant' : false , 'isLValue' : false , 'isPure' : true , 'lValueRequested' : false , 'subdenomination' : null , 'token' : 'string' , 'type' : 'literal_string \'fuu\'' , 'value' : 'fuu' } , 'id' : 55 , 'name' : 'Literal' , 'src' : '491:5:0' } ] , 'id' : 56 , 'name' : 'FunctionCall' , 'src' : '462:35:0' }
t . equals ( common . isRequireCall ( node ) , true )
t . equals ( common . getFunctionCallType ( node ) , 'function (bool,string memory) pure' , 'Extracts right type' )
t . equals ( common . getFunctionCallTypeParameterType ( node ) , 'bool,string memory' , 'Extracts param right type' )
} )
test ( 'staticAnalysisCommon: isDeleteOfDynamicArray' , function ( t ) {
t . plan ( 2 )
var node = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'operator' : 'delete' , 'prefix' : true , 'type' : 'tuple()' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 4 , 'type' : 'uint256[] storage ref' , 'value' : 'users' } , 'id' : 58 , 'name' : 'Identifier' , 'src' : '514:5:0' } ] , 'id' : 59 , 'name' : 'UnaryOperation' , 'src' : '507:12:0' }
t . equals ( common . isDeleteOfDynamicArray ( node ) , true )
t . equals ( common . isDynamicArrayAccess ( node . children [ 0 ] ) , true , 'Extracts right type' )
} )
test ( 'staticAnalysisCommon: isAbiNamespaceCall' , function ( t ) {
t . plan ( 8 )
var node1 = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'isStructConstructorCall' : false , 'lValueRequested' : false , 'names' : [ null ] , 'type' : 'bytes memory' , 'type_conversion' : false } , 'children' : [ { 'attributes' : { 'argumentTypes' : [ { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } ] , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'member_name' : 'encode' , 'referencedDeclaration' : null , 'type' : 'function () pure returns (bytes memory)' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 64 , 'type' : 'abi' , 'value' : 'abi' } , 'id' : 26 , 'name' : 'Identifier' , 'src' : '245: 3:0' } ] , 'id' : 28 , 'name' : 'MemberAccess' , 'src' : '245:10:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 7 , 'type' : 'uint256' , 'value' : 'a' } , 'id' : 29 , 'name' : 'Identifier' , 'src' : '256:1:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 15 , 'type' : 'uint256' , 'value' : 'b' } , 'id' : 30 , 'name' : 'Identifier' , 'src' : '258:1:0' } ] , 'id' : 31 , 'name' : 'FunctionCall' , 'src' : '245:15:0' }
var node2 = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'isStructConstructorCall' : false , 'lValueRequested' : false , 'names' : [ null ] , 'type' : 'bytes memory' , 'type_conversion' : false } , 'children' : [ { 'attributes' : { 'argumentTypes' : [ { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } ] , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'member_name' : 'encodePacked' , 'referencedDeclaration' : null , 'type' : 'function () pure returns (bytes memory)' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 64 , 'type' : 'abi' , 'value' : 'abi' } , 'id' : 33 , 'name' : 'Identifier' , 'src' : '279:3:0' } ] , 'id' : 35 , 'name' : 'MemberAccess' , 'src' : '279:16:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 7 , 'type' : 'uint256' , 'value' : 'a' } , 'id' : 36 , 'name' : 'Identifier' , 'src' : '296:1:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 15 , 'type' : 'uint256' , 'value' : 'b' } , 'id' : 37 , 'name' : 'Identifier' , 'src' : '298:1:0' } ] , 'id' : 38 , 'name' : 'FunctionCall' , 'src' : '279:21:0' }
var node3 = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'isStructConstructorCall' : false , 'lValueRequested' : false , 'names' : [ null ] , 'type' : 'bytes memory' , 'type_conversion' : false } , 'children' : [ { 'attributes' : { 'argumentTypes' : [ { 'typeIdentifier' : 't_bytes4' , 'typeString' : 'bytes4' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } ] , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'member_name' : 'encodeWithSelector' , 'referencedDeclaration' : null , 'type' : 'function (bytes4) pure returns (bytes memory)' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 64 , 'type' : 'abi' , 'value' : 'abi' } , 'id' : 40 , 'name' : 'Identifier' , 'src' : '319:3:0' } ] , 'id' : 42 , 'name' : 'MemberAccess' , 'src' : '319:22:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 19 , 'type' : 'bytes4' , 'value' : 'selector' } , 'id' : 43 , 'name' : 'Identifier' , 'src' : '342:8:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 7 , 'type' : 'uint256' , 'value' : 'a' } , 'id' : 44 , 'name' : 'Identifier' , 'src' : '352:1:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 15 , 'type' : 'uint256' , 'value' : 'b' } , 'id' : 45 , 'name' : 'Identifier' , 'src' : '355:1:0' } ] , 'id' : 46 , 'name' : 'FunctionCall' , 'src' : '319:38:0' }
var node4 = { 'attributes' : { 'argumentTypes' : null , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'isStructConstructorCall' : false , 'lValueRequested' : false , 'names' : [ null ] , 'type' : 'bytes memory' , 'type_conversion' : false } , 'children' : [ { 'attributes' : { 'argumentTypes' : [ { 'typeIdentifier' : 't_string_memory_ptr' , 'typeString' : 'string memory' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } , { 'typeIdentifier' : 't_uint256' , 'typeString' : 'uint256' } ] , 'isConstant' : false , 'isLValue' : false , 'isPure' : false , 'lValueRequested' : false , 'member_name' : 'encodeWithSignature' , 'referencedDeclaration' : null , 'type' : 'function (string memory) pure returns (bytes memory)' } , 'children' : [ { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 64 , 'type' : 'abi' , 'value' : 'abi' } , 'id' : 48 , 'name' : 'Identifier' , 'src' : '367:3:0' } ] , 'id' : 50 , 'name' : 'MemberAccess' , 'src' : '367:23:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 11 , 'type' : 'string memory' , 'value' : 'sig' } , 'id' : 51 , 'name' : 'Identifier' , 'src' : '391:3:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 7 , 'type' : 'uint256' , 'value' : 'a' } , 'id' : 52 , 'name' : 'Identifier' , 'src' : '396:1:0' } , { 'attributes' : { 'argumentTypes' : null , 'overloadedDeclarations' : [ null ] , 'referencedDeclaration' : 15 , 'type' : 'uint256' , 'value' : 'b' } , 'id' : 53 , 'name' : 'Identifier' , 'src' : '399:1:0' } ] , 'id' : 54 , 'name' : 'FunctionCall' , 'src' : '367:34:0' }
t . equals ( common . isAbiNamespaceCall ( node1 ) , true , 'encode abi' )
t . equals ( common . isAbiNamespaceCall ( node2 ) , true , 'encodePacked abi' )
t . equals ( common . isAbiNamespaceCall ( node3 ) , true , 'encodeWithSelector abi' )
t . equals ( common . isAbiNamespaceCall ( node4 ) , true , 'encodeWithSignature abi' )
t . equals ( common . isBuiltinFunctionCall ( node1 ) , true , 'encode Builtin' )
t . equals ( common . isBuiltinFunctionCall ( node2 ) , true , 'encodePacked Builtin' )
t . equals ( common . isBuiltinFunctionCall ( node3 ) , true , 'encodeWithSelector Builtin' )
t . equals ( common . isBuiltinFunctionCall ( node4 ) , true , 'encodeWithSignature Builtin' )
} )