Files
RedBear-OS/local/recipes/dev/libclc/source/llvm/lib/TableGen/JSONBackend.cpp
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

185 lines
5.8 KiB
C++

//===- JSONBackend.cpp - Generate a JSON dump of all records. -*- C++ -*-=====//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This TableGen back end generates a machine-readable representation
// of all the classes and records defined by the input, in JSON format.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/JSON.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#define DEBUG_TYPE "json-emitter"
using namespace llvm;
namespace {
class JSONEmitter {
private:
const RecordKeeper &Records;
json::Value translateInit(const Init &I);
public:
explicit JSONEmitter(const RecordKeeper &R) : Records(R) {}
void run(raw_ostream &OS);
};
} // end anonymous namespace
json::Value JSONEmitter::translateInit(const Init &I) {
// Init subclasses that we return as JSON primitive values of one
// kind or another.
if (isa<UnsetInit>(&I))
return nullptr;
if (const auto *Bit = dyn_cast<BitInit>(&I))
return Bit->getValue() ? 1 : 0;
if (const auto *Bits = dyn_cast<BitsInit>(&I)) {
json::Array Array;
for (unsigned Idx = 0, E = Bits->getNumBits(); Idx < E; ++Idx)
Array.push_back(translateInit(*Bits->getBit(Idx)));
return std::move(Array);
}
if (const auto *Int = dyn_cast<IntInit>(&I))
return Int->getValue();
if (const auto *Str = dyn_cast<StringInit>(&I))
return Str->getValue();
if (const auto *List = dyn_cast<ListInit>(&I)) {
json::Array Array;
for (const auto *Val : *List)
Array.push_back(translateInit(*Val));
return std::move(Array);
}
// Init subclasses that we return as JSON objects containing a
// 'kind' discriminator. For these, we also provide the same
// translation back into TableGen input syntax that -print-records
// would give.
json::Object Obj;
Obj["printable"] = I.getAsString();
if (const auto *Def = dyn_cast<DefInit>(&I)) {
Obj["kind"] = "def";
Obj["def"] = Def->getDef()->getName();
return std::move(Obj);
}
if (const auto *Var = dyn_cast<VarInit>(&I)) {
Obj["kind"] = "var";
Obj["var"] = Var->getName();
return std::move(Obj);
}
if (const auto *VarBit = dyn_cast<VarBitInit>(&I)) {
if (const auto *Var = dyn_cast<VarInit>(VarBit->getBitVar())) {
Obj["kind"] = "varbit";
Obj["var"] = Var->getName();
Obj["index"] = VarBit->getBitNum();
return std::move(Obj);
}
}
if (const auto *Dag = dyn_cast<DagInit>(&I)) {
Obj["kind"] = "dag";
Obj["operator"] = translateInit(*Dag->getOperator());
if (auto name = Dag->getName())
Obj["name"] = name->getAsUnquotedString();
json::Array Args;
for (unsigned Idx = 0, E = Dag->getNumArgs(); Idx < E; ++Idx) {
json::Array Arg;
Arg.push_back(translateInit(*Dag->getArg(Idx)));
if (const auto ArgName = Dag->getArgName(Idx))
Arg.push_back(ArgName->getAsUnquotedString());
else
Arg.push_back(nullptr);
Args.push_back(std::move(Arg));
}
Obj["args"] = std::move(Args);
return std::move(Obj);
}
// Final fallback: anything that gets past here is simply given a
// kind field of 'complex', and the only other field is the standard
// 'printable' representation.
assert(!I.isConcrete());
Obj["kind"] = "complex";
return std::move(Obj);
}
void JSONEmitter::run(raw_ostream &OS) {
json::Object Root;
Root["!tablegen_json_version"] = 1;
// Prepare the arrays that will list the instances of every class.
// We mostly fill those in by iterating over the superclasses of
// each def, but we also want to ensure we store an empty list for a
// class with no instances at all, so we do a preliminary iteration
// over the classes, invoking std::map::operator[] to default-
// construct the array for each one.
std::map<std::string, json::Array> InstanceLists;
for (const auto &[ClassName, ClassRec] : Records.getClasses())
InstanceLists.emplace(ClassRec->getNameInitAsString(), json::Array());
// Main iteration over the defs.
for (const auto &[DefName, Def] : Records.getDefs()) {
const std::string Name = Def->getNameInitAsString();
json::Object Obj;
json::Array Fields;
for (const RecordVal &RV : Def->getValues()) {
if (!Def->isTemplateArg(RV.getNameInit())) {
auto Name = RV.getNameInitAsString();
if (RV.isNonconcreteOK())
Fields.push_back(Name);
Obj[Name] = translateInit(*RV.getValue());
}
}
Obj["!fields"] = std::move(Fields);
json::Array SuperClasses;
// Add this def to the instance list for each of its superclasses.
for (const Record *SuperClass : Def->getSuperClasses()) {
std::string SuperName = SuperClass->getNameInitAsString();
SuperClasses.push_back(SuperName);
InstanceLists[SuperName].push_back(Name);
}
Obj["!superclasses"] = std::move(SuperClasses);
Obj["!name"] = Name;
Obj["!anonymous"] = Def->isAnonymous();
json::Array Locs;
for (const SMLoc Loc : Def->getLoc())
Locs.push_back(SrcMgr.getFormattedLocationNoOffset(Loc));
Obj["!locs"] = std::move(Locs);
Root[Name] = std::move(Obj);
}
// Make a JSON object from the std::map of instance lists.
json::Object InstanceOf;
for (auto &[ClassName, Instances] : InstanceLists)
InstanceOf[ClassName] = std::move(Instances);
Root["!instanceof"] = std::move(InstanceOf);
// Done. Write the output.
OS << json::Value(std::move(Root)) << "\n";
}
void llvm::EmitJSON(const RecordKeeper &RK, raw_ostream &OS) {
JSONEmitter(RK).run(OS);
}