13 #include "clang/Basic/LangOptions.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Basic/TokenKinds.h"
16 #include "clang/Format/Format.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/raw_os_ostream.h"
19 #include "llvm/Testing/Support/Annotations.h"
20 #include "llvm/Testing/Support/Error.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
32 MATCHER_P2(
Pos,
Line, Col,
"") {
33 return arg.line == int(
Line) && arg.character == int(Col);
39 Position position(
int Line,
int Character) {
74 TEST(SourceCodeTests, lspLengthBadUTF8) {
77 const char *BadUTF8[] = {
"\xa0",
"\xff\xff\xff\xff\xff"};
82 for (
const char *Bad : BadUTF8) {
90 const char File[] = R
"(0:0 = 0
100 TEST(SourceCodeTests, PositionToOffset) {
102 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(-1, 2)), llvm::Failed());
157 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(3, 0)), llvm::Failed());
158 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(3, 1)), llvm::Failed());
163 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(-1, 2)), llvm::Failed());
214 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(3, 0)), llvm::Failed());
215 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(3, 1)), llvm::Failed());
219 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(-1, 2)), llvm::Failed());
220 EXPECT_THAT_EXPECTED(
positionToOffset(File, position(3, 0)), llvm::Failed());
221 for (
Line L : FileLines) {
224 for (
unsigned I = 0; I <= L.Length; ++I)
227 EXPECT_THAT_EXPECTED(
230 EXPECT_THAT_EXPECTED(
236 TEST(SourceCodeTests, OffsetToPosition) {
278 for (
Line L : FileLines) {
279 for (
unsigned I = 0; I <= L.Length; ++I)
285 TEST(SourceCodeTests, SourceLocationInMainFile) {
286 Annotations Source(R
"cpp(
289 ^baz ^() {} {} {} {} { }^
292 SourceManagerForFile Owner("foo.cpp", Source.code());
293 SourceManager &SM = Owner.get();
295 SourceLocation StartOfFile = SM.getLocForStartOfFile(SM.getMainFileID());
299 EXPECT_THAT_EXPECTED(
301 HasValue(StartOfFile.getLocWithOffset(Source.code().size())));
310 for (
auto P : Source.points()) {
317 TEST(SourceCodeTests, CollectIdentifiers) {
318 auto Style = format::getLLVMStyle();
321 void foo() { int xyz; int abc = xyz; return foo(); }
324 EXPECT_EQ(IDs.size(), 7u);
325 EXPECT_EQ(IDs["include"], 1u);
326 EXPECT_EQ(IDs[
"void"], 1u);
327 EXPECT_EQ(IDs[
"int"], 2u);
328 EXPECT_EQ(IDs[
"xyz"], 2u);
329 EXPECT_EQ(IDs[
"abc"], 1u);
330 EXPECT_EQ(IDs[
"return"], 1u);
331 EXPECT_EQ(IDs[
"foo"], 2u);
334 TEST(SourceCodeTests, CollectWords) {
338 std::string getSomeText() { return "magic word"; }
340 std::set<StringRef> ActualWords(Words.keys().begin(), Words.keys().end());
341 std::set<StringRef> ExpectedWords = {"define",
"fizz",
"buzz",
"this",
342 "comment",
"string",
"some",
"text",
343 "return",
"magic",
"word"};
344 EXPECT_EQ(ActualWords, ExpectedWords);
347 class SpelledWordsTest :
public ::testing::Test {
348 llvm::Optional<ParsedAST>
AST;
350 llvm::Optional<SpelledWord> tryWord(
const char *
Text) {
351 llvm::Annotations A(
Text);
355 AST->getSourceManager().getComposedLoc(
356 AST->getSourceManager().getMainFileID(), A.point()),
357 AST->getTokens(),
AST->getLangOpts());
358 if (A.ranges().size()) {
359 llvm::StringRef Want = A.code().slice(A.range().Begin, A.range().End);
360 EXPECT_EQ(Want, SW->Text) <<
Text;
366 SpelledWord word(
const char *
Text) {
367 auto Result = tryWord(
Text);
368 EXPECT_TRUE(Result) <<
Text;
369 return Result.getValueOr(SpelledWord());
372 void noWord(
const char *
Text) { EXPECT_FALSE(tryWord(
Text)) <<
Text; }
375 TEST_F(SpelledWordsTest, HeuristicBoundaries) {
376 word(
"// [[^foo]] ");
377 word(
"// [[f^oo]] ");
378 word(
"// [[foo^]] ");
379 word(
"// [[foo^]]+bar ");
384 TEST_F(SpelledWordsTest, LikelyIdentifier) {
385 EXPECT_FALSE(word(
"// ^foo ").LikelyIdentifier);
386 EXPECT_TRUE(word(
"// [[^foo_bar]] ").LikelyIdentifier);
387 EXPECT_TRUE(word(
"// [[^fooBar]] ").LikelyIdentifier);
388 EXPECT_FALSE(word(
"// H^TTP ").LikelyIdentifier);
389 EXPECT_TRUE(word(
"// \\p [[^foo]] ").LikelyIdentifier);
390 EXPECT_TRUE(word(
"// @param[in] [[^foo]] ").LikelyIdentifier);
391 EXPECT_TRUE(word(
"// `[[f^oo]]` ").LikelyIdentifier);
392 EXPECT_TRUE(word(
"// bar::[[f^oo]] ").LikelyIdentifier);
393 EXPECT_TRUE(word(
"// [[f^oo]]::bar ").LikelyIdentifier);
396 TEST_F(SpelledWordsTest, Comment) {
397 auto W = word(
"// [[^foo]]");
398 EXPECT_FALSE(W.PartOfSpelledToken);
399 EXPECT_FALSE(W.SpelledToken);
400 EXPECT_FALSE(W.ExpandedToken);
403 TEST_F(SpelledWordsTest, PartOfString) {
404 auto W = word(R
"( auto str = "foo [[^bar]] baz"; )");
405 ASSERT_TRUE(W.PartOfSpelledToken);
406 EXPECT_EQ(W.PartOfSpelledToken->kind(), tok::string_literal);
407 EXPECT_FALSE(W.SpelledToken);
408 EXPECT_FALSE(W.ExpandedToken);
411 TEST_F(SpelledWordsTest, DisabledSection) {
417 ASSERT_TRUE(W.SpelledToken);
418 EXPECT_EQ(W.SpelledToken->kind(), tok::identifier);
419 EXPECT_EQ(W.SpelledToken, W.PartOfSpelledToken);
420 EXPECT_FALSE(W.ExpandedToken);
423 TEST_F(SpelledWordsTest, Macros) {
428 ASSERT_TRUE(W.SpelledToken);
429 EXPECT_EQ(W.SpelledToken->kind(), tok::identifier);
430 EXPECT_EQ(W.SpelledToken, W.PartOfSpelledToken);
431 ASSERT_TRUE(W.ExpandedToken);
432 EXPECT_EQ(W.ExpandedToken->kind(), tok::identifier);
435 #define OBJECT Expansion;
438 EXPECT_TRUE(W.SpelledToken);
439 EXPECT_FALSE(W.ExpandedToken) << "Expanded token is spelled differently";
442 TEST(SourceCodeTests, VisibleNamespaces) {
443 std::vector<std::pair<const char *, std::vector<std::string>>> Cases = {
446 // Using directive resolved against enclosing namespaces.
451 {"ns",
"",
"bar",
"foo",
"ns::bar"},
455 // Don't include namespaces we've closed, ignore namespace aliases.
456 using namespace clang;
460 namespace ll = ::llvm;
468 // Using directives visible even if a namespace is reopened.
469 // Ignore anonymous namespaces.
470 namespace foo{ using namespace bar; }
471 namespace foo{ namespace {
473 {"foo",
"",
"bar",
"foo::bar"},
486 // Namespaces with multiple chunks.
488 using namespace c::d;
509 namespace bar{})cpp",
513 for (
const auto &Case : Cases) {
514 EXPECT_EQ(Case.second,
516 format::getLLVMStyle())))
521 TEST(SourceCodeTests, GetMacros) {
522 Annotations
Code(R
"cpp(
527 auto AST = TU.
build();
529 ASSERT_TRUE(
bool(CurLoc));
530 const auto *Id = syntax::spelledIdentifierTouching(*CurLoc, AST.
getTokens());
534 EXPECT_THAT(*Result, MacroName(
"MACRO"));
537 TEST(SourceCodeTests, WorksAtBeginOfFile) {
538 Annotations
Code(
"^MACRO");
541 auto AST = TU.
build();
543 ASSERT_TRUE(
bool(CurLoc));
544 const auto *Id = syntax::spelledIdentifierTouching(*CurLoc, AST.
getTokens());
548 EXPECT_THAT(*Result, MacroName(
"MACRO"));
551 TEST(SourceCodeTests, IsInsideMainFile) {
553 TU.HeaderCode = R
"cpp(
554 #define DEFINE_CLASS(X) class X {};
555 #define DEFINE_YY DEFINE_CLASS(YY)
558 DEFINE_CLASS(Header2)
562 #define DEFINE_MAIN4 class Main4{};
569 TU.ExtraArgs.push_back("-DHeader=Header3");
570 TU.ExtraArgs.push_back(
"-DMain=Main3");
571 auto AST = TU.
build();
573 auto DeclLoc = [&AST](llvm::StringRef
Name) {
576 for (
const auto *HeaderDecl : {
"Header1",
"Header2",
"Header3"})
579 for (
const auto *MainDecl : {
"Main1",
"Main2",
"Main3",
"Main4",
"YY"})
587 TEST(SourceCodeTests, HalfOpenFileRange) {
590 Annotations Test(R
"cpp(
591 #define FOO(X, Y) int Y = ++X
595 #define BUZZ BAZZ(ADD)
597 #define ADD(a) int f = a + 1;
602 $a[[P<P<P<P<P<int>>>>> a]];
605 $d[[FOO(BAR(BAR(b)), d)]];
606 // FIXME: We might want to select everything inside the outer ECHO.
607 ECHO(ECHO($e[[int) ECHO(e]]));
614 llvm::errs() << Test.code();
618 auto SourceRangeToRange = [&SM](SourceRange SrcRange) {
622 auto CheckRange = [&](llvm::StringRef
Name) {
625 SCOPED_TRACE(
"Checking range: " +
Name);
627 Range HalfOpenRange = SourceRangeToRange(*FileRange);
628 EXPECT_EQ(HalfOpenRange, Test.ranges(
Name)[0]);
639 TEST(SourceCodeTests, HalfOpenFileRangePathologicalPreprocessor) {
640 const char *Case = R
"cpp(
641 #define MACRO while(1)
643 [[#include "Expand.inc"
647 Annotations Test(Case);
650 auto AST = TU.
build();
652 const auto &Func = cast<FunctionDecl>(
findDecl(AST,
"test"));
653 const auto &Body = cast<CompoundStmt>(Func.getBody());
654 const auto &Loop = cast<WhileStmt>(*Body->child_begin());
657 ASSERT_TRUE(
Range) <<
"Failed to get file range";
659 Test.llvm::Annotations::range().Begin);
661 Test.llvm::Annotations::range().End);
664 TEST(SourceCodeTests, IncludeHashLoc) {
665 const char *Case = R
"cpp(
666 $foo^#include "foo.inc"
667 #define HEADER "bar.inc"
668 $bar^# include HEADER
670 Annotations Test(Case);
673 TU.AdditionalFiles[
"bar.inc"] =
"int bar;\n";
674 auto AST = TU.
build();
677 FileID Foo = SM.getFileID(
findDecl(AST,
"foo").getLocation());
679 Test.llvm::Annotations::point(
"foo"));
680 FileID Bar = SM.getFileID(
findDecl(AST,
"bar").getLocation());
682 Test.llvm::Annotations::point(
"bar"));
685 TEST(SourceCodeTests, GetEligiblePoints) {
688 const char *FullyQualifiedName;
691 {R
"cpp(// FIXME: We should also mark positions before and after
692 //declarations/definitions as eligible.
694 namespace a { namespace ns2 {} }
704 "ns1::ns2::symbol",
"ns1::ns2::"},
707 namespace a { namespace ns2 {} }
711 "ns1::ns2::symbol",
"ns1::"},
714 namespace a { namespace ns2 {} }
718 "ns1::ns2::symbol",
""},
725 namespace ns1 {namespace ns2 {^^}})cpp",
726 "ns1::ns2::symbol",
"ns1::ns2::"},
733 namespace ns1 {^namespace ns {}^})cpp",
734 "ns1::ns2::symbol",
"ns1::"},
736 for (
auto Case : Cases) {
737 Annotations Test(Case.Code);
740 Test.code(), Case.FullyQualifiedName,
741 format::getFormattingLangOpts(format::getLLVMStyle()));
742 EXPECT_THAT(Res.EligiblePoints, testing::ElementsAreArray(Test.points()))
744 EXPECT_EQ(Res.EnclosingNamespace, Case.EnclosingNamespace) << Test.code();
748 TEST(SourceCodeTests, IdentifierRanges) {
749 Annotations
Code(R
"cpp(
753 void f([[Foo]]* foo1) {
756 // cross-line identifier is not supported.
762 LangOptions LangOpts;
763 LangOpts.CPlusPlus = true;
764 EXPECT_EQ(
Code.ranges(),
783 LangOptions LangOpts;
784 LangOpts.IsHeaderFile =
true;
788 LangOpts.IsHeaderFile =
false;