blob: 5383c745548486e2b5a63c8c3f31962bfbf23a90 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/zxdb/console/format_function.h"
#include "src/developer/debug/zxdb/common/string_util.h"
#include "src/developer/debug/zxdb/console/command_utils.h"
#include "src/developer/debug/zxdb/symbols/collection.h"
#include "src/developer/debug/zxdb/symbols/function.h"
#include "src/developer/debug/zxdb/symbols/variable.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
// Checks if the function is a Clang-style lambda and formats it to the
// output. Returns true if there was a match, false means id wasn't a lambda.
//
// Clang lambdas are implemented as functions called "operator()" as a member
// of an unnamed class. GCC lambdas are also "operator()" but on a structure
// named like "<lambda(int)>" where the <...> lists the parameter types to the
// functions..
bool FormatClangLambda(const Function* function, OutputBuffer* out) {
if (!function->parent())
return false; // Not a member function.
if (function->GetAssignedName() != "operator()")
return false; // Not the right function name.
// This is currently designed assuming the file/line will be printed
// separately so aren't useful here. The main use of function printing is as
// part of locations, which will append the file/line after the function
// name.
//
// If this is used in contexts where the file/line isn't shown, we should add
// a flag and an optional_target_symbols parameter to this function so we can
// print it as:
// out->Append("λ @ " + DescribeFileLine(optional_target_symbols,
// function->decl_line()));
// so users can tell where the lambda function is.
const Collection* coll = function->parent().Get()->AsCollection();
if (coll && coll->tag() == DwarfTag::kClassType && coll->GetAssignedName().empty()) {
// Clang-style.
out->Append("λ");
return true;
} else if (coll && coll->tag() == DwarfTag::kStructureType &&
StringBeginsWith(coll->GetAssignedName(), "<lambda(")) {
// GCC-style.
out->Append("λ");
return true;
}
return false;
}
bool FormatRustClosure(const Function* function, OutputBuffer* out) {
// Rust closures currently look like
// "fuchsia_async::executor::{{impl}}::run_singlethreaded::{{closure}}<()>"
// The function "assigned name" will be just the last component.
if (!StringBeginsWith(function->GetAssignedName(), "{{closure}}"))
return false;
// As with the Clang lambda above, this assumes the file/line or function
// enclosing the original lambda is redundant.
out->Append("λ");
return true;
}
} // namespace
OutputBuffer FormatFunctionName(const Function* function, bool show_params) {
OutputBuffer result;
if (!FormatClangLambda(function, &result) && !FormatRustClosure(function, &result))
result = FormatIdentifier(function->GetIdentifier(), true);
const auto& params = function->parameters();
std::string params_str;
if (show_params) {
params_str.push_back('(');
for (size_t i = 0; i < params.size(); i++) {
if (i > 0)
params_str += ", ";
if (const Variable* var = params[i].Get()->AsVariable())
params_str += var->type().Get()->GetFullName();
}
params_str.push_back(')');
} else {
if (params.empty())
params_str += "()";
else
params_str += "(…)";
}
result.Append(Syntax::kComment, std::move(params_str));
return result;
}
} // namespace zxdb