• 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 <gtest/gtest.h>
17 
18 #include "libabckit/include/c/extensions/arkts/metadata_arkts.h"
19 #include "helpers/helpers.h"
20 #include "helpers/helpers_runtime.h"
21 #include "tests/helpers/visit_helper/visit_helper-inl.h"
22 #include "metadata_inspect_impl.h"
23 #include "libabckit/src/logger.h"
24 
25 namespace {
26 
27 auto g_impl = AbckitGetApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
28 auto g_implI = AbckitGetInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
29 auto g_implM = AbckitGetModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
30 auto g_implG = AbckitGetGraphApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
31 auto g_dynG = AbckitGetIsaApiDynamicImpl(ABCKIT_VERSION_RELEASE_1_0_0);
32 auto g_implArkI = AbckitGetArktsInspectApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
33 auto g_implArkM = AbckitGetArktsModifyApiImpl(ABCKIT_VERSION_RELEASE_1_0_0);
34 
35 const std::string ROUTER_MAP_FILE_MODULE_NAME = "modules/routerMap";
36 const std::string ROUTER_ANNOTATION_NAME = "Router";
37 const std::string FUNC_MAIN_0 = "func_main_0";
38 
39 template <class ModuleCallBack>
EnumerateModules(const ModuleCallBack & cb,AbckitFile * file)40 inline void EnumerateModules(const ModuleCallBack &cb, AbckitFile *file)
41 {
42     LIBABCKIT_LOG_FUNC;
43 
44     g_implI->fileEnumerateModules(file, (void *)(&cb), [](AbckitCoreModule *mod, void *data) {
45         const auto &cb = *((ModuleCallBack *)(data));
46         cb(mod);
47         return true;
48     });
49 }
50 
51 template <class ClassCallBack>
EnumerateModuleClasses(AbckitCoreModule * mod,const ClassCallBack & cb)52 inline void EnumerateModuleClasses(AbckitCoreModule *mod, const ClassCallBack &cb)
53 {
54     LIBABCKIT_LOG_FUNC;
55 
56     g_implI->moduleEnumerateClasses(mod, (void *)(&cb), [](AbckitCoreClass *klass, void *data) {
57         const auto &cb = *((ClassCallBack *)data);
58         cb(klass);
59         return true;
60     });
61 }
62 
63 template <class AnnotationCallBack>
EnumerateClassAnnotations(AbckitCoreClass * klass,const AnnotationCallBack & cb)64 inline void EnumerateClassAnnotations(AbckitCoreClass *klass, const AnnotationCallBack &cb)
65 {
66     g_implI->classEnumerateAnnotations(klass, (void *)(&cb), [](AbckitCoreAnnotation *an, void *data) {
67         const auto &cb = *((AnnotationCallBack *)data);
68         cb(an);
69         return true;
70     });
71 }
72 
73 template <class AnnotationElementCallBack>
EnumerateAnnotationElements(AbckitCoreAnnotation * an,const AnnotationElementCallBack & cb)74 inline void EnumerateAnnotationElements(AbckitCoreAnnotation *an, const AnnotationElementCallBack &cb)
75 {
76     g_implI->annotationEnumerateElements(an, (void *)(&cb), [](AbckitCoreAnnotationElement *ele, void *data) {
77         const auto &cb = *((AnnotationElementCallBack *)data);
78         cb(ele);
79         return true;
80     });
81 }
82 
83 struct RouterAnnotation {
84     AbckitCoreClass *owner;
85     AbckitCoreAnnotation *ptrToAnno;
86     AbckitString *scheme;
87     AbckitString *path;
88 };
89 
90 struct UserData {
91     AbckitString *classStr;
92     AbckitString *moduleStr;
93     RouterAnnotation routerInfo;
94 };
95 
96 struct LocalData {
97     size_t idx;
98     AbckitInst *insertAfterInst;
99     AbckitCoreImportDescriptor *coreImport;
100 };
101 
FindFirstInst(AbckitGraph * graph,AbckitIsaApiDynamicOpcode opcode)102 AbckitInst *FindFirstInst(AbckitGraph *graph, AbckitIsaApiDynamicOpcode opcode)
103 {
104     std::vector<AbckitBasicBlock *> bbs;
105     g_implG->gVisitBlocksRpo(graph, &bbs, [](AbckitBasicBlock *bb, void *data) {
106         reinterpret_cast<std::vector<AbckitBasicBlock *> *>(data)->emplace_back(bb);
107         return true;
108     });
109     for (auto *bb : bbs) {
110         auto *curInst = g_implG->bbGetFirstInst(bb);
111         while (curInst != nullptr) {
112             if (g_dynG->iGetOpcode(curInst) == opcode) {
113                 return curInst;
114             }
115             curInst = g_implG->iGetNext(curInst);
116         }
117     }
118     return nullptr;
119 }
120 
TransformMethod(AbckitCoreFunction * method,VisitHelper & visitor,const UserData * ud,LocalData * ld)121 void TransformMethod(AbckitCoreFunction *method, VisitHelper &visitor, const UserData *ud, LocalData *ld)
122 {
123     visitor.TransformMethod(method, [&](AbckitFile *file, AbckitCoreFunction *method) {
124         auto ctxG = g_implI->createGraphFromFunction(method);
125         AbckitBasicBlock *startBB = g_implG->gGetStartBasicBlock(ctxG);
126         std::vector<AbckitBasicBlock *> succBBs;
127         g_implG->bbVisitSuccBlocks(startBB, &succBBs, [](AbckitBasicBlock *succBasicBlock, void *d) {
128             auto *succs = reinterpret_cast<std::vector<AbckitBasicBlock *> *>(d);
129             succs->emplace_back(succBasicBlock);
130             return true;
131         });
132         AbckitInst *createEmptyArray = FindFirstInst(ctxG, ABCKIT_ISA_API_DYNAMIC_OPCODE_CREATEEMPTYARRAY);
133 
134         const auto &routerInfo = ud->routerInfo;
135         std::string fullPath =
136             std::string(visitor.GetString(routerInfo.scheme)) + std::string(visitor.GetString(routerInfo.path));
137         auto arr = std::vector<AbckitLiteral *>();
138         AbckitLiteral *str = g_implM->createLiteralString(file, fullPath.data(), fullPath.size());
139         arr.emplace_back(str);
140 
141         auto *litArr = g_implM->createLiteralArray(file, arr.data(), arr.size());
142         auto *createArrayWithBuffer = g_dynG->iCreateCreatearraywithbuffer(ctxG, litArr);
143 
144         if (ld->insertAfterInst == nullptr) {
145             ld->insertAfterInst = createEmptyArray;
146         }
147 
148         auto *ldExternal = g_dynG->iCreateLdexternalmodulevar(ctxG, ld->coreImport);
149 
150         auto *classThrow =
151             g_dynG->iCreateThrowUndefinedifholewithname(ctxG, ldExternal, g_implI->classGetName(routerInfo.owner));
152 
153         auto *newObj = g_dynG->iCreateNewobjrange(ctxG, 1, ldExternal);
154 
155         auto *stownByIndex1 = g_dynG->iCreateStownbyindex(ctxG, newObj, createArrayWithBuffer, 1);
156 
157         auto *stownByIndex2 = g_dynG->iCreateStownbyindex(ctxG, createArrayWithBuffer, createEmptyArray, ld->idx++);
158 
159         ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
160 
161         g_implG->iInsertAfter(createArrayWithBuffer, ld->insertAfterInst);
162         g_implG->iInsertAfter(ldExternal, createArrayWithBuffer);
163         g_implG->iInsertAfter(classThrow, ldExternal);
164         g_implG->iInsertAfter(newObj, classThrow);
165         g_implG->iInsertAfter(stownByIndex1, newObj);
166         g_implG->iInsertAfter(stownByIndex2, stownByIndex1);
167 
168         ld->insertAfterInst = stownByIndex2;
169 
170         g_implM->functionSetGraph(method, ctxG);
171         g_impl->destroyGraph(ctxG);
172     });
173 }
174 
175 struct ModuleByNameContext {
176     AbckitCoreModule *module;
177     const char *name;
178 };
179 
ModuleByNameFinder(AbckitCoreModule * module,void * data)180 bool ModuleByNameFinder(AbckitCoreModule *module, void *data)
181 {
182     auto ctxFinder = reinterpret_cast<ModuleByNameContext *>(data);
183     auto name = g_implI->abckitStringToString(g_implI->moduleGetName(module));
184     if (strcmp(name, ctxFinder->name) == 0) {
185         ctxFinder->module = module;
186         return false;
187     }
188 
189     return true;
190 }
191 
ModifyRouterTable(AbckitCoreFunction * method,VisitHelper & visitor,const std::vector<UserData> & udContainer)192 void ModifyRouterTable(AbckitCoreFunction *method, VisitHelper &visitor, const std::vector<UserData> &udContainer)
193 {
194     LocalData ld {};
195     ld.idx = 0;
196     ld.insertAfterInst = nullptr;
197     for (const auto &ud : udContainer) {
198         const auto &className = visitor.GetString(ud.classStr);
199         AbckitArktsImportFromDynamicModuleCreateParams params {};
200         params.name = className.data();
201         params.alias = className.data();
202 
203         const auto &moduleName = visitor.GetString(ud.moduleStr);
204         ModuleByNameContext ctxFinder = {nullptr, moduleName.data()};
205         g_implI->fileEnumerateModules(g_implI->functionGetFile(method), &ctxFinder, ModuleByNameFinder);
206         ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
207         ASSERT_NE(ctxFinder.module, nullptr);
208         auto *newImport = g_implArkM->moduleAddImportFromArktsV1ToArktsV1(
209             g_implArkI->coreModuleToArktsModule(g_implI->functionGetModule(method)),
210             g_implArkI->coreModuleToArktsModule(ctxFinder.module), &params);
211         ld.coreImport = g_implArkI->arktsImportDescriptorToCoreImportDescriptor(newImport);
212         TransformMethod(method, visitor, &ud, &ld);
213     }
214 }
215 
FindMethodWithRouterTable(VisitHelper & visitor)216 AbckitCoreFunction *FindMethodWithRouterTable(VisitHelper &visitor)
217 {
218     AbckitCoreFunction *routerFunc = nullptr;
219     visitor.EnumerateModules([&](AbckitCoreModule *mod) {
220         auto moduleName = visitor.GetString(g_implI->moduleGetName(mod));
221         if (moduleName != ROUTER_MAP_FILE_MODULE_NAME) {
222             return;
223         }
224         visitor.EnumerateModuleTopLevelFunctions(mod, [&](AbckitCoreFunction *func) {
225             auto funcName = visitor.GetString(g_implI->functionGetName(func));
226             if (funcName != FUNC_MAIN_0) {
227                 return;
228             }
229             routerFunc = func;
230         });
231     });
232     return routerFunc;
233 }
234 
RemoveAnnotations(const std::vector<UserData> & udContainer)235 void RemoveAnnotations(const std::vector<UserData> &udContainer)
236 {
237     for (const auto &ud : udContainer) {
238         const auto &routerInfo = ud.routerInfo;
239         g_implArkM->classRemoveAnnotation(g_implArkI->coreClassToArktsClass(routerInfo.owner),
240                                           g_implArkI->coreAnnotationToArktsAnnotation(routerInfo.ptrToAnno));
241     }
242 }
243 
CollectClassInfo(std::vector<UserData> & udContainer,AbckitCoreModule * mod,AbckitCoreClass * klass)244 void CollectClassInfo(std::vector<UserData> &udContainer, AbckitCoreModule *mod, AbckitCoreClass *klass)
245 {
246     EnumerateClassAnnotations(klass, [&](AbckitCoreAnnotation *anno) {
247         auto *annoClass = g_implI->annotationGetInterface(anno);
248         auto annoName = g_implI->abckitStringToString(g_implI->annotationInterfaceGetName(annoClass));
249         if (annoName != ROUTER_ANNOTATION_NAME) {
250             return;
251         }
252         UserData ud {};
253         ud.classStr = g_implI->classGetName(klass);
254         ud.moduleStr = g_implI->moduleGetName(mod);
255         auto &routerInfo = ud.routerInfo;
256         routerInfo.ptrToAnno = anno;
257         routerInfo.owner = klass;
258         EnumerateAnnotationElements(anno, [&](AbckitCoreAnnotationElement *annoElem) {
259             auto annoElemName = g_implI->abckitStringToString(g_implI->annotationElementGetName(annoElem));
260             auto *value = g_implI->annotationElementGetValue(annoElem);
261             if (std::string_view(annoElemName) == "scheme") {
262                 routerInfo.scheme = g_implI->valueGetString(value);
263             }
264             if (std::string_view(annoElemName) == "path") {
265                 routerInfo.path = g_implI->valueGetString(value);
266             }
267         });
268         udContainer.push_back(ud);
269     });
270 }
271 
CollectClassesInfo(std::vector<UserData> & udContainer,AbckitFile * file)272 void CollectClassesInfo(std::vector<UserData> &udContainer, AbckitFile *file)
273 {
274     EnumerateModules(
275         [&](AbckitCoreModule *mod) {
276             EnumerateModuleClasses(mod, [&](AbckitCoreClass *klass) { CollectClassInfo(udContainer, mod, klass); });
277         },
278         file);
279 }
280 
ClassHasAnnotation(VisitHelper & visitor,const UserData & ud)281 bool ClassHasAnnotation(VisitHelper &visitor, const UserData &ud)
282 {
283     bool found = false;
284 
285     auto classAnnotationsEnumCb = [&](AbckitCoreAnnotation *anno) {
286         auto *annoClass = g_implI->annotationGetInterface(anno);
287         auto annoName = visitor.GetString(g_implI->annotationInterfaceGetName(annoClass));
288         if (annoName == ROUTER_ANNOTATION_NAME) {
289             found = true;
290         }
291     };
292 
293     visitor.EnumerateModules([&](AbckitCoreModule *mod) {
294         if (visitor.GetString(g_implI->moduleGetName(mod)) != visitor.GetString(ud.moduleStr)) {
295             return;
296         }
297         visitor.EnumerateModuleClasses(mod, [&](AbckitCoreClass *klass) {
298             if (visitor.GetString(g_implI->classGetName(klass)) != visitor.GetString(ud.classStr)) {
299                 return;
300             }
301             visitor.EnumerateClassAnnotations(klass, classAnnotationsEnumCb);
302         });
303     });
304     return found;
305 }
306 }  // namespace
307 
308 namespace libabckit::test {
309 
310 class AbckitScenarioCTestClean : public ::testing::Test {};
311 
312 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=c
TEST_F(AbckitScenarioCTestClean,LibAbcKitTestDynamicRouterTableClean)313 TEST_F(AbckitScenarioCTestClean, LibAbcKitTestDynamicRouterTableClean)
314 {
315     std::string inputPath = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/router_table/router_table.abc";
316     std::string outputPath = ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/router_table/router_table_modified.abc";
317 
318     auto output = helpers::ExecuteDynamicAbc(inputPath, "router_table");
319     EXPECT_TRUE(helpers::Match(output, ""));
320 
321     AbckitFile *file = g_impl->openAbc(inputPath.c_str(), inputPath.size());
322     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
323 
324     auto visitor = VisitHelper(file, g_impl, g_implI, g_implG, g_dynG);
325 
326     std::vector<UserData> userData;
327 
328     CollectClassesInfo(userData, file);
329     RemoveAnnotations(userData);
330     auto *method = FindMethodWithRouterTable(visitor);
331     ModifyRouterTable(method, visitor, userData);
332 
333     g_impl->writeAbc(file, outputPath.c_str(), outputPath.size());
334     ASSERT_EQ(g_impl->getLastError(), ABCKIT_STATUS_NO_ERROR);
335 
336     for (const auto &ud : userData) {
337         ASSERT_FALSE(ClassHasAnnotation(visitor, ud));
338     }
339 
340     output = helpers::ExecuteDynamicAbc(outputPath, "router_table");
341 
342     g_impl->closeFile(file);
343 
344     EXPECT_TRUE(helpers::Match(output,
345                                "xxxHandler.handle was called\n"
346                                "handle1/xxx\n"));
347 }
348 
349 }  // namespace libabckit::test
350