#include "Test/Tester.h" #include "Feature/SemanticToken.h" namespace clice::testing { namespace { struct SemanticToken : TestFixture { feature::SemanticTokens tokens; using Self = SemanticToken; void run(llvm::StringRef code) { add_main("main.cpp", code); Tester::compile_with_pch(); tokens = feature::semantic_tokens(*unit); } void EXPECT_TOKEN(this Self& self, llvm::StringRef pos, SymbolKind kind, uint32_t length, LocationChain chain = LocationChain()) { bool visited = false; auto offset = self["main.cpp", pos]; for(auto& token: self.tokens) { if(token.range.begin == offset) { EXPECT_EQ(token.kind, kind, chain); EXPECT_EQ(token.range.end - token.range.begin, length, chain); visited = true; break; } } EXPECT_EQ(visited, true, chain); } void EXPECT_TOKEN(this Self& self, llvm::StringRef pos, SymbolKind kind, SymbolModifiers modifiers, uint32_t length, LocationChain chain = LocationChain()) { bool visited = false; auto offset = self["main.cpp", pos]; for(auto& token: self.tokens) { if(token.range.begin == offset) { EXPECT_EQ(token.kind, kind, chain); EXPECT_EQ(token.range.end - token.range.begin, length, chain); EXPECT_EQ(token.modifiers, modifiers, chain); visited = true; break; } } EXPECT_EQ(visited, true, chain); } void dump_result() { for(auto& token: tokens) { clice::println("token: {}", dump(token)); } } }; using enum SymbolKind::Kind; using enum SymbolModifiers::Kind; TEST_F(SemanticToken, Include) { run(R"cpp( $(0)#include $(1) $(2)#include $(3)"stddef.h" $(4)# $(5)include $(6)"stddef.h" )cpp"); /// FIXME: Included file could be macro. EXPECT_TOKEN("0", Directive, 8); EXPECT_TOKEN("1", Header, 10); EXPECT_TOKEN("2", Directive, 8); EXPECT_TOKEN("3", Header, 10); EXPECT_TOKEN("4", Directive, 1); EXPECT_TOKEN("5", Directive, 7); EXPECT_TOKEN("6", Header, 10); } TEST_F(SemanticToken, Comment) { run(R"cpp( $(line)/// line comment int x = 1; )cpp"); EXPECT_TOKEN("line", Comment, 16); } TEST_F(SemanticToken, Keyword) { run(R"cpp( $(int)int main() { $(return)return 0; } )cpp"); EXPECT_TOKEN("int", Keyword, 3); EXPECT_TOKEN("return", Keyword, 6); } TEST_F(SemanticToken, Macro) { run(R"cpp( $(0)#define $(macro)FOO )cpp"); EXPECT_TOKEN("0", Directive, 7); EXPECT_TOKEN("macro", Macro, 3); } TEST_F(SemanticToken, FinalAndOverride) { run(R"cpp( struct A $(0)final {}; struct B { virtual void foo(); }; struct C : B { void foo() $(1)override; }; struct D : C { void foo() $(2)final; }; )cpp"); EXPECT_TOKEN("0", Keyword, 5); EXPECT_TOKEN("1", Keyword, 8); EXPECT_TOKEN("2", Keyword, 5); } TEST_F(SemanticToken, VarDecl) { run(R"cpp( extern int $(0)x; int $(1)x = 1; template extern int $(2)y; template int $(3)y = 2; template extern int $(4)y; template int $(5)y = 4; template<> int $(6)y = 5; int main() { $(7)x = 6; } )cpp"); EXPECT_TOKEN("0", Variable, Declaration, 1); EXPECT_TOKEN("1", Variable, Definition, 1); EXPECT_TOKEN("2", Variable, SymbolModifiers(Declaration, Templated), 1); EXPECT_TOKEN("3", Variable, SymbolModifiers(Definition, Templated), 1); EXPECT_TOKEN("4", Variable, SymbolModifiers(Declaration, Templated), 1); EXPECT_TOKEN("5", Variable, SymbolModifiers(Definition, Templated), 1); EXPECT_TOKEN("6", Variable, Definition, 1); EXPECT_TOKEN("7", Variable, SymbolModifiers(), 1); } TEST_F(SemanticToken, FunctionDecl) { run(R"cpp( extern int $(0)foo(); int $(1)foo() { return 0; } template extern int $(2)bar(); template int $(3)bar() { return 1; } )cpp"); EXPECT_TOKEN("0", Function, Declaration, 3); EXPECT_TOKEN("1", Function, Definition, 3); EXPECT_TOKEN("2", Function, SymbolModifiers(Declaration, Templated), 3); EXPECT_TOKEN("3", Function, SymbolModifiers(Definition, Templated), 3); } TEST_F(SemanticToken, RecordDecl) { run(R"cpp( class $(0)A; class $(1)A {}; struct $(2)B; struct $(3)B {}; union $(4)C; union $(5)C {}; )cpp"); EXPECT_TOKEN("0", Class, Declaration, 1); EXPECT_TOKEN("1", Class, Definition, 1); EXPECT_TOKEN("2", Struct, Declaration, 1); EXPECT_TOKEN("3", Struct, Definition, 1); EXPECT_TOKEN("4", Union, Declaration, 1); EXPECT_TOKEN("5", Union, Definition, 1); /// FIXME: Add more tests. } } // namespace } // namespace clice::testing