• 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 "ast/ast_parameter.h"
17 #include "util/logger.h"
18 #include "util/string_builder.h"
19 #include "parser/intf_type_check.h"
20 
21 namespace OHOS {
22 namespace Idl {
CheckIntegrity()23 bool IntfTypeChecker::CheckIntegrity()
24 {
25     if (ast_ == nullptr) {
26         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast is nullptr.", __func__, __LINE__).c_str());
27         return false;
28     }
29 
30     if (ast_->GetName().empty()) {
31         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast's name is empty.", __func__, __LINE__).c_str());
32         return false;
33     }
34 
35     InterfaceType interfaceType = Options::GetInstance().GetInterfaceType();
36     if (interfaceType == InterfaceType::SA) {
37         return CheckIntfSaAst();
38     } else if (interfaceType == InterfaceType::HDI) {
39         return CheckIntfHdiAst();
40     } else if (interfaceType == InterfaceType::SM ||
41         interfaceType == InterfaceType::SAM ||
42         interfaceType == InterfaceType::SAM_SM ||
43         interfaceType == InterfaceType::SAM_UDS ||
44         interfaceType == InterfaceType::SM_UDS) {
45         return CheckIntfSmAst();
46     }
47 
48     Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf type is invalid.", __func__, __LINE__).c_str());
49     return false;
50 }
51 
CheckIntfSaAst()52 bool IntfTypeChecker::CheckIntfSaAst()
53 {
54     AutoPtr<ASTInterfaceType> interfaceType = ast_->GetInterfaceDef();
55     if (interfaceType == nullptr) {
56         return true;
57     }
58     if (!CheckIntfSaAstTypes() || !CheckIntfSaAstMethods()) {
59         return false;
60     }
61 
62     return true;
63 }
64 
CheckIntfSaAstTypes()65 bool IntfTypeChecker::CheckIntfSaAstTypes()
66 {
67     for (const auto &pair : ast_->GetTypes()) {
68         AutoPtr<ASTType> type = pair.second;
69         switch (type->GetTypeKind()) {
70             case TypeKind::TYPE_ASHMEM:
71             case TypeKind::TYPE_NATIVE_BUFFER:
72             case TypeKind::TYPE_POINTER:
73             case TypeKind::TYPE_SMQ:
74             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: type '%s' not support", __func__, __LINE__,
75                 pair.first.c_str()).c_str());
76                 return false;
77             default:
78                 break;
79         }
80     }
81     return true;
82 }
83 
CheckIntfSaAstMethods()84 bool IntfTypeChecker::CheckIntfSaAstMethods()
85 {
86     AutoPtr<ASTInterfaceType> interfaceType = ast_->GetInterfaceDef();
87     bool onewayInterface = (interfaceType->GetAttribute()->GetValue() == ASTAttr::ONEWAY);
88 
89     for (size_t i = 0; i < interfaceType->GetMethodNumber(); i++) {
90         AutoPtr<ASTMethod> method = interfaceType->GetMethod(i);
91         if (((method->GetAttribute()->GetValue()) &
92             (~(ASTAttr::ONEWAY | ASTAttr::CUSTOM_MSG_OPTION | ASTAttr::CACHEABLE | ASTAttr::IPCCODE |
93                 ASTAttr::IPC_IN_CAPACITY | ASTAttr::IPC_OUT_CAPACITY | ASTAttr::CALLBACK | ASTAttr::MACRO))) != 0) {
94             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: method attr support oneway, cacheable, "
95                 "ipccode, ipcincapacity, ipcoutcapacity, macrodef, macrondef", __func__, __LINE__).c_str());
96             return false;
97         }
98         if (method->GetAttribute()->HasValue(ASTAttr::CACHEABLE) &&
99             !method->GetAttribute()->HasValue(ASTAttr::ONEWAY)) {
100             auto ret = method->SetCacheableTime();
101             if (ret) {
102                 ast_->SetHasCacheableProxyMethods(true);
103             } else {
104                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: method attr cacheable time invalid",
105                     __func__, __LINE__).c_str());
106                 return false;
107             }
108         }
109         if ((onewayInterface || method->GetAttribute()->GetValue() == ASTAttr::ONEWAY) &&
110             !method->GetReturnType()->IsVoidType()) {
111             Logger::E(TAG, StringHelper::Format(
112                 "[%s:%d] error:intf sa: method return type must be void in [oneway] interface or method", __func__,
113                 __LINE__).c_str());
114             return false;
115         }
116     }
117     return true;
118 }
119 
CheckIntfHdiAst()120 bool IntfTypeChecker::CheckIntfHdiAst()
121 {
122     if (ast_->GetPackageName().empty()) {
123         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi ast's package name is empty.", __func__,
124             __LINE__).c_str());
125         return false;
126     }
127 
128     if (!CheckIntfHdiAstFileType() || !CheckIntfHdiAstTypes()) {
129         return false;
130     }
131 
132     AutoPtr<ASTInterfaceType> interfaceType = ast_->GetInterfaceDef();
133     if (interfaceType == nullptr) {
134         return true;
135     }
136 
137     if (interfaceType->IsExternal()) {
138         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface not support external", __func__,
139             __LINE__).c_str());
140         return false;
141     }
142 
143     for (size_t i = 0; i < interfaceType->GetMethodNumber(); i++) {
144         AutoPtr<ASTMethod> method = interfaceType->GetMethod(i);
145         for (size_t j = 0; j < method->GetParameterNumber(); j++) {
146             if (!CheckIntfHdiAstParam(method->GetParameter(j), i, j)) {
147                 return false;
148             }
149         }
150     }
151 
152     return true;
153 }
154 
CheckIntfHdiAstFileType()155 bool IntfTypeChecker::CheckIntfHdiAstFileType()
156 {
157     switch (ast_->GetASTFileType()) {
158         case ASTFileType::AST_IFACE:
159             return CheckInterfaceAst();
160         case ASTFileType::AST_ICALLBACK:
161             return CheckCallbackAst();
162         case ASTFileType::AST_SEQUENCEABLE:
163             Logger::E(TAG, StringHelper::Format("[%s:%d] error:it's impossible that ast is sequenceable.", __func__,
164                 __LINE__).c_str());
165             return false;
166         case ASTFileType::AST_TYPES:
167             if (ast_->GetInterfaceDef() != nullptr) {
168                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:custom ast cannot has interface.", __func__,
169                     __LINE__).c_str());
170                 return false;
171             }
172             return true;
173         default:
174             return true;
175     }
176 }
177 
CheckIntfHdiAstTypes()178 bool IntfTypeChecker::CheckIntfHdiAstTypes()
179 {
180     for (const auto &pair : ast_->GetTypes()) {
181         AutoPtr<ASTType> type = pair.second;
182         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
183             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: type '%s' not support", __func__, __LINE__,
184                 pair.first.c_str()).c_str());
185             return false;
186         }
187     }
188     return true;
189 }
190 
CheckIntfHdiAstParam(AutoPtr<ASTParameter> param,size_t methodIdx,size_t paramIdx)191 bool IntfTypeChecker::CheckIntfHdiAstParam(AutoPtr<ASTParameter> param, size_t methodIdx, size_t paramIdx)
192 {
193     ASTParamAttr::ParamAttr paramAttr = param->GetAttribute();
194     if (paramAttr == ASTParamAttr::PARAM_INOUT) {
195         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: method[%d] param[%d] attr not support "
196             "[inout] or [in, out]", __func__, __LINE__, methodIdx, paramIdx).c_str());
197         return false;
198     }
199 
200     AutoPtr<ASTType> paramType = param->GetType();
201     if (paramType != nullptr && paramType->IsInterfaceType()) {
202         AutoPtr<ASTInterfaceType> ifaceType = dynamic_cast<ASTInterfaceType *>(paramType.Get());
203         if (ifaceType->IsCallback() && paramAttr != ASTParamAttr::PARAM_IN) {
204             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: '%s' "
205                 "param of callback interface type must be 'in' attr", __func__, __LINE__,
206                 param->GetName().c_str()).c_str());
207             return false;
208         } else if (!ifaceType->IsCallback() && paramAttr != ASTParamAttr::PARAM_OUT) {
209             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: '%s' param of interface "
210                 "type must be 'out' attr", __func__, __LINE__, param->GetName().c_str()).c_str());
211             return false;
212         }
213     }
214 
215     return true;
216 }
CheckInterfaceAst()217 bool IntfTypeChecker::CheckInterfaceAst()
218 {
219     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef();
220     if (interface == nullptr) {
221         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: ast's interface is empty.", __func__,
222             __LINE__).c_str());
223         return false;
224     }
225 
226     if (ast_->GetTypeDefinitionNumber() > 0) {
227         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface ast cannot has custom types.", __func__,
228             __LINE__).c_str());
229         return false;
230     }
231 
232     if (interface->GetMethodNumber() == 0) {
233         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface ast has no method.", __func__,
234             __LINE__).c_str());
235         return false;
236     }
237     return true;
238 }
239 
CheckCallbackAst()240 bool IntfTypeChecker::CheckCallbackAst()
241 {
242     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef();
243     if (interface == nullptr) {
244         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast's interface is empty.", __func__, __LINE__).c_str());
245         return false;
246     }
247 
248     if (!interface->IsCallback()) {
249         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast is callback, but ast's interface is not callback.",
250             __func__, __LINE__).c_str());
251         return false;
252     }
253     return true;
254 }
255 
CheckIntfSmAst()256 bool IntfTypeChecker::CheckIntfSmAst()
257 {
258     if (ast_->GetPackageName().empty()) {
259         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm ast's package name is empty.", __func__,
260             __LINE__).c_str());
261         return false;
262     }
263 
264     if (!CheckIntfSmAstFileType()) {
265         return false;
266     }
267 
268     for (const auto &pair : ast_->GetTypes()) {
269         AutoPtr<ASTType> type = pair.second;
270         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
271         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: type '%s' not support", __func__, __LINE__,
272             pair.first.c_str()).c_str());
273             return false;
274         }
275     }
276 
277     return true;
278 }
279 
CheckIntfSmAstFileType()280 bool IntfTypeChecker::CheckIntfSmAstFileType()
281 {
282     switch (ast_->GetASTFileType()) {
283         case ASTFileType::AST_IFACE:
284             return CheckSmInterfaceAst();
285         case ASTFileType::AST_ICALLBACK:
286             return CheckCallbackAst();
287         case ASTFileType::AST_SEQUENCEABLE:
288             Logger::E(TAG, StringHelper::Format("[%s:%d] error:it's impossible that ast is sequenceable.",
289                 __func__, __LINE__).c_str());
290             return false;
291         case ASTFileType::AST_TYPES:
292             if (ast_->GetInterfaceDef() != nullptr) {
293                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:custom ast cannot has interface.",
294                     __func__, __LINE__).c_str());
295                 return false;
296             }
297             return true;
298         default:
299             return true;
300     }
301 }
302 
CheckIntfSmAstTypes()303 bool IntfTypeChecker::CheckIntfSmAstTypes()
304 {
305     for (const auto &pair : ast_->GetTypes()) {
306         AutoPtr<ASTType> type = pair.second;
307         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
308             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: type '%s' not support", __func__, __LINE__,
309                 pair.first.c_str()).c_str());
310             return false;
311         }
312     }
313     return true;
314 }
315 
CheckSmInterfaceAst()316 bool IntfTypeChecker::CheckSmInterfaceAst()
317 {
318     size_t index = 0;
319     for (size_t i = 0; i < ast_->GetInterfaceDefNumber(); i++) {
320         if (!ast_->GetInterfaceDef(i)->IsExternal()) {
321             index = i;
322             break;
323         }
324     }
325     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef(index);
326     if (interface == nullptr) {
327         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: ast's interface is empty.", __func__,
328             __LINE__).c_str());
329         return false;
330     }
331 
332     if (ast_->GetTypeDefinitionNumber() > 0) {
333         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: interface ast cannot has custom types.", __func__,
334             __LINE__).c_str());
335         return false;
336     }
337 
338     if (interface->GetMethodNumber() == 0) {
339         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: interface ast has no method.", __func__,
340             __LINE__).c_str());
341         return false;
342     }
343     return true;
344 }
345 
CheckBasicType(Token token)346 bool IntfTypeChecker::CheckBasicType(Token token)
347 {
348     switch (token.kind) {
349         case TokenType::VOID:
350         case TokenType::BOOLEAN:
351         case TokenType::BYTE:
352         case TokenType::SHORT:
353         case TokenType::INT:
354         case TokenType::LONG:
355         case TokenType::STRING:
356         case TokenType::STRING16:
357         case TokenType::FLOAT:
358         case TokenType::DOUBLE:
359         case TokenType::FD:
360         case TokenType::ASHMEM:
361         case TokenType::NATIVE_BUFFER:
362         case TokenType::POINTER:
363         case TokenType::UNSIGNED:
364         case TokenType::CHAR:
365             return true;
366         default:
367             return false;
368     }
369 }
370 
CheckUserDefType(Token token)371 bool IntfTypeChecker::CheckUserDefType(Token token)
372 {
373     switch (token.kind) {
374         case TokenType::ENUM:
375         case TokenType::STRUCT:
376         case TokenType::UNION:
377         case TokenType::ID:
378         case TokenType::SEQ:
379             return true;
380         default:
381             return false;
382     }
383 }
384 
CheckMessageOption(std::string & messageOption)385 bool IntfTypeChecker::CheckMessageOption(std::string &messageOption)
386 {
387     std::string flags = "";
388     std::string waitTime = "";
389     std::string flags_replace = "flags=";
390     std::string waitTime_replace = "waitTime=";
391     std::vector<std::string> msgOpts = StringHelper::Split(messageOption, " and ");
392     if (msgOpts.size() == 1) {
393         if (StringHelper::StartWith(msgOpts[0], waitTime_replace)) {
394             Logger::E(TAG, StringHelper::Format("[%s:%d] error: customMsgOption should start with 'flags='.",
395                 __func__, __LINE__).c_str());
396             return false;
397         }
398         flags = StringHelper::Replace(msgOpts[0], flags_replace, "");
399         messageOption = flags;
400         return true;
401     }
402     if (msgOpts.size() > 1) {
403         if (StringHelper::StartWith(msgOpts[0], flags_replace)) {
404             flags = StringHelper::Replace(msgOpts[0], flags_replace, "");
405         } else if (StringHelper::StartWith(msgOpts[0], waitTime_replace)) {
406             waitTime = StringHelper::Replace(msgOpts[0], waitTime_replace, "");
407         } else {
408             Logger::E(TAG, StringHelper::Format(
409                 "[%s:%d] error: customMsgOption should start with 'flags=' or 'waitTime='.",
410                 __func__, __LINE__).c_str());
411             return false;
412         }
413 
414         if (StringHelper::StartWith(msgOpts[1], flags_replace) && !waitTime.empty()) {
415             flags = StringHelper::Replace(msgOpts[1], flags_replace, "");
416         } else if (StringHelper::StartWith(msgOpts[1], waitTime_replace) && !flags.empty()) {
417             waitTime = StringHelper::Replace(msgOpts[1], waitTime_replace, "");
418         } else {
419             Logger::E(TAG, StringHelper::Format(
420                 "[%s:%d] error: customMsgOption 'flags=' or 'waitTime=' should not empty.",
421                 __func__, __LINE__).c_str());
422             return false;
423         }
424         if (flags.empty() || waitTime.empty()) {
425             Logger::E(TAG, StringHelper::Format(
426                 "[%s:%d] error: customMsgOption 'flags=' or 'waitTime=' should not empty.",
427                 __func__, __LINE__).c_str());
428             return false;
429         }
430         messageOption = flags + ", " + waitTime;
431     }
432     return true;
433 }
434 } // namespace Idl
435 } // namespace OHOS
436