Files
Pietro Fezzardi 80a33109eb Print opaque types in model header
Emit forward declarations and definitions of the opaque-array
artificial structs from the C model header (and from the helpers
header). Definitions are gated on a new DefineOpaqueTypes flag
threaded through PTMLHeaderBuilder::printModelHeader so that the
helpers header keeps emitting only the declarations.
2026-05-08 11:37:10 +02:00

160 lines
4.9 KiB
C++

//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
#include <unordered_map>
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/raw_ostream.h"
#include "revng/ABI/ModelHelpers.h"
#include "revng/HeadersGeneration/PTMLHeaderBuilder.h"
#include "revng/Model/Binary.h"
#include "revng/Model/Helpers.h"
#include "revng/Model/TypeDefinition.h"
#include "revng/Pipeline/Location.h"
#include "revng/Pipes/Ranks.h"
#include "revng/Support/Assert.h"
#include "revng/Support/Debug.h"
#include "revng/Support/YAMLTraits.h"
static Logger Log{ "model-to-header" };
bool ptml::HeaderBuilder::printModelHeader(bool DefineOpaqueTypes) {
auto Scope = B.getScopeTag(ptml::tags::Div);
std::string Includes = B.getPragmaOnce() + "\n"
+ B.getIncludeAngle("stdint.h")
+ B.getIncludeAngle("stdbool.h")
+ B.getIncludeQuote("primitive-types.h")
+ B.getIncludeQuote("attributes.h") + "\n";
B.append(std::move(Includes));
if (not Configuration.PostIncludeSnippet.empty())
B.append(Configuration.PostIncludeSnippet + '\n');
std::string Defines = B.getDirective(CBuilder::Directive::IfNotDef) + " "
+ B.getNullTag() + "\n"
+ B.getDirective(CBuilder::Directive::Define) + " "
+ B.getNullTag() + " (" + B.getZeroTag() + ")\n"
+ B.getDirective(CBuilder::Directive::EndIf) + "\n";
B.append(std::move(Defines));
if (not B.Binary.TypeDefinitions().empty()) {
auto Foldable = B.getScopeTag(CBuilder::Scopes::TypeDeclarations,
/* Newline = */ true);
B.appendLineComment("\\defgroup Type definitions");
B.appendLineComment("\\{");
B.append("\n");
B.printTypeDefinitions();
B.append("\n");
B.appendLineComment("\\}");
B.append("\n");
}
if (not B.Binary.Functions().empty()) {
auto Foldable = B.getScopeTag(CBuilder::Scopes::FunctionDeclarations,
/* Newline = */ true);
B.appendLineComment("\\defgroup Functions");
B.appendLineComment("\\{");
B.append("\n");
for (const model::Function &MF : B.Binary.Functions()) {
if (Configuration.FunctionsToOmit.contains(MF.Entry()))
continue;
const auto &FT = *B.Binary.prototypeOrDefault(MF.prototype());
if (B.Configuration.TypesToOmit.contains(FT.key()))
continue;
if (Log.isEnabled()) {
helpers::BlockComment CommentScope = B.getBlockCommentScope();
B.append("Emitting a model function `" + B.NameBuilder.name(MF) + "`:\n"
+ MF.toString() + "Its prototype is:\n" + FT.toString());
}
B.printFunctionPrototype(FT, MF, /* SingleLine = */ false);
B.append(";\n\n");
}
B.appendLineComment("\\}");
B.append("\n");
}
if (not B.Binary.ImportedDynamicFunctions().empty()) {
auto F = B.getScopeTag(CBuilder::Scopes::DynamicFunctionDeclarations,
/* Newline = */ true);
B.appendLineComment("\\defgroup Imported dynamic functions");
B.appendLineComment("\\{");
B.append("\n");
for (const auto &MF : B.Binary.ImportedDynamicFunctions()) {
const auto &FT = *B.Binary.prototypeOrDefault(MF.prototype());
if (B.Configuration.TypesToOmit.contains(FT.key()))
continue;
if (Log.isEnabled()) {
helpers::BlockComment CommentScope = B.getBlockCommentScope();
B.append("Emitting a dynamic function `" + B.NameBuilder.name(MF)
+ "`:\n" + MF.toString() + "Its prototype is:\n"
+ FT.toString());
}
B.printFunctionPrototype(FT, MF, /* SingleLine = */ false);
B.append(";\n\n");
}
B.appendLineComment("\\}");
B.append("\n");
}
if (not B.Binary.Segments().empty()) {
auto Foldable = B.getScopeTag(CBuilder::Scopes::SegmentDeclarations,
/* Newline = */ true);
B.appendLineComment("\\defgroup Segments");
B.appendLineComment("\\{");
for (const model::Segment &Segment : B.Binary.Segments()) {
if (Segment.Type().isEmpty())
continue;
auto &SegmentType = Segment.Type()->toStruct();
if (B.Configuration.TypesToOmit.contains(SegmentType.key()))
continue;
B.printSegmentType(Segment);
}
B.append("\n");
B.appendLineComment("\\}");
B.append("\n");
}
if (DefineOpaqueTypes) {
B.appendLineComment("\\defgroup Opaque Types");
B.appendLineComment("\\{");
auto Scope = B.getScopeTag(ptml::tags::Div);
B.printModelOpaqueTypeDefinitions();
B.appendLineComment("\\}");
B.append("\n");
}
return true;
}