mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-06 05:40:54 -06:00
Found via `codespell -q 3 -I ../cmake-whitelist.txt --skip="./Utilities"` where the whitelist consists of ``` aci ans behaviour buil convertor dum earch ect emmited emmitted helpfull iff isnt ith lowercased mose nd nknown nto objext ot pathes pevents splitted substract superceded supercedes te tim todays uint upto whitespaces ```
249 lines
7.8 KiB
C++
249 lines
7.8 KiB
C++
#include "cmParseGTMCoverage.h"
|
|
|
|
#include "cmCTest.h"
|
|
#include "cmCTestCoverageHandler.h"
|
|
#include "cmSystemTools.h"
|
|
|
|
#include "cmsys/Directory.hxx"
|
|
#include "cmsys/FStream.hxx"
|
|
#include <map>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <vector>
|
|
|
|
cmParseGTMCoverage::cmParseGTMCoverage(cmCTestCoverageHandlerContainer& cont,
|
|
cmCTest* ctest)
|
|
: cmParseMumpsCoverage(cont, ctest)
|
|
{
|
|
}
|
|
|
|
bool cmParseGTMCoverage::LoadCoverageData(const char* d)
|
|
{
|
|
// load all the .mcov files in the specified directory
|
|
cmsys::Directory dir;
|
|
if (!dir.Load(d)) {
|
|
return false;
|
|
}
|
|
size_t numf;
|
|
unsigned int i;
|
|
numf = dir.GetNumberOfFiles();
|
|
for (i = 0; i < numf; i++) {
|
|
std::string file = dir.GetFile(i);
|
|
if (file != "." && file != ".." && !cmSystemTools::FileIsDirectory(file)) {
|
|
std::string path = d;
|
|
path += "/";
|
|
path += file;
|
|
if (cmSystemTools::GetFilenameLastExtension(path) == ".mcov") {
|
|
if (!this->ReadMCovFile(path.c_str())) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool cmParseGTMCoverage::ReadMCovFile(const char* file)
|
|
{
|
|
cmsys::ifstream in(file);
|
|
if (!in) {
|
|
return false;
|
|
}
|
|
std::string line;
|
|
std::string lastfunction;
|
|
std::string lastroutine;
|
|
std::string lastpath;
|
|
int lastoffset = 0;
|
|
while (cmSystemTools::GetLineFromStream(in, line)) {
|
|
// only look at lines that have coverage data
|
|
if (line.find("^ZZCOVERAGE") == std::string::npos) {
|
|
continue;
|
|
}
|
|
std::string filepath;
|
|
std::string function;
|
|
std::string routine;
|
|
int linenumber = 0;
|
|
int count = 0;
|
|
this->ParseMCOVLine(line, routine, function, linenumber, count);
|
|
// skip this one
|
|
if (routine == "RSEL") {
|
|
continue;
|
|
}
|
|
// no need to search the file if we just did it
|
|
if (function == lastfunction && lastroutine == routine) {
|
|
if (!lastpath.empty()) {
|
|
this->Coverage.TotalCoverage[lastpath][lastoffset + linenumber] +=
|
|
count;
|
|
} else {
|
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
|
"Can not find mumps file : "
|
|
<< lastroutine
|
|
<< " referenced in this line of mcov data:\n"
|
|
"["
|
|
<< line << "]\n");
|
|
}
|
|
continue;
|
|
}
|
|
// Find the full path to the file
|
|
bool found = this->FindMumpsFile(routine, filepath);
|
|
if (found) {
|
|
int lineoffset = 0;
|
|
if (this->FindFunctionInMumpsFile(filepath, function, lineoffset)) {
|
|
cmCTestCoverageHandlerContainer::SingleFileCoverageVector&
|
|
coverageVector = this->Coverage.TotalCoverage[filepath];
|
|
// This section accounts for lines that were previously marked
|
|
// as non-executable code (-1), if the parser comes back with
|
|
// a non-zero count, increase the count by 1 to push the line
|
|
// into the executable code set in addition to the count found.
|
|
if (coverageVector[lineoffset + linenumber] == -1 && count > 0) {
|
|
coverageVector[lineoffset + linenumber] += count + 1;
|
|
} else {
|
|
coverageVector[lineoffset + linenumber] += count;
|
|
}
|
|
lastoffset = lineoffset;
|
|
}
|
|
} else {
|
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
|
"Can not find mumps file : "
|
|
<< routine
|
|
<< " referenced in this line of mcov data:\n"
|
|
"["
|
|
<< line << "]\n");
|
|
}
|
|
lastfunction = function;
|
|
lastroutine = routine;
|
|
lastpath = filepath;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool cmParseGTMCoverage::FindFunctionInMumpsFile(std::string const& filepath,
|
|
std::string const& function,
|
|
int& lineoffset)
|
|
{
|
|
cmsys::ifstream in(filepath.c_str());
|
|
if (!in) {
|
|
return false;
|
|
}
|
|
std::string line;
|
|
int linenum = 0;
|
|
while (cmSystemTools::GetLineFromStream(in, line)) {
|
|
std::string::size_type pos = line.find(function);
|
|
if (pos == 0) {
|
|
char nextchar = line[function.size()];
|
|
if (nextchar == ' ' || nextchar == '(' || nextchar == '\t') {
|
|
lineoffset = linenum;
|
|
return true;
|
|
}
|
|
}
|
|
if (pos == 1) {
|
|
char prevchar = line[0];
|
|
char nextchar = line[function.size() + 1];
|
|
if (prevchar == '%' && (nextchar == ' ' || nextchar == '(')) {
|
|
lineoffset = linenum;
|
|
return true;
|
|
}
|
|
}
|
|
linenum++; // move to next line count
|
|
}
|
|
lineoffset = 0;
|
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
|
"Could not find entry point : " << function << " in " << filepath
|
|
<< "\n");
|
|
return false;
|
|
}
|
|
|
|
bool cmParseGTMCoverage::ParseMCOVLine(std::string const& line,
|
|
std::string& routine,
|
|
std::string& function, int& linenumber,
|
|
int& count)
|
|
{
|
|
// this method parses lines from the .mcov file
|
|
// each line has ^COVERAGE(...) in it, and there
|
|
// are several variants of coverage lines:
|
|
//
|
|
// ^COVERAGE("DIC11","PR1",0)="2:0:0:0"
|
|
// ( file , entry, line ) = "number_executed:timing_info"
|
|
// ^COVERAGE("%RSEL","SRC")="1:0:0:0"
|
|
// ( file , entry ) = "number_executed:timing_info"
|
|
// ^COVERAGE("%RSEL","init",8,"FOR_LOOP",1)=1
|
|
// ( file , entry, line, IGNORE ) =number_executed
|
|
std::vector<std::string> args;
|
|
std::string::size_type pos = line.find('(', 0);
|
|
// if no ( is found, then return line has no coverage
|
|
if (pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
std::string arg;
|
|
bool done = false;
|
|
// separate out all of the comma separated arguments found
|
|
// in the COVERAGE(...) line
|
|
while (line[pos] && !done) {
|
|
// save the char we are looking at
|
|
char cur = line[pos];
|
|
// , or ) means end of argument
|
|
if (cur == ',' || cur == ')') {
|
|
// save the argument into the argument vector
|
|
args.push_back(arg);
|
|
// start on a new argument
|
|
arg.clear();
|
|
// if we are at the end of the ), then finish while loop
|
|
if (cur == ')') {
|
|
done = true;
|
|
}
|
|
} else {
|
|
// all chars except ", (, and % get stored in the arg string
|
|
if (cur != '\"' && cur != '(' && cur != '%') {
|
|
arg.append(1, line[pos]);
|
|
}
|
|
}
|
|
// move to next char
|
|
pos++;
|
|
}
|
|
// now parse the right hand side of the =
|
|
pos = line.find('=');
|
|
// no = found, this is an error
|
|
if (pos == std::string::npos) {
|
|
return false;
|
|
}
|
|
pos++; // move past =
|
|
|
|
// if the next positing is not a ", then this is a
|
|
// COVERAGE(..)=count line and turn the rest of the string
|
|
// past the = into an integer and set it to count
|
|
if (line[pos] != '\"') {
|
|
count = atoi(line.substr(pos).c_str());
|
|
} else {
|
|
// this means line[pos] is a ", and we have a
|
|
// COVERAGE(...)="1:0:0:0" type of line
|
|
pos++; // move past "
|
|
// find the first : past the "
|
|
std::string::size_type pos2 = line.find(':', pos);
|
|
// turn the string between the " and the first : into an integer
|
|
// and set it to count
|
|
count = atoi(line.substr(pos, pos2 - pos).c_str());
|
|
}
|
|
// less then two arguments is an error
|
|
if (args.size() < 2) {
|
|
cmCTestLog(this->CTest, ERROR_MESSAGE,
|
|
"Error parsing mcov line: [" << line << "]\n");
|
|
return false;
|
|
}
|
|
routine = args[0]; // the routine is the first argument
|
|
function = args[1]; // the function in the routine is the second
|
|
// in the two argument only format
|
|
// ^COVERAGE("%RSEL","SRC"), the line offset is 0
|
|
if (args.size() == 2) {
|
|
// To avoid double counting of line 0 of each entry point,
|
|
// Don't count the lines that do not give an explicit line
|
|
// number.
|
|
routine.clear();
|
|
function.clear();
|
|
} else {
|
|
// this is the format for this line
|
|
// ^COVERAGE("%RSEL","SRC",count)
|
|
linenumber = atoi(args[2].c_str());
|
|
}
|
|
return true;
|
|
}
|