Add a HACK to detect coverage of the modifiers with no parameters

This commit is contained in:
Leonid Logvinov 2018-03-12 12:31:33 +01:00
parent 2a9913b8fb
commit 1cdfbbadaa
No known key found for this signature in database
GPG Key ID: 0DD294BFDE8C95D4
2 changed files with 28 additions and 0 deletions

View File

@ -7,6 +7,7 @@ export interface CoverageEntriesDescription {
fnMap: FnMap; fnMap: FnMap;
branchMap: BranchMap; branchMap: BranchMap;
statementMap: StatementMap; statementMap: StatementMap;
modifiersStatementIds: number[];
} }
enum BranchType { enum BranchType {
@ -19,6 +20,7 @@ export class ASTVisitor {
private _entryId = 0; private _entryId = 0;
private _fnMap: FnMap = {}; private _fnMap: FnMap = {};
private _branchMap: BranchMap = {}; private _branchMap: BranchMap = {};
private _modifiersStatementIds: number[] = [];
private _statementMap: StatementMap = {}; private _statementMap: StatementMap = {};
private _locationByOffset: LocationByOffset; private _locationByOffset: LocationByOffset;
private static _doesLookLikeAnASTNode(ast: any): boolean { private static _doesLookLikeAnASTNode(ast: any): boolean {
@ -49,6 +51,7 @@ export class ASTVisitor {
fnMap: this._fnMap, fnMap: this._fnMap,
branchMap: this._branchMap, branchMap: this._branchMap,
statementMap: this._statementMap, statementMap: this._statementMap,
modifiersStatementIds: this._modifiersStatementIds,
}; };
return coverageEntriesDescription; return coverageEntriesDescription;
} }
@ -91,6 +94,7 @@ export class ASTVisitor {
private _visitModifierArgument(ast: SolidityParser.AST): void { private _visitModifierArgument(ast: SolidityParser.AST): void {
const BUILTIN_MODIFIERS = ['public', 'view', 'payable', 'external', 'internal', 'pure', 'constant']; const BUILTIN_MODIFIERS = ['public', 'view', 'payable', 'external', 'internal', 'pure', 'constant'];
if (!_.includes(BUILTIN_MODIFIERS, ast.name)) { if (!_.includes(BUILTIN_MODIFIERS, ast.name)) {
this._modifiersStatementIds.push(this._entryId);
this._visitStatement(ast); this._visitStatement(ast);
} }
} }

View File

@ -69,6 +69,30 @@ export class CoverageManager {
); );
functionCoverage[fnId] = isCovered; functionCoverage[fnId] = isCovered;
} }
// HACK: Solidity doesn't emit any opcodes that map back to modifiers with no args, that's why we map back to the
// function range and check if there is any covered statement within that range.
for (const modifierStatementId of coverageEntriesDescription.modifiersStatementIds) {
if (statementCoverage[modifierStatementId]) {
// Already detected as covered
continue;
}
const modifierDescription = coverageEntriesDescription.statementMap[modifierStatementId];
const enclosingFunction = _.find(coverageEntriesDescription.fnMap, functionDescription =>
utils.isRangeInside(modifierDescription, functionDescription.loc),
) as FunctionDescription;
const isModifierCovered = _.some(
coverageEntriesDescription.statementMap,
(statementDescription: StatementDescription, statementId: number) => {
const isInsideTheModifierEnclosingFunction = utils.isRangeInside(
statementDescription,
enclosingFunction.loc,
);
const isCovered = statementCoverage[statementId];
return isInsideTheModifierEnclosingFunction && isCovered;
},
);
statementCoverage[modifierStatementId] = isModifierCovered;
}
const partialCoverage = { const partialCoverage = {
[contractData.sources[fileIndex]]: { [contractData.sources[fileIndex]]: {
...coverageEntriesDescription, ...coverageEntriesDescription,