Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 96e15c9e authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Fix template support."

parents 55c9284f 584333e3
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -334,6 +334,29 @@ TEST(DemangleTest, TemplateFunction) {
  // Template within templates.
  ASSERT_EQ("one::two<three<char, int>>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE"));
  ASSERT_EQ("one::two<three<char, four<int>>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE"));

  ASSERT_EQ("one<char>", demangler.Parse("_Z3oneIcE"));
  ASSERT_EQ("one<void>", demangler.Parse("_Z3oneIvE"));
  ASSERT_EQ("one<void*>", demangler.Parse("_Z3oneIPvE"));
  ASSERT_EQ("one<void const>", demangler.Parse("_Z3oneIKvE"));
  ASSERT_EQ("one<char, int, bool>", demangler.Parse("_Z3oneIcibE"));
  ASSERT_EQ("one(two<three>)", demangler.Parse("_Z3one3twoIN5threeEE"));
  ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_Z3oneIciN3two5threeEE"));
  // Template within templates.
  ASSERT_EQ("one(two<three<char, int>>)", demangler.Parse("_Z3one3twoIN5threeIciEEE"));
  ASSERT_EQ("one(two<three<char, four<int>>>)",
            demangler.Parse("_Z3one3twoIN5threeIcN4fourIiEEEEE"));
}

TEST(DemangleTest, TemplateFunctionWithReturnType) {
  Demangler demangler;

  ASSERT_EQ("char one<int>(char)", demangler.Parse("_Z3oneIiEcc"));
  ASSERT_EQ("void one<int>()", demangler.Parse("_Z3oneIiEvv"));
  ASSERT_EQ("char one<int>()", demangler.Parse("_Z3oneIiEcv"));
  ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_Z3oneIiEcvv"));
  ASSERT_EQ("char one<int>()", demangler.Parse("_ZN3oneIiEEcv"));
  ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_ZN3oneIiEEcvv"));
}

