summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Language/CPlusPlus
diff options
context:
space:
mode:
authorJim Ingham <jingham@apple.com>2017-04-05 00:08:21 +0000
committerJim Ingham <jingham@apple.com>2017-04-05 00:08:21 +0000
commit9645a6290a983ec0d34e8d82f6b1044a71766996 (patch)
treea9704c72e067fc4f5e99a9f47276e14959fa138b /lldb/source/Plugins/Language/CPlusPlus
parentd7f951104182808f04b936e74f1ec128b1c599eb (diff)
downloadbcm5719-llvm-9645a6290a983ec0d34e8d82f6b1044a71766996.tar.gz
bcm5719-llvm-9645a6290a983ec0d34e8d82f6b1044a71766996.zip
Reverting r299374 & r299402 due to testsuite failure.
This caused a failure in the test case: functionalities/breakpoint/objc/TestObjCBreakpoints.py When we are parsing up names we stick interesting parts of the names in various buckets, one of which is the ObjC selector bucket. The new C++ name parser must be interfering with this process somehow. <rdar://problem/31439305> llvm-svn: 299489
Diffstat (limited to 'lldb/source/Plugins/Language/CPlusPlus')
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt1
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp171
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h19
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp614
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h176
5 files changed, 119 insertions, 862 deletions
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
index 8f769c49998..d569a15856d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
+++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
@@ -1,7 +1,6 @@
add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
BlockPointer.cpp
CPlusPlusLanguage.cpp
- CPlusPlusNameParser.cpp
CxxStringTypes.cpp
LibCxx.cpp
LibCxxAtomic.cpp
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index f12048e7d02..c48b3d5005c 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -21,6 +21,7 @@
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Threading.h"
// Project includes
#include "lldb/Core/PluginManager.h"
@@ -35,7 +36,6 @@
#include "lldb/Utility/RegularExpression.h"
#include "BlockPointer.h"
-#include "CPlusPlusNameParser.h"
#include "CxxStringTypes.h"
#include "LibCxx.h"
#include "LibCxxAtomic.h"
@@ -85,14 +85,15 @@ void CPlusPlusLanguage::MethodName::Clear() {
m_context = llvm::StringRef();
m_arguments = llvm::StringRef();
m_qualifiers = llvm::StringRef();
+ m_type = eTypeInvalid;
m_parsed = false;
m_parse_error = false;
}
-static bool ReverseFindMatchingChars(const llvm::StringRef &s,
- const llvm::StringRef &left_right_chars,
- size_t &left_pos, size_t &right_pos,
- size_t pos = llvm::StringRef::npos) {
+bool ReverseFindMatchingChars(const llvm::StringRef &s,
+ const llvm::StringRef &left_right_chars,
+ size_t &left_pos, size_t &right_pos,
+ size_t pos = llvm::StringRef::npos) {
assert(left_right_chars.size() == 2);
left_pos = llvm::StringRef::npos;
const char left_char = left_right_chars[0];
@@ -118,9 +119,10 @@ static bool ReverseFindMatchingChars(const llvm::StringRef &s,
return false;
}
-static bool IsTrivialBasename(const llvm::StringRef &basename) {
- // Check that the basename matches with the following regular expression
- // "^~?([A-Za-z_][A-Za-z_0-9]*)$"
+static bool IsValidBasename(const llvm::StringRef &basename) {
+ // Check that the basename matches with the following regular expression or is
+ // an operator name:
+ // "^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$"
// We are using a hand written implementation because it is significantly more
// efficient then
// using the general purpose regular expression library.
@@ -147,69 +149,100 @@ static bool IsTrivialBasename(const llvm::StringRef &basename) {
if (idx == basename.size())
return true;
- return false;
-}
+ // Check for basename with template arguments
+ // TODO: Improve the quality of the validation with validating the template
+ // arguments
+ if (basename[idx] == '<' && basename.back() == '>')
+ return true;
-bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() {
- // This method tries to parse simple method definitions
- // which are presumably most comman in user programs.
- // Definitions that can be parsed by this function don't have return types
- // and templates in the name.
- // A::B::C::fun(std::vector<T> &) const
- size_t arg_start, arg_end;
- llvm::StringRef full(m_full.GetCString());
- llvm::StringRef parens("()", 2);
- if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
- m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
- if (arg_end + 1 < full.size())
- m_qualifiers = full.substr(arg_end + 1).ltrim();
-
- if (arg_start == 0)
- return false;
- size_t basename_end = arg_start;
- size_t context_start = 0;
- size_t context_end = full.rfind(':', basename_end);
- if (context_end == llvm::StringRef::npos)
- m_basename = full.substr(0, basename_end);
- else {
- if (context_start < context_end)
- m_context = full.substr(context_start, context_end - 1 - context_start);
- const size_t basename_begin = context_end + 1;
- m_basename = full.substr(basename_begin, basename_end - basename_begin);
- }
+ // Check if the basename is a vaild C++ operator name
+ if (!basename.startswith("operator"))
+ return false;
- if (IsTrivialBasename(m_basename)) {
- return true;
- } else {
- // The C++ basename doesn't match our regular expressions so this can't
- // be a valid C++ method, clear everything out and indicate an error
- m_context = llvm::StringRef();
- m_basename = llvm::StringRef();
- m_arguments = llvm::StringRef();
- m_qualifiers = llvm::StringRef();
- return false;
- }
- }
- return false;
+ static RegularExpression g_operator_regex(
+ llvm::StringRef("^(operator)( "
+ "?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|"
+ "\\[\\]|[\\^<>=!\\/"
+ "*+-]+)(<.*>)?(\\[\\])?$"));
+ std::string basename_str(basename.str());
+ return g_operator_regex.Execute(basename_str, nullptr);
}
void CPlusPlusLanguage::MethodName::Parse() {
if (!m_parsed && m_full) {
- if (TrySimplifiedParse()) {
- m_parse_error = false;
- } else {
- CPlusPlusNameParser parser(m_full.GetStringRef());
- if (auto function = parser.ParseAsFunctionDefinition()) {
- m_basename = function.getValue().name.basename;
- m_context = function.getValue().name.context;
- m_arguments = function.getValue().arguments;
- m_qualifiers = function.getValue().qualifiers;
- m_parse_error = false;
+ // ConstString mangled;
+ // m_full.GetMangledCounterpart(mangled);
+ // printf ("\n parsing = '%s'\n", m_full.GetCString());
+ // if (mangled)
+ // printf (" mangled = '%s'\n", mangled.GetCString());
+ m_parse_error = false;
+ m_parsed = true;
+ llvm::StringRef full(m_full.GetCString());
+
+ size_t arg_start, arg_end;
+ llvm::StringRef parens("()", 2);
+ if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) {
+ m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
+ if (arg_end + 1 < full.size())
+ m_qualifiers = full.substr(arg_end + 1);
+ if (arg_start > 0) {
+ size_t basename_end = arg_start;
+ size_t context_start = 0;
+ size_t context_end = llvm::StringRef::npos;
+ if (basename_end > 0 && full[basename_end - 1] == '>') {
+ // TODO: handle template junk...
+ // Templated function
+ size_t template_start, template_end;
+ llvm::StringRef lt_gt("<>", 2);
+ if (ReverseFindMatchingChars(full, lt_gt, template_start,
+ template_end, basename_end)) {
+ // Check for templated functions that include return type like:
+ // 'void foo<Int>()'
+ context_start = full.rfind(' ', template_start);
+ if (context_start == llvm::StringRef::npos)
+ context_start = 0;
+ else
+ ++context_start;
+
+ context_end = full.rfind(':', template_start);
+ if (context_end == llvm::StringRef::npos ||
+ context_end < context_start)
+ context_end = context_start;
+ } else {
+ context_end = full.rfind(':', basename_end);
+ }
+ } else if (context_end == llvm::StringRef::npos) {
+ context_end = full.rfind(':', basename_end);
+ }
+
+ if (context_end == llvm::StringRef::npos)
+ m_basename = full.substr(0, basename_end);
+ else {
+ if (context_start < context_end)
+ m_context =
+ full.substr(context_start, context_end - 1 - context_start);
+ const size_t basename_begin = context_end + 1;
+ m_basename =
+ full.substr(basename_begin, basename_end - basename_begin);
+ }
+ m_type = eTypeUnknownMethod;
} else {
m_parse_error = true;
+ return;
+ }
+
+ if (!IsValidBasename(m_basename)) {
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_parse_error = true;
}
+ } else {
+ m_parse_error = true;
}
- m_parsed = true;
}
}
@@ -240,13 +273,14 @@ llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() {
std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() {
if (!m_parsed)
Parse();
- if (m_context.empty())
- return m_basename;
+ if (m_basename.empty() || m_context.empty())
+ return std::string();
std::string res;
res += m_context;
res += "::";
res += m_basename;
+
return res;
}
@@ -262,10 +296,13 @@ bool CPlusPlusLanguage::IsCPPMangledName(const char *name) {
bool CPlusPlusLanguage::ExtractContextAndIdentifier(
const char *name, llvm::StringRef &context, llvm::StringRef &identifier) {
- CPlusPlusNameParser parser(name);
- if (auto full_name = parser.ParseAsFullName()) {
- identifier = full_name.getValue().basename;
- context = full_name.getValue().context;
+ static RegularExpression g_basename_regex(llvm::StringRef(
+ "^(([A-Za-z_][A-Za-z_0-9]*::)*)(~?[A-Za-z_~][A-Za-z_0-9]*)$"));
+ RegularExpression::Match match(4);
+ if (g_basename_regex.Execute(llvm::StringRef::withNullAsEmpty(name),
+ &match)) {
+ match.GetMatchAtIndex(name, 1, context);
+ match.GetMatchAtIndex(name, 3, identifier);
return true;
}
return false;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
index 056cced2808..dbc1d59c8ba 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h
@@ -29,13 +29,20 @@ class CPlusPlusLanguage : public Language {
public:
class MethodName {
public:
+ enum Type {
+ eTypeInvalid,
+ eTypeUnknownMethod,
+ eTypeClassMethod,
+ eTypeInstanceMethod
+ };
+
MethodName()
: m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers(),
- m_parsed(false), m_parse_error(false) {}
+ m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {}
MethodName(const ConstString &s)
: m_full(s), m_basename(), m_context(), m_arguments(), m_qualifiers(),
- m_parsed(false), m_parse_error(false) {}
+ m_type(eTypeInvalid), m_parsed(false), m_parse_error(false) {}
void Clear();
@@ -44,9 +51,13 @@ public:
Parse();
if (m_parse_error)
return false;
+ if (m_type == eTypeInvalid)
+ return false;
return (bool)m_full;
}
+ Type GetType() const { return m_type; }
+
const ConstString &GetFullName() const { return m_full; }
std::string GetScopeQualifiedName();
@@ -61,7 +72,6 @@ public:
protected:
void Parse();
- bool TrySimplifiedParse();
ConstString m_full; // Full name:
// "lldb::SBTarget::GetBreakpointAtIndex(unsigned int)
@@ -70,6 +80,7 @@ public:
llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
llvm::StringRef m_qualifiers; // Qualifiers: "const"
+ Type m_type;
bool m_parsed;
bool m_parse_error;
};
@@ -110,7 +121,7 @@ public:
// If the name is a lone C identifier (e.g. C) or a qualified C identifier
// (e.g. A::B::C) it will return true,
// and identifier will be the identifier (C and C respectively) and the
- // context will be "" and "A::B" respectively.
+ // context will be "" and "A::B::" respectively.
// If the name fails the heuristic matching for a qualified or unqualified
// C/C++ identifier, then it will return false
// and identifier and context will be unchanged.
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
deleted file mode 100644
index 7736c4f545e..00000000000
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp
+++ /dev/null
@@ -1,614 +0,0 @@
-//===-- CPlusPlusNameParser.cpp ---------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CPlusPlusNameParser.h"
-
-#include "clang/Basic/IdentifierTable.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/Threading.h"
-
-using namespace lldb;
-using namespace lldb_private;
-using llvm::Optional;
-using llvm::None;
-using ParsedFunction = lldb_private::CPlusPlusNameParser::ParsedFunction;
-using ParsedName = lldb_private::CPlusPlusNameParser::ParsedName;
-namespace tok = clang::tok;
-
-Optional<ParsedFunction> CPlusPlusNameParser::ParseAsFunctionDefinition() {
- m_next_token_index = 0;
- Optional<ParsedFunction> result(None);
-
- // Try to parse the name as function without a return type specified
- // e.g. main(int, char*[])
- {
- Bookmark start_position = SetBookmark();
- result = ParseFunctionImpl(false);
- if (result && !HasMoreTokens())
- return result;
- }
-
- // Try to parse the name as function with function pointer return type
- // e.g. void (*get_func(const char*))()
- result = ParseFuncPtr(true);
- if (result)
- return result;
-
- // Finally try to parse the name as a function with non-function return type
- // e.g. int main(int, char*[])
- result = ParseFunctionImpl(true);
- return result;
-}
-
-Optional<ParsedName> CPlusPlusNameParser::ParseAsFullName() {
- m_next_token_index = 0;
- Optional<ParsedNameRanges> name_ranges = ParseFullNameImpl();
- if (!name_ranges)
- return None;
- ParsedName result;
- result.basename = GetTextForRange(name_ranges.getValue().basename_range);
- result.context = GetTextForRange(name_ranges.getValue().context_range);
- return result;
-}
-
-bool CPlusPlusNameParser::HasMoreTokens() {
- return m_next_token_index < m_tokens.size();
-}
-
-void CPlusPlusNameParser::Advance() { ++m_next_token_index; }
-
-void CPlusPlusNameParser::TakeBack() { --m_next_token_index; }
-
-bool CPlusPlusNameParser::ConsumeToken(tok::TokenKind kind) {
- if (!HasMoreTokens())
- return false;
-
- if (!Peek().is(kind))
- return false;
-
- Advance();
- return true;
-}
-
-template <typename... Ts> bool CPlusPlusNameParser::ConsumeToken(Ts... kinds) {
- if (!HasMoreTokens())
- return false;
-
- if (!Peek().isOneOf(kinds...))
- return false;
-
- Advance();
- return true;
-}
-
-CPlusPlusNameParser::Bookmark CPlusPlusNameParser::SetBookmark() {
- return Bookmark(m_next_token_index);
-}
-
-size_t CPlusPlusNameParser::GetCurrentPosition() { return m_next_token_index; }
-
-clang::Token &CPlusPlusNameParser::Peek() {
- assert(HasMoreTokens());
- return m_tokens[m_next_token_index];
-}
-
-Optional<ParsedFunction>
-CPlusPlusNameParser::ParseFunctionImpl(bool expect_return_type) {
- Bookmark start_position = SetBookmark();
- if (expect_return_type) {
- // Consume return type if it's expected.
- if (!ConsumeTypename())
- return None;
- }
-
- auto maybe_name = ParseFullNameImpl();
- if (!maybe_name) {
- return None;
- }
-
- size_t argument_start = GetCurrentPosition();
- if (!ConsumeArguments()) {
- return None;
- }
-
- size_t qualifiers_start = GetCurrentPosition();
- SkipFunctionQualifiers();
- size_t end_position = GetCurrentPosition();
-
- ParsedFunction result;
- result.name.basename = GetTextForRange(maybe_name.getValue().basename_range);
- result.name.context = GetTextForRange(maybe_name.getValue().context_range);
- result.arguments = GetTextForRange(Range(argument_start, qualifiers_start));
- result.qualifiers = GetTextForRange(Range(qualifiers_start, end_position));
- start_position.Remove();
- return result;
-}
-
-Optional<ParsedFunction>
-CPlusPlusNameParser::ParseFuncPtr(bool expect_return_type) {
- Bookmark start_position = SetBookmark();
- if (expect_return_type) {
- // Consume return type.
- if (!ConsumeTypename())
- return None;
- }
-
- if (!ConsumeToken(tok::l_paren))
- return None;
- if (!ConsumePtrsAndRefs())
- return None;
-
- {
- Bookmark before_inner_function_pos = SetBookmark();
- auto maybe_inner_function_name = ParseFunctionImpl(false);
- if (maybe_inner_function_name)
- if (ConsumeToken(tok::r_paren))
- if (ConsumeArguments()) {
- SkipFunctionQualifiers();
- start_position.Remove();
- before_inner_function_pos.Remove();
- return maybe_inner_function_name;
- }
- }
-
- auto maybe_inner_function_ptr_name = ParseFuncPtr(false);
- if (maybe_inner_function_ptr_name)
- if (ConsumeToken(tok::r_paren))
- if (ConsumeArguments()) {
- SkipFunctionQualifiers();
- start_position.Remove();
- return maybe_inner_function_ptr_name;
- }
- return None;
-}
-
-bool CPlusPlusNameParser::ConsumeArguments() {
- return ConsumeBrackets(tok::l_paren, tok::r_paren);
-}
-
-bool CPlusPlusNameParser::ConsumeTemplateArgs() {
- Bookmark start_position = SetBookmark();
- if (!HasMoreTokens() || Peek().getKind() != tok::less)
- return false;
- Advance();
-
- // Consuming template arguments is a bit trickier than consuming function
- // arguments, because '<' '>' brackets are not always trivially balanced.
- // In some rare cases tokens '<' and '>' can appear inside template arguments
- // as arithmetic or shift operators not as template brackets.
- // Examples: std::enable_if<(10u)<(64), bool>
- // f<A<operator<(X,Y)::Subclass>>
- // Good thing that compiler makes sure that really ambiguous cases of
- // '>' usage should be enclosed within '()' brackets.
- int template_counter = 1;
- bool can_open_template = false;
- while (HasMoreTokens() && template_counter > 0) {
- tok::TokenKind kind = Peek().getKind();
- switch (kind) {
- case tok::greatergreater:
- template_counter -= 2;
- can_open_template = false;
- Advance();
- break;
- case tok::greater:
- --template_counter;
- can_open_template = false;
- Advance();
- break;
- case tok::less:
- // '<' is an attempt to open a subteamplte
- // check if parser is at the point where it's actually possible,
- // otherwise it's just a part of an expression like 'sizeof(T)<(10)'.
- // No need to do the same for '>' because compiler actually makes sure
- // that '>' always surrounded by brackets to avoid ambiguity.
- if (can_open_template)
- ++template_counter;
- can_open_template = false;
- Advance();
- break;
- case tok::kw_operator: // C++ operator overloading.
- if (!ConsumeOperator())
- return false;
- can_open_template = true;
- break;
- case tok::raw_identifier:
- can_open_template = true;
- Advance();
- break;
- case tok::l_square:
- if (!ConsumeBrackets(tok::l_square, tok::r_square))
- return false;
- can_open_template = false;
- break;
- case tok::l_paren:
- if (!ConsumeArguments())
- return false;
- can_open_template = false;
- break;
- default:
- can_open_template = false;
- Advance();
- break;
- }
- }
-
- assert(template_counter >= 0);
- if (template_counter > 0) {
- return false;
- }
- start_position.Remove();
- return true;
-}
-
-bool CPlusPlusNameParser::ConsumeAnonymousNamespace() {
- Bookmark start_position = SetBookmark();
- if (!ConsumeToken(tok::l_paren)) {
- return false;
- }
- constexpr llvm::StringLiteral g_anonymous("anonymous");
- if (HasMoreTokens() && Peek().is(tok::raw_identifier) &&
- Peek().getRawIdentifier() == g_anonymous) {
- Advance();
- } else {
- return false;
- }
-
- if (!ConsumeToken(tok::kw_namespace)) {
- return false;
- }
-
- if (!ConsumeToken(tok::r_paren)) {
- return false;
- }
- start_position.Remove();
- return true;
-}
-
-bool CPlusPlusNameParser::ConsumeBrackets(tok::TokenKind left,
- tok::TokenKind right) {
- Bookmark start_position = SetBookmark();
- if (!HasMoreTokens() || Peek().getKind() != left)
- return false;
- Advance();
-
- int counter = 1;
- while (HasMoreTokens() && counter > 0) {
- tok::TokenKind kind = Peek().getKind();
- if (kind == right)
- --counter;
- else if (kind == left)
- ++counter;
- Advance();
- }
-
- assert(counter >= 0);
- if (counter > 0) {
- return false;
- }
- start_position.Remove();
- return true;
-}
-
-bool CPlusPlusNameParser::ConsumeOperator() {
- Bookmark start_position = SetBookmark();
- if (!ConsumeToken(tok::kw_operator))
- return false;
-
- if (!HasMoreTokens()) {
- return false;
- }
-
- const auto &token = Peek();
- switch (token.getKind()) {
- case tok::kw_new:
- case tok::kw_delete:
- // This is 'new' or 'delete' operators.
- Advance();
- // Check for array new/delete.
- if (HasMoreTokens() && Peek().is(tok::l_square)) {
- // Consume the '[' and ']'.
- if (!ConsumeBrackets(tok::l_square, tok::r_square))
- return false;
- }
- break;
-
-#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \
- case tok::Token: \
- Advance(); \
- break;
-#define OVERLOADED_OPERATOR_MULTI(Name, Spelling, Unary, Binary, MemberOnly)
-#include "clang/Basic/OperatorKinds.def"
-#undef OVERLOADED_OPERATOR
-#undef OVERLOADED_OPERATOR_MULTI
-
- case tok::l_paren:
- // Call operator consume '(' ... ')'.
- if (ConsumeBrackets(tok::l_paren, tok::r_paren))
- break;
- return false;
-
- case tok::l_square:
- // This is a [] operator.
- // Consume the '[' and ']'.
- if (ConsumeBrackets(tok::l_square, tok::r_square))
- break;
- return false;
-
- default:
- // This might be a cast operator.
- if (ConsumeTypename())
- break;
- return false;
- }
- start_position.Remove();
- return true;
-}
-
-void CPlusPlusNameParser::SkipTypeQualifiers() {
- while (ConsumeToken(tok::kw_const, tok::kw_volatile))
- ;
-}
-
-void CPlusPlusNameParser::SkipFunctionQualifiers() {
- while (ConsumeToken(tok::kw_const, tok::kw_volatile, tok::amp, tok::ampamp))
- ;
-}
-
-bool CPlusPlusNameParser::ConsumeBuiltinType() {
- bool result = false;
- bool continue_parsing = true;
- // Built-in types can be made of a few keywords
- // like 'unsigned long long int'. This function
- // consumes all built-in type keywords without
- // checking if they make sense like 'unsigned char void'.
- while (continue_parsing && HasMoreTokens()) {
- switch (Peek().getKind()) {
- case tok::kw_short:
- case tok::kw_long:
- case tok::kw___int64:
- case tok::kw___int128:
- case tok::kw_signed:
- case tok::kw_unsigned:
- case tok::kw_void:
- case tok::kw_char:
- case tok::kw_int:
- case tok::kw_half:
- case tok::kw_float:
- case tok::kw_double:
- case tok::kw___float128:
- case tok::kw_wchar_t:
- case tok::kw_bool:
- case tok::kw_char16_t:
- case tok::kw_char32_t:
- result = true;
- Advance();
- break;
- default:
- continue_parsing = false;
- break;
- }
- }
- return result;
-}
-
-void CPlusPlusNameParser::SkipPtrsAndRefs() {
- // Ignoring result.
- ConsumePtrsAndRefs();
-}
-
-bool CPlusPlusNameParser::ConsumePtrsAndRefs() {
- bool found = false;
- SkipTypeQualifiers();
- while (ConsumeToken(tok::star, tok::amp, tok::ampamp, tok::kw_const,
- tok::kw_volatile)) {
- found = true;
- SkipTypeQualifiers();
- }
- return found;
-}
-
-bool CPlusPlusNameParser::ConsumeTypename() {
- Bookmark start_position = SetBookmark();
- SkipTypeQualifiers();
- if (!ConsumeBuiltinType()) {
- if (!ParseFullNameImpl())
- return false;
- }
- SkipPtrsAndRefs();
- start_position.Remove();
- return true;
-}
-
-Optional<CPlusPlusNameParser::ParsedNameRanges>
-CPlusPlusNameParser::ParseFullNameImpl() {
- // Name parsing state machine.
- enum class State {
- Beginning, // start of the name
- AfterTwoColons, // right after ::
- AfterIdentifier, // right after alphanumerical identifier ([a-z0-9_]+)
- AfterTemplate, // right after template brackets (<something>)
- AfterOperator, // right after name of C++ operator
- };
-
- Bookmark start_position = SetBookmark();
- State state = State::Beginning;
- bool continue_parsing = true;
- Optional<size_t> last_coloncolon_position = None;
-
- while (continue_parsing && HasMoreTokens()) {
- const auto &token = Peek();
- switch (token.getKind()) {
- case tok::raw_identifier: // Just a name.
- if (state != State::Beginning && state != State::AfterTwoColons) {
- continue_parsing = false;
- break;
- }
- Advance();
- state = State::AfterIdentifier;
- break;
- case tok::l_paren: {
- if (state == State::Beginning || state == State::AfterTwoColons) {
- // (anonymous namespace)
- if (ConsumeAnonymousNamespace()) {
- state = State::AfterIdentifier;
- break;
- }
- }
-
- // Type declared inside a function 'func()::Type'
- if (state != State::AfterIdentifier && state != State::AfterTemplate &&
- state != State::AfterOperator) {
- continue_parsing = false;
- break;
- }
- Bookmark l_paren_position = SetBookmark();
- // Consume the '(' ... ') [const]'.
- if (!ConsumeArguments()) {
- continue_parsing = false;
- break;
- }
- SkipFunctionQualifiers();
-
- // Consume '::'
- size_t coloncolon_position = GetCurrentPosition();
- if (!ConsumeToken(tok::coloncolon)) {
- continue_parsing = false;
- break;
- }
- l_paren_position.Remove();
- last_coloncolon_position = coloncolon_position;
- state = State::AfterTwoColons;
- break;
- }
- case tok::coloncolon: // Type nesting delimiter.
- if (state != State::Beginning && state != State::AfterIdentifier &&
- state != State::AfterTemplate) {
- continue_parsing = false;
- break;
- }
- last_coloncolon_position = GetCurrentPosition();
- Advance();
- state = State::AfterTwoColons;
- break;
- case tok::less: // Template brackets.
- if (state != State::AfterIdentifier && state != State::AfterOperator) {
- continue_parsing = false;
- break;
- }
- if (!ConsumeTemplateArgs()) {
- continue_parsing = false;
- break;
- }
- state = State::AfterTemplate;
- break;
- case tok::kw_operator: // C++ operator overloading.
- if (state != State::Beginning && state != State::AfterTwoColons) {
- continue_parsing = false;
- break;
- }
- if (!ConsumeOperator()) {
- continue_parsing = false;
- break;
- }
- state = State::AfterOperator;
- break;
- case tok::tilde: // Destructor.
- if (state != State::Beginning && state != State::AfterTwoColons) {
- continue_parsing = false;
- break;
- }
- Advance();
- if (ConsumeToken(tok::raw_identifier)) {
- state = State::AfterIdentifier;
- } else {
- TakeBack();
- continue_parsing = false;
- }
- break;
- default:
- continue_parsing = false;
- break;
- }
- }
-
- if (state == State::AfterIdentifier || state == State::AfterOperator ||
- state == State::AfterTemplate) {
- ParsedNameRanges result;
- if (last_coloncolon_position) {
- result.context_range = Range(start_position.GetSavedPosition(),
- last_coloncolon_position.getValue());
- result.basename_range =
- Range(last_coloncolon_position.getValue() + 1, GetCurrentPosition());
- } else {
- result.basename_range =
- Range(start_position.GetSavedPosition(), GetCurrentPosition());
- }
- start_position.Remove();
- return result;
- } else {
- return None;
- }
-}
-
-llvm::StringRef CPlusPlusNameParser::GetTextForRange(const Range &range) {
- if (range.empty())
- return llvm::StringRef();
- assert(range.begin_index < range.end_index);
- assert(range.begin_index < m_tokens.size());
- assert(range.end_index <= m_tokens.size());
- clang::Token &first_token = m_tokens[range.begin_index];
- clang::Token &last_token = m_tokens[range.end_index - 1];
- clang::SourceLocation start_loc = first_token.getLocation();
- clang::SourceLocation end_loc = last_token.getLocation();
- unsigned start_pos = start_loc.getRawEncoding();
- unsigned end_pos = end_loc.getRawEncoding() + last_token.getLength();
- return m_text.take_front(end_pos).drop_front(start_pos);
-}
-
-static const clang::LangOptions &GetLangOptions() {
- static clang::LangOptions g_options;
- static llvm::once_flag g_once_flag;
- llvm::call_once(g_once_flag, []() {
- g_options.LineComment = true;
- g_options.C99 = true;
- g_options.C11 = true;
- g_options.CPlusPlus = true;
- g_options.CPlusPlus11 = true;
- g_options.CPlusPlus14 = true;
- g_options.CPlusPlus1z = true;
- });
- return g_options;
-}
-
-static const llvm::StringMap<tok::TokenKind> &GetKeywordsMap() {
- static llvm::StringMap<tok::TokenKind> g_map{
-#define KEYWORD(Name, Flags) {llvm::StringRef(#Name), tok::kw_##Name},
-#include "clang/Basic/TokenKinds.def"
-#undef KEYWORD
- };
- return g_map;
-}
-
-void CPlusPlusNameParser::ExtractTokens() {
- clang::Lexer lexer(clang::SourceLocation(), GetLangOptions(), m_text.data(),
- m_text.data(), m_text.data() + m_text.size());
- const auto &kw_map = GetKeywordsMap();
- clang::Token token;
- for (lexer.LexFromRawLexer(token); !token.is(clang::tok::eof);
- lexer.LexFromRawLexer(token)) {
- if (token.is(clang::tok::raw_identifier)) {
- auto it = kw_map.find(token.getRawIdentifier());
- if (it != kw_map.end()) {
- token.setKind(it->getValue());
- }
- }
-
- m_tokens.push_back(token);
- }
-}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
deleted file mode 100644
index f90b4f2e28e..00000000000
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h
+++ /dev/null
@@ -1,176 +0,0 @@
-//===-- CPlusPlusNameParser.h -----------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_CPlusPlusNameParser_h_
-#define liblldb_CPlusPlusNameParser_h_
-
-// C Includes
-// C++ Includes
-
-// Other libraries and framework includes
-#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-
-// Project includes
-#include "lldb/Utility/ConstString.h"
-#include "lldb/lldb-private.h"
-
-namespace lldb_private {
-
-// Helps to validate and obtain various parts of C++ definitions.
-class CPlusPlusNameParser {
-public:
- CPlusPlusNameParser(llvm::StringRef text) : m_text(text) { ExtractTokens(); }
-
- struct ParsedName {
- llvm::StringRef basename;
- llvm::StringRef context;
- };
-
- struct ParsedFunction {
- ParsedName name;
- llvm::StringRef arguments;
- llvm::StringRef qualifiers;
- };
-
- // Treats given text as a function definition and parses it.
- // Function definition might or might not have a return type and this should
- // change parsing result.
- // Examples:
- // main(int, chat const*)
- // T fun(int, bool)
- // std::vector<int>::push_back(int)
- // int& map<int, pair<short, int>>::operator[](short) const
- // int (*get_function(const chat *))()
- llvm::Optional<ParsedFunction> ParseAsFunctionDefinition();
-
- // Treats given text as a potentially nested name of C++ entity (function,
- // class, field) and parses it.
- // Examples:
- // main
- // fun
- // std::vector<int>::push_back
- // map<int, pair<short, int>>::operator[]
- // func<C>(int, C&)::nested_class::method
- llvm::Optional<ParsedName> ParseAsFullName();
-
-private:
- // A C++ definition to parse.
- llvm::StringRef m_text;
- // Tokens extracted from m_text.
- llvm::SmallVector<clang::Token, 30> m_tokens;
- // Index of the next token to look at from m_tokens.
- size_t m_next_token_index = 0;
-
- // Range of tokens saved in m_next_token_index.
- struct Range {
- size_t begin_index = 0;
- size_t end_index = 0;
-
- Range() {}
- Range(size_t begin, size_t end) : begin_index(begin), end_index(end) {
- assert(end >= begin);
- }
-
- size_t size() const { return end_index - begin_index; }
-
- bool empty() const { return size() == 0; }
- };
-
- struct ParsedNameRanges {
- Range basename_range;
- Range context_range;
- };
-
- // Bookmark automatically restores parsing position (m_next_token_index)
- // when destructed unless it's manually removed with Remove().
- class Bookmark {
- public:
- Bookmark(size_t &position)
- : m_position(position), m_position_value(position) {}
- Bookmark(const Bookmark &) = delete;
- Bookmark(Bookmark &&b)
- : m_position(b.m_position), m_position_value(b.m_position_value),
- m_restore(b.m_restore) {
- b.Remove();
- }
- Bookmark &operator=(Bookmark &&) = delete;
- Bookmark &operator=(const Bookmark &) = delete;
-
- void Remove() { m_restore = false; }
- size_t GetSavedPosition() { return m_position_value; }
- ~Bookmark() {
- if (m_restore) {
- m_position = m_position_value;
- }
- }
-
- private:
- size_t &m_position;
- size_t m_position_value;
- bool m_restore = true;
- };
-
- bool HasMoreTokens();
- void Advance();
- void TakeBack();
- bool ConsumeToken(clang::tok::TokenKind kind);
- template <typename... Ts> bool ConsumeToken(Ts... kinds);
- Bookmark SetBookmark();
- size_t GetCurrentPosition();
- clang::Token &Peek();
- bool ConsumeBrackets(clang::tok::TokenKind left, clang::tok::TokenKind right);
-
- llvm::Optional<ParsedFunction> ParseFunctionImpl(bool expect_return_type);
-
- // Parses functions returning function pointers 'string (*f(int x))(float y)'
- llvm::Optional<ParsedFunction> ParseFuncPtr(bool expect_return_type);
-
- // Consumes function arguments enclosed within '(' ... ')'
- bool ConsumeArguments();
-
- // Consumes template arguments enclosed within '<' ... '>'
- bool ConsumeTemplateArgs();
-
- // Consumes '(anonymous namespace)'
- bool ConsumeAnonymousNamespace();
-
- // Consumes operator declaration like 'operator *' or 'operator delete []'
- bool ConsumeOperator();
-
- // Skips 'const' and 'volatile'
- void SkipTypeQualifiers();
-
- // Skips 'const', 'volatile', '&', '&&' in the end of the function.
- void SkipFunctionQualifiers();
-
- // Consumes built-in types like 'int' or 'unsigned long long int'
- bool ConsumeBuiltinType();
-
- // Skips 'const' and 'volatile'
- void SkipPtrsAndRefs();
-
- // Consumes things like 'const * const &'
- bool ConsumePtrsAndRefs();
-
- // Consumes full type name like 'Namespace::Class<int>::Method()::InnerClass'
- bool ConsumeTypename();
-
- llvm::Optional<ParsedNameRanges> ParseFullNameImpl();
- llvm::StringRef GetTextForRange(const Range &range);
-
- // Populate m_tokens by calling clang lexer on m_text.
- void ExtractTokens();
-};
-
-} // namespace lldb_private
-
-#endif // liblldb_CPlusPlusNameParser_h_
OpenPOWER on IntegriCloud