1//===- VirtualMethodFamilyFormat.cpp --------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "SSAFAnalysesCommon.h"
10#include "clang/ScalableStaticAnalysis/Analyses/VirtualMethodFamily/VirtualMethodFamily.h"
11#include "clang/ScalableStaticAnalysis/Core/Serialization/JSONFormat.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/Support/Error.h"
14#include "llvm/Support/JSON.h"
15#include "llvm/Support/Registry.h"
16#include <memory>
17#include <utility>
18#include <vector>
19
20using namespace clang;
21using namespace ssaf;
22
23using llvm::Expected;
24using Object = llvm::json::Object;
25using Array = llvm::json::Array;
26
27namespace {
28constexpr llvm::StringLiteral KeyParamEntities = "param_entities";
29constexpr llvm::StringLiteral KeyReturnEntity = "return_entity";
30constexpr llvm::StringLiteral KeyOverriddenMethods = "overridden_methods";
31
32constexpr llvm::StringLiteral KeyRetAndParamFamilyIds = "families";
33constexpr llvm::StringLiteral KeyParamId = "pid";
34constexpr llvm::StringLiteral KeyFamilyId = "fid";
35} // namespace
36
37static Array entityIdVectorToJSON(const std::vector<EntityId> &Ids,
38 JSONFormat::EntityIdToJSONFn IdToJSON) {
39 Array Result;
40 Result.reserve(S: Ids.size());
41 for (EntityId Id : Ids)
42 Result.push_back(E: IdToJSON(Id));
43 return Result;
44}
45
46static Expected<std::vector<EntityId>>
47entityIdVectorFromJSON(const Array &Arr,
48 JSONFormat::EntityIdFromJSONFn IdFromJSON) {
49 std::vector<EntityId> Result;
50 Result.reserve(n: Arr.size());
51 for (const auto &V : Arr) {
52 const Object *Obj = V.getAsObject();
53 if (!Obj)
54 return makeSawButExpectedError(Saw: V, Expected: "an object representing EntityId");
55 auto Id = IdFromJSON(*Obj);
56 if (!Id)
57 return Id.takeError();
58 Result.push_back(x: *Id);
59 }
60 return Result;
61}
62
63//===----------------------------------------------------------------------===//
64// VirtualMethodSummary <-> JSON
65//===----------------------------------------------------------------------===//
66
67static Object
68serializeVirtualMethodSummary(const EntitySummary &ES,
69 JSONFormat::EntityIdToJSONFn IdToJSON) {
70 const auto &S = static_cast<const VirtualMethodSummary &>(ES);
71 Object Out;
72 Out[KeyParamEntities] = entityIdVectorToJSON(Ids: S.ParamEntities, IdToJSON);
73 if (S.ReturnEntity.has_value())
74 Out[KeyReturnEntity] = IdToJSON(*S.ReturnEntity);
75 Out[KeyOverriddenMethods] =
76 entityIdVectorToJSON(Ids: S.OverriddenMethods, IdToJSON);
77 return Out;
78}
79
80static Expected<std::unique_ptr<EntitySummary>>
81deserializeVirtualMethodSummary(const Object &Obj, EntityIdTable &,
82 JSONFormat::EntityIdFromJSONFn IdFromJSON) {
83 auto Result = std::make_unique<VirtualMethodSummary>();
84
85 const Array *ParamArr = Obj.getArray(K: KeyParamEntities);
86 if (!ParamArr)
87 return makeSawButExpectedError(Saw: Obj, Expected: "an object with an array field '%s'",
88 ExpectedArgs: KeyParamEntities.data());
89 auto Params = entityIdVectorFromJSON(Arr: *ParamArr, IdFromJSON);
90 if (!Params)
91 return Params.takeError();
92 Result->ParamEntities = std::move(*Params);
93
94 if (const Object *RE = Obj.getObject(K: KeyReturnEntity)) {
95 auto Id = IdFromJSON(*RE);
96 if (!Id)
97 return Id.takeError();
98 Result->ReturnEntity = *Id;
99 }
100
101 // Tolerant: absent key means no override edges (a root virtual method).
102 if (const Array *OMArr = Obj.getArray(K: KeyOverriddenMethods)) {
103 auto OM = entityIdVectorFromJSON(Arr: *OMArr, IdFromJSON);
104 if (!OM)
105 return OM.takeError();
106 Result->OverriddenMethods = std::move(*OM);
107 }
108
109 return std::move(Result);
110}
111
112//===----------------------------------------------------------------------===//
113// VirtualMethodFamilyAnalysisResult <-> JSON
114//===----------------------------------------------------------------------===//
115
116static Object serializeVirtualMethodFamilyAnalysisResult(
117 const VirtualMethodFamilyAnalysisResult &R,
118 JSONFormat::EntityIdToJSONFn IdToJSON) {
119 Array FamilyDataArr;
120 for (const auto &[ParamId, FamilyId] : R.RetAndParamData) {
121 Object Item;
122 Item[KeyParamId] = IdToJSON(ParamId);
123 Item[KeyFamilyId] = IdToJSON(FamilyId);
124 FamilyDataArr.push_back(E: std::move(Item));
125 }
126
127 Object Out;
128 Out[KeyRetAndParamFamilyIds] = std::move(FamilyDataArr);
129 return Out;
130}
131
132static Expected<std::unique_ptr<AnalysisResult>>
133deserializeVirtualMethodFamilyAnalysisResult(
134 const Object &Obj, JSONFormat::EntityIdFromJSONFn IdFromJSON) {
135 const Array *FamilyDataArr = Obj.getArray(K: KeyRetAndParamFamilyIds);
136 if (!FamilyDataArr)
137 return makeSawButExpectedError(Saw: Obj, Expected: "an object with an array field '%s'",
138 ExpectedArgs: KeyRetAndParamFamilyIds.data());
139
140 auto Result = std::make_unique<VirtualMethodFamilyAnalysisResult>();
141
142 for (const auto &V : *FamilyDataArr) {
143 const Object *Item = V.getAsObject();
144 if (!Item)
145 return makeSawButExpectedError(Saw: V, Expected: "an object {pid, fid}");
146 const Object *ParamObj = Item->getObject(K: KeyParamId);
147 const Object *FamilyObj = Item->getObject(K: KeyFamilyId);
148 if (!ParamObj || !FamilyObj)
149 return makeSawButExpectedError(Saw: *Item,
150 Expected: "an object with fields {'%s', '%s'}",
151 ExpectedArgs: KeyParamId.data(), ExpectedArgs: KeyFamilyId.data());
152 auto ParamId = IdFromJSON(*ParamObj);
153 if (!ParamId)
154 return ParamId.takeError();
155 auto FamilyId = IdFromJSON(*FamilyObj);
156 if (!FamilyId)
157 return FamilyId.takeError();
158 Result->RetAndParamData.insert(KV: {*ParamId, *FamilyId});
159 }
160 return std::move(Result);
161}
162
163namespace {
164
165struct VirtualMethodSummaryJSONFormatInfo final : JSONFormat::FormatInfo {
166 VirtualMethodSummaryJSONFormatInfo()
167 : JSONFormat::FormatInfo(VirtualMethodSummary::summaryName(),
168 serializeVirtualMethodSummary,
169 deserializeVirtualMethodSummary) {}
170};
171} // namespace
172
173static llvm::Registry<JSONFormat::FormatInfo>::Add<
174 VirtualMethodSummaryJSONFormatInfo>
175 RegisterJSONFormat(VirtualMethodSummary::Name,
176 "JSON Format info for VirtualMethodSummary");
177
178static JSONFormat::AnalysisResultRegistry::Add<
179 VirtualMethodFamilyAnalysisResult>
180 RegisterResultJSONFormat(serializeVirtualMethodFamilyAnalysisResult,
181 deserializeVirtualMethodFamilyAnalysisResult);
182
183namespace clang::ssaf {
184// NOLINTNEXTLINE(misc-use-internal-linkage)
185volatile int VirtualMethodFamilyJSONFormatAnchorSource = 0;
186} // namespace clang::ssaf
187