TEST(DemangleTest, TemplateArguments) {
@@ -410,6 +433,28 @@ TEST(DemangleTest, ComplexSubstitution) {
            demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_"));
}

TEST(DemangleTest, TemplateSubstitution) {
  Demangler demangler;

  ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_ZN3oneIidEEvT_"));
  ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_ZN3oneIidEEvT0_"));
  ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_ZN3oneIidcvEEvT1_"));

  ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_Z3oneIidEvT_"));
  ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_Z3oneIidEvT0_"));
  ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_Z3oneIidcvEvT1_"));

  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
            demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT10_"));
  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
            demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT11_"));

  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
            demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT10_"));
  ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
            demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT11_"));
}

TEST(DemangleTest, StringTooLong) {
  Demangler demangler;

@@ -434,6 +479,13 @@ TEST(DemangleTest, BooleanLiterals) {
  ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE"));
  ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE"));
  ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE"));

  ASSERT_EQ("one<true>", demangler.Parse("_Z3oneILb1EE"));
  ASSERT_EQ("one<false>", demangler.Parse("_Z3oneILb0EE"));
  ASSERT_EQ("one<false, true>", demangler.Parse("_Z3oneILb0ELb1EE"));

  ASSERT_EQ("one(two<three<four>, false, true>)",
            demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE"));
}

TEST(DemangleTest, demangle) {
+110 −3
Original line number Diff line number Diff line
@@ -347,6 +347,33 @@ const char* Demangler::ParseS(const char* name) {
  return name + 1;
}

const char* Demangler::ParseT(const char* name) {
  if (template_saves_.empty()) {
    return nullptr;
  }

  if (*name == '_') {
    last_save_name_ = false;
    AppendCurrent(template_saves_[0]);
    return name + 1;
  }

  // Need to get the total number.
  char* end;
  unsigned long int index = strtoul(name, &end, 10) + 1;
  if (name == end || *end != '_') {
    return nullptr;
  }

  if (index >= template_saves_.size()) {
    return nullptr;
  }

  last_save_name_ = false;
  AppendCurrent(template_saves_[index]);
  return end + 1;
}

const char* Demangler::ParseFunctionName(const char* name) {
  if (*name == 'E') {
    if (parse_funcs_.empty()) {
@@ -371,9 +398,28 @@ const char* Demangler::ParseFunctionName(const char* name) {
    return name + 1;
  }

  if (*name == 'I') {
    state_stack_.push(cur_state_);
    cur_state_.Clear();

    parse_funcs_.push_back(parse_func_);
    parse_func_ = &Demangler::ParseFunctionNameTemplate;
    return name + 1;
  }

  return ParseComplexString(name);
}

const char* Demangler::ParseFunctionNameTemplate(const char* name) {
  if (*name == 'E' && name[1] == 'E') {
    // Only consider this a template with saves if it is right before
    // the end of the name.
    template_found_ = true;
    template_saves_ = cur_state_.args;
  }
  return ParseTemplateArgumentsComplex(name);
}

const char* Demangler::ParseComplexArgument(const char* name) {
  if (*name == 'E') {
    if (parse_funcs_.empty()) {
@@ -690,6 +736,7 @@ const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
    }
    parse_func_ = parse_funcs_.back();
    parse_funcs_.pop_back();

    FinalizeTemplate();
    Save(cur_state_.str, false);
    return name + 1;
@@ -699,6 +746,7 @@ const char* Demangler::ParseTemplateArgumentsComplex(const char* name) {
    parse_func_ = &Demangler::ParseTemplateLiteral;
    return name + 1;
  }

  return ParseArguments(name);
}

@@ -713,13 +761,33 @@ const char* Demangler::ParseTemplateArguments(const char* name) {
    AppendArgument(cur_state_.str);
    cur_state_.str.clear();
    return name + 1;
  } else if (*name == 'L') {
    // Literal value for a template.
    parse_funcs_.push_back(parse_func_);
    parse_func_ = &Demangler::ParseTemplateLiteral;
    return name + 1;
  }

  return ParseArguments(name);
}

const char* Demangler::ParseFunctionTemplateArguments(const char* name) {
  if (*name == 'E') {
    parse_func_ = parse_funcs_.back();
    parse_funcs_.pop_back();

    function_name_ += '<' + GetArgumentsString() + '>';
    template_found_ = true;
    template_saves_ = cur_state_.args;
    cur_state_.Clear();
    return name + 1;
  }
  return ParseTemplateArgumentsComplex(name);
}

const char* Demangler::FindFunctionName(const char* name) {
  if (*name == 'N') {
    parse_funcs_.push_back(&Demangler::ParseArguments);
    parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
    parse_func_ = &Demangler::ParseFunctionName;
    return name + 1;
  }
@@ -732,11 +800,35 @@ const char* Demangler::FindFunctionName(const char* name) {
    name = AppendOperatorString(name);
    function_name_ = cur_state_.str;
  }
  parse_func_ = &Demangler::ParseArguments;
  cur_state_.Clear();

  // Check for a template argument, which will still be part of the function
  // name.
  if (name != nullptr && *name == 'I') {
    parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel);
    parse_func_ = &Demangler::ParseFunctionTemplateArguments;
    return name + 1;
  }
  parse_func_ = &Demangler::ParseArgumentsAtTopLevel;
  return name;
}

const char* Demangler::ParseArgumentsAtTopLevel(const char* name) {
  // At the top level is the only place where T is allowed.
  if (*name == 'T') {
    name++;
    name = ParseT(name);
    if (name == nullptr) {
      return nullptr;
    }
    AppendArgument(cur_state_.str);
    cur_state_.str.clear();
    return name;
  }

  return Demangler::ParseArguments(name);
}

std::string Demangler::Parse(const char* name, size_t max_length) {
  if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') {
    // Name is not mangled.
@@ -757,6 +849,21 @@ std::string Demangler::Parse(const char* name, size_t max_length) {
    return name;
  }

  std::string return_type;
  if (template_found_) {
    // Only a single argument with a template is not allowed.
    if (cur_state_.args.size() == 1) {
      return name;
    }

    // If there are at least two arguments, this template has a return type.
    if (cur_state_.args.size() > 1) {
      // The first argument will be the return value.
      return_type = cur_state_.args[0] + ' ';
      cur_state_.args.erase(cur_state_.args.begin());
    }
  }

  std::string arg_str;
  if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") {
    // If the only argument is void, then don't print any args.
@@ -767,7 +874,7 @@ std::string Demangler::Parse(const char* name, size_t max_length) {
      arg_str = '(' + arg_str + ')';
    }
  }
  return function_name_ + arg_str + function_suffix_;
  return return_type + function_name_ + arg_str + function_suffix_;
}

std::string demangle(const char* name) {
+8 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ class Demangler {
  std::string GetArgumentsString();
  void FinalizeTemplate();
  const char* ParseS(const char* name);
  const char* ParseT(const char* name);
  const char* AppendOperatorString(const char* name);
  void Save(const std::string& str, bool is_name);

@@ -50,17 +51,21 @@ class Demangler {
    first_save_.clear();
    cur_state_.Clear();
    saves_.clear();
    template_saves_.clear();
    while (!state_stack_.empty()) {
      state_stack_.pop();
    }
    last_save_name_ = false;
    template_found_ = false;
  }

  using parse_func_type = const char* (Demangler::*)(const char*);
  parse_func_type parse_func_;
  std::vector<parse_func_type> parse_funcs_;
  std::vector<std::string> saves_;
  std::vector<std::string> template_saves_;
  bool last_save_name_;
  bool template_found_;

  std::string function_name_;
  std::string function_suffix_;
@@ -89,12 +94,15 @@ class Demangler {
  // Parsing functions.
  const char* ParseComplexString(const char* name);
  const char* ParseComplexArgument(const char* name);
  const char* ParseArgumentsAtTopLevel(const char* name);
  const char* ParseArguments(const char* name);
  const char* ParseTemplateArguments(const char* name);
  const char* ParseTemplateArgumentsComplex(const char* name);
  const char* ParseTemplateLiteral(const char* name);
  const char* ParseFunctionArgument(const char* name);
  const char* ParseFunctionName(const char* name);
  const char* ParseFunctionNameTemplate(const char* name);
  const char* ParseFunctionTemplateArguments(const char* name);
  const char* FindFunctionName(const char* name);
  const char* Fail(const char*) { return nullptr; }