diff options
-rw-r--r-- | packages/sol-cov/src/ast_visitor.ts | 29 | ||||
-rw-r--r-- | packages/sol-cov/src/collect_coverage_entries.ts | 21 |
2 files changed, 48 insertions, 2 deletions
diff --git a/packages/sol-cov/src/ast_visitor.ts b/packages/sol-cov/src/ast_visitor.ts index 564f0f7d2..49b7ac4bd 100644 --- a/packages/sol-cov/src/ast_visitor.ts +++ b/packages/sol-cov/src/ast_visitor.ts @@ -23,8 +23,11 @@ export class ASTVisitor { private _modifiersStatementIds: number[] = []; private _statementMap: StatementMap = {}; private _locationByOffset: LocationByOffset; - constructor(locationByOffset: LocationByOffset) { + private _ignoreRangesBeginingAt: number[]; + private _ignoreRangesWithin: Array<[number, number]> = []; + constructor(locationByOffset: LocationByOffset, ignoreRangesBeginingAt: number[] = []) { this._locationByOffset = locationByOffset; + this._ignoreRangesBeginingAt = ignoreRangesBeginingAt; } public getCollectedCoverageEntries(): CoverageEntriesDescription { const coverageEntriesDescription = { @@ -96,6 +99,9 @@ export class ASTVisitor { public ModifierInvocation(ast: Parser.ModifierInvocation): void { const BUILTIN_MODIFIERS = ['public', 'view', 'payable', 'external', 'internal', 'pure', 'constant']; if (!_.includes(BUILTIN_MODIFIERS, ast.name)) { + if (this._ignoreExpression(ast)) { + return; + } this._modifiersStatementIds.push(this._entryId); this._visitStatement(ast); } @@ -106,6 +112,9 @@ export class ASTVisitor { right: Parser.ASTNode, type: BranchType, ): void { + if (this._ignoreExpression(ast)) { + return; + } this._branchMap[this._entryId++] = { line: this._getExpressionRange(ast).start.line, type, @@ -113,6 +122,9 @@ export class ASTVisitor { }; } private _visitStatement(ast: Parser.ASTNode): void { + if (this._ignoreExpression(ast)) { + return; + } this._statementMap[this._entryId++] = this._getExpressionRange(ast); } private _getExpressionRange(ast: Parser.ASTNode): SingleFileSourceRange { @@ -125,7 +137,22 @@ export class ASTVisitor { }; return range; } + private _ignoreExpression(ast: Parser.ASTNode): boolean { + const [astStart, astEnd] = ast.range as [number, number]; + const isRangeIgnored = _.some( + this._ignoreRangesWithin, + ([rangeStart, rangeEnd]: [number, number]) => astStart >= rangeStart && astEnd <= rangeEnd, + ); + return this._ignoreRangesBeginingAt.includes(astStart) || isRangeIgnored; + } private _visitFunctionLikeDefinition(ast: Parser.ModifierDefinition | Parser.FunctionDefinition): void { + if (this._ignoreExpression(ast)) { + // we want to ignore everything within this function + // add this nodes range to the ignoreRangesWithin array + // so we can ignore any later nodes that are children of this node + this._ignoreRangesWithin.push(ast.range as [number, number]); + return; + } const loc = this._getExpressionRange(ast); this._fnMap[this._entryId++] = { name: ast.name, diff --git a/packages/sol-cov/src/collect_coverage_entries.ts b/packages/sol-cov/src/collect_coverage_entries.ts index 3fc85008c..703af3099 100644 --- a/packages/sol-cov/src/collect_coverage_entries.ts +++ b/packages/sol-cov/src/collect_coverage_entries.ts @@ -13,10 +13,29 @@ export const collectCoverageEntries = (contractSource: string) => { if (_.isUndefined(coverageEntriesBySourceHash[sourceHash]) && !_.isUndefined(contractSource)) { const ast = parser.parse(contractSource, { range: true }); const locationByOffset = getLocationByOffset(contractSource); - const visitor = new ASTVisitor(locationByOffset); + const ignoreRangesBegingingAt = gatherRangesToIgnore(contractSource); + const visitor = new ASTVisitor(locationByOffset, ignoreRangesBegingingAt); parser.visit(ast, visitor); coverageEntriesBySourceHash[sourceHash] = visitor.getCollectedCoverageEntries(); } const coverageEntriesDescription = coverageEntriesBySourceHash[sourceHash]; return coverageEntriesDescription; }; + +const IGNORE_RE = /\/\*\s*solcov\s+ignore\s+next\s*\*\/\s*/gm; + +// Gather the start index of all code blocks preceeded by "/* solcov ignore next */" +function gatherRangesToIgnore(contractSource: string): number[] { + const ignoreRangesStart = []; + + let match; + do { + match = IGNORE_RE.exec(contractSource); + if (match) { + const matchLen = match[0].length; + ignoreRangesStart.push(match.index + matchLen); + } + } while (match); + + return ignoreRangesStart; +} |