189 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H10#define LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H11 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 20namespace lldb_private {21 22// Helps to validate and obtain various parts of C++ definitions.23class CPlusPlusNameParser {24public: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 should41 // 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) const47 // 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 // main54 // fun55 // std::vector<int>::push_back56 // map<int, pair<short, int>>::operator[]57 // func<C>(int, C&)::nested_class::method58 std::optional<ParsedName> ParseAsFullName();59 60private: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 tag172 /// string may contain, this API supports parsing a small173 /// 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_private187 188#endif // LLDB_SOURCE_PLUGINS_LANGUAGE_CPLUSPLUS_CPLUSPLUSNAMEPARSER_H189