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 = static_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::CSTRING:
356 case TokenType::STRING:
357 case TokenType::STRING16:
358 case TokenType::U16STRING:
359 case TokenType::FLOAT:
360 case TokenType::DOUBLE:
361 case TokenType::FD:
362 case TokenType::FDSAN:
363 case TokenType::ASHMEM:
364 case TokenType::NATIVE_BUFFER:
365 case TokenType::POINTER:
366 case TokenType::UNSIGNED:
367 case TokenType::CHAR:
368 return true;
369 default:
370 return false;
371 }
372 }
373
CheckUserDefType(Token token)374 bool IntfTypeChecker::CheckUserDefType(Token token)
375 {
376 switch (token.kind) {
377 case TokenType::ENUM:
378 case TokenType::STRUCT:
379 case TokenType::UNION:
380 case TokenType::ID:
381 case TokenType::SEQ:
382 return true;
383 default:
384 return false;
385 }
386 }
387
CheckMessageOption(std::string & messageOption)388 bool IntfTypeChecker::CheckMessageOption(std::string &messageOption)
389 {
390 std::string flags = "";
391 std::string waitTime = "";
392 std::string flags_replace = "flags=";
393 std::string waitTime_replace = "waitTime=";
394 std::vector<std::string> msgOpts = StringHelper::Split(messageOption, " and ");
395 if (msgOpts.size() == 1) {
396 if (StringHelper::StartWith(msgOpts[0], waitTime_replace)) {
397 Logger::E(TAG, StringHelper::Format("[%s:%d] error: customMsgOption should start with 'flags='.",
398 __func__, __LINE__).c_str());
399 return false;
400 }
401 flags = StringHelper::Replace(msgOpts[0], flags_replace, "");
402 messageOption = flags;
403 return true;
404 }
405 if (msgOpts.size() > 1) {
406 if (StringHelper::StartWith(msgOpts[0], flags_replace)) {
407 flags = StringHelper::Replace(msgOpts[0], flags_replace, "");
408 } else if (StringHelper::StartWith(msgOpts[0], waitTime_replace)) {
409 waitTime = StringHelper::Replace(msgOpts[0], waitTime_replace, "");
410 } else {
411 Logger::E(TAG, StringHelper::Format(
412 "[%s:%d] error: customMsgOption should start with 'flags=' or 'waitTime='.",
413 __func__, __LINE__).c_str());
414 return false;
415 }
416
417 if (StringHelper::StartWith(msgOpts[1], flags_replace) && !waitTime.empty()) {
418 flags = StringHelper::Replace(msgOpts[1], flags_replace, "");
419 } else if (StringHelper::StartWith(msgOpts[1], waitTime_replace) && !flags.empty()) {
420 waitTime = StringHelper::Replace(msgOpts[1], waitTime_replace, "");
421 } else {
422 Logger::E(TAG, StringHelper::Format(
423 "[%s:%d] error: customMsgOption 'flags=' or 'waitTime=' should not empty.",
424 __func__, __LINE__).c_str());
425 return false;
426 }
427 if (flags.empty() || waitTime.empty()) {
428 Logger::E(TAG, StringHelper::Format(
429 "[%s:%d] error: customMsgOption 'flags=' or 'waitTime=' should not empty.",
430 __func__, __LINE__).c_str());
431 return false;
432 }
433 messageOption = flags + ", " + waitTime;
434 }
435 return true;
436 }
437
CheckSAPtrType(AutoPtr<ASTType> type)438 bool IntfTypeChecker::CheckSAPtrType(AutoPtr<ASTType> type)
439 {
440 Options &options = Options::GetInstance();
441 if (!(options.GetInterfaceType() == InterfaceType::SA && options.GetLanguage() == Language::CPP)) {
442 Logger::E(TAG, StringHelper::Format("[%s:%d] error: only --intf-type 'sa' and language 'cpp' support ptr",
443 __func__, __LINE__).c_str());
444 return false;
445 }
446 if ((type->GetTypeKind() == TypeKind::TYPE_SEQUENCEABLE && type->ToShortString() == "IRemoteObject") ||
447 type->GetTypeKind() == TypeKind::TYPE_INTERFACE) {
448 Logger::E(TAG, StringHelper::Format("[%s:%d] error: ptr not support 'IRemoteObject' and 'interface'",
449 __func__, __LINE__).c_str());
450 return false;
451 }
452 return true;
453 }
454 } // namespace Idl
455 } // namespace OHOS
456