• 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/cpp/abckit_cpp.h"
19 
20 #include "helpers/helpers.h"
21 #include "helpers/helpers_runtime.h"
22 #include "libabckit/src/logger.h"
23 
24 namespace {
25 
26 class ErrorHandler final : public abckit::IErrorHandler {
HandleError(abckit::Exception && e)27     void HandleError(abckit::Exception &&e) override
28     {
29         EXPECT_TRUE(false) << "Abckit exception raised: " << e.what();
30     }
31 };
32 
33 const std::string ROUTER_MAP_FILE_MODULE_NAME = "modules/routerMap";
34 const std::string ROUTER_ANNOTATION_NAME = "Router";
35 const std::string FUNC_MAIN_0 = "func_main_0";
36 
37 struct RouterAnnotation {
38     abckit::core::Class owner;
39     abckit::core::Annotation anno;
40     std::string scheme;
41     std::string path;
42 };
43 
44 struct UserData {
45     std::string classStr;
46     std::string moduleStr;
47     RouterAnnotation routerInfo;
48 };
49 
FindFirstInst(const abckit::Graph & graph,AbckitIsaApiDynamicOpcode opcode)50 abckit::Instruction FindFirstInst(const abckit::Graph &graph, AbckitIsaApiDynamicOpcode opcode)
51 {
52     std::vector<abckit::BasicBlock> bbs = graph.GetBlocksRPO();
53     for (const auto &bb : bbs) {
54         auto curInst = bb.GetFirstInst();
55         while (curInst) {
56             if (curInst.GetGraph()->DynIsa().GetOpcode(curInst) == opcode) {
57                 return curInst;
58             }
59             curInst = curInst.GetNext();
60         }
61     }
62     return abckit::Instruction();
63 }
64 
TransformMethod(const abckit::core::Function & method,const UserData & ud,const abckit::core::ImportDescriptor & coreImport)65 void TransformMethod(const abckit::core::Function &method, const UserData &ud,
66                      const abckit::core::ImportDescriptor &coreImport)
67 {
68     size_t idx = 0;
69     auto ctxG = method.CreateGraph();
70     abckit::BasicBlock startBB = ctxG.GetStartBb();
71     std::vector<abckit::BasicBlock> succBBs = startBB.GetSuccs();
72     abckit::Instruction createEmptyArray = FindFirstInst(ctxG, ABCKIT_ISA_API_DYNAMIC_OPCODE_CREATEEMPTYARRAY);
73 
74     const auto &routerInfo = ud.routerInfo;
75     std::string fullPath = routerInfo.scheme + routerInfo.path;
76     auto arr = std::vector<abckit::Literal>();
77     auto filePtr = method.GetFile();
78     abckit::Literal str = filePtr->CreateLiteralString(fullPath);
79     arr.emplace_back(str);
80 
81     auto litArr = filePtr->CreateLiteralArray(arr);
82     auto createArrayWithBuffer = ctxG.DynIsa().CreateCreatearraywithbuffer(litArr);
83 
84     auto insertAfterInst = createEmptyArray;
85 
86     auto ldExternal = ctxG.DynIsa().CreateLdexternalmodulevar(coreImport);
87     auto classThrow = ctxG.DynIsa().CreateThrowUndefinedifholewithname(ldExternal, routerInfo.owner.GetName());
88     auto newObj = ctxG.DynIsa().CreateNewobjrange(ldExternal);
89     auto stownByIndex1 = ctxG.DynIsa().CreateStownbyindex(newObj, createArrayWithBuffer, 1);
90     auto stownByIndex2 = ctxG.DynIsa().CreateStownbyindex(createArrayWithBuffer, createEmptyArray, idx++);
91 
92     createArrayWithBuffer.InsertAfter(insertAfterInst);
93     ldExternal.InsertAfter(createArrayWithBuffer);
94     classThrow.InsertAfter(ldExternal);
95     newObj.InsertAfter(classThrow);
96     stownByIndex1.InsertAfter(newObj);
97     stownByIndex2.InsertAfter(stownByIndex1);
98     insertAfterInst = stownByIndex2;
99 
100     method.SetGraph(ctxG);
101 }
102 
ModifyRouterTable(const abckit::core::Function & method,const std::vector<UserData> & udContainer)103 void ModifyRouterTable(const abckit::core::Function &method, const std::vector<UserData> &udContainer)
104 {
105     for (const auto &ud : udContainer) {
106         std::optional<abckit::arkts::Module> foundModule;
107 
108         method.GetFile()->EnumerateModules([&](const abckit::core::Module &mod) -> bool {
109             if (ud.moduleStr == mod.GetName()) {
110                 foundModule = abckit::arkts::Module(mod);
111             }
112             return true;
113         });
114         EXPECT_TRUE(foundModule.has_value());
115 
116         abckit::arkts::Module arktsModule = abckit::arkts::Module(method.GetModule());
117         auto newImport = arktsModule.AddImportFromArktsV1ToArktsV1(*foundModule, ud.classStr, ud.classStr);
118         auto coreImport = *static_cast<abckit::core::ImportDescriptor *>(&newImport);
119         TransformMethod(method, ud, coreImport);
120     }
121 }
122 
FindMethodWithRouterTable(const abckit::File * filePtr)123 abckit::core::Function FindMethodWithRouterTable(const abckit::File *filePtr)
124 {
125     abckit::core::Function routerFunc;
126     filePtr->EnumerateModules([&](const abckit::core::Module &mod) -> bool {
127         if (mod.GetName() != ROUTER_MAP_FILE_MODULE_NAME) {
128             return true;
129         }
130         mod.EnumerateTopLevelFunctions([&](const abckit::core::Function &func) -> bool {
131             if (func.GetName() == FUNC_MAIN_0) {
132                 routerFunc = func;
133             }
134             return true;
135         });
136         return true;
137     });
138     return routerFunc;
139 }
140 
RemoveAnnotations(const std::vector<UserData> & udContainer)141 void RemoveAnnotations(const std::vector<UserData> &udContainer)
142 {
143     for (const auto &ud : udContainer) {
144         const auto &routerInfo = ud.routerInfo;
145         abckit::arkts::Class(routerInfo.owner).RemoveAnnotation(abckit::arkts::Annotation(routerInfo.anno));
146     }
147 }
148 
CollectClassInfo(std::vector<UserData> & udContainer,const abckit::core::Module & mod,const abckit::core::Class & klass)149 void CollectClassInfo(std::vector<UserData> &udContainer, const abckit::core::Module &mod,
150                       const abckit::core::Class &klass)
151 {
152     klass.EnumerateAnnotations([&](const abckit::core::Annotation &anno) -> bool {
153         auto annoClass = anno.GetInterface();
154         auto annoName = annoClass.GetName();
155         if (annoName != ROUTER_ANNOTATION_NAME) {
156             return true;
157         }
158 
159         std::string scheme;
160         std::string path;
161         anno.EnumerateElements([&](const abckit::core::AnnotationElement &annoElem) -> bool {
162             auto annoElemName = annoElem.GetName();
163             auto value = annoElem.GetValue();
164             if (annoElemName == "scheme") {
165                 scheme = value.GetString();
166             }
167             if (annoElemName == "path") {
168                 path = value.GetString();
169             }
170             return true;
171         });
172         UserData ud {klass.GetName(), mod.GetName(), RouterAnnotation {klass, anno, scheme, path}};
173         udContainer.push_back(ud);
174         return true;
175     });
176 }
177 
ClassHasAnnotation(const abckit::File * filePtr,const UserData & ud)178 bool ClassHasAnnotation(const abckit::File *filePtr, const UserData &ud)
179 {
180     bool found = false;
181 
182     auto classAnnotationsEnumCb = [&](const abckit::core::Annotation &anno) -> bool {
183         auto annoClass = anno.GetInterface();
184         if (annoClass.GetName() == ROUTER_ANNOTATION_NAME) {
185             found = true;
186         }
187         return true;
188     };
189 
190     filePtr->EnumerateModules([&](const abckit::core::Module &mod) -> bool {
191         if (mod.GetName() != ud.moduleStr) {
192             return true;
193         }
194         mod.EnumerateClasses([&](const abckit::core::Class &klass) -> bool {
195             if (klass.GetName() == ud.classStr) {
196                 klass.EnumerateAnnotations(classAnnotationsEnumCb);
197             }
198             return true;
199         });
200         return true;
201     });
202     return found;
203 }
204 
CollectClassesInfo(const abckit::File * filePtr,std::vector<UserData> & udContainer)205 void CollectClassesInfo(const abckit::File *filePtr, std::vector<UserData> &udContainer)
206 {
207     filePtr->EnumerateModules([&](const abckit::core::Module &mod) -> bool {
208         mod.EnumerateClasses([&](const abckit::core::Class &klass) -> bool {
209             CollectClassInfo(udContainer, mod, klass);
210             return true;
211         });
212         return true;
213     });
214 }
215 
216 }  // namespace
217 
218 namespace libabckit::test {
219 
220 class AbckitScenarioCppTestClean : public ::testing::Test {};
221 
222 // Test: test-kind=scenario, abc-kind=ArkTS1, category=positive, extension=cpp
TEST_F(AbckitScenarioCppTestClean,LibAbcKitTestDynammicRouterTableClean)223 TEST_F(AbckitScenarioCppTestClean, LibAbcKitTestDynammicRouterTableClean)
224 {
225     const std::string testSandboxPath = ABCKIT_ABC_DIR "clean_scenarios/cpp_api/dynamic/router_table/";
226     const std::string inputPath = testSandboxPath + "router_table.abc";
227     const std::string outputPath = testSandboxPath + "router_table_modified.abc";
228 
229     auto output = helpers::ExecuteDynamicAbc(inputPath, "router_table");
230     EXPECT_TRUE(helpers::Match(output, ""));
231 
232     abckit::File file(inputPath, std::make_unique<ErrorHandler>());
233 
234     const abckit::File *filePtr = &file;
235 
236     std::vector<UserData> userData;
237 
238     CollectClassesInfo(filePtr, userData);
239     RemoveAnnotations(userData);
240     auto method = FindMethodWithRouterTable(filePtr);
241     ModifyRouterTable(method, userData);
242 
243     file.WriteAbc(outputPath);
244 
245     for (const auto &ud : userData) {
246         ASSERT_FALSE(ClassHasAnnotation(filePtr, ud));
247     }
248 
249     output = helpers::ExecuteDynamicAbc(
250         ABCKIT_ABC_DIR "clean_scenarios/c_api/dynamic/router_table/router_table_modified.abc", "router_table");
251 
252     EXPECT_TRUE(helpers::Match(output,
253                                "xxxHandler.handle was called\n"
254                                "handle1/xxx\n"));
255 }
256 
257 }  // namespace libabckit::test
258