| // 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/expr/resolve_variant.h" |
| |
| #include <inttypes.h> |
| |
| #include "src/developer/debug/zxdb/expr/eval_context.h" |
| #include "src/developer/debug/zxdb/expr/expr_value.h" |
| #include "src/developer/debug/zxdb/expr/resolve_collection.h" |
| #include "src/developer/debug/zxdb/symbols/data_member.h" |
| #include "src/developer/debug/zxdb/symbols/variant.h" |
| #include "src/developer/debug/zxdb/symbols/variant_part.h" |
| |
| namespace zxdb { |
| |
| Err ResolveVariant(const fxl::RefPtr<EvalContext>& context, const ExprValue& value, |
| const Collection* collection, const VariantPart* variant_part, |
| fxl::RefPtr<Variant>* result) { |
| // Resolve the discriminant value. It is effectively a member of the enclosing structure. |
| const DataMember* discr_member = variant_part->discriminant().Get()->AsDataMember(); |
| if (!discr_member) |
| return Err("Missing discriminant for variant."); |
| |
| // Variants don't have static variant members or virtual inheritance. |
| ErrOrValue discr_value = |
| ResolveNonstaticMember(context, value, FoundMember(collection, discr_member)); |
| if (discr_value.has_error()) |
| return discr_value.err(); |
| |
| // Expect the discriminant value to resolve to a <= 64-bit number. |
| // |
| // NOTE: there is some trickery with signed/unsigned values as described in the |
| // Variant.discr_value() getter. If we need to support signed discriminants this block will have |
| // to be updated. |
| uint64_t discr = 0; |
| if (Err err = discr_value.value().PromoteTo64(&discr); err.has_error()) |
| return err; |
| |
| // Check against all variants and also look for the default variant. |
| const Variant* default_var = nullptr; |
| for (const auto& lazy_var : variant_part->variants()) { |
| const Variant* var = lazy_var.Get()->AsVariant(); |
| if (!var) |
| continue; |
| |
| if (var->discr_value()) { |
| if (*var->discr_value() == discr) { |
| // Found match. |
| *result = RefPtrTo(var); |
| return Err(); |
| } |
| } else { |
| // No discriminant value set on the variant means it's the default one. |
| default_var = var; |
| } |
| } |
| |
| // No match means use the default value if there is one. |
| if (default_var) { |
| *result = RefPtrTo(default_var); |
| return Err(); |
| } |
| |
| return Err("Discriminant value of 0x%" PRIx64 " does not match any of the Variants.", discr); |
| } |
| |
| } // namespace zxdb |