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