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

Solution 1:

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:

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:

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...