[clang-tools-extra] r209450 - Add clang-tidy -line-filter option to filter findings by line ranges.

Alexander Kornienko alexfh at google.com
Thu May 22 09:07:12 PDT 2014


Author: alexfh
Date: Thu May 22 11:07:11 2014
New Revision: 209450

URL: http://llvm.org/viewvc/llvm-project?rev=209450&view=rev
Log:
Add clang-tidy -line-filter option to filter findings by line ranges.

Summary:
This is going to be used for a clang-tidy-diff script to display
warnings in changed lines only. The option uses JSON, as its value is not
intended to be entered manually.

Reviewers: klimek

Reviewed By: klimek

Subscribers: cfe-commits

Differential Revision: http://reviews.llvm.org/D3873

Added:
    clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp
    clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/
    clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header1.h
    clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header2.h
    clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header3.h
    clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp
    clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h
    clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h
    clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp
    clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt

Modified: clang-tools-extra/trunk/clang-tidy/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/CMakeLists.txt?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/CMakeLists.txt Thu May 22 11:07:11 2014
@@ -6,6 +6,7 @@ add_clang_library(clangTidy
   ClangTidy.cpp
   ClangTidyModule.cpp
   ClangTidyDiagnosticConsumer.cpp
+  ClangTidyOptions.cpp
 
   DEPENDS
   ClangSACheckers

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.cpp Thu May 22 11:07:11 2014
@@ -203,7 +203,7 @@ StringRef ClangTidyContext::getCheckName
 
 ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
     : Context(Ctx), HeaderFilter(Ctx.getOptions().HeaderFilterRegex),
-      LastErrorRelatesToUserCode(false) {
+      LastErrorRelatesToUserCode(false), LastErrorPassesLineFilter(false) {
   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   Diags.reset(new DiagnosticsEngine(
       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts, this,
@@ -220,11 +220,15 @@ void ClangTidyDiagnosticConsumer::finali
     } else if (!LastErrorRelatesToUserCode) {
       ++Context.Stats.ErrorsIgnoredNonUserCode;
       Errors.pop_back();
+    } else if (!LastErrorPassesLineFilter) {
+      ++Context.Stats.ErrorsIgnoredLineFilter;
+      Errors.pop_back();
     } else {
       ++Context.Stats.ErrorsDisplayed;
     }
   }
   LastErrorRelatesToUserCode = false;
+  LastErrorPassesLineFilter = false;
 }
 
 void ClangTidyDiagnosticConsumer::HandleDiagnostic(
@@ -259,32 +263,58 @@ void ClangTidyDiagnosticConsumer::Handle
       llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()),
       Sources);
 
-  // Let argument parsing-related warnings through.
-  if (relatesToUserCode(Info.getLocation())) {
-    LastErrorRelatesToUserCode = true;
+  checkFilters(Info.getLocation());
+}
+
+bool ClangTidyDiagnosticConsumer::passesLineFilter(StringRef FileName,
+                                                   unsigned LineNumber) const {
+  if (Context.getOptions().LineFilter.empty())
+    return true;
+  for (const FileFilter& Filter : Context.getOptions().LineFilter) {
+    if (FileName.endswith(Filter.Name)) {
+      if (Filter.LineRanges.empty())
+        return true;
+      for (const FileFilter::LineRange &Range : Filter.LineRanges) {
+        if (Range.first <= LineNumber && LineNumber <= Range.second)
+          return true;
+      }
+      return false;
+    }
   }
+  return false;
 }
 
-bool ClangTidyDiagnosticConsumer::relatesToUserCode(SourceLocation Location) {
+void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location) {
   // Invalid location may mean a diagnostic in a command line, don't skip these.
-  if (!Location.isValid())
-    return true;
+  if (!Location.isValid()) {
+    LastErrorRelatesToUserCode = true;
+    LastErrorPassesLineFilter = true;
+    return;
+  }
 
   const SourceManager &Sources = Diags->getSourceManager();
   if (Sources.isInSystemHeader(Location))
-    return false;
+    return;
 
   // FIXME: We start with a conservative approach here, but the actual type of
   // location needed depends on the check (in particular, where this check wants
   // to apply fixes).
   FileID FID = Sources.getDecomposedExpansionLoc(Location).first;
-  if (FID == Sources.getMainFileID())
-    return true;
-
   const FileEntry *File = Sources.getFileEntryForID(FID);
+
   // -DMACRO definitions on the command line have locations in a virtual buffer
   // that doesn't have a FileEntry. Don't skip these as well.
-  return !File || HeaderFilter.match(File->getName());
+  if (!File) {
+    LastErrorRelatesToUserCode = true;
+    LastErrorPassesLineFilter = true;
+    return;
+  }
+
+  StringRef FileName(File->getName());
+  unsigned LineNumber = Sources.getExpansionLineNumber(Location);
+  LastErrorRelatesToUserCode |=
+      Sources.isInMainFile(Location) || HeaderFilter.match(FileName);
+  LastErrorPassesLineFilter |= passesLineFilter(FileName, LineNumber);
 }
 
 namespace {

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyDiagnosticConsumer.h Thu May 22 11:07:11 2014
@@ -79,12 +79,18 @@ private:
 struct ClangTidyStats {
   ClangTidyStats()
       : ErrorsDisplayed(0), ErrorsIgnoredCheckFilter(0), ErrorsIgnoredNOLINT(0),
-        ErrorsIgnoredNonUserCode(0) {}
+        ErrorsIgnoredNonUserCode(0), ErrorsIgnoredLineFilter(0) {}
 
   unsigned ErrorsDisplayed;
   unsigned ErrorsIgnoredCheckFilter;
   unsigned ErrorsIgnoredNOLINT;
   unsigned ErrorsIgnoredNonUserCode;
+  unsigned ErrorsIgnoredLineFilter;
+
+  unsigned errorsIgnored() const {
+    return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter +
+           ErrorsIgnoredNonUserCode + ErrorsIgnoredLineFilter;
+  }
 };
 
 /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine
@@ -165,13 +171,15 @@ public:
 
 private:
   void finalizeLastError();
-  bool relatesToUserCode(SourceLocation Location);
+  void checkFilters(SourceLocation Location);
+  bool passesLineFilter(StringRef FileName, unsigned LineNumber) const;
 
   ClangTidyContext &Context;
   llvm::Regex HeaderFilter;
   std::unique_ptr<DiagnosticsEngine> Diags;
   SmallVector<ClangTidyError, 8> Errors;
   bool LastErrorRelatesToUserCode;
+  bool LastErrorPassesLineFilter;
 };
 
 } // end namespace tidy

