Index: llvm/trunk/tools/sancov/sancov.cc =================================================================== --- llvm/trunk/tools/sancov/sancov.cc +++ llvm/trunk/tools/sancov/sancov.cc @@ -628,32 +628,21 @@ CovAddrInfo = getAddrInfo(ObjectFile, Addrs, true); } - // Compute number of functions hit/total in a file. - // file_name -> - std::map> computeFileFnCoverage() { + // Compute number of coverage points hit/total in a file. + // file_name -> + std::map> computeFileCoverage() { std::map> FileCoverage; auto AllCovPointsByFile = group_by(AllAddrInfo, [](const AddrInfo &AI) { return AI.FileName; }); - auto CovPointByFile = + auto CovPointsByFile = group_by(CovAddrInfo, [](const AddrInfo &AI) { return AI.FileName; }); - for (auto P : AllCovPointsByFile) { + for (const auto &P : AllCovPointsByFile) { const std::string &FileName = P.first; - const auto &AllCovInfo = P.second; - auto AllFns = group_by( - AllCovInfo, [](const AddrInfo &AI) { return AI.FunctionName; }); - size_t AllCoverage = AllFns.size(); - size_t Coverage = 0; - - auto It = CovPointByFile.find(FileName); - if (It != CovPointByFile.end()) { - const auto &CovInfo = It->second; - auto Fns = group_by(CovInfo, - [](const AddrInfo &AI) { return AI.FunctionName; }); - Coverage = Fns.size(); - } - FileCoverage[FileName] = std::make_pair(Coverage, AllCoverage); + FileCoverage[FileName] = + std::make_pair(CovPointsByFile[FileName].size(), + AllCovPointsByFile[FileName].size()); } return FileCoverage; } @@ -688,6 +677,14 @@ return StatusMap; } + std::set computeAllFunctions() const { + std::set Fns; + for (const auto &AI : AllAddrInfo) { + Fns.insert(FileFn{AI.FileName, AI.FunctionName}); + } + return Fns; + } + std::set computeCoveredFunctions() const { std::set Fns; auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) { @@ -718,6 +715,25 @@ return Fns; } + // Compute % coverage for each function. + std::map computeFunctionsCoverage() const { + std::map FnCoverage; + auto AllFns = group_by(AllAddrInfo, [](const AddrInfo &AI) { + return FileFn{AI.FileName, AI.FunctionName}; + }); + + auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) { + return FileFn{AI.FileName, AI.FunctionName}; + }); + + for (const auto &P : AllFns) { + FileFn F = P.first; + FnCoverage[F] = CovFns[F].size() * 100 / P.second.size(); + } + + return FnCoverage; + } + typedef std::map> FunctionLocs; // finds first line number in a file for each function. FunctionLocs resolveFunctions(const std::set &Fns) const { @@ -812,13 +828,16 @@ SourceCoverageData SCovData(ObjectFile, *Addrs); auto LineStatusMap = SCovData.computeLineStatusMap(); - // file_name -> [file_fn]. - auto NotCoveredFns = SCovData.computeNotCoveredFunctions(); - auto NotCoveredFnMap = group_by( - NotCoveredFns, [](const FileFn &FileFn) { return FileFn.FileName; }); + std::set AllFns = SCovData.computeAllFunctions(); // file_loc -> set[function_name] - auto NotCoveredFnByLoc = SCovData.resolveFunctions(NotCoveredFns); - auto FileFnCoverage = SCovData.computeFileFnCoverage(); + auto AllFnsByLoc = SCovData.resolveFunctions(AllFns); + auto FileCoverage = SCovData.computeFileCoverage(); + + auto FnCoverage = SCovData.computeFunctionsCoverage(); + auto FnCoverageByFile = + group_by(FnCoverage, [](const std::pair &FileFn) { + return FileFn.first.FileName; + }); // TOC @@ -828,10 +847,10 @@ // Covered Files. OS << "
Touched Files\n"; OS << "\n"; - OS << ""; + OS << ""; OS << "\n"; for (auto FileName : Files) { - std::pair FC = FileFnCoverage[FileName]; + std::pair FC = FileCoverage[FileName]; if (FC.first == 0) { NotCoveredFilesCount++; continue; @@ -852,7 +871,7 @@ OS << "
Not Touched Files\n"; OS << "
FileHit Fns %
FileCoverage %Hit (Total) Fns
\n"; for (auto FileName : Files) { - std::pair FC = FileFnCoverage[FileName]; + std::pair FC = FileCoverage[FileName]; if (FC.first == 0) OS << "\n"; } @@ -864,25 +883,27 @@ // Source for (auto FileName : Files) { - std::pair FC = FileFnCoverage[FileName]; + std::pair FC = FileCoverage[FileName]; if (FC.first == 0) continue; OS << "\n"; OS << "

" << stripPathPrefix(FileName) << "

\n"; + OS << "
Function Coverage"; + OS << "
\n"; - auto NotCoveredFns = NotCoveredFnMap.find(FileName); - if (NotCoveredFns != NotCoveredFnMap.end()) { - OS << "
Not Covered Functions"; - OS << "
" << stripPathPrefix(FileName) << "
\n"; - for (auto FileFn : NotCoveredFns->second) { - OS << "\n"; - } - OS << "
"; - OS << ""; - OS << escapeHtml(FileFn.FunctionName) << ""; - OS << "
\n"; + auto &FileFnCoverage = FnCoverageByFile[FileName]; + + for (const auto &P : FileFnCoverage) { + std::string FunctionName = P.first.FunctionName; + + OS << "
"; + OS << "" << P.second << "% "; + OS << ""; + OS << escapeHtml(FunctionName) << ""; + OS << "
\n"; } + OS << "\n"; ErrorOr> BufOrErr = MemoryBuffer::getFile(FileName); @@ -900,8 +921,8 @@ uint32_t Line = I.line_number(); { // generate anchors (if any); FileLoc Loc = FileLoc{FileName, Line}; - auto It = NotCoveredFnByLoc.find(Loc); - if (It != NotCoveredFnByLoc.end()) { + auto It = AllFnsByLoc.find(Loc); + if (It != AllFnsByLoc.end()) { for (std::string Fn : It->second) { OS << ""; @@ -1041,6 +1062,10 @@ OS << ".mixed { background: #FF7; }\n"; OS << "summary { font-weight: bold; }\n"; OS << "details > summary + * { margin-left: 1em; }\n"; + OS << ".fnlist { display: flex; flex-flow: column nowrap; }\n"; + OS << ".fn { display: flex; flex-flow: row nowrap; }\n"; + OS << ".pct { width: 3em; text-align: right; margin-right: 1em; }\n"; + OS << ".name { flex: 2; }\n"; OS << "\n"; OS << "" << Title << "\n"; OS << "\n";