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; }
67 return (arg.IncludeHeaders.size() == 1) &&
68 (arg.IncludeHeaders.begin()->IncludeHeader == P);
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,
106 Range.end.line, Range.end.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 = 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 {}; } 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,
210 CommentHandler *PragmaHandler)
211 : DataConsumer(std::move(DataConsumer)), Opts(Opts),
214 std::unique_ptr<ASTConsumer>
215 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile)
override {
217 CI.getPreprocessor().addCommentHandler(PragmaHandler);
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++"});
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, NameReferences) {
706 Annotations Header(R
"( 714 runSymbolCollector(Header.code(), "");
718 HaveRanges(Header.ranges()))));
721 TEST_F(SymbolCollectorTest, RefsOnMacros) {
726 Annotations Header(R
"( 729 #define CAT(X, Y) X##Y 734 TYPE(TYPE([[Foo]])) foo3; 739 runSymbolCollector(Header.code(), "");
741 HaveRanges(Header.ranges()))));
744 TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
746 Annotations Header(R
"( 747 class $Foo[[Foo]] {}; 749 void $Func[[Func]]() { 756 runSymbolCollector(
"", Header.code());
757 EXPECT_THAT(
Refs, UnorderedElementsAre());
761 runSymbolCollector(
"", Header.code(),
762 {
"-xobjective-c++-header"});
766 HaveRanges(Header.ranges(
"Foo"))),
768 HaveRanges(Header.ranges(
"Func")))));
773 runSymbolCollector(
"", Header.code());
777 HaveRanges(Header.ranges(
"Foo"))),
779 HaveRanges(Header.ranges(
"Func")))));
782 TEST_F(SymbolCollectorTest, RefsInHeaders) {
786 Annotations Header(R
"( 787 #define $macro[[MACRO]](x) (x+1) 788 class $foo[[Foo]] {}; 790 runSymbolCollector(Header.code(), "");
792 HaveRanges(Header.ranges(
"foo")))));
794 HaveRanges(Header.ranges(
"macro")))));
798 std::string Header = R
"( 800 class Derived : public Base {}; 802 runSymbolCollector(Header, "");
809 TEST_F(SymbolCollectorTest, CountReferences) {
810 const std::string Header = R
"( 814 class Z {}; // not used anywhere 815 Y* y = nullptr; // used in header doesn't count 816 #define GLOBAL_Z(name) Z name; 818 const std::string Main = R
"( 820 W* w2 = nullptr; // only one usage counts 823 class Y{}; // definition doesn't count as a reference 825 GLOBAL_Z(z); // Not a reference to Z, we don't spell the type. 828 runSymbolCollector(Header, Main);
831 UnorderedElementsAreArray(
832 {AllOf(
QName(
"W"), RefCount(1)), AllOf(
QName(
"X"), RefCount(1)),
833 AllOf(
QName(
"Y"), RefCount(0)), AllOf(
QName(
"Z"), RefCount(0)),
834 AllOf(
QName(
"y"), RefCount(0)), AllOf(
QName(
"z"), RefCount(0)),
835 AllOf(
QName(
"x"), RefCount(0)), AllOf(
QName(
"w"), RefCount(0)),
836 AllOf(
QName(
"w2"), RefCount(0)), AllOf(
QName(
"V"), RefCount(1)),
837 AllOf(
QName(
"v"), RefCount(0))}));
840 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
841 runSymbolCollector(
"class Foo {};",
"");
842 EXPECT_THAT(
Symbols, UnorderedElementsAre(
846 TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
851 runSymbolCollector(
"class Foo {};",
"");
852 EXPECT_THAT(
Symbols, UnorderedElementsAre(
856 TEST_F(SymbolCollectorTest, UnittestURIScheme) {
860 runSymbolCollector(
"class Foo {};",
"");
861 EXPECT_THAT(
Symbols, UnorderedElementsAre(
862 AllOf(
QName(
"Foo"), DeclURI(
"unittest:///x.h"))));
865 TEST_F(SymbolCollectorTest, IncludeEnums) {
866 const std::string Header = R
"( 882 runSymbolCollector(Header, "");
884 UnorderedElementsAre(
885 AllOf(
QName(
"Red"), ForCodeCompletion(
true)),
886 AllOf(
QName(
"Color"), ForCodeCompletion(
true)),
887 AllOf(
QName(
"Green"), ForCodeCompletion(
true)),
888 AllOf(
QName(
"Color2"), ForCodeCompletion(
true)),
889 AllOf(
QName(
"Color2::Yellow"), ForCodeCompletion(
false)),
890 AllOf(
QName(
"ns"), ForCodeCompletion(
true)),
891 AllOf(
QName(
"ns::Black"), ForCodeCompletion(
true))));
894 TEST_F(SymbolCollectorTest, NamelessSymbols) {
895 const std::string Header = R
"( 900 runSymbolCollector(Header, "");
902 QName(
"(anonymous struct)::a")));
905 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
907 Annotations Header(R
"( 909 class name##_Test {}; 911 $expansion[[FF]](abc); 914 class $spelling[[Test]] {}; 919 runSymbolCollector(Header.code(), "");
921 UnorderedElementsAre(
922 AllOf(
QName(
"abc_Test"), DeclRange(Header.range(
"expansion")),
924 AllOf(
QName(
"Test"), DeclRange(Header.range(
"spelling")),
928 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
929 Annotations Header(R
"( 931 class $expansion[[NAME]] {}; 934 runSymbolCollector(Header.code(), "", {
"-DNAME=name"});
935 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
936 QName(
"name"), DeclRange(Header.range(
"expansion")),
940 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
941 const std::string Main = R
"( 957 runSymbolCollector("", Main);
958 EXPECT_THAT(
Symbols, UnorderedElementsAre(
963 TEST_F(SymbolCollectorTest, Documentation) {
964 const std::string Header = R
"( 972 runSymbolCollector(Header,
"");
974 UnorderedElementsAre(
975 AllOf(
QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
977 ForCodeCompletion(
false))));
980 runSymbolCollector(Header,
"");
982 UnorderedElementsAre(
983 AllOf(
QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
985 ForCodeCompletion(
false))));
988 TEST_F(SymbolCollectorTest, ClassMembers) {
989 const std::string Header = R
"( 998 const std::string Main = R
"( 1002 runSymbolCollector(Header, Main); 1005 UnorderedElementsAre( 1014 TEST_F(SymbolCollectorTest, Scopes) {
1015 const std::string Header = R
"( 1023 runSymbolCollector(Header, "");
1025 UnorderedElementsAre(
QName(
"na"),
QName(
"na::nb"),
1029 TEST_F(SymbolCollectorTest, ExternC) {
1030 const std::string Header = R
"( 1031 extern "C" { class Foo {}; } 1033 extern "C" { class Bar {}; } 1036 runSymbolCollector(Header, "");
1041 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1042 const std::string Header = R
"( 1044 inline namespace nb { 1049 // This is still inlined. 1055 runSymbolCollector(Header, "");
1057 UnorderedElementsAre(
QName(
"na"),
QName(
"na::nb"),
1061 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1062 const std::string Header = R
"( 1065 int ff(int x, double y) { return 0; }
1068 runSymbolCollector(Header,
"");
1071 UnorderedElementsAre(
1072 QName(
"nx"), AllOf(
QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
1077 const std::string Header = R
"( 1080 int ff(int x, double y) { return 0; } 1083 runSymbolCollector(Header, "");
1085 UnorderedElementsAre(
1088 AllOf(
QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
1089 Snippet(
"ff(${1:int x}, ${2:double y})"))));
1092 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1094 runSymbolCollector(
"#pragma once\nclass Foo {};",
"");
1095 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1097 EXPECT_THAT(
Symbols.begin()->IncludeHeaders,
1098 UnorderedElementsAre(IncludeHeaderWithRef(
TestHeaderURI, 1u)));
1101 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1103 CanonicalIncludes Includes;
1104 auto Language = LangOptions();
1105 Language.CPlusPlus =
true;
1106 Includes.addSystemHeadersMapping(Language);
1108 runSymbolCollector(
"namespace std { class string {}; }",
"");
1114 TEST_F(SymbolCollectorTest, IWYUPragma) {
1116 CanonicalIncludes Includes;
1119 const std::string Header = R
"( 1120 // IWYU pragma: private, include the/good/header.h 1123 runSymbolCollector(Header, "");
1124 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1129 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1131 CanonicalIncludes Includes;
1134 const std::string Header = R
"( 1135 // IWYU pragma: private, include "the/good/header.h" 1138 runSymbolCollector(Header, "");
1139 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1144 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1146 CanonicalIncludes Includes;
1149 auto IncFile =
testPath(
"test.inc");
1152 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1153 runSymbolCollector(
"#include \"test.inc\"\nclass Y {};",
"",
1156 UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1162 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1168 auto IncFile =
testPath(
"test.inc");
1171 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1172 runSymbolCollector(
"", R
"cpp( 1173 // Can't use #pragma once in a main file clang doesn't think is a header. 1180 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1184 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1188 auto IncFile =
testPath(
"test.inc");
1191 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1192 runSymbolCollector(
"", R
"cpp( 1196 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1202 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1205 runSymbolCollector(R
"cpp( 1206 #ifndef HEADER_GUARD_ 1207 #define HEADER_GUARD_ 1209 // Symbols are seen before the header guard is complete. 1213 #endif // Header guard is recognized here. 1216 EXPECT_THAT(
Symbols, Not(Contains(
QName(
"HEADER_GUARD_"))));
1220 TEST_F(SymbolCollectorTest, NonModularHeader) {
1222 EXPECT_THAT(TU.headerSymbols(), ElementsAre(
IncludeHeader()));
1225 TU.ImplicitHeaderGuard =
false;
1226 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(
IncludeHeader())));
1231 #error "This file isn't safe to include directly" 1235 TU.ExtraArgs.push_back("-DSECRET");
1236 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(
IncludeHeader())));
1239 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1241 Annotations Header(R
"( 1243 // Forward declarations of TagDecls. 1248 // Canonical declarations. 1249 class $cdecl[[C]] {}; 1250 struct $sdecl[[S]] {}; 1251 union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];}; 1253 runSymbolCollector(Header.code(), "");
1256 UnorderedElementsAre(
1268 DefRange(Header.range(
"xdecl"))),
1271 DefRange(Header.range(
"ydecl")))));
1274 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1276 runSymbolCollector(
"#pragma once\nclass X;",
1278 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1283 TEST_F(SymbolCollectorTest, UTF16Character) {
1285 Annotations Header(
"class [[pörk]] {};");
1286 runSymbolCollector(Header.code(),
"");
1287 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1288 AllOf(
QName(
"pörk"), DeclRange(Header.range()))));
1291 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1292 Annotations Header(R
"( 1299 friend void $bar[[bar]]() {} 1305 runSymbolCollector(Header.code(), "");
1308 UnorderedElementsAre(
1310 AllOf(
QName(
"nx::Y"), DeclRange(Header.range(
"y"))),
1311 AllOf(
QName(
"nx::Z"), DeclRange(Header.range(
"z"))),
1312 AllOf(
QName(
"nx::foo"), DeclRange(Header.range(
"foo"))),
1313 AllOf(
QName(
"nx::bar"), DeclRange(Header.range(
"bar")))));
1316 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1317 const std::string Header = R
"( 1321 const std::string Main = R
"( 1328 runSymbolCollector(Header, Main);
1329 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), RefCount(1)),
1330 AllOf(
QName(
"Y"), RefCount(1)),
1331 AllOf(
QName(
"C"), RefCount(0))));
1334 TEST_F(SymbolCollectorTest, Origin) {
1336 runSymbolCollector(
"class Foo {};",
"");
1337 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1341 TEST_F(SymbolCollectorTest, CollectMacros) {
1343 Annotations Header(R
"( 1346 #define $mac[[MAC]](x) int x 1347 #define $used[[USED]](y) float y; 1352 Annotations Main(R"( 1353 #define $main[[MAIN]] 1 1358 runSymbolCollector(Header.code(), Main.code());
1361 UnorderedElementsAre(
1365 AllOf(Labeled(
"MAC(x)"), RefCount(0),
1367 DeclRange(Header.range(
"mac")), VisibleOutsideFile()),
1368 AllOf(Labeled(
"USED(y)"), RefCount(1),
1369 DeclRange(Header.range(
"used")), VisibleOutsideFile()),
1370 AllOf(Labeled(
"MAIN"), RefCount(0), DeclRange(Main.range(
"main")),
1371 Not(VisibleOutsideFile()))));
1374 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1375 const std::string Header = R
"( 1376 void TestClangc() __attribute__((deprecated("", ""))); 1379 runSymbolCollector(Header, "");
1380 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1381 AllOf(
QName(
"TestClangc"), Deprecated()),
1382 AllOf(
QName(
"TestClangd"), Not(Deprecated()))));
1385 TEST_F(SymbolCollectorTest, ImplementationDetail) {
1386 const std::string Header = R
"( 1387 #define DECL_NAME(x, y) x##_##y##_Decl 1388 #define DECL(x, y) class DECL_NAME(x, y) {}; 1389 DECL(X, Y); // X_Y_Decl 1393 runSymbolCollector(Header, "");
1395 UnorderedElementsAre(
1396 AllOf(
QName(
"X_Y_Decl"), ImplementationDetail()),
1397 AllOf(
QName(
"Public"), Not(ImplementationDetail()))));
1400 TEST_F(SymbolCollectorTest, UsingDecl) {
1401 const char *Header = R
"( 1406 runSymbolCollector(Header, "");
1410 TEST_F(SymbolCollectorTest, CBuiltins) {
1412 const char *Header = R
"( 1413 extern int printf(const char*, ...); 1415 runSymbolCollector(Header, "", {
"-xc"});
1419 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1420 const char *Header = R
"( 1421 void operator delete(void*) 1422 __attribute__((__externally_visible__));)"; 1423 runSymbolCollector(Header, "");
1424 EXPECT_THAT(
Symbols, Contains(
QName(
"operator delete")));
std::unique_ptr< CommentHandler > collectIWYUHeaderMaps(CanonicalIncludes *Includes)
Returns a CommentHandler that parses pragma comment on include files to determine when we should incl...
SymbolCollector::Options CollectorOpts
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
std::string TestHeaderName
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
Symbol is visible to other files (not e.g. a static helper function).
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
std::string TestHeaderURI
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
Symbol is an implementation detail.
SymbolCollector::Options COpts
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
Whether or not this symbol is meant to be used for the code completion.
std::string testPath(PathRef File)
static constexpr llvm::StringLiteral Name
std::shared_ptr< SymbolCollector > Collector
int line
Line position in a document (zero-based).
int character
Character offset on a line in a document (zero-based).
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
static llvm::Expected< URI > create(llvm::StringRef AbsolutePath, llvm::StringRef Scheme)
Creates a URI for a file in the given scheme.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
CharSourceRange Range
SourceRange for the file name.
std::string IncludeHeader
Indicates if the symbol is deprecated.
std::unique_ptr< GlobalCompilationDatabase > Base
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
llvm::StringMap< std::string > Files
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
CommentHandler * PragmaHandler