1 //===--- TestLexer.h - Format C++ code --------------------------*- C++ -*-===//
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 /// \file
10 /// This file contains a TestLexer to create FormatTokens from strings.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef CLANG_UNITTESTS_FORMAT_TESTLEXER_H
15 #define CLANG_UNITTESTS_FORMAT_TESTLEXER_H
16 
17 #include "../../lib/Format/FormatTokenLexer.h"
18 #include "../../lib/Format/TokenAnalyzer.h"
19 #include "../../lib/Format/TokenAnnotator.h"
20 #include "../../lib/Format/UnwrappedLineParser.h"
21 
22 #include "clang/Basic/FileManager.h"
23 #include "clang/Basic/SourceManager.h"
24 
25 #include <numeric>
26 #include <ostream>
27 
28 namespace clang {
29 namespace format {
30 
31 typedef llvm::SmallVector<FormatToken *, 8> TokenList;
32 
33 inline std::ostream &operator<<(std::ostream &Stream, const FormatToken &Tok) {
34   Stream << "(" << Tok.Tok.getName() << ", \"" << Tok.TokenText.str() << "\" , "
35          << getTokenTypeName(Tok.getType()) << ")";
36   return Stream;
37 }
38 inline std::ostream &operator<<(std::ostream &Stream, const TokenList &Tokens) {
39   Stream << "{";
40   for (size_t I = 0, E = Tokens.size(); I != E; ++I)
41     Stream << (I > 0 ? ", " : "") << *Tokens[I];
42   Stream << "} (" << Tokens.size() << " tokens)";
43   return Stream;
44 }
45 
uneof(const TokenList & Tokens)46 inline TokenList uneof(const TokenList &Tokens) {
47   assert(!Tokens.empty() && Tokens.back()->is(tok::eof));
48   return TokenList(Tokens.begin(), std::prev(Tokens.end()));
49 }
50 
text(llvm::ArrayRef<FormatToken * > Tokens)51 inline std::string text(llvm::ArrayRef<FormatToken *> Tokens) {
52   return std::accumulate(Tokens.begin(), Tokens.end(), std::string(),
53                          [](const std::string &R, FormatToken *Tok) {
54                            return (R + Tok->TokenText).str();
55                          });
56 }
57 
58 class TestLexer : public UnwrappedLineConsumer {
59 public:
60   TestLexer(llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator,
61             std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Buffers,
62             FormatStyle Style = getLLVMStyle())
Allocator(Allocator)63       : Allocator(Allocator), Buffers(Buffers), Style(Style),
64         SourceMgr("test.cpp", ""), IdentTable(getFormattingLangOpts(Style)) {}
65 
lex(llvm::StringRef Code)66   TokenList lex(llvm::StringRef Code) {
67     FormatTokenLexer Lex = getNewLexer(Code);
68     ArrayRef<FormatToken *> Result = Lex.lex();
69     return TokenList(Result.begin(), Result.end());
70   }
71 
annotate(llvm::StringRef Code)72   TokenList annotate(llvm::StringRef Code) {
73     FormatTokenLexer Lex = getNewLexer(Code);
74     auto Tokens = Lex.lex();
75     UnwrappedLineParser Parser(Style, Lex.getKeywords(), 0, Tokens, *this);
76     Parser.parse();
77     TokenAnnotator Annotator(Style, Lex.getKeywords());
78     for (auto &Line : UnwrappedLines) {
79       AnnotatedLine Annotated(Line);
80       Annotator.annotate(Annotated);
81       Annotator.calculateFormattingInformation(Annotated);
82     }
83     UnwrappedLines.clear();
84     return TokenList(Tokens.begin(), Tokens.end());
85   }
86 
id(llvm::StringRef Code)87   FormatToken *id(llvm::StringRef Code) {
88     auto Result = uneof(lex(Code));
89     assert(Result.size() == 1U && "Code must expand to 1 token.");
90     return Result[0];
91   }
92 
93 protected:
consumeUnwrappedLine(const UnwrappedLine & TheLine)94   void consumeUnwrappedLine(const UnwrappedLine &TheLine) override {
95     UnwrappedLines.push_back(TheLine);
96   }
finishRun()97   void finishRun() override {}
98 
getNewLexer(StringRef Code)99   FormatTokenLexer getNewLexer(StringRef Code) {
100     Buffers.push_back(
101         llvm::MemoryBuffer::getMemBufferCopy(Code, "<scratch space>"));
102     clang::FileID FID =
103         SourceMgr.get().createFileID(Buffers.back()->getMemBufferRef());
104     return FormatTokenLexer(SourceMgr.get(), FID, 0, Style, Encoding, Allocator,
105                             IdentTable);
106   }
107 
108 public:
109   llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator;
110   std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Buffers;
111   FormatStyle Style;
112   encoding::Encoding Encoding = encoding::Encoding_UTF8;
113   clang::SourceManagerForFile SourceMgr;
114   IdentifierTable IdentTable;
115   SmallVector<UnwrappedLine, 16> UnwrappedLines;
116 };
117 
118 } // namespace format
119 } // namespace clang
120 
121 #endif // LLVM_CLANG_UNITTESTS_FORMAT_TEST_LEXER_H
122