13#include "clang-include-cleaner/Record.h"
15#include "clang/Basic/FileManager.h"
16#include "clang/Basic/FileSystemOptions.h"
17#include "clang/Basic/SourceLocation.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Index/IndexingAction.h"
20#include "clang/Index/IndexingOptions.h"
21#include "clang/Tooling/Tooling.h"
22#include "llvm/ADT/IntrusiveRefCntPtr.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/VirtualFileSystem.h"
26#include "gmock/gmock-matchers.h"
27#include "gmock/gmock.h"
28#include "gtest/gtest.h"
40using ::testing::AllOf;
41using ::testing::Contains;
43using ::testing::ElementsAre;
44using ::testing::Field;
45using ::testing::IsEmpty;
48using ::testing::UnorderedElementsAre;
49using ::testing::UnorderedElementsAreArray;
53 return (arg.Name + arg.Signature).str() ==
Label;
55MATCHER_P(returnType, D,
"") {
return arg.ReturnType == D; }
56MATCHER_P(doc, D,
"") {
return arg.Documentation == D; }
58 return (arg.Name + arg.CompletionSnippetSuffix).str() == S;
63 return arg.TemplateSpecializationArgs == TemplArgs;
67 return StringRef(arg.CanonicalDeclaration.FileURI) == P;
69MATCHER_P(defURI, P,
"") {
return StringRef(arg.Definition.FileURI) == P; }
70MATCHER(includeHeader,
"") {
return !arg.IncludeHeaders.empty(); }
72 return (arg.IncludeHeaders.size() == 1) &&
73 (arg.IncludeHeaders.begin()->IncludeHeader == P);
76 return (arg.IncludeHeader == includeHeader) && (arg.References ==
References);
78bool rangesMatch(
const SymbolLocation &
Loc,
const Range &R) {
79 return std::make_tuple(
Loc.Start.line(),
Loc.Start.column(),
Loc.End.line(),
81 std::make_tuple(R.start.line, R.start.character, R.end.line,
85 return rangesMatch(arg.CanonicalDeclaration,
Pos);
87MATCHER_P(defRange,
Pos,
"") {
return rangesMatch(arg.Definition,
Pos); }
88MATCHER_P(refCount, R,
"") {
return int(arg.References) == R; }
89MATCHER_P(forCodeCompletion, IsIndexedForCodeCompletion,
"") {
91 IsIndexedForCodeCompletion;
94MATCHER(implementationDetail,
"") {
97MATCHER(visibleOutsideFile,
"") {
101 const Ref &
Pos = ::testing::get<0>(arg);
103 return rangesMatch(
Pos.Location, Range);
111::testing::Matcher<const std::vector<Ref> &>
112haveRanges(
const std::vector<Range> Ranges) {
113 return ::testing::UnorderedPointwise(refRange(), Ranges);
116class ShouldCollectSymbolTest :
public ::testing::Test {
118 void build(llvm::StringRef HeaderCode, llvm::StringRef Code =
"") {
119 File.HeaderFilename = HeaderName;
121 File.HeaderCode = std::string(HeaderCode);
122 File.Code = std::string(Code);
127 bool shouldCollect(llvm::StringRef
Name,
bool Qualified =
true) {
129 const NamedDecl &ND =
131 const SourceManager &SM = AST->getSourceManager();
134 ND, AST->getASTContext(), SymbolCollector::Options(),
MainFile);
138 std::string HeaderName =
"f.h";
141 std::optional<ParsedAST> AST;
144TEST_F(ShouldCollectSymbolTest, ShouldCollectSymbol) {
148 auto f() { int Local; } // auto ensures function body is parsed.
149 struct { int x; } var;
154 namespace { class InAnonymous {}; }
158 EXPECT_TRUE(shouldCollect(
"nx"));
159 EXPECT_TRUE(shouldCollect(
"nx::X"));
160 EXPECT_TRUE(shouldCollect(
"nx::f"));
161 EXPECT_TRUE(shouldCollect(
"InMain"));
162 EXPECT_TRUE(shouldCollect(
"InAnonymous",
false));
163 EXPECT_TRUE(shouldCollect(
"g"));
165 EXPECT_FALSE(shouldCollect(
"Local",
false));
168TEST_F(ShouldCollectSymbolTest, CollectLocalClassesAndVirtualMethods) {
173 auto LocalLambda = [&](){
175 class ClassInLambda{};
178 } // auto ensures function body is parsed.
181 virtual void LocalVirtual();
182 void LocalConcrete();
190 EXPECT_FALSE(shouldCollect(
"Local",
false));
191 EXPECT_TRUE(shouldCollect(
"ClassInLambda",
false));
192 EXPECT_TRUE(shouldCollect(
"LocalBase",
false));
193 EXPECT_TRUE(shouldCollect(
"LocalVirtual",
false));
194 EXPECT_TRUE(shouldCollect(
"LocalConcrete",
false));
195 EXPECT_FALSE(shouldCollect(
"BaseMember",
false));
196 EXPECT_FALSE(shouldCollect(
"Local",
false));
199TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) {
200 HeaderName =
"f.proto.h";
202 R
"(// Generated by the protocol buffer compiler. DO NOT EDIT!
204 enum Outer_Enum : int {
208 bool Outer_Enum_IsValid(int);
210 class Outer_Inner {};
212 using Inner = Outer_Inner;
213 using Enum = Outer_Enum;
214 static constexpr Enum KIND1 = Outer_Enum_KIND1;
215 static constexpr Enum Kind_2 = Outer_Enum_Kind_2;
216 static bool Enum_IsValid(int);
219 void _internal_set_x();
227 bool Foo_IsValid(int);
231 EXPECT_FALSE(shouldCollect(
"nx::Outer_Enum"));
232 EXPECT_FALSE(shouldCollect(
"nx::Outer_Enum_KIND1"));
233 EXPECT_FALSE(shouldCollect(
"nx::Outer_Enum_Kind_2"));
234 EXPECT_FALSE(shouldCollect(
"nx::Outer_Enum_IsValid"));
236 EXPECT_TRUE(shouldCollect(
"nx::Outer::Enum"));
237 EXPECT_TRUE(shouldCollect(
"nx::Outer::KIND1"));
238 EXPECT_TRUE(shouldCollect(
"nx::Outer::Kind_2"));
239 EXPECT_TRUE(shouldCollect(
"nx::Outer::Enum_IsValid"));
242 EXPECT_FALSE(shouldCollect(
"nx::Outer_Inner"));
243 EXPECT_TRUE(shouldCollect(
"nx::Outer"));
244 EXPECT_TRUE(shouldCollect(
"nx::Outer::Inner"));
248 EXPECT_TRUE(shouldCollect(
"nx::Outer::x"));
249 EXPECT_TRUE(shouldCollect(
"nx::Outer::set_x"));
250 EXPECT_FALSE(shouldCollect(
"nx::Outer::_internal_set_x"));
251 EXPECT_TRUE(shouldCollect(
"nx::Outer::Outer_y"));
254 EXPECT_TRUE(shouldCollect(
"nx::Foo::FOO_VAL1"));
255 EXPECT_TRUE(shouldCollect(
"nx::FOO_VAL1"));
256 EXPECT_TRUE(shouldCollect(
"nx::Foo_IsValid"));
259 EXPECT_FALSE(shouldCollect(
"nx::Foo::Foo_VAL2"));
260 EXPECT_FALSE(shouldCollect(
"nx::Foo_VAL2"));
263TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
264 HeaderName =
"f.proto.h";
273 EXPECT_TRUE(shouldCollect("nx::Top_Level"));
274 EXPECT_TRUE(shouldCollect(
"nx::Kind_Fine"));
277class SymbolIndexActionFactory :
public tooling::FrontendActionFactory {
279 SymbolIndexActionFactory(SymbolCollector::Options COpts)
282 std::unique_ptr<FrontendAction> create()
override {
283 class IndexAction :
public ASTFrontendAction {
285 IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
286 const index::IndexingOptions &Opts,
287 std::shared_ptr<include_cleaner::PragmaIncludes> PI)
288 : DataConsumer(std::move(DataConsumer)), Opts(Opts),
291 std::unique_ptr<ASTConsumer>
292 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
294 return createIndexingASTConsumer(DataConsumer, Opts,
295 CI.getPreprocessorPtr());
298 bool BeginInvocation(CompilerInstance &
CI)
override {
300 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
305 std::shared_ptr<index::IndexDataConsumer> DataConsumer;
306 index::IndexingOptions Opts;
307 std::shared_ptr<include_cleaner::PragmaIncludes> PI;
309 index::IndexingOptions IndexOpts;
310 IndexOpts.SystemSymbolFilter =
311 index::IndexingOptions::SystemSymbolFilterKind::All;
312 IndexOpts.IndexFunctionLocals =
true;
313 std::shared_ptr<include_cleaner::PragmaIncludes> PI =
314 std::make_shared<include_cleaner::PragmaIncludes>();
315 COpts.PragmaIncludes = PI.get();
316 Collector = std::make_shared<SymbolCollector>(COpts);
317 return std::make_unique<IndexAction>(Collector, std::move(IndexOpts),
321 std::shared_ptr<SymbolCollector> Collector;
322 SymbolCollector::Options
COpts;
325class SymbolCollectorTest :
public ::testing::Test {
327 SymbolCollectorTest()
337 bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
338 const std::vector<std::string> &ExtraArgs = {}) {
339 llvm::IntrusiveRefCntPtr<FileManager> Files(
340 new FileManager(FileSystemOptions(), InMemoryFileSystem));
342 auto Factory = std::make_unique<SymbolIndexActionFactory>(CollectorOpts);
344 std::vector<std::string>
Args = {
"symbol_collector",
"-fsyntax-only",
346 Args.insert(
Args.end(), ExtraArgs.begin(), ExtraArgs.end());
349 Args.push_back(TestFileName);
351 tooling::ToolInvocation Invocation(
352 Args, Factory->create(), Files.get(),
353 std::make_shared<PCHContainerOperations>());
358 TestHeaderName, 0, llvm::MemoryBuffer::getMemBuffer(HeaderCode)));
360 TestFileName, 0, llvm::MemoryBuffer::getMemBuffer(MainCode)));
362 Symbols = Factory->Collector->takeSymbols();
363 Refs = Factory->Collector->takeRefs();
364 Relations = Factory->Collector->takeRelations();
376 RelationSlab Relations;
380TEST_F(SymbolCollectorTest, CollectSymbols) {
381 const std::string Header = R
"(
388 Foo& operator=(const Foo&);
399 static const int KInt = 2;
400 const char* kStr = "123";
403 void ff() {} // ignore
407 auto LocalLambda = [&](){
408 class ClassInLambda{};
415 using int32_t = int32;
430 runSymbolCollector(Header, "");
432 UnorderedElementsAreArray(
433 {AllOf(qName(
"Foo"), forCodeCompletion(
true)),
434 AllOf(qName(
"Foo::Foo"), forCodeCompletion(
false)),
435 AllOf(qName(
"Foo::Foo"), forCodeCompletion(
false)),
436 AllOf(qName(
"Foo::f"), forCodeCompletion(
false)),
437 AllOf(qName(
"Foo::~Foo"), forCodeCompletion(
false)),
438 AllOf(qName(
"Foo::operator="), forCodeCompletion(
false)),
439 AllOf(qName(
"Foo::Nested"), forCodeCompletion(
false)),
440 AllOf(qName(
"Foo::Nested::f"), forCodeCompletion(
false)),
441 AllOf(qName(
"ClassInLambda"), forCodeCompletion(
false)),
442 AllOf(qName(
"Friend"), forCodeCompletion(
true)),
443 AllOf(qName(
"f1"), forCodeCompletion(
true)),
444 AllOf(qName(
"f2"), forCodeCompletion(
true)),
445 AllOf(qName(
"KInt"), forCodeCompletion(
true)),
446 AllOf(qName(
"kStr"), forCodeCompletion(
true)),
447 AllOf(qName(
"foo"), forCodeCompletion(
true)),
448 AllOf(qName(
"foo::bar"), forCodeCompletion(
true)),
449 AllOf(qName(
"foo::int32"), forCodeCompletion(
true)),
450 AllOf(qName(
"foo::int32_t"), forCodeCompletion(
true)),
451 AllOf(qName(
"foo::v1"), forCodeCompletion(
true)),
452 AllOf(qName(
"foo::bar::v2"), forCodeCompletion(
true)),
453 AllOf(qName(
"foo::v2"), forCodeCompletion(
true)),
454 AllOf(qName(
"foo::baz"), forCodeCompletion(
true))}));
457TEST_F(SymbolCollectorTest, FileLocal) {
458 const std::string Header = R
"(
465 const std::string Main = R
"(
474 runSymbolCollector(Header, Main);
476 UnorderedElementsAre(
477 AllOf(qName("Foo"), visibleOutsideFile()),
478 AllOf(qName(
"bar"), visibleOutsideFile()),
479 AllOf(qName(
"a"), Not(visibleOutsideFile())),
480 AllOf(qName(
"B"), Not(visibleOutsideFile())),
481 AllOf(qName(
"c"), Not(visibleOutsideFile())),
483 AllOf(qName(
"ForwardDecl"), Not(visibleOutsideFile()))));
486TEST_F(SymbolCollectorTest, Template) {
487 Annotations Header(R
"(
488 // Primary template and explicit specialization are indexed, instantiation
490 template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
491 template <> struct $specdecl[[Tmpl]]<int, bool> {};
492 template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {};
493 extern template struct Tmpl<float, bool>;
494 template struct Tmpl<double, bool>;
496 runSymbolCollector(Header.code(), "");
498 UnorderedElementsAre(
499 AllOf(qName(
"Tmpl"), declRange(Header.range()),
500 forCodeCompletion(
true)),
501 AllOf(qName(
"Tmpl"), declRange(Header.range(
"specdecl")),
502 forCodeCompletion(
false)),
503 AllOf(qName(
"Tmpl"), declRange(Header.range(
"partspecdecl")),
504 forCodeCompletion(
false)),
505 AllOf(qName(
"Tmpl::x"), declRange(Header.range(
"xdecl")),
506 forCodeCompletion(
false))));
509TEST_F(SymbolCollectorTest, templateArgs) {
510 Annotations Header(R
"(
511 template <class X> class $barclasstemp[[Bar]] {};
512 template <class T, class U, template<typename> class Z, int Q>
513 struct [[Tmpl]] { T $xdecl[[x]] = 0; };
515 // template-template, non-type and type full spec
516 template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
518 // template-template, non-type and type partial spec
519 template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
521 extern template struct Tmpl<float, bool, Bar, 8>;
523 template struct Tmpl<double, bool, Bar, 2>;
525 template <typename ...> class $fooclasstemp[[Foo]] {};
526 // parameter-packs full spec
527 template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
528 // parameter-packs partial spec
529 template<class T> class $parampackpartial[[Foo]]<T, T> {};
531 template <int ...> class $bazclasstemp[[Baz]] {};
532 // non-type parameter-packs full spec
533 template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
534 // non-type parameter-packs partial spec
535 template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
537 template <template <class> class ...> class $fozclasstemp[[Foz]] {};
538 // template-template parameter-packs full spec
539 template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
540 // template-template parameter-packs partial spec
541 template<template <class> class T>
542 class $parampacktempltemplpartial[[Foz]]<T, T> {};
544 runSymbolCollector(Header.code(), "");
548 Contains(AllOf(qName(
"Tmpl"), templateArgs(
"<int, bool, Bar, 3>"),
549 declRange(Header.range(
"specdecl")),
550 forCodeCompletion(
false))),
551 Contains(AllOf(qName(
"Tmpl"), templateArgs(
"<bool, U, Bar, T>"),
552 declRange(Header.range(
"partspecdecl")),
553 forCodeCompletion(
false))),
554 Contains(AllOf(qName(
"Foo"), templateArgs(
"<Bar<int>, int, double>"),
555 declRange(Header.range(
"parampack")),
556 forCodeCompletion(
false))),
557 Contains(AllOf(qName(
"Foo"), templateArgs(
"<T, T>"),
558 declRange(Header.range(
"parampackpartial")),
559 forCodeCompletion(
false))),
560 Contains(AllOf(qName(
"Baz"), templateArgs(
"<3, 5, 8>"),
561 declRange(Header.range(
"parampacknontype")),
562 forCodeCompletion(
false))),
563 Contains(AllOf(qName(
"Baz"), templateArgs(
"<T, T>"),
564 declRange(Header.range(
"parampacknontypepartial")),
565 forCodeCompletion(
false))),
566 Contains(AllOf(qName(
"Foz"), templateArgs(
"<Bar, Bar>"),
567 declRange(Header.range(
"parampacktempltempl")),
568 forCodeCompletion(
false))),
569 Contains(AllOf(qName(
"Foz"), templateArgs(
"<T, T>"),
570 declRange(Header.range(
"parampacktempltemplpartial")),
571 forCodeCompletion(
false)))));
574TEST_F(SymbolCollectorTest, ObjCRefs) {
575 Annotations Header(R
"(
577 - (void)$talk[[talk]];
578 - (void)$say[[say]]:(id)something;
580 @interface Person (Category)
581 - (void)categoryMethod;
582 - (void)multiArg:(id)a method:(id)b;
586 @implementation Person
587 - (void)$talk[[talk]] {}
588 - (void)$say[[say]]:(id)something {}
591 void fff(Person *p) {
595 [p multiArg:0 method:0];
601 runSymbolCollector(Header.code(), Main.code(),
602 {
"-fblocks",
"-xobjective-c++",
"-Wno-objc-root-class"});
604 haveRanges(Main.ranges(
"talk")))));
606 haveRanges(Main.ranges(
"say")))));
609 ElementsAre(isSpelled()))));
612 ElementsAre(isSpelled()))));
615TEST_F(SymbolCollectorTest, ObjCSymbols) {
616 const std::string Header = R
"(
618 - (void)someMethodName:(void*)name1 lastName:(void*)lName;
621 @implementation Person
622 - (void)someMethodName:(void*)name1 lastName:(void*)lName{
624 ^(int param){ int bar; };
628 @interface Person (MyCategory)
629 - (void)someMethodName2:(void*)name2;
632 @implementation Person (MyCategory)
633 - (void)someMethodName2:(void*)name2 {
639 - (void)someMethodName3:(void*)name3;
643 runSymbolCollector(Header,
"", {
"-fblocks",
"-xobjective-c++"});
645 UnorderedElementsAre(
646 qName(
"Person"), qName(
"Person::someMethodName:lastName:"),
647 AllOf(qName(
"MyCategory"), forCodeCompletion(
false)),
648 qName(
"Person::someMethodName2:"), qName(
"MyProtocol"),
649 qName(
"MyProtocol::someMethodName3:")));
652TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
653 const std::string Header = R
"(
655 @property(nonatomic) int magic;
658 @implementation Container
662 runSymbolCollector(Header,
"", {
"-xobjective-c++"});
663 EXPECT_THAT(
Symbols, Contains(qName(
"Container")));
664 EXPECT_THAT(
Symbols, Contains(qName(
"Container::magic")));
669TEST_F(SymbolCollectorTest, ObjCLocations) {
670 Annotations Header(R
"(
671 // Declared in header, defined in main.
672 @interface $dogdecl[[Dog]]
674 @interface $fluffydecl[[Dog]] (Fluffy)
680 @implementation $dogdef[[Dog]]
682 @implementation $fluffydef[[Dog]] (Fluffy)
684 // Category with no declaration (only implementation).
685 @implementation $ruff[[Dog]] (Ruff)
687 // Implicitly defined interface.
688 @implementation $catdog[[CatDog]]
691 runSymbolCollector(Header.code(), Main.code(),
692 {"-xobjective-c++",
"-Wno-objc-root-class"});
694 UnorderedElementsAre(
695 AllOf(qName(
"Dog"), declRange(Header.range(
"dogdecl")),
696 defRange(Main.range(
"dogdef"))),
697 AllOf(qName(
"Fluffy"), declRange(Header.range(
"fluffydecl")),
698 defRange(Main.range(
"fluffydef"))),
699 AllOf(qName(
"CatDog"), declRange(Main.range(
"catdog")),
700 defRange(Main.range(
"catdog"))),
701 AllOf(qName(
"Ruff"), declRange(Main.range(
"ruff")),
702 defRange(Main.range(
"ruff")))));
705TEST_F(SymbolCollectorTest, ObjCForwardDecls) {
706 Annotations Header(R
"(
707 // Forward declared in header, declared and defined in main.
710 // Never fully declared so Clang latches onto this decl.
711 @class $catdogdecl[[CatDog]];
714 @protocol $barkerdecl[[Barker]]
717 @interface $dogdecl[[Dog]]<Barker>
720 @implementation $dogdef[[Dog]]
723 @implementation $catdogdef[[CatDog]]
726 runSymbolCollector(Header.code(), Main.code(),
727 {"-xobjective-c++",
"-Wno-objc-root-class"});
729 UnorderedElementsAre(
730 AllOf(qName(
"CatDog"), declRange(Header.range(
"catdogdecl")),
731 defRange(Main.range(
"catdogdef"))),
732 AllOf(qName(
"Dog"), declRange(Main.range(
"dogdecl")),
733 defRange(Main.range(
"dogdef"))),
734 AllOf(qName(
"Barker"), declRange(Main.range(
"barkerdecl"))),
735 qName(
"Barker::woof"), qName(
"Dog::woof")));
738TEST_F(SymbolCollectorTest, ObjCClassExtensions) {
739 Annotations Header(R
"(
740 @interface $catdecl[[Cat]]
751 runSymbolCollector(Header.code(), Main.code(),
752 {"-xobjective-c++",
"-Wno-objc-root-class"});
754 UnorderedElementsAre(
755 AllOf(qName(
"Cat"), declRange(Header.range(
"catdecl"))),
756 qName(
"Cat::meow"), qName(
"Cat::pur")));
759TEST_F(SymbolCollectorTest, ObjCFrameworkIncludeHeader) {
761 auto FrameworksPath =
testPath(
"Frameworks/");
762 std::string FrameworkHeader = R
"(
763 __attribute((objc_root_class))
768 testPath("Frameworks/Foundation.framework/Headers/NSObject.h"), 0,
769 llvm::MemoryBuffer::getMemBuffer(FrameworkHeader));
770 std::string PrivateFrameworkHeader = R
"(
771 #import <Foundation/NSObject.h>
773 @interface PrivateClass : NSObject
778 "Frameworks/Foundation.framework/PrivateHeaders/NSObject+Private.h"),
779 0, llvm::MemoryBuffer::getMemBuffer(PrivateFrameworkHeader));
781 std::string Header = R
"(
782 #import <Foundation/NSObject+Private.h>
783 #import <Foundation/NSObject.h>
785 @interface Container : NSObject
788 std::string Main = "";
790 runSymbolCollector(Header, Main, {
"-F", FrameworksPath,
"-xobjective-c++"});
793 UnorderedElementsAre(
794 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/NSObject.h>")),
795 AllOf(qName(
"PrivateClass"),
796 includeHeader(
"<Foundation/NSObject+Private.h>")),
797 AllOf(qName(
"Container"))));
800 std::string UmbrellaHeader = R
"(
801 #import <Foundation/NSObject.h>
804 testPath("Frameworks/Foundation.framework/Headers/Foundation.h"), 0,
805 llvm::MemoryBuffer::getMemBuffer(UmbrellaHeader));
806 std::string PrivateUmbrellaHeader = R
"(
807 #import <Foundation/NSObject+Private.h>
810 testPath("Frameworks/Foundation.framework/PrivateHeaders/"
811 "Foundation_Private.h"),
812 0, llvm::MemoryBuffer::getMemBuffer(PrivateUmbrellaHeader));
813 runSymbolCollector(Header, Main, {
"-F", FrameworksPath,
"-xobjective-c++"});
816 UnorderedElementsAre(
817 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/Foundation.h>")),
818 AllOf(qName(
"PrivateClass"),
819 includeHeader(
"<Foundation/Foundation_Private.h>")),
820 AllOf(qName(
"Container"))));
822 runSymbolCollector(Header, Main,
823 {
"-iframework", FrameworksPath,
"-xobjective-c++"});
826 UnorderedElementsAre(
827 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/Foundation.h>")),
828 AllOf(qName(
"PrivateClass"),
829 includeHeader(
"<Foundation/Foundation_Private.h>")),
830 AllOf(qName(
"Container"))));
833TEST_F(SymbolCollectorTest, Locations) {
834 Annotations Header(R
"cpp(
835 // Declared in header, defined in main.
836 extern int $xdecl[[X]];
837 class $clsdecl[[Cls]];
838 void $printdecl[[print]]();
840 // Declared in header, defined nowhere.
841 extern int $zdecl[[Z]];
846 Annotations Main(R"cpp(
848 class $clsdef[[Cls]] {};
849 void $printdef[[print]]() {}
851 // Declared/defined in main only.
854 runSymbolCollector(Header.code(), Main.code());
856 UnorderedElementsAre(
857 AllOf(qName("X"), declRange(Header.range(
"xdecl")),
858 defRange(Main.range(
"xdef"))),
859 AllOf(qName(
"Cls"), declRange(Header.range(
"clsdecl")),
860 defRange(Main.range(
"clsdef"))),
861 AllOf(qName(
"print"), declRange(Header.range(
"printdecl")),
862 defRange(Main.range(
"printdef"))),
863 AllOf(qName(
"Z"), declRange(Header.range(
"zdecl"))),
864 AllOf(qName(
"foo"), declRange(Header.range(
"foodecl"))),
865 AllOf(qName(
"Y"), declRange(Main.range(
"ydecl")))));
868TEST_F(SymbolCollectorTest, Refs) {
869 Annotations Header(R
"(
870 #define MACRO(X) (X + 1)
879 namespace NS {} // namespace ref is ignored
882 class $bar[[Bar]] {};
884 void $func[[func]]();
891 $foo[[Foo]] foo2 = abc;
892 abc = $macro[[MACRO]](1);
895 Annotations SymbolsOnlyInMainCode(R"(
896 #define FUNC(X) (X+1)
899 static const int c = FUNC(1);
904 runSymbolCollector(Header.code(),
905 (Main.code() + SymbolsOnlyInMainCode.code()).str());
907 haveRanges(Main.ranges(
"foo")))));
909 haveRanges(Main.ranges(
"bar")))));
911 haveRanges(Main.ranges(
"func")))));
914 haveRanges(Main.ranges(
"macro")))));
922 EXPECT_THAT(Refs, Not(Contains(
Pair(
findSymbol(MainSymbols,
"FUNC").
ID, _))));
930 runSymbolCollector(Header.code(),
931 (Main.code() + SymbolsOnlyInMainCode.code()).str());
939TEST_F(SymbolCollectorTest, RefContainers) {
940 Annotations Code(R
"cpp(
941 int $toplevel1[[f1]](int);
943 (void) $ref1a[[f1]](1);
944 auto fptr = &$ref1b[[f1]];
946 int $toplevel2[[v1]] = $ref2[[f1]](2);
947 void f3(int arg = $ref3[[f1]](3));
949 int $classscope1[[member1]] = $ref4[[f1]](4);
950 int $classscope2[[member2]] = 42;
952 constexpr int f4(int x) { return x + 1; }
953 template <int I = $ref5[[f4]](0)> struct S2 {};
954 S2<$ref6[[f4]](0)> v2;
955 S2<$ref7a[[f4]](0)> f5(S2<$ref7b[[f4]](0)>);
957 void $namespacescope1[[f6]]();
958 int $namespacescope2[[v3]];
963 runSymbolCollector(
"", Code.code());
964 auto FindRefWithRange = [&](
Range R) -> std::optional<Ref> {
965 for (
auto &
Entry : Refs) {
966 for (
auto &Ref :
Entry.second) {
967 if (rangesMatch(Ref.Location, R))
974 auto Ref = FindRefWithRange(Code.range(
RangeName));
975 EXPECT_TRUE(
bool(Ref));
976 return Ref->Container;
997 EXPECT_FALSE(
Container(
"classscope1").isNull());
998 EXPECT_FALSE(
Container(
"namespacescope1").isNull());
1009TEST_F(SymbolCollectorTest, MacroRefInHeader) {
1010 Annotations Header(R
"(
1011 #define $foo[[FOO]](X) (X + 1)
1012 #define $bar[[BAR]](X) (X + 2)
1014 // Macro defined multiple times.
1015 #define $ud1[[UD]] 1
1016 int ud_1 = $ud1[[UD]];
1019 #define $ud2[[UD]] 2
1020 int ud_2 = $ud2[[UD]];
1023 // Macros from token concatenations not included.
1024 #define $concat[[CONCAT]](X) X##A()
1025 #define $prepend[[PREPEND]](X) MACRO##X()
1026 #define $macroa[[MACROA]]() 123
1027 int B = $concat[[CONCAT]](MACRO);
1028 int D = $prepend[[PREPEND]](A);
1031 int abc = $foo[[FOO]](1) + $bar[[BAR]]($foo[[FOO]](1));
1039 runSymbolCollector(Header.code(),
"");
1042 haveRanges(Header.ranges(
"foo")))));
1044 haveRanges(Header.ranges(
"bar")))));
1046 EXPECT_THAT(Refs, Contains(
Pair(_, haveRanges(Header.ranges(
"ud1")))));
1047 EXPECT_THAT(Refs, Contains(
Pair(_, haveRanges(Header.ranges(
"ud2")))));
1049 haveRanges(Header.ranges(
"concat")))));
1051 haveRanges(Header.ranges(
"prepend")))));
1053 haveRanges(Header.ranges(
"macroa")))));
1056TEST_F(SymbolCollectorTest, MacroRefWithoutCollectingSymbol) {
1057 Annotations Header(R
"(
1058 #define $foo[[FOO]](X) (X + 1)
1059 int abc = $foo[[FOO]](1);
1064 runSymbolCollector(Header.code(),
"");
1065 EXPECT_THAT(Refs, Contains(
Pair(_, haveRanges(Header.ranges(
"foo")))));
1068TEST_F(SymbolCollectorTest, MacrosWithRefFilter) {
1069 Annotations Header(
"#define $macro[[MACRO]](X) (X + 1)");
1070 Annotations Main(
"void foo() { int x = $macro[[MACRO]](1); }");
1072 runSymbolCollector(Header.code(), Main.code());
1073 EXPECT_THAT(Refs, IsEmpty());
1076TEST_F(SymbolCollectorTest, SpelledReferences) {
1078 llvm::StringRef Header;
1079 llvm::StringRef Main;
1080 llvm::StringRef TargetSymbolName;
1088 struct $spelled[[Foo]] {
1092 $spelled[[Foo]] Variable1;
1093 $implicit[[MACRO]] Variable2;
1105 void f() { Foo $implicit[[f]]; f = $spelled[[Foo]]();}
1122 for (
const auto& T : TestCases) {
1123 SCOPED_TRACE(
T.Header +
"\n---\n" +
T.Main);
1124 Annotations Header(
T.Header);
1125 Annotations Main(
T.Main);
1128 runSymbolCollector(Header.code(), Main.code());
1130 const auto SpelledRanges = Main.ranges(
"spelled");
1131 const auto ImplicitRanges = Main.ranges(
"implicit");
1132 RefSlab::Builder SpelledSlabBuilder, ImplicitSlabBuilder;
1134 for (
const auto &SymbolAndRefs : Refs) {
1135 const auto ID = SymbolAndRefs.first;
1138 for (
const auto &Ref : SymbolAndRefs.second)
1140 SpelledSlabBuilder.insert(
ID, Ref);
1142 ImplicitSlabBuilder.insert(
ID, Ref);
1144 const auto SpelledRefs = std::move(SpelledSlabBuilder).build(),
1145 ImplicitRefs = std::move(ImplicitSlabBuilder).build();
1146 EXPECT_EQ(SpelledRanges.empty(), SpelledRefs.empty());
1147 EXPECT_EQ(ImplicitRanges.empty(), ImplicitRefs.empty());
1148 if (!SpelledRanges.empty())
1149 EXPECT_THAT(SpelledRefs,
1150 Contains(
Pair(TargetID, haveRanges(SpelledRanges))));
1151 if (!ImplicitRanges.empty())
1152 EXPECT_THAT(ImplicitRefs,
1153 Contains(
Pair(TargetID, haveRanges(ImplicitRanges))));
1157TEST_F(SymbolCollectorTest, NameReferences) {
1160 Annotations Header(R
"(
1168 runSymbolCollector(Header.code(), "");
1172 haveRanges(Header.ranges()))));
1175TEST_F(SymbolCollectorTest, RefsOnMacros) {
1180 Annotations Header(R
"(
1183 #define CAT(X, Y) X##Y
1188 TYPE(TYPE([[Foo]])) foo3;
1189 [[CAT]](Fo, o) foo4;
1193 runSymbolCollector(Header.code(), "");
1195 haveRanges(Header.ranges()))));
1198TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
1200 Annotations Header(R
"(
1201 class $Foo[[Foo]] {};
1203 void $Func[[Func]]() {
1211 runSymbolCollector(
"", Header.code());
1214 haveRanges(Header.ranges(
"Foo"))),
1216 haveRanges(Header.ranges(
"Func")))));
1220 runSymbolCollector(
"", Header.code(),
1221 {
"-xobjective-c++-header"});
1222 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"), qName(
"Func")));
1225 haveRanges(Header.ranges(
"Foo"))),
1227 haveRanges(Header.ranges(
"Func")))));
1231 runSymbolCollector(
"", Header.code());
1232 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"), qName(
"Func")));
1235 haveRanges(Header.ranges(
"Foo"))),
1237 haveRanges(Header.ranges(
"Func")))));
1240TEST_F(SymbolCollectorTest, RefsInHeaders) {
1244 Annotations Header(R
"(
1245 #define $macro[[MACRO]](x) (x+1)
1246 class $foo[[Foo]] {};
1248 runSymbolCollector(Header.code(), "");
1250 haveRanges(Header.ranges(
"foo")))));
1252 haveRanges(Header.ranges(
"macro")))));
1255TEST_F(SymbolCollectorTest, BaseOfRelations) {
1256 std::string Header = R
"(
1258 class Derived : public Base {};
1260 runSymbolCollector(Header, "");
1263 EXPECT_THAT(Relations,
1267TEST_F(SymbolCollectorTest, OverrideRelationsSimpleInheritance) {
1268 std::string Header = R
"cpp(
1272 class B : public A {
1273 void foo() override; // A::foo
1276 class C : public B {
1277 void bar() override; // B::bar
1280 void foo() override; // B::foo
1281 void bar() override; // C::bar
1284 runSymbolCollector(Header, "");
1293 std::vector<Relation> Result;
1294 for (
const Relation &R : Relations)
1296 Result.push_back(R);
1297 EXPECT_THAT(Result, UnorderedElementsAre(
1302TEST_F(SymbolCollectorTest, OverrideRelationsMultipleInheritance) {
1303 std::string Header = R
"cpp(
1310 class C : public B {
1311 void bar() override; // B::bar
1314 class D : public A, C {
1315 void foo() override; // A::foo
1316 void bar() override; // C::bar
1317 void baz() override; // C::baz
1320 runSymbolCollector(Header, "");
1329 std::vector<Relation> Result;
1330 for (
const Relation &R : Relations)
1332 Result.push_back(R);
1333 EXPECT_THAT(Result, UnorderedElementsAre(
1338TEST_F(SymbolCollectorTest, CountReferences) {
1339 const std::string Header = R
"(
1343 class Z {}; // not used anywhere
1344 Y* y = nullptr; // used in header doesn't count
1345 #define GLOBAL_Z(name) Z name;
1347 const std::string Main = R
"(
1349 W* w2 = nullptr; // only one usage counts
1352 class Y{}; // definition doesn't count as a reference
1354 GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
1357 runSymbolCollector(Header, Main);
1360 UnorderedElementsAreArray(
1361 {AllOf(qName(
"W"), refCount(1)), AllOf(qName(
"X"), refCount(1)),
1362 AllOf(qName(
"Y"), refCount(0)), AllOf(qName(
"Z"), refCount(0)),
1363 AllOf(qName(
"y"), refCount(0)), AllOf(qName(
"z"), refCount(0)),
1364 AllOf(qName(
"x"), refCount(0)), AllOf(qName(
"w"), refCount(0)),
1365 AllOf(qName(
"w2"), refCount(0)), AllOf(qName(
"V"), refCount(1)),
1366 AllOf(qName(
"v"), refCount(0))}));
1369TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
1370 runSymbolCollector(
"class Foo {};",
"");
1371 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1375TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
1380 runSymbolCollector(
"class Foo {};",
"");
1381 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1385TEST_F(SymbolCollectorTest, UnittestURIScheme) {
1389 runSymbolCollector(
"class Foo {};",
"");
1390 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1391 AllOf(qName(
"Foo"), declURI(
"unittest:///x.h"))));
1394TEST_F(SymbolCollectorTest, IncludeEnums) {
1395 const std::string Header = R
"(
1416 runSymbolCollector(Header, "");
1418 UnorderedElementsAre(
1419 AllOf(qName(
"Red"), forCodeCompletion(
true)),
1420 AllOf(qName(
"Color"), forCodeCompletion(
true)),
1421 AllOf(qName(
"Green"), forCodeCompletion(
true)),
1422 AllOf(qName(
"Color2"), forCodeCompletion(
true)),
1423 AllOf(qName(
"Color2::Yellow"), forCodeCompletion(
true)),
1424 AllOf(qName(
"ns"), forCodeCompletion(
true)),
1425 AllOf(qName(
"ns::Black"), forCodeCompletion(
true)),
1426 AllOf(qName(
"Color3"), forCodeCompletion(
true)),
1427 AllOf(qName(
"Color3::Blue"), forCodeCompletion(
true))));
1430TEST_F(SymbolCollectorTest, NamelessSymbols) {
1431 const std::string Header = R
"(
1436 runSymbolCollector(Header, "");
1437 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"),
1438 qName(
"(anonymous struct)::a")));
1441TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
1443 Annotations Header(R
"(
1445 class name##_Test {};
1447 $expansion[[FF]](abc);
1450 class $spelling[[Test]] {};
1455 runSymbolCollector(Header.code(), "");
1457 UnorderedElementsAre(
1458 AllOf(qName(
"abc_Test"), declRange(Header.range(
"expansion")),
1460 AllOf(qName(
"Test"), declRange(Header.range(
"spelling")),
1464TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
1465 Annotations Header(R
"(
1467 class $expansion[[NAME]] {};
1470 runSymbolCollector(Header.code(), "", {
"-DNAME=name"});
1471 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1472 qName(
"name"), declRange(Header.range(
"expansion")),
1476TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
1477 const std::string Main = R
"(
1493 runSymbolCollector("", Main);
1494 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1495 qName(
"Foo"), qName(
"f1"), qName(
"f2"), qName(
"ff"),
1496 qName(
"foo"), qName(
"foo::Bar"), qName(
"main_f")));
1499TEST_F(SymbolCollectorTest, Documentation) {
1500 const std::string Header = R
"(
1508 runSymbolCollector(Header,
"");
1510 UnorderedElementsAre(
1511 AllOf(qName(
"Foo"), doc(
"doc Foo"), forCodeCompletion(
true)),
1512 AllOf(qName(
"Foo::f"), doc(
""), returnType(
""),
1513 forCodeCompletion(
false))));
1516 runSymbolCollector(Header,
"");
1518 UnorderedElementsAre(
1519 AllOf(qName(
"Foo"), doc(
"doc Foo"), forCodeCompletion(
true)),
1520 AllOf(qName(
"Foo::f"), doc(
"doc f"), returnType(
""),
1521 forCodeCompletion(
false))));
1524TEST_F(SymbolCollectorTest, DocumentationInMain) {
1525 const std::string Header = R
"(
1531 const std::string Main = R
"(
1536 runSymbolCollector(Header, Main);
1538 UnorderedElementsAre(
1539 AllOf(qName(
"Foo"), doc(
"doc Foo"), forCodeCompletion(
true)),
1540 AllOf(qName(
"Foo::f"), doc(
"doc f"), returnType(
""),
1541 forCodeCompletion(
false))));
1544TEST_F(SymbolCollectorTest, DocumentationAtDeclThenDef) {
1545 const std::string Header = R
"(
1551 const std::string Main = R
"(
1556 runSymbolCollector(Header, Main);
1558 UnorderedElementsAre(AllOf(qName(
"Foo")),
1559 AllOf(qName(
"Foo::f"), doc(
"doc f decl"))));
1562TEST_F(SymbolCollectorTest, DocumentationAtDefThenDecl) {
1563 const std::string Header = R
"(
1571 runSymbolCollector(Header,
"" );
1573 UnorderedElementsAre(AllOf(qName(
"f"), doc(
"doc f def"))));
1576TEST_F(SymbolCollectorTest, ClassMembers) {
1577 const std::string Header = R
"(
1586 const std::string Main = R
"(
1590 runSymbolCollector(Header, Main);
1593 UnorderedElementsAre(
1595 AllOf(qName(
"Foo::f"), returnType(
""), forCodeCompletion(
false)),
1596 AllOf(qName(
"Foo::g"), returnType(
""), forCodeCompletion(
false)),
1597 AllOf(qName(
"Foo::sf"), returnType(
""), forCodeCompletion(
false)),
1598 AllOf(qName(
"Foo::ssf"), returnType(
""), forCodeCompletion(
false)),
1599 AllOf(qName(
"Foo::x"), returnType(
""), forCodeCompletion(
false))));
1602TEST_F(SymbolCollectorTest, Scopes) {
1603 const std::string Header = R
"(
1611 runSymbolCollector(Header, "");
1613 UnorderedElementsAre(qName(
"na"), qName(
"na::nb"),
1614 qName(
"na::Foo"), qName(
"na::nb::Bar")));
1617TEST_F(SymbolCollectorTest, ExternC) {
1618 const std::string Header = R
"(
1619 extern "C" { class Foo {}; }
1621 extern "C" { class Bar {}; }
1624 runSymbolCollector(Header, "");
1625 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"na"), qName(
"Foo"),
1629TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1630 const std::string Header = R
"(
1632 inline namespace nb {
1637 // This is still inlined.
1643 runSymbolCollector(Header, "");
1645 UnorderedElementsAre(qName(
"na"), qName(
"na::nb"),
1646 qName(
"na::Foo"), qName(
"na::Bar")));
1649TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1650 const std::string Header = R
"(
1653 int ff(int x, double y) { return 0; }
1656 runSymbolCollector(Header,
"");
1659 UnorderedElementsAre(
1660 qName(
"nx"), AllOf(qName(
"nx::ff"), labeled(
"ff(int x, double y)"),
1661 returnType(
"int"), doc(
"Foo comment."))));
1664TEST_F(SymbolCollectorTest, snippet) {
1665 const std::string Header = R
"(
1668 int ff(int x, double y) { return 0; }
1671 runSymbolCollector(Header, "");
1673 UnorderedElementsAre(
1675 AllOf(qName(
"nx::f"), labeled(
"f()"), snippet(
"f()")),
1676 AllOf(qName(
"nx::ff"), labeled(
"ff(int x, double y)"),
1677 snippet(
"ff(${1:int x}, ${2:double y})"))));
1680TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1682 runSymbolCollector(
"#pragma once\nclass Foo {};",
"");
1683 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1685 EXPECT_THAT(
Symbols.begin()->IncludeHeaders,
1686 UnorderedElementsAre(IncludeHeaderWithRef(
TestHeaderURI, 1u)));
1689TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1695 // Move overloads have special handling.
1696 template <typename _T> T&& move(_T&& __value);
1697 template <typename _I, typename _O> _O move(_I, _I, _O);
1698 template <typename _T, typename _O, typename _I> _O move(
1705 UnorderedElementsAre(
1708 includeHeader(
"<string>")),
1710 AllOf(labeled(
"move(T &&value)"), includeHeader(
"<utility>")),
1711 AllOf(labeled(
"move(I, I, O)"), includeHeader(
"<algorithm>")),
1712 AllOf(labeled(
"move(T &&, O, O, I)"), includeHeader(
"<algorithm>"))));
1715TEST_F(SymbolCollectorTest, IWYUPragma) {
1717 const std::string Header = R
"(
1718 // IWYU pragma: private, include the/good/header.h
1721 runSymbolCollector(Header, "");
1722 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1724 includeHeader(
"\"the/good/header.h\""))));
1727TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1729 const std::string Header = R
"(
1730 // IWYU pragma: private, include "the/good/header.h"
1733 runSymbolCollector(Header, "");
1734 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1736 includeHeader(
"\"the/good/header.h\""))));
1739TEST_F(SymbolCollectorTest, IWYUPragmaExport) {
1741 const std::string Header = R
"cpp(#pragma once
1742 #include "exporter.h"
1744 auto ExporterFile =
testPath(
"exporter.h");
1746 ExporterFile, 0, llvm::MemoryBuffer::getMemBuffer(R
"cpp(#pragma once
1747 #include "private.h" // IWYU pragma: export
1749 auto PrivateFile =
testPath(
"private.h");
1751 PrivateFile, 0, llvm::MemoryBuffer::getMemBuffer(
"class Foo {};"));
1752 runSymbolCollector(Header,
"",
1754 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1760TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1766 auto IncFile =
testPath(
"test.inc");
1769 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1770 runSymbolCollector(
"", R
"cpp(
1771 // Can't use #pragma once in a main file clang doesn't think is a header.
1778 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), declURI(IncURI),
1782TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1786 auto IncFile =
testPath(
"test.inc");
1789 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1790 runSymbolCollector(
"", R
"cpp(
1794 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), declURI(IncURI),
1795 Not(includeHeader()))));
1800TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1803 runSymbolCollector(R
"cpp(
1804 #ifndef HEADER_GUARD_
1805 #define HEADER_GUARD_
1807 // Symbols are seen before the header guard is complete.
1811 #endif // Header guard is recognized here.
1814 EXPECT_THAT(
Symbols, Not(Contains(qName(
"HEADER_GUARD_"))));
1815 EXPECT_THAT(
Symbols, Each(includeHeader()));
1818TEST_F(SymbolCollectorTest, NonModularHeader) {
1820 EXPECT_THAT(TU.headerSymbols(), ElementsAre(includeHeader()));
1823 TU.ImplicitHeaderGuard =
false;
1824 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1829#error "This file isn't safe to include directly"
1833 TU.ExtraArgs.push_back("-DSECRET");
1834 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1837TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1839 Annotations Header(R
"(
1841 // Forward declarations of TagDecls.
1846 // Canonical declarations.
1847 class $cdecl[[C]] {};
1848 struct $sdecl[[S]] {};
1849 union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1851 runSymbolCollector(Header.code(), "");
1854 UnorderedElementsAre(
1856 declRange(Header.range(
"cdecl")), includeHeader(
TestHeaderURI),
1859 declRange(Header.range(
"sdecl")), includeHeader(
TestHeaderURI),
1862 declRange(Header.range(
"udecl")), includeHeader(
TestHeaderURI),
1866 defRange(Header.range(
"xdecl"))),
1869 defRange(Header.range(
"ydecl")))));
1872TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1874 runSymbolCollector(
"#pragma once\nclass X;",
1876 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1881TEST_F(SymbolCollectorTest, UTF16Character) {
1883 Annotations Header(
"class [[pörk]] {};");
1884 runSymbolCollector(Header.code(),
"");
1885 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1886 AllOf(qName(
"pörk"), declRange(Header.range()))));
1889TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1890 Annotations Header(R
"(
1897 friend void $bar[[bar]]() {}
1903 runSymbolCollector(Header.code(), "");
1906 UnorderedElementsAre(
1907 qName(
"nx"), qName(
"nx::X"),
1908 AllOf(qName(
"nx::Y"), declRange(Header.range(
"y"))),
1909 AllOf(qName(
"nx::Z"), declRange(Header.range(
"z"))),
1910 AllOf(qName(
"nx::foo"), declRange(Header.range(
"foo"))),
1911 AllOf(qName(
"nx::bar"), declRange(Header.range(
"bar")))));
1914TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1915 const std::string Header = R
"(
1919 const std::string Main = R
"(
1926 runSymbolCollector(Header, Main);
1927 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), refCount(1)),
1928 AllOf(qName(
"Y"), refCount(1)),
1929 AllOf(qName(
"C"), refCount(0))));
1932TEST_F(SymbolCollectorTest, Origin) {
1934 runSymbolCollector(
"class Foo {};",
"");
1935 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1939 runSymbolCollector(
"#define FOO",
"");
1940 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1944TEST_F(SymbolCollectorTest, CollectMacros) {
1946 Annotations Header(R
"(
1949 #define $mac[[MAC]](x) int x
1950 #define $used[[USED]](y) float y;
1955 Annotations Main(R"(
1956 #define $main[[MAIN]] 1
1961 runSymbolCollector(Header.code(), Main.code());
1964 UnorderedElementsAre(
1965 qName(
"p"), qName(
"t"),
1968 AllOf(labeled(
"MAC(x)"), refCount(0),
1970 declRange(Header.range(
"mac")), visibleOutsideFile()),
1971 AllOf(labeled(
"USED(y)"), refCount(1),
1972 declRange(Header.range(
"used")), visibleOutsideFile()),
1973 AllOf(labeled(
"MAIN"), refCount(0), declRange(Main.range(
"main")),
1974 Not(visibleOutsideFile()))));
1977TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1978 const std::string Header = R
"(
1979 void TestClangc() __attribute__((deprecated("", "")));
1982 runSymbolCollector(Header, "");
1983 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1984 AllOf(qName(
"TestClangc"), deprecated()),
1985 AllOf(qName(
"TestClangd"), Not(deprecated()))));
1988TEST_F(SymbolCollectorTest, implementationDetail) {
1989 const std::string Header = R
"(
1990 #define DECL_NAME(x, y) x##_##y##_Decl
1991 #define DECL(x, y) class DECL_NAME(x, y) {};
1992 DECL(X, Y); // X_Y_Decl
1996 runSymbolCollector(Header, "");
1998 UnorderedElementsAre(
1999 AllOf(qName(
"X_Y_Decl"), implementationDetail()),
2000 AllOf(qName(
"Public"), Not(implementationDetail()))));
2003TEST_F(SymbolCollectorTest, UsingDecl) {
2004 const char *Header = R
"(
2009 runSymbolCollector(Header, "");
2010 EXPECT_THAT(
Symbols, Contains(qName(
"std::foo")));
2013TEST_F(SymbolCollectorTest, CBuiltins) {
2015 const char *Header = R
"(
2016 extern int printf(const char*, ...);
2018 runSymbolCollector(Header, "", {
"-xc"});
2019 EXPECT_THAT(
Symbols, Contains(qName(
"printf")));
2022TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
2023 const char *Header = R
"(
2024 void operator delete(void*)
2025 __attribute__((__externally_visible__));)";
2026 runSymbolCollector(Header, "");
2027 EXPECT_THAT(
Symbols, Contains(qName(
"operator delete")));
2030TEST_F(SymbolCollectorTest, BadUTF8) {
2033 const char *Header =
"int PUNCT = 0;\n"
2034 "/* \xa1 */ int types[] = { /* \xa1 */PUNCT };";
2037 runSymbolCollector(Header,
"");
2038 EXPECT_THAT(
Symbols, Contains(AllOf(qName(
"types"), doc(
"\xef\xbf\xbd "))));
2039 EXPECT_THAT(
Symbols, Contains(qName(
"PUNCT")));
2044TEST_F(SymbolCollectorTest, MacrosInHeaders) {
2047 runSymbolCollector(
"",
"#define X");
2049 UnorderedElementsAre(AllOf(qName(
"X"), forCodeCompletion(
true))));
2053TEST_F(SymbolCollectorTest, UndefOfModuleMacro) {
2055 TU.AdditionalFiles["bar.h"] = R
"cpp(
2059 TU.AdditionalFiles["foo.h"] =
"#define X 1";
2060 TU.AdditionalFiles[
"module.modulemap"] = R
"cpp(
2066 TU.ExtraArgs.push_back("-fmodules");
2067 TU.ExtraArgs.push_back(
"-fmodule-map-file=" +
testPath(
"module.modulemap"));
2068 TU.OverlayRealFileSystemForModules =
true;
2073 EXPECT_THAT(TU.headerSymbols(), Not(Contains(qName(
"X"))));
2076TEST_F(SymbolCollectorTest, NoCrashOnObjCMethodCStyleParam) {
2079 - (void)fun:(bool)foo, bool bar;
2082 TU.ExtraArgs.push_back("-xobjective-c++");
2086 EXPECT_THAT(TU.headerSymbols(),
2087 UnorderedElementsAre(qName(
"Foo"), qName(
"Foo::fun:")));
2090TEST_F(SymbolCollectorTest, Reserved) {
2091 const char *Header = R
"cpp(
2094 namespace _X { int secret; }
2098 runSymbolCollector(Header,
"");
2099 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"__foo"), qName(
"_X"),
2100 qName(
"_X::secret")));
2103 runSymbolCollector(Header,
"");
2104 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"__foo"), qName(
"_X"),
2105 qName(
"_X::secret")));
2110 runSymbolCollector(
"#pragma GCC system_header\n" + std::string(Header),
"");
2111 EXPECT_THAT(
Symbols, IsEmpty());
2114TEST_F(SymbolCollectorTest, ReservedSymbolInIntrinsicHeader) {
2115 const char *Header = R
"cpp(
2124 runSymbolCollector(
"#pragma GCC system_header\n" + std::string(Header),
"");
2125 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"__foo")));
2128TEST_F(SymbolCollectorTest, Concepts) {
2129 const char *Header = R
"cpp(
2131 concept A = sizeof(T) <= 8;
2133 runSymbolCollector("", Header, {
"-std=c++20"});
2135 UnorderedElementsAre(AllOf(
2136 qName(
"A"), hasKind(clang::index::SymbolKind::Concept))));
2139TEST_F(SymbolCollectorTest, IncludeHeaderForwardDecls) {
2141 const std::string Header = R
"cpp(#pragma once
2145 auto FullFile =
testPath(
"full.h");
2147 llvm::MemoryBuffer::getMemBuffer(R
"cpp(
2149struct Foo {};)cpp"));
2150 runSymbolCollector(Header, "",
2152 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
llvm::SmallString< 256U > Name
CharSourceRange Range
SourceRange for the file name.
std::string TestHeaderName
SymbolCollector::Options COpts
std::string TestHeaderURI
llvm::IntrusiveRefCntPtr< llvm::vfs::InMemoryFileSystem > InMemoryFileSystem
SymbolCollector::Options CollectorOpts
std::unique_ptr< CompilerInvocation > CI
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.
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile)
const NamedDecl & findDecl(ParsedAST &AST, llvm::StringRef QName)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
MATCHER_P2(hasFlag, Flag, Path, "")
static const char * toString(OffsetEncoding OE)
std::string testPath(PathRef File, llvm::sys::path::Style Style)
const NamedDecl & findUnqualifiedDecl(ParsedAST &AST, llvm::StringRef Name)
const Symbol & findSymbol(const SymbolSlab &Slab, llvm::StringRef QName)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Some operations such as code completion produce a set of candidates.
bool CollectMacro
Collect macros.
std::string FallbackDir
When symbol paths cannot be resolved to absolute paths (e.g.
RefKind RefFilter
The symbol ref kinds that will be collected.
bool StoreAllDocumentation
If set to true, SymbolCollector will collect doc for all symbols.
bool CollectMainFileRefs
Collect references to main-file symbols.
bool RefsInHeaders
If set to true, SymbolCollector will collect all refs (from main file and included headers); otherwis...
bool CollectReserved
Collect symbols with reserved names, like __Vector_base.
@ IndexedForCodeCompletion
Whether or not this symbol is meant to be used for the code completion.
@ Deprecated
Indicates if the symbol is deprecated.
@ ImplementationDetail
Symbol is an implementation detail.
@ VisibleOutsideFile
Symbol is visible to other files (not e.g. a static helper function).
SymbolID ID
The ID of the symbol.
SymbolOrigin Origin
Where this symbol came from. Usually an index provides a constant value.
static TestTU withHeaderCode(llvm::StringRef HeaderCode)
SymbolSlab headerSymbols() const
static TestTU withCode(llvm::StringRef Code)