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!
211 EXPECT_TRUE(shouldCollect("nx::TopLevel"));
212 EXPECT_TRUE(shouldCollect(
"nx::Kind::KIND_OK"));
213 EXPECT_TRUE(shouldCollect(
"nx::Kind"));
215 EXPECT_FALSE(shouldCollect(
"nx::Top_Level"));
216 EXPECT_FALSE(shouldCollect(
"nx::Kind::Kind_Not_Ok"));
219TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
220 HeaderName =
"f.proto.h";
229 EXPECT_TRUE(shouldCollect("nx::Top_Level"));
230 EXPECT_TRUE(shouldCollect(
"nx::Kind_Fine"));
233class SymbolIndexActionFactory :
public tooling::FrontendActionFactory {
235 SymbolIndexActionFactory(SymbolCollector::Options COpts)
238 std::unique_ptr<FrontendAction> create()
override {
239 class IndexAction :
public ASTFrontendAction {
241 IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
242 const index::IndexingOptions &Opts,
243 std::shared_ptr<include_cleaner::PragmaIncludes> PI)
244 : DataConsumer(std::move(DataConsumer)), Opts(Opts),
247 std::unique_ptr<ASTConsumer>
248 CreateASTConsumer(CompilerInstance &
CI, llvm::StringRef InFile)
override {
250 return createIndexingASTConsumer(DataConsumer, Opts,
251 CI.getPreprocessorPtr());
254 bool BeginInvocation(CompilerInstance &
CI)
override {
256 CI.getLangOpts().CommentOpts.ParseAllComments =
true;
261 std::shared_ptr<index::IndexDataConsumer> DataConsumer;
262 index::IndexingOptions Opts;
263 std::shared_ptr<include_cleaner::PragmaIncludes> PI;
265 index::IndexingOptions IndexOpts;
266 IndexOpts.SystemSymbolFilter =
267 index::IndexingOptions::SystemSymbolFilterKind::All;
268 IndexOpts.IndexFunctionLocals =
true;
269 std::shared_ptr<include_cleaner::PragmaIncludes> PI =
270 std::make_shared<include_cleaner::PragmaIncludes>();
271 COpts.PragmaIncludes = PI.get();
272 Collector = std::make_shared<SymbolCollector>(COpts);
273 return std::make_unique<IndexAction>(Collector, std::move(IndexOpts),
277 std::shared_ptr<SymbolCollector> Collector;
278 SymbolCollector::Options
COpts;
281class SymbolCollectorTest :
public ::testing::Test {
283 SymbolCollectorTest()
293 bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode,
294 const std::vector<std::string> &ExtraArgs = {}) {
295 llvm::IntrusiveRefCntPtr<FileManager> Files(
296 new FileManager(FileSystemOptions(), InMemoryFileSystem));
298 auto Factory = std::make_unique<SymbolIndexActionFactory>(CollectorOpts);
300 std::vector<std::string>
Args = {
"symbol_collector",
"-fsyntax-only",
302 Args.insert(
Args.end(), ExtraArgs.begin(), ExtraArgs.end());
305 Args.push_back(TestFileName);
307 tooling::ToolInvocation Invocation(
308 Args, Factory->create(), Files.get(),
309 std::make_shared<PCHContainerOperations>());
314 TestHeaderName, 0, llvm::MemoryBuffer::getMemBuffer(HeaderCode)));
316 TestFileName, 0, llvm::MemoryBuffer::getMemBuffer(MainCode)));
318 Symbols = Factory->Collector->takeSymbols();
319 Refs = Factory->Collector->takeRefs();
320 Relations = Factory->Collector->takeRelations();
332 RelationSlab Relations;
336TEST_F(SymbolCollectorTest, CollectSymbols) {
337 const std::string Header = R
"(
344 Foo& operator=(const Foo&);
355 static const int KInt = 2;
356 const char* kStr = "123";
359 void ff() {} // ignore
363 auto LocalLambda = [&](){
364 class ClassInLambda{};
371 using int32_t = int32;
386 runSymbolCollector(Header, "");
388 UnorderedElementsAreArray(
389 {AllOf(qName(
"Foo"), forCodeCompletion(
true)),
390 AllOf(qName(
"Foo::Foo"), forCodeCompletion(
false)),
391 AllOf(qName(
"Foo::Foo"), forCodeCompletion(
false)),
392 AllOf(qName(
"Foo::f"), forCodeCompletion(
false)),
393 AllOf(qName(
"Foo::~Foo"), forCodeCompletion(
false)),
394 AllOf(qName(
"Foo::operator="), forCodeCompletion(
false)),
395 AllOf(qName(
"Foo::Nested"), forCodeCompletion(
false)),
396 AllOf(qName(
"Foo::Nested::f"), forCodeCompletion(
false)),
397 AllOf(qName(
"ClassInLambda"), forCodeCompletion(
false)),
398 AllOf(qName(
"Friend"), forCodeCompletion(
true)),
399 AllOf(qName(
"f1"), forCodeCompletion(
true)),
400 AllOf(qName(
"f2"), forCodeCompletion(
true)),
401 AllOf(qName(
"KInt"), forCodeCompletion(
true)),
402 AllOf(qName(
"kStr"), forCodeCompletion(
true)),
403 AllOf(qName(
"foo"), forCodeCompletion(
true)),
404 AllOf(qName(
"foo::bar"), forCodeCompletion(
true)),
405 AllOf(qName(
"foo::int32"), forCodeCompletion(
true)),
406 AllOf(qName(
"foo::int32_t"), forCodeCompletion(
true)),
407 AllOf(qName(
"foo::v1"), forCodeCompletion(
true)),
408 AllOf(qName(
"foo::bar::v2"), forCodeCompletion(
true)),
409 AllOf(qName(
"foo::v2"), forCodeCompletion(
true)),
410 AllOf(qName(
"foo::baz"), forCodeCompletion(
true))}));
413TEST_F(SymbolCollectorTest, FileLocal) {
414 const std::string Header = R
"(
421 const std::string Main = R
"(
430 runSymbolCollector(Header, Main);
432 UnorderedElementsAre(
433 AllOf(qName("Foo"), visibleOutsideFile()),
434 AllOf(qName(
"bar"), visibleOutsideFile()),
435 AllOf(qName(
"a"), Not(visibleOutsideFile())),
436 AllOf(qName(
"B"), Not(visibleOutsideFile())),
437 AllOf(qName(
"c"), Not(visibleOutsideFile())),
439 AllOf(qName(
"ForwardDecl"), Not(visibleOutsideFile()))));
442TEST_F(SymbolCollectorTest, Template) {
443 Annotations Header(R
"(
444 // Primary template and explicit specialization are indexed, instantiation
446 template <class T, class U> struct [[Tmpl]] {T $xdecl[[x]] = 0;};
447 template <> struct $specdecl[[Tmpl]]<int, bool> {};
448 template <class U> struct $partspecdecl[[Tmpl]]<bool, U> {};
449 extern template struct Tmpl<float, bool>;
450 template struct Tmpl<double, bool>;
452 runSymbolCollector(Header.code(), "");
454 UnorderedElementsAre(
455 AllOf(qName(
"Tmpl"), declRange(Header.range()),
456 forCodeCompletion(
true)),
457 AllOf(qName(
"Tmpl"), declRange(Header.range(
"specdecl")),
458 forCodeCompletion(
false)),
459 AllOf(qName(
"Tmpl"), declRange(Header.range(
"partspecdecl")),
460 forCodeCompletion(
false)),
461 AllOf(qName(
"Tmpl::x"), declRange(Header.range(
"xdecl")),
462 forCodeCompletion(
false))));
465TEST_F(SymbolCollectorTest, templateArgs) {
466 Annotations Header(R
"(
467 template <class X> class $barclasstemp[[Bar]] {};
468 template <class T, class U, template<typename> class Z, int Q>
469 struct [[Tmpl]] { T $xdecl[[x]] = 0; };
471 // template-template, non-type and type full spec
472 template <> struct $specdecl[[Tmpl]]<int, bool, Bar, 3> {};
474 // template-template, non-type and type partial spec
475 template <class U, int T> struct $partspecdecl[[Tmpl]]<bool, U, Bar, T> {};
477 extern template struct Tmpl<float, bool, Bar, 8>;
479 template struct Tmpl<double, bool, Bar, 2>;
481 template <typename ...> class $fooclasstemp[[Foo]] {};
482 // parameter-packs full spec
483 template<> class $parampack[[Foo]]<Bar<int>, int, double> {};
484 // parameter-packs partial spec
485 template<class T> class $parampackpartial[[Foo]]<T, T> {};
487 template <int ...> class $bazclasstemp[[Baz]] {};
488 // non-type parameter-packs full spec
489 template<> class $parampacknontype[[Baz]]<3, 5, 8> {};
490 // non-type parameter-packs partial spec
491 template<int T> class $parampacknontypepartial[[Baz]]<T, T> {};
493 template <template <class> class ...> class $fozclasstemp[[Foz]] {};
494 // template-template parameter-packs full spec
495 template<> class $parampacktempltempl[[Foz]]<Bar, Bar> {};
496 // template-template parameter-packs partial spec
497 template<template <class> class T>
498 class $parampacktempltemplpartial[[Foz]]<T, T> {};
500 runSymbolCollector(Header.code(), "");
504 Contains(AllOf(qName(
"Tmpl"), templateArgs(
"<int, bool, Bar, 3>"),
505 declRange(Header.range(
"specdecl")),
506 forCodeCompletion(
false))),
507 Contains(AllOf(qName(
"Tmpl"), templateArgs(
"<bool, U, Bar, T>"),
508 declRange(Header.range(
"partspecdecl")),
509 forCodeCompletion(
false))),
510 Contains(AllOf(qName(
"Foo"), templateArgs(
"<Bar<int>, int, double>"),
511 declRange(Header.range(
"parampack")),
512 forCodeCompletion(
false))),
513 Contains(AllOf(qName(
"Foo"), templateArgs(
"<T, T>"),
514 declRange(Header.range(
"parampackpartial")),
515 forCodeCompletion(
false))),
516 Contains(AllOf(qName(
"Baz"), templateArgs(
"<3, 5, 8>"),
517 declRange(Header.range(
"parampacknontype")),
518 forCodeCompletion(
false))),
519 Contains(AllOf(qName(
"Baz"), templateArgs(
"<T, T>"),
520 declRange(Header.range(
"parampacknontypepartial")),
521 forCodeCompletion(
false))),
522 Contains(AllOf(qName(
"Foz"), templateArgs(
"<Bar, Bar>"),
523 declRange(Header.range(
"parampacktempltempl")),
524 forCodeCompletion(
false))),
525 Contains(AllOf(qName(
"Foz"), templateArgs(
"<T, T>"),
526 declRange(Header.range(
"parampacktempltemplpartial")),
527 forCodeCompletion(
false)))));
530TEST_F(SymbolCollectorTest, ObjCRefs) {
531 Annotations Header(R
"(
533 - (void)$talk[[talk]];
534 - (void)$say[[say]]:(id)something;
536 @interface Person (Category)
537 - (void)categoryMethod;
538 - (void)multiArg:(id)a method:(id)b;
542 @implementation Person
543 - (void)$talk[[talk]] {}
544 - (void)$say[[say]]:(id)something {}
547 void fff(Person *p) {
551 [p multiArg:0 method:0];
557 runSymbolCollector(Header.code(), Main.code(),
558 {
"-fblocks",
"-xobjective-c++",
"-Wno-objc-root-class"});
560 haveRanges(Main.ranges(
"talk")))));
562 haveRanges(Main.ranges(
"say")))));
565 ElementsAre(isSpelled()))));
568 ElementsAre(isSpelled()))));
571TEST_F(SymbolCollectorTest, ObjCSymbols) {
572 const std::string Header = R
"(
574 - (void)someMethodName:(void*)name1 lastName:(void*)lName;
577 @implementation Person
578 - (void)someMethodName:(void*)name1 lastName:(void*)lName{
580 ^(int param){ int bar; };
584 @interface Person (MyCategory)
585 - (void)someMethodName2:(void*)name2;
588 @implementation Person (MyCategory)
589 - (void)someMethodName2:(void*)name2 {
595 - (void)someMethodName3:(void*)name3;
599 runSymbolCollector(Header,
"", {
"-fblocks",
"-xobjective-c++"});
601 UnorderedElementsAre(
602 qName(
"Person"), qName(
"Person::someMethodName:lastName:"),
603 AllOf(qName(
"MyCategory"), forCodeCompletion(
false)),
604 qName(
"Person::someMethodName2:"), qName(
"MyProtocol"),
605 qName(
"MyProtocol::someMethodName3:")));
608TEST_F(SymbolCollectorTest, ObjCPropertyImpl) {
609 const std::string Header = R
"(
611 @property(nonatomic) int magic;
614 @implementation Container
618 runSymbolCollector(Header,
"", {
"-xobjective-c++"});
619 EXPECT_THAT(
Symbols, Contains(qName(
"Container")));
620 EXPECT_THAT(
Symbols, Contains(qName(
"Container::magic")));
625TEST_F(SymbolCollectorTest, ObjCLocations) {
626 Annotations Header(R
"(
627 // Declared in header, defined in main.
628 @interface $dogdecl[[Dog]]
630 @interface $fluffydecl[[Dog]] (Fluffy)
636 @implementation $dogdef[[Dog]]
638 @implementation $fluffydef[[Dog]] (Fluffy)
640 // Category with no declaration (only implementation).
641 @implementation $ruff[[Dog]] (Ruff)
643 // Implicitly defined interface.
644 @implementation $catdog[[CatDog]]
647 runSymbolCollector(Header.code(), Main.code(),
648 {"-xobjective-c++",
"-Wno-objc-root-class"});
650 UnorderedElementsAre(
651 AllOf(qName(
"Dog"), declRange(Header.range(
"dogdecl")),
652 defRange(Main.range(
"dogdef"))),
653 AllOf(qName(
"Fluffy"), declRange(Header.range(
"fluffydecl")),
654 defRange(Main.range(
"fluffydef"))),
655 AllOf(qName(
"CatDog"), declRange(Main.range(
"catdog")),
656 defRange(Main.range(
"catdog"))),
657 AllOf(qName(
"Ruff"), declRange(Main.range(
"ruff")),
658 defRange(Main.range(
"ruff")))));
661TEST_F(SymbolCollectorTest, ObjCForwardDecls) {
662 Annotations Header(R
"(
663 // Forward declared in header, declared and defined in main.
666 // Never fully declared so Clang latches onto this decl.
667 @class $catdogdecl[[CatDog]];
670 @protocol $barkerdecl[[Barker]]
673 @interface $dogdecl[[Dog]]<Barker>
676 @implementation $dogdef[[Dog]]
679 @implementation $catdogdef[[CatDog]]
682 runSymbolCollector(Header.code(), Main.code(),
683 {"-xobjective-c++",
"-Wno-objc-root-class"});
685 UnorderedElementsAre(
686 AllOf(qName(
"CatDog"), declRange(Header.range(
"catdogdecl")),
687 defRange(Main.range(
"catdogdef"))),
688 AllOf(qName(
"Dog"), declRange(Main.range(
"dogdecl")),
689 defRange(Main.range(
"dogdef"))),
690 AllOf(qName(
"Barker"), declRange(Main.range(
"barkerdecl"))),
691 qName(
"Barker::woof"), qName(
"Dog::woof")));
694TEST_F(SymbolCollectorTest, ObjCClassExtensions) {
695 Annotations Header(R
"(
696 @interface $catdecl[[Cat]]
707 runSymbolCollector(Header.code(), Main.code(),
708 {"-xobjective-c++",
"-Wno-objc-root-class"});
710 UnorderedElementsAre(
711 AllOf(qName(
"Cat"), declRange(Header.range(
"catdecl"))),
712 qName(
"Cat::meow"), qName(
"Cat::pur")));
715TEST_F(SymbolCollectorTest, ObjCFrameworkIncludeHeader) {
717 auto FrameworksPath =
testPath(
"Frameworks/");
718 std::string FrameworkHeader = R
"(
719 __attribute((objc_root_class))
724 testPath("Frameworks/Foundation.framework/Headers/NSObject.h"), 0,
725 llvm::MemoryBuffer::getMemBuffer(FrameworkHeader));
726 std::string PrivateFrameworkHeader = R
"(
727 #import <Foundation/NSObject.h>
729 @interface PrivateClass : NSObject
734 "Frameworks/Foundation.framework/PrivateHeaders/NSObject+Private.h"),
735 0, llvm::MemoryBuffer::getMemBuffer(PrivateFrameworkHeader));
737 std::string Header = R
"(
738 #import <Foundation/NSObject+Private.h>
739 #import <Foundation/NSObject.h>
741 @interface Container : NSObject
744 std::string Main = "";
746 runSymbolCollector(Header, Main, {
"-F", FrameworksPath,
"-xobjective-c++"});
749 UnorderedElementsAre(
750 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/NSObject.h>")),
751 AllOf(qName(
"PrivateClass"),
752 includeHeader(
"<Foundation/NSObject+Private.h>")),
753 AllOf(qName(
"Container"))));
756 std::string UmbrellaHeader = R
"(
757 #import <Foundation/NSObject.h>
760 testPath("Frameworks/Foundation.framework/Headers/Foundation.h"), 0,
761 llvm::MemoryBuffer::getMemBuffer(UmbrellaHeader));
762 std::string PrivateUmbrellaHeader = R
"(
763 #import <Foundation/NSObject+Private.h>
766 testPath("Frameworks/Foundation.framework/PrivateHeaders/"
767 "Foundation_Private.h"),
768 0, llvm::MemoryBuffer::getMemBuffer(PrivateUmbrellaHeader));
769 runSymbolCollector(Header, Main, {
"-F", FrameworksPath,
"-xobjective-c++"});
772 UnorderedElementsAre(
773 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/Foundation.h>")),
774 AllOf(qName(
"PrivateClass"),
775 includeHeader(
"<Foundation/Foundation_Private.h>")),
776 AllOf(qName(
"Container"))));
778 runSymbolCollector(Header, Main,
779 {
"-iframework", FrameworksPath,
"-xobjective-c++"});
782 UnorderedElementsAre(
783 AllOf(qName(
"NSObject"), includeHeader(
"<Foundation/Foundation.h>")),
784 AllOf(qName(
"PrivateClass"),
785 includeHeader(
"<Foundation/Foundation_Private.h>")),
786 AllOf(qName(
"Container"))));
789TEST_F(SymbolCollectorTest, Locations) {
790 Annotations Header(R
"cpp(
791 // Declared in header, defined in main.
792 extern int $xdecl[[X]];
793 class $clsdecl[[Cls]];
794 void $printdecl[[print]]();
796 // Declared in header, defined nowhere.
797 extern int $zdecl[[Z]];
802 Annotations Main(R"cpp(
804 class $clsdef[[Cls]] {};
805 void $printdef[[print]]() {}
807 // Declared/defined in main only.
810 runSymbolCollector(Header.code(), Main.code());
812 UnorderedElementsAre(
813 AllOf(qName("X"), declRange(Header.range(
"xdecl")),
814 defRange(Main.range(
"xdef"))),
815 AllOf(qName(
"Cls"), declRange(Header.range(
"clsdecl")),
816 defRange(Main.range(
"clsdef"))),
817 AllOf(qName(
"print"), declRange(Header.range(
"printdecl")),
818 defRange(Main.range(
"printdef"))),
819 AllOf(qName(
"Z"), declRange(Header.range(
"zdecl"))),
820 AllOf(qName(
"foo"), declRange(Header.range(
"foodecl"))),
821 AllOf(qName(
"Y"), declRange(Main.range(
"ydecl")))));
824TEST_F(SymbolCollectorTest, Refs) {
825 Annotations Header(R
"(
826 #define MACRO(X) (X + 1)
835 namespace NS {} // namespace ref is ignored
838 class $bar[[Bar]] {};
840 void $func[[func]]();
847 $foo[[Foo]] foo2 = abc;
848 abc = $macro[[MACRO]](1);
851 Annotations SymbolsOnlyInMainCode(R"(
852 #define FUNC(X) (X+1)
855 static const int c = FUNC(1);
860 runSymbolCollector(Header.code(),
861 (Main.code() + SymbolsOnlyInMainCode.code()).str());
863 haveRanges(Main.ranges(
"foo")))));
865 haveRanges(Main.ranges(
"bar")))));
867 haveRanges(Main.ranges(
"func")))));
870 haveRanges(Main.ranges(
"macro")))));
875 EXPECT_THAT(Refs, Contains(Pair(
findSymbol(MainSymbols,
"a").
ID, _)));
876 EXPECT_THAT(Refs, Contains(Pair(
findSymbol(MainSymbols,
"b").
ID, _)));
877 EXPECT_THAT(Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"c").
ID, _))));
878 EXPECT_THAT(Refs, Not(Contains(Pair(
findSymbol(MainSymbols,
"FUNC").
ID, _))));
886 runSymbolCollector(Header.code(),
887 (Main.code() + SymbolsOnlyInMainCode.code()).str());
895TEST_F(SymbolCollectorTest, RefContainers) {
896 Annotations
Code(R
"cpp(
897 int $toplevel1[[f1]](int);
899 (void) $ref1a[[f1]](1);
900 auto fptr = &$ref1b[[f1]];
902 int $toplevel2[[v1]] = $ref2[[f1]](2);
903 void f3(int arg = $ref3[[f1]](3));
905 int $classscope1[[member1]] = $ref4[[f1]](4);
906 int $classscope2[[member2]] = 42;
908 constexpr int f4(int x) { return x + 1; }
909 template <int I = $ref5[[f4]](0)> struct S2 {};
910 S2<$ref6[[f4]](0)> v2;
911 S2<$ref7a[[f4]](0)> f5(S2<$ref7b[[f4]](0)>);
913 void $namespacescope1[[f6]]();
914 int $namespacescope2[[v3]];
919 runSymbolCollector(
"",
Code.code());
920 auto FindRefWithRange = [&](
Range R) -> std::optional<Ref> {
921 for (
auto &
Entry : Refs) {
922 for (
auto &Ref :
Entry.second) {
923 if (rangesMatch(Ref.Location, R))
931 EXPECT_TRUE(
bool(Ref));
932 return Ref->Container;
953 EXPECT_FALSE(
Container(
"classscope1").isNull());
954 EXPECT_FALSE(
Container(
"namespacescope1").isNull());
965TEST_F(SymbolCollectorTest, MacroRefInHeader) {
966 Annotations Header(R
"(
967 #define $foo[[FOO]](X) (X + 1)
968 #define $bar[[BAR]](X) (X + 2)
970 // Macro defined multiple times.
972 int ud_1 = $ud1[[UD]];
976 int ud_2 = $ud2[[UD]];
979 // Macros from token concatenations not included.
980 #define $concat[[CONCAT]](X) X##A()
981 #define $prepend[[PREPEND]](X) MACRO##X()
982 #define $macroa[[MACROA]]() 123
983 int B = $concat[[CONCAT]](MACRO);
984 int D = $prepend[[PREPEND]](A);
987 int abc = $foo[[FOO]](1) + $bar[[BAR]]($foo[[FOO]](1));
995 runSymbolCollector(Header.code(),
"");
998 haveRanges(Header.ranges(
"foo")))));
1000 haveRanges(Header.ranges(
"bar")))));
1002 EXPECT_THAT(Refs, Contains(Pair(_, haveRanges(Header.ranges(
"ud1")))));
1003 EXPECT_THAT(Refs, Contains(Pair(_, haveRanges(Header.ranges(
"ud2")))));
1005 haveRanges(Header.ranges(
"concat")))));
1007 haveRanges(Header.ranges(
"prepend")))));
1009 haveRanges(Header.ranges(
"macroa")))));
1012TEST_F(SymbolCollectorTest, MacroRefWithoutCollectingSymbol) {
1013 Annotations Header(R
"(
1014 #define $foo[[FOO]](X) (X + 1)
1015 int abc = $foo[[FOO]](1);
1020 runSymbolCollector(Header.code(),
"");
1021 EXPECT_THAT(Refs, Contains(Pair(_, haveRanges(Header.ranges(
"foo")))));
1024TEST_F(SymbolCollectorTest, MacrosWithRefFilter) {
1025 Annotations Header(
"#define $macro[[MACRO]](X) (X + 1)");
1026 Annotations Main(
"void foo() { int x = $macro[[MACRO]](1); }");
1028 runSymbolCollector(Header.code(), Main.code());
1029 EXPECT_THAT(Refs, IsEmpty());
1032TEST_F(SymbolCollectorTest, SpelledReferences) {
1034 llvm::StringRef Header;
1035 llvm::StringRef Main;
1036 llvm::StringRef TargetSymbolName;
1044 struct $spelled[[Foo]] {
1048 $spelled[[Foo]] Variable1;
1049 $implicit[[MACRO]] Variable2;
1061 void f() { Foo $implicit[[f]]; f = $spelled[[Foo]]();}
1078 for (
const auto& T : TestCases) {
1079 SCOPED_TRACE(
T.Header +
"\n---\n" +
T.Main);
1080 Annotations Header(
T.Header);
1081 Annotations Main(
T.Main);
1084 runSymbolCollector(Header.code(), Main.code());
1086 const auto SpelledRanges = Main.ranges(
"spelled");
1087 const auto ImplicitRanges = Main.ranges(
"implicit");
1088 RefSlab::Builder SpelledSlabBuilder, ImplicitSlabBuilder;
1090 for (
const auto &SymbolAndRefs : Refs) {
1091 const auto ID = SymbolAndRefs.first;
1094 for (
const auto &Ref : SymbolAndRefs.second)
1096 SpelledSlabBuilder.insert(
ID, Ref);
1098 ImplicitSlabBuilder.insert(
ID, Ref);
1100 const auto SpelledRefs = std::move(SpelledSlabBuilder).build(),
1101 ImplicitRefs = std::move(ImplicitSlabBuilder).build();
1102 EXPECT_EQ(SpelledRanges.empty(), SpelledRefs.empty());
1103 EXPECT_EQ(ImplicitRanges.empty(), ImplicitRefs.empty());
1104 if (!SpelledRanges.empty())
1105 EXPECT_THAT(SpelledRefs,
1106 Contains(Pair(TargetID, haveRanges(SpelledRanges))));
1107 if (!ImplicitRanges.empty())
1108 EXPECT_THAT(ImplicitRefs,
1109 Contains(Pair(TargetID, haveRanges(ImplicitRanges))));
1113TEST_F(SymbolCollectorTest, NameReferences) {
1116 Annotations Header(R
"(
1124 runSymbolCollector(Header.code(), "");
1128 haveRanges(Header.ranges()))));
1131TEST_F(SymbolCollectorTest, RefsOnMacros) {
1136 Annotations Header(R
"(
1139 #define CAT(X, Y) X##Y
1144 TYPE(TYPE([[Foo]])) foo3;
1145 [[CAT]](Fo, o) foo4;
1149 runSymbolCollector(Header.code(), "");
1151 haveRanges(Header.ranges()))));
1154TEST_F(SymbolCollectorTest, HeaderAsMainFile) {
1156 Annotations Header(R
"(
1157 class $Foo[[Foo]] {};
1159 void $Func[[Func]]() {
1167 runSymbolCollector(
"", Header.code());
1170 haveRanges(Header.ranges(
"Foo"))),
1172 haveRanges(Header.ranges(
"Func")))));
1176 runSymbolCollector(
"", Header.code(),
1177 {
"-xobjective-c++-header"});
1178 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"), qName(
"Func")));
1181 haveRanges(Header.ranges(
"Foo"))),
1183 haveRanges(Header.ranges(
"Func")))));
1187 runSymbolCollector(
"", Header.code());
1188 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"), qName(
"Func")));
1191 haveRanges(Header.ranges(
"Foo"))),
1193 haveRanges(Header.ranges(
"Func")))));
1196TEST_F(SymbolCollectorTest, RefsInHeaders) {
1200 Annotations Header(R
"(
1201 #define $macro[[MACRO]](x) (x+1)
1202 class $foo[[Foo]] {};
1204 runSymbolCollector(Header.code(), "");
1206 haveRanges(Header.ranges(
"foo")))));
1208 haveRanges(Header.ranges(
"macro")))));
1211TEST_F(SymbolCollectorTest, BaseOfRelations) {
1212 std::string Header = R
"(
1214 class Derived : public Base {};
1216 runSymbolCollector(Header, "");
1219 EXPECT_THAT(Relations,
1223TEST_F(SymbolCollectorTest, OverrideRelationsSimpleInheritance) {
1224 std::string Header = R
"cpp(
1228 class B : public A {
1229 void foo() override; // A::foo
1232 class C : public B {
1233 void bar() override; // B::bar
1236 void foo() override; // B::foo
1237 void bar() override; // C::bar
1240 runSymbolCollector(Header, "");
1249 std::vector<Relation> Result;
1250 for (
const Relation &R : Relations)
1252 Result.push_back(R);
1253 EXPECT_THAT(Result, UnorderedElementsAre(
1258TEST_F(SymbolCollectorTest, OverrideRelationsMultipleInheritance) {
1259 std::string Header = R
"cpp(
1266 class C : public B {
1267 void bar() override; // B::bar
1270 class D : public A, C {
1271 void foo() override; // A::foo
1272 void bar() override; // C::bar
1273 void baz() override; // C::baz
1276 runSymbolCollector(Header, "");
1285 std::vector<Relation> Result;
1286 for (
const Relation &R : Relations)
1288 Result.push_back(R);
1289 EXPECT_THAT(Result, UnorderedElementsAre(
1294TEST_F(SymbolCollectorTest, CountReferences) {
1295 const std::string Header = R
"(
1299 class Z {}; // not used anywhere
1300 Y* y = nullptr; // used in header doesn't count
1301 #define GLOBAL_Z(name) Z name;
1303 const std::string Main = R
"(
1305 W* w2 = nullptr; // only one usage counts
1308 class Y{}; // definition doesn't count as a reference
1310 GLOBAL_Z(z); // Not a reference to Z, we don't spell the type.
1313 runSymbolCollector(Header, Main);
1316 UnorderedElementsAreArray(
1317 {AllOf(qName(
"W"), refCount(1)), AllOf(qName(
"X"), refCount(1)),
1318 AllOf(qName(
"Y"), refCount(0)), AllOf(qName(
"Z"), refCount(0)),
1319 AllOf(qName(
"y"), refCount(0)), AllOf(qName(
"z"), refCount(0)),
1320 AllOf(qName(
"x"), refCount(0)), AllOf(qName(
"w"), refCount(0)),
1321 AllOf(qName(
"w2"), refCount(0)), AllOf(qName(
"V"), refCount(1)),
1322 AllOf(qName(
"v"), refCount(0))}));
1325TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
1326 runSymbolCollector(
"class Foo {};",
"");
1327 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1331TEST_F(SymbolCollectorTest, SymbolRelativeWithFallback) {
1336 runSymbolCollector(
"class Foo {};",
"");
1337 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1341TEST_F(SymbolCollectorTest, UnittestURIScheme) {
1345 runSymbolCollector(
"class Foo {};",
"");
1346 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1347 AllOf(qName(
"Foo"), declURI(
"unittest:///x.h"))));
1350TEST_F(SymbolCollectorTest, IncludeEnums) {
1351 const std::string Header = R
"(
1372 runSymbolCollector(Header, "");
1374 UnorderedElementsAre(
1375 AllOf(qName(
"Red"), forCodeCompletion(
true)),
1376 AllOf(qName(
"Color"), forCodeCompletion(
true)),
1377 AllOf(qName(
"Green"), forCodeCompletion(
true)),
1378 AllOf(qName(
"Color2"), forCodeCompletion(
true)),
1379 AllOf(qName(
"Color2::Yellow"), forCodeCompletion(
true)),
1380 AllOf(qName(
"ns"), forCodeCompletion(
true)),
1381 AllOf(qName(
"ns::Black"), forCodeCompletion(
true)),
1382 AllOf(qName(
"Color3"), forCodeCompletion(
true)),
1383 AllOf(qName(
"Color3::Blue"), forCodeCompletion(
true))));
1386TEST_F(SymbolCollectorTest, NamelessSymbols) {
1387 const std::string Header = R
"(
1392 runSymbolCollector(Header, "");
1393 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"Foo"),
1394 qName(
"(anonymous struct)::a")));
1397TEST_F(SymbolCollectorTest, SymbolFormedFromRegisteredSchemeFromMacro) {
1399 Annotations Header(R
"(
1401 class name##_Test {};
1403 $expansion[[FF]](abc);
1406 class $spelling[[Test]] {};
1411 runSymbolCollector(Header.code(), "");
1413 UnorderedElementsAre(
1414 AllOf(qName(
"abc_Test"), declRange(Header.range(
"expansion")),
1416 AllOf(qName(
"Test"), declRange(Header.range(
"spelling")),
1420TEST_F(SymbolCollectorTest, SymbolFormedByCLI) {
1421 Annotations Header(R
"(
1423 class $expansion[[NAME]] {};
1426 runSymbolCollector(Header.code(), "", {
"-DNAME=name"});
1427 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1428 qName(
"name"), declRange(Header.range(
"expansion")),
1432TEST_F(SymbolCollectorTest, SymbolsInMainFile) {
1433 const std::string Main = R
"(
1449 runSymbolCollector("", Main);
1450 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1451 qName(
"Foo"), qName(
"f1"), qName(
"f2"), qName(
"ff"),
1452 qName(
"foo"), qName(
"foo::Bar"), qName(
"main_f")));
1455TEST_F(SymbolCollectorTest, Documentation) {
1456 const std::string Header = R
"(
1464 runSymbolCollector(Header,
"");
1466 UnorderedElementsAre(
1467 AllOf(qName(
"Foo"), doc(
"doc Foo"), forCodeCompletion(
true)),
1468 AllOf(qName(
"Foo::f"), doc(
""), returnType(
""),
1469 forCodeCompletion(
false))));
1472 runSymbolCollector(Header,
"");
1474 UnorderedElementsAre(
1475 AllOf(qName(
"Foo"), doc(
"doc Foo"), forCodeCompletion(
true)),
1476 AllOf(qName(
"Foo::f"), doc(
"doc f"), returnType(
""),
1477 forCodeCompletion(
false))));
1480TEST_F(SymbolCollectorTest, ClassMembers) {
1481 const std::string Header = R
"(
1490 const std::string Main = R
"(
1494 runSymbolCollector(Header, Main);
1497 UnorderedElementsAre(
1499 AllOf(qName(
"Foo::f"), returnType(
""), forCodeCompletion(
false)),
1500 AllOf(qName(
"Foo::g"), returnType(
""), forCodeCompletion(
false)),
1501 AllOf(qName(
"Foo::sf"), returnType(
""), forCodeCompletion(
false)),
1502 AllOf(qName(
"Foo::ssf"), returnType(
""), forCodeCompletion(
false)),
1503 AllOf(qName(
"Foo::x"), returnType(
""), forCodeCompletion(
false))));
1506TEST_F(SymbolCollectorTest, Scopes) {
1507 const std::string Header = R
"(
1515 runSymbolCollector(Header, "");
1517 UnorderedElementsAre(qName(
"na"), qName(
"na::nb"),
1518 qName(
"na::Foo"), qName(
"na::nb::Bar")));
1521TEST_F(SymbolCollectorTest, ExternC) {
1522 const std::string Header = R
"(
1523 extern "C" { class Foo {}; }
1525 extern "C" { class Bar {}; }
1528 runSymbolCollector(Header, "");
1529 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"na"), qName(
"Foo"),
1533TEST_F(SymbolCollectorTest, SkipInlineNamespace) {
1534 const std::string Header = R
"(
1536 inline namespace nb {
1541 // This is still inlined.
1547 runSymbolCollector(Header, "");
1549 UnorderedElementsAre(qName(
"na"), qName(
"na::nb"),
1550 qName(
"na::Foo"), qName(
"na::Bar")));
1553TEST_F(SymbolCollectorTest, SymbolWithDocumentation) {
1554 const std::string Header = R
"(
1557 int ff(int x, double y) { return 0; }
1560 runSymbolCollector(Header,
"");
1563 UnorderedElementsAre(
1564 qName(
"nx"), AllOf(qName(
"nx::ff"), labeled(
"ff(int x, double y)"),
1565 returnType(
"int"), doc(
"Foo comment."))));
1568TEST_F(SymbolCollectorTest, snippet) {
1569 const std::string Header = R
"(
1572 int ff(int x, double y) { return 0; }
1575 runSymbolCollector(Header, "");
1577 UnorderedElementsAre(
1579 AllOf(qName(
"nx::f"), labeled(
"f()"), snippet(
"f()")),
1580 AllOf(qName(
"nx::ff"), labeled(
"ff(int x, double y)"),
1581 snippet(
"ff(${1:int x}, ${2:double y})"))));
1584TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
1586 runSymbolCollector(
"#pragma once\nclass Foo {};",
"");
1587 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1589 EXPECT_THAT(
Symbols.begin()->IncludeHeaders,
1590 UnorderedElementsAre(IncludeHeaderWithRef(
TestHeaderURI, 1u)));
1593TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
1599 // Move overloads have special handling.
1600 template <typename _T> T&& move(_T&& __value);
1601 template <typename _I, typename _O> _O move(_I, _I, _O);
1602 template <typename _T, typename _O, typename _I> _O move(
1609 UnorderedElementsAre(
1612 includeHeader(
"<string>")),
1614 AllOf(labeled(
"move(T &&value)"), includeHeader(
"<utility>")),
1615 AllOf(labeled(
"move(I, I, O)"), includeHeader(
"<algorithm>")),
1616 AllOf(labeled(
"move(T &&, O, O, I)"), includeHeader(
"<algorithm>"))));
1619TEST_F(SymbolCollectorTest, IWYUPragma) {
1621 const std::string Header = R
"(
1622 // IWYU pragma: private, include the/good/header.h
1625 runSymbolCollector(Header, "");
1626 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1628 includeHeader(
"\"the/good/header.h\""))));
1631TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
1633 const std::string Header = R
"(
1634 // IWYU pragma: private, include "the/good/header.h"
1637 runSymbolCollector(Header, "");
1638 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1640 includeHeader(
"\"the/good/header.h\""))));
1643TEST_F(SymbolCollectorTest, IWYUPragmaExport) {
1645 const std::string Header = R
"cpp(#pragma once
1646 #include "exporter.h"
1648 auto ExporterFile =
testPath(
"exporter.h");
1650 ExporterFile, 0, llvm::MemoryBuffer::getMemBuffer(R
"cpp(#pragma once
1651 #include "private.h" // IWYU pragma: export
1653 auto PrivateFile =
testPath(
"private.h");
1655 PrivateFile, 0, llvm::MemoryBuffer::getMemBuffer(
"class Foo {};"));
1656 runSymbolCollector(Header,
"",
1658 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1664TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {
1670 auto IncFile =
testPath(
"test.inc");
1673 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1674 runSymbolCollector(
"", R
"cpp(
1675 // Can't use #pragma once in a main file clang doesn't think is a header.
1682 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), declURI(IncURI),
1686TEST_F(SymbolCollectorTest, IncFileInNonHeader) {
1690 auto IncFile =
testPath(
"test.inc");
1693 llvm::MemoryBuffer::getMemBuffer(
"class X {};"));
1694 runSymbolCollector(
"", R
"cpp(
1698 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), declURI(IncURI),
1699 Not(includeHeader()))));
1704TEST_F(SymbolCollectorTest, HeaderGuardDetected) {
1707 runSymbolCollector(R
"cpp(
1708 #ifndef HEADER_GUARD_
1709 #define HEADER_GUARD_
1711 // Symbols are seen before the header guard is complete.
1715 #endif // Header guard is recognized here.
1718 EXPECT_THAT(
Symbols, Not(Contains(qName(
"HEADER_GUARD_"))));
1719 EXPECT_THAT(
Symbols, Each(includeHeader()));
1722TEST_F(SymbolCollectorTest, NonModularHeader) {
1724 EXPECT_THAT(TU.headerSymbols(), ElementsAre(includeHeader()));
1727 TU.ImplicitHeaderGuard =
false;
1728 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1733#error "This file isn't safe to include directly"
1737 TU.ExtraArgs.push_back("-DSECRET");
1738 EXPECT_THAT(TU.headerSymbols(), ElementsAre(Not(includeHeader())));
1741TEST_F(SymbolCollectorTest, AvoidUsingFwdDeclsAsCanonicalDecls) {
1743 Annotations Header(R
"(
1745 // Forward declarations of TagDecls.
1750 // Canonical declarations.
1751 class $cdecl[[C]] {};
1752 struct $sdecl[[S]] {};
1753 union $udecl[[U]] {int $xdecl[[x]]; bool $ydecl[[y]];};
1755 runSymbolCollector(Header.code(), "");
1758 UnorderedElementsAre(
1760 declRange(Header.range(
"cdecl")), includeHeader(
TestHeaderURI),
1763 declRange(Header.range(
"sdecl")), includeHeader(
TestHeaderURI),
1766 declRange(Header.range(
"udecl")), includeHeader(
TestHeaderURI),
1770 defRange(Header.range(
"xdecl"))),
1773 defRange(Header.range(
"ydecl")))));
1776TEST_F(SymbolCollectorTest, ClassForwardDeclarationIsCanonical) {
1778 runSymbolCollector(
"#pragma once\nclass X;",
1780 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(
1785TEST_F(SymbolCollectorTest, UTF16Character) {
1787 Annotations Header(
"class [[pörk]] {};");
1788 runSymbolCollector(Header.code(),
"");
1789 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1790 AllOf(qName(
"pörk"), declRange(Header.range()))));
1793TEST_F(SymbolCollectorTest, DoNotIndexSymbolsInFriendDecl) {
1794 Annotations Header(R
"(
1801 friend void $bar[[bar]]() {}
1807 runSymbolCollector(Header.code(), "");
1810 UnorderedElementsAre(
1811 qName(
"nx"), qName(
"nx::X"),
1812 AllOf(qName(
"nx::Y"), declRange(Header.range(
"y"))),
1813 AllOf(qName(
"nx::Z"), declRange(Header.range(
"z"))),
1814 AllOf(qName(
"nx::foo"), declRange(Header.range(
"foo"))),
1815 AllOf(qName(
"nx::bar"), declRange(Header.range(
"bar")))));
1818TEST_F(SymbolCollectorTest, ReferencesInFriendDecl) {
1819 const std::string Header = R
"(
1823 const std::string Main = R
"(
1830 runSymbolCollector(Header, Main);
1831 EXPECT_THAT(
Symbols, UnorderedElementsAre(AllOf(qName(
"X"), refCount(1)),
1832 AllOf(qName(
"Y"), refCount(1)),
1833 AllOf(qName(
"C"), refCount(0))));
1836TEST_F(SymbolCollectorTest, Origin) {
1838 runSymbolCollector(
"class Foo {};",
"");
1839 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1843 runSymbolCollector(
"#define FOO",
"");
1844 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1848TEST_F(SymbolCollectorTest, CollectMacros) {
1850 Annotations Header(R
"(
1853 #define $mac[[MAC]](x) int x
1854 #define $used[[USED]](y) float y;
1859 Annotations Main(R"(
1860 #define $main[[MAIN]] 1
1865 runSymbolCollector(Header.code(), Main.code());
1868 UnorderedElementsAre(
1869 qName(
"p"), qName(
"t"),
1872 AllOf(labeled(
"MAC(x)"), refCount(0),
1874 declRange(Header.range(
"mac")), visibleOutsideFile()),
1875 AllOf(labeled(
"USED(y)"), refCount(1),
1876 declRange(Header.range(
"used")), visibleOutsideFile()),
1877 AllOf(labeled(
"MAIN"), refCount(0), declRange(Main.range(
"main")),
1878 Not(visibleOutsideFile()))));
1881TEST_F(SymbolCollectorTest, DeprecatedSymbols) {
1882 const std::string Header = R
"(
1883 void TestClangc() __attribute__((deprecated("", "")));
1886 runSymbolCollector(Header, "");
1887 EXPECT_THAT(
Symbols, UnorderedElementsAre(
1888 AllOf(qName(
"TestClangc"), deprecated()),
1889 AllOf(qName(
"TestClangd"), Not(deprecated()))));
1892TEST_F(SymbolCollectorTest, implementationDetail) {
1893 const std::string Header = R
"(
1894 #define DECL_NAME(x, y) x##_##y##_Decl
1895 #define DECL(x, y) class DECL_NAME(x, y) {};
1896 DECL(X, Y); // X_Y_Decl
1900 runSymbolCollector(Header, "");
1902 UnorderedElementsAre(
1903 AllOf(qName(
"X_Y_Decl"), implementationDetail()),
1904 AllOf(qName(
"Public"), Not(implementationDetail()))));
1907TEST_F(SymbolCollectorTest, UsingDecl) {
1908 const char *Header = R
"(
1913 runSymbolCollector(Header, "");
1914 EXPECT_THAT(
Symbols, Contains(qName(
"std::foo")));
1917TEST_F(SymbolCollectorTest, CBuiltins) {
1919 const char *Header = R
"(
1920 extern int printf(const char*, ...);
1922 runSymbolCollector(Header, "", {
"-xc"});
1923 EXPECT_THAT(
Symbols, Contains(qName(
"printf")));
1926TEST_F(SymbolCollectorTest, InvalidSourceLoc) {
1927 const char *Header = R
"(
1928 void operator delete(void*)
1929 __attribute__((__externally_visible__));)";
1930 runSymbolCollector(Header, "");
1931 EXPECT_THAT(
Symbols, Contains(qName(
"operator delete")));
1934TEST_F(SymbolCollectorTest, BadUTF8) {
1937 const char *Header =
"int PUNCT = 0;\n"
1938 "/* \xa1 */ int types[] = { /* \xa1 */PUNCT };";
1941 runSymbolCollector(Header,
"");
1942 EXPECT_THAT(
Symbols, Contains(AllOf(qName(
"types"), doc(
"\xef\xbf\xbd "))));
1943 EXPECT_THAT(
Symbols, Contains(qName(
"PUNCT")));
1948TEST_F(SymbolCollectorTest, MacrosInHeaders) {
1951 runSymbolCollector(
"",
"#define X");
1953 UnorderedElementsAre(AllOf(qName(
"X"), forCodeCompletion(
true))));
1957TEST_F(SymbolCollectorTest, UndefOfModuleMacro) {
1959 TU.AdditionalFiles["bar.h"] = R
"cpp(
1963 TU.AdditionalFiles["foo.h"] =
"#define X 1";
1964 TU.AdditionalFiles[
"module.modulemap"] = R
"cpp(
1970 TU.ExtraArgs.push_back("-fmodules");
1971 TU.ExtraArgs.push_back(
"-fmodule-map-file=" +
testPath(
"module.modulemap"));
1972 TU.OverlayRealFileSystemForModules =
true;
1977 EXPECT_THAT(TU.headerSymbols(), Not(Contains(qName(
"X"))));
1980TEST_F(SymbolCollectorTest, NoCrashOnObjCMethodCStyleParam) {
1983 - (void)fun:(bool)foo, bool bar;
1986 TU.ExtraArgs.push_back("-xobjective-c++");
1990 EXPECT_THAT(TU.headerSymbols(),
1991 UnorderedElementsAre(qName(
"Foo"), qName(
"Foo::fun:")));
1994TEST_F(SymbolCollectorTest, Reserved) {
1995 const char *Header = R
"cpp(
1998 namespace _X { int secret; }
2002 runSymbolCollector(Header,
"");
2003 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"__foo"), qName(
"_X"),
2004 qName(
"_X::secret")));
2007 runSymbolCollector(Header,
"");
2008 EXPECT_THAT(
Symbols, UnorderedElementsAre(qName(
"__foo"), qName(
"_X"),
2009 qName(
"_X::secret")));
2014 runSymbolCollector(
"#pragma GCC system_header\n" + std::string(Header),
"");
2015 EXPECT_THAT(
Symbols, IsEmpty());
2018TEST_F(SymbolCollectorTest, Concepts) {
2019 const char *Header = R
"cpp(
2021 concept A = sizeof(T) <= 8;
2023 runSymbolCollector("", Header, {
"-std=c++20"});
2025 UnorderedElementsAre(AllOf(
2026 qName(
"A"), hasKind(clang::index::SymbolKind::Concept))));
2029TEST_F(SymbolCollectorTest, IncludeHeaderForwardDecls) {
2031 const std::string Header = R
"cpp(#pragma once
2035 auto FullFile =
testPath(
"full.h");
2037 llvm::MemoryBuffer::getMemBuffer(R
"cpp(
2039struct Foo {};)cpp"));
2040 runSymbolCollector(Header, "",
2042 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)