1 /**
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "helpers/helpers.h"
17
18 #include "libabckit/include/c/abckit.h"
19 #include "libabckit/include/c/isa/isa_dynamic.h"
20 #include "libabckit/include/c/metadata_core.h"
21 #include "src/metadata_inspect_impl.h"
22 #include "libabckit/src/logger.h"
23 #include "libabckit/include/c/ir_core.h"
24 #include "libabckit/include/c/statuses.h"
25
26 #include <cassert>
27 #include <regex>
28 #include <vector>
29 #include <unordered_map>
30
31 #include <gtest/gtest.h>
32
33 namespace libabckit::test::helpers {
34
Match(const std::string & actual,const std::string & expected)35 bool Match(const std::string &actual, const std::string &expected)
36 {
37 std::smatch m;
38 auto res = std::regex_match(actual, m, std::regex(expected));
39 if (!res) {
40 LIBABCKIT_LOG_TEST(DEBUG) << "Doesn't match:\n";
41 LIBABCKIT_LOG_TEST(DEBUG) << "Actual:\n" << actual << '\n';
42 LIBABCKIT_LOG_TEST(DEBUG) << "Expected:\n" << expected << '\n';
43 }
44 return res;
45 }
46
47 struct UserTransformerData {
48 AbckitCoreFunction *method;
49 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer;
50 };
51
TransformMethodImpl(AbckitFile * file,AbckitCoreFunction * method,void * data)52 static void TransformMethodImpl(AbckitFile *file, AbckitCoreFunction *method, void *data)
53 {
54 auto userTransformerData = reinterpret_cast<UserTransformerData *>(data);
55
56 AbckitGraph *graph = g_implI->createGraphFromFunction(method);
57 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
58
59 userTransformerData->userTransformer(file, method, graph);
60
61 g_implM->functionSetGraph(method, graph);
62 g_impl->destroyGraph(graph);
63 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
64 }
65
TransformMethod(AbckitFile * file,const std::string & methodSignature,const std::function<void (AbckitFile *,AbckitCoreFunction *,AbckitGraph *)> & userTransformer)66 void TransformMethod(AbckitFile *file, const std::string &methodSignature,
67 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer)
68 {
69 auto *method = FindMethodByName(file, methodSignature);
70 ASSERT_NE(method, nullptr);
71
72 UserTransformerData utd({method, userTransformer});
73
74 TransformMethodImpl(g_implI->functionGetFile(method), method, &utd);
75 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
76 }
77
TransformMethod(const std::string & inputPath,const std::string & outputPath,const std::string & methodSignature,const std::function<void (AbckitFile *,AbckitCoreFunction *,AbckitGraph *)> & userTransformer,const std::function<void (AbckitGraph *)> & validateResult)78 void TransformMethod(const std::string &inputPath, const std::string &outputPath, const std::string &methodSignature,
79 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer,
80 const std::function<void(AbckitGraph *)> &validateResult)
81 {
82 LIBABCKIT_LOG_TEST(DEBUG) << "TransformMethod: " << inputPath << '\n';
83
84 // Open file
85 AbckitFile *file = g_impl->openAbc(inputPath.c_str(), inputPath.size());
86 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
87
88 // Transform method
89 auto *method = FindMethodByName(file, methodSignature);
90 ASSERT_NE(method, nullptr);
91 UserTransformerData utd({method, userTransformer});
92 TransformMethodImpl(g_implI->functionGetFile(method), method, &utd);
93 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
94
95 // Validate method
96 AbckitGraph *graph = g_implI->createGraphFromFunction(method);
97 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
98 validateResult(graph);
99 g_impl->destroyGraph(graph);
100
101 // Write output
102 g_impl->writeAbc(file, outputPath.c_str(), outputPath.size());
103 g_impl->closeFile(file);
104 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
105 }
106
TransformMethod(const std::string & inputPath,const std::string & outputPath,const std::string & methodSignature,const std::function<void (AbckitFile *,AbckitCoreFunction *,AbckitGraph *)> & userTransformer)107 void TransformMethod(const std::string &inputPath, const std::string &outputPath, const std::string &methodSignature,
108 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userTransformer)
109 {
110 LIBABCKIT_LOG_TEST(DEBUG) << "TransformMethod: " << inputPath << '\n';
111
112 // Open file
113 AbckitFile *file = g_impl->openAbc(inputPath.c_str(), inputPath.size());
114 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
115
116 // Transform method
117 auto *method = FindMethodByName(file, methodSignature);
118 ASSERT_NE(method, nullptr);
119 UserTransformerData utd({method, userTransformer});
120 TransformMethodImpl(g_implI->functionGetFile(method), method, &utd);
121 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
122
123 // Write output
124 g_impl->writeAbc(file, outputPath.c_str(), outputPath.size());
125 g_impl->closeFile(file);
126 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
127 }
128
129 struct UserInspectorData {
130 AbckitCoreFunction *method;
131 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userInspector;
132 };
133
InspectMethodImpl(AbckitFile * file,AbckitCoreFunction * method,void * data)134 static void InspectMethodImpl(AbckitFile *file, AbckitCoreFunction *method, void *data)
135 {
136 auto userInspectorData = reinterpret_cast<UserInspectorData *>(data);
137
138 AbckitGraph *graph = g_implI->createGraphFromFunction(method);
139 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
140
141 userInspectorData->userInspector(file, method, graph);
142
143 g_impl->destroyGraph(graph);
144 }
145
InspectMethod(AbckitFile * file,const std::string & methodSignature,const std::function<void (AbckitFile *,AbckitCoreFunction *,AbckitGraph *)> & userInspector)146 void InspectMethod(AbckitFile *file, const std::string &methodSignature,
147 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userInspector)
148 {
149 auto *method = FindMethodByName(file, methodSignature);
150 ASSERT_NE(method, nullptr);
151
152 UserInspectorData uid({method, userInspector});
153
154 InspectMethodImpl(g_implI->functionGetFile(method), method, &uid);
155 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
156 }
157
InspectMethod(const std::string & inputPath,const std::string & methodSignature,const std::function<void (AbckitFile *,AbckitCoreFunction *,AbckitGraph *)> & userInspector)158 void InspectMethod(const std::string &inputPath, const std::string &methodSignature,
159 const std::function<void(AbckitFile *, AbckitCoreFunction *, AbckitGraph *)> &userInspector)
160 {
161 LIBABCKIT_LOG_TEST(DEBUG) << "InspectMethod: " << inputPath << '\n';
162
163 // Open file
164 AbckitFile *file = g_impl->openAbc(inputPath.c_str(), inputPath.size());
165 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
166
167 // Inspect method
168 auto *method = FindMethodByName(file, methodSignature);
169 ASSERT_NE(method, nullptr);
170 UserInspectorData uid({method, userInspector});
171 InspectMethodImpl(file, method, &uid);
172 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
173
174 g_impl->closeFile(file);
175 }
176
BBgetPredBlocks(AbckitBasicBlock * bb)177 std::vector<AbckitBasicBlock *> BBgetPredBlocks(AbckitBasicBlock *bb)
178 {
179 std::vector<AbckitBasicBlock *> predBBs;
180 g_implG->bbVisitPredBlocks(bb, &predBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
181 auto *preds = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
182 preds->emplace_back(succBasicBlock);
183 return true;
184 });
185 return predBBs;
186 }
187
BBgetSuccBlocks(AbckitBasicBlock * bb)188 std::vector<AbckitBasicBlock *> BBgetSuccBlocks(AbckitBasicBlock *bb)
189 {
190 std::vector<AbckitBasicBlock *> succBBs;
191 g_implG->bbVisitSuccBlocks(bb, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
192 auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
193 succs->emplace_back(succBasicBlock);
194 return true;
195 });
196 return succBBs;
197 }
198
BBgetAllInsts(AbckitBasicBlock * bb)199 std::vector<AbckitInst *> BBgetAllInsts(AbckitBasicBlock *bb)
200 {
201 std::vector<AbckitInst *> insts;
202 for (auto *inst = g_implG->bbGetFirstInst(bb); inst != nullptr; inst = g_implG->iGetNext(inst)) {
203 insts.emplace_back(inst);
204 }
205
206 return insts;
207 }
208
FindFirstInst(AbckitGraph * graph,AbckitIsaApiStaticOpcode opcode,const std::function<bool (AbckitInst *)> & findIf)209 AbckitInst *FindFirstInst(AbckitGraph *graph, AbckitIsaApiStaticOpcode opcode,
210 const std::function<bool(AbckitInst *)> &findIf)
211 {
212 std::vector<AbckitBasicBlock *> bbs;
213 g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
214 reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
215 return true;
216 });
217 for (auto *bb : bbs) {
218 auto *curInst = g_implG->bbGetFirstInst(bb);
219 while (curInst != nullptr) {
220 if (g_gStat->iGetOpcode(curInst) == opcode && findIf(curInst)) {
221 return curInst;
222 }
223 curInst = g_implG->iGetNext(curInst);
224 }
225 }
226 return nullptr;
227 }
228
FindFirstInst(AbckitGraph * graph,AbckitIsaApiDynamicOpcode opcode,const std::function<bool (AbckitInst *)> & findIf)229 AbckitInst *FindFirstInst(AbckitGraph *graph, AbckitIsaApiDynamicOpcode opcode,
230 const std::function<bool(AbckitInst *)> &findIf)
231 {
232 std::vector<AbckitBasicBlock *> bbs;
233 g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
234 reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
235 return true;
236 });
237 for (auto *bb : bbs) {
238 auto *curInst = g_implG->bbGetFirstInst(bb);
239 while (curInst != nullptr) {
240 if (g_gDyn->iGetOpcode(curInst) == opcode && findIf(curInst)) {
241 return curInst;
242 }
243 curInst = g_implG->iGetNext(curInst);
244 }
245 }
246 return nullptr;
247 }
248
FindLastInst(AbckitGraph * graph,AbckitIsaApiDynamicOpcode opcode,const std::function<bool (AbckitInst *)> & findIf)249 AbckitInst *FindLastInst(AbckitGraph *graph, AbckitIsaApiDynamicOpcode opcode,
250 const std::function<bool(AbckitInst *)> &findIf)
251 {
252 std::vector<AbckitBasicBlock *> bbs;
253 g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
254 reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
255 return true;
256 });
257 AbckitInst *res {nullptr};
258 for (auto *bb : bbs) {
259 auto *curInst = g_implG->bbGetFirstInst(bb);
260 while (curInst != nullptr) {
261 if (g_gDyn->iGetOpcode(curInst) == opcode && findIf(curInst)) {
262 res = curInst;
263 }
264 curInst = g_implG->iGetNext(curInst);
265 }
266 }
267 return res;
268 }
269
FindLastInst(AbckitGraph * graph,AbckitIsaApiStaticOpcode opcode,const std::function<bool (AbckitInst *)> & findIf)270 AbckitInst *FindLastInst(AbckitGraph *graph, AbckitIsaApiStaticOpcode opcode,
271 const std::function<bool(AbckitInst *)> &findIf)
272 {
273 std::vector<AbckitBasicBlock *> bbs;
274 g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
275 reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
276 return true;
277 });
278 AbckitInst *res {nullptr};
279 for (auto *bb : bbs) {
280 auto *curInst = g_implG->bbGetFirstInst(bb);
281 while (curInst != nullptr) {
282 if (g_gStat->iGetOpcode(curInst) == opcode && findIf(curInst)) {
283 res = curInst;
284 }
285 curInst = g_implG->iGetNext(curInst);
286 }
287 }
288 return res;
289 }
290
ReplaceInst(AbckitInst * what,AbckitInst * with)291 void ReplaceInst(AbckitInst *what, AbckitInst *with)
292 {
293 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
294
295 std::vector<AbckitInst *> users;
296
297 struct ReplaceContext {
298 AbckitInst *inst = nullptr;
299 AbckitInst *oldInput = nullptr;
300 AbckitInst *newInput = nullptr;
301 std::vector<AbckitInst *> *users = nullptr;
302 };
303 ReplaceContext ctx = {what, what, with, &users};
304
305 g_implG->iVisitUsers(what, &ctx, [](AbckitInst *user, void *data) {
306 auto *users = static_cast<ReplaceContext *>(data)->users;
307 users->push_back(user);
308 return true;
309 });
310 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
311
312 for (auto *user : users) {
313 ctx.inst = user;
314 g_implG->iVisitInputs(user, &ctx, [](AbckitInst *input, size_t inputIdx, void *data) {
315 auto *ctx = reinterpret_cast<ReplaceContext *>(data);
316
317 if (input == ctx->oldInput) {
318 g_implG->iSetInput(ctx->inst, ctx->newInput, inputIdx);
319 }
320 return true;
321 });
322 }
323 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
324
325 g_implG->iInsertBefore(with, what);
326 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
327
328 g_implG->iRemove(what);
329 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
330 }
331
EnumerateAllMethodsInModule(AbckitFile * file,std::function<void (AbckitCoreNamespace *)> & cbNamespace,std::function<void (AbckitCoreClass *)> & cbClass,std::function<void (AbckitCoreFunction *)> & cbFunc)332 static bool EnumerateAllMethodsInModule(AbckitFile *file, std::function<void(AbckitCoreNamespace *)> &cbNamespace,
333 std::function<void(AbckitCoreClass *)> &cbClass,
334 std::function<void(AbckitCoreFunction *)> &cbFunc)
335 {
336 std::function<void(AbckitCoreModule *)> cbModule = [&](AbckitCoreModule *m) {
337 g_implI->moduleEnumerateNamespaces(m, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
338 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
339 return true;
340 });
341 g_implI->moduleEnumerateClasses(m, &cbClass, [](AbckitCoreClass *c, void *cb) {
342 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
343 return true;
344 });
345 g_implI->moduleEnumerateTopLevelFunctions(m, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
346 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
347 return true;
348 });
349 };
350
351 return g_implI->fileEnumerateModules(file, &cbModule, [](AbckitCoreModule *m, void *cb) {
352 (*reinterpret_cast<std::function<void(AbckitCoreModule *)> *>(cb))(m);
353 return true;
354 });
355 }
356
EnumerateAllMethods(AbckitFile * file,const std::function<void (AbckitCoreFunction *)> & cbUserFunc)357 void EnumerateAllMethods(AbckitFile *file, const std::function<void(AbckitCoreFunction *)> &cbUserFunc)
358 {
359 std::function<void(AbckitCoreFunction *)> cbFunc;
360 std::function<void(AbckitCoreClass *)> cbClass;
361
362 cbFunc = [&](AbckitCoreFunction *f) {
363 cbUserFunc(f);
364 g_implI->functionEnumerateNestedFunctions(f, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
365 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(f);
366 return true;
367 });
368 g_implI->functionEnumerateNestedClasses(f, &cbClass, [](AbckitCoreClass *f, void *cb) {
369 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(f);
370 return true;
371 });
372 };
373
374 cbClass = [&](AbckitCoreClass *c) {
375 g_implI->classEnumerateMethods(c, &cbFunc, [](AbckitCoreFunction *m, void *cb) {
376 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(m);
377
378 return true;
379 });
380 };
381
382 std::function<void(AbckitCoreNamespace *)> cbNamespace = [&](AbckitCoreNamespace *n) {
383 g_implI->namespaceEnumerateNamespaces(n, &cbNamespace, [](AbckitCoreNamespace *n, void *cb) {
384 (*reinterpret_cast<std::function<void(AbckitCoreNamespace *)> *>(cb))(n);
385 return true;
386 });
387 g_implI->namespaceEnumerateClasses(n, &cbClass, [](AbckitCoreClass *c, void *cb) {
388 (*reinterpret_cast<std::function<void(AbckitCoreClass *)> *>(cb))(c);
389 return true;
390 });
391 g_implI->namespaceEnumerateTopLevelFunctions(n, &cbFunc, [](AbckitCoreFunction *f, void *cb) {
392 (*reinterpret_cast<std::function<void(AbckitCoreFunction *)> *>(cb))(f);
393
394 return true;
395 });
396 };
397
398 EnumerateAllMethodsInModule(file, cbNamespace, cbClass, cbFunc);
399 }
400
AssertModuleVisitor(AbckitCoreModule * module,void * data)401 void AssertModuleVisitor([[maybe_unused]] AbckitCoreModule *module, [[maybe_unused]] void *data)
402 {
403 EXPECT_TRUE(module != nullptr);
404 EXPECT_TRUE(module->file != nullptr);
405 EXPECT_TRUE(data != nullptr);
406 }
407
AssertImportVisitor(AbckitCoreImportDescriptor * id,void * data)408 void AssertImportVisitor([[maybe_unused]] AbckitCoreImportDescriptor *id, [[maybe_unused]] void *data)
409 {
410 EXPECT_TRUE(id != nullptr);
411 EXPECT_TRUE(id->importingModule != nullptr);
412 EXPECT_TRUE(id->importedModule != nullptr);
413 EXPECT_TRUE(data != nullptr);
414 }
415
AssertExportVisitor(AbckitCoreExportDescriptor * ed,void * data)416 void AssertExportVisitor([[maybe_unused]] AbckitCoreExportDescriptor *ed, [[maybe_unused]] void *data)
417 {
418 EXPECT_TRUE(ed != nullptr);
419 EXPECT_TRUE(ed->exportingModule != nullptr);
420 EXPECT_TRUE(ed->exportedModule != nullptr);
421 EXPECT_TRUE(data != nullptr);
422 }
423
AssertClassVisitor(AbckitCoreClass * klass,void * data)424 void AssertClassVisitor([[maybe_unused]] AbckitCoreClass *klass, [[maybe_unused]] void *data)
425 {
426 EXPECT_TRUE(klass != nullptr);
427 [[maybe_unused]] AbckitFile *file = g_implI->classGetFile(klass);
428 EXPECT_TRUE(file != nullptr);
429 EXPECT_TRUE(data != nullptr);
430 }
431
AssertNamespaceVisitor(AbckitCoreNamespace * n,void * data)432 void AssertNamespaceVisitor([[maybe_unused]] AbckitCoreNamespace *n, [[maybe_unused]] void *data)
433 {
434 EXPECT_TRUE(n != nullptr);
435 EXPECT_TRUE(data != nullptr);
436 }
437
AssertMethodVisitor(AbckitCoreFunction * method,void * data)438 void AssertMethodVisitor([[maybe_unused]] AbckitCoreFunction *method, [[maybe_unused]] void *data)
439 {
440 EXPECT_TRUE(method != nullptr);
441 [[maybe_unused]] AbckitFile *file = g_implI->functionGetFile(method);
442 EXPECT_TRUE(file != nullptr);
443 EXPECT_TRUE(data != nullptr);
444 }
445
AssertAnnotationInterfaceVisitor(AbckitCoreAnnotationInterface * ai,void * data)446 void AssertAnnotationInterfaceVisitor(AbckitCoreAnnotationInterface *ai, void *data)
447 {
448 ASSERT_TRUE(ai != nullptr);
449 ASSERT_TRUE(data != nullptr);
450 }
451
AssertAnnotationVisitor(AbckitCoreAnnotation * anno,void * data)452 void AssertAnnotationVisitor(AbckitCoreAnnotation *anno, void *data)
453 {
454 ASSERT_NE(anno, nullptr);
455 auto ai = g_implI->annotationGetInterface(anno);
456 ASSERT_NE(ai, nullptr);
457 ASSERT_NE(data, nullptr);
458 }
459
AssertOpenAbc(const char * fname,AbckitFile ** file)460 void AssertOpenAbc(const char *fname, AbckitFile **file)
461 {
462 ASSERT_NE(g_impl, nullptr);
463 ASSERT_NE(g_implI, nullptr);
464 *file = g_impl->openAbc(fname, strlen(fname));
465 ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
466 ASSERT_NE(*file, nullptr);
467 }
468
ClassByNameFinder(AbckitCoreClass * klass,void * data)469 bool ClassByNameFinder(AbckitCoreClass *klass, void *data)
470 {
471 AssertClassVisitor(klass, data);
472
473 auto ctxFinder = reinterpret_cast<ClassByNameContext *>(data);
474 auto name = helpers::AbckitStringToString(g_implI->classGetName(klass));
475 if (name == ctxFinder->name) {
476 ctxFinder->klass = klass;
477 return false;
478 }
479
480 return true;
481 }
482
NamespaceByNameFinder(AbckitCoreNamespace * n,void * data)483 bool NamespaceByNameFinder(AbckitCoreNamespace *n, void *data)
484 {
485 AssertNamespaceVisitor(n, data);
486
487 auto ctxFinder = reinterpret_cast<NamepsaceByNameContext *>(data);
488 auto name = helpers::AbckitStringToString(g_implI->namespaceGetName(n));
489 if (name == ctxFinder->name) {
490 ctxFinder->n = n;
491 return false;
492 }
493 return true;
494 }
495
ModuleByNameFinder(AbckitCoreModule * module,void * data)496 bool ModuleByNameFinder(AbckitCoreModule *module, void *data)
497 {
498 AssertModuleVisitor(module, data);
499
500 auto ctxFinder = reinterpret_cast<ModuleByNameContext *>(data);
501 auto name = helpers::AbckitStringToString(g_implI->moduleGetName(module));
502 if (name == ctxFinder->name) {
503 ctxFinder->module = module;
504 return false;
505 }
506
507 return true;
508 }
509
ImportByAliasFinder(AbckitCoreImportDescriptor * id,void * data)510 bool ImportByAliasFinder(AbckitCoreImportDescriptor *id, void *data)
511 {
512 AssertImportVisitor(id, data);
513
514 auto ctxFinder = reinterpret_cast<ImportByAliasContext *>(data);
515 auto name = helpers::AbckitStringToString(g_implI->importDescriptorGetAlias(id));
516 if (name == ctxFinder->name) {
517 ctxFinder->id = id;
518 return false;
519 }
520
521 return true;
522 }
523
ExportByAliasFinder(AbckitCoreExportDescriptor * ed,void * data)524 bool ExportByAliasFinder(AbckitCoreExportDescriptor *ed, void *data)
525 {
526 AssertExportVisitor(ed, data);
527
528 auto ctxFinder = reinterpret_cast<ExportByAliasContext *>(data);
529 auto name = helpers::AbckitStringToString(g_implI->exportDescriptorGetAlias(ed));
530 if (name == ctxFinder->name) {
531 ctxFinder->ed = ed;
532 return false;
533 }
534
535 return true;
536 }
537
AnnotationInterfaceByNameFinder(AbckitCoreAnnotationInterface * ai,void * data)538 bool AnnotationInterfaceByNameFinder(AbckitCoreAnnotationInterface *ai, void *data)
539 {
540 AssertAnnotationInterfaceVisitor(ai, data);
541
542 auto ctxFinder = reinterpret_cast<AnnotationInterfaceByNameContext *>(data);
543 auto str = g_implI->annotationInterfaceGetName(ai);
544 auto name = helpers::AbckitStringToString(str);
545 if (name == ctxFinder->name) {
546 ctxFinder->ai = ai;
547 return false;
548 }
549
550 return true;
551 }
552
AnnotationByNameFinder(AbckitCoreAnnotation * anno,void * data)553 bool AnnotationByNameFinder(AbckitCoreAnnotation *anno, void *data)
554 {
555 AssertAnnotationVisitor(anno, data);
556
557 auto ctxFinder = reinterpret_cast<AnnotationByNameContext *>(data);
558 auto ai = g_implI->annotationGetInterface(anno);
559 auto str = g_implI->annotationInterfaceGetName(ai);
560 auto name = helpers::AbckitStringToString(str);
561 if (name == ctxFinder->name) {
562 ctxFinder->anno = anno;
563 return false;
564 }
565
566 return true;
567 }
568
GetCropFuncName(const std::string & fullSig)569 std::string GetCropFuncName(const std::string &fullSig)
570 {
571 auto fullName = fullSig.substr(0, fullSig.find(':'));
572 auto pos = fullName.rfind('.');
573 return fullName.substr(pos + 1);
574 }
575
576 struct NamespaceAndName final {
577 AbckitCoreNamespace *foundNamespace;
578 const std::string &namespaceName;
579 };
580
581 struct MethodAndName final {
582 std::vector<AbckitCoreFunction *> foundMethods;
583 const std::string &methodName;
584 bool fullSign = true;
585 };
586
SplitFunctionName(const std::string & fullName)587 static std::pair<std::string, std::string> SplitFunctionName(const std::string &fullName)
588 {
589 size_t colonPos = fullName.find(':');
590 std::string croppedName = fullName.substr(0, colonPos);
591 size_t dotPos = croppedName.find('.');
592 if (dotPos == std::string::npos) {
593 return {"", fullName};
594 }
595 return {fullName.substr(0, dotPos), fullName.substr(dotPos + 1)};
596 }
597
FindFunctionInTopLevel(AbckitCoreFunction * func,MethodAndName * mn)598 static void FindFunctionInTopLevel(AbckitCoreFunction *func, MethodAndName *mn)
599 {
600 auto currmname = g_implI->functionGetName(func);
601 auto currMethodNameStr = helpers::AbckitStringToString(currmname);
602 auto currMethodName = mn->fullSign ? currMethodNameStr.data() : GetCropFuncName(currMethodNameStr.data());
603 auto [methodModule, methodName] = SplitFunctionName(mn->methodName);
604 if (currMethodName == methodName) {
605 mn->foundMethods.emplace_back(func);
606 }
607 }
608
FindMethodInClass(AbckitCoreClass * klass,MethodAndName * mn)609 static void FindMethodInClass(AbckitCoreClass *klass, MethodAndName *mn)
610 {
611 g_implI->classEnumerateMethods(klass, mn, [](AbckitCoreFunction *method, void *data) {
612 auto mn = static_cast<MethodAndName *>(data);
613 auto currmname = g_implI->functionGetName(method);
614 auto currMethodNameStr = helpers::AbckitStringToString(currmname);
615 auto currMethodName = mn->fullSign ? currMethodNameStr.data() : GetCropFuncName(currMethodNameStr.data());
616 auto [methodModule, methodName] = SplitFunctionName(mn->methodName);
617 if (currMethodName == methodName) {
618 mn->foundMethods.emplace_back(method);
619 }
620 return true;
621 });
622 }
623
FindMethodInNamespace(AbckitCoreNamespace * n,MethodAndName * mn)624 static void FindMethodInNamespace(AbckitCoreNamespace *n, MethodAndName *mn)
625 {
626 g_implI->namespaceEnumerateClasses(n, mn, [](AbckitCoreClass *klass, void *data) {
627 FindMethodInClass(klass, static_cast<MethodAndName *>(data));
628 return true;
629 });
630 g_implI->namespaceEnumerateTopLevelFunctions(n, mn, [](AbckitCoreFunction *func, void *data) {
631 FindFunctionInTopLevel(func, static_cast<MethodAndName *>(data));
632 return true;
633 });
634 g_implI->namespaceEnumerateNamespaces(n, mn, [](AbckitCoreNamespace *n, void *data) {
635 FindMethodInNamespace(n, static_cast<MethodAndName *>(data));
636 return true;
637 });
638 }
639
FindMethodByNameImpl(AbckitFile * file,void * data)640 bool FindMethodByNameImpl(AbckitFile *file, void *data)
641 {
642 bool earlyExit = g_implI->fileEnumerateModules(file, data, [](AbckitCoreModule *m, void *data) {
643 auto moduleName = helpers::AbckitStringToString(g_implI->moduleGetName(m));
644 auto mn = static_cast<MethodAndName *>(data);
645 auto [funcModule, funcName] = SplitFunctionName(mn->methodName);
646 if (!funcModule.empty()) {
647 if (funcModule != moduleName) {
648 return true;
649 }
650 }
651 g_implI->moduleEnumerateClasses(m, data, [](AbckitCoreClass *klass, void *data) {
652 FindMethodInClass(klass, static_cast<MethodAndName *>(data));
653 return true;
654 });
655
656 g_implI->moduleEnumerateTopLevelFunctions(m, data, [](AbckitCoreFunction *method, void *data) {
657 FindFunctionInTopLevel(method, static_cast<MethodAndName *>(data));
658 return true;
659 });
660
661 g_implI->moduleEnumerateNamespaces(m, data, [](AbckitCoreNamespace *n, void *data) {
662 FindMethodInNamespace(n, static_cast<MethodAndName *>(data));
663 return true;
664 });
665 return true;
666 });
667 auto mn = static_cast<MethodAndName *>(data);
668 LIBABCKIT_LOG_TEST(DEBUG) << "Method found by name: " << mn->methodName << '\n';
669 return earlyExit;
670 }
671
FindNamespaceInNamespaces(AbckitCoreNamespace * n,NamespaceAndName * nn)672 static void FindNamespaceInNamespaces(AbckitCoreNamespace *n, NamespaceAndName *nn)
673 {
674 g_implI->namespaceEnumerateNamespaces(n, nn, [](AbckitCoreNamespace *n, void *data) {
675 auto nn = static_cast<NamespaceAndName *>(data);
676 auto currNamespaceName = g_implI->namespaceGetName(n);
677 auto currNamespaceNameStr = helpers::AbckitStringToString(currNamespaceName);
678 if (currNamespaceNameStr == nn->namespaceName) {
679 nn->foundNamespace = n;
680 }
681 FindNamespaceInNamespaces(n, nn);
682 return true;
683 });
684 }
685
FindNamespaceByNameImpl(AbckitFile * file,void * data)686 bool FindNamespaceByNameImpl(AbckitFile *file, void *data)
687 {
688 return g_implI->fileEnumerateModules(file, data, [](AbckitCoreModule *m, void *data) {
689 g_implI->moduleEnumerateNamespaces(m, data, [](AbckitCoreNamespace *n, void *data) {
690 auto nn = static_cast<NamespaceAndName *>(data);
691 FindNamespaceInNamespaces(n, nn);
692 return true;
693 });
694
695 g_implI->moduleEnumerateNamespaces(m, data, [](AbckitCoreNamespace *n, void *data) {
696 auto nn = static_cast<NamespaceAndName *>(data);
697 auto currNamespaceName = g_implI->namespaceGetName(n);
698 auto currNamespaceNameStr = helpers::AbckitStringToString(currNamespaceName);
699 if (currNamespaceNameStr == nn->namespaceName) {
700 nn->foundNamespace = n;
701 }
702 return true;
703 });
704 return true;
705 });
706 }
707
FindNamespaceByName(AbckitFile * file,const std::string & name)708 AbckitCoreNamespace *FindNamespaceByName(AbckitFile *file, const std::string &name)
709 {
710 NamespaceAndName nn {nullptr, name};
711 FindNamespaceByNameImpl(file, &nn);
712 if (nn.foundNamespace != nullptr) {
713 LIBABCKIT_LOG_TEST(DEBUG) << "Namespace found by name: " << nn.namespaceName << '\n';
714 }
715 return nn.foundNamespace;
716 }
717
718 /*
719 Returns pointer to AbckitCoreFunction if found,
720 nullptr otherwise
721 */
FindMethodByName(AbckitFile * file,const std::string & name)722 AbckitCoreFunction *FindMethodByName(AbckitFile *file, const std::string &name)
723 {
724 MethodAndName mn {{}, name};
725 LIBABCKIT_LOG_TEST(DEBUG) << "Method searching: " << name << '\n';
726 FindMethodByNameImpl(file, &mn);
727 if (!mn.foundMethods.empty()) {
728 EXPECT_EQ(mn.foundMethods.size(), 1);
729 return mn.foundMethods[0];
730 }
731
732 mn.fullSign = false;
733 FindMethodByNameImpl(file, &mn);
734 EXPECT_EQ(mn.foundMethods.size(), 1);
735 return mn.foundMethods[0];
736 }
737
MethodByNameFinder(AbckitCoreFunction * method,void * data)738 bool MethodByNameFinder(AbckitCoreFunction *method, void *data)
739 {
740 AssertMethodVisitor(method, data);
741
742 auto ctxFinder = reinterpret_cast<MethodByNameContext *>(data);
743 auto fullName = helpers::AbckitStringToString(g_implI->functionGetName(method));
744 auto name = ctxFinder->fullSign ? fullName.data() : GetCropFuncName(fullName.data());
745 if (name == ctxFinder->name) {
746 ctxFinder->method = method;
747 return false;
748 }
749
750 return true;
751 }
752
NameToModuleCollector(AbckitCoreModule * module,void * data)753 bool NameToModuleCollector(AbckitCoreModule *module, void *data)
754 {
755 AssertModuleVisitor(module, data);
756
757 auto modules = reinterpret_cast<std::unordered_map<std::string, AbckitCoreModule *> *>(data);
758 auto moduleName = g_implI->moduleGetName(module);
759 EXPECT_TRUE(g_impl->getLastError() == ABCKIT_STATUS_NO_ERROR);
760
761 auto name = helpers::AbckitStringToString(moduleName);
762 LIBABCKIT_LOG_TEST(DEBUG) << "module name: " << name << std::endl;
763 EXPECT_TRUE(modules->find(name.data()) == modules->end());
764 modules->emplace(name, module);
765
766 return true;
767 }
768
ModuleImportsCollector(AbckitCoreImportDescriptor * id,void * data)769 bool ModuleImportsCollector(AbckitCoreImportDescriptor *id, void *data)
770 {
771 helpers::AssertImportVisitor(id, data);
772
773 auto imports = reinterpret_cast<std::set<AbckitCoreImportDescriptor *> *>(data);
774 imports->insert(id);
775
776 return true;
777 }
778
ModuleExportsCollector(AbckitCoreExportDescriptor * ed,void * data)779 bool ModuleExportsCollector(AbckitCoreExportDescriptor *ed, void *data)
780 {
781 helpers::AssertExportVisitor(ed, data);
782
783 auto exports = reinterpret_cast<std::set<AbckitCoreExportDescriptor *> *>(data);
784 exports->insert(ed);
785
786 return true;
787 }
788
AbckitStringToString(AbckitString * str)789 std::string_view AbckitStringToString(AbckitString *str)
790 {
791 EXPECT_TRUE(str != nullptr);
792
793 auto name = g_implI->abckitStringToString(str);
794 EXPECT_TRUE(g_impl->getLastError() == ABCKIT_STATUS_NO_ERROR);
795
796 return name;
797 }
798
799 } // namespace libabckit::test::helpers
800