13 #include "clang/Basic/FileManager.h"
14 #include "clang/Basic/FileSystemOptions.h"
15 #include "clang/Frontend/CompilerInstance.h"
16 #include "clang/Index/IndexingAction.h"
17 #include "clang/Index/IndexingOptions.h"
18 #include "clang/Tooling/Tooling.h"
19 #include "llvm/ADT/IntrusiveRefCntPtr.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/MemoryBuffer.h"
23 #include "llvm/Support/VirtualFileSystem.h"
24 #include "gmock/gmock-matchers.h"
25 #include "gmock/gmock-more-matchers.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
37 using ::testing::AllOf;
38 using ::testing::Contains;
39 using ::testing::Each;
40 using ::testing::ElementsAre;
41 using ::testing::Field;
42 using ::testing::IsEmpty;
44 using ::testing::Pair;
45 using ::testing::UnorderedElementsAre;
46 using ::testing::UnorderedElementsAreArray;
50 return (arg.Name + arg.Signature).str() == Label;
53 MATCHER_P(Doc, D,
"") {
return arg.Documentation == D; }
55 return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
59 return arg.TemplateSpecializationArgs == TemplArgs;
62 return StringRef(arg.CanonicalDeclaration.FileURI) == P;
64 MATCHER_P(DefURI, P,
"") {
return StringRef(arg.Definition.FileURI) == P; }
65 MATCHER(IncludeHeader,
"") {
return !arg.IncludeHeaders.empty(); }
67 return (arg.IncludeHeaders.size() == 1) &&
68 (arg.IncludeHeaders.begin()->IncludeHeader == P);
70 MATCHER_P2(IncludeHeaderWithRef, IncludeHeader,
References,
"") {
71 return (arg.IncludeHeader == IncludeHeader) && (arg.References ==
References);
74 return std::make_tuple(arg.CanonicalDeclaration.Start.line(),
75 arg.CanonicalDeclaration.Start.column(),
76 arg.CanonicalDeclaration.End.line(),
77 arg.CanonicalDeclaration.End.column()) ==
82 return std::make_tuple(
83 arg.Definition.Start.line(), arg.Definition.Start.column(),
84 arg.Definition.End.line(), arg.Definition.End.column()) ==
88 MATCHER_P(RefCount, R,
"") {
return int(arg.References) == R; }
89 MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion,
"") {
91 IsIndexedForCodeCompletion;
94 MATCHER(ImplementationDetail,
"") {
97 MATCHER(VisibleOutsideFile,
"") {
101 const Ref &
Pos = ::testing::get<0>(arg);
103 return std::make_tuple(
Pos.Location.Start.
line(),
Pos.Location.Start.column(),
104 Pos.Location.End.
line(),
Pos.Location.End.column()) ==
105 std::make_tuple(
Range.start.line,
Range.start.character,
108 ::testing::Matcher<const std::vector<Ref> &>
109 HaveRanges(
const std::vector<Range> Ranges) {
110 return ::testing::UnorderedPointwise(RefRange(), Ranges);
113 class ShouldCollectSymbolTest :
public ::testing::Test {
115 void build(llvm::StringRef HeaderCode, llvm::StringRef
Code =
"") {
118 File.HeaderCode = std::string(HeaderCode);
124 bool shouldCollect(llvm::StringRef
Name,
bool Qualified =
true) {
125 assert(
AST.hasValue());
126 const NamedDecl &ND =
128 const SourceManager &SM =
AST->getSourceManager();
131 ND,
AST->getASTContext(), SymbolCollector::Options(),
MainFile);
138 llvm::Optional<ParsedAST>
AST;
141 TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
145 auto f() { int Local; } // auto ensures function body is parsed.
146 struct { int x; } var;
151 namespace { class InAnonymous {}; }
154 auto AST = File.build();
155 EXPECT_TRUE(shouldCollect(
"nx"));
156 EXPECT_TRUE(shouldCollect(
"nx::X"));
157 EXPECT_TRUE(shouldCollect(
"nx::f"));
158 EXPECT_TRUE(shouldCollect(
"InMain"));
159 EXPECT_TRUE(shouldCollect(
"InAnonymous",
false));
160 EXPECT_TRUE(shouldCollect(
"g"));
162 EXPECT_FALSE(shouldCollect(
"Local",
false));
165 TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
168 R
"(// Generated by the protocol buffer compiler. DO NOT EDIT!
177 EXPECT_TRUE(shouldCollect("nx::TopLevel"));
178 EXPECT_TRUE(shouldCollect(
"nx::Kind::KIND_OK"));
179 EXPECT_TRUE(shouldCollect(
"nx::Kind"));
181 EXPECT_FALSE(shouldCollect(
"nx::Top_Level"));
182 EXPECT_FALSE(shouldCollect(
"nx::Kind::Kind_Not_Ok"));
185 TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
195 EXPECT_TRUE(shouldCollect("nx::Top_Level"));
196 EXPECT_TRUE(shouldCollect(
"nx::Kind_Fine"));
199 class SymbolIndexActionFactory :
public tooling::FrontendActionFactory {
201 SymbolIndexActionFactory(SymbolCollector::Options
COpts,
205 std::unique_ptr<FrontendAction> create()
override {
206 class IndexAction :
public ASTFrontendAction {
208 IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
209 const index::IndexingOptions &Opts,
211 : DataConsumer(std::move(DataConsumer)), Opts(Opts),
214 std::unique_ptr<ASTConsumer>
215 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
218 return createIndexingASTConsumer(DataConsumer, Opts,
219 CI.getPreprocessorPtr());
222 bool BeginInvocation(CompilerInstance &
CI)
override {
224 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
229 std::shared_ptr<index::IndexDataConsumer> DataConsumer;
230 index::IndexingOptions Opts;
233 index::IndexingOptions IndexOpts;
234 IndexOpts.SystemSymbolFilter =
235 index::IndexingOptions::SystemSymbolFilterKind::All;
236 IndexOpts.IndexFunctionLocals =
false;
238 return std::make_unique<IndexAction>(
Collector, std::move(IndexOpts),
247 class SymbolCollectorTest :
public ::testing::Test {
249 SymbolCollectorTest()
259 bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
260 const std::vector<std::string> &ExtraArgs = {}) {
261 llvm::IntrusiveRefCntPtr<FileManager> Files(
264 auto Factory = std::make_unique<SymbolIndexActionFactory>(
267 std::vector<std::string> Args = {
"symbol_collector",
"-fsyntax-only",
269 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
274 tooling::ToolInvocation Invocation(
275 Args, Factory->create(), Files.get(),
276 std::make_shared<PCHContainerOperations>());
279 llvm::MemoryBuffer::getMemBuffer(HeaderCode));
281 llvm::MemoryBuffer::getMemBuffer(MainCode));
283 Symbols = Factory->Collector->takeSymbols();
284 Refs = Factory->Collector->takeRefs();
285 Relations = Factory->Collector->takeRelations();
302 TEST_F(SymbolCollectorTest, CollectSymbols) {
303 const std::string Header = R
"(
310 Foo& operator=(const Foo&);
321 static const int KInt = 2;
322 const char* kStr = "123";
325 void ff() {} // ignore
333 using int32_t = int32;
348 runSymbolCollector(Header, "");
350 UnorderedElementsAreArray(
351 {AllOf(QName(
"Foo"), ForCodeCompletion(
true)),
352 AllOf(QName(
"Foo::Foo"), ForCodeCompletion(
false)),
353 AllOf(QName(
"Foo::Foo"), ForCodeCompletion(
false)),
354 AllOf(QName(
"Foo::f"), ForCodeCompletion(
false)),
355 AllOf(QName(
"Foo::~Foo"), ForCodeCompletion(
false)),
356 AllOf(QName(
"Foo::operator="), ForCodeCompletion(
false)),
357 AllOf(QName(
"Foo::Nested"), ForCodeCompletion(
false)),
358 AllOf(QName(
"Foo::Nested::f"), ForCodeCompletion(
false)),
360 AllOf(QName(
"Friend"), ForCodeCompletion(
true)),
361 AllOf(QName(
"f1"), ForCodeCompletion(
true)),
362 AllOf(QName(
"f2"), ForCodeCompletion(
true)),
363 AllOf(QName(
"KInt"), ForCodeCompletion(
true)),
364 AllOf(QName(
"kStr"), ForCodeCompletion(
true)),
365 AllOf(QName(
"foo"), ForCodeCompletion(
true)),
366 AllOf(QName(
"foo::bar"), ForCodeCompletion(
true)),
367 AllOf(QName(
"foo::int32"), ForCodeCompletion(
true)),
368 AllOf(QName(
"foo::int32_t"), ForCodeCompletion(
true)),
369 AllOf(QName(
"foo::v1"), ForCodeCompletion(
true)),
370 AllOf(QName(
"foo::bar::v2"), ForCodeCompletion(
true)),
371 AllOf(QName(
"foo::v2"), ForCodeCompletion(
true)),
372 AllOf(QName(
"foo::baz"), ForCodeCompletion(
true))}));
375 TEST_F(SymbolCollectorTest, FileLocal) {
376 const std::string Header = R
"(
383 const std::string Main = R
"(
392 runSymbolCollector(Header, Main);
394 UnorderedElementsAre(
395 AllOf(QName("Foo"), VisibleOutsideFile()),
396 AllOf(QName(
"bar"), VisibleOutsideFile()),
397 AllOf(QName(
"a"), Not(VisibleOutsideFile())),
398 AllOf(QName(
"B"), Not(VisibleOutsideFile())),
399 AllOf(QName(
"c"), Not(VisibleOutsideFile())),
401 AllOf(QName(
"ForwardDecl"), Not(VisibleOutsideFile()))));
404 TEST_F(SymbolCollectorTest, Template) {
405 Annotations Header(R
"(
406 // Primary template and explicit specialization are indexed, instantiation
408 template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
409 template <> struct $specdecl[[Tmpl]]<int, bool> {};
410 template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {};
411 extern template struct Tmpl<float, bool>;
412 template struct Tmpl<double, bool>;
414 runSymbolCollector(Header.code(), "");
416 UnorderedElementsAre(
417 AllOf(QName(
"Tmpl"), DeclRange(Header.range()),
418 ForCodeCompletion(
true)),
419 AllOf(QName(
"Tmpl"), DeclRange(Header.range(
"specdecl")),
420 ForCodeCompletion(
false)),
421 AllOf(QName(
"Tmpl"), DeclRange(Header.range(
"partspecdecl")),
422 ForCodeCompletion(
false)),
423 AllOf(QName(
"Tmpl::x"), DeclRange(Header.range(
"xdecl")),
424 ForCodeCompletion(
false))));
427 TEST_F(SymbolCollectorTest, TemplateArgs) {
428 Annotations Header(R
"(
429 template <class X> class $barclasstemp[[Bar]] {};
430 template <class T, class U, template<typename> class Z, int Q>
431 struct [[Tmpl]] { T $xdecl[[x]] = 0; };
433 // template-template, non-type and type full spec
434 template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
436 // template-template, non-type and type partial spec
437 template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
439 extern template struct Tmpl<float, bool, Bar, 8>;
441 template struct Tmpl<double, bool, Bar, 2>;
443 template <typename ...> class $fooclasstemp[[Foo]] {};
444 // parameter-packs full spec
445 template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
446 // parameter-packs partial spec
447 template<class T> class $parampackpartial[[Foo]]<T, T> {};
449 template <int ...> class $bazclasstemp[[Baz]] {};
450 // non-type parameter-packs full spec
451 template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
452 // non-type parameter-packs partial spec
453 template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
455 template <template <class> class ...> class $fozclasstemp[[Foz]] {};
456 // template-template parameter-packs full spec
457 template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
458 // template-template parameter-packs partial spec
459 template<template <class> class T>
460 class $parampacktempltemplpartial[[Foz]]<T, T> {};
462 runSymbolCollector(Header.code(), "");
466 Contains(AllOf(QName(
"Tmpl"), TemplateArgs(
"<int, bool, Bar, 3>"),
467 DeclRange(Header.range(
"specdecl")),
468 ForCodeCompletion(
false))),
469 Contains(AllOf(QName(
"Tmpl"), TemplateArgs(
"<bool, U, Bar, T>"),
470 DeclRange(Header.range(
"partspecdecl")),
471 ForCodeCompletion(
false))),
472 Contains(AllOf(QName(
"Foo"), TemplateArgs(
"<Bar<int>, int, double>"),
473 DeclRange(Header.range(
"parampack")),
474 ForCodeCompletion(
false))),
475 Contains(AllOf(QName(
"Foo"), TemplateArgs(
"<T, T>"),
476 DeclRange(Header.range(
"parampackpartial")),
477 ForCodeCompletion(
false))),
478 Contains(AllOf(QName(
"Baz"), TemplateArgs(
"<3, 5, 8>"),
479 DeclRange(Header.range(
"parampacknontype")),
480 ForCodeCompletion(
false))),
481 Contains(AllOf(QName(
"Baz"), TemplateArgs(
"<T, T>"),
482 DeclRange(Header.range(
"parampacknontypepartial")),
483 ForCodeCompletion(
false))),
484 Contains(AllOf(QName(
"Foz"), TemplateArgs(
"<Bar, Bar>"),
485 DeclRange(Header.range(
"parampacktempltempl")),
486 ForCodeCompletion(
false))),
487 Contains(AllOf(QName(
"Foz"), TemplateArgs(
"<T, T>"),
488 DeclRange(Header.range(
"parampacktempltemplpartial")),
489 ForCodeCompletion(
false)))));
492 TEST_F(SymbolCollectorTest, ObjCSymbols) {
493 const std::string Header = R
"(
495 - (void)someMethodName:(void*)name1 lastName:(void*)lName;
498 @implementation Person
499 - (void)someMethodName:(void*)name1 lastName:(void*)lName{
501 ^(int param){ int bar; };
505 @interface Person (MyCategory)
506 - (void)someMethodName2:(void*)name2;
509 @implementation Person (MyCategory)
510 - (void)someMethodName2:(void*)name2 {
516 - (void)someMethodName3:(void*)name3;
520 runSymbolCollector(Header,
"", {
"-fblocks",
"-xobjective-c++"});
522 UnorderedElementsAre(
523 QName(
"Person"), QName(
"Person::someMethodName:lastName:"),
524 QName(
"MyCategory"), QName(
"Person::someMethodName2:"),
525 QName(
"MyProtocol"), QName(
"MyProtocol::someMethodName3:")));
528 TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
529 const std::string Header = R
"(
531 @property(nonatomic) int magic;
534 @implementation Container
538 runSymbolCollector(Header,
"", {
"-xobjective-c++"});
539 EXPECT_THAT(
Symbols, Contains(QName(
"Container")));
540 EXPECT_THAT(
Symbols, Contains(QName(
"Container::magic")));
545 TEST_F(SymbolCollectorTest, Locations) {
546 Annotations Header(R
"cpp(
547 // Declared in header, defined in main.
548 extern int $xdecl[[X]];
549 class $clsdecl[[Cls]];
550 void $printdecl[[print]]();
552 // Declared in header, defined nowhere.
553 extern int $zdecl[[Z]];
558 Annotations Main(R"cpp(
560 class $clsdef[[Cls]] {};
561 void $printdef[[print]]() {}
563 // Declared/defined in main only.
566 runSymbolCollector(Header.code(), Main.code());
568 UnorderedElementsAre(
569 AllOf(QName("X"), DeclRange(Header.range(
"xdecl")),
570 DefRange(Main.range(
"xdef"))),
571 AllOf(QName(
"Cls"), DeclRange(Header.range(
"clsdecl")),
572 DefRange(Main.range(
"clsdef"))),
573 AllOf(QName(
"print"), DeclRange(Header.range(
"printdecl")),
574 DefRange(Main.range(
"printdef"))),
575 AllOf(QName(
"Z"), DeclRange(Header.range(
"zdecl"))),
576 AllOf(QName(
"foo"), DeclRange(Header.range(
"foodecl"))),
577 AllOf(QName(
"Y"), DeclRange(Main.range(
"ydecl")))));
581 Annotations Header(R
"(
582 #define MACRO(X) (X + 1)
591 namespace NS {} // namespace ref is ignored
594 class $bar[[Bar]] {};
596 void $func[[func]]();
603 $foo[[Foo]] foo2 = abc;
604 abc = $macro[[MACRO]](1);
607 Annotations SymbolsOnlyInMainCode(R"(
608 #define FUNC(X) (X+1)
611 static const int c = FUNC(1);
616 runSymbolCollector(Header.code(),
617 (Main.code() + SymbolsOnlyInMainCode.code()).str());
619 HaveRanges(Main.ranges(
"foo")))));
621 HaveRanges(Main.ranges(
"bar")))));
623 HaveRanges(Main.ranges(
"func")))));
626 HaveRanges(Main.ranges(
"macro")))));
630 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"a").ID, _))));
631 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"b").ID, _))));
632 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"c").ID, _))));
633 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"FUNC").ID, _))));
636 TEST_F(SymbolCollectorTest, MacroRefInHeader) {
637 Annotations Header(R
"(
638 #define $foo[[FOO]](X) (X + 1)
639 #define $bar[[BAR]](X) (X + 2)
641 // Macro defined multiple times.
643 int ud_1 = $ud1[[UD]];
647 int ud_2 = $ud2[[UD]];
650 // Macros from token concatenations not included.
651 #define $concat[[CONCAT]](X) X##A()
652 #define $prepend[[PREPEND]](X) MACRO##X()
653 #define $macroa[[MACROA]]() 123
654 int B = $concat[[CONCAT]](MACRO);
655 int D = $prepend[[PREPEND]](A);
658 int abc = $foo[[FOO]](1) + $bar[[BAR]]($foo[[FOO]](1));
666 runSymbolCollector(Header.code(),
"");
669 HaveRanges(Header.ranges(
"foo")))));
671 HaveRanges(Header.ranges(
"bar")))));
673 EXPECT_THAT(
Refs, Contains(Pair(_, HaveRanges(Header.ranges(
"ud1")))));
674 EXPECT_THAT(
Refs, Contains(Pair(_, HaveRanges(Header.ranges(
"ud2")))));
676 HaveRanges(Header.ranges(
"concat")))));
678 HaveRanges(Header.ranges(
"prepend")))));
680 HaveRanges(Header.ranges(
"macroa")))));
683 TEST_F(SymbolCollectorTest, MacroRefWithoutCollectingSymbol) {
684 Annotations Header(R
"(
685 #define $foo[[FOO]](X) (X + 1)
686 int abc = $foo[[FOO]](1);
691 runSymbolCollector(Header.code(),
"");
692 EXPECT_THAT(
Refs, Contains(Pair(_, HaveRanges(Header.ranges(
"foo")))));
695 TEST_F(SymbolCollectorTest, MacrosWithRefFilter) {
696 Annotations Header(
"#define $macro[[MACRO]](X) (X + 1)");
697 Annotations Main(
"void foo() { int x = $macro[[MACRO]](1); }");
699 runSymbolCollector(Header.code(), Main.code());
700 EXPECT_THAT(
Refs, IsEmpty());
703 TEST_F(SymbolCollectorTest, SpelledReferences) {
705 llvm::StringRef Header;
706 llvm::StringRef Main;
707 llvm::StringRef TargetSymbolName;
715 struct $spelled[[Foo]] {
719 $spelled[[Foo]] Variable1;
720 $implicit[[MACRO]] Variable2;
732 void f() { Foo $implicit[[f]]; f = $spelled[[Foo]]();}
739 for (
const auto& T : TestCases) {
740 Annotations Header(T.Header);
741 Annotations Main(T.Main);
744 runSymbolCollector(Header.code(), Main.code());
746 const auto SpelledRanges = Main.ranges(
"spelled");
747 const auto ImplicitRanges = Main.ranges(
"implicit");
750 for (
const auto &SymbolAndRefs :
Refs) {
751 const auto ID = SymbolAndRefs.first;
754 for (
const auto &Ref : SymbolAndRefs.second)
756 SpelledSlabBuilder.insert(ID, Ref);
758 ImplicitSlabBuilder.insert(ID, Ref);
760 const auto SpelledRefs = std::move(SpelledSlabBuilder).build(),
761 ImplicitRefs = std::move(ImplicitSlabBuilder).build();
762 EXPECT_THAT(SpelledRefs,
763 Contains(Pair(TargetID, HaveRanges(SpelledRanges))));
764 EXPECT_THAT(ImplicitRefs,
765 Contains(Pair(TargetID, HaveRanges(ImplicitRanges))));
769 TEST_F(SymbolCollectorTest, NameReferences) {
772 Annotations Header(R
"(
780 runSymbolCollector(Header.code(), "");
784 HaveRanges(Header.ranges()))));
787 TEST_F(SymbolCollectorTest, RefsOnMacros) {
792 Annotations Header(R
"(
795 #define CAT(X, Y) X##Y
800 TYPE(TYPE([[Foo]])) foo3;
805 runSymbolCollector(Header.code(), "");
807 HaveRanges(Header.ranges()))));
810 TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
812 Annotations Header(R
"(
813 class $Foo[[Foo]] {};
815 void $Func[[Func]]() {
822 runSymbolCollector(
"", Header.code());
823 EXPECT_THAT(
Refs, UnorderedElementsAre());
827 runSymbolCollector(
"", Header.code(),
828 {
"-xobjective-c++-header"});
829 EXPECT_THAT(
Symbols, UnorderedElementsAre(QName(
"Foo"), QName(
"Func")));
832 HaveRanges(Header.ranges(
"Foo"))),
834 HaveRanges(Header.ranges(
"Func")))));
839 runSymbolCollector(
"", Header.code());
840 EXPECT_THAT(
Symbols, UnorderedElementsAre(QName(
"Foo"), QName(
"Func")));
843 HaveRanges(Header.ranges(
"Foo"))),
845 HaveRanges(Header.ranges(
"Func")))));
848 TEST_F(SymbolCollectorTest, RefsInHeaders) {
852 Annotations Header(R
"(
853 #define $macro[[MACRO]](x) (x+1)
854 class $foo[[Foo]] {};
856 runSymbolCollector(Header.code(), "");
858 HaveRanges(Header.ranges(
"foo")))));
860 HaveRanges(Header.ranges(
"macro")))));
864 std::string Header = R
"(
866 class Derived : public Base {};
868 runSymbolCollector(Header, "");
875 TEST_F(SymbolCollectorTest, CountReferences) {
876 const std::string Header = R
"(
880 class Z {}; // not used anywhere
881 Y* y = nullptr; // used in header doesn't count
882 #define GLOBAL_Z(name) Z name;
884 const std::string Main = R
"(
886 W* w2 = nullptr; // only one usage counts
889 class Y{}; // definition doesn't count as a reference
891 GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
894 runSymbolCollector(Header, Main);
897 UnorderedElementsAreArray(
898 {AllOf(QName(
"W"), RefCount(1)), AllOf(QName(
"X"), RefCount(1)),
899 AllOf(QName(
"Y"), RefCount(0)), AllOf(QName(
"Z"), RefCount(0)),
900 AllOf(QName(
"y"), RefCount(0)), AllOf(QName(
"z"), RefCount(0)),
901 AllOf(QName(
"x"), RefCount(0)), AllOf(QName(
"w"), RefCount(0)),
902 AllOf(QName(
"w2"), RefCount(0)), AllOf(QName(
"V"), RefCount(1)),
903 AllOf(QName(
"v"), RefCount(0))}));
906 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
907 runSymbolCollector(
"class Foo {};",
"");
908 EXPECT_THAT(
Symbols, UnorderedElementsAre(
912 TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
917 runSymbolCollector(
"class Foo {};",
"");
918 EXPECT_THAT(
Symbols, UnorderedElementsAre(
922 TEST_F(SymbolCollectorTest, UnittestURIScheme) {
926 runSymbolCollector(
"class Foo {};",
"");
927 EXPECT_THAT(
Symbols, UnorderedElementsAre(
928 AllOf(QName(
"Foo"), DeclURI(
"unittest:///x.h"))));
931 TEST_F(SymbolCollectorTest, IncludeEnums) {
932 const std::string Header = R
"(
948 runSymbolCollector(Header, "");
950 UnorderedElementsAre(
951 AllOf(QName(
"Red"), ForCodeCompletion(
true)),
952 AllOf(QName(
"Color"), ForCodeCompletion(
true)),
953 AllOf(QName(
"Green"), ForCodeCompletion(
true)),
954 AllOf(QName(
"Color2"), ForCodeCompletion(
true)),
955 AllOf(QName(
"Color2::Yellow"), ForCodeCompletion(
false)),
956 AllOf(QName(
"ns"), ForCodeCompletion(
true)),
957 AllOf(QName(
"ns::Black"), ForCodeCompletion(
true))));
960 TEST_F(SymbolCollectorTest, NamelessSymbols) {
961 const std::string Header = R
"(
966 runSymbolCollector(Header, "");
967 EXPECT_THAT(
Symbols, UnorderedElementsAre(QName(
"Foo"),
968 QName(
"(anonymous struct)::a")));
971 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
973 Annotations Header(R
"(
975 class name##_Test {};
977 $expansion[[FF]](abc);
980 class $spelling[[Test]] {};
985 runSymbolCollector(Header.code(), "");
987 UnorderedElementsAre(
988 AllOf(QName(
"abc_Test"), DeclRange(Header.range(
"expansion")),
990 AllOf(QName(
"Test"), DeclRange(Header.range(
"spelling")),
994 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
995 Annotations Header(R
"(
997 class $expansion[[NAME]] {};
1000 runSymbolCollector(Header.code(), "", {
"-DNAME=name"});
1001 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1002 QName(
"name"), DeclRange(Header.range(
"expansion")),
1006 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
1007 const std::string Main = R
"(
1023 runSymbolCollector("", Main);
1024 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1025 QName(
"Foo"), QName(
"f1"), QName(
"f2"), QName(
"ff"),
1026 QName(
"foo"), QName(
"foo::Bar"), QName(
"main_f")));
1029 TEST_F(SymbolCollectorTest, Documentation) {
1030 const std::string Header = R
"(
1038 runSymbolCollector(Header,
"");
1040 UnorderedElementsAre(
1041 AllOf(QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
1042 AllOf(QName(
"Foo::f"), Doc(
""),
ReturnType(
""),
1043 ForCodeCompletion(
false))));
1046 runSymbolCollector(Header,
"");
1048 UnorderedElementsAre(
1049 AllOf(QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
1050 AllOf(QName(
"Foo::f"), Doc(
"Doc f"),
ReturnType(
""),
1051 ForCodeCompletion(
false))));
1054 TEST_F(SymbolCollectorTest, ClassMembers) {
1055 const std::string Header = R
"(
1064 const std::string Main = R
"(
1068 runSymbolCollector(Header, Main);
1071 UnorderedElementsAre(
1073 AllOf(QName(
"Foo::f"),
ReturnType(
""), ForCodeCompletion(
false)),
1074 AllOf(QName(
"Foo::g"),
ReturnType(
""), ForCodeCompletion(
false)),
1075 AllOf(QName(
"Foo::sf"),
ReturnType(
""), ForCodeCompletion(
false)),
1076 AllOf(QName(
"Foo::ssf"),
ReturnType(
""), ForCodeCompletion(
false)),
1077 AllOf(QName(
"Foo::x"),
ReturnType(
""), ForCodeCompletion(
false))));
1080 TEST_F(SymbolCollectorTest, Scopes) {
1081 const std::string Header = R
"(
1089 runSymbolCollector(Header, "");
1091 UnorderedElementsAre(QName(
"na"), QName(
"na::nb"),
1092 QName(
"na::Foo"), QName(
"na::nb::Bar")));
1095 TEST_F(SymbolCollectorTest, ExternC) {
1096 const std::string Header = R
"(
1097 extern "C" { class Foo {}; }
1099 extern "C" { class Bar {}; }
1102 runSymbolCollector(Header, "");
1103 EXPECT_THAT(
Symbols, UnorderedElementsAre(QName(
"na"), QName(
"Foo"),
1107 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1108 const std::string Header = R
"(
1110 inline namespace nb {
1115 // This is still inlined.
1121 runSymbolCollector(Header, "");
1123 UnorderedElementsAre(QName(
"na"), QName(
"na::nb"),
1124 QName(
"na::Foo"), QName(
"na::Bar")));
1127 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1128 const std::string Header = R
"(
1131 int ff(int x, double y) { return 0; }
1134 runSymbolCollector(Header,
"");
1137 UnorderedElementsAre(
1138 QName(
"nx"), AllOf(QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
1142 TEST_F(SymbolCollectorTest, Snippet) {
1143 const std::string Header = R
"(
1146 int ff(int x, double y) { return 0; }
1149 runSymbolCollector(Header, "");
1151 UnorderedElementsAre(
1153 AllOf(QName(
"nx::f"), Labeled(
"f()"),
Snippet(
"f()")),
1154 AllOf(QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
1155 Snippet(
"ff(${1:int x}, ${2:double y})"))));
1158 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1160 runSymbolCollector(
"#pragma once\nclass Foo {};",
"");
1161 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1164 UnorderedElementsAre(IncludeHeaderWithRef(
TestHeaderURI, 1u)));
1167 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1169 CanonicalIncludes Includes;
1170 auto Language = LangOptions();
1171 Language.CPlusPlus =
true;
1172 Includes.addSystemHeadersMapping(Language);
1174 runSymbolCollector(
"namespace std { class string {}; }",
"");
1176 Contains(AllOf(QName(
"std::string"), DeclURI(
TestHeaderURI),
1177 IncludeHeader(
"<string>"))));
1180 TEST_F(SymbolCollectorTest, IWYUPragma) {
1182 CanonicalIncludes Includes;
1185 const std::string Header = R
"(
1186 // IWYU pragma: private, include the/good/header.h
1189 runSymbolCollector(Header, "");
1190 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1192 IncludeHeader(
"\"the/good/header.h\""))));
1195 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1197 CanonicalIncludes Includes;
1200 const std::string Header = R
"(
1201 // IWYU pragma: private, include "the/good/header.h"
1204 runSymbolCollector(Header, "");
1205 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1207 IncludeHeader(
"\"the/good/header.h\""))));
1210 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1212 CanonicalIncludes Includes;
1215 auto IncFile =
testPath(
"test.inc");
1218 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1219 runSymbolCollector(
"#include \"test.inc\"\nclass Y {};",
"",
1222 UnorderedElementsAre(AllOf(QName(
"X"), DeclURI(IncURI),
1223 IncludeHeader(
"<canonical>")),
1225 IncludeHeader(
"<canonical>"))));
1228 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1234 auto IncFile =
testPath(
"test.inc");
1237 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1238 runSymbolCollector(
"", R
"cpp(
1239 // Can't use #pragma once in a main file clang doesn't think is a header.
1246 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(QName(
"X"), DeclURI(IncURI),
1250 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1254 auto IncFile =
testPath(
"test.inc");
1257 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1258 runSymbolCollector(
"", R
"cpp(
1262 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(QName(
"X"), DeclURI(IncURI),
1263 Not(IncludeHeader()))));
1268 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1271 runSymbolCollector(R
"cpp(
1272 #ifndef HEADER_GUARD_
1273 #define HEADER_GUARD_
1275 // Symbols are seen before the header guard is complete.
1279 #endif // Header guard is recognized here.
1282 EXPECT_THAT(
Symbols, Not(Contains(QName(
"HEADER_GUARD_"))));
1283 EXPECT_THAT(
Symbols, Each(IncludeHeader()));
1286 TEST_F(SymbolCollectorTest, NonModularHeader) {
1288 EXPECT_THAT(TU.headerSymbols(), ElementsAre(IncludeHeader()));
1291 TU.ImplicitHeaderGuard =
false;
1292 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1297 #error "This file isn't safe to include directly"
1301 TU.ExtraArgs.push_back("-DSECRET");
1302 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(IncludeHeader())));
1305 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1307 Annotations Header(R
"(
1309 // Forward declarations of TagDecls.
1314 // Canonical declarations.
1315 class $cdecl[[C]] {};
1316 struct $sdecl[[S]] {};
1317 union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1319 runSymbolCollector(Header.code(), "");
1322 UnorderedElementsAre(
1324 DeclRange(Header.range(
"cdecl")), IncludeHeader(
TestHeaderURI),
1327 DeclRange(Header.range(
"sdecl")), IncludeHeader(
TestHeaderURI),
1330 DeclRange(Header.range(
"udecl")), IncludeHeader(
TestHeaderURI),
1334 DefRange(Header.range(
"xdecl"))),
1337 DefRange(Header.range(
"ydecl")))));
1340 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1342 runSymbolCollector(
"#pragma once\nclass X;",
1344 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1349 TEST_F(SymbolCollectorTest, UTF16Character) {
1351 Annotations Header(
"class [[pörk]] {};");
1352 runSymbolCollector(Header.code(),
"");
1353 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1354 AllOf(QName(
"pörk"), DeclRange(Header.range()))));
1357 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1358 Annotations Header(R
"(
1365 friend void $bar[[bar]]() {}
1371 runSymbolCollector(Header.code(), "");
1374 UnorderedElementsAre(
1375 QName(
"nx"), QName(
"nx::X"),
1376 AllOf(QName(
"nx::Y"), DeclRange(Header.range(
"y"))),
1377 AllOf(QName(
"nx::Z"), DeclRange(Header.range(
"z"))),
1378 AllOf(QName(
"nx::foo"), DeclRange(Header.range(
"foo"))),
1379 AllOf(QName(
"nx::bar"), DeclRange(Header.range(
"bar")))));
1382 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1383 const std::string Header = R
"(
1387 const std::string Main = R
"(
1394 runSymbolCollector(Header, Main);
1395 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(QName(
"X"), RefCount(1)),
1396 AllOf(QName(
"Y"), RefCount(1)),
1397 AllOf(QName(
"C"), RefCount(0))));
1400 TEST_F(SymbolCollectorTest, Origin) {
1402 runSymbolCollector(
"class Foo {};",
"");
1403 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1407 TEST_F(SymbolCollectorTest, CollectMacros) {
1409 Annotations Header(R
"(
1412 #define $mac[[MAC]](x) int x
1413 #define $used[[USED]](y) float y;
1418 Annotations Main(R"(
1419 #define $main[[MAIN]] 1
1424 runSymbolCollector(Header.code(), Main.code());
1427 UnorderedElementsAre(
1428 QName(
"p"), QName(
"t"),
1431 AllOf(Labeled(
"MAC(x)"), RefCount(0),
1433 DeclRange(Header.range(
"mac")), VisibleOutsideFile()),
1434 AllOf(Labeled(
"USED(y)"), RefCount(1),
1435 DeclRange(Header.range(
"used")), VisibleOutsideFile()),
1436 AllOf(Labeled(
"MAIN"), RefCount(0), DeclRange(Main.range(
"main")),
1437 Not(VisibleOutsideFile()))));
1440 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1441 const std::string Header = R
"(
1442 void TestClangc() __attribute__((deprecated("", "")));
1445 runSymbolCollector(Header, "");
1446 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1447 AllOf(QName(
"TestClangc"), Deprecated()),
1448 AllOf(QName(
"TestClangd"), Not(Deprecated()))));
1451 TEST_F(SymbolCollectorTest, ImplementationDetail) {
1452 const std::string Header = R
"(
1453 #define DECL_NAME(x, y) x##_##y##_Decl
1454 #define DECL(x, y) class DECL_NAME(x, y) {};
1455 DECL(X, Y); // X_Y_Decl
1459 runSymbolCollector(Header, "");
1461 UnorderedElementsAre(
1462 AllOf(QName(
"X_Y_Decl"), ImplementationDetail()),
1463 AllOf(QName(
"Public"), Not(ImplementationDetail()))));
1466 TEST_F(SymbolCollectorTest, UsingDecl) {
1467 const char *Header = R
"(
1472 runSymbolCollector(Header, "");
1473 EXPECT_THAT(
Symbols, Contains(QName(
"std::foo")));
1476 TEST_F(SymbolCollectorTest, CBuiltins) {
1478 const char *Header = R
"(
1479 extern int printf(const char*, ...);
1481 runSymbolCollector(Header, "", {
"-xc"});
1482 EXPECT_THAT(
Symbols, Contains(QName(
"printf")));
1485 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1486 const char *Header = R
"(
1487 void operator delete(void*)
1488 __attribute__((__externally_visible__));)";
1489 runSymbolCollector(Header, "");
1490 EXPECT_THAT(
Symbols, Contains(QName(
"operator delete")));
1493 TEST_F(SymbolCollectorTest, BadUTF8) {
1496 const char *Header =
"int PUNCT = 0;\n"
1497 "int types[] = { /* \xa1 */PUNCT };";
1500 runSymbolCollector(Header,
"");
1501 EXPECT_THAT(
Symbols, Contains(QName(
"types")));
1502 EXPECT_THAT(
Symbols, Contains(QName(
"PUNCT")));