diff --git a/lib/lcovutil.pm b/lib/lcovutil.pm index 6cd9fb5..fccc132 100644 --- a/lib/lcovutil.pm +++ b/lib/lcovutil.pm @@ -302,6 +302,8 @@ our $FILTER_MISSING_FILE; our $FILTER_EXCEPTION_BRANCH; # remove lone branch in block - it can't be an actual conditional our $FILTER_ORPHAN_BRANCH; +# MC/DC with single expression is identical to branch +our $FILTER_MCDC_SINGLE; our $FILTER_OMIT_PATTERNS; # special/somewhat faked filter our %COVERAGE_FILTERS = ("branch" => \$FILTER_BRANCH_NO_COND, @@ -317,6 +319,7 @@ our %COVERAGE_FILTERS = ("branch" => \$FILTER_BRANCH_NO_COND, 'branch_region' => \$FILTER_EXCLUDE_BRANCH, 'exception' => \$FILTER_EXCEPTION_BRANCH, 'orphan' => \$FILTER_ORPHAN_BRANCH, + 'mcdc' => \$FILTER_MCDC_SINGLE, "trivial" => \$FILTER_TRIVIAL_FUNCTION,); our @cov_filter; # 'undef' if filter is not enabled, # [line_count, coverpoint_count] histogram if @@ -2439,6 +2442,10 @@ sub parse_cov_filters(@) "branch filter enabled but neither branch or condition coverage is enabled" ); } + lcovutil::ignorable_warning($ERROR_USAGE, + "'mcdc' filter enabled but MC/DC coverage is not enabled.") + if (defined($cov_filter[$FILTER_MCDC_SINGLE]) && + !$mcdc_coverage); if ($cov_filter[$FILTER_BRANCH_NO_COND]) { # turn on exception and orphan filtering too $cov_filter[$FILTER_EXCEPTION_BRANCH] = ['exception', 0, 0]; @@ -7432,6 +7439,8 @@ sub _filterFile my $directive = $cov_filter[$FILTER_DIRECTIVE]; my $omit = $cov_filter[$FILTER_OMIT_PATTERNS] if defined($FILTER_OMIT_PATTERNS); + my $mcdc_single = $cov_filter[$FILTER_MCDC_SINGLE] + if defined($FILTER_MCDC_SINGLE && $lcovutil::mcdc_coverage); my $context = MessageContext->new("filtering $source_file"); if (lcovutil::is_filter_enabled()) { @@ -7637,7 +7646,23 @@ sub _filterFile } } # foreach line } # if branch_coverage - # Line related data + if ($mcdc_single) { + # find single-expression MC/DC's - if there is a matching branch + # expression on the same line, then remove the MC/DC + foreach my $line ($mcdc_count->keylist()) { + my $block = $mcdc_count->value($line); + my $groups = $block->groups(); + if (exists($groups->{1}) && + scalar(keys %$groups) == 1) { + my $branch = $testbrcount->value($line); + next unless $branch && ($branch->totals())[0] == 2; + $mcdc_count->remove($line); + ++$mcdc_single->[-2]; # one MC/DC skipped + + $mcdc->remove($line); # remove at top + } + } + } next unless $region || $range || @@ -7647,6 +7672,7 @@ sub _filterFile $omit || $filter_initializer_list; + # Line related data my %initializerListRange; foreach my $line ($testcount->keylist()) { # don't suppresss if this line has associated branch or MC/DC data diff --git a/man/genhtml.1 b/man/genhtml.1 index 084ad9d..2c293e0 100644 --- a/man/genhtml.1 +++ b/man/genhtml.1 @@ -2236,6 +2236,13 @@ Exclude lines which appear to be part of a C++ std::initializer_list. alias for "\-\-filter brace,blank". .PP +.IP mcdc: 3 +Remove MC/DC coverpoint which contains single expression, if 'branch' coverpoint +is present on the same line. +Singe-element MC/DC coverpoints are identical to the corresponding branch - except +in the case of compile-time expression evaluation, for example, in a template +function. + .IP orphan: 3 Remove branches which appear by themselves - .I i.e., diff --git a/tests/lcov/mcdc/main.cpp b/tests/lcov/mcdc/main.cpp index e7cd34e..3ba9bdc 100644 --- a/tests/lcov/mcdc/main.cpp +++ b/tests/lcov/mcdc/main.cpp @@ -21,4 +21,3 @@ int main(int ac, char ** av) #endif return 0; } - diff --git a/tests/lcov/mcdc/mcdc.sh b/tests/lcov/mcdc/mcdc.sh index 42c2ce1..1b65a2e 100755 --- a/tests/lcov/mcdc/mcdc.sh +++ b/tests/lcov/mcdc/mcdc.sh @@ -104,7 +104,7 @@ PARENT=`(cd .. ; pwd)` LCOV_OPTS="--branch-coverage $PARALLEL $PROFILE" -rm -rf *.xml *.dat *.info *.jsn cover_one *_rpt *Test[123]* +rm -rf *.xml *.dat *.info *.jsn cover_one *_rpt *Test[123]* *.gcno *.gcda gccTest* llvmTest* if [ "x$COVER" != "x" ] && [ $LOCAL_COVERAGE == 1 ]; then cover -delete @@ -170,21 +170,25 @@ function runClang() function runGcc() { + NAME=$1 + shift + ARG=$1 + shift # runGcc exeName srcFile flags - g++ --coverage -fcondition-coverage -o $1 main.cpp test.cpp $2 + eval g++ --coverage -fcondition-coverage -o $NAME main.cpp test.cpp $ARG if [ $? != 0 ] ; then - echo "ERROR from g++ $1" + echo "ERROR from g++ $NAME" return 1 fi - ./$1 - $COVER $GENINFO_TOOL -o $1.info --mcdc --branch $1-test.gcda + ./$NAME + $COVER $GENINFO_TOOL -o $NAME.info --mcdc --branch $NAME-test.gcda $@ if [ $? != 0 ] ; then - echo "ERROR from geninfo $1" + echo "ERROR from geninfo $NAME" return 1 fi - $COVER $GENHTML_TOOL --flat --branch --mcdc -o $1_rpt $1.info + $COVER $GENHTML_TOOL --flat --branch --mcdc -o ${NAME}_rpt $NAME.info if [ $? != 0 ] ; then - echo "ERROR from genhtml $1" + echo "ERROR from genhtml $NAME" return 1 fi rm -f *.gcda *.gcno @@ -232,6 +236,55 @@ if [ "$ENABLE_MCDC" == 1 ] ; then exit 1 fi fi + runGcc gccTest4 '-DSENS2 -DSIMPLE' --filter mcdc + if [ $? != 0 ] ; then + STATUS=1 + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi + # the MC/DC should have been filtered out - in favor of the branch + COUNT=`grep -c MCDC gccTest4.info` + if [ 0 != "$COUNT" ] ; then + STATUS=1 + echo "filter error MC/DC" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi + runGcc gccTest4a '-DSENS2 -DSIMPLE' + if [ $? != 0 ] ; then + STATUS=1 + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi + # the MC/DC shouldn't be filtered + COUNT=`grep -c MCDC gccTest4a.info` + if [ 0 == "$COUNT" ] ; then + STATUS=1 + echo "filter error2 MC/DC" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi + + runGcc gccTest5 -DSENS2 --filter mcdc + if [ $? != 0 ] ; then + STATUS=1 + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi + # the MC/DC shouldn't have been filtered out + COUNT=`grep -c MCDC gccTest5.info` + if [ 0 == "$COUNT" ] ; then + STATUS=1 + echo "MC/DC filter error" + if [ $KEEP_GOING == 0 ] ; then + exit 1 + fi + fi else echo "SKIPPING MC/DC tests: ancient compiler" fi @@ -258,7 +311,7 @@ if [ "$ENABLE_LLVM" == 1 ] ; then exit 1 fi fi -else +else echo "SKIPPING LLVM tests" fi diff --git a/tests/lcov/mcdc/test.cpp b/tests/lcov/mcdc/test.cpp index 9e145f3..5c1a2b3 100644 --- a/tests/lcov/mcdc/test.cpp +++ b/tests/lcov/mcdc/test.cpp @@ -8,9 +8,13 @@ void test(int a, int b, int c) { - if (a && (b || c)) { + if +#ifdef SIMPLE + (a) +#else + (a && (b || c)) +#endif printf("%d && (%d || %d)\n", a, b, c); - } else { + else printf("not..\n"); - } }