brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.4 KiB · a9b4629 Raw
609 lines · cpp
1//===-- ConfigCompileTests.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Config.h"10#include "ConfigFragment.h"11#include "ConfigTesting.h"12#include "Diagnostics.h"13#include "Feature.h"14#include "TestFS.h"15#include "clang/Basic/DiagnosticSema.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Path.h"18#include "llvm/Support/SourceMgr.h"19#include "gmock/gmock.h"20#include "gtest/gtest.h"21#include <optional>22#include <string>23 24namespace clang {25namespace clangd {26namespace config {27namespace {28using ::testing::AllOf;29using ::testing::Contains;30using ::testing::ElementsAre;31using ::testing::IsEmpty;32using ::testing::SizeIs;33using ::testing::StartsWith;34using ::testing::UnorderedElementsAre;35 36class ConfigCompileTests : public ::testing::Test {37protected:38  CapturedDiags Diags;39  Config Conf;40  Fragment Frag;41  Params Parm;42 43  bool compileAndApply() {44    Conf = Config();45    Diags.Diagnostics.clear();46    auto Compiled = std::move(Frag).compile(Diags.callback());47    return Compiled(Parm, Conf);48  }49};50 51TEST_F(ConfigCompileTests, Condition) {52  // No condition.53  Frag = {};54  Frag.CompileFlags.Add.emplace_back("X");55  EXPECT_TRUE(compileAndApply()) << "Empty config";56  EXPECT_THAT(Diags.Diagnostics, IsEmpty());57  EXPECT_THAT(Conf.CompileFlags.Edits, SizeIs(1));58 59  // Regex with no file.60  Frag = {};61  Frag.If.PathMatch.emplace_back("fo*");62  EXPECT_FALSE(compileAndApply());63  EXPECT_THAT(Diags.Diagnostics, IsEmpty());64  EXPECT_THAT(Conf.CompileFlags.Edits, SizeIs(0));65 66  // Following tests have a file path set.67  Parm.Path = "bar";68 69  // Non-matching regex.70  Frag = {};71  Frag.If.PathMatch.emplace_back("fo*");72  EXPECT_FALSE(compileAndApply());73  EXPECT_THAT(Diags.Diagnostics, IsEmpty());74 75  // Matching regex.76  Frag = {};77  Frag.If.PathMatch.emplace_back("fo*");78  Frag.If.PathMatch.emplace_back("ba*r");79  EXPECT_TRUE(compileAndApply());80  EXPECT_THAT(Diags.Diagnostics, IsEmpty());81 82  // Excluded regex.83  Frag = {};84  Frag.If.PathMatch.emplace_back("b.*");85  Frag.If.PathExclude.emplace_back(".*r");86  EXPECT_FALSE(compileAndApply()) << "Included but also excluded";87  EXPECT_THAT(Diags.Diagnostics, IsEmpty());88 89  // Invalid regex.90  Frag = {};91  Frag.If.PathMatch.emplace_back("**]@theu");92  EXPECT_TRUE(compileAndApply());93  EXPECT_THAT(Diags.Diagnostics, SizeIs(1));94  EXPECT_THAT(Diags.Diagnostics.front().Message, StartsWith("Invalid regex"));95 96  // Valid regex and unknown key.97  Frag = {};98  Frag.If.HasUnrecognizedCondition = true;99  Frag.If.PathMatch.emplace_back("ba*r");100  EXPECT_FALSE(compileAndApply());101  EXPECT_THAT(Diags.Diagnostics, IsEmpty());102 103  // Only matches case-insensitively.104  Frag = {};105  Frag.If.PathMatch.emplace_back("B.*R");106  EXPECT_THAT(Diags.Diagnostics, IsEmpty());107#ifdef CLANGD_PATH_CASE_INSENSITIVE108  EXPECT_TRUE(compileAndApply());109#else110  EXPECT_FALSE(compileAndApply());111#endif112 113  Frag = {};114  Frag.If.PathExclude.emplace_back("B.*R");115  EXPECT_THAT(Diags.Diagnostics, IsEmpty());116#ifdef CLANGD_PATH_CASE_INSENSITIVE117  EXPECT_FALSE(compileAndApply());118#else119  EXPECT_TRUE(compileAndApply());120#endif121}122 123TEST_F(ConfigCompileTests, CompileCommands) {124  Frag.CompileFlags.Compiler.emplace("tpc.exe");125  Frag.CompileFlags.Add.emplace_back("-foo");126  Frag.CompileFlags.Remove.emplace_back("--include-directory=");127  std::vector<std::string> Argv = {"clang", "-I", "bar/", "--", "a.cc"};128  EXPECT_TRUE(compileAndApply());129  EXPECT_THAT(Conf.CompileFlags.Edits, SizeIs(3));130  for (auto &Edit : Conf.CompileFlags.Edits)131    Edit(Argv);132  EXPECT_THAT(Argv, ElementsAre("tpc.exe", "-foo", "--", "a.cc"));133}134 135TEST_F(ConfigCompileTests, CompilationDatabase) {136  Frag.CompileFlags.CompilationDatabase.emplace("None");137  EXPECT_TRUE(compileAndApply());138  EXPECT_EQ(Conf.CompileFlags.CDBSearch.Policy,139            Config::CDBSearchSpec::NoCDBSearch);140 141  Frag.CompileFlags.CompilationDatabase.emplace("Ancestors");142  EXPECT_TRUE(compileAndApply());143  EXPECT_EQ(Conf.CompileFlags.CDBSearch.Policy,144            Config::CDBSearchSpec::Ancestors);145 146  // Relative path not allowed without directory set.147  Frag.CompileFlags.CompilationDatabase.emplace("Something");148  EXPECT_TRUE(compileAndApply());149  EXPECT_EQ(Conf.CompileFlags.CDBSearch.Policy,150            Config::CDBSearchSpec::Ancestors)151      << "default value";152  EXPECT_THAT(Diags.Diagnostics,153              ElementsAre(diagMessage(154                  "CompilationDatabase must be an absolute path, because this "155                  "fragment is not associated with any directory.")));156 157  // Relative path allowed if directory is set.158  Frag.Source.Directory = testRoot();159  EXPECT_TRUE(compileAndApply());160  EXPECT_EQ(Conf.CompileFlags.CDBSearch.Policy,161            Config::CDBSearchSpec::FixedDir);162  EXPECT_EQ(Conf.CompileFlags.CDBSearch.FixedCDBPath, testPath("Something"));163  EXPECT_THAT(Diags.Diagnostics, IsEmpty());164 165  // Absolute path allowed.166  Frag.Source.Directory.clear();167  Frag.CompileFlags.CompilationDatabase.emplace(testPath("Something2"));168  EXPECT_TRUE(compileAndApply());169  EXPECT_EQ(Conf.CompileFlags.CDBSearch.Policy,170            Config::CDBSearchSpec::FixedDir);171  EXPECT_EQ(Conf.CompileFlags.CDBSearch.FixedCDBPath, testPath("Something2"));172  EXPECT_THAT(Diags.Diagnostics, IsEmpty());173}174 175TEST_F(ConfigCompileTests, Index) {176  Frag.Index.Background.emplace("Skip");177  EXPECT_TRUE(compileAndApply());178  EXPECT_EQ(Conf.Index.Background, Config::BackgroundPolicy::Skip);179 180  Frag = {};181  Frag.Index.Background.emplace("Foo");182  EXPECT_TRUE(compileAndApply());183  EXPECT_EQ(Conf.Index.Background, Config::BackgroundPolicy::Build)184      << "by default";185  EXPECT_THAT(186      Diags.Diagnostics,187      ElementsAre(diagMessage(188          "Invalid Background value 'Foo'. Valid values are Build, Skip.")));189}190 191TEST_F(ConfigCompileTests, PathSpecMatch) {192  auto BarPath = llvm::sys::path::convert_to_slash(testPath("foo/bar.h"));193  Parm.Path = BarPath;194 195  struct {196    std::string Directory;197    std::string PathSpec;198    bool ShouldMatch;199  } Cases[] = {200      {201          // Absolute path matches.202          "",203          llvm::sys::path::convert_to_slash(testPath("foo/bar.h")),204          true,205      },206      {207          // Absolute path fails.208          "",209          llvm::sys::path::convert_to_slash(testPath("bar/bar.h")),210          false,211      },212      {213          // Relative should fail to match as /foo/bar.h doesn't reside under214          // /baz/.215          testPath("baz"),216          "bar\\.h",217          false,218      },219      {220          // Relative should pass with /foo as directory.221          testPath("foo"),222          "bar\\.h",223          true,224      },225  };226 227  // PathMatch228  for (const auto &Case : Cases) {229    Frag = {};230    Frag.If.PathMatch.emplace_back(Case.PathSpec);231    Frag.Source.Directory = Case.Directory;232    EXPECT_EQ(compileAndApply(), Case.ShouldMatch);233    ASSERT_THAT(Diags.Diagnostics, IsEmpty());234  }235 236  // PathEclude237  for (const auto &Case : Cases) {238    SCOPED_TRACE(Case.Directory);239    SCOPED_TRACE(Case.PathSpec);240    Frag = {};241    Frag.If.PathExclude.emplace_back(Case.PathSpec);242    Frag.Source.Directory = Case.Directory;243    EXPECT_NE(compileAndApply(), Case.ShouldMatch);244    ASSERT_THAT(Diags.Diagnostics, IsEmpty());245  }246}247 248TEST_F(ConfigCompileTests, DiagnosticsIncludeCleaner) {249  // Defaults to Strict.250  EXPECT_TRUE(compileAndApply());251  EXPECT_EQ(Conf.Diagnostics.UnusedIncludes, Config::IncludesPolicy::Strict);252 253  Frag = {};254  Frag.Diagnostics.UnusedIncludes.emplace("None");255  EXPECT_TRUE(compileAndApply());256  EXPECT_EQ(Conf.Diagnostics.UnusedIncludes, Config::IncludesPolicy::None);257 258  Frag = {};259  Frag.Diagnostics.UnusedIncludes.emplace("Strict");260  EXPECT_TRUE(compileAndApply());261  EXPECT_EQ(Conf.Diagnostics.UnusedIncludes, Config::IncludesPolicy::Strict);262 263  Frag = {};264  EXPECT_TRUE(Conf.Diagnostics.Includes.IgnoreHeader.empty())265      << Conf.Diagnostics.Includes.IgnoreHeader.size();266  Frag.Diagnostics.Includes.IgnoreHeader.push_back(267      Located<std::string>("foo.h"));268  Frag.Diagnostics.Includes.IgnoreHeader.push_back(269      Located<std::string>(".*inc"));270  EXPECT_TRUE(compileAndApply());271  auto HeaderFilter = [this](llvm::StringRef Path) {272    for (auto &Filter : Conf.Diagnostics.Includes.IgnoreHeader) {273      if (Filter(Path))274        return true;275    }276    return false;277  };278  EXPECT_TRUE(HeaderFilter("foo.h"));279  EXPECT_FALSE(HeaderFilter("bar.h"));280 281  Frag = {};282  EXPECT_FALSE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes);283  Frag.Diagnostics.Includes.AnalyzeAngledIncludes = true;284  EXPECT_TRUE(compileAndApply());285  EXPECT_TRUE(Conf.Diagnostics.Includes.AnalyzeAngledIncludes);286}287 288TEST_F(ConfigCompileTests, DiagnosticSuppression) {289  Frag.Diagnostics.Suppress.emplace_back("bugprone-use-after-move");290  Frag.Diagnostics.Suppress.emplace_back("unreachable-code");291  Frag.Diagnostics.Suppress.emplace_back("-Wunused-variable");292  Frag.Diagnostics.Suppress.emplace_back("typecheck_bool_condition");293  Frag.Diagnostics.Suppress.emplace_back("err_unexpected_friend");294  Frag.Diagnostics.Suppress.emplace_back("warn_alloca");295  EXPECT_TRUE(compileAndApply());296  EXPECT_THAT(Conf.Diagnostics.Suppress.keys(),297              UnorderedElementsAre("bugprone-use-after-move",298                                   "unreachable-code", "unused-variable",299                                   "typecheck_bool_condition",300                                   "unexpected_friend", "warn_alloca"));301  clang::DiagnosticOptions DiagOpts;302  clang::DiagnosticsEngine DiagEngine(DiagnosticIDs::create(), DiagOpts,303                                      new clang::IgnoringDiagConsumer);304 305  using Diag = clang::Diagnostic;306  {307    auto D = DiagEngine.Report(diag::warn_unreachable);308    EXPECT_TRUE(isDiagnosticSuppressed(309        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));310  }311  // Subcategory not respected/suppressed.312  {313    auto D = DiagEngine.Report(diag::warn_unreachable_break);314    EXPECT_FALSE(isDiagnosticSuppressed(315        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));316  }317  {318    auto D = DiagEngine.Report(diag::warn_unused_variable);319    EXPECT_TRUE(isDiagnosticSuppressed(320        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));321  }322  {323    auto D = DiagEngine.Report(diag::err_typecheck_bool_condition);324    EXPECT_TRUE(isDiagnosticSuppressed(325        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));326  }327  {328    auto D = DiagEngine.Report(diag::err_unexpected_friend);329    EXPECT_TRUE(isDiagnosticSuppressed(330        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));331  }332  {333    auto D = DiagEngine.Report(diag::warn_alloca);334    EXPECT_TRUE(isDiagnosticSuppressed(335        Diag{&DiagEngine, D}, Conf.Diagnostics.Suppress, LangOptions()));336  }337 338  Frag.Diagnostics.Suppress.emplace_back("*");339  EXPECT_TRUE(compileAndApply());340  EXPECT_TRUE(Conf.Diagnostics.SuppressAll);341  EXPECT_THAT(Conf.Diagnostics.Suppress, IsEmpty());342}343 344TEST_F(ConfigCompileTests, Tidy) {345  auto &Tidy = Frag.Diagnostics.ClangTidy;346  Tidy.Add.emplace_back("bugprone-use-after-move");347  Tidy.Add.emplace_back("llvm-*");348  Tidy.Remove.emplace_back("llvm-include-order");349  Tidy.Remove.emplace_back("readability-*");350  Tidy.CheckOptions.emplace_back(std::make_pair(351      std::string("example-check.ExampleOption"), std::string("0")));352  EXPECT_TRUE(compileAndApply());353  EXPECT_EQ(Conf.Diagnostics.ClangTidy.CheckOptions.size(), 1U);354  EXPECT_EQ(Conf.Diagnostics.ClangTidy.CheckOptions.lookup(355                "example-check.ExampleOption"),356            "0");357#if CLANGD_TIDY_CHECKS358  EXPECT_EQ(359      Conf.Diagnostics.ClangTidy.Checks,360      "bugprone-use-after-move,llvm-*,-llvm-include-order,-readability-*");361  EXPECT_THAT(Diags.Diagnostics, IsEmpty());362#else // !CLANGD_TIDY_CHECKS363  EXPECT_EQ(Conf.Diagnostics.ClangTidy.Checks, "llvm-*,-readability-*");364  EXPECT_THAT(365      Diags.Diagnostics,366      ElementsAre(367          diagMessage(368              "clang-tidy check 'bugprone-use-after-move' was not found"),369          diagMessage("clang-tidy check 'llvm-include-order' was not found")));370#endif371}372 373TEST_F(ConfigCompileTests, TidyBadChecks) {374  auto &Tidy = Frag.Diagnostics.ClangTidy;375  Tidy.Add.emplace_back("unknown-check");376  Tidy.Remove.emplace_back("*");377  Tidy.Remove.emplace_back("llvm-includeorder");378  EXPECT_TRUE(compileAndApply());379  // Ensure bad checks are stripped from the glob.380  EXPECT_EQ(Conf.Diagnostics.ClangTidy.Checks, "-*");381  EXPECT_THAT(382      Diags.Diagnostics,383      ElementsAre(384          AllOf(diagMessage("clang-tidy check 'unknown-check' was not found"),385                diagKind(llvm::SourceMgr::DK_Warning)),386          AllOf(387              diagMessage("clang-tidy check 'llvm-includeorder' was not found"),388              diagKind(llvm::SourceMgr::DK_Warning))));389}390 391TEST_F(ConfigCompileTests, ExternalServerNeedsTrusted) {392  Fragment::IndexBlock::ExternalBlock External;393  External.Server.emplace("xxx");394  Frag.Index.External = std::move(External);395  compileAndApply();396  EXPECT_THAT(397      Diags.Diagnostics,398      ElementsAre(diagMessage(399          "Remote index may not be specified by untrusted configuration. "400          "Copy this into user config to use it.")));401  EXPECT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);402}403 404TEST_F(ConfigCompileTests, ExternalBlockWarnOnMultipleSource) {405  Frag.Source.Trusted = true;406  Fragment::IndexBlock::ExternalBlock External;407  External.File.emplace("");408  External.Server.emplace("");409  Frag.Index.External = std::move(External);410  compileAndApply();411#ifdef CLANGD_ENABLE_REMOTE412  EXPECT_THAT(413      Diags.Diagnostics,414      Contains(415          AllOf(diagMessage("Exactly one of File, Server or None must be set."),416                diagKind(llvm::SourceMgr::DK_Error))));417#else418  ASSERT_TRUE(Conf.Index.External.hasValue());419  EXPECT_EQ(Conf.Index.External->Kind, Config::ExternalIndexSpec::File);420#endif421}422 423TEST_F(ConfigCompileTests, ExternalBlockDisableWithNone) {424  compileAndApply();425  EXPECT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);426 427  Fragment::IndexBlock::ExternalBlock External;428  External.IsNone = true;429  Frag.Index.External = std::move(External);430  compileAndApply();431  EXPECT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);432}433 434TEST_F(ConfigCompileTests, ExternalBlockErrOnNoSource) {435  Frag.Index.External.emplace(Fragment::IndexBlock::ExternalBlock{});436  compileAndApply();437  EXPECT_THAT(438      Diags.Diagnostics,439      Contains(440          AllOf(diagMessage("Exactly one of File, Server or None must be set."),441                diagKind(llvm::SourceMgr::DK_Error))));442}443 444TEST_F(ConfigCompileTests, ExternalBlockDisablesBackgroundIndex) {445  auto BazPath = testPath("foo/bar/baz.h", llvm::sys::path::Style::posix);446  Parm.Path = BazPath;447  Frag.Index.Background.emplace("Build");448  Fragment::IndexBlock::ExternalBlock External;449  External.File.emplace(testPath("foo"));450  External.MountPoint.emplace(451      testPath("foo/bar", llvm::sys::path::Style::posix));452  Frag.Index.External = std::move(External);453  compileAndApply();454  EXPECT_EQ(Conf.Index.Background, Config::BackgroundPolicy::Skip);455}456 457TEST_F(ConfigCompileTests, ExternalBlockMountPoint) {458  auto GetFrag = [](llvm::StringRef Directory,459                    std::optional<const char *> MountPoint) {460    Fragment Frag;461    Frag.Source.Directory = Directory.str();462    Fragment::IndexBlock::ExternalBlock External;463    External.File.emplace(testPath("foo"));464    if (MountPoint)465      External.MountPoint.emplace(*MountPoint);466    Frag.Index.External = std::move(External);467    return Frag;468  };469 470  auto BarPath = testPath("foo/bar.h", llvm::sys::path::Style::posix);471  BarPath = llvm::sys::path::convert_to_slash(BarPath);472  Parm.Path = BarPath;473  // Non-absolute MountPoint without a directory raises an error.474  Frag = GetFrag("", "foo");475  compileAndApply();476  ASSERT_THAT(477      Diags.Diagnostics,478      ElementsAre(479          AllOf(diagMessage("MountPoint must be an absolute path, because this "480                            "fragment is not associated with any directory."),481                diagKind(llvm::SourceMgr::DK_Error))));482  EXPECT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);483 484  auto FooPath = testPath("foo/", llvm::sys::path::Style::posix);485  FooPath = llvm::sys::path::convert_to_slash(FooPath);486  // Ok when relative.487  Frag = GetFrag(testRoot(), "foo/");488  compileAndApply();489  ASSERT_THAT(Diags.Diagnostics, IsEmpty());490  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::File);491  EXPECT_THAT(Conf.Index.External.MountPoint, FooPath);492 493  // None defaults to ".".494  Frag = GetFrag(FooPath, std::nullopt);495  compileAndApply();496  ASSERT_THAT(Diags.Diagnostics, IsEmpty());497  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::File);498  EXPECT_THAT(Conf.Index.External.MountPoint, FooPath);499 500  // Without a file, external index is empty.501  Parm.Path = "";502  Frag = GetFrag("", FooPath.c_str());503  compileAndApply();504  ASSERT_THAT(Diags.Diagnostics, IsEmpty());505  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);506 507  // File outside MountPoint, no index.508  auto BazPath = testPath("bar/baz.h", llvm::sys::path::Style::posix);509  BazPath = llvm::sys::path::convert_to_slash(BazPath);510  Parm.Path = BazPath;511  Frag = GetFrag("", FooPath.c_str());512  compileAndApply();513  ASSERT_THAT(Diags.Diagnostics, IsEmpty());514  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);515 516  // File under MountPoint, index should be set.517  BazPath = testPath("foo/baz.h", llvm::sys::path::Style::posix);518  BazPath = llvm::sys::path::convert_to_slash(BazPath);519  Parm.Path = BazPath;520  Frag = GetFrag("", FooPath.c_str());521  compileAndApply();522  ASSERT_THAT(Diags.Diagnostics, IsEmpty());523  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::File);524  EXPECT_THAT(Conf.Index.External.MountPoint, FooPath);525 526  // Only matches case-insensitively.527  BazPath = testPath("fOo/baz.h", llvm::sys::path::Style::posix);528  BazPath = llvm::sys::path::convert_to_slash(BazPath);529  Parm.Path = BazPath;530 531  FooPath = testPath("FOO/", llvm::sys::path::Style::posix);532  FooPath = llvm::sys::path::convert_to_slash(FooPath);533  Frag = GetFrag("", FooPath.c_str());534  compileAndApply();535  ASSERT_THAT(Diags.Diagnostics, IsEmpty());536#ifdef CLANGD_PATH_CASE_INSENSITIVE537  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::File);538  EXPECT_THAT(Conf.Index.External.MountPoint, FooPath);539#else540  ASSERT_EQ(Conf.Index.External.Kind, Config::ExternalIndexSpec::None);541#endif542}543 544TEST_F(ConfigCompileTests, AllScopes) {545  // Defaults to true.546  EXPECT_TRUE(compileAndApply());547  EXPECT_TRUE(Conf.Completion.AllScopes);548 549  Frag = {};550  Frag.Completion.AllScopes = false;551  EXPECT_TRUE(compileAndApply());552  EXPECT_FALSE(Conf.Completion.AllScopes);553 554  Frag = {};555  Frag.Completion.AllScopes = true;556  EXPECT_TRUE(compileAndApply());557  EXPECT_TRUE(Conf.Completion.AllScopes);558}559 560TEST_F(ConfigCompileTests, Style) {561  Frag = {};562  Frag.Style.FullyQualifiedNamespaces.push_back(std::string("foo"));563  Frag.Style.FullyQualifiedNamespaces.push_back(std::string("bar"));564  EXPECT_TRUE(compileAndApply());565  EXPECT_THAT(Conf.Style.FullyQualifiedNamespaces, ElementsAre("foo", "bar"));566 567  {568    Frag = {};569    EXPECT_TRUE(Conf.Style.QuotedHeaders.empty())570        << Conf.Style.QuotedHeaders.size();571    Frag.Style.QuotedHeaders.push_back(Located<std::string>("foo.h"));572    Frag.Style.QuotedHeaders.push_back(Located<std::string>(".*inc"));573    EXPECT_TRUE(compileAndApply());574    auto HeaderFilter = [this](llvm::StringRef Path) {575      for (auto &Filter : Conf.Style.QuotedHeaders) {576        if (Filter(Path))577          return true;578      }579      return false;580    };581    EXPECT_TRUE(HeaderFilter("foo.h"));582    EXPECT_TRUE(HeaderFilter("prefix/foo.h"));583    EXPECT_FALSE(HeaderFilter("bar.h"));584    EXPECT_FALSE(HeaderFilter("foo.h/bar.h"));585  }586 587  {588    Frag = {};589    EXPECT_TRUE(Conf.Style.AngledHeaders.empty())590        << Conf.Style.AngledHeaders.size();591    Frag.Style.AngledHeaders.push_back(Located<std::string>("foo.h"));592    Frag.Style.AngledHeaders.push_back(Located<std::string>(".*inc"));593    EXPECT_TRUE(compileAndApply());594    auto HeaderFilter = [this](llvm::StringRef Path) {595      for (auto &Filter : Conf.Style.AngledHeaders) {596        if (Filter(Path))597          return true;598      }599      return false;600    };601    EXPECT_TRUE(HeaderFilter("foo.h"));602    EXPECT_FALSE(HeaderFilter("bar.h"));603  }604}605} // namespace606} // namespace config607} // namespace clangd608} // namespace clang609