Index: test/tools/llvm-cov/Inputs/name_whitelist.cpp =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/name_whitelist.cpp @@ -0,0 +1,18 @@ +int func1() { + return 1; +} +int func2() { + return 1; +} +int func3() { + return 1; +} +int func4() { + return 1; +} +int func5() { + return 1; +} +int func6() { + return 1; +} Index: test/tools/llvm-cov/Inputs/name_whitelist.proftext =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/name_whitelist.proftext @@ -0,0 +1,56 @@ +_Z5func1v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +_Z5func2v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +_Z5func3v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +_Z5func4v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +main +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +1 + +_Z5func5v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + +_Z5func6v +# Func Hash: +0 +# Num Counters: +1 +# Counter Values: +0 + Index: test/tools/llvm-cov/Inputs/whitelist1.txt =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/whitelist1.txt @@ -0,0 +1,4 @@ +# Comment + +func1 # Comment + func2 # Comment Index: test/tools/llvm-cov/Inputs/whitelist2.txt =================================================================== --- /dev/null +++ test/tools/llvm-cov/Inputs/whitelist2.txt @@ -0,0 +1,2 @@ +func3 +func4 Index: test/tools/llvm-cov/name_whitelist.test =================================================================== --- /dev/null +++ test/tools/llvm-cov/name_whitelist.test @@ -0,0 +1,21 @@ +RUN: llvm-profdata merge %S/Inputs/name_whitelist.proftext -o %t.profdata + +RUN: llvm-cov show %S/Inputs/name_whitelist.covmapping -instr-profile=%t.profdata -path-equivalence=/tmp,%S/Inputs -name-whitelist=%S/Inputs/whitelist1.txt %S/Inputs/name_whitelist.cpp > %t.one_list +RUN: FileCheck -input-file=%t.one_list -check-prefix=ONE_WHITELIST %s +RUN: FileCheck -input-file=%t.one_list -check-prefix=ONE_WHITELIST_NEG %s +ONE_WHITELIST: _Z5func1v: +ONE_WHITELIST: _Z5func2v: +ONE_WHITELIST_NEG-NOT: _Z5func3v: +ONE_WHITELIST_NEG-NOT: _Z5func4v: +ONE_WHITELIST_NEG-NOT: _Z5func5v: +ONE_WHITELIST_NEG-NOT: _Z5func6v: + +RUN: llvm-cov show %S/Inputs/name_whitelist.covmapping -instr-profile=%t.profdata -path-equivalence=/tmp,%S/Inputs -name-whitelist=%S/Inputs/whitelist1.txt -name-whitelist=%S/Inputs/whitelist2.txt %S/Inputs/name_whitelist.cpp > %t.two_list +RUN: FileCheck -input-file=%t.two_list -check-prefix=TWO_WHITELIST %s +RUN: FileCheck -input-file=%t.two_list -check-prefix=TWO_WHITELIST_NEG %s +TWO_WHITELIST: _Z5func1v: +TWO_WHITELIST: _Z5func2v: +TWO_WHITELIST: _Z5func3v: +TWO_WHITELIST: _Z5func4v: +TWO_WHITELIST_NEG-NOT: _Z5func5v: +TWO_WHITELIST_NEG-NOT: _Z5func6v: Index: tools/llvm-cov/CodeCoverage.cpp =================================================================== --- tools/llvm-cov/CodeCoverage.cpp +++ tools/llvm-cov/CodeCoverage.cpp @@ -150,6 +150,9 @@ std::mutex LoadedSourceFilesLock; std::vector>> LoadedSourceFiles; + + /// Function names from -name-whitelist to be used for filtering. + std::vector FilteredFunctionNamesFromFile; }; } @@ -561,6 +564,12 @@ cl::desc("Show code coverage only for functions with the given name"), cl::ZeroOrMore, cl::cat(FilteringCategory)); + cl::list NameFilterFiles( + "name-whitelist", cl::Optional, + cl::desc("Show code coverage only for functions listed in the given " + "file"), + cl::ZeroOrMore, cl::cat(FilteringCategory)); + cl::list NameRegexFilters( "name-regex", cl::Optional, cl::desc("Show code coverage only for functions that match the given " @@ -643,11 +652,31 @@ ViewOpts.DemanglerOpts.swap(DemanglerOpts); } + // Read in -name-whitelist files. + for (const auto &NameFile : NameFilterFiles) { + auto BufOrError = MemoryBuffer::getFile(NameFile); + if (!BufOrError) { + error(NameFile, BufOrError.getError().message()); + continue; + } + for (line_iterator LI(**BufOrError, /*SkipBlanks=*/true, + /*CommentMarker=*/'#'); + !LI.is_at_eof(); ++LI) { + auto Name = + LI->take_until([](char C) -> bool { return C == '#'; }).trim(); + if (!Name.empty()) + FilteredFunctionNamesFromFile.push_back(Name); + } + } + // Create the function filters - if (!NameFilters.empty() || !NameRegexFilters.empty()) { + if (!NameFilters.empty() || !FilteredFunctionNamesFromFile.empty() || + !NameRegexFilters.empty()) { auto NameFilterer = llvm::make_unique(); for (const auto &Name : NameFilters) NameFilterer->push_back(llvm::make_unique(Name)); + for (const auto &Name : FilteredFunctionNamesFromFile) + NameFilterer->push_back(llvm::make_unique(Name)); for (const auto &Regex : NameRegexFilters) NameFilterer->push_back( llvm::make_unique(Regex));