1 //===- unittest/Format/TokenAnnotatorTest.cpp - Formatting unit tests -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Format/Format.h"
10 
11 #include "FormatTestUtils.h"
12 #include "TestLexer.h"
13 #include "gtest/gtest.h"
14 
15 namespace clang {
16 namespace format {
17 namespace {
18 
19 class TokenAnnotatorTest : public ::testing::Test {
20 protected:
21   TokenList annotate(llvm::StringRef Code,
22                      const FormatStyle &Style = getLLVMStyle()) {
23     return TestLexer(Allocator, Buffers, Style).annotate(Code);
24   }
25   llvm::SpecificBumpPtrAllocator<FormatToken> Allocator;
26   std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
27 };
28 
29 #define EXPECT_TOKEN_KIND(FormatTok, Kind)                                     \
30   EXPECT_EQ((FormatTok)->Tok.getKind(), Kind) << *(FormatTok)
31 #define EXPECT_TOKEN_TYPE(FormatTok, Type)                                     \
32   EXPECT_EQ((FormatTok)->getType(), Type) << *(FormatTok)
33 #define EXPECT_TOKEN(FormatTok, Kind, Type)                                    \
34   do {                                                                         \
35     EXPECT_TOKEN_KIND(FormatTok, Kind);                                        \
36     EXPECT_TOKEN_TYPE(FormatTok, Type);                                        \
37   } while (false);
38 
39 TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmpInMacroDefinition) {
40   // This is a regression test for mis-parsing the & after decltype as a binary
41   // operator instead of a reference (when inside a macro definition).
42   auto Tokens = annotate("auto x = [](const decltype(x) &ptr) {};");
43   EXPECT_EQ(Tokens.size(), 18u) << Tokens;
44   EXPECT_TOKEN(Tokens[7], tok::kw_decltype, TT_Unknown);
45   EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_TypeDeclarationParen);
46   EXPECT_TOKEN(Tokens[9], tok::identifier, TT_Unknown);
47   EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_TypeDeclarationParen);
48   EXPECT_TOKEN(Tokens[11], tok::amp, TT_PointerOrReference);
49   // Same again with * instead of &:
50   Tokens = annotate("auto x = [](const decltype(x) *ptr) {};");
51   EXPECT_EQ(Tokens.size(), 18u) << Tokens;
52   EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_TypeDeclarationParen);
53   EXPECT_TOKEN(Tokens[11], tok::star, TT_PointerOrReference);
54 
55   // Also check that we parse correctly within a macro definition:
56   Tokens = annotate("#define lambda [](const decltype(x) &ptr) {}");
57   EXPECT_EQ(Tokens.size(), 17u) << Tokens;
58   EXPECT_TOKEN(Tokens[7], tok::kw_decltype, TT_Unknown);
59   EXPECT_TOKEN(Tokens[8], tok::l_paren, TT_TypeDeclarationParen);
60   EXPECT_TOKEN(Tokens[9], tok::identifier, TT_Unknown);
61   EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_TypeDeclarationParen);
62   EXPECT_TOKEN(Tokens[11], tok::amp, TT_PointerOrReference);
63   // Same again with * instead of &:
64   Tokens = annotate("#define lambda [](const decltype(x) *ptr) {}");
65   EXPECT_EQ(Tokens.size(), 17u) << Tokens;
66   EXPECT_TOKEN(Tokens[10], tok::r_paren, TT_TypeDeclarationParen);
67   EXPECT_TOKEN(Tokens[11], tok::star, TT_PointerOrReference);
68 }
69 
70 } // namespace
71 } // namespace format
72 } // namespace clang
73