[llvm] r216300 - llvm-cov: add code coverage tool that's based on coverage mapping format and clang's pgo.
Alex L
arphaman at gmail.com
Fri Aug 22 17:54:07 PDT 2014
The big-endian buildbots are failing, I will commit an XFAIL for big-endian
for now.
2014-08-22 15:56 GMT-07:00 Alex Lorenz <arphaman at gmail.com>:
> Author: arphaman
> Date: Fri Aug 22 17:56:03 2014
> New Revision: 216300
>
> URL: http://llvm.org/viewvc/llvm-project?rev=216300&view=rev
> Log:
> llvm-cov: add code coverage tool that's based on coverage mapping format
> and clang's pgo.
>
> This commit expands llvm-cov's functionality by adding support for a new
> code coverage
> tool that uses LLVM's coverage mapping format and clang's instrumentation
> based profiling.
> The gcov compatible tool can be invoked by supplying the 'gcov' command as
> the first argument,
> or by modifying the tool's name to end with 'gcov'.
>
> Differential Revision: http://reviews.llvm.org/D4445
>
> Added:
> llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping
> (with props)
> llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata
> (with props)
> llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping
> (with props)
> llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata
> (with props)
> llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping (with
> props)
> llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata (with
> props)
> llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
> llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
> llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
> llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
> llvm/trunk/tools/llvm-cov/CoverageFilters.cpp
> llvm/trunk/tools/llvm-cov/CoverageFilters.h
> llvm/trunk/tools/llvm-cov/CoverageReport.cpp
> llvm/trunk/tools/llvm-cov/CoverageReport.h
> llvm/trunk/tools/llvm-cov/CoverageSummary.cpp
> llvm/trunk/tools/llvm-cov/CoverageSummary.h
> llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
> llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
> llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
> llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h
> llvm/trunk/tools/llvm-cov/RenderingSupport.h
> llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
> llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
> llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
> llvm/trunk/tools/llvm-cov/SourceCoverageView.h
> llvm/trunk/tools/llvm-cov/TestingSupport.cpp
> Modified:
> llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp
> llvm/trunk/test/tools/llvm-cov/Inputs/README
> llvm/trunk/tools/llvm-cov/CMakeLists.txt
> llvm/trunk/tools/llvm-cov/LLVMBuild.txt
> llvm/trunk/tools/llvm-cov/Makefile
> llvm/trunk/tools/llvm-cov/llvm-cov.cpp
>
> Modified: llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp (original)
> +++ llvm/trunk/lib/ProfileData/CoverageMappingReader.cpp Fri Aug 22
> 17:56:03 2014
> @@ -289,18 +289,6 @@ ObjectFileCoverageMappingReader::ObjectF
> Object = std::move(File.get());
> }
>
> -ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
> - std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type)
> - : CurrentRecord(0) {
> - auto File = object::ObjectFile::createObjectFile(
> - ObjectBuffer->getMemBufferRef(), Type);
> - if (!File)
> - error(File.getError());
> - else
> - Object = OwningBinary<ObjectFile>(std::move(File.get()),
> - std::move(ObjectBuffer));
> -}
> -
> namespace {
> /// \brief The coverage mapping data for a single function.
> /// It points to the function's name.
> @@ -347,19 +335,11 @@ struct SectionData {
>
> template <typename T>
> std::error_code readCoverageMappingData(
> - SectionRef &ProfileNames, SectionRef &CoverageMapping,
> + SectionData &ProfileNames, StringRef Data,
> std::vector<ObjectFileCoverageMappingReader::ProfileMappingRecord>
> &Records,
> std::vector<StringRef> &Filenames) {
> llvm::DenseSet<T> UniqueFunctionMappingData;
>
> - // Get the contents of the given sections.
> - StringRef Data;
> - if (auto Err = CoverageMapping.getContents(Data))
> - return Err;
> - SectionData ProfileNamesData;
> - if (auto Err = ProfileNamesData.load(ProfileNames))
> - return Err;
> -
> // Read the records in the coverage data section.
> while (!Data.empty()) {
> if (Data.size() < sizeof(CoverageMappingTURecord<T>))
> @@ -418,9 +398,9 @@ std::error_code readCoverageMappingData(
> continue;
> UniqueFunctionMappingData.insert(MappingRecord.FunctionNamePtr);
> StringRef FunctionName;
> - if (auto Err = ProfileNamesData.get(MappingRecord.FunctionNamePtr,
> - MappingRecord.FunctionNameSize,
> - FunctionName))
> + if (auto Err =
> + ProfileNames.get(MappingRecord.FunctionNamePtr,
> + MappingRecord.FunctionNameSize,
> FunctionName))
> return Err;
>
> Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord(
> Version, FunctionName, MappingRecord.FunctionHash, Mapping,
> @@ -431,6 +411,63 @@ std::error_code readCoverageMappingData(
> return instrprof_error::success;
> }
>
> +static const char *TestingFormatMagic = "llvmcovmtestdata";
> +
> +static std::error_code decodeTestingFormat(StringRef Data,
> + SectionData &ProfileNames,
> + StringRef &CoverageMapping) {
> + Data = Data.substr(StringRef(TestingFormatMagic).size());
> + if (Data.size() < 1)
> + return instrprof_error::truncated;
> + unsigned N = 0;
> + auto ProfileNamesSize =
> + decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
> + if (N > Data.size())
> + return instrprof_error::malformed;
> + Data = Data.substr(N);
> + if (Data.size() < 1)
> + return instrprof_error::truncated;
> + N = 0;
> + ProfileNames.Address =
> + decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);
> + if (N > Data.size())
> + return instrprof_error::malformed;
> + Data = Data.substr(N);
> + if (Data.size() < ProfileNamesSize)
> + return instrprof_error::malformed;
> + ProfileNames.Data = Data.substr(0, ProfileNamesSize);
> + CoverageMapping = Data.substr(ProfileNamesSize);
> + return instrprof_error::success;
> +}
> +
> +ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader(
> + std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type)
> + : CurrentRecord(0) {
> + if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) {
> + // This is a special format used for testing.
> + SectionData ProfileNames;
> + StringRef CoverageMapping;
> + if (auto Err = decodeTestingFormat(ObjectBuffer->getBuffer(),
> ProfileNames,
> + CoverageMapping)) {
> + error(Err);
> + return;
> + }
> + error(readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping,
> + MappingRecords, Filenames));
> + Object = OwningBinary<ObjectFile>(std::unique_ptr<ObjectFile>(),
> + std::move(ObjectBuffer));
> + return;
> + }
> +
> + auto File = object::ObjectFile::createObjectFile(
> + ObjectBuffer->getMemBufferRef(), Type);
> + if (!File)
> + error(File.getError());
> + else
> + Object = OwningBinary<ObjectFile>(std::move(File.get()),
> + std::move(ObjectBuffer));
> +}
> +
> std::error_code ObjectFileCoverageMappingReader::readHeader() {
> ObjectFile *OF = Object.getBinary().get();
> if (!OF)
> @@ -457,13 +494,21 @@ std::error_code ObjectFileCoverageMappin
> if (FoundSectionCount != 2)
> return error(instrprof_error::bad_header);
>
> + // Get the contents of the given sections.
> + StringRef Data;
> + if (auto Err = CoverageMapping.getContents(Data))
> + return Err;
> + SectionData ProfileNamesData;
> + if (auto Err = ProfileNamesData.load(ProfileNames))
> + return Err;
> +
> // Load the data from the found sections.
> std::error_code Err;
> if (BytesInAddress == 4)
> - Err = readCoverageMappingData<uint32_t>(ProfileNames, CoverageMapping,
> + Err = readCoverageMappingData<uint32_t>(ProfileNamesData, Data,
> MappingRecords, Filenames);
> else
> - Err = readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping,
> + Err = readCoverageMappingData<uint64_t>(ProfileNamesData, Data,
> MappingRecords, Filenames);
> if (Err)
> return error(Err);
>
> Modified: llvm/trunk/test/tools/llvm-cov/Inputs/README
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/README?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-cov/Inputs/README (original)
> +++ llvm/trunk/test/tools/llvm-cov/Inputs/README Fri Aug 22 17:56:03 2014
> @@ -1,7 +1,21 @@
> These inputs were pre-generated to allow for easier testing of llvm-cov.
>
> -test.gcno and test.gcda were create by running clang:
> - clang++ -g -ftest-coverage -fprofile-arcs test.cpp
> +The files used to test the gcov compatible code coverage tool were
> generated
> +using the following method:
>
> -test.cpp.gcov was created by running gcov 4.2.1:
> - gcov test.cpp
> + test.gcno and test.gcda were create by running clang:
> + clang++ -g -ftest-coverage -fprofile-arcs test.cpp
> +
> + test.cpp.gcov was created by running gcov 4.2.1:
> + gcov test.cpp
> +
> +The 'covmapping' files that are used to test llvm-cov contain raw sections
> +with the coverage mapping data generated by the compiler and linker. They
> are
> +created by running clang and llvm-cov:
> + clang++ -fprofile-instr-generate -fcoverage-mapping -o test test.cpp
> + llvm-cov convert-for-testing -o test.covmapping test
> +
> +The 'profdata' files were generated by running an instrumented version of
> the
> +program and merging the raw profile data using llvm-profdata.
> + ./test
> + llvm-profdata merge -o test.profdata default.profraw
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange:
> llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.covmapping
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange:
> llvm/trunk/test/tools/llvm-cov/Inputs/highlightedRanges.profdata
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange:
> llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.covmapping
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange:
> llvm/trunk/test/tools/llvm-cov/Inputs/lineExecutionCounts.profdata
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.covmapping
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata?rev=216300&view=auto
>
> ==============================================================================
> Binary file - no diff available.
>
> Propchange: llvm/trunk/test/tools/llvm-cov/Inputs/regionMarkers.profdata
>
> ------------------------------------------------------------------------------
> svn:mime-type = application/octet-stream
>
> Added: llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp (added)
> +++ llvm/trunk/test/tools/llvm-cov/showHighlightedRanges.cpp Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,45 @@
> +// RUN: llvm-cov show %S/Inputs/highlightedRanges.covmapping
> -instr-profile %S/Inputs/highlightedRanges.profdata -dump
> -filename-equivalence %s | FileCheck %s
> +
> +void func() {
> + return;
> + int i = 0; // CHECK: Highlighted line [[@LINE]], 3
> -> 12
> +}
> +
> +void func2(int x) {
> + if(x > 5) {
> + while(x >= 9) {
> + return;
> + --x; // CHECK: Highlighted line [[@LINE]], 7
> -> 10
> + }
> + int i = 0; // CHECK: Highlighted line [[@LINE]], 5
> -> 14
> + }
> +}
> +
> +void test() {
> + int x = 0;
> +
> + if (x) { // CHECK: Highlighted line [[@LINE]], 10
> -> ?
> + x = 0; // CHECK: Highlighted line [[@LINE]], 1
> -> ?
> + } else { // CHECK: Highlighted line [[@LINE]], 1
> -> 4
> + x = 1;
> + }
> +
> + // CHECK: Highlighted line [[@LINE+1]],
> 26 -> 29
> + for (int i = 0; i < 0; ++i) { // CHECK: Highlighted line [[@LINE]],
> 31 -> ?
> + x = 1; // CHECK: Highlighted line [[@LINE]], 1
> -> ?
> + } // CHECK: Highlighted line [[@LINE]], 1
> -> 4
> +
> + x = x < 10 ? x +
> + 1
> + : x - 1; // CHECK: Highlighted line [[@LINE]],
> 16 -> 21
> + x = x > 10 ? x + // CHECK: Highlighted line [[@LINE]],
> 16 -> ?
> + 1 // CHECK: Highlighted line [[@LINE]], 1
> -> 17
> + : x - 1;
> +}
> +
> +int main() {
> + test();
> + func();
> + func2(9);
> + return 0;
> +}
>
> Added: llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp (added)
> +++ llvm/trunk/test/tools/llvm-cov/showLineExecutionCounts.cpp Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,22 @@
> +// RUN: llvm-cov show %S/Inputs/lineExecutionCounts.covmapping
> -instr-profile %S/Inputs/lineExecutionCounts.profdata -no-colors
> -filename-equivalence %s | FileCheck %s
> +
> +int main() { // CHECK: 1| [[@LINE]]|int
> main(
> + int x = 0; // CHECK: 1| [[@LINE]]| int x
> + // CHECK: 1| [[@LINE]]|
> + if (x) { // CHECK: 0| [[@LINE]]| if (x)
> + x = 0; // CHECK: 0| [[@LINE]]| x =
> 0
> + } else { // CHECK: 1| [[@LINE]]| } else
> + x = 1; // CHECK: 1| [[@LINE]]| x =
> 1
> + } // CHECK: 1| [[@LINE]]| }
> + // CHECK: 1| [[@LINE]]|
> + for (int i = 0; i < 100; ++i) { // CHECK: 100| [[@LINE]]| for (
> + x = 1; // CHECK: 100| [[@LINE]]| x =
> 1
> + } // CHECK: 100| [[@LINE]]| }
> + // CHECK: 1| [[@LINE]]|
> + x = x < 10 ? x + 1 : x - 1; // CHECK: 0| [[@LINE]]| x =
> + x = x > 10 ? // CHECK: 1| [[@LINE]]| x =
> + x - 1: // CHECK: 0| [[@LINE]]|
> x
> + x + 1; // CHECK: 1| [[@LINE]]|
> x
> + // CHECK: 1| [[@LINE]]|
> + return 0; // CHECK: 1| [[@LINE]]| return
> +} // CHECK: 1| [[@LINE]]|}
>
> Added: llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp (added)
> +++ llvm/trunk/test/tools/llvm-cov/showRegionMarkers.cpp Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,23 @@
> +// RUN: llvm-cov show %S/Inputs/regionMarkers.covmapping -instr-profile
> %S/Inputs/regionMarkers.profdata -show-regions -dump -filename-equivalence
> %s | FileCheck %s
> +
> +int main() { // CHECK: Marker at [[@LINE]]:12 = 1
> + int x = 0;
> +
> + if (x) { // CHECK: Marker at [[@LINE]]:10 = 0
> + x = 0;
> + } else { // CHECK: Marker at [[@LINE]]:10 = 1
> + x = 1;
> + }
> + // CHECK: Marker at [[@LINE+2]]:19 = 101
> + // CHECK: Marker at [[@LINE+1]]:28 = 100
> + for (int i = 0; i < 100; ++i) { // CHECK: Marker at [[@LINE]]:33 = 100
> + x = 1;
> + }
> + // CHECK: Marker at [[@LINE+1]]:16 = 1
> + x = x < 10 ? x + 1 : x - 1; // CHECK: Marker at [[@LINE]]:24 = 0
> + x = x > 10 ?
> + x - 1: // CHECK: Marker at [[@LINE]]:9 = 0
> + x + 1; // CHECK: Marker at [[@LINE]]:9 = 1
> +
> + return 0;
> +}
>
> Modified: llvm/trunk/tools/llvm-cov/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CMakeLists.txt?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CMakeLists.txt (original)
> +++ llvm/trunk/tools/llvm-cov/CMakeLists.txt Fri Aug 22 17:56:03 2014
> @@ -1,6 +1,14 @@
> -set(LLVM_LINK_COMPONENTS core support )
> +set(LLVM_LINK_COMPONENTS core support object profiledata)
>
> add_llvm_tool(llvm-cov
> llvm-cov.cpp
> gcov.cpp
> + CodeCoverage.cpp
> + CoverageFilters.cpp
> + CoverageReport.cpp
> + CoverageSummary.cpp
> + CoverageSummaryInfo.cpp
> + SourceCoverageDataManager.cpp
> + SourceCoverageView.cpp
> + TestingSupport.cpp
> )
>
> Added: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,709 @@
> +//===- CodeCoverage.cpp - Coverage tool based on profiling
> instrumentation-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// The 'CodeCoverageTool' class implements a command line tool to analyze
> and
> +// report coverage information using the profiling instrumentation and
> code
> +// coverage mapping.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "FunctionCoverageMapping.h"
> +#include "RenderingSupport.h"
> +#include "CoverageViewOptions.h"
> +#include "CoverageFilters.h"
> +#include "SourceCoverageDataManager.h"
> +#include "SourceCoverageView.h"
> +#include "CoverageSummary.h"
> +#include "CoverageReport.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/SmallString.h"
> +#include "llvm/ADT/SmallSet.h"
> +#include "llvm/ADT/DenseSet.h"
> +#include "llvm/ProfileData/InstrProfReader.h"
> +#include "llvm/ProfileData/CoverageMapping.h"
> +#include "llvm/ProfileData/CoverageMappingReader.h"
> +#include "llvm/Support/CommandLine.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/MemoryObject.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/Path.h"
> +#include "llvm/Support/Signals.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include <system_error>
> +#include <functional>
> +
> +using namespace llvm;
> +using namespace coverage;
> +
> +namespace {
> +/// \brief Distribute the functions into instantiation sets.
> +/// An instantiation set is a collection of functions
> +/// that have the same source code, e.g.
> +/// template functions specializations.
> +class FunctionInstantiationSetCollector {
> + ArrayRef<FunctionCoverageMapping> FunctionMappings;
> + typedef uint64_t KeyType;
> + typedef std::vector<const FunctionCoverageMapping *> SetType;
> + std::unordered_map<uint64_t, SetType> InstantiatedFunctions;
> +
> + static KeyType getKey(const MappingRegion &R) {
> + return uint64_t(R.LineStart) | uint64_t(R.ColumnStart) << 32;
> + }
> +
> +public:
> + void insert(const FunctionCoverageMapping &Function, unsigned FileID) {
> + KeyType Key = 0;
> + for (const auto &R : Function.MappingRegions) {
> + if (R.FileID == FileID) {
> + Key = getKey(R);
> + break;
> + }
> + }
> + auto I = InstantiatedFunctions.find(Key);
> + if (I == InstantiatedFunctions.end()) {
> + SetType Set;
> + Set.push_back(&Function);
> + InstantiatedFunctions.insert(std::make_pair(Key, Set));
> + } else
> + I->second.push_back(&Function);
> + }
> +
> + std::unordered_map<KeyType, SetType>::iterator begin() {
> + return InstantiatedFunctions.begin();
> + }
> +
> + std::unordered_map<KeyType, SetType>::iterator end() {
> + return InstantiatedFunctions.end();
> + }
> +};
> +
> +/// \brief The implementation of the coverage tool.
> +class CodeCoverageTool {
> +public:
> + enum Command {
> + /// \brief The show command.
> + Show,
> + /// \brief The report command.
> + Report
> + };
> +
> + /// \brief Print the error message to the error output stream.
> + void error(const Twine &Message, StringRef Whence = "");
> +
> + /// \brief Return a memory buffer for the given source file.
> + ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
> +
> + /// \brief Return true if two filepaths refer to the same file.
> + bool equivalentFiles(StringRef A, StringRef B);
> +
> + /// \brief Collect a set of function's file ids which correspond to the
> + /// given source file. Return false if the set is empty.
> + bool gatherInterestingFileIDs(StringRef SourceFile,
> + const FunctionCoverageMapping &Function,
> + SmallSet<unsigned, 8>
> &InterestingFileIDs);
> +
> + /// \brief Find the file id which is not an expanded file id.
> + bool findMainViewFileID(StringRef SourceFile,
> + const FunctionCoverageMapping &Function,
> + unsigned &MainViewFileID);
> +
> + bool findMainViewFileID(const FunctionCoverageMapping &Function,
> + unsigned &MainViewFileID);
> +
> + /// \brief Create a source view which shows coverage for an expansion
> + /// of a file.
> + void createExpansionSubView(const MappingRegion &ExpandedRegion,
> + const FunctionCoverageMapping &Function,
> + SourceCoverageView &Parent);
> +
> + void createExpansionSubViews(SourceCoverageView &View, unsigned
> ViewFileID,
> + const FunctionCoverageMapping &Function);
> +
> + /// \brief Create a source view which shows coverage for an
> instantiation
> + /// of a funciton.
> + void createInstantiationSubView(StringRef SourceFile,
> + const FunctionCoverageMapping &Function,
> + SourceCoverageView &View);
> +
> + /// \brief Create the main source view of a particular source file.
> + /// Return true if this particular source file is not covered.
> + bool
> + createSourceFileView(StringRef SourceFile, SourceCoverageView &View,
> + ArrayRef<FunctionCoverageMapping>
> FunctionMappingRecords,
> + bool UseOnlyRegionsInMainFile = false);
> +
> + /// \brief Load the coverage mapping data. Return true if an error
> occured.
> + bool load();
> +
> + int run(Command Cmd, int argc, const char **argv);
> +
> + typedef std::function<int(int, const char **)> CommandLineParserType;
> +
> + int show(int argc, const char **argv,
> + CommandLineParserType commandLineParser);
> +
> + int report(int argc, const char **argv,
> + CommandLineParserType commandLineParser);
> +
> + StringRef ObjectFilename;
> + CoverageViewOptions ViewOpts;
> + std::unique_ptr<IndexedInstrProfReader> PGOReader;
> + CoverageFiltersMatchAll Filters;
> + std::vector<std::string> SourceFiles;
> + std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
> + LoadedSourceFiles;
> + std::vector<FunctionCoverageMapping> FunctionMappingRecords;
> + bool CompareFilenamesOnly;
> +};
> +}
> +
> +void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
> + errs() << "error: ";
> + if (!Whence.empty())
> + errs() << Whence << ": ";
> + errs() << Message << "\n";
> +}
> +
> +ErrorOr<const MemoryBuffer &>
> +CodeCoverageTool::getSourceFile(StringRef SourceFile) {
> + SmallString<256> Path(SourceFile);
> + sys::fs::make_absolute(Path);
> + for (const auto &Files : LoadedSourceFiles) {
> + if (sys::fs::equivalent(Path.str(), Files.first)) {
> + return *Files.second;
> + }
> + }
> + auto Buffer = MemoryBuffer::getFile(SourceFile);
> + if (auto EC = Buffer.getError()) {
> + error(EC.message(), SourceFile);
> + return EC;
> + }
> + LoadedSourceFiles.push_back(std::make_pair(
> + std::string(Path.begin(), Path.end()), std::move(Buffer.get())));
> + return *LoadedSourceFiles.back().second;
> +}
> +
> +/// \brief Return a line start - line end range which contains
> +/// all the mapping regions of a given function with a particular file id.
> +std::pair<unsigned, unsigned>
> +findExpandedFileInterestingLineRange(unsigned FileID,
> + const FunctionCoverageMapping
> &Function) {
> + unsigned LineStart = std::numeric_limits<unsigned>::max();
> + unsigned LineEnd = 0;
> + for (const auto &Region : Function.MappingRegions) {
> + if (Region.FileID != FileID)
> + continue;
> + LineStart = std::min(Region.LineStart, LineStart);
> + LineEnd = std::max(Region.LineEnd, LineEnd);
> + }
> + return std::make_pair(LineStart, LineEnd);
> +}
> +
> +bool CodeCoverageTool::equivalentFiles(StringRef A, StringRef B) {
> + if (CompareFilenamesOnly)
> + return sys::path::filename(A).equals_lower(sys::path::filename(B));
> + return sys::fs::equivalent(A, B);
> +}
> +
> +bool CodeCoverageTool::gatherInterestingFileIDs(
> + StringRef SourceFile, const FunctionCoverageMapping &Function,
> + SmallSet<unsigned, 8> &InterestingFileIDs) {
> + bool Interesting = false;
> + for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
> + if (equivalentFiles(SourceFile, Function.Filenames[I])) {
> + InterestingFileIDs.insert(I);
> + Interesting = true;
> + }
> + }
> + return Interesting;
> +}
> +
> +bool
> +CodeCoverageTool::findMainViewFileID(StringRef SourceFile,
> + const FunctionCoverageMapping
> &Function,
> + unsigned &MainViewFileID) {
> + llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(),
> false);
> + llvm::SmallVector<bool, 8>
> FilenameEquivalence(Function.Filenames.size(),
> + false);
> + for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
> + if (equivalentFiles(SourceFile, Function.Filenames[I]))
> + FilenameEquivalence[I] = true;
> + }
> + for (const auto &Region : Function.MappingRegions) {
> + if (Region.Kind == MappingRegion::ExpansionRegion &&
> + FilenameEquivalence[Region.FileID])
> + IsExpandedFile[Region.ExpandedFileID] = true;
> + }
> + for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
> + if (!FilenameEquivalence[I] || IsExpandedFile[I])
> + continue;
> + MainViewFileID = I;
> + return false;
> + }
> + return true;
> +}
> +
> +bool
> +CodeCoverageTool::findMainViewFileID(const FunctionCoverageMapping
> &Function,
> + unsigned &MainViewFileID) {
> + llvm::SmallVector<bool, 8> IsExpandedFile(Function.Filenames.size(),
> false);
> + for (const auto &Region : Function.MappingRegions) {
> + if (Region.Kind == MappingRegion::ExpansionRegion)
> + IsExpandedFile[Region.ExpandedFileID] = true;
> + }
> + for (unsigned I = 0, E = Function.Filenames.size(); I < E; ++I) {
> + if (IsExpandedFile[I])
> + continue;
> + MainViewFileID = I;
> + return false;
> + }
> + return true;
> +}
> +
> +void CodeCoverageTool::createExpansionSubView(
> + const MappingRegion &ExpandedRegion,
> + const FunctionCoverageMapping &Function, SourceCoverageView &Parent) {
> + auto ExpandedLines = findExpandedFileInterestingLineRange(
> + ExpandedRegion.ExpandedFileID, Function);
> + if (ViewOpts.Debug)
> + llvm::outs() << "Expansion of " << ExpandedRegion.ExpandedFileID <<
> ":"
> + << ExpandedLines.first << " -> " << ExpandedLines.second
> + << " @ " << ExpandedRegion.FileID << ", "
> + << ExpandedRegion.LineStart << ":"
> + << ExpandedRegion.ColumnStart << "\n";
> + auto SourceBuffer =
> + getSourceFile(Function.Filenames[ExpandedRegion.ExpandedFileID]);
> + if (!SourceBuffer)
> + return;
> + auto SubView = llvm::make_unique<SourceCoverageView>(
> + SourceBuffer.get(), Parent.getOptions(), ExpandedLines.first,
> + ExpandedLines.second, ExpandedRegion);
> + SourceCoverageDataManager RegionManager;
> + for (const auto &Region : Function.MappingRegions) {
> + if (Region.FileID == ExpandedRegion.ExpandedFileID)
> + RegionManager.insert(Region);
> + }
> + SubView->load(RegionManager);
> + createExpansionSubViews(*SubView, ExpandedRegion.ExpandedFileID,
> Function);
> + Parent.addChild(std::move(SubView));
> +}
> +
> +void CodeCoverageTool::createExpansionSubViews(
> + SourceCoverageView &View, unsigned ViewFileID,
> + const FunctionCoverageMapping &Function) {
> + if (!ViewOpts.ShowExpandedRegions)
> + return;
> + for (const auto &Region : Function.MappingRegions) {
> + if (Region.Kind != CounterMappingRegion::ExpansionRegion)
> + continue;
> + if (Region.FileID != ViewFileID)
> + continue;
> + createExpansionSubView(Region, Function, View);
> + }
> +}
> +
> +void CodeCoverageTool::createInstantiationSubView(
> + StringRef SourceFile, const FunctionCoverageMapping &Function,
> + SourceCoverageView &View) {
> + SourceCoverageDataManager RegionManager;
> + SmallSet<unsigned, 8> InterestingFileIDs;
> + if (!gatherInterestingFileIDs(SourceFile, Function, InterestingFileIDs))
> + return;
> + // Get the interesting regions
> + for (const auto &Region : Function.MappingRegions) {
> + if (InterestingFileIDs.count(Region.FileID))
> + RegionManager.insert(Region);
> + }
> + View.load(RegionManager);
> + unsigned MainFileID;
> + if (findMainViewFileID(SourceFile, Function, MainFileID))
> + return;
> + createExpansionSubViews(View, MainFileID, Function);
> +}
> +
> +bool CodeCoverageTool::createSourceFileView(
> + StringRef SourceFile, SourceCoverageView &View,
> + ArrayRef<FunctionCoverageMapping> FunctionMappingRecords,
> + bool UseOnlyRegionsInMainFile) {
> + SourceCoverageDataManager RegionManager;
> + FunctionInstantiationSetCollector InstantiationSetCollector;
> +
> + for (const auto &Function : FunctionMappingRecords) {
> + unsigned MainFileID;
> + if (findMainViewFileID(SourceFile, Function, MainFileID))
> + continue;
> + SmallSet<unsigned, 8> InterestingFileIDs;
> + if (UseOnlyRegionsInMainFile) {
> + InterestingFileIDs.insert(MainFileID);
> + } else if (!gatherInterestingFileIDs(SourceFile, Function,
> + InterestingFileIDs))
> + continue;
> + // Get the interesting regions
> + for (const auto &Region : Function.MappingRegions) {
> + if (InterestingFileIDs.count(Region.FileID))
> + RegionManager.insert(Region);
> + }
> + InstantiationSetCollector.insert(Function, MainFileID);
> + createExpansionSubViews(View, MainFileID, Function);
> + }
> + if (RegionManager.getSourceRegions().empty())
> + return true;
> + View.load(RegionManager);
> + // Show instantiations
> + if (!ViewOpts.ShowFunctionInstantiations)
> + return false;
> + for (const auto &InstantiationSet : InstantiationSetCollector) {
> + if (InstantiationSet.second.size() < 2)
> + continue;
> + auto InterestingRange = findExpandedFileInterestingLineRange(
> + InstantiationSet.second.front()->MappingRegions.front().FileID,
> + *InstantiationSet.second.front());
> + for (auto Function : InstantiationSet.second) {
> + auto SubView = llvm::make_unique<SourceCoverageView>(
> + View, InterestingRange.first, InterestingRange.second,
> + Function->PrettyName);
> + createInstantiationSubView(SourceFile, *Function, *SubView);
> + View.addChild(std::move(SubView));
> + }
> + }
> + return false;
> +}
> +
> +bool CodeCoverageTool::load() {
> + auto CounterMappingBuff = MemoryBuffer::getFileOrSTDIN(ObjectFilename);
> + if (auto EC = CounterMappingBuff.getError()) {
> + error(EC.message(), ObjectFilename);
> + return true;
> + }
> + ObjectFileCoverageMappingReader MappingReader(CounterMappingBuff.get());
> + if (auto EC = MappingReader.readHeader()) {
> + error(EC.message(), ObjectFilename);
> + return true;
> + }
> +
> + std::vector<uint64_t> Counts;
> + for (const auto &I : MappingReader) {
> + FunctionCoverageMapping Function(I.FunctionName, I.Filenames);
> +
> + // Create the mapping regions with evaluated execution counts
> + Counts.clear();
> + PGOReader->getFunctionCounts(Function.Name, I.FunctionHash, Counts);
> +
> + // Get the biggest referenced counters
> + bool RegionError = false;
> + CounterMappingContext Ctx(I.Expressions, Counts);
> + for (const auto &R : I.MappingRegions) {
> + // Compute the values of mapped regions
> + if (ViewOpts.Debug) {
> + outs() << "File " << R.FileID << "| " << R.LineStart << ":"
> + << R.ColumnStart << " -> " << R.LineEnd << ":" <<
> R.ColumnEnd
> + << " = ";
> + Ctx.dump(R.Count);
> + if (R.Kind == CounterMappingRegion::ExpansionRegion) {
> + outs() << " (Expanded file id = " << R.ExpandedFileID << ") ";
> + }
> + outs() << "\n";
> + }
> + std::error_code Error;
> + Function.MappingRegions.push_back(
> + MappingRegion(R, Ctx.evaluate(R.Count, Error)));
> + if (Error && !RegionError) {
> + colored_ostream(errs(), raw_ostream::RED)
> + << "error: Regions and counters don't match in a function '"
> + << Function.PrettyName << "' (re-run the instrumented
> binary).";
> + errs() << "\n";
> + RegionError = true;
> + }
> + }
> +
> + if (RegionError || !Filters.matches(Function))
> + continue;
> +
> + FunctionMappingRecords.push_back(Function);
> + }
> + return false;
> +}
> +
> +int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
> + // Print a stack trace if we signal out.
> + sys::PrintStackTraceOnErrorSignal();
> + PrettyStackTraceProgram X(argc, argv);
> + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
> +
> + cl::list<std::string> InputSourceFiles(
> + cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
> +
> + cl::opt<std::string> PGOFilename(
> + "instr-profile", cl::Required,
> + cl::desc(
> + "File with the profile data obtained after an instrumented
> run"));
> +
> + cl::opt<bool> DebugDump("dump", cl::Optional,
> + cl::desc("Show internal debug dump"));
> +
> + cl::opt<bool> FilenameEquivalence(
> + "filename-equivalence", cl::Optional,
> + cl::desc("Compare the filenames instead of full filepaths"));
> +
> + cl::OptionCategory FilteringCategory("Function filtering options");
> +
> + cl::list<std::string> NameFilters(
> + "name", cl::Optional,
> + cl::desc("Show code coverage only for functions with the given
> name"),
> + cl::ZeroOrMore, cl::cat(FilteringCategory));
> +
> + cl::list<std::string> NameRegexFilters(
> + "name-regex", cl::Optional,
> + cl::desc("Show code coverage only for functions that match the
> given "
> + "regular expression"),
> + cl::ZeroOrMore, cl::cat(FilteringCategory));
> +
> + cl::opt<double> RegionCoverageLtFilter(
> + "region-coverage-lt", cl::Optional,
> + cl::desc("Show code coverage only for functions with region
> coverage "
> + "less than the given threshold"),
> + cl::cat(FilteringCategory));
> +
> + cl::opt<double> RegionCoverageGtFilter(
> + "region-coverage-gt", cl::Optional,
> + cl::desc("Show code coverage only for functions with region
> coverage "
> + "greater than the given threshold"),
> + cl::cat(FilteringCategory));
> +
> + cl::opt<double> LineCoverageLtFilter(
> + "line-coverage-lt", cl::Optional,
> + cl::desc("Show code coverage only for functions with line coverage
> less "
> + "than the given threshold"),
> + cl::cat(FilteringCategory));
> +
> + cl::opt<double> LineCoverageGtFilter(
> + "line-coverage-gt", cl::Optional,
> + cl::desc("Show code coverage only for functions with line coverage "
> + "greater than the given threshold"),
> + cl::cat(FilteringCategory));
> +
> + auto commandLineParser = [&, this](int argc, const char **argv) -> int {
> + cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
> + ViewOpts.Debug = DebugDump;
> + CompareFilenamesOnly = FilenameEquivalence;
> +
> + if (auto EC = IndexedInstrProfReader::create(PGOFilename, PGOReader))
> {
> + error(EC.message(), PGOFilename);
> + return 1;
> + }
> +
> + // Create the function filters
> + if (!NameFilters.empty() || !NameRegexFilters.empty()) {
> + auto NameFilterer = new CoverageFilters;
> + for (const auto &Name : NameFilters)
> +
> NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
> + for (const auto &Regex : NameRegexFilters)
> + NameFilterer->push_back(
> + llvm::make_unique<NameRegexCoverageFilter>(Regex));
> + Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
> + }
> + if (RegionCoverageLtFilter.getNumOccurrences() ||
> + RegionCoverageGtFilter.getNumOccurrences() ||
> + LineCoverageLtFilter.getNumOccurrences() ||
> + LineCoverageGtFilter.getNumOccurrences()) {
> + auto StatFilterer = new CoverageFilters;
> + if (RegionCoverageLtFilter.getNumOccurrences())
> + StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
> + RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
> + if (RegionCoverageGtFilter.getNumOccurrences())
> + StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
> + RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
> + if (LineCoverageLtFilter.getNumOccurrences())
> + StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
> + LineCoverageFilter::LessThan, LineCoverageLtFilter));
> + if (LineCoverageGtFilter.getNumOccurrences())
> + StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
> + RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
> + Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
> + }
> +
> + SourceFiles = InputSourceFiles;
> + return 0;
> + };
> +
> + // Parse the object filename
> + if (argc > 1) {
> + StringRef Arg(argv[1]);
> + if (Arg.equals_lower("-help") || Arg.equals_lower("-version")) {
> + cl::ParseCommandLineOptions(2, argv, "LLVM code coverage tool\n");
> + return 0;
> + }
> + ObjectFilename = Arg;
> +
> + argv[1] = argv[0];
> + --argc;
> + ++argv;
> + } else {
> + errs() << sys::path::filename(argv[0]) << ": No executable file
> given!\n";
> + return 1;
> + }
> +
> + switch (Cmd) {
> + case Show:
> + return show(argc, argv, commandLineParser);
> + case Report:
> + return report(argc, argv, commandLineParser);
> + }
> + return 0;
> +}
> +
> +int CodeCoverageTool::show(int argc, const char **argv,
> + CommandLineParserType commandLineParser) {
> +
> + cl::OptionCategory ViewCategory("Viewing options");
> +
> + cl::opt<bool> ShowLineExecutionCounts(
> + "show-line-counts", cl::Optional,
> + cl::desc("Show the execution counts for each line"), cl::init(true),
> + cl::cat(ViewCategory));
> +
> + cl::opt<bool> ShowRegions(
> + "show-regions", cl::Optional,
> + cl::desc("Show the execution counts for each region"),
> + cl::cat(ViewCategory));
> +
> + cl::opt<bool> ShowBestLineRegionsCounts(
> + "show-line-counts-or-regions", cl::Optional,
> + cl::desc("Show the execution counts for each line, or the execution
> "
> + "counts for each region on lines that have multiple
> regions"),
> + cl::cat(ViewCategory));
> +
> + cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
> + cl::desc("Show expanded source regions"),
> + cl::cat(ViewCategory));
> +
> + cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
> + cl::desc("Show function
> instantiations"),
> + cl::cat(ViewCategory));
> +
> + cl::opt<bool> NoColors("no-colors", cl::Optional,
> + cl::desc("Don't show text colors"),
> cl::init(false),
> + cl::cat(ViewCategory));
> +
> + auto Err = commandLineParser(argc, argv);
> + if (Err)
> + return Err;
> +
> + ViewOpts.Colors = !NoColors;
> + ViewOpts.ShowLineNumbers = true;
> + ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() !=
> 0 ||
> + !ShowRegions || ShowBestLineRegionsCounts;
> + ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
> + ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
> + ViewOpts.ShowExpandedRegions = ShowExpansions;
> + ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
> +
> + if (load())
> + return 1;
> +
> + if (!Filters.empty()) {
> + // Show functions
> + for (const auto &Function : FunctionMappingRecords) {
> + unsigned MainFileID;
> + if (findMainViewFileID(Function, MainFileID))
> + continue;
> + StringRef SourceFile = Function.Filenames[MainFileID];
> + std::unique_ptr<SourceCoverageView> mainView;
> + auto SourceBuffer = getSourceFile(SourceFile);
> + if (!SourceBuffer)
> + return 1;
> + auto Range = findExpandedFileInterestingLineRange(MainFileID,
> Function);
> + mainView.reset(new SourceCoverageView(SourceBuffer.get(), ViewOpts,
> + Range.first, Range.second));
> + createSourceFileView(SourceFile, *mainView, Function, true);
> + ViewOpts.colored_ostream(outs(), raw_ostream::CYAN)
> + << Function.PrettyName << " from " << SourceFile << ":";
> + outs() << "\n";
> + mainView->render(outs());
> + if (FunctionMappingRecords.size() > 1)
> + outs() << "\n";
> + }
> + return 0;
> + }
> +
> + // Show files
> + bool ShowFilenames = SourceFiles.size() != 1;
> +
> + if (SourceFiles.empty()) {
> + // Get the source files from the function coverage mapping
> + std::set<StringRef> UniqueFilenames;
> + for (const auto &Function : FunctionMappingRecords) {
> + for (const auto &Filename : Function.Filenames)
> + UniqueFilenames.insert(Filename);
> + }
> + for (const auto &Filename : UniqueFilenames)
> + SourceFiles.push_back(Filename);
> + }
> +
> + for (const auto &SourceFile : SourceFiles) {
> + std::unique_ptr<SourceCoverageView> mainView;
> + auto SourceBuffer = getSourceFile(SourceFile);
> + if (!SourceBuffer)
> + return 1;
> + mainView.reset(new SourceCoverageView(SourceBuffer.get(), ViewOpts));
> + if (createSourceFileView(SourceFile, *mainView,
> FunctionMappingRecords)) {
> + ViewOpts.colored_ostream(outs(), raw_ostream::RED)
> + << "warning: The file '" << SourceFile << "' isn't covered.";
> + outs() << "\n";
> + continue;
> + }
> +
> + if (ShowFilenames) {
> + ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile
> << ":";
> + outs() << "\n";
> + }
> + mainView->render(outs());
> + if (SourceFiles.size() > 1)
> + outs() << "\n";
> + }
> +
> + return 0;
> +}
> +
> +int CodeCoverageTool::report(int argc, const char **argv,
> + CommandLineParserType commandLineParser) {
> + cl::opt<bool> NoColors("no-colors", cl::Optional,
> + cl::desc("Don't show text colors"),
> cl::init(false));
> +
> + auto Err = commandLineParser(argc, argv);
> + if (Err)
> + return Err;
> +
> + ViewOpts.Colors = !NoColors;
> +
> + if (load())
> + return 1;
> +
> + CoverageSummary Summarizer;
> + Summarizer.createSummaries(FunctionMappingRecords);
> + CoverageReport Report(ViewOpts, Summarizer);
> + if (SourceFiles.empty() && Filters.empty()) {
> + Report.renderFileReports(llvm::outs());
> + return 0;
> + }
> +
> + Report.renderFunctionReports(llvm::outs());
> + return 0;
> +}
> +
> +int show_main(int argc, const char **argv) {
> + CodeCoverageTool Tool;
> + return Tool.run(CodeCoverageTool::Show, argc, argv);
> +}
> +
> +int report_main(int argc, const char **argv) {
> + CodeCoverageTool Tool;
> + return Tool.run(CodeCoverageTool::Report, argc, argv);
> +}
>
> Added: llvm/trunk/tools/llvm-cov/CoverageFilters.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageFilters.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageFilters.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageFilters.cpp Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,57 @@
> +//===- CoverageFilters.cpp - Function coverage mapping filters
> ------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// These classes provide filtering for function coverage mapping records.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "CoverageFilters.h"
> +#include "CoverageSummaryInfo.h"
> +#include "llvm/Support/Regex.h"
> +
> +using namespace llvm;
> +
> +bool NameCoverageFilter::matches(const FunctionCoverageMapping &Function)
> {
> + StringRef FuncName = Function.PrettyName;
> + return FuncName.find(Name) != StringRef::npos;
> +}
> +
> +bool NameRegexCoverageFilter::matches(const FunctionCoverageMapping
> &Function) {
> + return llvm::Regex(Regex).match(Function.PrettyName);
> +}
> +
> +bool RegionCoverageFilter::matches(const FunctionCoverageMapping
> &Function) {
> + return PassesThreshold(FunctionCoverageSummary::get(Function)
> + .RegionCoverage.getPercentCovered());
> +}
> +
> +bool LineCoverageFilter::matches(const FunctionCoverageMapping &Function)
> {
> + return PassesThreshold(
> +
> FunctionCoverageSummary::get(Function).LineCoverage.getPercentCovered());
> +}
> +
> +void CoverageFilters::push_back(std::unique_ptr<CoverageFilter> Filter) {
> + Filters.push_back(std::move(Filter));
> +}
> +
> +bool CoverageFilters::matches(const FunctionCoverageMapping &Function) {
> + for (const auto &Filter : Filters) {
> + if (Filter->matches(Function))
> + return true;
> + }
> + return false;
> +}
> +
> +bool CoverageFiltersMatchAll::matches(const FunctionCoverageMapping
> &Function) {
> + for (const auto &Filter : Filters) {
> + if (!Filter->matches(Function))
> + return false;
> + }
> + return true;
> +}
>
> Added: llvm/trunk/tools/llvm-cov/CoverageFilters.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageFilters.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageFilters.h (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageFilters.h Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,125 @@
> +//===- CoverageFilters.h - Function coverage mapping filters
> --------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// These classes provide filtering for function coverage mapping records.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_COVERAGEFILTERS_H
> +#define LLVM_COV_COVERAGEFILTERS_H
> +
> +#include "FunctionCoverageMapping.h"
> +#include <vector>
> +#include <memory>
> +
> +namespace llvm {
> +
> +/// \brief Matches specific functions that pass the requirement of this
> filter.
> +class CoverageFilter {
> +public:
> + virtual ~CoverageFilter() {}
> +
> + /// \brief Return true if the function passes the requirements of this
> filter.
> + virtual bool matches(const FunctionCoverageMapping &Function) { return
> true; }
> +};
> +
> +/// \brief Matches functions that contain a specific string in their name.
> +class NameCoverageFilter : public CoverageFilter {
> + StringRef Name;
> +
> +public:
> + NameCoverageFilter(StringRef Name) : Name(Name) {}
> +
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +/// \brief Matches functions whose name matches a certain regular
> expression.
> +class NameRegexCoverageFilter : public CoverageFilter {
> + StringRef Regex;
> +
> +public:
> + NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {}
> +
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +/// \brief Matches numbers that pass a certain threshold.
> +template <typename T> class StatisticThresholdFilter {
> +public:
> + enum Operation { LessThan, GreaterThan };
> +
> +protected:
> + Operation Op;
> + T Threshold;
> +
> + StatisticThresholdFilter(Operation Op, T Threshold)
> + : Op(Op), Threshold(Threshold) {}
> +
> + /// \brief Return true if the given number is less than
> + /// or greater than the certain threshold.
> + bool PassesThreshold(T Value) const {
> + switch (Op) {
> + case LessThan:
> + return Value < Threshold;
> + case GreaterThan:
> + return Value > Threshold;
> + }
> + return false;
> + }
> +};
> +
> +/// \brief Matches functions whose region coverage percentage
> +/// is above/below a certain percentage.
> +class RegionCoverageFilter : public CoverageFilter,
> + public StatisticThresholdFilter<double> {
> +public:
> + RegionCoverageFilter(Operation Op, double Threshold)
> + : StatisticThresholdFilter(Op, Threshold) {}
> +
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +/// \brief Matches functions whose line coverage percentage
> +/// is above/below a certain percentage.
> +class LineCoverageFilter : public CoverageFilter,
> + public StatisticThresholdFilter<double> {
> +public:
> + LineCoverageFilter(Operation Op, double Threshold)
> + : StatisticThresholdFilter(Op, Threshold) {}
> +
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +/// \brief A collection of filters.
> +/// Matches functions that match any filters contained
> +/// in an instance of this class.
> +class CoverageFilters : public CoverageFilter {
> +protected:
> + std::vector<std::unique_ptr<CoverageFilter>> Filters;
> +
> +public:
> + /// \brief Append a filter to this collection.
> + void push_back(std::unique_ptr<CoverageFilter> Filter);
> +
> + bool empty() const { return Filters.empty(); }
> +
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +/// \brief A collection of filters.
> +/// Matches functions that match all of the filters contained
> +/// in an instance of this class.
> +class CoverageFiltersMatchAll : public CoverageFilters {
> +public:
> + bool matches(const FunctionCoverageMapping &Function) override;
> +};
> +
> +} // namespace llvm
> +
> +#endif // LLVM_COV_COVERAGEFILTERS_H
>
> Added: llvm/trunk/tools/llvm-cov/CoverageReport.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageReport.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageReport.cpp Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,201 @@
> +//===- CoverageReport.cpp - Code coverage report
> -------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements rendering of a code coverage report.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "CoverageReport.h"
> +#include "CoverageSummary.h"
> +#include "RenderingSupport.h"
> +#include "llvm/Support/Format.h"
> +#include "llvm/Support/FileSystem.h"
> +
> +using namespace llvm;
> +namespace {
> +/// \brief Helper struct which prints trimmed and aligned columns.
> +struct Column {
> + enum TrimKind { NoTrim, LeftTrim, RightTrim };
> +
> + enum AlignmentKind { LeftAlignment, RightAlignment };
> +
> + StringRef Str;
> + unsigned Width;
> + TrimKind Trim;
> + AlignmentKind Alignment;
> +
> + Column(StringRef Str, unsigned Width)
> + : Str(Str), Width(Width), Trim(NoTrim), Alignment(LeftAlignment) {}
> +
> + Column &set(TrimKind Value) {
> + Trim = Value;
> + return *this;
> + }
> +
> + Column &set(AlignmentKind Value) {
> + Alignment = Value;
> + return *this;
> + }
> +
> + void render(raw_ostream &OS) const;
> +};
> +raw_ostream &operator<<(raw_ostream &OS, const Column &Value) {
> + Value.render(OS);
> + return OS;
> +}
> +}
> +
> +void Column::render(raw_ostream &OS) const {
> + if (Str.size() <= Width) {
> + if (Alignment == RightAlignment) {
> + OS.indent(Width - Str.size());
> + OS << Str;
> + return;
> + }
> + OS << Str;
> + OS.indent(Width - Str.size());
> + return;
> + }
> +
> + switch (Trim) {
> + case NoTrim:
> + OS << Str.substr(0, Width);
> + break;
> + case LeftTrim:
> + OS << "..." << Str.substr(Str.size() - Width + 3);
> + break;
> + case RightTrim:
> + OS << Str.substr(0, Width - 3) << "...";
> + break;
> + }
> +}
> +
> +static Column column(StringRef Str, unsigned Width) {
> + return Column(Str, Width);
> +}
> +
> +template <typename T>
> +static Column column(StringRef Str, unsigned Width, const T &Value) {
> + return Column(Str, Width).set(Value);
> +}
> +
> +static const unsigned FileReportColumns[] = {25, 10, 8, 8, 10, 8};
> +static const unsigned FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};
> +
> +/// \brief Prints a horizontal divider which spans across the given
> columns.
> +template <typename T, size_t N>
> +static void renderDivider(T (&Columns)[N], raw_ostream &OS) {
> + unsigned Length = 0;
> + for (unsigned I = 0; I < N; ++I)
> + Length += Columns[I];
> + for (unsigned I = 0; I < Length; ++I)
> + OS << '-';
> +}
> +
> +/// \brief Return the color which correponds to the coverage
> +/// percentage of a certain metric.
> +template <typename T>
> +static raw_ostream::Colors determineCoveragePercentageColor(const T
> &Info) {
> + if (Info.isFullyCovered())
> + return raw_ostream::GREEN;
> + return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW
> + : raw_ostream::RED;
> +}
> +
> +void CoverageReport::render(const FileCoverageSummary &File, raw_ostream
> &OS) {
> + OS << column(File.Name, FileReportColumns[0], Column::LeftTrim)
> + << format("%*zd", FileReportColumns[1],
> File.RegionCoverage.NumRegions);
> + Options.colored_ostream(OS, File.RegionCoverage.isFullyCovered()
> + ? raw_ostream::GREEN
> + : raw_ostream::RED)
> + << format("%*zd", FileReportColumns[2],
> File.RegionCoverage.NotCovered);
> + Options.colored_ostream(OS,
> +
> determineCoveragePercentageColor(File.RegionCoverage))
> + << format("%*.2f", FileReportColumns[3] - 1,
> + File.RegionCoverage.getPercentCovered()) << '%';
> + OS << format("%*zd", FileReportColumns[4],
> + File.FunctionCoverage.NumFunctions);
> + Options.colored_ostream(
> + OS, determineCoveragePercentageColor(File.FunctionCoverage))
> + << format("%*.2f", FileReportColumns[5] - 1,
> + File.FunctionCoverage.getPercentCovered()) << '%';
> + OS << "\n";
> +}
> +
> +void CoverageReport::render(const FunctionCoverageSummary &Function,
> + raw_ostream &OS) {
> + OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
> + << format("%*zd", FunctionReportColumns[1],
> + Function.RegionCoverage.NumRegions);
> + Options.colored_ostream(OS, Function.RegionCoverage.isFullyCovered()
> + ? raw_ostream::GREEN
> + : raw_ostream::RED)
> + << format("%*zd", FunctionReportColumns[2],
> + Function.RegionCoverage.NotCovered);
> + Options.colored_ostream(
> + OS, determineCoveragePercentageColor(Function.RegionCoverage))
> + << format("%*.2f", FunctionReportColumns[3] - 1,
> + Function.RegionCoverage.getPercentCovered()) << '%';
> + OS << format("%*zd", FunctionReportColumns[4],
> + Function.LineCoverage.NumLines);
> + Options.colored_ostream(OS, Function.LineCoverage.isFullyCovered()
> + ? raw_ostream::GREEN
> + : raw_ostream::RED)
> + << format("%*zd", FunctionReportColumns[5],
> + Function.LineCoverage.NotCovered);
> + Options.colored_ostream(
> + OS, determineCoveragePercentageColor(Function.LineCoverage))
> + << format("%*.2f", FunctionReportColumns[6] - 1,
> + Function.LineCoverage.getPercentCovered()) << '%';
> + OS << "\n";
> +}
> +
> +void CoverageReport::renderFunctionReports(raw_ostream &OS) {
> + bool isFirst = true;
> + for (const auto &File : Summary.getFileSummaries()) {
> + if (isFirst)
> + isFirst = false;
> + else
> + OS << "\n";
> + OS << "File '" << File.Name << "':\n";
> + OS << column("Name", FunctionReportColumns[0])
> + << column("Regions", FunctionReportColumns[1],
> Column::RightAlignment)
> + << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
> + << column("Cover", FunctionReportColumns[3],
> Column::RightAlignment)
> + << column("Lines", FunctionReportColumns[4],
> Column::RightAlignment)
> + << column("Miss", FunctionReportColumns[5], Column::RightAlignment)
> + << column("Cover", FunctionReportColumns[6],
> Column::RightAlignment);
> + OS << "\n";
> + renderDivider(FunctionReportColumns, OS);
> + OS << "\n";
> + for (const auto &Function : File.FunctionSummaries)
> + render(Function, OS);
> + renderDivider(FunctionReportColumns, OS);
> + OS << "\n";
> + render(FunctionCoverageSummary("TOTAL", File.RegionCoverage,
> + File.LineCoverage),
> + OS);
> + }
> +}
> +
> +void CoverageReport::renderFileReports(raw_ostream &OS) {
> + OS << column("Filename", FileReportColumns[0])
> + << column("Regions", FileReportColumns[1], Column::RightAlignment)
> + << column("Miss", FileReportColumns[2], Column::RightAlignment)
> + << column("Cover", FileReportColumns[3], Column::RightAlignment)
> + << column("Functions", FileReportColumns[4], Column::RightAlignment)
> + << column("Cover", FileReportColumns[5], Column::RightAlignment) <<
> "\n";
> + renderDivider(FileReportColumns, OS);
> + OS << "\n";
> + for (const auto &File : Summary.getFileSummaries())
> + render(File, OS);
> + renderDivider(FileReportColumns, OS);
> + OS << "\n";
> + render(Summary.getCombinedFileSummaries(), OS);
> +}
>
> Added: llvm/trunk/tools/llvm-cov/CoverageReport.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageReport.h (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageReport.h Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,40 @@
> +//===- CoverageReport.h - Code coverage report
> ---------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements rendering of a code coverage report.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_COVERAGEREPORT_H
> +#define LLVM_COV_COVERAGEREPORT_H
> +
> +#include "CoverageViewOptions.h"
> +#include "CoverageSummary.h"
> +
> +namespace llvm {
> +
> +/// \brief Displays the code coverage report.
> +class CoverageReport {
> + const CoverageViewOptions &Options;
> + CoverageSummary &Summary;
> +
> + void render(const FileCoverageSummary &File, raw_ostream &OS);
> + void render(const FunctionCoverageSummary &Function, raw_ostream &OS);
> +
> +public:
> + CoverageReport(const CoverageViewOptions &Options, CoverageSummary
> &Summary)
> + : Options(Options), Summary(Summary) {}
> +
> + void renderFunctionReports(raw_ostream &OS);
> +
> + void renderFileReports(raw_ostream &OS);
> +};
> +}
> +
> +#endif // LLVM_COV_COVERAGEREPORT_H
>
> Added: llvm/trunk/tools/llvm-cov/CoverageSummary.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummary.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageSummary.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageSummary.cpp Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,92 @@
> +//===- CoverageSummary.cpp - Code coverage summary
> ------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements data management and rendering for the code
> coverage
> +// summaries of all files and functions.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "CoverageSummary.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Format.h"
> +
> +using namespace llvm;
> +
> +unsigned CoverageSummary::getFileID(StringRef Filename) {
> + for (unsigned I = 0, E = Filenames.size(); I < E; ++I) {
> + if (sys::fs::equivalent(Filenames[I], Filename))
> + return I;
> + }
> + Filenames.push_back(Filename);
> + return Filenames.size() - 1;
> +}
> +
> +void
> +CoverageSummary::createSummaries(ArrayRef<FunctionCoverageMapping>
> Functions) {
> + std::vector<std::pair<unsigned, size_t>> FunctionFileIDs;
> +
> + FunctionFileIDs.resize(Functions.size());
> + for (size_t I = 0, E = Functions.size(); I < E; ++I) {
> + StringRef Filename = Functions[I].Filenames[0];
> + FunctionFileIDs[I] = std::make_pair(getFileID(Filename), I);
> + }
> +
> + // Sort the function records by file ids
> + std::sort(FunctionFileIDs.begin(), FunctionFileIDs.end(),
> + [](const std::pair<unsigned, size_t> &lhs,
> + const std::pair<unsigned, size_t> &rhs) {
> + return lhs.first < rhs.first;
> + });
> +
> + // Create function summaries in a sorted order (by file ids)
> + FunctionSummaries.reserve(Functions.size());
> + for (size_t I = 0, E = Functions.size(); I < E; ++I)
> + FunctionSummaries.push_back(
> +
> FunctionCoverageSummary::get(Functions[FunctionFileIDs[I].second]));
> +
> + // Create file summaries
> + size_t CurrentSummary = 0;
> + for (unsigned FileID = 0; FileID < Filenames.size(); ++FileID) {
> + // Gather the relevant functions summaries
> + auto PrevSummary = CurrentSummary;
> + while (CurrentSummary < FunctionSummaries.size() &&
> + FunctionFileIDs[CurrentSummary].first == FileID)
> + ++CurrentSummary;
> + ArrayRef<FunctionCoverageSummary> LocalSummaries(
> + FunctionSummaries.data() + PrevSummary,
> + FunctionSummaries.data() + CurrentSummary);
> + if (LocalSummaries.empty())
> + continue;
> +
> + FileSummaries.push_back(
> + FileCoverageSummary::get(Filenames[FileID], LocalSummaries));
> + }
> +}
> +
> +FileCoverageSummary CoverageSummary::getCombinedFileSummaries() {
> + size_t NumRegions = 0, CoveredRegions = 0;
> + size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
> + size_t NumFunctionsCovered = 0, NumFunctions = 0;
> + for (const auto &File : FileSummaries) {
> + NumRegions += File.RegionCoverage.NumRegions;
> + CoveredRegions += File.RegionCoverage.Covered;
> +
> + NumLines += File.LineCoverage.NumLines;
> + NonCodeLines += File.LineCoverage.NonCodeLines;
> + CoveredLines += File.LineCoverage.Covered;
> +
> + NumFunctionsCovered += File.FunctionCoverage.FullyCovered;
> + NumFunctions += File.FunctionCoverage.NumFunctions;
> + }
> + return FileCoverageSummary(
> + "TOTAL", RegionCoverageInfo(CoveredRegions, NumRegions),
> + LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
> + FunctionCoverageInfo(NumFunctionsCovered, NumFunctions),
> + ArrayRef<FunctionCoverageSummary>());
> +}
>
> Added: llvm/trunk/tools/llvm-cov/CoverageSummary.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummary.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageSummary.h (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageSummary.h Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,45 @@
> +//===- CoverageSummary.h - Code coverage summary
> --------------------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements data management and rendering for the code
> coverage
> +// summaries of all files and functions.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_COVERAGESUMMARY_H
> +#define LLVM_COV_COVERAGESUMMARY_H
> +
> +#include "CoverageSummaryInfo.h"
> +#include <vector>
> +
> +namespace llvm {
> +
> +/// \brief Manager for the function and file code coverage summaries.
> +class CoverageSummary {
> + std::vector<StringRef> Filenames;
> + std::vector<FunctionCoverageSummary> FunctionSummaries;
> + std::vector<std::pair<unsigned, unsigned>> FunctionSummariesFileIDs;
> + std::vector<FileCoverageSummary> FileSummaries;
> +
> + unsigned getFileID(StringRef Filename);
> +
> +public:
> + void createSummaries(ArrayRef<FunctionCoverageMapping> Functions);
> +
> + ArrayRef<FileCoverageSummary> getFileSummaries() { return
> FileSummaries; }
> +
> + FileCoverageSummary getCombinedFileSummaries();
> +
> + void render(const FunctionCoverageSummary &Summary, raw_ostream &OS);
> +
> + void render(raw_ostream &OS);
> +};
> +}
> +
> +#endif // LLVM_COV_COVERAGESUMMARY_H
>
> Added: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp Fri Aug 22 17:56:03
> 2014
> @@ -0,0 +1,95 @@
> +//===- CoverageSummaryInfo.cpp - Coverage summary for function/file
> -------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// These structures are used to represent code coverage metrics
> +// for functions/files.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "CoverageSummaryInfo.h"
> +
> +using namespace llvm;
> +using namespace coverage;
> +
> +FunctionCoverageSummary
> +FunctionCoverageSummary::get(const FunctionCoverageMapping &Function) {
> + // Compute the region coverage
> + size_t NumCodeRegions = 0, CoveredRegions = 0;
> + for (auto &Region : Function.MappingRegions) {
> + if (Region.Kind != CounterMappingRegion::CodeRegion)
> + continue;
> + ++NumCodeRegions;
> + if (Region.ExecutionCount != 0)
> + ++CoveredRegions;
> + }
> +
> + // Compute the line coverage
> + size_t NumLines = 0, CoveredLines = 0;
> + for (unsigned FileID = 0, E = Function.Filenames.size(); FileID < E;
> + ++FileID) {
> + // Find the line start and end of the function's source code
> + // in that particular file
> + unsigned LineStart = std::numeric_limits<unsigned>::max();
> + unsigned LineEnd = 0;
> + for (auto &Region : Function.MappingRegions) {
> + if (Region.FileID != FileID)
> + continue;
> + LineStart = std::min(LineStart, Region.LineStart);
> + LineEnd = std::max(LineEnd, Region.LineEnd);
> + }
> + unsigned LineCount = LineEnd - LineStart + 1;
> +
> + // Get counters
> + llvm::SmallVector<uint64_t, 16> ExecutionCounts;
> + ExecutionCounts.resize(LineCount, 0);
> + for (auto &Region : Function.MappingRegions) {
> + if (Region.FileID != FileID)
> + continue;
> + // Ignore the lines that were skipped by the preprocessor.
> + auto ExecutionCount = Region.ExecutionCount;
> + if (Region.Kind == MappingRegion::SkippedRegion) {
> + LineCount -= Region.LineEnd - Region.LineStart + 1;
> + ExecutionCount = 1;
> + }
> + for (unsigned I = Region.LineStart; I <= Region.LineEnd; ++I)
> + ExecutionCounts[I - LineStart] = ExecutionCount;
> + }
> + CoveredLines += LineCount - std::count(ExecutionCounts.begin(),
> + ExecutionCounts.end(), 0);
> + NumLines += LineCount;
> + }
> + return FunctionCoverageSummary(
> + Function.PrettyName, RegionCoverageInfo(CoveredRegions,
> NumCodeRegions),
> + LineCoverageInfo(CoveredLines, 0, NumLines));
> +}
> +
> +FileCoverageSummary
> +FileCoverageSummary::get(StringRef Name,
> + ArrayRef<FunctionCoverageSummary>
> FunctionSummaries) {
> + size_t NumRegions = 0, CoveredRegions = 0;
> + size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
> + size_t NumFunctionsCovered = 0;
> + for (const auto &Func : FunctionSummaries) {
> + CoveredRegions += Func.RegionCoverage.Covered;
> + NumRegions += Func.RegionCoverage.NumRegions;
> +
> + CoveredLines += Func.LineCoverage.Covered;
> + NonCodeLines += Func.LineCoverage.NonCodeLines;
> + NumLines += Func.LineCoverage.NumLines;
> +
> + if (Func.RegionCoverage.isFullyCovered())
> + ++NumFunctionsCovered;
> + }
> +
> + return FileCoverageSummary(
> + Name, RegionCoverageInfo(CoveredRegions, NumRegions),
> + LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
> + FunctionCoverageInfo(NumFunctionsCovered, FunctionSummaries.size()),
> + FunctionSummaries);
> +}
>
> Added: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h Fri Aug 22 17:56:03
> 2014
> @@ -0,0 +1,131 @@
> +//===- CoverageSummaryInfo.h - Coverage summary for function/file
> ---------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// These structures are used to represent code coverage metrics
> +// for functions/files.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_COVERAGESUMMARYINFO_H
> +#define LLVM_COV_COVERAGESUMMARYINFO_H
> +
> +#include "FunctionCoverageMapping.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +namespace llvm {
> +
> +/// \brief Provides information about region coverage for a function/file.
> +struct RegionCoverageInfo {
> + /// \brief The number of regions that were executed at least once.
> + size_t Covered;
> +
> + /// \brief The number of regions that weren't executed.
> + size_t NotCovered;
> +
> + /// \brief The total number of regions in a function/file.
> + size_t NumRegions;
> +
> + RegionCoverageInfo(size_t Covered, size_t NumRegions)
> + : Covered(Covered), NotCovered(NumRegions - Covered),
> + NumRegions(NumRegions) {}
> +
> + bool isFullyCovered() const { return Covered == NumRegions; }
> +
> + double getPercentCovered() const {
> + return double(Covered) / double(NumRegions) * 100.0;
> + }
> +};
> +
> +/// \brief Provides information about line coverage for a function/file.
> +struct LineCoverageInfo {
> + /// \brief The number of lines that were executed at least once.
> + size_t Covered;
> +
> + /// \brief The number of lines that weren't executed.
> + size_t NotCovered;
> +
> + /// \brief The number of lines that aren't code.
> + size_t NonCodeLines;
> +
> + /// \brief The total number of lines in a function/file.
> + size_t NumLines;
> +
> + LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t
> NumLines)
> + : Covered(Covered), NotCovered(NumLines - NumNonCodeLines -
> Covered),
> + NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
> +
> + bool isFullyCovered() const { return Covered == (NumLines -
> NonCodeLines); }
> +
> + double getPercentCovered() const {
> + return double(Covered) / double(NumLines - NonCodeLines) * 100.0;
> + }
> +};
> +
> +/// \brief Provides information about function coverage for a file.
> +struct FunctionCoverageInfo {
> + /// \brief The number of functions that have full
> + /// region coverage.
> + size_t FullyCovered;
> +
> + /// \brief The total number of functions in this file.
> + size_t NumFunctions;
> +
> + FunctionCoverageInfo(size_t FullyCovered, size_t NumFunctions)
> + : FullyCovered(FullyCovered), NumFunctions(NumFunctions) {}
> +
> + bool isFullyCovered() const { return FullyCovered == NumFunctions; }
> +
> + double getPercentCovered() const {
> + return double(FullyCovered) / double(NumFunctions) * 100.0;
> + }
> +};
> +
> +/// \brief A summary of function's code coverage.
> +struct FunctionCoverageSummary {
> + StringRef Name;
> + RegionCoverageInfo RegionCoverage;
> + LineCoverageInfo LineCoverage;
> +
> + FunctionCoverageSummary(StringRef Name,
> + const RegionCoverageInfo &RegionCoverage,
> + const LineCoverageInfo &LineCoverage)
> + : Name(Name), RegionCoverage(RegionCoverage),
> LineCoverage(LineCoverage) {
> + }
> +
> + /// \brief Compute the code coverage summary for the given function
> coverage
> + /// mapping record.
> + static FunctionCoverageSummary get(const FunctionCoverageMapping
> &Function);
> +};
> +
> +/// \brief A summary of file's code coverage.
> +struct FileCoverageSummary {
> + StringRef Name;
> + RegionCoverageInfo RegionCoverage;
> + LineCoverageInfo LineCoverage;
> + FunctionCoverageInfo FunctionCoverage;
> + /// \brief The summary of every function
> + /// in this file.
> + ArrayRef<FunctionCoverageSummary> FunctionSummaries;
> +
> + FileCoverageSummary(StringRef Name, const RegionCoverageInfo
> &RegionCoverage,
> + const LineCoverageInfo &LineCoverage,
> + const FunctionCoverageInfo &FunctionCoverage,
> + ArrayRef<FunctionCoverageSummary> FunctionSummaries)
> + : Name(Name), RegionCoverage(RegionCoverage),
> LineCoverage(LineCoverage),
> + FunctionCoverage(FunctionCoverage),
> + FunctionSummaries(FunctionSummaries) {}
> +
> + /// \brief Compute the code coverage summary for a file.
> + static FileCoverageSummary
> + get(StringRef Name, ArrayRef<FunctionCoverageSummary>
> FunctionSummaries);
> +};
> +
> +} // namespace llvm
> +
> +#endif // LLVM_COV_COVERAGESUMMARYINFO_H
>
> Added: llvm/trunk/tools/llvm-cov/CoverageViewOptions.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageViewOptions.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/CoverageViewOptions.h (added)
> +++ llvm/trunk/tools/llvm-cov/CoverageViewOptions.h Fri Aug 22 17:56:03
> 2014
> @@ -0,0 +1,36 @@
> +//===- CoverageViewOptions.h - Code coverage display options
> -------------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_COVERAGEVIEWOPTIONS_H
> +#define LLVM_COV_COVERAGEVIEWOPTIONS_H
> +
> +#include "RenderingSupport.h"
> +
> +namespace llvm {
> +
> +/// \brief The options for displaying the code coverage information.
> +struct CoverageViewOptions {
> + bool Debug;
> + bool Colors;
> + bool ShowLineNumbers;
> + bool ShowLineStats;
> + bool ShowRegionMarkers;
> + bool ShowLineStatsOrRegionMarkers;
> + bool ShowExpandedRegions;
> + bool ShowFunctionInstantiations;
> +
> + /// \brief Change the output's stream color if the colors are enabled.
> + ColoredRawOstream colored_ostream(raw_ostream &OS,
> + raw_ostream::Colors Color) const {
> + return llvm::colored_ostream(OS, Color, Colors);
> + }
> +};
> +}
> +
> +#endif // LLVM_COV_COVERAGEVIEWOPTIONS_H
>
> Added: llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h (added)
> +++ llvm/trunk/tools/llvm-cov/FunctionCoverageMapping.h Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,50 @@
> +//===- FunctionCoverageMapping.h - Function coverage mapping record
> -------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// A structure that stores the coverage mapping record for a single
> function.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_FUNCTIONCOVERAGEMAPPING_H
> +#define LLVM_COV_FUNCTIONCOVERAGEMAPPING_H
> +
> +#include <string>
> +#include <vector>
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ProfileData/CoverageMapping.h"
> +
> +namespace llvm {
> +
> +/// \brief Associates a source range with an execution count.
> +struct MappingRegion : public coverage::CounterMappingRegion {
> + uint64_t ExecutionCount;
> +
> + MappingRegion(const CounterMappingRegion &R, uint64_t ExecutionCount)
> + : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {}
> +};
> +
> +/// \brief Stores all the required information
> +/// about code coverage for a single function.
> +struct FunctionCoverageMapping {
> + /// \brief Raw function name.
> + std::string Name;
> + /// \brief Demangled function name.
> + std::string PrettyName;
> + std::vector<std::string> Filenames;
> + std::vector<MappingRegion> MappingRegions;
> +
> + FunctionCoverageMapping(StringRef Name, ArrayRef<StringRef> Filenames)
> + : Name(Name), PrettyName(Name),
> + Filenames(Filenames.begin(), Filenames.end()) {}
> +};
> +
> +} // namespace llvm
> +
> +#endif // LLVM_COV_FUNCTIONCOVERAGEMAPPING_H
>
> Modified: llvm/trunk/tools/llvm-cov/LLVMBuild.txt
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/LLVMBuild.txt?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/LLVMBuild.txt (original)
> +++ llvm/trunk/tools/llvm-cov/LLVMBuild.txt Fri Aug 22 17:56:03 2014
> @@ -19,4 +19,4 @@
> type = Tool
> name = llvm-cov
> parent = Tools
> -required_libraries = Instrumentation
> +required_libraries = ProfileData Support Instrumentation
>
> Modified: llvm/trunk/tools/llvm-cov/Makefile
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/Makefile?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/Makefile (original)
> +++ llvm/trunk/tools/llvm-cov/Makefile Fri Aug 22 17:56:03 2014
> @@ -9,7 +9,7 @@
>
> LEVEL := ../..
> TOOLNAME := llvm-cov
> -LINK_COMPONENTS := core support
> +LINK_COMPONENTS := core support profiledata object
>
> # This tool has no plugins, optimize startup time.
> TOOL_NO_EXPORTS := 1
>
> Added: llvm/trunk/tools/llvm-cov/RenderingSupport.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/RenderingSupport.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/RenderingSupport.h (added)
> +++ llvm/trunk/tools/llvm-cov/RenderingSupport.h Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,59 @@
> +//===- RenderingSupport.h - output stream rendering support functions
> ----===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_RENDERINGSUPPORT_H
> +#define LLVM_COV_RENDERINGSUPPORT_H
> +
> +#include "llvm/Support/raw_ostream.h"
> +#include <utility>
> +
> +namespace llvm {
> +
> +/// \brief A helper class that resets the output stream's color if needed
> +/// when destroyed.
> +class ColoredRawOstream {
> + ColoredRawOstream(const ColoredRawOstream &OS) LLVM_DELETED_FUNCTION;
> +
> +public:
> + raw_ostream &OS;
> + bool IsColorUsed;
> +
> + ColoredRawOstream(raw_ostream &OS, bool IsColorUsed)
> + : OS(OS), IsColorUsed(IsColorUsed) {}
> +
> + ColoredRawOstream(ColoredRawOstream &&Other)
> + : OS(Other.OS), IsColorUsed(Other.IsColorUsed) {
> + // Reset the other IsColorUsed so that the other object won't reset
> the
> + // color when destroyed.
> + Other.IsColorUsed = false;
> + }
> +
> + ~ColoredRawOstream() {
> + if (IsColorUsed)
> + OS.resetColor();
> + }
> +};
> +
> +template <typename T>
> +inline raw_ostream &operator<<(const ColoredRawOstream &OS, T &&Value) {
> + return OS.OS << std::forward<T>(Value);
> +}
> +
> +/// \brief Change the color of the output stream if the `IsColorUsed` flag
> +/// is true. Returns an object that resets the color when destroyed.
> +inline ColoredRawOstream colored_ostream(raw_ostream &OS,
> + raw_ostream::Colors Color,
> + bool IsColorUsed = false) {
> + if (IsColorUsed)
> + OS.changeColor(Color);
> + return ColoredRawOstream(OS, IsColorUsed);
> +}
> +}
> +
> +#endif // LLVM_COV_RENDERINGSUPPORT_H
>
> Added: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.cpp Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,57 @@
> +//===- SourceCoverageDataManager.cpp - Manager for source file coverage
> +// data-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class separates and merges mapping regions for a specific source
> file.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "SourceCoverageDataManager.h"
> +
> +using namespace llvm;
> +using namespace coverage;
> +
> +void SourceCoverageDataManager::insert(const MappingRegion &Region) {
> + SourceRange Range(Region.LineStart, Region.ColumnStart, Region.LineEnd,
> + Region.ColumnEnd);
> + if (Region.Kind == CounterMappingRegion::SkippedRegion) {
> + SkippedRegions.push_back(Range);
> + return;
> + }
> + Regions.push_back(std::make_pair(Range, Region.ExecutionCount));
> +}
> +
> +ArrayRef<std::pair<SourceCoverageDataManager::SourceRange, uint64_t>>
> +SourceCoverageDataManager::getSourceRegions() {
> + if (Uniqued || Regions.size() <= 1)
> + return Regions;
> +
> + // Sort.
> + std::sort(Regions.begin(), Regions.end(),
> + [](const std::pair<SourceRange, uint64_t> &LHS,
> + const std::pair<SourceRange, uint64_t> &RHS) {
> + return LHS.first < RHS.first;
> + });
> +
> + // Merge duplicate source ranges and sum their execution counts.
> + auto Prev = Regions.begin();
> + for (auto I = Prev + 1, E = Regions.end(); I != E; ++I) {
> + if (I->first == Prev->first) {
> + Prev->second += I->second;
> + continue;
> + }
> + ++Prev;
> + *Prev = *I;
> + }
> + ++Prev;
> + Regions.erase(Prev, Regions.end());
> +
> + Uniqued = true;
> + return Regions;
> +}
>
> Added: llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h (added)
> +++ llvm/trunk/tools/llvm-cov/SourceCoverageDataManager.h Fri Aug 22
> 17:56:03 2014
> @@ -0,0 +1,79 @@
> +//===- SourceCoverageDataManager.h - Manager for source file coverage
> data-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class separates and merges mapping regions for a specific source
> file.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
> +#define LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
> +
> +#include "FunctionCoverageMapping.h"
> +#include "llvm/ProfileData/CoverageMapping.h"
> +#include "llvm/ADT/Hashing.h"
> +#include <vector>
> +#include <unordered_map>
> +
> +namespace llvm {
> +
> +/// \brief Partions mapping regions by their kind and sums
> +/// the execution counts of the regions that start at the same location.
> +class SourceCoverageDataManager {
> +public:
> + struct SourceRange {
> + unsigned LineStart, ColumnStart, LineEnd, ColumnEnd;
> +
> + SourceRange(unsigned LineStart, unsigned ColumnStart, unsigned
> LineEnd,
> + unsigned ColumnEnd)
> + : LineStart(LineStart), ColumnStart(ColumnStart),
> LineEnd(LineEnd),
> + ColumnEnd(ColumnEnd) {}
> +
> + bool operator==(const SourceRange &Other) const {
> + return LineStart == Other.LineStart && ColumnStart ==
> Other.ColumnStart &&
> + LineEnd == Other.LineEnd && ColumnEnd == Other.ColumnEnd;
> + }
> +
> + bool operator<(const SourceRange &Other) const {
> + if (LineStart == Other.LineStart)
> + return ColumnStart < Other.ColumnStart;
> + return LineStart < Other.LineStart;
> + }
> +
> + bool contains(const SourceRange &Other) {
> + if (LineStart > Other.LineStart ||
> + (LineStart == Other.LineStart && ColumnStart >
> Other.ColumnStart))
> + return false;
> + if (LineEnd < Other.LineEnd ||
> + (LineEnd == Other.LineEnd && ColumnEnd < Other.ColumnEnd))
> + return false;
> + return true;
> + }
> + };
> +
> +protected:
> + std::vector<std::pair<SourceRange, uint64_t>> Regions;
> + std::vector<SourceRange> SkippedRegions;
> + bool Uniqued;
> +
> +public:
> + SourceCoverageDataManager() : Uniqued(false) {}
> +
> + void insert(const MappingRegion &Region);
> +
> + /// \brief Return the source ranges and execution counts
> + /// obtained from the non-skipped mapping regions.
> + ArrayRef<std::pair<SourceRange, uint64_t>> getSourceRegions();
> +
> + /// \brief Return the source ranges obtained from the skipped mapping
> regions.
> + ArrayRef<SourceRange> getSkippedRegions() const { return
> SkippedRegions; }
> +};
> +
> +} // namespace llvm
> +
> +#endif // LLVM_COV_SOURCECOVERAGEDATAMANAGER_H
>
> Added: llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/SourceCoverageView.cpp Fri Aug 22 17:56:03
> 2014
> @@ -0,0 +1,411 @@
> +//===- SourceCoverageView.cpp - Code coverage view for source code
> --------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements rendering for code coverage of source code.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "SourceCoverageView.h"
> +#include "llvm/ADT/SmallString.h"
> +#include "llvm/Support/LineIterator.h"
> +
> +using namespace llvm;
> +
> +void SourceCoverageView::renderLine(raw_ostream &OS, StringRef Line,
> + ArrayRef<HighlightRange> Ranges) {
> + if (Ranges.empty()) {
> + OS << Line << "\n";
> + return;
> + }
> + if (Line.empty())
> + Line = " ";
> +
> + unsigned PrevColumnStart = 0;
> + unsigned Start = 1;
> + for (const auto &Range : Ranges) {
> + if (PrevColumnStart == Range.ColumnStart)
> + continue;
> +
> + // Show the unhighlighted part
> + unsigned ColumnStart = PrevColumnStart = Range.ColumnStart;
> + OS << Line.substr(Start - 1, ColumnStart - Start);
> +
> + // Show the highlighted part
> + auto Color = Range.Kind == HighlightRange::NotCovered ?
> raw_ostream::RED
> + :
> raw_ostream::CYAN;
> + OS.changeColor(Color, false, true);
> + unsigned ColumnEnd = std::min(Range.ColumnEnd, (unsigned)Line.size()
> + 1);
> + OS << Line.substr(ColumnStart - 1, ColumnEnd - ColumnStart);
> + Start = ColumnEnd;
> + OS.resetColor();
> + }
> +
> + // Show the rest of the line
> + OS << Line.substr(Start - 1, Line.size() - Start + 1);
> + OS << "\n";
> +}
> +
> +void SourceCoverageView::renderOffset(raw_ostream &OS, unsigned I) {
> + for (unsigned J = 0; J < I; ++J)
> + OS << " |";
> +}
> +
> +void SourceCoverageView::renderViewDivider(unsigned Offset, unsigned
> Length,
> + raw_ostream &OS) {
> + for (unsigned J = 1; J < Offset; ++J)
> + OS << " |";
> + if (Offset != 0)
> + OS.indent(2);
> + for (unsigned I = 0; I < Length; ++I)
> + OS << "-";
> +}
> +
> +void
> +SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
> + const LineCoverageInfo
> &Line) {
> + if (!Line.isMapped()) {
> + OS.indent(LineCoverageColumnWidth) << '|';
> + return;
> + }
> + SmallString<32> Buffer;
> + raw_svector_ostream BufferOS(Buffer);
> + BufferOS << Line.ExecutionCount;
> + auto Str = BufferOS.str();
> + // Trim
> + Str = Str.substr(0, std::min(Str.size(),
> (size_t)LineCoverageColumnWidth));
> + // Align to the right
> + OS.indent(LineCoverageColumnWidth - Str.size());
> + colored_ostream(OS, raw_ostream::MAGENTA,
> + Line.hasMultipleRegions() && Options.Colors)
> + << Str;
> + OS << '|';
> +}
> +
> +void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
> + unsigned LineNo) {
> + SmallString<32> Buffer;
> + raw_svector_ostream BufferOS(Buffer);
> + BufferOS << LineNo;
> + auto Str = BufferOS.str();
> + // Trim and align to the right
> + Str = Str.substr(0, std::min(Str.size(),
> (size_t)LineNumberColumnWidth));
> + OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
> +}
> +
> +void SourceCoverageView::renderRegionMarkers(raw_ostream &OS,
> + ArrayRef<RegionMarker>
> Regions) {
> + SmallString<32> Buffer;
> + raw_svector_ostream BufferOS(Buffer);
> +
> + unsigned PrevColumn = 1;
> + for (const auto &Region : Regions) {
> + // Skip to the new region
> + if (Region.Column > PrevColumn)
> + OS.indent(Region.Column - PrevColumn);
> + PrevColumn = Region.Column + 1;
> + BufferOS << Region.ExecutionCount;
> + StringRef Str = BufferOS.str();
> + // Trim the execution count
> + Str = Str.substr(0, std::min(Str.size(), (size_t)7));
> + PrevColumn += Str.size();
> + OS << '^' << Str;
> + Buffer.clear();
> + }
> + OS << "\n";
> +}
> +
> +/// \brief Insert a new highlighting range into the line's highlighting
> ranges
> +/// Return line's new highlighting ranges in result.
> +static void insertHighlightRange(
> + ArrayRef<SourceCoverageView::HighlightRange> Ranges,
> + SourceCoverageView::HighlightRange RangeToInsert,
> + SmallVectorImpl<SourceCoverageView::HighlightRange> &Result) {
> + Result.clear();
> + size_t I = 0;
> + auto E = Ranges.size();
> + for (; I < E; ++I) {
> + if (RangeToInsert.ColumnStart < Ranges[I].ColumnEnd) {
> + const auto &Range = Ranges[I];
> + bool NextRangeContainsInserted = false;
> + // If the next range starts before the inserted range, move the end
> of the
> + // next range to the start of the inserted range.
> + if (Range.ColumnStart < RangeToInsert.ColumnStart) {
> + if (RangeToInsert.ColumnStart != Range.ColumnStart)
> + Result.push_back(SourceCoverageView::HighlightRange(
> + Range.Line, Range.ColumnStart, RangeToInsert.ColumnStart,
> + Range.Kind));
> + // If the next range also ends after the inserted range, keep
> this range
> + // and create a new range that starts at the inserted range and
> ends
> + // at the next range later.
> + if (Range.ColumnEnd > RangeToInsert.ColumnEnd)
> + NextRangeContainsInserted = true;
> + }
> + if (!NextRangeContainsInserted) {
> + ++I;
> + // Ignore ranges that are contained in inserted range
> + while (I < E && RangeToInsert.contains(Ranges[I]))
> + ++I;
> + }
> + break;
> + }
> + Result.push_back(Ranges[I]);
> + }
> + Result.push_back(RangeToInsert);
> + // If the next range starts before the inserted range end, move the
> start
> + // of the next range to the end of the inserted range.
> + if (I < E && Ranges[I].ColumnStart < RangeToInsert.ColumnEnd) {
> + const auto &Range = Ranges[I];
> + if (RangeToInsert.ColumnEnd != Range.ColumnEnd)
> + Result.push_back(SourceCoverageView::HighlightRange(
> + Range.Line, RangeToInsert.ColumnEnd, Range.ColumnEnd,
> Range.Kind));
> + ++I;
> + }
> + // Add the remaining ranges that are located after the inserted range
> + for (; I < E; ++I)
> + Result.push_back(Ranges[I]);
> +}
> +
> +void SourceCoverageView::sortChildren() {
> + for (auto &I : Children)
> + I->sortChildren();
> + std::sort(Children.begin(), Children.end(),
> + [](const std::unique_ptr<SourceCoverageView> &LHS,
> + const std::unique_ptr<SourceCoverageView> &RHS) {
> + return LHS->ExpansionRegion < RHS->ExpansionRegion;
> + });
> +}
> +
> +SourceCoverageView::HighlightRange
> +SourceCoverageView::getExpansionHighlightRange() const {
> + return HighlightRange(ExpansionRegion.LineStart,
> ExpansionRegion.ColumnStart,
> + ExpansionRegion.ColumnEnd,
> HighlightRange::Expanded);
> +}
> +
> +template <typename T>
> +ArrayRef<T> gatherLineItems(size_t &CurrentIdx, const std::vector<T>
> &Items,
> + unsigned LineNo) {
> + auto PrevIdx = CurrentIdx;
> + auto E = Items.size();
> + while (CurrentIdx < E && Items[CurrentIdx].Line == LineNo)
> + ++CurrentIdx;
> + return ArrayRef<T>(Items.data() + PrevIdx, CurrentIdx - PrevIdx);
> +}
> +
> +ArrayRef<std::unique_ptr<SourceCoverageView>>
> +gatherLineSubViews(size_t &CurrentIdx,
> + ArrayRef<std::unique_ptr<SourceCoverageView>> Items,
> + unsigned LineNo) {
> + auto PrevIdx = CurrentIdx;
> + auto E = Items.size();
> + while (CurrentIdx < E &&
> + Items[CurrentIdx]->getSubViewsExpansionLine() == LineNo)
> + ++CurrentIdx;
> + return ArrayRef<std::unique_ptr<SourceCoverageView>>(Items.data() +
> PrevIdx,
> + CurrentIdx -
> PrevIdx);
> +}
> +
> +void SourceCoverageView::render(raw_ostream &OS, unsigned Offset) {
> + // Make sure that the children are in sorted order.
> + sortChildren();
> +
> + SmallVector<HighlightRange, 8> AdjustedLineHighlightRanges;
> + size_t CurrentChild = 0;
> + size_t CurrentHighlightRange = 0;
> + size_t CurrentRegionMarker = 0;
> +
> + line_iterator Lines(File);
> + // Advance the line iterator to the first line.
> + while (Lines.line_number() < LineStart)
> + ++Lines;
> +
> + // The width of the leading columns
> + unsigned CombinedColumnWidth =
> + (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
> + (Options.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
> + // The width of the line that is used to divide between the view and the
> + // subviews.
> + unsigned DividerWidth = CombinedColumnWidth + 4;
> +
> + for (size_t I = 0; I < LineCount; ++I) {
> + unsigned LineNo = I + LineStart;
> +
> + // Gather the child subviews that are visible on this line.
> + auto LineSubViews = gatherLineSubViews(CurrentChild, Children,
> LineNo);
> +
> + renderOffset(OS, Offset);
> + if (Options.ShowLineStats)
> + renderLineCoverageColumn(OS, LineStats[I]);
> + if (Options.ShowLineNumbers)
> + renderLineNumberColumn(OS, LineNo);
> +
> + // Gather highlighting ranges.
> + auto LineHighlightRanges =
> + gatherLineItems(CurrentHighlightRange, HighlightRanges, LineNo);
> + auto LineRanges = LineHighlightRanges;
> + // Highlight the expansion range if there is an expansion subview on
> this
> + // line.
> + if (!LineSubViews.empty() &&
> LineSubViews.front()->isExpansionSubView() &&
> + Options.Colors) {
> + insertHighlightRange(LineHighlightRanges,
> +
> LineSubViews.front()->getExpansionHighlightRange(),
> + AdjustedLineHighlightRanges);
> + LineRanges = AdjustedLineHighlightRanges;
> + }
> +
> + // Display the source code for the current line.
> + StringRef Line = *Lines;
> + // Check if the line is empty, as line_iterator skips blank lines.
> + if (LineNo < Lines.line_number())
> + Line = "";
> + else if (!Lines.is_at_eof())
> + ++Lines;
> + renderLine(OS, Line, LineRanges);
> +
> + // Show the region markers.
> + bool ShowMarkers = !Options.ShowLineStatsOrRegionMarkers ||
> + LineStats[I].hasMultipleRegions();
> + auto LineMarkers = gatherLineItems(CurrentRegionMarker, Markers,
> LineNo);
> + if (ShowMarkers && !LineMarkers.empty()) {
> + renderOffset(OS, Offset);
> + OS.indent(CombinedColumnWidth);
> + renderRegionMarkers(OS, LineMarkers);
> + }
> +
> + // Show the line's expanded child subviews.
> + bool FirstChildExpansion = true;
> + if (LineSubViews.empty())
> + continue;
> + unsigned NewOffset = Offset + 1;
> + renderViewDivider(NewOffset, DividerWidth, OS);
> + OS << "\n";
> + for (const auto &Child : LineSubViews) {
> + // If this subview shows a function instantiation, render the
> function's
> + // name.
> + if (Child->isInstantiationSubView()) {
> + renderOffset(OS, NewOffset);
> + OS << ' ';
> + Options.colored_ostream(OS, raw_ostream::CYAN) <<
> Child->FunctionName
> + << ":";
> + OS << "\n";
> + } else {
> + if (!FirstChildExpansion) {
> + // Re-render the current line and highlight the expansion range
> for
> + // this
> + // subview.
> + insertHighlightRange(LineHighlightRanges,
> + Child->getExpansionHighlightRange(),
> + AdjustedLineHighlightRanges);
> + renderOffset(OS, Offset);
> + OS.indent(CombinedColumnWidth + (Offset == 0 ? 0 : 1));
> + renderLine(OS, Line, AdjustedLineHighlightRanges);
> + renderViewDivider(NewOffset, DividerWidth, OS);
> + OS << "\n";
> + } else
> + FirstChildExpansion = false;
> + }
> + // Render the child subview
> + Child->render(OS, NewOffset);
> + renderViewDivider(NewOffset, DividerWidth, OS);
> + OS << "\n";
> + }
> + }
> +}
> +
> +void
> +SourceCoverageView::createLineCoverageInfo(SourceCoverageDataManager
> &Data) {
> + LineStats.resize(LineCount);
> + for (const auto &Region : Data.getSourceRegions()) {
> + auto Value = Region.second;
> + LineStats[Region.first.LineStart -
> LineStart].addRegionStartCount(Value);
> + for (unsigned Line = Region.first.LineStart + 1;
> + Line <= Region.first.LineEnd; ++Line)
> + LineStats[Line - LineStart].addRegionCount(Value);
> + }
> +
> + // Reset the line stats for skipped regions.
> + for (const auto &Region : Data.getSkippedRegions()) {
> + for (unsigned Line = Region.LineStart; Line <= Region.LineEnd; ++Line)
> + LineStats[Line - LineStart] = LineCoverageInfo();
> + }
> +}
> +
> +void
> +SourceCoverageView::createHighlightRanges(SourceCoverageDataManager
> &Data) {
> + auto Regions = Data.getSourceRegions();
> + std::vector<bool> AlreadyHighlighted;
> + AlreadyHighlighted.resize(Regions.size(), false);
> +
> + for (size_t I = 0, S = Regions.size(); I < S; ++I) {
> + const auto &Region = Regions[I];
> + auto Value = Region.second;
> + auto SrcRange = Region.first;
> + if (Value != 0)
> + continue;
> + if (AlreadyHighlighted[I])
> + continue;
> + for (size_t J = 0; J < S; ++J) {
> + if (SrcRange.contains(Regions[J].first)) {
> + AlreadyHighlighted[J] = true;
> + }
> + }
> + if (SrcRange.LineStart == SrcRange.LineEnd) {
> + HighlightRanges.push_back(HighlightRange(
> + SrcRange.LineStart, SrcRange.ColumnStart, SrcRange.ColumnEnd));
> + continue;
> + }
> + HighlightRanges.push_back(
> + HighlightRange(SrcRange.LineStart, SrcRange.ColumnStart,
> + std::numeric_limits<unsigned>::max()));
> + HighlightRanges.push_back(
> + HighlightRange(SrcRange.LineEnd, 1, SrcRange.ColumnEnd));
> + for (unsigned Line = SrcRange.LineStart + 1; Line < SrcRange.LineEnd;
> + ++Line) {
> + HighlightRanges.push_back(
> + HighlightRange(Line, 1, std::numeric_limits<unsigned>::max()));
> + }
> + }
> +
> + std::sort(HighlightRanges.begin(), HighlightRanges.end());
> +
> + if (Options.Debug) {
> + for (const auto &Range : HighlightRanges) {
> + outs() << "Highlighted line " << Range.Line << ", " <<
> Range.ColumnStart
> + << " -> ";
> + if (Range.ColumnEnd == std::numeric_limits<unsigned>::max()) {
> + outs() << "?\n";
> + } else {
> + outs() << Range.ColumnEnd << "\n";
> + }
> + }
> + }
> +}
> +
> +void SourceCoverageView::createRegionMarkers(SourceCoverageDataManager
> &Data) {
> + for (const auto &Region : Data.getSourceRegions()) {
> + if (Region.first.LineStart >= LineStart)
> + Markers.push_back(RegionMarker(Region.first.LineStart,
> + Region.first.ColumnStart,
> Region.second));
> + }
> +
> + if (Options.Debug) {
> + for (const auto &Marker : Markers) {
> + outs() << "Marker at " << Marker.Line << ":" << Marker.Column << "
> = "
> + << Marker.ExecutionCount << "\n";
> + }
> + }
> +}
> +
> +void SourceCoverageView::load(SourceCoverageDataManager &Data) {
> + if (Options.ShowLineStats)
> + createLineCoverageInfo(Data);
> + if (Options.Colors)
> + createHighlightRanges(Data);
> + if (Options.ShowRegionMarkers)
> + createRegionMarkers(Data);
> +}
>
> Added: llvm/trunk/tools/llvm-cov/SourceCoverageView.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/SourceCoverageView.h?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/SourceCoverageView.h (added)
> +++ llvm/trunk/tools/llvm-cov/SourceCoverageView.h Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,213 @@
> +//===- SourceCoverageView.h - Code coverage view for source code
> ----------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +// This class implements rendering for code coverage of source code.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
> +#define LLVM_COV_SOURCECOVERAGEVIEW_H
> +
> +#include "CoverageViewOptions.h"
> +#include "SourceCoverageDataManager.h"
> +#include "llvm/ProfileData/CoverageMapping.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +#include <vector>
> +
> +namespace llvm {
> +
> +/// \brief A code coverage view of a specific source file.
> +/// It can have embedded coverage views.
> +class SourceCoverageView {
> +public:
> + enum SubViewKind { View, ExpansionView, InstantiationView };
> +
> + /// \brief Coverage information for a single line.
> + struct LineCoverageInfo {
> + uint64_t ExecutionCount;
> + unsigned RegionCount;
> + bool Mapped;
> +
> + LineCoverageInfo() : ExecutionCount(0), RegionCount(0), Mapped(false)
> {}
> +
> + bool isMapped() const { return Mapped; }
> +
> + bool hasMultipleRegions() const { return RegionCount > 1; }
> +
> + void addRegionStartCount(uint64_t Count) {
> + Mapped = true;
> + ExecutionCount = Count;
> + ++RegionCount;
> + }
> +
> + void addRegionCount(uint64_t Count) {
> + Mapped = true;
> + ExecutionCount = Count;
> + }
> + };
> +
> + /// \brief A marker that points at the start
> + /// of a specific mapping region.
> + struct RegionMarker {
> + unsigned Line, Column;
> + uint64_t ExecutionCount;
> +
> + RegionMarker(unsigned Line, unsigned Column, uint64_t Value)
> + : Line(Line), Column(Column), ExecutionCount(Value) {}
> + };
> +
> + /// \brief A single line source range used to
> + /// render highlighted text.
> + struct HighlightRange {
> + enum HighlightKind {
> + /// The code that wasn't executed.
> + NotCovered,
> +
> + /// The region of code that was expanded.
> + Expanded
> + };
> + HighlightKind Kind;
> + unsigned Line;
> + unsigned ColumnStart;
> + unsigned ColumnEnd;
> +
> + HighlightRange(unsigned Line, unsigned ColumnStart, unsigned
> ColumnEnd,
> + HighlightKind Kind = NotCovered)
> + : Kind(Kind), Line(Line), ColumnStart(ColumnStart),
> + ColumnEnd(ColumnEnd) {}
> +
> + bool operator<(const HighlightRange &Other) const {
> + if (Line == Other.Line)
> + return ColumnStart < Other.ColumnStart;
> + return Line < Other.Line;
> + }
> +
> + bool columnStartOverlaps(const HighlightRange &Other) const {
> + return ColumnStart <= Other.ColumnStart && ColumnEnd >
> Other.ColumnStart;
> + }
> + bool columnEndOverlaps(const HighlightRange &Other) const {
> + return ColumnEnd >= Other.ColumnEnd && ColumnStart <
> Other.ColumnEnd;
> + }
> + bool contains(const HighlightRange &Other) const {
> + if (Line != Other.Line)
> + return false;
> + return ColumnStart <= Other.ColumnStart && ColumnEnd >=
> Other.ColumnEnd;
> + }
> +
> + bool overlaps(const HighlightRange &Other) const {
> + if (Line != Other.Line)
> + return false;
> + return columnStartOverlaps(Other) || columnEndOverlaps(Other);
> + }
> + };
> +
> +private:
> + const MemoryBuffer &File;
> + const CoverageViewOptions &Options;
> + unsigned LineStart, LineCount;
> + SubViewKind Kind;
> + coverage::CounterMappingRegion ExpansionRegion;
> + std::vector<std::unique_ptr<SourceCoverageView>> Children;
> + std::vector<LineCoverageInfo> LineStats;
> + std::vector<HighlightRange> HighlightRanges;
> + std::vector<RegionMarker> Markers;
> + StringRef FunctionName;
> +
> + /// \brief Create the line coverage information using the coverage data.
> + void createLineCoverageInfo(SourceCoverageDataManager &Data);
> +
> + /// \brief Create the line highlighting ranges using the coverage data.
> + void createHighlightRanges(SourceCoverageDataManager &Data);
> +
> + /// \brief Create the region markers using the coverage data.
> + void createRegionMarkers(SourceCoverageDataManager &Data);
> +
> + /// \brief Sort children by the starting location.
> + void sortChildren();
> +
> + /// \brief Return a highlight range for the expansion region of this
> view.
> + HighlightRange getExpansionHighlightRange() const;
> +
> + /// \brief Render a source line with highlighting.
> + void renderLine(raw_ostream &OS, StringRef Line,
> + ArrayRef<HighlightRange> Ranges);
> +
> + void renderOffset(raw_ostream &OS, unsigned I);
> +
> + void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream
> &OS);
> +
> + /// \brief Render the line's execution count column.
> + void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageInfo
> &Line);
> +
> + /// \brief Render the line number column.
> + void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
> +
> + /// \brief Render all the region's execution counts on a line.
> + void renderRegionMarkers(raw_ostream &OS, ArrayRef<RegionMarker>
> Regions);
> +
> + static const unsigned LineCoverageColumnWidth = 7;
> + static const unsigned LineNumberColumnWidth = 5;
> +
> +public:
> + SourceCoverageView(const MemoryBuffer &File,
> + const CoverageViewOptions &Options)
> + : File(File), Options(Options), LineStart(1), Kind(View),
> + ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0) {
> + LineCount = File.getBuffer().count('\n') + 1;
> + }
> +
> + SourceCoverageView(const MemoryBuffer &File,
> + const CoverageViewOptions &Options, unsigned
> LineStart,
> + unsigned LineEnd)
> + : File(File), Options(Options), LineStart(LineStart),
> + LineCount(LineEnd - LineStart + 1), Kind(View),
> + ExpansionRegion(coverage::Counter(), 0, 0, 0, 0, 0) {}
> +
> + SourceCoverageView(SourceCoverageView &Parent, unsigned LineStart,
> + unsigned LineEnd, StringRef FunctionName)
> + : File(Parent.File), Options(Parent.Options), LineStart(LineStart),
> + LineCount(LineEnd - LineStart + 1), Kind(InstantiationView),
> + ExpansionRegion(coverage::Counter(), 0, LineEnd, 0, LineEnd, 0),
> + FunctionName(FunctionName) {}
> +
> + SourceCoverageView(const MemoryBuffer &File,
> + const CoverageViewOptions &Options, unsigned
> LineStart,
> + unsigned LineEnd,
> + const coverage::CounterMappingRegion
> &ExpansionRegion)
> + : File(File), Options(Options), LineStart(LineStart),
> + LineCount(LineEnd - LineStart + 1), Kind(ExpansionView),
> + ExpansionRegion(ExpansionRegion) {}
> +
> + const CoverageViewOptions &getOptions() const { return Options; }
> +
> + bool isExpansionSubView() const { return Kind == ExpansionView; }
> +
> + bool isInstantiationSubView() const { return Kind == InstantiationView;
> }
> +
> + /// \brief Return the line number after which the subview expansion is
> shown.
> + unsigned getSubViewsExpansionLine() const {
> + return ExpansionRegion.LineStart;
> + }
> +
> + void addChild(std::unique_ptr<SourceCoverageView> View) {
> + Children.push_back(std::move(View));
> + }
> +
> + /// \brief Print the code coverage information for a specific
> + /// portion of a source file to the output stream.
> + void render(raw_ostream &OS, unsigned Offset = 0);
> +
> + /// \brief Load the coverage information required for rendering
> + /// from the mapping regions in the data manager.
> + void load(SourceCoverageDataManager &Data);
> +};
> +
> +} // namespace llvm
> +
> +#endif // LLVM_COV_SOURCECOVERAGEVIEW_H
>
> Added: llvm/trunk/tools/llvm-cov/TestingSupport.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/TestingSupport.cpp?rev=216300&view=auto
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/TestingSupport.cpp (added)
> +++ llvm/trunk/tools/llvm-cov/TestingSupport.cpp Fri Aug 22 17:56:03 2014
> @@ -0,0 +1,92 @@
> +//===- TestingSupport.cpp - Convert objects files into test files
> --------===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Object/ObjectFile.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Support/LEB128.h"
> +#include "llvm/Support/CommandLine.h"
> +#include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/MemoryObject.h"
> +#include "llvm/Support/Signals.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include <system_error>
> +#include <functional>
> +
> +using namespace llvm;
> +using namespace object;
> +
> +int convert_for_testing_main(int argc, const char **argv) {
> + sys::PrintStackTraceOnErrorSignal();
> + PrettyStackTraceProgram X(argc, argv);
> + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
> +
> + cl::opt<std::string> InputSourceFile(cl::Positional, cl::Required,
> + cl::desc("<Source file>"));
> +
> + cl::opt<std::string> OutputFilename(
> + "o", cl::Required,
> + cl::desc(
> + "File with the profile data obtained after an instrumented
> run"));
> +
> + cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
> +
> + auto ObjErr =
> llvm::object::ObjectFile::createObjectFile(InputSourceFile);
> + if (auto Err = ObjErr.getError()) {
> + errs() << "error: " << Err.message() << "\n";
> + return 1;
> + }
> + ObjectFile *OF = ObjErr.get().getBinary().get();
> + auto BytesInAddress = OF->getBytesInAddress();
> + if (BytesInAddress != 8) {
> + errs() << "error: 64 bit binary expected\n";
> + return 1;
> + }
> +
> + // Look for the sections that we are interested in.
> + int FoundSectionCount = 0;
> + SectionRef ProfileNames, CoverageMapping;
> + for (const auto &Section : OF->sections()) {
> + StringRef Name;
> + if (Section.getName(Name))
> + return 1;
> + if (Name == "__llvm_prf_names") {
> + ProfileNames = Section;
> + } else if (Name == "__llvm_covmap") {
> + CoverageMapping = Section;
> + } else
> + continue;
> + ++FoundSectionCount;
> + }
> + if (FoundSectionCount != 2)
> + return 1;
> +
> + // Get the contents of the given sections.
> + StringRef CoverageMappingData;
> + uint64_t ProfileNamesAddress;
> + StringRef ProfileNamesData;
> + if (CoverageMapping.getContents(CoverageMappingData) ||
> + ProfileNames.getAddress(ProfileNamesAddress) ||
> + ProfileNames.getContents(ProfileNamesData))
> + return 1;
> +
> + int FD;
> + if (auto Err =
> + sys::fs::openFileForWrite(OutputFilename, FD, sys::fs::F_None))
> {
> + errs() << "error: " << Err.message() << "\n";
> + return 1;
> + }
> +
> + raw_fd_ostream OS(FD, true);
> + OS << "llvmcovmtestdata";
> + encodeULEB128(ProfileNamesData.size(), OS);
> + encodeULEB128(ProfileNamesAddress, OS);
> + OS << ProfileNamesData << CoverageMappingData;
> +
> + return 0;
> +}
>
> Modified: llvm/trunk/tools/llvm-cov/llvm-cov.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/llvm-cov.cpp?rev=216300&r1=216299&r2=216300&view=diff
>
> ==============================================================================
> --- llvm/trunk/tools/llvm-cov/llvm-cov.cpp (original)
> +++ llvm/trunk/tools/llvm-cov/llvm-cov.cpp Fri Aug 22 17:56:03 2014
> @@ -11,9 +11,63 @@
> //
>
> //===----------------------------------------------------------------------===//
>
> -/// \brief The main function for the gcov compatible coverage tool
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Support/Path.h"
> +#include <string>
> +
> +using namespace llvm;
> +
> +/// \brief The main entry point for the 'show' subcommand.
> +int show_main(int argc, const char **argv);
> +
> +/// \brief The main entry point for the 'report' subcommand.
> +int report_main(int argc, const char **argv);
> +
> +/// \brief The main entry point for the 'convert-for-testing' subcommand.
> +int convert_for_testing_main(int argc, const char **argv);
> +
> +/// \brief The main entry point for the gcov compatible coverage tool.
> int gcov_main(int argc, const char **argv);
>
> int main(int argc, const char **argv) {
> + // If argv[0] is or ends with 'gcov', always be gcov compatible
> + if (sys::path::stem(argv[0]).endswith_lower("gcov"))
> + return gcov_main(argc, argv);
> +
> + // Check if we are invoking a specific tool command.
> + if (argc > 1) {
> + int (*func)(int, const char **) = nullptr;
> +
> + StringRef command = argv[1];
> + if (command.equals_lower("show"))
> + func = show_main;
> + else if (command.equals_lower("report"))
> + func = report_main;
> + else if (command.equals_lower("convert-for-testing"))
> + func = convert_for_testing_main;
> + else if (command.equals_lower("gcov"))
> + func = gcov_main;
> +
> + if (func) {
> + std::string Invocation(std::string(argv[0]) + " " + argv[1]);
> + argv[1] = Invocation.c_str();
> + return func(argc - 1, argv + 1);
> + }
> + }
> +
> + // Give a warning and fall back to gcov
> + errs().changeColor(raw_ostream::RED);
> + errs() << "warning:";
> + // Assume that argv[1] wasn't a command when it stats with a '-' or is a
> + // filename (i.e. contains a '.')
> + if (argc > 1 && !StringRef(argv[1]).startswith("-") &&
> + StringRef(argv[1]).find(".") == StringRef::npos)
> + errs() << " Unrecognized command '" << argv[1] << "'.";
> + errs() << " Using the gcov compatible mode "
> + "(this behaviour may be dropped in the future).";
> + errs().resetColor();
> + errs() << "\n";
> +
> return gcov_main(argc, argv);
> }
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20140822/3e6d782b/attachment.html>
More information about the llvm-commits
mailing list