static void walk_entity(entity_t *entity, const walk_env_t *const env) { env->declaration_func(entity, env->env); switch (entity->kind) { case ENTITY_VARIABLE: { const variable_t *variable = &entity->variable; const initializer_t *initializer = variable->initializer; walk_type(entity->declaration.type, env); if (initializer != NULL) { walk_initializer(initializer, env); } return; } case ENTITY_ENUM_VALUE: if (entity->enum_value.value != NULL) walk_expression(entity->enum_value.value, env); return; case ENTITY_TYPEDEF: walk_type(entity->declaration.type, env); return; case ENTITY_FUNCTION: walk_type(entity->declaration.type, env); if (entity->function.body != NULL) walk_statement(entity->function.body, env); return; case ENTITY_COMPOUND_MEMBER: case ENTITY_PARAMETER: walk_type(entity->declaration.type, env); return; case ENTITY_CLASS: case ENTITY_STRUCT: case ENTITY_UNION: walk_scope(&entity->compound.members, env); return; case ENTITY_NAMESPACE: walk_scope(&entity->namespacee.members, env); return; case ENTITY_ENUM: for (entity_t *entry = entity->enume.first_value; entry != NULL && entry->kind == ENTITY_ENUM_VALUE; entry = entry->base.next) { walk_entity(entry, env); } return; case ENTITY_LABEL: case ENTITY_LOCAL_LABEL: return; case ENTITY_ASM_ARGUMENT: walk_expression(entity->asm_argument.expression, env); return; } panic("invalid entity"); }
static void walk_type(type_t *const type, const walk_env_t *const env) { if (pset_find_ptr(env->visited_types, type) != NULL) return; pset_insert_ptr(env->visited_types, type); switch (type->kind) { case TYPE_ATOMIC: case TYPE_COMPLEX: case TYPE_IMAGINARY: case TYPE_REFERENCE: case TYPE_ERROR: case TYPE_VOID: case TYPE_BUILTIN_TEMPLATE: return; case TYPE_POINTER: walk_type(type->pointer.points_to, env); return; case TYPE_ARRAY: walk_type(type->array.element_type, env); if (type->array.size_expression != NULL) walk_expression(type->array.size_expression, env); return; case TYPE_FUNCTION: for (function_parameter_t *parameter = type->function.parameters; parameter != NULL; parameter = parameter->next) { walk_type(parameter->type, env); } walk_type(type->function.return_type, env); return; case TYPE_TYPEOF: { expression_t *const expr = type->typeoft.expression; if (expr) walk_expression(expr, env); return; } case TYPE_TYPEDEF: walk_entity((entity_t*)type->typedeft.typedefe, env); return; case TYPE_COMPOUND_STRUCT: case TYPE_COMPOUND_UNION: walk_entity((entity_t*)type->compound.compound, env); return; case TYPE_ENUM: walk_entity((entity_t*)type->enumt.enume, env); return; } panic("invalid type"); }
static void walk_expression(expression_t *const expr, const walk_env_t *const env) { env->expression_func(expr, env->env); switch (expr->base.kind) { case EXPR_STATEMENT: walk_statement(expr->statement.statement, env); return; case EXPR_BINARY_CASES: walk_expression(expr->binary.left, env); walk_expression(expr->binary.right, env); return; case EXPR_UNARY_CASES_OPTIONAL: if (expr->unary.value == NULL) return; /* FALLTHROUGH */ case EXPR_UNARY_CASES_MANDATORY: walk_expression(expr->unary.value, env); return; case EXPR_CALL: walk_expression(expr->call.function, env); for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) { walk_expression(arg->expression, env); } return; case EXPR_COMPOUND_LITERAL: walk_initializer(expr->compound_literal.initializer, env); return; case EXPR_CONDITIONAL: walk_expression(expr->conditional.condition, env); /* may be NULL because of gnu extension */ if (expr->conditional.true_expression != NULL) walk_expression(expr->conditional.true_expression, env); walk_expression(expr->conditional.false_expression, env); return; case EXPR_BUILTIN_CONSTANT_P: walk_expression(expr->builtin_constant.value, env); return; case EXPR_BUILTIN_TYPES_COMPATIBLE_P: walk_type(expr->builtin_types_compatible.left, env); walk_type(expr->builtin_types_compatible.right, env); return; case EXPR_SELECT: walk_expression(expr->select.compound, env); return; case EXPR_ARRAY_ACCESS: walk_expression(expr->array_access.array_ref, env); walk_expression(expr->array_access.index, env); return; case EXPR_CLASSIFY_TYPE: walk_expression(expr->classify_type.type_expression, env); return; case EXPR_SIZEOF: case EXPR_ALIGNOF: { expression_t *tp_expression = expr->typeprop.tp_expression; if (tp_expression != NULL) { walk_expression(tp_expression, env); } return; } case EXPR_VA_START: walk_expression(expr->va_starte.ap, env); return; case EXPR_VA_ARG: walk_expression(expr->va_arge.ap, env); return; case EXPR_VA_COPY: walk_expression(expr->va_copye.src, env); walk_expression(expr->va_copye.dst, env); return; case EXPR_OFFSETOF: walk_designator(expr->offsetofe.designator, env); return; case EXPR_LITERAL_CASES: case EXPR_LITERAL_CHARACTER: case EXPR_REFERENCE: case EXPR_ENUM_CONSTANT: case EXPR_STRING_LITERAL: case EXPR_FUNCNAME: case EXPR_LABEL_ADDRESS: case EXPR_ERROR: return; } panic("invalid expr kind"); }
void gather_interface_dies(root_die& root, set<iterator_base>& out, type_set& dedup_types_out, std::function<bool(const iterator_base&)> pred) { /* We want to deduplicate the types that we output, as we go. * CARE: what about anonymous types? We might want to generate names for them * based on their offset, in which case deduplication isn't transparent. * For this reason we output dedup_types_out separately from the DIEs. * However, everything in dedup_types_out is also in out (FIXME: is this a good idea?) */ auto toplevel_seq = root.grandchildren(); type_set& types = dedup_types_out; /* FIXME: it needn't be just grandchildren. */ for (auto i_d = std::move(toplevel_seq.first); i_d != toplevel_seq.second; ++i_d) { if (pred(i_d.base().base())) { // looks like a goer -- add it to the objs out.insert(i_d.base().base()); /* utility that will come in handy */ auto add_all_types = [&types, &root](iterator_df<type_die> outer_t) { walk_type(outer_t, iterator_base::END, [&types, &root](iterator_df<type_die> t, iterator_df<program_element_die> reason) -> bool { if (!t) return false; // void case auto memb = reason.as_a<member_die>(); if (memb && memb->get_declaration() && *memb->get_declaration() && memb->get_external() && *memb->get_external()) { // static member vars don't get added nor recursed on return false; } // apart from that, insert all nonvoids.... auto inserted = types.insert(t); if (!inserted.second) { // cerr << "Type was already present: " << *t // << " (or something equal to it: " << *inserted.first // << ")" << endl; // cerr << "Attributes: " << t->copy_attrs(root) << endl; return false; // was already present } else { cerr << "Inserted new type: " << *t << endl; // cerr << "Attributes: " << t->copy_attrs(root) << endl; return true; } } ); }; /* Also output everything that this depends on. We have to case-split * for now. */ if (i_d.base().base().is_a<subprogram_die>()) { // make sure we have all the relevant types in our set auto i_subp = i_d.base().base().as_a<subprogram_die>(); if (i_subp->find_type()) add_all_types(i_subp->find_type()); auto fps = i_subp->children().subseq_of<formal_parameter_die>(); for (auto i_fp = std::move(fps.first); i_fp != fps.second; ++i_fp) { auto outer_t = i_fp->find_type(); add_all_types(outer_t); } } else if (i_d.base().base().is_a<variable_die>()) { add_all_types(i_d.base().base().as_a<variable_die>()->get_type()); } else if (i_d.base().base().is_a<type_die>()) { /* Just walk it. */ add_all_types(i_d.base().base().as_a<type_die>()); } } // end if pred } // end for /* Now we've gathered everything. Make sure everything in "types" is in * "out". */ for (auto i_d = types.begin(); i_d != types.end(); ++i_d) { out.insert(*i_d); } /* Check that everything that's in "out", if it is a type, is also in * types. */ for (auto i_d = out.begin(); i_d != out.end(); ++i_d) { if (i_d->is_a<type_die>() && !i_d->is_a<subprogram_die>()) { if (types.find(i_d->as_a<type_die>()) == types.end()) { cerr << "BUG: didn't find " << i_d->summary() << " in types list." << endl; } } } }