How do I tell gcov to ignore un-hittable lines of C++ code?

C++Code CoverageGcov

C++ Problem Overview


I'm using gcov to measure coverage in my C++ code. I'd like to get to 100% coverage, but am hampered by the fact that there are some lines of code that are theoretically un-hittable (methods that are required to be implemented but which are never called, default branches of switch statements, etc.). Each of these branches contains an assert( false ); statement, but gcov still marks them as un-hit.

I'd like to be able to tell gcov to ignore these branches. Is there any way to give gcov that information -- by annotating the source code, or by any other mechanism?

C++ Solutions


Solution 1 - C++

Please use lcov. It hides gcov's complexity, produces nice output, allows detailed output per test, features easy file filtering and - ta-taa - line markers for already reviewed lines:

From geninfo(1):

> The following markers are recognized by geninfo: > > - LCOV_EXCL_LINE > - Lines containing this marker will be excluded. > - LCOV_EXCL_START > - Marks the beginning of an excluded section. The current line is part of this section. > - LCOV_EXCL_STOP > - Marks the end of an excluded section. The current line not part of this section.

Solution 2 - C++

A tool called gcovr can be used to summarise the output of gcov, and (from at least version 3.4) it supports the same exclusion markers as lcov.

From this answer:

> The following markers are recognized by geninfo: > > - LCOV_EXCL_LINE > - Lines containing this marker will be excluded. > - LCOV_EXCL_START > - Marks the beginning of an excluded section. The current line is part of this section. > - LCOV_EXCL_STOP > - Marks the end of an excluded section. The current line not part of this section.

You can also replace 'LCOV' above with 'GCOV' or 'GCOVR'. They all work.

Solution 3 - C++

Could you introduce unit tests of the relevant functions, that exist solely to shut gcov up by directly attacking the theoretically-unhittable code paths? Since they're unit tests, they could perhaps ignore the "impossibility" of the situations. They could call the functions that are never called, pass invalid enum values to catch default branches, etc.

Then either run those tests only on the version of your code compiled with NDEBUG, or else run them in a harness which tests that the assert is triggered - whatever your test framework supports.

I find it a bit odd though for the spec to say that the code has to be there, rather than the spec containing functional requirements on the code. In particular, it means that your tests aren't testing those requirements, which is as good a reason as any to keep requirements functional. Personally I'd want to modify the spec to say, "if called with an invalid enum value, the function shall fail an assert. Callers shall not call the function with an invalid enum value in release mode". Or some such.

Presumably what it currently says, is along the lines of "all switch statements must have a default case". But that means coding standards are interfering with observable behaviour (at least, observable under gcov) by introducing dead code. Coding standards shouldn't do that, so the functional spec should take account of the coding standards if possible.

Failing that, you could perhaps wrap the unhittable code in #if !GCOV_BUILD, and do a separate build for gcov's benefit. This build will fail some requirements, but conditional on your analysis of the code being correct, it gives you the confidence you want that the test suite tests everything else.

Edit: you say you're using a dodgy code generator, but you're also asking for a solution by annotating the source code. If you're changing the source, can you just remove the dead code in many cases? Not that changing generated source is ideal, but needs must...

Solution 4 - C++

I do not believe this is possible. Gcov depends on gcc to generate extra code to produce the coverage output. GCov itself just parses the data. This means that Gcov cannot analyze the code any better than gcc (and I assume you use -Wall and have removed code reported as unreachable).

Remember that relocatable functions can be called from anywhere, potentially even external dlls or executables so there is no way the compiler can know what relocatable functions will not be called or what input these functions may have.

You probably will need to use some facy static analysis tool to get the info that you want.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjchlView Question on Stackoverflow
Solution 1 - C++Torsten ScheckView Answer on Stackoverflow
Solution 2 - C++Simon PickupView Answer on Stackoverflow
Solution 3 - C++Steve JessopView Answer on Stackoverflow
Solution 4 - C++doronView Answer on Stackoverflow