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/Tooling/Tooling.h" 18 #include "llvm/ADT/IntrusiveRefCntPtr.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/MemoryBuffer.h" 22 #include "llvm/Support/VirtualFileSystem.h" 23 #include "gmock/gmock-matchers.h" 24 #include "gmock/gmock-more-matchers.h" 25 #include "gmock/gmock.h" 26 #include "gtest/gtest.h" 36 using ::testing::AllOf;
37 using ::testing::Contains;
38 using ::testing::Each;
39 using ::testing::ElementsAre;
40 using ::testing::Field;
42 using ::testing::Pair;
43 using ::testing::UnorderedElementsAre;
44 using ::testing::UnorderedElementsAreArray;
48 return (arg.Name + arg.Signature).str() == Label;
51 MATCHER_P(Doc,
D,
"") {
return arg.Documentation ==
D; }
53 return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
57 return arg.TemplateSpecializationArgs == TemplArgs;
60 return StringRef(arg.CanonicalDeclaration.FileURI) == P;
62 MATCHER_P(DefURI, P,
"") {
return StringRef(arg.Definition.FileURI) == P; }
65 return (arg.IncludeHeaders.size() == 1) &&
66 (arg.IncludeHeaders.begin()->IncludeHeader == P);
72 return std::make_tuple(arg.CanonicalDeclaration.Start.line(),
73 arg.CanonicalDeclaration.Start.column(),
74 arg.CanonicalDeclaration.End.line(),
75 arg.CanonicalDeclaration.End.column()) ==
76 std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
80 return std::make_tuple(
81 arg.Definition.Start.line(), arg.Definition.Start.column(),
82 arg.Definition.End.line(), arg.Definition.End.column()) ==
83 std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
86 MATCHER_P(RefCount, R,
"") {
return int(arg.References) == R; }
87 MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion,
"") {
89 IsIndexedForCodeCompletion;
92 MATCHER(ImplementationDetail,
"") {
95 MATCHER(VisibleOutsideFile,
"") {
99 const Ref &Pos = ::testing::get<0>(arg);
101 return std::make_tuple(Pos.Location.Start.line(), Pos.Location.Start.column(),
102 Pos.Location.End.line(), Pos.Location.End.column()) ==
103 std::make_tuple(Range.start.line, Range.start.character,
104 Range.end.line, Range.end.character);
106 ::testing::Matcher<const std::vector<Ref> &>
107 HaveRanges(
const std::vector<Range> Ranges) {
108 return ::testing::UnorderedPointwise(RefRange(), Ranges);
111 class ShouldCollectSymbolTest :
public ::testing::Test {
113 void build(llvm::StringRef HeaderCode, llvm::StringRef Code =
"") {
116 File.HeaderCode = HeaderCode;
122 bool shouldCollect(llvm::StringRef
Name,
bool Qualified =
true) {
123 assert(
AST.hasValue());
124 const NamedDecl &ND =
126 const SourceManager &SM =
AST->getSourceManager();
128 SM.isWrittenInMainFile(SM.getExpansionLoc(ND.getBeginLoc()));
130 ND,
AST->getASTContext(), SymbolCollector::Options(),
MainFile);
137 llvm::Optional<ParsedAST>
AST;
140 TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
144 auto f() { int Local; } // auto ensures function body is parsed. 145 struct { int x; } var; 150 namespace { class InAnonymous {}; } 154 EXPECT_TRUE(shouldCollect(
"nx"));
155 EXPECT_TRUE(shouldCollect(
"nx::X"));
156 EXPECT_TRUE(shouldCollect(
"nx::f"));
157 EXPECT_TRUE(shouldCollect(
"InMain"));
158 EXPECT_TRUE(shouldCollect(
"InAnonymous",
false));
159 EXPECT_TRUE(shouldCollect(
"g"));
161 EXPECT_FALSE(shouldCollect(
"Local",
false));
164 TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
167 R
"(// Generated by the protocol buffer compiler. DO NOT EDIT! 176 EXPECT_TRUE(shouldCollect("nx::TopLevel"));
177 EXPECT_TRUE(shouldCollect(
"nx::Kind::KIND_OK"));
178 EXPECT_TRUE(shouldCollect(
"nx::Kind"));
180 EXPECT_FALSE(shouldCollect(
"nx::Top_Level"));
181 EXPECT_FALSE(shouldCollect(
"nx::Kind::Kind_Not_Ok"));
184 TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
194 EXPECT_TRUE(shouldCollect("nx::Top_Level"));
195 EXPECT_TRUE(shouldCollect(
"nx::Kind_Fine"));
198 class SymbolIndexActionFactory :
public tooling::FrontendActionFactory {
200 SymbolIndexActionFactory(SymbolCollector::Options
COpts,
204 clang::FrontendAction *create()
override {
205 class WrappedIndexAction :
public WrapperFrontendAction {
207 WrappedIndexAction(std::shared_ptr<SymbolCollector> C,
208 const index::IndexingOptions &Opts,
209 CommentHandler *PragmaHandler)
210 : WrapperFrontendAction(
211 index::createIndexingAction(C, Opts,
nullptr)),
214 std::unique_ptr<ASTConsumer>
215 CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile)
override {
217 CI.getPreprocessor().addCommentHandler(PragmaHandler);
218 return WrapperFrontendAction::CreateASTConsumer(CI, InFile);
221 bool BeginInvocation(CompilerInstance &CI)
override {
223 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
224 return WrapperFrontendAction::BeginInvocation(CI);
228 index::IndexingOptions IndexOpts;
231 index::IndexingOptions IndexOpts;
232 IndexOpts.SystemSymbolFilter =
233 index::IndexingOptions::SystemSymbolFilterKind::All;
234 IndexOpts.IndexFunctionLocals =
false;
236 return new WrappedIndexAction(
Collector, std::move(IndexOpts),
245 class SymbolCollectorTest :
public ::testing::Test {
247 SymbolCollectorTest()
257 bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
258 const std::vector<std::string> &ExtraArgs = {}) {
259 llvm::IntrusiveRefCntPtr<FileManager>
Files(
262 auto Factory = llvm::make_unique<SymbolIndexActionFactory>(
265 std::vector<std::string> Args = {
"symbol_collector",
"-fsyntax-only",
267 Args.insert(Args.end(), ExtraArgs.begin(), ExtraArgs.end());
272 tooling::ToolInvocation Invocation(
273 Args, Factory->create(), Files.get(),
274 std::make_shared<PCHContainerOperations>());
277 llvm::MemoryBuffer::getMemBuffer(HeaderCode));
279 llvm::MemoryBuffer::getMemBuffer(MainCode));
281 Symbols = Factory->Collector->takeSymbols();
282 Refs = Factory->Collector->takeRefs();
283 Relations = Factory->Collector->takeRelations();
300 TEST_F(SymbolCollectorTest, CollectSymbols) {
301 const std::string Header = R
"( 308 Foo& operator=(const Foo&); 319 static const int KInt = 2; 320 const char* kStr = "123"; 323 void ff() {} // ignore 331 using int32_t = int32; 346 runSymbolCollector(Header, "");
348 UnorderedElementsAreArray(
349 {AllOf(
QName(
"Foo"), ForCodeCompletion(
true)),
350 AllOf(
QName(
"Foo::Foo"), ForCodeCompletion(
false)),
351 AllOf(
QName(
"Foo::Foo"), ForCodeCompletion(
false)),
352 AllOf(
QName(
"Foo::f"), ForCodeCompletion(
false)),
353 AllOf(
QName(
"Foo::~Foo"), ForCodeCompletion(
false)),
354 AllOf(
QName(
"Foo::operator="), ForCodeCompletion(
false)),
355 AllOf(
QName(
"Foo::Nested"), ForCodeCompletion(
false)),
356 AllOf(
QName(
"Foo::Nested::f"), ForCodeCompletion(
false)),
358 AllOf(
QName(
"Friend"), ForCodeCompletion(
true)),
359 AllOf(
QName(
"f1"), ForCodeCompletion(
true)),
360 AllOf(
QName(
"f2"), ForCodeCompletion(
true)),
361 AllOf(
QName(
"KInt"), ForCodeCompletion(
true)),
362 AllOf(
QName(
"kStr"), ForCodeCompletion(
true)),
363 AllOf(
QName(
"foo"), ForCodeCompletion(
true)),
364 AllOf(
QName(
"foo::bar"), ForCodeCompletion(
true)),
365 AllOf(
QName(
"foo::int32"), ForCodeCompletion(
true)),
366 AllOf(
QName(
"foo::int32_t"), ForCodeCompletion(
true)),
367 AllOf(
QName(
"foo::v1"), ForCodeCompletion(
true)),
368 AllOf(
QName(
"foo::bar::v2"), ForCodeCompletion(
true)),
369 AllOf(
QName(
"foo::v2"), ForCodeCompletion(
true)),
370 AllOf(
QName(
"foo::baz"), ForCodeCompletion(
true))}));
373 TEST_F(SymbolCollectorTest, FileLocal) {
374 const std::string Header = R
"( 381 const std::string Main = R
"( 390 runSymbolCollector(Header, Main); 392 UnorderedElementsAre( 393 AllOf(QName("Foo"), VisibleOutsideFile()),
394 AllOf(
QName(
"bar"), VisibleOutsideFile()),
395 AllOf(
QName(
"a"), Not(VisibleOutsideFile())),
396 AllOf(
QName(
"B"), Not(VisibleOutsideFile())),
397 AllOf(
QName(
"c"), Not(VisibleOutsideFile())),
399 AllOf(
QName(
"ForwardDecl"), Not(VisibleOutsideFile()))));
402 TEST_F(SymbolCollectorTest, Template) {
403 Annotations Header(R
"( 404 // Primary template and explicit specialization are indexed, instantiation 406 template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;}; 407 template <> struct $specdecl[[Tmpl]]<int, bool> {}; 408 template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {}; 409 extern template struct Tmpl<float, bool>; 410 template struct Tmpl<double, bool>; 412 runSymbolCollector(Header.code(), "");
414 UnorderedElementsAre(
415 AllOf(
QName(
"Tmpl"), DeclRange(Header.range()),
416 ForCodeCompletion(
true)),
417 AllOf(
QName(
"Tmpl"), DeclRange(Header.range(
"specdecl")),
418 ForCodeCompletion(
false)),
419 AllOf(
QName(
"Tmpl"), DeclRange(Header.range(
"partspecdecl")),
420 ForCodeCompletion(
false)),
421 AllOf(
QName(
"Tmpl::x"), DeclRange(Header.range(
"xdecl")),
422 ForCodeCompletion(
false))));
425 TEST_F(SymbolCollectorTest, TemplateArgs) {
426 Annotations Header(R
"( 427 template <class X> class $barclasstemp[[Bar]] {}; 428 template <class T, class U, template<typename> class Z, int Q> 429 struct [[Tmpl]] { T $xdecl[[x]] = 0; }; 431 // template-template, non-type and type full spec 432 template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {}; 434 // template-template, non-type and type partial spec 435 template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {}; 437 extern template struct Tmpl<float, bool, Bar, 8>; 439 template struct Tmpl<double, bool, Bar, 2>; 441 template <typename ...> class $fooclasstemp[[Foo]] {}; 442 // parameter-packs full spec 443 template<> class $parampack[[Foo]]<Bar<int>, int, double> {}; 444 // parameter-packs partial spec 445 template<class T> class $parampackpartial[[Foo]]<T, T> {}; 447 template <int ...> class $bazclasstemp[[Baz]] {}; 448 // non-type parameter-packs full spec 449 template<> class $parampacknontype[[Baz]]<3, 5, 8> {}; 450 // non-type parameter-packs partial spec 451 template<int T> class $parampacknontypepartial[[Baz]]<T, T> {}; 453 template <template <class> class ...> class $fozclasstemp[[Foz]] {}; 454 // template-template parameter-packs full spec 455 template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {}; 456 // template-template parameter-packs partial spec 457 template<template <class> class T> 458 class $parampacktempltemplpartial[[Foz]]<T, T> {}; 460 runSymbolCollector(Header.code(), "");
464 Contains(AllOf(
QName(
"Tmpl"), TemplateArgs(
"<int, bool, Bar, 3>"),
465 DeclRange(Header.range(
"specdecl")),
466 ForCodeCompletion(
false))),
467 Contains(AllOf(
QName(
"Tmpl"), TemplateArgs(
"<bool, U, Bar, T>"),
468 DeclRange(Header.range(
"partspecdecl")),
469 ForCodeCompletion(
false))),
470 Contains(AllOf(
QName(
"Foo"), TemplateArgs(
"<Bar<int>, int, double>"),
471 DeclRange(Header.range(
"parampack")),
472 ForCodeCompletion(
false))),
473 Contains(AllOf(
QName(
"Foo"), TemplateArgs(
"<T, T>"),
474 DeclRange(Header.range(
"parampackpartial")),
475 ForCodeCompletion(
false))),
476 Contains(AllOf(
QName(
"Baz"), TemplateArgs(
"<3, 5, 8>"),
477 DeclRange(Header.range(
"parampacknontype")),
478 ForCodeCompletion(
false))),
479 Contains(AllOf(
QName(
"Baz"), TemplateArgs(
"<T, T>"),
480 DeclRange(Header.range(
"parampacknontypepartial")),
481 ForCodeCompletion(
false))),
482 Contains(AllOf(
QName(
"Foz"), TemplateArgs(
"<Bar, Bar>"),
483 DeclRange(Header.range(
"parampacktempltempl")),
484 ForCodeCompletion(
false))),
485 Contains(AllOf(
QName(
"Foz"), TemplateArgs(
"<T, T>"),
486 DeclRange(Header.range(
"parampacktempltemplpartial")),
487 ForCodeCompletion(
false)))));
490 TEST_F(SymbolCollectorTest, ObjCSymbols) {
491 const std::string Header = R
"( 493 - (void)someMethodName:(void*)name1 lastName:(void*)lName; 496 @implementation Person 497 - (void)someMethodName:(void*)name1 lastName:(void*)lName{ 499 ^(int param){ int bar; }; 503 @interface Person (MyCategory) 504 - (void)someMethodName2:(void*)name2; 507 @implementation Person (MyCategory) 508 - (void)someMethodName2:(void*)name2 { 514 - (void)someMethodName3:(void*)name3; 518 runSymbolCollector(Header,
"", {
"-fblocks",
"-xobjective-c++"});
520 UnorderedElementsAre(
521 QName(
"Person"),
QName(
"Person::someMethodName:lastName:"),
522 QName(
"MyCategory"),
QName(
"Person::someMethodName2:"),
523 QName(
"MyProtocol"),
QName(
"MyProtocol::someMethodName3:")));
526 TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
527 const std::string Header = R
"( 529 @property(nonatomic) int magic; 532 @implementation Container 536 runSymbolCollector(Header,
"", {
"-xobjective-c++"});
538 EXPECT_THAT(
Symbols, Contains(
QName(
"Container::magic")));
543 TEST_F(SymbolCollectorTest, Locations) {
544 Annotations Header(R
"cpp( 545 // Declared in header, defined in main. 546 extern int $xdecl[[X]]; 547 class $clsdecl[[Cls]]; 548 void $printdecl[[print]](); 550 // Declared in header, defined nowhere. 551 extern int $zdecl[[Z]]; 556 Annotations Main(R"cpp( 558 class $clsdef[[Cls]] {}; 559 void $printdef[[print]]() {} 561 // Declared/defined in main only. 564 runSymbolCollector(Header.code(), Main.code()); 566 UnorderedElementsAre( 567 AllOf(QName("X"), DeclRange(Header.range(
"xdecl")),
568 DefRange(Main.range(
"xdef"))),
569 AllOf(
QName(
"Cls"), DeclRange(Header.range(
"clsdecl")),
570 DefRange(Main.range(
"clsdef"))),
571 AllOf(
QName(
"print"), DeclRange(Header.range(
"printdecl")),
572 DefRange(Main.range(
"printdef"))),
573 AllOf(
QName(
"Z"), DeclRange(Header.range(
"zdecl"))),
574 AllOf(
QName(
"foo"), DeclRange(Header.range(
"foodecl"))),
575 AllOf(
QName(
"Y"), DeclRange(Main.range(
"ydecl")))));
579 Annotations Header(R
"( 586 void $func[[func]](); 588 namespace $ns[[NS]] {} // namespace ref is ignored 591 class $bar[[Bar]] {}; 593 void $func[[func]](); 600 $foo[[Foo]] foo2 = abc; 603 Annotations SymbolsOnlyInMainCode(R"( 606 static const int c = 0; 610 runSymbolCollector(Header.code(), 611 (Main.code() + SymbolsOnlyInMainCode.code()).str()); 615 HaveRanges(Main.ranges(
"foo")))));
617 HaveRanges(Main.ranges(
"bar")))));
619 HaveRanges(Main.ranges(
"func")))));
624 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"a").ID, _))));
625 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"b").ID, _))));
626 EXPECT_THAT(
Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"c").ID, _))));
630 TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
632 Annotations Header(R
"( 633 class $Foo[[Foo]] {}; 635 void $Func[[Func]]() { 642 runSymbolCollector(
"", Header.code());
643 EXPECT_THAT(
Refs, UnorderedElementsAre());
647 runSymbolCollector(
"", Header.code(),
648 {
"-xobjective-c++-header"});
651 HaveRanges(Header.ranges(
"Foo"))),
653 HaveRanges(Header.ranges(
"Func")))));
656 TEST_F(SymbolCollectorTest, RefsInHeaders) {
659 Annotations Header(R
"( 662 runSymbolCollector(Header.code(), "");
664 HaveRanges(Header.ranges()))));
668 std::string Header = R
"( 670 class Derived : public Base {}; 672 runSymbolCollector(Header, "");
676 Contains(Relation{Base.ID, index::SymbolRole::RelationBaseOf,
681 const std::string Header = R
"( 685 class Z {}; // not used anywhere 686 Y* y = nullptr; // used in header doesn't count 687 #define GLOBAL_Z(name) Z name; 689 const std::string Main = R
"( 691 W* w2 = nullptr; // only one usage counts 694 class Y{}; // definition doesn't count as a reference 696 GLOBAL_Z(z); // Not a reference to Z, we don't spell the type. 699 runSymbolCollector(Header, Main);
702 UnorderedElementsAreArray(
703 {AllOf(
QName(
"W"), RefCount(1)), AllOf(
QName(
"X"), RefCount(1)),
704 AllOf(
QName(
"Y"), RefCount(0)), AllOf(
QName(
"Z"), RefCount(0)),
705 AllOf(
QName(
"y"), RefCount(0)), AllOf(
QName(
"z"), RefCount(0)),
706 AllOf(
QName(
"x"), RefCount(0)), AllOf(
QName(
"w"), RefCount(0)),
707 AllOf(
QName(
"w2"), RefCount(0)), AllOf(
QName(
"V"), RefCount(1)),
708 AllOf(
QName(
"v"), RefCount(0))}));
711 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
712 runSymbolCollector(
"class Foo {};",
"");
713 EXPECT_THAT(
Symbols, UnorderedElementsAre(
717 TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
722 runSymbolCollector(
"class Foo {};",
"");
723 EXPECT_THAT(
Symbols, UnorderedElementsAre(
727 TEST_F(SymbolCollectorTest, UnittestURIScheme) {
731 runSymbolCollector(
"class Foo {};",
"");
732 EXPECT_THAT(
Symbols, UnorderedElementsAre(
733 AllOf(
QName(
"Foo"), DeclURI(
"unittest:///x.h"))));
736 TEST_F(SymbolCollectorTest, IncludeEnums) {
737 const std::string Header = R
"( 753 runSymbolCollector(Header, "");
755 UnorderedElementsAre(
756 AllOf(
QName(
"Red"), ForCodeCompletion(
true)),
757 AllOf(
QName(
"Color"), ForCodeCompletion(
true)),
758 AllOf(
QName(
"Green"), ForCodeCompletion(
true)),
759 AllOf(
QName(
"Color2"), ForCodeCompletion(
true)),
760 AllOf(
QName(
"Color2::Yellow"), ForCodeCompletion(
false)),
761 AllOf(
QName(
"ns"), ForCodeCompletion(
true)),
762 AllOf(
QName(
"ns::Black"), ForCodeCompletion(
true))));
765 TEST_F(SymbolCollectorTest, NamelessSymbols) {
766 const std::string Header = R
"( 771 runSymbolCollector(Header, "");
773 QName(
"(anonymous struct)::a")));
776 TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
778 Annotations Header(R
"( 780 class name##_Test {}; 782 $expansion[[FF]](abc); 785 class $spelling[[Test]] {}; 790 runSymbolCollector(Header.code(), "");
792 UnorderedElementsAre(
793 AllOf(
QName(
"abc_Test"), DeclRange(Header.range(
"expansion")),
795 AllOf(
QName(
"Test"), DeclRange(Header.range(
"spelling")),
799 TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
800 Annotations Header(R
"( 802 class $expansion[[NAME]] {}; 805 runSymbolCollector(Header.code(), "", {
"-DNAME=name"});
806 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
807 QName(
"name"), DeclRange(Header.range(
"expansion")),
811 TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
812 const std::string Main = R
"( 828 runSymbolCollector("", Main);
829 EXPECT_THAT(
Symbols, UnorderedElementsAre(
834 TEST_F(SymbolCollectorTest, Documentation) {
835 const std::string Header = R
"( 843 runSymbolCollector(Header,
"");
845 UnorderedElementsAre(
846 AllOf(
QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
848 ForCodeCompletion(
false))));
851 runSymbolCollector(Header,
"");
853 UnorderedElementsAre(
854 AllOf(
QName(
"Foo"), Doc(
"Doc Foo"), ForCodeCompletion(
true)),
856 ForCodeCompletion(
false))));
859 TEST_F(SymbolCollectorTest, ClassMembers) {
860 const std::string Header = R
"( 869 const std::string Main = R
"( 873 runSymbolCollector(Header, Main); 876 UnorderedElementsAre( 885 TEST_F(SymbolCollectorTest, Scopes) {
886 const std::string Header = R
"( 894 runSymbolCollector(Header, "");
896 UnorderedElementsAre(
QName(
"na"),
QName(
"na::nb"),
900 TEST_F(SymbolCollectorTest, ExternC) {
901 const std::string Header = R
"( 902 extern "C" { class Foo {}; } 904 extern "C" { class Bar {}; } 907 runSymbolCollector(Header, "");
912 TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
913 const std::string Header = R
"( 915 inline namespace nb { 920 // This is still inlined. 926 runSymbolCollector(Header, "");
928 UnorderedElementsAre(
QName(
"na"),
QName(
"na::nb"),
932 TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
933 const std::string Header = R
"( 936 int ff(int x, double y) { return 0; }
939 runSymbolCollector(Header,
"");
942 UnorderedElementsAre(
943 QName(
"nx"), AllOf(
QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
948 const std::string Header = R
"( 951 int ff(int x, double y) { return 0; } 954 runSymbolCollector(Header, "");
956 UnorderedElementsAre(
959 AllOf(
QName(
"nx::ff"), Labeled(
"ff(int x, double y)"),
960 Snippet(
"ff(${1:int x}, ${2:double y})"))));
963 TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
965 runSymbolCollector(
"#pragma once\nclass Foo {};",
"");
966 EXPECT_THAT(
Symbols, UnorderedElementsAre(
968 EXPECT_THAT(
Symbols.begin()->IncludeHeaders,
969 UnorderedElementsAre(IncludeHeaderWithRef(
TestHeaderURI, 1u)));
972 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
974 CanonicalIncludes Includes;
975 auto Language = LangOptions();
976 Language.CPlusPlus =
true;
979 runSymbolCollector(
"namespace std { class string {}; }",
"");
985 TEST_F(SymbolCollectorTest, IWYUPragma) {
987 CanonicalIncludes Includes;
990 const std::string Header = R
"( 991 // IWYU pragma: private, include the/good/header.h 994 runSymbolCollector(Header, "");
995 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1000 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1002 CanonicalIncludes Includes;
1005 const std::string Header = R
"( 1006 // IWYU pragma: private, include "the/good/header.h" 1009 runSymbolCollector(Header, "");
1010 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1015 TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
1017 CanonicalIncludes Includes;
1020 auto IncFile =
testPath(
"test.inc");
1023 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1024 runSymbolCollector(
"#include \"test.inc\"\nclass Y {};",
"",
1027 UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1033 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1039 auto IncFile =
testPath(
"test.inc");
1042 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1043 runSymbolCollector(
"", R
"cpp( 1044 // Can't use #pragma once in a main file clang doesn't think is a header. 1051 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1055 TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1059 auto IncFile =
testPath(
"test.inc");
1062 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1063 runSymbolCollector(
"", R
"cpp( 1067 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), DeclURI(IncURI),
1073 TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1076 runSymbolCollector(R
"cpp( 1077 #ifndef HEADER_GUARD_ 1078 #define HEADER_GUARD_ 1080 // Symbols are seen before the header guard is complete. 1084 #endif // Header guard is recognized here. 1087 EXPECT_THAT(
Symbols, Not(Contains(
QName(
"HEADER_GUARD_"))));
1091 TEST_F(SymbolCollectorTest, NonModularHeader) {
1093 EXPECT_THAT(TU.headerSymbols(), ElementsAre(
IncludeHeader()));
1096 TU.ImplicitHeaderGuard =
false;
1097 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(
IncludeHeader())));
1102 #error "This file isn't safe to include directly" 1106 TU.ExtraArgs.push_back("-DSECRET");
1107 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(
IncludeHeader())));
1110 TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1112 Annotations Header(R
"( 1114 // Forward declarations of TagDecls. 1119 // Canonical declarations. 1120 class $cdecl[[C]] {}; 1121 struct $sdecl[[S]] {}; 1122 union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];}; 1124 runSymbolCollector(Header.code(), "");
1127 UnorderedElementsAre(
1139 DefRange(Header.range(
"xdecl"))),
1142 DefRange(Header.range(
"ydecl")))));
1145 TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1147 runSymbolCollector(
"#pragma once\nclass X;",
1149 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1154 TEST_F(SymbolCollectorTest, UTF16Character) {
1156 Annotations Header(
"class [[pörk]] {};");
1157 runSymbolCollector(Header.code(),
"");
1158 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1159 AllOf(
QName(
"pörk"), DeclRange(Header.range()))));
1162 TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1163 Annotations Header(R
"( 1170 friend void $bar[[bar]]() {} 1176 runSymbolCollector(Header.code(), "");
1179 UnorderedElementsAre(
1181 AllOf(
QName(
"nx::Y"), DeclRange(Header.range(
"y"))),
1182 AllOf(
QName(
"nx::Z"), DeclRange(Header.range(
"z"))),
1183 AllOf(
QName(
"nx::foo"), DeclRange(Header.range(
"foo"))),
1184 AllOf(
QName(
"nx::bar"), DeclRange(Header.range(
"bar")))));
1187 TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1188 const std::string Header = R
"( 1192 const std::string Main = R
"( 1199 runSymbolCollector(Header, Main);
1200 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
QName(
"X"), RefCount(1)),
1201 AllOf(
QName(
"Y"), RefCount(1)),
1202 AllOf(
QName(
"C"), RefCount(0))));
1205 TEST_F(SymbolCollectorTest, Origin) {
1207 runSymbolCollector(
"class Foo {};",
"");
1208 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1212 TEST_F(SymbolCollectorTest, CollectMacros) {
1214 Annotations Header(R
"( 1217 #define $mac[[MAC]](x) int x 1218 #define $used[[USED]](y) float y; 1223 Annotations Main(R"( 1224 #define $main[[MAIN]] 1 1229 runSymbolCollector(Header.code(), Main.code());
1232 UnorderedElementsAre(
1236 AllOf(Labeled(
"MAC(x)"), RefCount(0),
1238 DeclRange(Header.range(
"mac")), VisibleOutsideFile()),
1239 AllOf(Labeled(
"USED(y)"), RefCount(1),
1240 DeclRange(Header.range(
"used")), VisibleOutsideFile()),
1241 AllOf(Labeled(
"MAIN"), RefCount(0), DeclRange(Main.range(
"main")),
1242 Not(VisibleOutsideFile()))));
1245 TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1246 const std::string Header = R
"( 1247 void TestClangc() __attribute__((deprecated("", ""))); 1250 runSymbolCollector(Header, "");
1251 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1252 AllOf(
QName(
"TestClangc"), Deprecated()),
1253 AllOf(
QName(
"TestClangd"), Not(Deprecated()))));
1256 TEST_F(SymbolCollectorTest, ImplementationDetail) {
1257 const std::string Header = R
"( 1258 #define DECL_NAME(x, y) x##_##y##_Decl 1259 #define DECL(x, y) class DECL_NAME(x, y) {}; 1260 DECL(X, Y); // X_Y_Decl 1264 runSymbolCollector(Header, "");
1266 UnorderedElementsAre(
1267 AllOf(
QName(
"X_Y_Decl"), ImplementationDetail()),
1268 AllOf(
QName(
"Public"), Not(ImplementationDetail()))));
1271 TEST_F(SymbolCollectorTest, UsingDecl) {
1272 const char *Header = R
"( 1277 runSymbolCollector(Header, "");
1281 TEST_F(SymbolCollectorTest, CBuiltins) {
1283 const char *Header = R
"( 1284 extern int printf(const char*, ...); 1286 runSymbolCollector(Header, "", {
"-xc"});
1290 TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1291 const char *Header = R
"( 1292 void operator delete(void*) 1293 __attribute__((__externally_visible__));)"; 1294 runSymbolCollector(Header, "");
1295 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
Symbol is visible to other files (not e.g. a static helper function).
void addSystemHeadersMapping(CanonicalIncludes *Includes, const LangOptions &Language)
Adds mapping for system headers and some special symbols (e.g.
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
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