[llvm] [mlir] [llvm-cov] Add inline exclusion marker support for coverage reporting (PR #203723)
Maksim Levental via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 13 12:42:32 PDT 2026
https://github.com/makslevental created https://github.com/llvm/llvm-project/pull/203723
Add --exclude-line-regex, --exclude-region-start-regex, and --exclude-region-stop-regex options to llvm-cov. These allow excluding lines from coverage totals based on inline source comments.
Defaults: LCOV_EXCL_LINE (single line), LCOV_EXCL_START/LCOV_EXCL_STOP (region). This brings parity with lcov/gcov exclusion markers and kcov --exclude-line regex support.
The implementation scans source files for markers when loaded, builds a per-file set of excluded line numbers, and subtracts them from the line coverage totals in prepareFileReports().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
>From bd6c6fa2345f5976d8f495a0eb051a8949cb8bd5 Mon Sep 17 00:00:00 2001
From: Maksim Levental <maksim.levental at gmail.com>
Date: Fri, 12 Jun 2026 23:27:02 -0700
Subject: [PATCH 1/6] [mlir-tblgen] Render enum keyword alternatives in
generated attr/type docs
When mlir-tblgen generates documentation for AttrDefs/TypeDefs that have
EnumParameter fields, it previously rendered the raw C++ type (e.g.
`::mlir::ns::MyEnum`) in the syntax block. This was unhelpful for
users who need to know the valid keyword values.
This patch:
1. Adds an `EnumInfo enum = enumInfo;` field to the `EnumParameter`
TableGen class, persisting the enum record for tooling to inspect.
2. Modifies `emitAttrOrTypeDefAssemblyFormat` in OpDocGen.cpp to detect
EnumParameter fields and render their cases as backtick-quoted
alternatives (e.g. `` `read` | `read_write` ``).
3. Adds a test case to gen-dialect-doc.td verifying the new behavior.
Before:
#my_dialect.my_attr<
int32_t, # index
::mlir::ns::MyEnum, # access
>
After:
#my_dialect.my_attr<
int32_t, # index
`read` | `read_write`, # access
>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
mlir/include/mlir/IR/EnumAttr.td | 3 +++
mlir/test/mlir-tblgen/gen-dialect-doc.td | 25 ++++++++++++++++++++++++
mlir/tools/mlir-tblgen/OpDocGen.cpp | 24 ++++++++++++++++++++++-
3 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td
index 6eef5075fe18a..5f3384e95ba79 100644
--- a/mlir/include/mlir/IR/EnumAttr.td
+++ b/mlir/include/mlir/IR/EnumAttr.td
@@ -503,6 +503,9 @@ class I64BitEnumAttr<string name, string summary,
class EnumParameter<EnumInfo enumInfo>
: AttrParameter<enumInfo.cppNamespace # "::" # enumInfo.className,
"an enum of type " # enumInfo.className> {
+ // Store the enum info so that tooling (e.g. doc generation) can inspect the
+ // enum cases without re-parsing the C++ type string.
+ EnumInfo enum = enumInfo;
let parser = !if(!isa<EnumAttrInfo>(enumInfo),
!cast<EnumAttrInfo>(enumInfo).parameterParser, ?);
let printer = !if(!isa<EnumAttrInfo>(enumInfo),
diff --git a/mlir/test/mlir-tblgen/gen-dialect-doc.td b/mlir/test/mlir-tblgen/gen-dialect-doc.td
index 72916704369ee..c373f3fb6801b 100644
--- a/mlir/test/mlir-tblgen/gen-dialect-doc.td
+++ b/mlir/test/mlir-tblgen/gen-dialect-doc.td
@@ -67,6 +67,24 @@ def TestAttrDefParams : AttrDef<Test_Dialect, "TestAttrDefParams"> {
let assemblyFormat = "`<` $value `>`";
}
+def TestEnumForParam :
+ I32EnumAttr<"TestEnumForParam",
+ "enum for param test", [
+ I32EnumAttrCase<"Alpha", 0, "alpha">,
+ I32EnumAttrCase<"Beta", 1, "beta">]> {
+ let genSpecializedAttr = 0;
+ let cppNamespace = "NS";
+}
+
+def TestAttrWithEnum : AttrDef<Test_Dialect, "TestAttrWithEnum"> {
+ let mnemonic = "with_enum";
+ let parameters = (ins
+ "int":$value,
+ EnumParameter<TestEnumForParam>:$mode
+ );
+ let assemblyFormat = "`<` $value `,` $mode `>`";
+}
+
def TestTypeDef : TypeDef<Test_Dialect, "TestTypeDef"> {
let mnemonic = "test_type_def";
}
@@ -140,6 +158,13 @@ def TestEnum :
// CHECK: Syntax:
// CHECK: #test.test_attr_def_params
+// CHECK: TestAttrWithEnumAttr
+// CHECK: Syntax:
+// CHECK: #test.with_enum<
+// CHECK-NEXT: int, # value
+// CHECK-NEXT: `alpha` | `beta` # mode
+// CHECK-NEXT: >
+
// CHECK: ## Type constraints
// CHECK: ### type summary
// CHECK: type description
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 5e3cf302ed3ea..7c050dbb08a3b 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -384,6 +384,25 @@ static void emitTypeDoc(const Type &type, raw_ostream &os) {
// TypeDef Documentation
//===----------------------------------------------------------------------===//
+/// If \p param is an EnumParameter, return a string listing the enum's keyword
+/// alternatives (e.g. "`read` | `read_write`"). Otherwise return std::nullopt.
+static std::optional<std::string>
+getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
+ const auto *paramDef = dyn_cast<DefInit>(param.getDef());
+ if (!paramDef || !paramDef->getDef()->isSubClassOf("EnumParameter"))
+ return std::nullopt;
+ const Record *enumRec = paramDef->getDef()->getValueAsDef("enum");
+ EnumInfo enumInfo(enumRec);
+ std::vector<EnumCase> cases = enumInfo.getAllCases();
+ std::string result;
+ for (const auto &caseIt : llvm::enumerate(cases)) {
+ if (caseIt.index() > 0)
+ result += " | ";
+ result += (llvm::Twine("`") + caseIt.value().getStr() + "`").str();
+ }
+ return result;
+}
+
static void emitAttrOrTypeDefAssemblyFormat(const AttrOrTypeDef &def,
raw_ostream &os) {
ArrayRef<AttrOrTypeParameter> parameters = def.getParameters();
@@ -399,7 +418,10 @@ static void emitAttrOrTypeDefAssemblyFormat(const AttrOrTypeDef &def,
<< "<\n";
for (const auto &it : llvm::enumerate(parameters)) {
const AttrOrTypeParameter ¶m = it.value();
- os << " " << param.getSyntax();
+ if (auto enumSyntax = getEnumParameterDocSyntax(param))
+ os << " " << *enumSyntax;
+ else
+ os << " " << param.getSyntax();
if (it.index() < (parameters.size() - 1))
os << ",";
os << " # " << param.getName() << "\n";
>From f29b6c0f70c616fd0096e1115b520c20cd8e29d6 Mon Sep 17 00:00:00 2001
From: Maksim Levental <maksim.levental at gmail.com>
Date: Sat, 13 Jun 2026 06:27:21 -0700
Subject: [PATCH 2/6] Update mlir/tools/mlir-tblgen/OpDocGen.cpp
Co-authored-by: Federico Bruzzone <federico.bruzzone.i at gmail.com>
---
mlir/tools/mlir-tblgen/OpDocGen.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index 7c050dbb08a3b..d91b134764b28 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -384,7 +384,7 @@ static void emitTypeDoc(const Type &type, raw_ostream &os) {
// TypeDef Documentation
//===----------------------------------------------------------------------===//
-/// If \p param is an EnumParameter, return a string listing the enum's keyword
+/// If `param` is an EnumParameter, return a string listing the enum's keyword
/// alternatives (e.g. "`read` | `read_write`"). Otherwise return std::nullopt.
static std::optional<std::string>
getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
>From 47001d7786004f3383537c7643d6fe64e2b51db6 Mon Sep 17 00:00:00 2001
From: makslevental <m_levental at apple.com>
Date: Sat, 13 Jun 2026 08:53:46 -0700
Subject: [PATCH 3/6] address comment
---
mlir/tools/mlir-tblgen/OpDocGen.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp
index d91b134764b28..971039d31ed34 100644
--- a/mlir/tools/mlir-tblgen/OpDocGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp
@@ -395,11 +395,9 @@ getEnumParameterDocSyntax(const AttrOrTypeParameter ¶m) {
EnumInfo enumInfo(enumRec);
std::vector<EnumCase> cases = enumInfo.getAllCases();
std::string result;
- for (const auto &caseIt : llvm::enumerate(cases)) {
- if (caseIt.index() > 0)
- result += " | ";
- result += (llvm::Twine("`") + caseIt.value().getStr() + "`").str();
- }
+ llvm::interleave(
+ cases, [&](const EnumCase &c) { result += "`" + c.getStr().str() + "`"; },
+ [&] { result += " | "; });
return result;
}
>From 65bab0af8c05007b3522148ffed8af40ca6c4587 Mon Sep 17 00:00:00 2001
From: makslevental <m_levental at apple.com>
Date: Sat, 13 Jun 2026 08:56:25 -0700
Subject: [PATCH 4/6] remove unncessary comment
---
mlir/include/mlir/IR/EnumAttr.td | 2 --
1 file changed, 2 deletions(-)
diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td
index 5f3384e95ba79..4b7ea55d089d6 100644
--- a/mlir/include/mlir/IR/EnumAttr.td
+++ b/mlir/include/mlir/IR/EnumAttr.td
@@ -503,8 +503,6 @@ class I64BitEnumAttr<string name, string summary,
class EnumParameter<EnumInfo enumInfo>
: AttrParameter<enumInfo.cppNamespace # "::" # enumInfo.className,
"an enum of type " # enumInfo.className> {
- // Store the enum info so that tooling (e.g. doc generation) can inspect the
- // enum cases without re-parsing the C++ type string.
EnumInfo enum = enumInfo;
let parser = !if(!isa<EnumAttrInfo>(enumInfo),
!cast<EnumAttrInfo>(enumInfo).parameterParser, ?);
>From 81435fc4e5eda29a6299729736f9a8019e8ca3c9 Mon Sep 17 00:00:00 2001
From: makslevental <m_levental at apple.com>
Date: Sat, 13 Jun 2026 09:03:50 -0700
Subject: [PATCH 5/6] add another test
---
mlir/test/mlir-tblgen/gen-dialect-doc.td | 27 ++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/mlir/test/mlir-tblgen/gen-dialect-doc.td b/mlir/test/mlir-tblgen/gen-dialect-doc.td
index c373f3fb6801b..b279b518b85a9 100644
--- a/mlir/test/mlir-tblgen/gen-dialect-doc.td
+++ b/mlir/test/mlir-tblgen/gen-dialect-doc.td
@@ -85,6 +85,26 @@ def TestAttrWithEnum : AttrDef<Test_Dialect, "TestAttrWithEnum"> {
let assemblyFormat = "`<` $value `,` $mode `>`";
}
+def TestEnumWithAttrWrapper :
+ I32EnumAttr<"TestEnumWithWrapper",
+ "enum with attr wrapper", [
+ I32EnumAttrCase<"Red", 0, "red">,
+ I32EnumAttrCase<"Green", 1, "green">,
+ I32EnumAttrCase<"Blue", 2, "blue">]> {
+ let genSpecializedAttr = 0;
+ let cppNamespace = "NS";
+}
+def TestEnumWithWrapperAttr : EnumAttr<Test_Dialect, TestEnumWithAttrWrapper, "color">;
+
+def TestAttrWithWrappedEnum : AttrDef<Test_Dialect, "TestAttrWithWrappedEnum"> {
+ let mnemonic = "with_wrapped_enum";
+ let parameters = (ins
+ "int":$id,
+ EnumParameter<TestEnumWithAttrWrapper>:$color
+ );
+ let assemblyFormat = "`<` $id `,` $color `>`";
+}
+
def TestTypeDef : TypeDef<Test_Dialect, "TestTypeDef"> {
let mnemonic = "test_type_def";
}
@@ -165,6 +185,13 @@ def TestEnum :
// CHECK-NEXT: `alpha` | `beta` # mode
// CHECK-NEXT: >
+// CHECK: TestAttrWithWrappedEnumAttr
+// CHECK: Syntax:
+// CHECK: #test.with_wrapped_enum<
+// CHECK-NEXT: int, # id
+// CHECK-NEXT: `red` | `green` | `blue` # color
+// CHECK-NEXT: >
+
// CHECK: ## Type constraints
// CHECK: ### type summary
// CHECK: type description
>From 0f0ab35b1a56d74a3ed24c45940f3cf793f7271d Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Sat, 13 Jun 2026 12:03:15 -0700
Subject: [PATCH 6/6] [llvm-cov] Add inline exclusion marker support for
coverage reporting
Add --exclude-line-regex, --exclude-region-start-regex, and
--exclude-region-stop-regex options to llvm-cov. These allow excluding
lines from coverage totals based on inline source comments.
Defaults: LCOV_EXCL_LINE (single line), LCOV_EXCL_START/LCOV_EXCL_STOP
(region). This brings parity with lcov/gcov exclusion markers and
kcov --exclude-line regex support.
The implementation scans source files for markers when loaded, builds a
per-file set of excluded line numbers, and subtracts them from the line
coverage totals in prepareFileReports().
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
.../report-custom-region.covmapping | Bin 0 -> 333 bytes
.../report-custom-region.cpp | 18 ++
.../report-custom-region.profdata | Bin 0 -> 840 bytes
.../report-custom.covmapping | Bin 0 -> 333 bytes
.../exclude-markers-custom/report-custom.cpp | 16 ++
.../report-custom.profdata | Bin 0 -> 840 bytes
.../report-region.covmapping | Bin 0 -> 333 bytes
.../exclude-markers-region/report-region.cpp | 18 ++
.../report-region.profdata | Bin 0 -> 840 bytes
.../Inputs/exclude-markers/report.covmapping | Bin 0 -> 325 bytes
.../Inputs/exclude-markers/report.cpp | 16 ++
.../Inputs/exclude-markers/report.profdata | Bin 0 -> 840 bytes
llvm/test/tools/llvm-cov/exclude-markers.test | 181 ++++++++++++++++++
llvm/tools/llvm-cov/CodeCoverage.cpp | 45 ++++-
llvm/tools/llvm-cov/CoverageReport.cpp | 16 ++
llvm/tools/llvm-cov/CoverageSummaryInfo.h | 9 +
llvm/tools/llvm-cov/CoverageViewOptions.h | 59 ++++++
17 files changed, 377 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.covmapping
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.profdata
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.covmapping
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.profdata
create mode 100755 llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.covmapping
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.profdata
create mode 100755 llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.covmapping
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.profdata
create mode 100644 llvm/test/tools/llvm-cov/exclude-markers.test
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.covmapping b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.covmapping
new file mode 100644
index 0000000000000000000000000000000000000000..a5d3c31255967d69f2a62bba44768879b47fbdac
GIT binary patch
literal 333
zcmd1FDa%dHFUw_QfB at AWtg^}#x4Qd{{7#?uPwD~EUOHOLm(((sR-R1l+1WX>l3^kn
z=feP~dJts~WwQZkCR3Y=TdW5exf&ceSPtZ~>^=C-H}SM!>Zw&1KIf;&ry72EeOvs9
zpIw4iRq#f^hdLL}6$vNZ`zI^4kwNsWh%tlv?%QwQa9y`n1)4Q+3B+LgYfG2D)0$nu
z2n4LGjEthpOpJ`|4BQH=ObkGZm4Sz$x1phdgO!1okp=3O6sKp58bX>MIiY+Ig)oPK
wk&%sukqIc4;xv1!+_j8&oa(rE!Rmfp?R{>RGW9k{odn1*AV4vXkB5Z`08^e=2mk;8
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.cpp b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.cpp
new file mode 100644
index 0000000000000..ee9b0b21b3ef3
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.cpp
@@ -0,0 +1,18 @@
+void foo(bool cond) {
+ if (cond) {
+ }
+}
+
+void bar() {
+}
+
+// BEGIN_NO_COV
+void func() {
+}
+// END_NO_COV
+
+int main() {
+ foo(false);
+ bar();
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.profdata b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom-region/report-custom-region.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..a50aa35e8b159980755080f57ff66a6dcedaf177
GIT binary patch
literal 840
zcmeyLQ&5zjmf6V5fE~PGLKU}QM&&y|`D{>O0VoYq#scLtqR~(;15BNOI!pwWUeE^9
zi7M{E3)6`z{$Mi9MpW?zDToVUronV8EMx~OL>E7x&WTk#VI3D%aRyT!tl|rHLqZna
z{10_}Sk)Uy^J5i{u){8X#}T`@nG<$#dmQ4748N}SJ~vC5dK(sg8en%YFytm?=1D-=
zFkirEs4xQuTt3C=8KZ`f=0`}VGBChQiH|Z)N-QdaX at D63qhaC*gWPxDe*1>&x;4xo
t1E><9L23E<NfVbq_^{-OZV<YGFoR+74wHw`9592R0)A+Gn7ZjW!~v(gDV+cS
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.covmapping b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.covmapping
new file mode 100644
index 0000000000000000000000000000000000000000..067571d04a1f4c795738ab590ffb95a59adae379
GIT binary patch
literal 333
zcmd1FDa%dHFUw_QfB at AWtg^}#x4Qd{{7#?uPwD~EUOHOLm(((sR-R1l+1WX>l3^kn
z=R+T;dJts^WwQZkCOxx?Ta&NppVYnJzt-cNrmyGKv%Wf~{B*Uh>7LWq_3{(d at zOn^
zuXWK^Pgn2c`K#V~8Vn2*lmx4xX1MRZ{q_ylb!$~1f8r8|;6}z{J|0^N>llH6m6efE
zl$nW<k)45Cft85?NU<{TF!VMwG;pvo at G`PM%}H^3#;75r`H>UK2T=%f7#JDZco><0
pVku6ux5{11h{vgplNYS+*VW$VW+_u|gVafY3<Clb^LThzm;l-!PU-*v
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.cpp b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.cpp
new file mode 100644
index 0000000000000..c5b6688a3978e
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.cpp
@@ -0,0 +1,16 @@
+void foo(bool cond) {
+ if (cond) {
+ }
+}
+
+void bar() {
+}
+
+void func() { // MY_SKIP
+} // MY_SKIP
+
+int main() {
+ foo(false);
+ bar();
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.profdata b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-custom/report-custom.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..a50aa35e8b159980755080f57ff66a6dcedaf177
GIT binary patch
literal 840
zcmeyLQ&5zjmf6V5fE~PGLKU}QM&&y|`D{>O0VoYq#scLtqR~(;15BNOI!pwWUeE^9
zi7M{E3)6`z{$Mi9MpW?zDToVUronV8EMx~OL>E7x&WTk#VI3D%aRyT!tl|rHLqZna
z{10_}Sk)Uy^J5i{u){8X#}T`@nG<$#dmQ4748N}SJ~vC5dK(sg8en%YFytm?=1D-=
zFkirEs4xQuTt3C=8KZ`f=0`}VGBChQiH|Z)N-QdaX at D63qhaC*gWPxDe*1>&x;4xo
t1E><9L23E<NfVbq_^{-OZV<YGFoR+74wHw`9592R0)A+Gn7ZjW!~v(gDV+cS
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.covmapping b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.covmapping
new file mode 100755
index 0000000000000000000000000000000000000000..53f23eb687ebabdbc1b2ed4580d2b2098145cd6a
GIT binary patch
literal 333
zcmd1FDa%dHFUw_QfB at AWtg^}#x4Qd{{7#?uPwD~EUOHOLm(((sR-R1l+1WX>l3^kn
z=R+T;dJts^WwQZkCOxx?Ta&NppVYnJzt-cNrmyGKv%Wf~{B*Uh>7LWq_3{(d at zOn^
zuXRz^%lG`5^OwE#G#D8A8w69JX1MRZ{q_ylb!$~1f8r8|;O#QK!*5Py?`8x7R#rwv
zQD!DaMs@~n1y&{oAjQhS!_eE%(7?gUz{|)2H7CXC8KZ`f=0{E_A4DO{VPIrr<6&e1
qilsQs-YR!3BOa$ZE?%&@Usrpdo25*>4N at loG7Jb%%;V!>VFCbt;Z>~w
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.cpp b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.cpp
new file mode 100644
index 0000000000000..e43570b76c416
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.cpp
@@ -0,0 +1,18 @@
+void foo(bool cond) {
+ if (cond) {
+ }
+}
+
+void bar() {
+}
+
+// LCOV_EXCL_START
+void func() {
+}
+// LCOV_EXCL_STOP
+
+int main() {
+ foo(false);
+ bar();
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.profdata b/llvm/test/tools/llvm-cov/Inputs/exclude-markers-region/report-region.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..a50aa35e8b159980755080f57ff66a6dcedaf177
GIT binary patch
literal 840
zcmeyLQ&5zjmf6V5fE~PGLKU}QM&&y|`D{>O0VoYq#scLtqR~(;15BNOI!pwWUeE^9
zi7M{E3)6`z{$Mi9MpW?zDToVUronV8EMx~OL>E7x&WTk#VI3D%aRyT!tl|rHLqZna
z{10_}Sk)Uy^J5i{u){8X#}T`@nG<$#dmQ4748N}SJ~vC5dK(sg8en%YFytm?=1D-=
zFkirEs4xQuTt3C=8KZ`f=0`}VGBChQiH|Z)N-QdaX at D63qhaC*gWPxDe*1>&x;4xo
t1E><9L23E<NfVbq_^{-OZV<YGFoR+74wHw`9592R0)A+Gn7ZjW!~v(gDV+cS
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.covmapping b/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.covmapping
new file mode 100755
index 0000000000000000000000000000000000000000..8fda4ada796e230ddbef2e7dd91747eccd3ff04c
GIT binary patch
literal 325
zcmd1FDa%dHFUw_QfB at AGtg^}#x4Qd{{7#?uPwD~EUOHOLm(((sR-R1l+1WX>l3^kn
z=R+5$dJts<WwQZkCUyOaTa&NppVYnJzt-cNrmyGKv%Wf~{B*Uh>7LWq_40eF<)wQ<
zU+bc`o(2Ph>^#0T5Y6tpZ at +!Rb=_JO$ep+ZBKECeM=?uf_-jTWU}a at w6lG>&WMpUH
zR$ygf08*?BJPf at J4GkQu47`ji5G at QTPR|%Mgfu^LLir#HVGaW$BO4DR6HqM0Y4%pR
jYZ>u4)p7EI)&08K``j#L>TQrZ36NnxfMOmG4+|3jnA}fG
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.cpp b/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.cpp
new file mode 100644
index 0000000000000..3c255cdc932f4
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.cpp
@@ -0,0 +1,16 @@
+void foo(bool cond) {
+ if (cond) {
+ }
+}
+
+void bar() {
+}
+
+void func() { // LCOV_EXCL_LINE
+} // LCOV_EXCL_LINE
+
+int main() {
+ foo(false);
+ bar();
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.profdata b/llvm/test/tools/llvm-cov/Inputs/exclude-markers/report.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..a50aa35e8b159980755080f57ff66a6dcedaf177
GIT binary patch
literal 840
zcmeyLQ&5zjmf6V5fE~PGLKU}QM&&y|`D{>O0VoYq#scLtqR~(;15BNOI!pwWUeE^9
zi7M{E3)6`z{$Mi9MpW?zDToVUronV8EMx~OL>E7x&WTk#VI3D%aRyT!tl|rHLqZna
z{10_}Sk)Uy^J5i{u){8X#}T`@nG<$#dmQ4748N}SJ~vC5dK(sg8en%YFytm?=1D-=
zFkirEs4xQuTt3C=8KZ`f=0`}VGBChQiH|Z)N-QdaX at D63qhaC*gWPxDe*1>&x;4xo
t1E><9L23E<NfVbq_^{-OZV<YGFoR+74wHw`9592R0)A+Gn7ZjW!~v(gDV+cS
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/exclude-markers.test b/llvm/test/tools/llvm-cov/exclude-markers.test
new file mode 100644
index 0000000000000..a9f33ab2ca396
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/exclude-markers.test
@@ -0,0 +1,181 @@
+// Tests for --exclude-line-regex and --exclude-region-start/stop-regex.
+
+// ===== LCOV_EXCL_LINE (per-line exclusion) =====
+
+// Baseline: disable all exclusion markers, verify original totals.
+// RUN: llvm-cov report %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: --exclude-line-regex="" --exclude-region-start-regex="" \
+// RUN: --exclude-region-stop-regex="" --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=BASELINE %s
+
+// Original: 13 lines total, 3 missed, 76.92% covered.
+// BASELINE: TOTAL
+// BASELINE-SAME: 13
+// BASELINE-SAME: 3
+// BASELINE-SAME: 76.92%
+
+// With default LCOV_EXCL_LINE markers: func() lines excluded (2 lines removed).
+// RUN: llvm-cov report %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=EXCL %s
+
+// 13 - 2 excluded = 11 lines, 1 missed, 90.91%.
+// EXCL: TOTAL
+// EXCL-SAME: 11
+// EXCL-SAME: 1
+// EXCL-SAME: 90.91%
+
+// Custom regex that doesn't match: no exclusion.
+// RUN: llvm-cov report %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: --exclude-line-regex="MY_CUSTOM_EXCL" \
+// RUN: --exclude-region-start-regex="" --exclude-region-stop-regex="" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=CUSTOM_NOMATCH %s
+
+// CUSTOM_NOMATCH: TOTAL
+// CUSTOM_NOMATCH-SAME: 13
+// CUSTOM_NOMATCH-SAME: 3
+// CUSTOM_NOMATCH-SAME: 76.92%
+
+// Custom regex that matches the markers:
+// RUN: llvm-cov report %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: --exclude-line-regex="LCOV_EXCL" \
+// RUN: --exclude-region-start-regex="" --exclude-region-stop-regex="" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=CUSTOM_MATCH %s
+
+// CUSTOM_MATCH: TOTAL
+// CUSTOM_MATCH-SAME: 11
+// CUSTOM_MATCH-SAME: 1
+// CUSTOM_MATCH-SAME: 90.91%
+
+// JSON export with exclusion:
+// RUN: llvm-cov export --summary-only \
+// RUN: %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: 2>&1 | FileCheck -check-prefix=JSON %s
+
+// JSON: "lines":{"count":11,"covered":10,"percent":90
+
+// ===== LCOV_EXCL_START / LCOV_EXCL_STOP (region exclusion) =====
+
+// Region exclusion with defaults:
+// RUN: llvm-cov report %S/Inputs/exclude-markers-region/report-region.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-region/report-region.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-region \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=REGION %s
+
+// func() is inside EXCL_START/STOP region (2 mapped lines excluded).
+// 13 - 2 = 11 lines, 1 missed, 90.91%.
+// REGION: TOTAL
+// REGION-SAME: 11
+// REGION-SAME: 1
+// REGION-SAME: 90.91%
+
+// Region exclusion with explicit custom regex (same patterns):
+// RUN: llvm-cov report %S/Inputs/exclude-markers-region/report-region.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-region/report-region.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-region \
+// RUN: --exclude-line-regex="" \
+// RUN: --exclude-region-start-regex="LCOV_EXCL_START" \
+// RUN: --exclude-region-stop-regex="LCOV_EXCL_STOP" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=REGION_CUSTOM %s
+
+// REGION_CUSTOM: TOTAL
+// REGION_CUSTOM-SAME: 11
+// REGION_CUSTOM-SAME: 1
+// REGION_CUSTOM-SAME: 90.91%
+
+// Disabling all exclusion leaves totals unchanged:
+// RUN: llvm-cov report %S/Inputs/exclude-markers-region/report-region.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-region/report-region.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-region \
+// RUN: --exclude-line-regex="" --exclude-region-start-regex="" \
+// RUN: --exclude-region-stop-regex="" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=REGION_DISABLED %s
+
+// REGION_DISABLED: TOTAL
+// REGION_DISABLED-SAME: 13
+// REGION_DISABLED-SAME: 3
+// REGION_DISABLED-SAME: 76.92%
+
+// ===== Overriding default markers with custom regex =====
+
+// Custom per-line marker "MY_SKIP" (default LCOV_EXCL_LINE won't match):
+// RUN: llvm-cov report %S/Inputs/exclude-markers-custom/report-custom.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-custom/report-custom.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-custom \
+// RUN: --exclude-line-regex="MY_SKIP" \
+// RUN: --exclude-region-start-regex="" --exclude-region-stop-regex="" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=OVERRIDE_LINE %s
+
+// OVERRIDE_LINE: TOTAL
+// OVERRIDE_LINE-SAME: 11
+// OVERRIDE_LINE-SAME: 1
+// OVERRIDE_LINE-SAME: 90.91%
+
+// Default markers don't match "MY_SKIP":
+// RUN: llvm-cov report %S/Inputs/exclude-markers-custom/report-custom.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-custom/report-custom.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-custom \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=OVERRIDE_LINE_DEFAULT %s
+
+// OVERRIDE_LINE_DEFAULT: TOTAL
+// OVERRIDE_LINE_DEFAULT-SAME: 13
+// OVERRIDE_LINE_DEFAULT-SAME: 3
+// OVERRIDE_LINE_DEFAULT-SAME: 76.92%
+
+// Custom region markers "BEGIN_NO_COV" / "END_NO_COV":
+// RUN: llvm-cov report %S/Inputs/exclude-markers-custom-region/report-custom-region.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-custom-region/report-custom-region.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-custom-region \
+// RUN: --exclude-line-regex="" \
+// RUN: --exclude-region-start-regex="BEGIN_NO_COV" \
+// RUN: --exclude-region-stop-regex="END_NO_COV" \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=OVERRIDE_REGION %s
+
+// OVERRIDE_REGION: TOTAL
+// OVERRIDE_REGION-SAME: 11
+// OVERRIDE_REGION-SAME: 1
+// OVERRIDE_REGION-SAME: 90.91%
+
+// Default region markers don't match "BEGIN_NO_COV" / "END_NO_COV":
+// RUN: llvm-cov report %S/Inputs/exclude-markers-custom-region/report-custom-region.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers-custom-region/report-custom-region.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers-custom-region \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=OVERRIDE_REGION_DEFAULT %s
+
+// OVERRIDE_REGION_DEFAULT: TOTAL
+// OVERRIDE_REGION_DEFAULT-SAME: 13
+// OVERRIDE_REGION_DEFAULT-SAME: 3
+// OVERRIDE_REGION_DEFAULT-SAME: 76.92%
+
+// ===== "show" command with exclusions disabled =====
+// Exercises the scanForExclusionMarkers early-return path when both regexes
+// are empty (show always loads source files regardless of exclusion settings).
+// RUN: llvm-cov show %S/Inputs/exclude-markers/report.covmapping \
+// RUN: -instr-profile %S/Inputs/exclude-markers/report.profdata \
+// RUN: -path-equivalence=/tmp/exclude-markers-source,%S/Inputs/exclude-markers \
+// RUN: --exclude-line-regex="" --exclude-region-start-regex="" \
+// RUN: --exclude-region-stop-regex="" \
+// RUN: 2>&1 | FileCheck -check-prefix=SHOW_DISABLED %s
+
+// Source is displayed normally; LCOV_EXCL_LINE markers have no effect.
+// SHOW_DISABLED: func()
+// SHOW_DISABLED: LCOV_EXCL_LINE
diff --git a/llvm/tools/llvm-cov/CodeCoverage.cpp b/llvm/tools/llvm-cov/CodeCoverage.cpp
index e19101ac76045..2fc4f18b55509 100644
--- a/llvm/tools/llvm-cov/CodeCoverage.cpp
+++ b/llvm/tools/llvm-cov/CodeCoverage.cpp
@@ -284,6 +284,7 @@ ErrorOr<const MemoryBuffer &>
CodeCoverageTool::getSourceFile(StringRef SourceFile) {
// If we've remapped filenames, look up the real location for this file.
std::unique_lock<std::mutex> Guard{LoadedSourceFilesLock};
+ StringRef OriginalFile = SourceFile;
if (!RemappedFilenames.empty()) {
auto Loc = RemappedFilenames.find(SourceFile);
if (Loc != RemappedFilenames.end())
@@ -299,7 +300,9 @@ CodeCoverageTool::getSourceFile(StringRef SourceFile) {
}
LoadedSourceFiles.emplace_back(std::string(SourceFile),
std::move(Buffer.get()));
- return *LoadedSourceFiles.back().second;
+ auto &LoadedBuf = *LoadedSourceFiles.back().second;
+ ViewOpts.scanForExclusionMarkers(OriginalFile, LoadedBuf);
+ return LoadedBuf;
}
void CodeCoverageTool::attachExpansionSubViews(
@@ -740,6 +743,22 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
"given regular expression"),
cl::cat(FilteringCategory));
+ cl::opt<std::string> ExcludeLineRegex(
+ "exclude-line-regex", cl::Optional,
+ cl::desc("Exclude lines matching this regex from coverage totals"),
+ cl::init("LCOV_EXCL_LINE"), cl::cat(FilteringCategory));
+
+ cl::opt<std::string> ExcludeRegionStartRegex(
+ "exclude-region-start-regex", cl::Optional,
+ cl::desc("Start of an excluded region (lines until stop marker are "
+ "excluded from coverage totals)"),
+ cl::init("LCOV_EXCL_START"), cl::cat(FilteringCategory));
+
+ cl::opt<std::string> ExcludeRegionStopRegex(
+ "exclude-region-stop-regex", cl::Optional,
+ cl::desc("End of an excluded region"),
+ cl::init("LCOV_EXCL_STOP"), cl::cat(FilteringCategory));
+
cl::opt<double> RegionCoverageLtFilter(
"region-coverage-lt", cl::Optional,
cl::desc("Show code coverage only for functions with region coverage "
@@ -947,6 +966,16 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
FilenameFilters.push_back(std::make_unique<NameRegexCoverageFilter>(
RE, NameRegexCoverageFilter::FilterType::Include));
+ if (!ExcludeLineRegex.empty())
+ ViewOpts.ExcludeLineRE =
+ std::make_shared<Regex>(ExcludeLineRegex);
+ if (!ExcludeRegionStartRegex.empty())
+ ViewOpts.ExcludeRegionStartRE =
+ std::make_shared<Regex>(ExcludeRegionStartRegex);
+ if (!ExcludeRegionStopRegex.empty())
+ ViewOpts.ExcludeRegionStopRE =
+ std::make_shared<Regex>(ExcludeRegionStopRegex);
+
if (!Arches.empty()) {
for (const std::string &Arch : Arches) {
if (Triple(Arch).getArch() == llvm::Triple::ArchType::UnknownArch) {
@@ -1288,6 +1317,13 @@ int CodeCoverageTool::doReport(int argc, const char **argv,
if (!Coverage)
return 1;
+ // Pre-scan source files for exclusion markers (getSourceFile handles path
+ // remapping and triggers scanForExclusionMarkers).
+ if (ViewOpts.ExcludeLineRE || ViewOpts.ExcludeRegionStartRE) {
+ for (StringRef SF : Coverage->getUniqueSourceFiles())
+ getSourceFile(SF);
+ }
+
CoverageReport Report(ViewOpts, *Coverage);
if (!ShowFunctionSummaries) {
if (SourceFiles.empty())
@@ -1364,6 +1400,13 @@ int CodeCoverageTool::doExport(int argc, const char **argv,
return 1;
}
+ // Pre-scan source files for exclusion markers (getSourceFile handles path
+ // remapping and triggers scanForExclusionMarkers).
+ if (ViewOpts.ExcludeLineRE || ViewOpts.ExcludeRegionStartRE) {
+ for (StringRef SF : Coverage->getUniqueSourceFiles())
+ getSourceFile(SF);
+ }
+
std::unique_ptr<CoverageExporter> Exporter;
switch (ViewOpts.Format) {
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 9b754d613370c..b357af8cfdabb 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -496,6 +496,22 @@ std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
}
Pool.wait();
+ // Subtract excluded lines (from inline markers like LCOV_EXCL_LINE) from
+ // each file's line coverage totals. The ExcludedLines map is populated by
+ // the caller scanning source files before invoking this function.
+ for (unsigned I = 0; I < Files.size(); ++I) {
+ const auto *Excluded = Options.getExcludedLinesForFile(Files[I]);
+ if (!Excluded)
+ continue;
+ auto FileCoverage = Coverage.getCoverageForFile(Files[I]);
+ for (const auto &LCS : getLineCoverageStats(FileCoverage)) {
+ if (!LCS.isMapped())
+ continue;
+ if (Excluded->count(LCS.getLine()))
+ FileReports[I].LineCoverage.subtractLine(LCS.getExecutionCount() > 0);
+ }
+ }
+
for (const auto &FileReport : FileReports)
Totals += FileReport;
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index d9210676c41bf..85e24cda6d735 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -82,6 +82,15 @@ class LineCoverageInfo {
return *this;
}
+ void subtractLine(bool WasCovered) {
+ assert(NumLines > 0 && "Cannot subtract from zero lines");
+ --NumLines;
+ if (WasCovered) {
+ assert(Covered > 0 && "Cannot subtract covered from zero");
+ --Covered;
+ }
+ }
+
void merge(const LineCoverageInfo &RHS) {
Covered = std::max(Covered, RHS.Covered);
NumLines = std::max(NumLines, RHS.NumLines);
diff --git a/llvm/tools/llvm-cov/CoverageViewOptions.h b/llvm/tools/llvm-cov/CoverageViewOptions.h
index 4826d4adb53bf..16af86f037192 100644
--- a/llvm/tools/llvm-cov/CoverageViewOptions.h
+++ b/llvm/tools/llvm-cov/CoverageViewOptions.h
@@ -10,7 +10,13 @@
#define LLVM_COV_COVERAGEVIEWOPTIONS_H
#include "RenderingSupport.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Regex.h"
+#include <memory>
#include <vector>
namespace llvm {
@@ -61,6 +67,59 @@ struct CoverageViewOptions {
float HighCovWatermark;
float LowCovWatermark;
+ /// Per-file sets of line numbers excluded from coverage via inline markers.
+ /// Mutable because it's lazily populated as source files are loaded.
+ mutable StringMap<DenseSet<unsigned>> ExcludedLines;
+
+ /// Regexes for inline exclusion markers.
+ std::shared_ptr<Regex> ExcludeLineRE;
+ std::shared_ptr<Regex> ExcludeRegionStartRE;
+ std::shared_ptr<Regex> ExcludeRegionStopRE;
+
+ /// Get excluded lines for a file, or nullptr if none.
+ const DenseSet<unsigned> *getExcludedLinesForFile(StringRef Filename) const {
+ auto It = ExcludedLines.find(Filename);
+ if (It == ExcludedLines.end())
+ return nullptr;
+ return &It->second;
+ }
+
+ /// Scan a source buffer for exclusion markers and populate ExcludedLines.
+ void scanForExclusionMarkers(StringRef Filename,
+ const MemoryBuffer &Buffer) const {
+ if (!ExcludeLineRE && !ExcludeRegionStartRE)
+ return;
+
+ DenseSet<unsigned> Excluded;
+ bool InExcludedRegion = false;
+ unsigned LineNo = 0;
+
+ for (line_iterator LI(Buffer, /*SkipBlanks=*/false); !LI.is_at_eof();
+ ++LI) {
+ ++LineNo;
+ StringRef Line = *LI;
+
+ if (InExcludedRegion) {
+ Excluded.insert(LineNo);
+ if (ExcludeRegionStopRE && ExcludeRegionStopRE->match(Line))
+ InExcludedRegion = false;
+ continue;
+ }
+
+ if (ExcludeRegionStartRE && ExcludeRegionStartRE->match(Line)) {
+ InExcludedRegion = true;
+ Excluded.insert(LineNo);
+ continue;
+ }
+
+ if (ExcludeLineRE && ExcludeLineRE->match(Line))
+ Excluded.insert(LineNo);
+ }
+
+ if (!Excluded.empty())
+ ExcludedLines[Filename] = std::move(Excluded);
+ }
+
/// Change the output's stream color if the colors are enabled.
ColoredRawOstream colored_ostream(raw_ostream &OS,
raw_ostream::Colors Color) const {
More information about the llvm-commits
mailing list