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 TEST_F(TokenAnnotatorTest, UnderstandsClasses) { 71 auto Tokens = annotate("class C {};"); 72 EXPECT_EQ(Tokens.size(), 6u) << Tokens; 73 EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_RecordLBrace); 74 } 75 76 TEST_F(TokenAnnotatorTest, UnderstandsStructs) { 77 auto Tokens = annotate("struct S {};"); 78 EXPECT_EQ(Tokens.size(), 6u) << Tokens; 79 EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_RecordLBrace); 80 } 81 82 TEST_F(TokenAnnotatorTest, UnderstandsUnions) { 83 auto Tokens = annotate("union U {};"); 84 EXPECT_EQ(Tokens.size(), 6u) << Tokens; 85 EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_RecordLBrace); 86 } 87 88 TEST_F(TokenAnnotatorTest, UnderstandsEnums) { 89 auto Tokens = annotate("enum E {};"); 90 EXPECT_EQ(Tokens.size(), 6u) << Tokens; 91 EXPECT_TOKEN(Tokens[2], tok::l_brace, TT_RecordLBrace); 92 } 93 94 TEST_F(TokenAnnotatorTest, UnderstandsLBracesInMacroDefinition) { 95 auto Tokens = annotate("#define BEGIN NS {"); 96 EXPECT_EQ(Tokens.size(), 6u) << Tokens; 97 EXPECT_TOKEN(Tokens[4], tok::l_brace, TT_Unknown); 98 } 99 100 TEST_F(TokenAnnotatorTest, UnderstandsDelete) { 101 auto Tokens = annotate("delete (void *)p;"); 102 EXPECT_EQ(Tokens.size(), 8u) << Tokens; 103 EXPECT_TOKEN(Tokens[4], tok::r_paren, TT_CastRParen); 104 105 Tokens = annotate("delete[] (void *)p;"); 106 EXPECT_EQ(Tokens.size(), 10u) << Tokens; 107 EXPECT_TOKEN(Tokens[6], tok::r_paren, TT_CastRParen); 108 109 Tokens = annotate("delete[] /*comment*/ (void *)p;"); 110 EXPECT_EQ(Tokens.size(), 11u) << Tokens; 111 EXPECT_TOKEN(Tokens[7], tok::r_paren, TT_CastRParen); 112 113 Tokens = annotate("delete[/*comment*/] (void *)p;"); 114 EXPECT_EQ(Tokens.size(), 11u) << Tokens; 115 EXPECT_TOKEN(Tokens[7], tok::r_paren, TT_CastRParen); 116 117 Tokens = annotate("delete/*comment*/[] (void *)p;"); 118 EXPECT_EQ(Tokens.size(), 11u) << Tokens; 119 EXPECT_TOKEN(Tokens[7], tok::r_paren, TT_CastRParen); 120 } 121 122 } // namespace 123 } // namespace format 124 } // namespace clang 125