brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.4 KiB · 5ec1239 Raw
997 lines · cpp
1//===-- DefineInlineTests.cpp -----------------------------------*- C++ -*-===//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 "TweakTesting.h"10#include "TestFS.h"11#include "gmock/gmock.h"12#include "gtest/gtest.h"13 14using ::testing::ElementsAre;15 16namespace clang {17namespace clangd {18namespace {19 20TWEAK_TEST(DefineInline);21 22TEST_F(DefineInlineTest, TriggersOnFunctionDecl) {23  // Basic check for function body and signature.24  EXPECT_AVAILABLE(R"cpp(25  class Bar {26    void baz();27  };28 29  [[void [[Bar::[[b^a^z]]]]() [[{30    return;31  }]]]]32 33  void foo();34  [[void [[f^o^o]]() [[{35    return;36  }]]]]37  )cpp");38 39  EXPECT_UNAVAILABLE(R"cpp(40  // Not a definition41  vo^i[[d^ ^f]]^oo();42 43  [[vo^id ]]foo[[()]] {[[44    [[(void)(5+3);45    return;]]46  }]]47 48  // Definition with no body.49  class Bar { Bar() = def^ault; };50  )cpp");51}52 53TEST_F(DefineInlineTest, NoForwardDecl) {54  Header = "void bar();";55  EXPECT_UNAVAILABLE(R"cpp(56  void bar() {57    return;58  }59  // FIXME: Generate a decl in the header.60  void fo^o() {61    return;62  })cpp");63}64 65TEST_F(DefineInlineTest, ReferencedDecls) {66  EXPECT_AVAILABLE(R"cpp(67    void bar();68    void foo(int test);69 70    void fo^o(int baz) {71      int x = 10;72      bar();73    })cpp");74 75  // Internal symbol usage.76  Header = "void foo(int test);";77  EXPECT_UNAVAILABLE(R"cpp(78    void bar();79    void fo^o(int baz) {80      int x = 10;81      bar();82    })cpp");83 84  // Becomes available after making symbol visible.85  Header = "void bar();" + Header;86  EXPECT_AVAILABLE(R"cpp(87    void fo^o(int baz) {88      int x = 10;89      bar();90    })cpp");91 92  // FIXME: Move declaration below bar to make it visible.93  Header.clear();94  EXPECT_UNAVAILABLE(R"cpp(95    void foo();96    void bar();97 98    void fo^o() {99      bar();100    })cpp");101 102  // Order doesn't matter within a class.103  EXPECT_AVAILABLE(R"cpp(104    class Bar {105      void foo();106      void bar();107    };108 109    void Bar::fo^o() {110      bar();111    })cpp");112 113  // FIXME: Perform include insertion to make symbol visible.114  ExtraFiles["a.h"] = "void bar();";115  Header = "void foo(int test);";116  EXPECT_UNAVAILABLE(R"cpp(117    #include "a.h"118    void fo^o(int baz) {119      int x = 10;120      bar();121    })cpp");122}123 124TEST_F(DefineInlineTest, TemplateSpec) {125  EXPECT_UNAVAILABLE(R"cpp(126    template <typename T> void foo();127    template<> void foo<char>();128 129    template<> void f^oo<int>() {130    })cpp");131  EXPECT_UNAVAILABLE(R"cpp(132    template <typename T> void foo();133 134    template<> void f^oo<int>() {135    })cpp");136  EXPECT_UNAVAILABLE(R"cpp(137    template <typename T> struct Foo { void foo(); };138 139    template <typename T> void Foo<T>::f^oo() {140    })cpp");141  EXPECT_AVAILABLE(R"cpp(142    template <typename T> void foo();143    void bar();144    template <> void foo<int>();145 146    template<> void f^oo<int>() {147      bar();148    })cpp");149  EXPECT_UNAVAILABLE(R"cpp(150    namespace bar {151      template <typename T> void f^oo() {}152      template void foo<int>();153    })cpp");154}155 156TEST_F(DefineInlineTest, CheckForCanonDecl) {157  EXPECT_UNAVAILABLE(R"cpp(158    void foo();159 160    void bar() {}161    void f^oo() {162      // This bar normally refers to the definition just above, but it is not163      // visible from the forward declaration of foo.164      bar();165    })cpp");166  // Make it available with a forward decl.167  EXPECT_AVAILABLE(R"cpp(168    void bar();169    void foo();170 171    void bar() {}172    void f^oo() {173      bar();174    })cpp");175}176 177TEST_F(DefineInlineTest, UsingShadowDecls) {178  EXPECT_UNAVAILABLE(R"cpp(179  namespace ns1 { void foo(int); }180  namespace ns2 { void foo(int*); }181  template <typename T>182  void bar();183 184  using ns1::foo;185  using ns2::foo;186 187  template <typename T>188  void b^ar() {189    foo(T());190  })cpp");191}192 193TEST_F(DefineInlineTest, TransformNestedNamespaces) {194  auto *Test = R"cpp(195    namespace a {196      void bar();197      namespace b {198        void baz();199        namespace c {200          void aux();201        }202      }203    }204 205    void foo();206    using namespace a;207    using namespace b;208    using namespace c;209    void f^oo() {210      bar();211      a::bar();212 213      baz();214      b::baz();215      a::b::baz();216 217      aux();218      c::aux();219      b::c::aux();220      a::b::c::aux();221    })cpp";222  auto *Expected = R"cpp(223    namespace a {224      void bar();225      namespace b {226        void baz();227        namespace c {228          void aux();229        }230      }231    }232 233    void foo(){234      a::bar();235      a::bar();236 237      a::b::baz();238      a::b::baz();239      a::b::baz();240 241      a::b::c::aux();242      a::b::c::aux();243      a::b::c::aux();244      a::b::c::aux();245    }246    using namespace a;247    using namespace b;248    using namespace c;249    )cpp";250  EXPECT_EQ(apply(Test), Expected);251}252 253TEST_F(DefineInlineTest, TransformUsings) {254  auto *Test = R"cpp(255    namespace a { namespace b { namespace c { void aux(); } } }256 257    void foo();258    void f^oo() {259      using namespace a;260      using namespace b;261      using namespace c;262      using c::aux;263      namespace d = c;264    })cpp";265  auto *Expected = R"cpp(266    namespace a { namespace b { namespace c { void aux(); } } }267 268    void foo(){269      using namespace a;270      using namespace a::b;271      using namespace a::b::c;272      using a::b::c::aux;273      namespace d = a::b::c;274    }275    )cpp";276  EXPECT_EQ(apply(Test), Expected);277}278 279TEST_F(DefineInlineTest, TransformDecls) {280  auto *Test = R"cpp(281    void foo();282    void f^oo() {283      class Foo {284      public:285        void foo();286        int x;287      };288 289      enum En { Zero, One };290      En x = Zero;291 292      enum class EnClass { Zero, One };293      EnClass y = EnClass::Zero;294    })cpp";295  auto *Expected = R"cpp(296    void foo(){297      class Foo {298      public:299        void foo();300        int x;301      };302 303      enum En { Zero, One };304      En x = Zero;305 306      enum class EnClass { Zero, One };307      EnClass y = EnClass::Zero;308    }309    )cpp";310  EXPECT_EQ(apply(Test), Expected);311}312 313TEST_F(DefineInlineTest, TransformTemplDecls) {314  auto *Test = R"cpp(315    namespace a {316      template <typename T> class Bar {317      public:318        void bar();319      };320      template <typename T> T bar;321      template <typename T> void aux() {}322    }323 324    void foo();325 326    using namespace a;327    void f^oo() {328      bar<Bar<int>>.bar();329      aux<Bar<int>>();330    })cpp";331  auto *Expected = R"cpp(332    namespace a {333      template <typename T> class Bar {334      public:335        void bar();336      };337      template <typename T> T bar;338      template <typename T> void aux() {}339    }340 341    void foo(){342      a::bar<a::Bar<int>>.bar();343      a::aux<a::Bar<int>>();344    }345 346    using namespace a;347    )cpp";348  EXPECT_EQ(apply(Test), Expected);349}350 351TEST_F(DefineInlineTest, TransformMembers) {352  auto *Test = R"cpp(353    class Foo {354      void foo();355    };356 357    void Foo::f^oo() {358      return;359    })cpp";360  auto *Expected = R"cpp(361    class Foo {362      void foo(){363      return;364    }365    };366 367    )cpp";368  EXPECT_EQ(apply(Test), Expected);369 370  ExtraFiles["a.h"] = R"cpp(371    class Foo {372      void foo();373    };)cpp";374 375  llvm::StringMap<std::string> EditedFiles;376  Test = R"cpp(377    #include "a.h"378    void Foo::f^oo() {379      return;380    })cpp";381  Expected = R"cpp(382    #include "a.h"383    )cpp";384  EXPECT_EQ(apply(Test, &EditedFiles), Expected);385 386  Expected = R"cpp(387    class Foo {388      void foo(){389      return;390    }391    };)cpp";392  EXPECT_THAT(EditedFiles,393              ElementsAre(FileWithContents(testPath("a.h"), Expected)));394}395 396TEST_F(DefineInlineTest, TransformDependentTypes) {397  auto *Test = R"cpp(398    namespace a {399      template <typename T> class Bar {};400    }401 402    template <typename T>403    void foo();404 405    using namespace a;406    template <typename T>407    void f^oo() {408      Bar<T> B;409      Bar<Bar<T>> q;410    })cpp";411  auto *Expected = R"cpp(412    namespace a {413      template <typename T> class Bar {};414    }415 416    template <typename T>417    void foo(){418      a::Bar<T> B;419      a::Bar<a::Bar<T>> q;420    }421 422    using namespace a;423    )cpp";424 425  EXPECT_EQ(apply(Test), Expected);426}427 428TEST_F(DefineInlineTest, TransformFunctionTempls) {429  // Check we select correct specialization decl.430  std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {431      {R"cpp(432          template <typename T>433          void foo(T p);434 435          template <>436          void foo<int>(int p);437 438          template <>439          void foo<char>(char p);440 441          template <>442          void fo^o<int>(int p) {443            return;444          })cpp",445       R"cpp(446          template <typename T>447          void foo(T p);448 449          template <>450          void foo<int>(int p){451            return;452          }453 454          template <>455          void foo<char>(char p);456 457          )cpp"},458      {// Make sure we are not selecting the first specialization all the time.459       R"cpp(460          template <typename T>461          void foo(T p);462 463          template <>464          void foo<int>(int p);465 466          template <>467          void foo<char>(char p);468 469          template <>470          void fo^o<char>(char p) {471            return;472          })cpp",473       R"cpp(474          template <typename T>475          void foo(T p);476 477          template <>478          void foo<int>(int p);479 480          template <>481          void foo<char>(char p){482            return;483          }484 485          )cpp"},486      {R"cpp(487          template <typename T>488          void foo(T p);489 490          template <>491          void foo<int>(int p);492 493          template <typename T>494          void fo^o(T p) {495            return;496          })cpp",497       R"cpp(498          template <typename T>499          void foo(T p){500            return;501          }502 503          template <>504          void foo<int>(int p);505 506          )cpp"},507  };508  for (const auto &Case : Cases)509    EXPECT_EQ(apply(Case.first), Case.second) << Case.first;510}511 512TEST_F(DefineInlineTest, TransformTypeLocs) {513  auto *Test = R"cpp(514    namespace a {515      template <typename T> class Bar {516      public:517        template <typename Q> class Baz {};518      };519      class Foo{};520    }521 522    void foo();523 524    using namespace a;525    void f^oo() {526      Bar<int> B;527      Foo foo;528      a::Bar<Bar<int>>::Baz<Bar<int>> q;529    })cpp";530  auto *Expected = R"cpp(531    namespace a {532      template <typename T> class Bar {533      public:534        template <typename Q> class Baz {};535      };536      class Foo{};537    }538 539    void foo(){540      a::Bar<int> B;541      a::Foo foo;542      a::Bar<a::Bar<int>>::Baz<a::Bar<int>> q;543    }544 545    using namespace a;546    )cpp";547  EXPECT_EQ(apply(Test), Expected);548}549 550TEST_F(DefineInlineTest, TransformDeclRefs) {551  auto *Test = R"cpp(552    namespace a {553      template <typename T> class Bar {554      public:555        void foo();556        static void bar();557        int x;558        static int y;559      };560      void bar();561      void test();562    }563 564    void foo();565    using namespace a;566    void f^oo() {567      a::Bar<int> B;568      B.foo();569      a::bar();570      Bar<Bar<int>>::bar();571      a::Bar<int>::bar();572      B.x = Bar<int>::y;573      Bar<int>::y = 3;574      bar();575      a::test();576    })cpp";577  auto *Expected = R"cpp(578    namespace a {579      template <typename T> class Bar {580      public:581        void foo();582        static void bar();583        int x;584        static int y;585      };586      void bar();587      void test();588    }589 590    void foo(){591      a::Bar<int> B;592      B.foo();593      a::bar();594      a::Bar<a::Bar<int>>::bar();595      a::Bar<int>::bar();596      B.x = a::Bar<int>::y;597      a::Bar<int>::y = 3;598      a::bar();599      a::test();600    }601    using namespace a;602    )cpp";603  EXPECT_EQ(apply(Test), Expected);604}605 606TEST_F(DefineInlineTest, StaticMembers) {607  auto *Test = R"cpp(608    namespace ns { class X { static void foo(); void bar(); }; }609    void ns::X::b^ar() {610      foo();611    })cpp";612  auto *Expected = R"cpp(613    namespace ns { class X { static void foo(); void bar(){614      foo();615    } }; }616    )cpp";617  EXPECT_EQ(apply(Test), Expected);618}619 620TEST_F(DefineInlineTest, TransformParamNames) {621  std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {622      {R"cpp(623        void foo(int, bool b, int T\624est);625        void ^foo(int f, bool x, int z) {})cpp",626       R"cpp(627        void foo(int f, bool x, int z){}628        )cpp"},629      {R"cpp(630        #define PARAM int Z631        void foo(PARAM);632 633        void ^foo(int X) {})cpp",634       "fail: Cant rename parameter inside macro body."},635      {R"cpp(636        #define TYPE int637        #define PARAM TYPE Z638        #define BODY(x) 5 * (x) + 2639        template <int P>640        void foo(PARAM, TYPE Q, TYPE, TYPE W = BODY(P));641        template <int x>642        void ^foo(int Z, int b, int c, int d) {})cpp",643       R"cpp(644        #define TYPE int645        #define PARAM TYPE Z646        #define BODY(x) 5 * (x) + 2647        template <int x>648        void foo(PARAM, TYPE b, TYPE c, TYPE d = BODY(x)){}649        )cpp"},650  };651  for (const auto &Case : Cases)652    EXPECT_EQ(apply(Case.first), Case.second) << Case.first;653}654 655TEST_F(DefineInlineTest, TransformTemplParamNames) {656  auto *Test = R"cpp(657    struct Foo {658      struct Bar {659        template <class, class X,660                  template<typename> class, template<typename> class Y,661                  int, int Z>662        void foo(X, Y<X>, int W = 5 * Z + 2);663      };664    };665 666    template <class T, class U,667              template<typename> class V, template<typename> class W,668              int X, int Y>669    void Foo::Bar::f^oo(U, W<U>, int Q) {})cpp";670  auto *Expected = R"cpp(671    struct Foo {672      struct Bar {673        template <class T, class U,674                  template<typename> class V, template<typename> class W,675                  int X, int Y>676        void foo(U, W<U>, int Q = 5 * Y + 2){}677      };678    };679 680    )cpp";681  EXPECT_EQ(apply(Test), Expected);682}683 684TEST_F(DefineInlineTest, TransformInlineNamespaces) {685  auto *Test = R"cpp(686    namespace a { inline namespace b { namespace { struct Foo{}; } } }687    void foo();688 689    using namespace a;690    void ^foo() {Foo foo;})cpp";691  auto *Expected = R"cpp(692    namespace a { inline namespace b { namespace { struct Foo{}; } } }693    void foo(){a::Foo foo;}694 695    using namespace a;696    )cpp";697  EXPECT_EQ(apply(Test), Expected);698}699 700TEST_F(DefineInlineTest, TokensBeforeSemicolon) {701  std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {702      {R"cpp(703          void foo()    /*Comment -_-*/ /*Com 2*/ ;704          void fo^o() { return ; })cpp",705       R"cpp(706          void foo()    /*Comment -_-*/ /*Com 2*/ { return ; }707          )cpp"},708 709      {R"cpp(710          void foo();711          void fo^o() { return ; })cpp",712       R"cpp(713          void foo(){ return ; }714          )cpp"},715 716      {R"cpp(717          #define SEMI ;718          void foo() SEMI719          void fo^o() { return ; })cpp",720       "fail: Couldn't find semicolon for target declaration."},721  };722  for (const auto &Case : Cases)723    EXPECT_EQ(apply(Case.first), Case.second) << Case.first;724}725 726TEST_F(DefineInlineTest, HandleMacros) {727  EXPECT_UNAVAILABLE(R"cpp(728    #define BODY { return; }729    void foo();730    void f^oo()BODY)cpp");731 732  EXPECT_UNAVAILABLE(R"cpp(733    #define BODY void foo(){ return; }734    void foo();735    [[BODY]])cpp");736 737  std::pair<llvm::StringRef, llvm::StringRef> Cases[] = {738      // We don't qualify declarations coming from macros.739      {R"cpp(740          #define BODY Foo741          namespace a { class Foo{}; }742          void foo();743          using namespace a;744          void f^oo(){BODY();})cpp",745       R"cpp(746          #define BODY Foo747          namespace a { class Foo{}; }748          void foo(){BODY();}749          using namespace a;750          )cpp"},751 752      // Macro is not visible at declaration location, but we proceed.753      {R"cpp(754          void foo();755          #define BODY return;756          void f^oo(){BODY})cpp",757       R"cpp(758          void foo(){BODY}759          #define BODY return;760          )cpp"},761 762      {R"cpp(763          #define TARGET void foo()764          TARGET;765          void f^oo(){ return; })cpp",766       R"cpp(767          #define TARGET void foo()768          TARGET{ return; }769          )cpp"},770 771      {R"cpp(772          #define TARGET foo773          void TARGET();774          void f^oo(){ return; })cpp",775       R"cpp(776          #define TARGET foo777          void TARGET(){ return; }778          )cpp"},779  };780  for (const auto &Case : Cases)781    EXPECT_EQ(apply(Case.first), Case.second) << Case.first;782}783 784TEST_F(DefineInlineTest, DropCommonNameSpecifiers) {785  struct {786    llvm::StringRef Test;787    llvm::StringRef Expected;788  } Cases[] = {789      {R"cpp(790        namespace a { namespace b { void aux(); } }791        namespace ns1 {792          void foo();793          namespace qq { void test(); }794          namespace ns2 {795            void bar();796            namespace ns3 { void baz(); }797          }798        }799 800        using namespace a;801        using namespace a::b;802        using namespace ns1::qq;803        void ns1::ns2::ns3::b^az() {804          foo();805          bar();806          baz();807          ns1::ns2::ns3::baz();808          aux();809          test();810        })cpp",811       R"cpp(812        namespace a { namespace b { void aux(); } }813        namespace ns1 {814          void foo();815          namespace qq { void test(); }816          namespace ns2 {817            void bar();818            namespace ns3 { void baz(){819          foo();820          bar();821          baz();822          ns1::ns2::ns3::baz();823          a::b::aux();824          qq::test();825        } }826          }827        }828 829        using namespace a;830        using namespace a::b;831        using namespace ns1::qq;832        )cpp"},833      {R"cpp(834        namespace ns1 {835          namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }836          namespace ns2 { void baz(); }837        }838 839        using namespace ns1::qq;840        void ns1::ns2::b^az() { Foo f; B b; })cpp",841       R"cpp(842        namespace ns1 {843          namespace qq { struct Foo { struct Bar {}; }; using B = Foo::Bar; }844          namespace ns2 { void baz(){ qq::Foo f; qq::B b; } }845        }846 847        using namespace ns1::qq;848        )cpp"},849      {R"cpp(850        namespace ns1 {851          namespace qq {852            template<class T> struct Foo { template <class U> struct Bar {}; };853            template<class T, class U>854            using B = typename Foo<T>::template Bar<U>;855          }856          namespace ns2 { void baz(); }857        }858 859        using namespace ns1::qq;860        void ns1::ns2::b^az() { B<int, bool> b; })cpp",861       R"cpp(862        namespace ns1 {863          namespace qq {864            template<class T> struct Foo { template <class U> struct Bar {}; };865            template<class T, class U>866            using B = typename Foo<T>::template Bar<U>;867          }868          namespace ns2 { void baz(){ qq::B<int, bool> b; } }869        }870 871        using namespace ns1::qq;872        )cpp"},873  };874  for (const auto &Case : Cases)875    EXPECT_EQ(apply(Case.Test), Case.Expected) << Case.Test;876}877 878TEST_F(DefineInlineTest, QualifyWithUsingDirectives) {879  llvm::StringRef Test = R"cpp(880    namespace a {881      void bar();882      namespace b { struct Foo{}; void aux(); }883      namespace c { void cux(); }884    }885    using namespace a;886    using X = b::Foo;887    void foo();888 889    using namespace b;890    using namespace c;891    void ^foo() {892      cux();893      bar();894      X x;895      aux();896      using namespace c;897      // FIXME: The last reference to cux() in body of foo should not be898      // qualified, since there is a using directive inside the function body.899      cux();900    })cpp";901  llvm::StringRef Expected = R"cpp(902    namespace a {903      void bar();904      namespace b { struct Foo{}; void aux(); }905      namespace c { void cux(); }906    }907    using namespace a;908    using X = b::Foo;909    void foo(){910      c::cux();911      bar();912      X x;913      b::aux();914      using namespace c;915      // FIXME: The last reference to cux() in body of foo should not be916      // qualified, since there is a using directive inside the function body.917      c::cux();918    }919 920    using namespace b;921    using namespace c;922    )cpp";923  EXPECT_EQ(apply(Test), Expected) << Test;924}925 926TEST_F(DefineInlineTest, AddInline) {927  llvm::StringMap<std::string> EditedFiles;928  ExtraFiles["a.h"] = "void foo();";929  apply(R"cpp(#include "a.h"930              void fo^o() {})cpp",931        &EditedFiles);932  EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(933                               testPath("a.h"), "inline void foo(){}")));934 935  // Check we put inline before cv-qualifiers.936  ExtraFiles["a.h"] = "const int foo();";937  apply(R"cpp(#include "a.h"938              const int fo^o() { return 0; })cpp",939        &EditedFiles);940  EXPECT_THAT(EditedFiles,941              testing::ElementsAre(FileWithContents(942                  testPath("a.h"), "inline const int foo(){ return 0; }")));943 944  // No double inline.945  ExtraFiles["a.h"] = "inline void foo();";946  apply(R"cpp(#include "a.h"947              inline void fo^o() {})cpp",948        &EditedFiles);949  EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(950                               testPath("a.h"), "inline void foo(){}")));951 952  // Constexprs don't need "inline".953  ExtraFiles["a.h"] = "constexpr void foo();";954  apply(R"cpp(#include "a.h"955              constexpr void fo^o() {})cpp",956        &EditedFiles);957  EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(958                               testPath("a.h"), "constexpr void foo(){}")));959 960  // Class members don't need "inline".961  ExtraFiles["a.h"] = "struct Foo { void foo(); };";962  apply(R"cpp(#include "a.h"963              void Foo::fo^o() {})cpp",964        &EditedFiles);965  EXPECT_THAT(EditedFiles,966              testing::ElementsAre(FileWithContents(967                  testPath("a.h"), "struct Foo { void foo(){} };")));968 969  // Function template doesn't need to be "inline"d.970  ExtraFiles["a.h"] = "template <typename T> void foo();";971  apply(R"cpp(#include "a.h"972              template <typename T>973              void fo^o() {})cpp",974        &EditedFiles);975  EXPECT_THAT(EditedFiles,976              testing::ElementsAre(FileWithContents(977                  testPath("a.h"), "template <typename T> void foo(){}")));978 979  // Specializations needs to be marked "inline".980  ExtraFiles["a.h"] = R"cpp(981                            template <typename T> void foo();982                            template <> void foo<int>();)cpp";983  apply(R"cpp(#include "a.h"984              template <>985              void fo^o<int>() {})cpp",986        &EditedFiles);987  EXPECT_THAT(EditedFiles,988              testing::ElementsAre(FileWithContents(testPath("a.h"),989                                                    R"cpp(990                            template <typename T> void foo();991                            template <> inline void foo<int>(){})cpp")));992}993 994} // namespace995} // namespace clangd996} // namespace clang997