Added: clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.cpp Thu May 22 11:07:11 2014
@@ -0,0 +1,64 @@
+//===--- ClangTidyOptions.cpp - clang-tidy ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangTidyOptions.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using clang::tidy::FileFilter;
+
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter)
+LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FileFilter::LineRange)
+
+namespace llvm {
+namespace yaml {
+
+// Map std::pair<int, int> to a JSON array of size 2.
+template <> struct SequenceTraits<FileFilter::LineRange> {
+  static size_t size(IO &IO, FileFilter::LineRange &Range) {
+    return Range.first == 0 ? 0 : Range.second == 0 ? 1 : 2;
+  }
+  static unsigned &element(IO &IO, FileFilter::LineRange &Range, size_t Index) {
+    if (Index > 1)
+      IO.setError("Too many elements in line range.");
+    return Index == 0 ? Range.first : Range.second;
+  }
+};
+
+template <> struct MappingTraits<FileFilter> {
+  static void mapping(IO &IO, FileFilter &File) {
+    IO.mapRequired("name", File.Name);
+    IO.mapOptional("lines", File.LineRanges);
+  }
+  static StringRef validate(IO &io, FileFilter &File) {
+    if (File.Name.empty())
+      return "No file name specified";
+    for (const FileFilter::LineRange &Range : File.LineRanges) {
+      if (Range.first <= 0 || Range.second <= 0)
+        return "Invalid line range";
+    }
+    return StringRef();
+  }
+};
+
+} // namespace yaml
+} // namespace llvm
+
+namespace clang {
+namespace tidy {
+
+/// \brief Parses -line-filter option and stores it to the \c Options.
+llvm::error_code parseLineFilter(const std::string &LineFilter,
+                                 clang::tidy::ClangTidyOptions &Options) {
+  llvm::yaml::Input Input(LineFilter);
+  Input >> Options.LineFilter;
+  return Input.error();
+}
+
+} // namespace tidy
+} // namespace clang

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyOptions.h Thu May 22 11:07:11 2014
@@ -10,21 +10,41 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CLANG_TIDY_OPTIONS_H
 
