Support multi-contract files w/ inheritance for solc 0.6.x (#511)

pull/512/head
cgewecke 5 years ago committed by GitHub
parent 1b379c2924
commit 1b8b73086c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      lib/injector.js
  2. 6
      lib/parse.js
  3. 2
      lib/registrar.js
  4. 2
      package.json
  5. 7
      test/integration/projects/solc-6/contracts/ContractA.sol
  6. 2
      test/units/buidler/standard.js

@ -12,23 +12,23 @@ class Injector {
}
}
_getInjectable(fileName, hash, type){
return `${this._getMethodIdentifier(fileName)}(${hash}); /* ${type} */ \n`;
_getInjectable(id, hash, type){
return `${this._getMethodIdentifier(id)}(${hash}); /* ${type} */ \n`;
}
_getHash(fileName) {
_getHash(id) {
this.hashCounter++;
return web3Utils.keccak256(`${fileName}:${this.hashCounter}`);
return web3Utils.keccak256(`${id}:${this.hashCounter}`);
}
_getMethodIdentifier(fileName){
return `coverage_${web3Utils.keccak256(fileName).slice(0,10)}`
_getMethodIdentifier(id){
return `coverage_${web3Utils.keccak256(id).slice(0,10)}`
}
_getInjectionComponents(contract, injectionPoint, fileName, type){
_getInjectionComponents(contract, injectionPoint, id, type){
const { start, end } = this._split(contract, injectionPoint);
const hash = this._getHash(fileName)
const injectable = this._getInjectable(fileName, hash, type);
const hash = this._getHash(id)
const injectable = this._getInjectable(id, hash, type);
return {
start: start,
@ -41,25 +41,26 @@ class Injector {
/**
* Generates a solidity statement injection. Declared once per fn.
* Definition is the same for every fn in file.
* @param {String} fileName
* @param {String} id
* @return {String} ex: bytes32[1] memory _sc_82e0891
*/
_getHashMethodDefinition(fileName){
const hash = web3Utils.keccak256(fileName).slice(0,10);
const method = this._getMethodIdentifier(fileName);
_getHashMethodDefinition(id, contract){
const hash = web3Utils.keccak256(id).slice(0,10);
const method = this._getMethodIdentifier(id);
return `\nfunction ${method}(bytes32 c__${hash}) public pure {}\n`;
}
injectLine(contract, fileName, injectionPoint, injection, instrumentation){
const type = 'line';
const { start, end } = this._split(contract, injectionPoint);
const id = `${fileName}:${injection.contractName}`;
const newLines = start.match(/\n/g);
const linecount = ( newLines || []).length + 1;
contract.runnableLines.push(linecount);
const hash = this._getHash(fileName)
const injectable = this._getInjectable(fileName, hash, type);
const hash = this._getHash(id)
const injectable = this._getInjectable(id, hash, type);
instrumentation[hash] = {
id: linecount,
@ -73,13 +74,14 @@ class Injector {
injectStatement(contract, fileName, injectionPoint, injection, instrumentation) {
const type = 'statement';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.statementId,
@ -93,13 +95,14 @@ class Injector {
injectFunction(contract, fileName, injectionPoint, injection, instrumentation){
const type = 'function';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.fnId,
@ -113,13 +116,14 @@ class Injector {
injectBranch(contract, fileName, injectionPoint, injection, instrumentation){
const type = 'branch';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.branchId,
@ -134,13 +138,14 @@ class Injector {
injectEmptyBranch(contract, fileName, injectionPoint, injection, instrumentation) {
const type = 'branch';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.branchId,
@ -155,13 +160,14 @@ class Injector {
injectAssertPre(contract, fileName, injectionPoint, injection, instrumentation) {
const type = 'assertPre';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.branchId,
@ -175,13 +181,14 @@ class Injector {
injectAssertPost(contract, fileName, injectionPoint, injection, instrumentation) {
const type = 'assertPost';
const id = `${fileName}:${injection.contractName}`;
const {
start,
end,
hash,
injectable
} = this._getInjectionComponents(contract, injectionPoint, fileName, type);
} = this._getInjectionComponents(contract, injectionPoint, id, type);
instrumentation[hash] = {
id: injection.branchId,
@ -196,7 +203,8 @@ class Injector {
injectHashMethod(contract, fileName, injectionPoint, injection, instrumentation){
const start = contract.instrumented.slice(0, injectionPoint);
const end = contract.instrumented.slice(injectionPoint);
contract.instrumented = `${start}${this._getHashMethodDefinition(fileName)}${end}`;
const id = `${fileName}:${injection.contractName}`;
contract.instrumented = `${start}${this._getHashMethodDefinition(id)}${end}`;
}
};

@ -72,9 +72,11 @@ parse.ContractOrLibraryStatement = function(contract, expression) {
const end = contract.instrumented.slice(start).indexOf('{') + 1;
const loc = start + end;;
contract.contractName = expression.name;
(contract.injectionPoints[loc])
? contract.injectionPoints[loc].push({ type: 'injectHashMethod'})
: contract.injectionPoints[loc] = [{ type: 'injectHashMethod'}];
? contract.injectionPoints[loc].push({ type: 'injectHashMethod', contractName: expression.name})
: contract.injectionPoints[loc] = [{ type: 'injectHashMethod', contractName: expression.name}];
}
if (expression.subNodes) {

@ -14,6 +14,8 @@ class Registrar {
* @param {Number} value injection point `id`
*/
_createInjectionPoint(contract, key, value) {
value.contractName = contract.contractName;
(contract.injectionPoints[key])
? contract.injectionPoints[key].push(value)
: contract.injectionPoints[key] = [value];

@ -11,7 +11,7 @@
},
"scripts": {
"nyc": "SILENT=true nyc --exclude '**/sc_temp/**' --exclude '**/test/**'",
"test": "SILENT=true node --max-old-space-size=4096 ./node_modules/.bin/nyc -- mocha test/units/* --timeout 100000 --no-warnings --exit",
"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",
"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",
"test:debug": "node --max-old-space-size=4096 ./node_modules/.bin/mocha test/units/* --timeout 100000 --no-warnings --exit"
},

@ -57,3 +57,10 @@ contract ContractA is ContractB {
//address y = payable(x); // parser-diligence crashing here...
}
}
// Making sure same-file inheritance works for solc-6...
contract ContractC is ContractA {
function simpleC(uint x) public {
x++;
}
}

@ -284,7 +284,7 @@ describe('Buidler Plugin: standard use cases', function() {
const expected = [
{
file: mock.pathToContract(buidlerConfig, 'ContractA.sol'),
pct: 100
pct: 87.5
},
{
file: mock.pathToContract(buidlerConfig, 'ContractB.sol'),

Loading…
Cancel
Save