blob: ccad92be9b7451762666d07b8e7eb69124f758cb [file]
//===- PointerFlowFormat.cpp ----------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "clang/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlowFormat.h"
#include "SSAFAnalysesCommon.h"
#include "clang/ScalableStaticAnalysis/Analyses/EntityPointerLevel/EntityPointerLevelFormat.h"
#include "clang/ScalableStaticAnalysis/Analyses/PointerFlow/PointerFlow.h"
#include "clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
using namespace clang;
using namespace ssaf;
using Object = llvm::json::Object;
using Array = llvm::json::Array;
using Value = llvm::json::Value;
ssaf::PointerFlowEntitySummary
ssaf::buildPointerFlowEntitySummary(EdgeSet Edges);
llvm::iterator_range<EdgeSet::const_iterator>
ssaf::getEdges(const PointerFlowEntitySummary &Sum);
namespace {
constexpr const char *const PointerFlowKey = "PointerFlow";
} // namespace
// Writes an EdgeSet as an array of arrays of EntityPointerLevels:
// [
// [ [src-node], [dest-node], [dest-node], ...],
// [ [src-node], [dest-node], [dest-node], ...],
// ...
// ]
Array clang::ssaf::edgeSetToJSON(
llvm::iterator_range<EdgeSet::const_iterator> Edges,
JSONFormat::EntityIdToJSONFn EntityId2JSON) {
Array EdgesData;
for (const auto &[LHS, RHSSet] : Edges) {
Array EdgeEntry;
EdgeEntry.push_back(entityPointerLevelToJSON(LHS, EntityId2JSON));
for (const auto &RHS : RHSSet)
EdgeEntry.push_back(entityPointerLevelToJSON(RHS, EntityId2JSON));
EdgesData.push_back(Value(std::move(EdgeEntry)));
}
return EdgesData;
}
llvm::Expected<EdgeSet>
clang::ssaf::edgeSetFromJSON(const Array &EdgesData,
JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
EdgeSet Edges;
for (const auto &EdgesEntryData : EdgesData) {
const auto *EPLArray = EdgesEntryData.getAsArray();
if (!EPLArray || EPLArray->size() <= 1)
return makeSawButExpectedError(
EdgesEntryData, "a JSON array of EntityPointerLevels with a size "
"greater than 1: [src, dest, dest, ...]");
auto SrcEPL =
entityPointerLevelFromJSON(*EPLArray->begin(), EntityIdFromJSON);
if (!SrcEPL)
return SrcEPL.takeError();
for (const auto &EPLData :
llvm::make_range(EPLArray->begin() + 1, EPLArray->end())) {
auto EPL = entityPointerLevelFromJSON(EPLData, EntityIdFromJSON);
if (!EPL)
return EPL.takeError();
Edges[*SrcEPL].insert(*EPL);
}
}
return Edges;
}
static llvm::json::Object
summaryToJSON(const EntitySummary &ES,
JSONFormat::EntityIdToJSONFn EntityId2JSON) {
Object Data;
Data[PointerFlowKey] = Value(
edgeSetToJSON(getEdges(static_cast<const PointerFlowEntitySummary &>(ES)),
EntityId2JSON));
return Data;
}
static llvm::Expected<std::unique_ptr<EntitySummary>>
summaryFromJSON(const Object &Data, EntityIdTable &,
JSONFormat::EntityIdFromJSONFn EntityIdFromJSON) {
const Value *EdgesData = Data.get(PointerFlowKey);
if (!EdgesData)
return makeSawButExpectedError(
Object(Data), "a JSON object with the key: %s", PointerFlowKey);
const auto *EdgesDataAsArr = EdgesData->getAsArray();
if (!EdgesDataAsArr)
return makeSawButExpectedError(
*EdgesData, "a JSON array of array of EntityPointerLevels");
auto Edges = edgeSetFromJSON(*EdgesDataAsArr, EntityIdFromJSON);
if (!Edges)
return Edges.takeError();
return std::make_unique<PointerFlowEntitySummary>(
buildPointerFlowEntitySummary(std::move(*Edges)));
}
namespace {
struct PointerFlowJSONFormatInfo final : JSONFormat::FormatInfo {
PointerFlowJSONFormatInfo()
: JSONFormat::FormatInfo(PointerFlowEntitySummary::summaryName(),
summaryToJSON, summaryFromJSON) {}
};
} // namespace
static llvm::Registry<JSONFormat::FormatInfo>::Add<PointerFlowJSONFormatInfo>
RegisterPointerFlowJSONFormatInfo(
"PointerFlow", "JSON Format info for PointerFlowEntitySummary");
namespace clang::ssaf {
// NOLINTNEXTLINE(misc-use-internal-linkage)
volatile int PointerFlowJSONFormatAnchorSource = 0;
} // namespace clang::ssaf