Skip to content

Commit 1b8b730

Browse files
authored
Support multi-contract files w/ inheritance for solc 0.6.x (sc-forks#511)
1 parent 1b379c2 commit 1b8b730

File tree

6 files changed

+45
-26
lines changed

6 files changed

+45
-26
lines changed

lib/injector.js

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,23 @@ class Injector {
1212
}
1313
}
1414

15-
_getInjectable(fileName, hash, type){
16-
return `${this._getMethodIdentifier(fileName)}(${hash}); /* ${type} */ \n`;
15+
_getInjectable(id, hash, type){
16+
return `${this._getMethodIdentifier(id)}(${hash}); /* ${type} */ \n`;
1717
}
1818

19-
_getHash(fileName) {
19+
_getHash(id) {
2020
this.hashCounter++;
21-
return web3Utils.keccak256(`${fileName}:${this.hashCounter}`);
21+
return web3Utils.keccak256(`${id}:${this.hashCounter}`);
2222
}
2323

24-
_getMethodIdentifier(fileName){
25-
return `coverage_${web3Utils.keccak256(fileName).slice(0,10)}`
24+
_getMethodIdentifier(id){
25+
return `coverage_${web3Utils.keccak256(id).slice(0,10)}`
2626
}
2727

28-
_getInjectionComponents(contract, injectionPoint, fileName, type){
28+
_getInjectionComponents(contract, injectionPoint, id, type){
2929
const { start, end } = this._split(contract, injectionPoint);
30-
const hash = this._getHash(fileName)
31-
const injectable = this._getInjectable(fileName, hash, type);
30+
const hash = this._getHash(id)
31+
const injectable = this._getInjectable(id, hash, type);
3232

3333
return {
3434
start: start,
@@ -41,25 +41,26 @@ class Injector {
4141
/**
4242
* Generates a solidity statement injection. Declared once per fn.
4343
* Definition is the same for every fn in file.
44-
* @param {String} fileName
44+
* @param {String} id
4545
* @return {String} ex: bytes32[1] memory _sc_82e0891
4646
*/
47-
_getHashMethodDefinition(fileName){
48-
const hash = web3Utils.keccak256(fileName).slice(0,10);
49-
const method = this._getMethodIdentifier(fileName);
47+
_getHashMethodDefinition(id, contract){
48+
const hash = web3Utils.keccak256(id).slice(0,10);
49+
const method = this._getMethodIdentifier(id);
5050
return `\nfunction ${method}(bytes32 c__${hash}) public pure {}\n`;
5151
}
5252

5353
injectLine(contract, fileName, injectionPoint, injection, instrumentation){
5454
const type = 'line';
5555
const { start, end } = this._split(contract, injectionPoint);
56+
const id = `${fileName}:${injection.contractName}`;
5657

5758
const newLines = start.match(/\n/g);
5859
const linecount = ( newLines || []).length + 1;
5960
contract.runnableLines.push(linecount);
6061

61-
const hash = this._getHash(fileName)
62-
const injectable = this._getInjectable(fileName, hash, type);
62+
const hash = this._getHash(id)
63+
const injectable = this._getInjectable(id, hash, type);
6364

6465
instrumentation[hash] = {
6566
id: linecount,
@@ -73,13 +74,14 @@ class Injector {
7374

7475
injectStatement(contract, fileName, injectionPoint, injection, instrumentation) {
7576
const type = 'statement';
77+
const id = `${fileName}:${injection.contractName}`;
7678

7779
const {
7880
start,
7981
end,
8082
hash,
8183
injectable
82-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
84+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
8385

8486
instrumentation[hash] = {
8587
id: injection.statementId,
@@ -93,13 +95,14 @@ class Injector {
9395

9496
injectFunction(contract, fileName, injectionPoint, injection, instrumentation){
9597
const type = 'function';
98+
const id = `${fileName}:${injection.contractName}`;
9699

97100
const {
98101
start,
99102
end,
100103
hash,
101104
injectable
102-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
105+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
103106

104107
instrumentation[hash] = {
105108
id: injection.fnId,
@@ -113,13 +116,14 @@ class Injector {
113116

114117
injectBranch(contract, fileName, injectionPoint, injection, instrumentation){
115118
const type = 'branch';
119+
const id = `${fileName}:${injection.contractName}`;
116120

117121
const {
118122
start,
119123
end,
120124
hash,
121125
injectable
122-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
126+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
123127

124128
instrumentation[hash] = {
125129
id: injection.branchId,
@@ -134,13 +138,14 @@ class Injector {
134138

135139
injectEmptyBranch(contract, fileName, injectionPoint, injection, instrumentation) {
136140
const type = 'branch';
141+
const id = `${fileName}:${injection.contractName}`;
137142

138143
const {
139144
start,
140145
end,
141146
hash,
142147
injectable
143-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
148+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
144149

145150
instrumentation[hash] = {
146151
id: injection.branchId,
@@ -155,13 +160,14 @@ class Injector {
155160

156161
injectAssertPre(contract, fileName, injectionPoint, injection, instrumentation) {
157162
const type = 'assertPre';
163+
const id = `${fileName}:${injection.contractName}`;
158164

159165
const {
160166
start,
161167
end,
162168
hash,
163169
injectable
164-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
170+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
165171

166172
instrumentation[hash] = {
167173
id: injection.branchId,
@@ -175,13 +181,14 @@ class Injector {
175181

176182
injectAssertPost(contract, fileName, injectionPoint, injection, instrumentation) {
177183
const type = 'assertPost';
184+
const id = `${fileName}:${injection.contractName}`;
178185

179186
const {
180187
start,
181188
end,
182189
hash,
183190
injectable
184-
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
191+
} = this._getInjectionComponents(contract, injectionPoint, id, type);
185192

186193
instrumentation[hash] = {
187194
id: injection.branchId,
@@ -196,7 +203,8 @@ class Injector {
196203
injectHashMethod(contract, fileName, injectionPoint, injection, instrumentation){
197204
const start = contract.instrumented.slice(0, injectionPoint);
198205
const end = contract.instrumented.slice(injectionPoint);
199-
contract.instrumented = `${start}${this._getHashMethodDefinition(fileName)}${end}`;
206+
const id = `${fileName}:${injection.contractName}`;
207+
contract.instrumented = `${start}${this._getHashMethodDefinition(id)}${end}`;
200208
}
201209
};
202210

lib/parse.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ parse.ContractOrLibraryStatement = function(contract, expression) {
7272
const end = contract.instrumented.slice(start).indexOf('{') + 1;
7373
const loc = start + end;;
7474

75+
contract.contractName = expression.name;
76+
7577
(contract.injectionPoints[loc])
76-
? contract.injectionPoints[loc].push({ type: 'injectHashMethod'})
77-
: contract.injectionPoints[loc] = [{ type: 'injectHashMethod'}];
78+
? contract.injectionPoints[loc].push({ type: 'injectHashMethod', contractName: expression.name})
79+
: contract.injectionPoints[loc] = [{ type: 'injectHashMethod', contractName: expression.name}];
7880
}
7981

8082
if (expression.subNodes) {

lib/registrar.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ class Registrar {
1414
* @param {Number} value injection point `id`
1515
*/
1616
_createInjectionPoint(contract, key, value) {
17+
value.contractName = contract.contractName;
18+
1719
(contract.injectionPoints[key])
1820
? contract.injectionPoints[key].push(value)
1921
: contract.injectionPoints[key] = [value];

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"scripts": {
1313
"nyc": "SILENT=true nyc --exclude '**/sc_temp/**' --exclude '**/test/**'",
14-
"test": "SILENT=true node --max-old-space-size=4096 ./node_modules/.bin/nyc -- mocha test/units/* --timeout 100000 --no-warnings --exit",
14+
"test": "SILENT=true node --max-old-space-size=4096 ./node_modules/.bin/nyc --exclude '**/sc_temp/**' --exclude '**/test/**/' -- mocha test/units/* --timeout 100000 --no-warnings --exit",
1515
"test:ci": "SILENT=true node --max-old-space-size=4096 ./node_modules/.bin/nyc --reporter=lcov --exclude '**/sc_temp/**' --exclude '**/test/**/' -- mocha test/units/* --timeout 100000 --no-warnings --exit",
1616
"test:debug": "node --max-old-space-size=4096 ./node_modules/.bin/mocha test/units/* --timeout 100000 --no-warnings --exit"
1717
},

test/integration/projects/solc-6/contracts/ContractA.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,10 @@ contract ContractA is ContractB {
5757
//address y = payable(x); // parser-diligence crashing here...
5858
}
5959
}
60+
61+
// Making sure same-file inheritance works for solc-6...
62+
contract ContractC is ContractA {
63+
function simpleC(uint x) public {
64+
x++;
65+
}
66+
}

test/units/buidler/standard.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ describe('Buidler Plugin: standard use cases', function() {
284284
const expected = [
285285
{
286286
file: mock.pathToContract(buidlerConfig, 'ContractA.sol'),
287-
pct: 100
287+
pct: 87.5
288288
},
289289
{
290290
file: mock.pathToContract(buidlerConfig, 'ContractB.sol'),

0 commit comments

Comments
 (0)