Skip to content

Commit 6567a8d

Browse files
committed
don't use fully qualified names for types if not needed
1 parent 0458e7b commit 6567a8d

File tree

5 files changed

+110
-50
lines changed

5 files changed

+110
-50
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.3.9
4+
5+
- Do not use fully qualified names for types in generated code unless necessary.
6+
37
## 0.3.8
48

59
- Support custom `paths.root` in Hardhat config.

contracts/Test.sol

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,19 @@ contract HasReceiveFunction {
239239
import { Imported } from './Imported.sol';
240240

241241
contract ImportedChild is Imported {}
242+
243+
contract HasEnum {
244+
enum InheritedEnum {
245+
X
246+
}
247+
}
248+
249+
contract ParentHasEnum is HasEnum {
250+
function _getValue(InheritedEnum foo) internal pure returns (uint8) {
251+
return uint8(foo);
252+
}
253+
254+
function _getY(Types.Enum e) internal pure returns (uint8) {
255+
return uint8(e);
256+
}
257+
}

src/core.test.ts.md

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ Generated by [AVA](https://avajs.dev).
377377
378378
mapping(uint256 => S) internal $v_S;␊
379379
380-
mapping(uint256 => Foo.Z) internal $v_Foo_Z;␊
380+
mapping(uint256 => Z) internal $v_Z;␊
381381
382382
constructor() payable {␊
383383
}␊
@@ -406,7 +406,7 @@ Generated by [AVA](https://avajs.dev).
406406
return _x4;␊
407407
}␊
408408
409-
function $z() external view returns (Foo.Integer) {␊
409+
function $z() external view returns (Integer) {␊
410410
return z;␊
411411
}␊
412412
@@ -434,11 +434,11 @@ Generated by [AVA](https://avajs.dev).
434434
super._testClash($v_S[t]);␊
435435
}␊
436436
437-
function $_testClash_Foo_Z(uint256 t) external {␊
438-
super._testClash($v_Foo_Z[t]);␊
437+
function $_testClash_Z(uint256 t) external {␊
438+
super._testClash($v_Z[t]);␊
439439
}␊
440440
441-
function $_testUDVT(Foo.Integer i) external {␊
441+
function $_testUDVT(Integer i) external {␊
442442
super._testUDVT(i);␊
443443
}␊
444444
@@ -450,7 +450,7 @@ Generated by [AVA](https://avajs.dev).
450450
451451
mapping(uint256 => S) internal $v_S;␊
452452
453-
mapping(uint256 => Foo.Z) internal $v_Foo_Z;␊
453+
mapping(uint256 => Z) internal $v_Z;␊
454454
455455
constructor() payable {␊
456456
}␊
@@ -479,7 +479,7 @@ Generated by [AVA](https://avajs.dev).
479479
return _x4;␊
480480
}␊
481481
482-
function $z() external view returns (Foo.Integer) {␊
482+
function $z() external view returns (Integer) {␊
483483
return z;␊
484484
}␊
485485
@@ -511,11 +511,11 @@ Generated by [AVA](https://avajs.dev).
511511
super._testClash($v_S[t]);␊
512512
}␊
513513
514-
function $_testClash_Foo_Z(uint256 t) external {␊
515-
super._testClash($v_Foo_Z[t]);␊
514+
function $_testClash_Z(uint256 t) external {␊
515+
super._testClash($v_Z[t]);␊
516516
}␊
517517
518-
function $_testUDVT(Foo.Integer i) external {␊
518+
function $_testUDVT(Integer i) external {␊
519519
super._testUDVT(i);␊
520520
}␊
521521
@@ -604,7 +604,7 @@ Generated by [AVA](https://avajs.dev).
604604
constructor() payable {␊
605605
}␊
606606
607-
function $_testEnumType(Types.Enum e) external {␊
607+
function $_testEnumType(Enum e) external {␊
608608
super._testEnumType(e);␊
609609
}␊
610610
@@ -694,23 +694,23 @@ Generated by [AVA](https://avajs.dev).
694694
return var3[arg0];␊
695695
}␊
696696
697-
function $var4() external view returns (WithVars.Struct memory) {␊
697+
function $var4() external view returns (Struct memory) {␊
698698
return var4;␊
699699
}␊
700700
701-
function $var5() external view returns (WithVars.Struct[] memory) {␊
701+
function $var5() external view returns (Struct[] memory) {␊
702702
return var5;␊
703703
}␊
704704
705-
function $var6(uint256 arg0) external view returns (WithVars.Struct memory) {␊
705+
function $var6(uint256 arg0) external view returns (Struct memory) {␊
706706
return var6[arg0];␊
707707
}␊
708708
709-
function $var7(uint256 arg0, bool arg1) external view returns (WithVars.Struct memory) {␊
709+
function $var7(uint256 arg0, bool arg1) external view returns (Struct memory) {␊
710710
return var7[arg0][arg1];␊
711711
}␊
712712
713-
function $var8(uint256 arg0, bool arg1) external view returns (WithVars.Struct[] memory) {␊
713+
function $var8(uint256 arg0, bool arg1) external view returns (Struct[] memory) {␊
714714
return var8[arg0][arg1];␊
715715
}␊
716716
@@ -780,6 +780,32 @@ Generated by [AVA](https://avajs.dev).
780780
781781
receive() external payable {}␊
782782
}␊
783+
784+
contract $HasEnum is HasEnum {␊
785+
bytes32 public constant __hh_exposed_bytecode_marker = "hardhat-exposed";␊
786+
787+
constructor() payable {␊
788+
}␊
789+
790+
receive() external payable {}␊
791+
}␊
792+
793+
contract $ParentHasEnum is ParentHasEnum {␊
794+
bytes32 public constant __hh_exposed_bytecode_marker = "hardhat-exposed";␊
795+
796+
constructor() payable {␊
797+
}␊
798+
799+
function $_getValue(InheritedEnum foo) external pure returns (uint8 ret0) {␊
800+
(ret0) = super._getValue(foo);␊
801+
}␊
802+
803+
function $_getY(Types.Enum e) external pure returns (uint8 ret0) {␊
804+
(ret0) = super._getY(e);␊
805+
}␊
806+
807+
receive() external payable {}␊
808+
}␊
783809
`
784810

785811
## snapshot initializers

src/core.test.ts.snap

51 Bytes
Binary file not shown.

src/core.ts

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { formatLines, Lines, spaceBetween } from './utils/format-lines';
55
import type { Visibility, SourceUnit, ContractDefinition, FunctionDefinition, VariableDeclaration, StorageLocation, TypeDescriptions, TypeName, InheritanceSpecifier, ModifierInvocation, FunctionCall } from 'solidity-ast';
66
import type { FileContent, ProjectPathsConfig, ResolvedFile } from 'hardhat/types';
77
import type { ExposedConfig } from './config';
8+
import assert from 'assert';
89

910
export interface SolcOutput {
1011
sources: {
@@ -105,7 +106,7 @@ function getExposedContent(ast: SourceUnit, relativizePath: (p: string) => strin
105106

106107
const clashingFunctions: Record<string, number> = {};
107108
for (const fn of externalizableFunctions) {
108-
const id = getFunctionId(fn);
109+
const id = getFunctionId(fn, c, deref);
109110
clashingFunctions[id] ??= 0;
110111
clashingFunctions[id] += 1;
111112
}
@@ -121,13 +122,13 @@ function getExposedContent(ast: SourceUnit, relativizePath: (p: string) => strin
121122
[`bytes32 public constant __hh_exposed_bytecode_marker = "hardhat-exposed";\n`],
122123
spaceBetween(
123124
// slots for storage function parameters
124-
...getAllStorageArguments(externalizableFunctions).map(a => [
125+
...getAllStorageArguments(externalizableFunctions, c, deref).map(a => [
125126
`mapping(uint256 => ${a.storageType}) internal ${prefix}${a.storageVar};`,
126127
]),
127128
// events for internal returns
128129
...returnedEventFunctions.map(fn => {
129-
const evName = clashingEvents[fn.name] === 1 ? fn.name : getFunctionNameQualified(fn, false);
130-
const params = getFunctionReturnParameters(fn, null);
130+
const evName = clashingEvents[fn.name] === 1 ? fn.name : getFunctionNameQualified(fn, c, deref, false);
131+
const params = getFunctionReturnParameters(fn, c, deref, null);
131132
return [
132133
`event return${prefix}${evName}(${params.map(printArgument).join(', ')});`
133134
]
@@ -138,24 +139,24 @@ function getExposedContent(ast: SourceUnit, relativizePath: (p: string) => strin
138139
...externalizableVariables.map(v => [
139140
[
140141
'function',
141-
`${prefix}${v.name}(${getVarGetterArgs(v).map(printArgument).join(', ')})`,
142+
`${prefix}${v.name}(${getVarGetterArgs(v, c, deref).map(printArgument).join(', ')})`,
142143
'external',
143144
v.mutability === 'mutable' || (v.mutability === 'immutable' && !v.value) ? 'view' : 'pure',
144145
'returns',
145-
`(${getVarGetterReturnType(v)})`,
146+
`(${getVarGetterReturnType(v, c, deref)})`,
146147
'{'
147148
].join(' '),
148149
[
149-
`return ${isLibrary ? c.name + '.' : ''}${v.name}${getVarGetterArgs(v).map(a => `[${a.name}]`).join('')};`,
150+
`return ${isLibrary ? c.name + '.' : ''}${v.name}${getVarGetterArgs(v, c, deref).map(a => `[${a.name}]`).join('')};`,
150151
],
151152
'}',
152153
]),
153154
// external functions
154155
...externalizableFunctions.map(fn => {
155-
const fnName = clashingFunctions[getFunctionId(fn)] === 1 ? fn.name : getFunctionNameQualified(fn);
156-
const fnArgs = getFunctionArguments(fn);
157-
const fnRets = getFunctionReturnParameters(fn);
158-
const evName = isNonViewWithReturns(fn) && (clashingEvents[fn.name] === 1 ? fn.name : getFunctionNameQualified(fn, false));
156+
const fnName = clashingFunctions[getFunctionId(fn, c, deref)] === 1 ? fn.name : getFunctionNameQualified(fn, c, deref);
157+
const fnArgs = getFunctionArguments(fn, c, deref);
158+
const fnRets = getFunctionReturnParameters(fn, c, deref);
159+
const evName = isNonViewWithReturns(fn) && (clashingEvents[fn.name] === 1 ? fn.name : getFunctionNameQualified(fn, c, deref, false));
159160

160161
// function header
161162
const header = [
@@ -228,14 +229,14 @@ function areFunctionsFullyImplemented(contract: ContractDefinition, deref: ASTDe
228229
return abstractFunctionIds.size === 0;
229230
}
230231

231-
function getFunctionId(fn: FunctionDefinition): string {
232-
const storageArgs = new Set<Argument>(getStorageArguments(fn));
233-
const nonStorageArgs = getFunctionArguments(fn).filter(a => !storageArgs.has(a));
232+
function getFunctionId(fn: FunctionDefinition, context: ContractDefinition, deref: ASTDereferencer): string {
233+
const storageArgs = new Set<Argument>(getStorageArguments(fn, context, deref));
234+
const nonStorageArgs = getFunctionArguments(fn, context, deref).filter(a => !storageArgs.has(a));
234235
return fn.name + nonStorageArgs.map(a => a.type).join('');
235236
}
236237

237-
function getFunctionNameQualified(fn: FunctionDefinition, onlyStorage: boolean = true): string {
238-
return fn.name + (onlyStorage ? getStorageArguments(fn) : getFunctionArguments(fn))
238+
function getFunctionNameQualified(fn: FunctionDefinition, context: ContractDefinition, deref: ASTDereferencer, onlyStorage: boolean = true): string {
239+
return fn.name + (onlyStorage ? getStorageArguments(fn, context, deref) : getFunctionArguments(fn, context, deref))
239240
.map(arg => arg.storageType ?? arg.type)
240241
.map(type => type.replace(/ .*/,'').replace(/[^0-9a-zA-Z$_]+/g, '_')) // sanitize
241242
.join('_')
@@ -289,7 +290,7 @@ function makeConstructor(contract: ContractDefinition, deref: ASTDereferencer, i
289290
const args = [];
290291
for (const a of constructors.get(c.id)?.parameters.parameters ?? []) {
291292
const name = missingArguments.has(a.name) ? `${c.name}_${a.name}` : a.name;
292-
const type = getVarType(a, 'memory');
293+
const type = getVarType(a, c, deref, 'memory');
293294
missingArguments.set(name, type);
294295
args.push(name);
295296
}
@@ -390,55 +391,68 @@ interface Argument {
390391

391392
const printArgument = (arg: Argument) => `${arg.type} ${arg.name}`;
392393

393-
function getFunctionArguments(fnDef: FunctionDefinition): Argument[] {
394+
function getFunctionArguments(fnDef: FunctionDefinition, context: ContractDefinition, deref: ASTDereferencer): Argument[] {
394395
return fnDef.parameters.parameters.map((p, i) => {
395396
const name = p.name || `arg${i}`;
396397
if (p.storageLocation === 'storage') {
397-
const storageType = getVarType(p, null);
398+
const storageType = getVarType(p, context, deref, null);
398399
const storageVar = 'v_' + storageType.replace(/[^0-9a-zA-Z$_]+/g, '_');
399400
// The argument is an index to an array in storage.
400401
return { name, type: 'uint256', storageVar, storageType };
401402
} else {
402-
const type = getVarType(p, 'calldata');
403+
const type = getVarType(p, context, deref, 'calldata');
403404
return { name, type };
404405
}
405406
});
406407
}
407408

408-
function getStorageArguments(fn: FunctionDefinition): Required<Argument>[] {
409-
return getFunctionArguments(fn)
409+
function getStorageArguments(fn: FunctionDefinition, context: ContractDefinition, deref: ASTDereferencer): Required<Argument>[] {
410+
return getFunctionArguments(fn, context, deref)
410411
.filter((a): a is Required<Argument> => !!(a.storageVar && a.storageType));
411412
}
412413

413-
function getAllStorageArguments(fns: FunctionDefinition[]): Required<Argument>[] {
414+
function getAllStorageArguments(fns: FunctionDefinition[], context: ContractDefinition, deref: ASTDereferencer): Required<Argument>[] {
414415
return [
415416
...new Map(
416-
fns.flatMap(getStorageArguments).map(a => [a.storageVar, a]),
417+
fns.flatMap(fn => getStorageArguments(fn, context, deref)).map(a => [a.storageVar, a]),
417418
).values(),
418419
];
419420
}
420421

421-
function getFunctionReturnParameters(fnDef: FunctionDefinition, location: StorageLocation | null = 'memory'): Argument[] {
422+
function getFunctionReturnParameters(fnDef: FunctionDefinition, context: ContractDefinition, deref: ASTDereferencer, location: StorageLocation | null = 'memory'): Argument[] {
422423
return fnDef.returnParameters.parameters.map((p, i) => {
423424
const name = p.name || `ret${i}`;
424-
const type = getVarType(p, location);
425+
const type = getVarType(p, context, deref, location);
425426
return { name, type };
426427
});
427428
}
428429

429-
function getVarType(varDecl: VariableDeclaration, location: StorageLocation | null = varDecl.storageLocation): string {
430+
function getVarType(varDecl: VariableDeclaration, context: ContractDefinition, deref: ASTDereferencer, location: StorageLocation | null = varDecl.storageLocation): string {
430431
if (!varDecl.typeName) {
431432
throw new Error('Missing type information');
432433
}
433-
return getType(varDecl.typeName, location);
434+
return getType(varDecl.typeName, context, deref, location);
434435
}
435436

436-
function getType(typeName: TypeName, location: StorageLocation | null): string {
437+
function getType(typeName: TypeName, context: ContractDefinition, deref: ASTDereferencer, location: StorageLocation | null): string {
437438
const { typeString, typeIdentifier } = typeName.typeDescriptions;
438439
if (typeof typeString !== 'string' || typeof typeIdentifier !== 'string') {
439440
throw new Error('Missing type information');
440441
}
441-
const type = typeString.replace(/^(struct|enum|contract) /, '') + (typeIdentifier.endsWith('_ptr') && location ? ` ${location}` : '');
442+
443+
let type = typeString.replace(/^(struct|enum|contract) /, '') + (typeIdentifier.endsWith('_ptr') && location ? ` ${location}` : '');
444+
445+
const typeScopeMatch = type.match(/^([a-zA-Z0-9_$]+)\./);
446+
if (typeScopeMatch) {
447+
const [, typeScope] = typeScopeMatch;
448+
449+
const isScopeImplicit = context.linearizedBaseContracts.some(c => deref('ContractDefinition', c).name === typeScope);
450+
451+
if (isScopeImplicit) {
452+
type = type.replace(`${typeScope}.`, '');
453+
}
454+
}
455+
442456
return type;
443457
}
444458

@@ -458,26 +472,26 @@ function getVariables(contract: ContractDefinition, deref: ASTDereferencer, subs
458472
return res;
459473
}
460474

461-
function getVarGetterArgs(v: VariableDeclaration): Argument[] {
475+
function getVarGetterArgs(v: VariableDeclaration, context: ContractDefinition, deref: ASTDereferencer): Argument[] {
462476
if (!v.typeName) {
463477
throw new Error('missing typenName');
464478
}
465479
const types = [];
466480
for (let t = v.typeName; t.nodeType === 'Mapping'; t = t.valueType) {
467-
types.push({ name: `arg${types.length}`, type: getType(t.keyType, 'memory') })
481+
types.push({ name: `arg${types.length}`, type: getType(t.keyType, context, deref, 'memory') })
468482
}
469483
return types;
470484
}
471485

472-
function getVarGetterReturnType(v: VariableDeclaration): string {
486+
function getVarGetterReturnType(v: VariableDeclaration, context: ContractDefinition, deref: ASTDereferencer): string {
473487
if (!v.typeName) {
474488
throw new Error('missing typenName');
475489
}
476490
let t = v.typeName;
477491
while (t.nodeType === 'Mapping') {
478492
t = t.valueType;
479493
}
480-
return getType(t, 'memory');
494+
return getType(t, context, deref, 'memory');
481495
}
482496

483497
function getFunctions(contract: ContractDefinition, deref: ASTDereferencer, subset?: Visibility[]): FunctionDefinition[] {

0 commit comments

Comments
 (0)