blob: 818ae834635374180d51df929ed24b2e1eb43ccd [file] [log] [blame]
// Copyright 2018 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/symbols/collection.h"
#include "src/developer/debug/zxdb/symbols/compile_unit.h"
#include "src/developer/debug/zxdb/symbols/data_member.h"
#include "src/developer/debug/zxdb/symbols/symbol_utils.h"
#include "src/lib/fxl/strings/string_printf.h"
namespace zxdb {
Collection::Collection(DwarfTag tag, std::string name) : Type(tag) {
set_assigned_name(std::move(name));
}
Collection::~Collection() = default;
const char* Collection::CallingConventionToString(CallingConvention cc) {
switch (cc) {
case kNormalCall:
return "DW_CC_normal";
case kPassByReference:
return "DW_CC_pass_by_reference";
case kPassByValue:
return "DW_CC_pass_by_value";
}
return "<invalid>";
}
const Collection* Collection::AsCollection() const { return this; }
Collection::SpecialType Collection::GetSpecialType() const {
if (!special_type_)
special_type_ = ComputeSpecialType();
return *special_type_;
}
const char* Collection::GetKindString() const {
switch (tag()) {
case DwarfTag::kStructureType:
return "struct";
case DwarfTag::kClassType:
return "class";
case DwarfTag::kUnionType:
return "union";
default:
return "unknown";
}
}
Identifier Collection::ComputeIdentifier() const {
Identifier result = GetSymbolScopePrefix(this);
if (auto& assigned_name = GetAssignedName(); !assigned_name.empty()) {
result.AppendComponent(IdentifierComponent(assigned_name));
} else {
// Provide a name for anonymous structs.
result.AppendComponent(IdentifierComponent(fxl::StringPrintf("(anon %s)", GetKindString())));
}
return result;
}
Collection::SpecialType Collection::ComputeSpecialType() const {
// All the special types use "structure" as their tag.
if (tag() != DwarfTag::kStructureType)
return kNotSpecial;
// As of this writing the language is slower to check because it involves
// decoding the CompileUnit which is not normally otherwise needed. As a
// result we try to check that last.
if (variant_part_) {
// Having a variant part and no members currently means we consider it a
// Rust enum. This may need to be enhanced for fxbug.dev/6466 (support Rust
// generators).
//
// No other special types have variants.
if (data_members_.empty() && GetLanguage() == DwarfLang::kRust)
return kRustEnum;
return kNotSpecial;
}
// Everything below requires at least one member.
if (data_members_.empty())
return kNotSpecial;
// Here we're checking for the two types of Rust tuples, regular tuples and
// tuple structs. Prefer to decode the first data member (it's very likely to
// be needed later no matter what) before the language.
//
// Tuples have members labeled starting counting from 0 with two leading
// underscores: __0, __1, __2, etc. With this heuristic we assume they're
// encoded in order in the symbols and that __0 will be first. Currently
// we check only the first one but this could be more precise (if slower)
// by checking to make sure all members are such numbers in sequential order.
const DataMember* first_member = data_members_[0].Get()->As<DataMember>();
if (!first_member)
return kNotSpecial;
if (first_member->GetAssignedName() != "__0")
return kNotSpecial;
// Now that we're pretty sure this looks like some kind of Rust tuple, double
// check the language.
if (GetLanguage() != DwarfLang::kRust)
return kNotSpecial;
// Either type of Rust tuple. Regular types are assigned names like
// "(i32, i32)" while struct tuples have regular names. Use the assigned name
// and not the full name because we don't want any namespace qualifications.
const std::string& assigned_name = GetAssignedName();
if (assigned_name.size() > 2 && assigned_name[0] == '(' && assigned_name.back() == ')')
return kRustTuple;
return kRustTupleStruct;
}
} // namespace zxdb