foundry
foundry copied to clipboard
Coverage: Library coverage
Libraries are currently not covered and they are somewhat non-trivial to map instructions for.
Generally, there are two types of library functions:
- Internal functions are inlined in the contract that use them
- External functions are called via
delegatecall
The way coverage works currently is in a few passes:
- First, we detect any sections of code that we want to include in our coverage report
- Second, we also take the base contracts of a contract into account, since all behavior of base contracts are inherited. We need this to map instructions to the items we generated in the first pass using source maps
- Third, we use the source maps of concrete contracts to find instructions that mark the items gathered in our first and second step as covered. One item might be covered by multiple instructions in different contracts because of inheritance
The issue with adding library coverage is that the Solidity compiler does not give us any easily digestable information about what libraries are used in contracts. This is in contrast to base contracts which are easily identified using a property of contract AST nodes called linearizedBaseContracts.
In order to reliably find what libraries are used in contracts so we can map instructions onto coverage items present in libraries, we need to walk each node in the AST to find call expression nodes.
These call expression nodes include some crude type information, and in the case of library calls, the type information will show up as e.g. type(library LibraryName).
After parsing this information, we need to map the library name back onto an AST node ID so we can find what coverage items are present in the library. The rest of the analysis step in forge coverage uses AST node IDs to refer to contracts.
Some unknowns:
- Is the type information correct, i.e. does it take shadowing and import aliases into account?
- Are library names from the type information easily mappable onto AST node IDs corresponding to the library's AST?
Hi @onbjerg , sorry to bother you, I would like to know, if it is a developer-defined library and the functions in the library are all internal functions, the coverage rate running through forge coverage cannot be supported at present, right?
No libraries are supported at the moment
Will it support library coverage later?
Shouldn't this issue be closed?
It looks like #3128 added support for library coverage, and I can also see that it works in my project.
Update: it looks like no, this issue cannot be just yet. There are still issues with library coverage, e.g. https://github.com/foundry-rs/foundry/issues/4305.
Also generally outside of dynamically linked libraries any and all delegatecall'd code is not being considered as covered I think. Is that right? Might be worth updating the issue with what is the current way of how coverage works.
Might be worth updating the issue with what is the current way of how coverage works.
Cc @gakonst. Many coverage-related issues are outdated, including https://github.com/foundry-rs/foundry/issues/1961.