Skip to content

Commit

Permalink
fix: cast to pure parameters types
Browse files Browse the repository at this point in the history
  • Loading branch information
agusduha committed May 17, 2024
1 parent f95ac6d commit 3dfa955
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 4 deletions.
9 changes: 9 additions & 0 deletions solidity/contracts/ContractTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ contract ContractTest is IContractTest {
_string = 'test';
}

function internalPureVirtualFunctionWithStruct(MyStruct memory _myStruct)
internal
pure
virtual
returns (MyStruct memory)
{
return _myStruct;
}

function testFunc(uint256) public pure returns (bool) {
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions solidity/contracts/utils/ContractJ.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ contract ContractJ {
myUserTypeVariable = add(a, b);
return myUserTypeVariable;
}

function internalPureAdd(MyUserType a, MyUserType b) internal pure virtual returns (MyUserType) {
return MyUserType.wrap(MyUserType.unwrap(a) + MyUserType.unwrap(b));
}
}
18 changes: 18 additions & 0 deletions solidity/test/ContractTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -428,4 +428,22 @@ contract E2EMockContractTest_Mock_call_Internal_Func is CommonE2EBase {
assertEq(_res2, 11);
assertEq(_res3, 'test');
}

function test_MockCall_InternalPureVirtualFunctionWithStruct() public {
IContractTest.MyStruct memory _myStruct = IContractTest.MyStruct(30, 'test');
IContractTest.MyStruct memory _myStruct2 = IContractTest.MyStruct(40, 'forty');

// Expect calls to internal functions
_contractTest.expectCall_internalPureVirtualFunctionWithStruct(_myStruct);
_contractTest.expectCall_internalPureVirtualFunctionWithStruct(_myStruct2);

_contractTest.mock_call_internalPureVirtualFunctionWithStruct(_myStruct, IContractTest.MyStruct(50, 'fifty'));
IContractTest.MyStruct memory _res = _contractTest.call_internalPureVirtualFunctionWithStruct(_myStruct);
assertEq(_res.value, 50);
assertEq(_res.name, 'fifty');

_res = _contractTest.call_internalPureVirtualFunctionWithStruct(_myStruct2);
assertEq(_res.value, 40);
assertEq(_res.name, 'forty');
}
}
5 changes: 5 additions & 0 deletions solidity/test/utils/ContractJ.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,9 @@ contract UnitMockContractJ is Test, SmockHelper {
_contractTest.mock_call_externalAdd(_myUserTypeA, _myUserTypeB, _myUserTypeResult);
assertEq(ContractJ.MyUserType.unwrap(_contractTest.externalAdd(_myUserTypeA, _myUserTypeB)), _result);
}

function test_InternalPureAdd() public {
_contractTest.mock_call_internalPureAdd(_myUserTypeA, _myUserTypeB, _myUserTypeResult);
assertEq(ContractJ.MyUserType.unwrap(_contractTest.call_internalPureAdd(_myUserTypeA, _myUserTypeB)), _result);
}
}
4 changes: 2 additions & 2 deletions src/templates/partials/internal-function.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ function expectCall_{{functionName}}({{#if inputs}}{{inputs}}{{/if}}) public {

{{#if isPure}}

function _{{functionName}}CastToPure(function({{#each inputTypes}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}) internal view {{#if outputs}}returns ({{explicitOutputTypes}}){{/if}} fnIn)
function _{{functionName}}CastToPure(function({{inputs}}) internal view {{#if outputs}}returns ({{explicitOutputTypes}}){{/if}} fnIn)
internal
pure
returns (function({{#each inputTypes}}{{this}}{{#unless @last}}, {{/unless}}{{/each}}) internal pure {{#if outputs}}returns ({{explicitOutputTypes}}){{/if}} fnOut)
returns (function({{inputs}}) internal pure {{#if outputs}}returns ({{explicitOutputTypes}}){{/if}} fnOut)
{
assembly {
fnOut := fnIn
Expand Down
3 changes: 2 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export function extractParameters(parameters: VariableDeclaration[]): {
const parameterNames = parameters.map((parameter, index) => parameter.name || `_param${index}`);

const parameterTypes = parameters.map((parameter) => {
// If the parameter is a user-defined value type, we need to get the underlying type
if (parameter.vType instanceof UserDefinedTypeName) {
if (parameter.vType.vReferencedDeclaration instanceof UserDefinedValueTypeDefinition) {
return sanitizeParameterType(parameter.vType.vReferencedDeclaration.underlyingType.typeString);
Expand Down Expand Up @@ -170,7 +171,7 @@ export function extractReturnParameters(returnParameters: VariableDeclaration[])
const returnParameterTypes = returnParameters.map((parameter) => sanitizeParameterType(parameter.typeString));
const returnParameterNames = returnParameters.map((parameter, index) => parameter.name || `_returnParam${index}`);
const returnExplicitParameterTypes = returnParameters.map((parameter) =>
explicitTypeStorageLocation(sanitizeParameterType(parameter.typeString)),
sanitizeParameterType(explicitTypeStorageLocation(parameter.typeString)),
);

return {
Expand Down
40 changes: 39 additions & 1 deletion test/unit/context/internalFunctionContext.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { expect } from 'chai';
import { DataLocation, FunctionStateMutability, FunctionVisibility, UserDefinedTypeName, UserDefinedValueTypeDefinition } from 'solc-typed-ast';
import { mockElementaryTypeName, mockFunctionDefinition, mockParameterList, mockVariableDeclaration } from '../../mocks';
import {
mockElementaryTypeName,
mockFunctionDefinition,
mockParameterList,
mockUserDefinedTypeName,
mockVariableDeclaration,
} from '../../mocks';
import { internalFunctionContext } from '../../../src/context';

describe('internalFunctionContext', () => {
Expand Down Expand Up @@ -260,4 +266,36 @@ describe('internalFunctionContext', () => {
isPure: false,
});
});

it('process structs return parameters', () => {
const parameters = [
mockVariableDeclaration({
typeString: 'struct MyStruct',
vType: mockUserDefinedTypeName({
typeString: 'struct MyStruct',
vReferencedDeclaration: mockUserDefinedTypeName({
children: [mockVariableDeclaration({ name: 'field1', typeString: 'uint256' })],
}),
}),
}),
];
const node = mockFunctionDefinition({ ...defaultAttributes, vReturnParameters: mockParameterList({ vParameters: parameters }) });
const context = internalFunctionContext(node);

expect(context).to.eql({
functionName: 'testInternalFunction',
signature: 'testInternalFunction()',
parameters: 'MyStruct _returnParam0',
inputs: '',
outputs: 'MyStruct _returnParam0',
inputNames: [],
outputNames: ['_returnParam0'],
inputTypes: [],
outputTypes: ['MyStruct'],
implemented: true,
isView: false,
explicitOutputTypes: ['MyStruct memory'],
isPure: false,
});
});
});

0 comments on commit 3dfa955

Please sign in to comment.