+#include "llvm/Support/system_error.h"
 #include <string>
+#include <utility>
+#include <vector>
 
 namespace clang {
 namespace tidy {
 
+struct FileFilter {
+  std::string Name;
+  // LineRange is a pair<start, end> (inclusive).
+  typedef std::pair<unsigned, unsigned> LineRange;
+  std::vector<LineRange> LineRanges;
+};
+
 /// \brief Contains options for clang-tidy.
 struct ClangTidyOptions {
   ClangTidyOptions() : Checks("*"), AnalyzeTemporaryDtors(false) {}
   std::string Checks;
+
   // Output warnings from headers matching this filter. Warnings from main files
   // will always be displayed.
   std::string HeaderFilterRegex;
+
+  // Output warnings from certain line ranges of certain files only. If this
+  // list is emtpy, it won't be applied.
+  std::vector<FileFilter> LineFilter;
+
   bool AnalyzeTemporaryDtors;
 };
 
+/// \brief Parses LineFilter from JSON and stores it to the \c Options.
+llvm::error_code parseLineFilter(const std::string &LineFilter,
+                                 clang::tidy::ClangTidyOptions &Options);
+
 } // end namespace tidy
 } // end namespace clang
 

Modified: clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp Thu May 22 11:07:11 2014
@@ -32,6 +32,7 @@ const char DefaultChecks[] =
     "-clang-analyzer-alpha*,"  // Too many false positives.
     "-llvm-include-order,"     // Not implemented yet.
     "-google-*,";              // Doesn't apply to LLVM.
