@ -1,4 +1,5 @@
# include "coverage.hpp"
# include "compile_commands.hpp"
# include "config.hpp"
# include "filesystem.hpp"
# include "json.hpp"
@ -114,9 +115,75 @@ static std::vector<Coverage::LineCoverage> extract_gcov(JSON &&json, const boost
return { } ;
}
std : : vector < Coverage : : LineCoverage > Coverage : : analyze ( const FileInfo & file_info ) {
if ( file_info . language_id = = " cpp " | | file_info . language_id = = " c " ) {
return extract_gcov ( run_gcov ( file_info . build_path , file_info . object_path ) , file_info . source_path ) ;
static Coverage : : LineCoverage tarpaulin_extract_line ( const JSON & line_json ) {
auto line = static_cast < unsigned long > ( line_json . integer ( " line " ) ) - 1U /* in tarpaulin, line numbers start at 1 */ ;
auto stats = line_json . object_optional ( " stats " ) ;
if ( ! stats ) {
return Coverage : : LineCoverage ( line , 0 ) ;
}
auto count = static_cast < unsigned long > ( stats - > integer_optional ( " Line " ) . value_or ( 0 ) ) ;
// branch and conditionally coverage are not yet implemented in tarpaulin (as of version 0.20.1
return Coverage : : LineCoverage ( line , count ) ;
}
static std : : vector < Coverage : : LineCoverage > tarpaulin_extract_lines ( const std : : vector < JSON > & lines_json ) {
std : : vector < Coverage : : LineCoverage > lines ;
lines . reserve ( lines_json . size ( ) ) ;
std : : transform ( lines_json . begin ( ) , lines_json . end ( ) , std : : back_inserter ( lines ) , tarpaulin_extract_line ) ;
std : : sort ( lines . begin ( ) , lines . end ( ) ) ;
return lines ;
}
static std : : vector < Coverage : : LineCoverage > extract_tarpaulin ( JSON & & json , const boost : : filesystem : : path & source_file ) {
auto traces = json . object_optional ( " traces " ) ;
if ( ! traces ) {
return { } ;
}
auto file_traces = traces - > array_optional ( source_file . string ( ) ) ;
if ( ! file_traces ) {
return { } ;
}
return tarpaulin_extract_lines ( * file_traces ) ;
}
std : : vector < Coverage : : LineCoverage > Coverage : : analyze ( Project : : Build & build , const boost : : filesystem : : path & file_path , const std : : string & language_id ) {
if ( language_id = = " cpp " | | language_id = = " c " ) {
CompileCommands commands ( build . get_default_path ( ) ) ;
boost : : filesystem : : path object_file ;
for ( const auto & command : commands . commands ) {
if ( command . file = = file_path ) {
auto values = command . parameter_values ( " -o " ) ;
if ( ! values . empty ( ) ) {
object_file = command . directory / values . front ( ) ;
break ;
}
}
}
if ( object_file . empty ( ) ) {
Terminal : : get ( ) . async_print ( file_path . filename ( ) . string ( ) + " : could not find the C/C++ object file " , true ) ;
return std : : vector < Coverage : : LineCoverage > { } ;
}
return extract_gcov ( run_gcov ( build . get_default_path ( ) , object_file ) , file_path ) ;
}
if ( language_id = = " rust " & & dynamic_cast < Project : : CargoBuild * > ( & build ) ) {
auto tarpaulin_folder = filesystem : : get_canonical_path ( build . get_default_path ( ) / " .. " / " tarpaulin " ) ;
if ( ! boost : : filesystem : : exists ( tarpaulin_folder ) | | ! boost : : filesystem : : is_directory ( tarpaulin_folder ) ) {
Terminal : : get ( ) . async_print ( " Directory ' " + tarpaulin_folder . string ( ) + " ' does not exist, you may need to generate the coverage report via: cargo tarpaulin " , true ) ;
return std : : vector < Coverage : : LineCoverage > { } ;
}
for ( const auto & file : boost : : filesystem : : directory_iterator ( tarpaulin_folder ) ) {
if ( boost : : filesystem : : is_regular ( file . path ( ) ) & & file . path ( ) . extension ( ) . string ( ) = = " .json " ) {
return extract_tarpaulin ( JSON ( file . path ( ) ) , file_path ) ;
}
}
Terminal : : get ( ) . async_print ( " No JSON coverage file found in ' " + tarpaulin_folder . string ( ) + " ', you may need to generate the coverage report via: cargo tarpaulin " , true ) ;
return std : : vector < Coverage : : LineCoverage > { } ;
}
return { } ;
}