• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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