+
 static cl::opt<std::string>
 Checks("checks", cl::desc("Comma-separated list of globs with optional '-'\n"
                           "prefix. Globs are processed in order of appearance\n"
@@ -40,13 +41,28 @@ Checks("checks", cl::desc("Comma-separat
                           "prefix remove checks with matching names from the\n"
                           "set of enabled checks."),
        cl::init(""), cl::cat(ClangTidyCategory));
+
 static cl::opt<std::string>
 HeaderFilter("header-filter",
              cl::desc("Regular expression matching the names of the\n"
-                      "headers to output diagnostics from.\n"
-                      "Diagnostics from the main file of each\n"
-                      "translation unit are always displayed."),
+                      "headers to output diagnostics from. Diagnostics\n"
+                      "from the main file of each translation unit are\n"
+                      "always displayed.\n"
+                      "Can be used together with -line-filter."),
              cl::init(""), cl::cat(ClangTidyCategory));
+
+static cl::opt<std::string>
+LineFilter("line-filter",
+           cl::desc("List of files with line ranges to filter the\n"
+                    "warnings. Can be used together with\n"
+                    "-header-filter. The format of the list is a JSON\n"
+                    "array of objects:\n"
+                    "  [\n"
+                    "    {\"name\":\"file1.cpp\",\"lines\":[[1,3],[5,7]]},\n"
+                    "    {\"name\":\"file2.h\"}\n"
+                    "  ]"),
+           cl::init(""), cl::cat(ClangTidyCategory));
+
 static cl::opt<bool> Fix("fix", cl::desc("Fix detected errors if possible."),
                          cl::init(false), cl::cat(ClangTidyCategory));
 
@@ -63,16 +79,18 @@ AnalyzeTemporaryDtors("analyze-temporary
                       cl::init(false), cl::cat(ClangTidyCategory));
 
 static void printStats(const clang::tidy::ClangTidyStats &Stats) {
-  unsigned ErrorsIgnored = Stats.ErrorsIgnoredNOLINT +
-                           Stats.ErrorsIgnoredCheckFilter +
-                           Stats.ErrorsIgnoredNonUserCode;
-  if (ErrorsIgnored) {
-    llvm::errs() << "Suppressed " << ErrorsIgnored << " warnings (";
+  if (Stats.errorsIgnored()) {
+    llvm::errs() << "Suppressed " << Stats.errorsIgnored() << " warnings (";
     StringRef Separator = "";
     if (Stats.ErrorsIgnoredNonUserCode) {
       llvm::errs() << Stats.ErrorsIgnoredNonUserCode << " in non-user code";
       Separator = ", ";
     }
+    if (Stats.ErrorsIgnoredLineFilter) {
+      llvm::errs() << Separator << Stats.ErrorsIgnoredLineFilter
+                   << " due to line filter";
+      Separator = ", ";
+    }
     if (Stats.ErrorsIgnoredNOLINT) {
       llvm::errs() << Separator << Stats.ErrorsIgnoredNOLINT << " NOLINT";
       Separator = ", ";
@@ -94,6 +112,12 @@ int main(int argc, const char **argv) {
   Options.Checks = DefaultChecks + Checks;
   Options.HeaderFilterRegex = HeaderFilter;
   Options.AnalyzeTemporaryDtors = AnalyzeTemporaryDtors;
+  if (llvm::error_code Err =
+          clang::tidy::parseLineFilter(LineFilter, Options)) {
+    llvm::errs() << "Invalid LineFilter: " << Err.message() << "\n\nUsage:\n";
+    llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
+    return 1;
+  }
 
   // FIXME: Allow using --list-checks without positional arguments.
   if (ListChecks) {

Added: clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header1.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header1.h?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header1.h (added)
+++ clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header1.h Thu May 22 11:07:11 2014
@@ -0,0 +1,3 @@
+class A1 { A1(int); };
+class B1 { B1(int); };
+class C1 { C1(int); };

Added: clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header2.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header2.h?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header2.h (added)
+++ clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header2.h Thu May 22 11:07:11 2014
@@ -0,0 +1,3 @@
+class A2 { A2(int); };
+class B2 { B2(int); };
+class C2 { C2(int); };

Added: clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header3.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header3.h?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header3.h (added)
+++ clang-tools-extra/trunk/test/clang-tidy/Inputs/line-filter/header3.h Thu May 22 11:07:11 2014
@@ -0,0 +1 @@
+class A3 { A3(int); };

Added: clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/line-filter.cpp Thu May 22 11:07:11 2014
@@ -0,0 +1,27 @@
+// RUN: clang-tidy -checks='-*,google-explicit-constructor' -line-filter='[{"name":"%s","lines":[[18,18],[22,22]]},{"name":"header1.h","lines":[[1,2]]},{"name":"header2.h"},{"name":"header3.h"}]' -header-filter='header[12]\.h$' %s -- -I %S/Inputs/line-filter 2>&1 | FileCheck %s
+
+#include "header1.h"
+// CHECK-NOT: header1.h:{{.*}} warning
+// CHECK: header1.h:1:12: warning: Single-argument constructors must be explicit [google-explicit-constructor]
+// CHECK: header1.h:2:12: warning: Single-argument constructors {{.*}}
+// CHECK-NOT: header1.h:{{.*}} warning
+
+#include "header2.h"
+// CHECK: header2.h:1:12: warning: Single-argument constructors {{.*}}
+// CHECK: header2.h:2:12: warning: Single-argument constructors {{.*}}
+// CHECK: header2.h:3:12: warning: Single-argument constructors {{.*}}
+// CHECK-NOT: header2.h:{{.*}} warning
+
+#include "header3.h"
+// CHECK-NOT: header3.h:{{.*}} warning
+
+class A { A(int); };
+// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors {{.*}}
+class B { B(int); };
+// CHECK-NOT: :[[@LINE-1]]:{{.*}} warning
+class C { C(int); };
+// CHECK: :[[@LINE-1]]:11: warning: Single-argument constructors {{.*}}
+
+// CHECK-NOT: warning:
+
+// CHECK: Suppressed 3 warnings (1 in non-user code, 2 due to line filter)

Modified: clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt?rev=209450&r1=209449&r2=209450&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/clang-tidy/CMakeLists.txt Thu May 22 11:07:11 2014
@@ -8,6 +8,7 @@ include_directories(${CLANG_LINT_SOURCE_
 
 add_extra_unittest(ClangTidyTests
   ClangTidyDiagnosticConsumerTest.cpp
+  ClangTidyOptionsTest.cpp
   LLVMModuleTest.cpp
   GoogleModuleTest.cpp
   MiscModuleTest.cpp)

Added: clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp?rev=209450&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/clang-tidy/ClangTidyOptionsTest.cpp Thu May 22 11:07:11 2014
@@ -0,0 +1,58 @@
+#include "ClangTidyOptions.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+namespace test {
+
+TEST(ParseLineFilter, EmptyFilter) {
+  ClangTidyOptions Options;
+  EXPECT_FALSE(parseLineFilter("", Options));
+  EXPECT_TRUE(Options.LineFilter.empty());
+  EXPECT_FALSE(parseLineFilter("[]", Options));
+  EXPECT_TRUE(Options.LineFilter.empty());
+}
+
+TEST(ParseLineFilter, InvalidFilter) {
+  ClangTidyOptions Options;
+  // TODO: Figure out why parsing succeeds here.
+  EXPECT_FALSE(parseLineFilter("asdf", Options));
+  EXPECT_TRUE(Options.LineFilter.empty());
+
+  EXPECT_TRUE(parseLineFilter("[{}]", Options));
+  EXPECT_TRUE(parseLineFilter(R"([{"name":""}])", Options));
+  EXPECT_TRUE(parseLineFilter(R"([{"name":"test","lines":[[1]]}])", Options));
+  EXPECT_TRUE(
+      parseLineFilter(R"([{"name":"test","lines":[[1,2,3]]}])", Options));
+  EXPECT_TRUE(
+      parseLineFilter(R"([{"name":"test","lines":[[1,-1]]}])", Options));
+}
+
+TEST(ParseLineFilter, ValidFilter) {
+  ClangTidyOptions Options;
+  llvm::error_code Error = parseLineFilter(
+      R"([{"name":"file1.cpp","lines":[[3,15],[20,30],[42,42]]},
+          {"name":"file2.h"},
+          {"name":"file3.cc","lines":[[100,1000]]}])",
+      Options);
+  EXPECT_FALSE(Error);
+  EXPECT_EQ(3u, Options.LineFilter.size());
+  EXPECT_EQ("file1.cpp", Options.LineFilter[0].Name);
+  EXPECT_EQ(3u, Options.LineFilter[0].LineRanges.size());
+  EXPECT_EQ(3u, Options.LineFilter[0].LineRanges[0].first);
+  EXPECT_EQ(15u, Options.LineFilter[0].LineRanges[0].second);
+  EXPECT_EQ(20u, Options.LineFilter[0].LineRanges[1].first);
+  EXPECT_EQ(30u, Options.LineFilter[0].LineRanges[1].second);
+  EXPECT_EQ(42u, Options.LineFilter[0].LineRanges[2].first);
+  EXPECT_EQ(42u, Options.LineFilter[0].LineRanges[2].second);
+  EXPECT_EQ("file2.h", Options.LineFilter[1].Name);
+  EXPECT_EQ(0u, Options.LineFilter[1].LineRanges.size());
+  EXPECT_EQ("file3.cc", Options.LineFilter[2].Name);
+  EXPECT_EQ(1u, Options.LineFilter[2].LineRanges.size());
+  EXPECT_EQ(100u, Options.LineFilter[2].LineRanges[0].first);
+  EXPECT_EQ(1000u, Options.LineFilter[2].LineRanges[0].second);
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang





More information about the cfe-commits mailing list