[llvm] r216300 - llvm-cov: add code coverage tool that's based on coverage mapping format and clang's pgo.
Sean Silva
chisophugis at gmail.com
Fri Aug 22 18:56:36 PDT 2014
On Fri, Aug 22, 2014 at 5:54 PM, Alex L <arphaman at gmail.com> wrote:
> The big-endian buildbots are failing, I will commit an XFAIL for
> big-endian for now.
>
In the future, consider just reverting instead. The benefit of doing that
is that then there isn't an XFAIL that can be forgotten.
-- Sean Silva
>
>
> 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
>>
>
>
> _______________________________________________
> 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/95b7c087/attachment.html>
More information about the llvm-commits
mailing list