diff options
author | Fabio Berger <me@fabioberger.com> | 2018-03-14 21:16:08 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2018-03-14 21:16:08 +0800 |
commit | 009b70f5b218a1ccb154034936256308131b7d9c (patch) | |
tree | cd9642a8d3323c9e80da54ac4e8fc40ade9f9020 /packages/sol-cov/src/source_maps.ts | |
parent | f7c1e10b5ac112866ee55e7fededdb37c890d30f (diff) | |
parent | 3f3e8be004818ddaa1921b3dff12bdd46052278b (diff) | |
download | dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar.gz dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar.bz2 dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar.lz dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar.xz dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.tar.zst dexon-sol-tools-009b70f5b218a1ccb154034936256308131b7d9c.zip |
Merge branch 'development' into convertScriptsToTs
* development: (71 commits)
Transform input data before encoding for callAsync and getABIEncodedTransactionData
Update coverage badge to show development coverage
Configure post build hook
Notify coveralls after all tasks have finished
Address feedback
Revert "Report all coverage reports together"
Separate published packages and typescript typings on README
Report all coverage reports together
Add other statement types
Properly and consistently parse ENV vars
Add forgotten file
Start using solidity-parser-antlr
Fix the default always overriding to address
Submit a TD PR
Add an explanatory comment for making ranges unique
Fix a typo in handling env variables
Introduce TESTRPC_FIRST_ADDRESS
Make BlockchainLifecycle accept only web3Wrapper
Fix comments
Fix deployer CHANGELOG
...
# Conflicts:
# README.md
# packages/deployer/package.json
# packages/subproviders/src/globals.d.ts
# yarn.lock
Diffstat (limited to 'packages/sol-cov/src/source_maps.ts')
-rw-r--r-- | packages/sol-cov/src/source_maps.ts | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/packages/sol-cov/src/source_maps.ts b/packages/sol-cov/src/source_maps.ts new file mode 100644 index 000000000..9b3ea9e24 --- /dev/null +++ b/packages/sol-cov/src/source_maps.ts @@ -0,0 +1,82 @@ +import * as _ from 'lodash'; + +import { getPcToInstructionIndexMapping } from './instructions'; +import { LineColumn, LocationByOffset, SourceRange } from './types'; + +const RADIX = 10; + +export interface SourceLocation { + offset: number; + length: number; + fileIndex: number; +} + +export function getLocationByOffset(str: string): LocationByOffset { + const locationByOffset: LocationByOffset = {}; + let currentOffset = 0; + for (const char of str.split('')) { + const location = locationByOffset[currentOffset - 1] || { line: 1, column: 0 }; + const isNewline = char === '\n'; + locationByOffset[currentOffset] = { + line: location.line + (isNewline ? 1 : 0), + column: isNewline ? 0 : location.column + 1, + }; + currentOffset++; + } + return locationByOffset; +} + +// Parses a sourcemap string +// The solidity sourcemap format is documented here: https://github.com/ethereum/solidity/blob/develop/docs/miscellaneous.rst#source-mappings +export function parseSourceMap( + sourceCodes: string[], + srcMap: string, + bytecodeHex: string, + sources: string[], +): { [programCounter: number]: SourceRange } { + const bytecode = Uint8Array.from(Buffer.from(bytecodeHex, 'hex')); + const pcToInstructionIndex: { [programCounter: number]: number } = getPcToInstructionIndexMapping(bytecode); + const locationByOffsetByFileIndex = _.map(sourceCodes, getLocationByOffset); + const entries = srcMap.split(';'); + const parsedEntries: SourceLocation[] = []; + let lastParsedEntry: SourceLocation = {} as any; + const instructionIndexToSourceRange: { [instructionIndex: number]: SourceRange } = {}; + _.each(entries, (entry: string, i: number) => { + const [instructionIndexStrIfExists, lengthStrIfExists, fileIndexStrIfExists, jumpTypeStrIfExists] = entry.split( + ':', + ); + const instructionIndexIfExists = parseInt(instructionIndexStrIfExists, RADIX); + const lengthIfExists = parseInt(lengthStrIfExists, RADIX); + const fileIndexIfExists = parseInt(fileIndexStrIfExists, RADIX); + const offset = _.isNaN(instructionIndexIfExists) ? lastParsedEntry.offset : instructionIndexIfExists; + const length = _.isNaN(lengthIfExists) ? lastParsedEntry.length : lengthIfExists; + const fileIndex = _.isNaN(fileIndexIfExists) ? lastParsedEntry.fileIndex : fileIndexIfExists; + const parsedEntry = { + offset, + length, + fileIndex, + }; + if (parsedEntry.fileIndex !== -1) { + const sourceRange = { + location: { + start: locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset - 1], + end: + locationByOffsetByFileIndex[parsedEntry.fileIndex][parsedEntry.offset + parsedEntry.length - 1], + }, + fileName: sources[parsedEntry.fileIndex], + }; + instructionIndexToSourceRange[i] = sourceRange; + } else { + // Some assembly code generated by Solidity can't be mapped back to a line of source code. + // Source: https://github.com/ethereum/solidity/issues/3629 + } + lastParsedEntry = parsedEntry; + }); + const pcsToSourceRange: { [programCounter: number]: SourceRange } = {}; + for (const programCounterKey of _.keys(pcToInstructionIndex)) { + const pc = parseInt(programCounterKey, RADIX); + const instructionIndex: number = pcToInstructionIndex[pc]; + pcsToSourceRange[pc] = instructionIndexToSourceRange[instructionIndex]; + } + return pcsToSourceRange; +} |