1 //===-- CPlusPlusNameParser.h -----------------------------------*- 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 #ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
10 #define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
11 
12 #include "clang/Lex/Lexer.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/ADT/StringRef.h"
15 
16 #include "lldb/Utility/ConstString.h"
17 #include "lldb/lldb-private.h"
18 #include <optional>
19 
20 namespace lldb_private {
21 
22 // Helps to validate and obtain various parts of C++ definitions.
23 class CPlusPlusNameParser {
24 public:
25   CPlusPlusNameParser(llvm::StringRef text) : m_text(text) { ExtractTokens(); }
26 
27   struct ParsedName {
28     llvm::StringRef basename;
29     llvm::StringRef context;
30   };
31 
32   struct ParsedFunction {
33     ParsedName name;
34     llvm::StringRef arguments;
35     llvm::StringRef qualifiers;
36     llvm::StringRef return_type;
37   };
38 
39   // Treats given text as a function definition and parses it.
40   // Function definition might or might not have a return type and this should
41   // change parsing result.
42   // Examples:
43   //    main(int, chat const*)
44   //    T fun(int, bool)
45   //    std::vector<int>::push_back(int)
46   //    int& map<int, pair<short, int>>::operator[](short) const
47   //    int (*get_function(const chat *))()
48   std::optional<ParsedFunction> ParseAsFunctionDefinition();
49 
50   // Treats given text as a potentially nested name of C++ entity (function,
51   // class, field) and parses it.
52   // Examples:
53   //    main
54   //    fun
55   //    std::vector<int>::push_back
56   //    map<int, pair<short, int>>::operator[]
57   //    func<C>(int, C&)::nested_class::method
58   std::optional<ParsedName> ParseAsFullName();
59 
60 private:
61   // A C++ definition to parse.
62   llvm::StringRef m_text;
63   // Tokens extracted from m_text.
64   llvm::SmallVector<clang::Token, 30> m_tokens;
65   // Index of the next token to look at from m_tokens.
66   size_t m_next_token_index = 0;
67 
68   // Range of tokens saved in m_next_token_index.
69   struct Range {
70     size_t begin_index = 0;
71     size_t end_index = 0;
72 
73     Range() = default;
74     Range(size_t begin, size_t end) : begin_index(begin), end_index(end) {
75       assert(end >= begin);
76     }
77 
78     size_t size() const { return end_index - begin_index; }
79 
80     bool empty() const { return size() == 0; }
81   };
82 
83   struct ParsedNameRanges {
84     Range basename_range;
85     Range context_range;
86   };
87 
88   // Bookmark automatically restores parsing position (m_next_token_index)
89   // when destructed unless it's manually removed with Remove().
90   class Bookmark {
91   public:
92     Bookmark(size_t &position)
93         : m_position(position), m_position_value(position) {}
94     Bookmark(const Bookmark &) = delete;
95     Bookmark(Bookmark &&b)
96         : m_position(b.m_position), m_position_value(b.m_position_value),
97           m_restore(b.m_restore) {
98       b.Remove();
99     }
100     Bookmark &operator=(Bookmark &&) = delete;
101     Bookmark &operator=(const Bookmark &) = delete;
102 
103     void Remove() { m_restore = false; }
104     size_t GetSavedPosition() { return m_position_value; }
105     ~Bookmark() {
106       if (m_restore) {
107         m_position = m_position_value;
108       }
109     }
110 
111   private:
112     size_t &m_position;
113     size_t m_position_value;
114     bool m_restore = true;
115   };
116 
117   bool HasMoreTokens();
118   void Advance();
119   void TakeBack();
120   bool ConsumeToken(clang::tok::TokenKind kind);
121 
122   template <typename... Ts> bool ConsumeToken(Ts... kinds);
123   Bookmark SetBookmark();
124   size_t GetCurrentPosition();
125   clang::Token &Peek();
126   bool ConsumeBrackets(clang::tok::TokenKind left, clang::tok::TokenKind right);
127 
128   std::optional<ParsedFunction> ParseFunctionImpl(bool expect_return_type);
129 
130   // Parses functions returning function pointers 'string (*f(int x))(float y)'
131   std::optional<ParsedFunction> ParseFuncPtr(bool expect_return_type);
132 
133   // Consumes function arguments enclosed within '(' ... ')'
134   bool ConsumeArguments();
135 
136   // Consumes template arguments enclosed within '<' ... '>'
137   bool ConsumeTemplateArgs();
138 
139   // Consumes '(anonymous namespace)'
140   bool ConsumeAnonymousNamespace();
141 
142   // Consumes '{lambda ...}'
143   bool ConsumeLambda();
144 
145   // Consumes operator declaration like 'operator *' or 'operator delete []'
146   bool ConsumeOperator();
147 
148   // Skips 'const' and 'volatile'
149   void SkipTypeQualifiers();
150 
151   // Skips 'const', 'volatile', '&', '&&' in the end of the function.
152   void SkipFunctionQualifiers();
153 
154   // Consumes built-in types like 'int' or 'unsigned long long int'
155   bool ConsumeBuiltinType();
156 
157   // Consumes types defined via decltype keyword.
158   bool ConsumeDecltype();
159 
160   // Skips 'const' and 'volatile'
161   void SkipPtrsAndRefs();
162 
163   // Consumes things like 'const * const &'
164   bool ConsumePtrsAndRefs();
165 
166   // Consumes full type name like 'Namespace::Class<int>::Method()::InnerClass'
167   bool ConsumeTypename();
168 
169   /// Consumes ABI tags enclosed within '[abi:' ... ']'
170   ///
171   /// Since there is no restriction on what the ABI tag
172   /// string may contain, this API supports parsing a small
173   /// set of special characters.
174   ///
175   /// The following regex describes the set of supported characters:
176   ///   [A-Za-z,.\s\d]+
177   bool ConsumeAbiTag();
178 
179   std::optional<ParsedNameRanges> ParseFullNameImpl();
180   llvm::StringRef GetTextForRange(const Range &range);
181 
182   // Populate m_tokens by calling clang lexer on m_text.
183   void ExtractTokens();
184 };
185 
186 } // namespace lldb_private
187 
188 #endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H
189