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     if (!ast_->GetPackageName().empty()) {
55         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: package not support", __func__, __LINE__).c_str());
56         return false;
57     }
58 
59     const auto &importMap = ast_->GetImports();
60     if (std::any_of(importMap.begin(), importMap.end(), [] (const std::pair<std::string, AutoPtr<AST>> &importPair) {
61         return importPair.second->GetASTFileType() != ASTFileType::AST_SEQUENCEABLE;
62     })) {
63         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: import not support", __func__, __LINE__).c_str());
64         return false;
65     }
66 
67     bool definedIntf = false;
68     for (size_t i = 0; i < ast_->GetInterfaceDefNumber(); i++) {
69         if (!ast_->GetInterfaceDef(i)->IsExternal()) {
70             definedIntf = true;
71             break;
72         }
73     }
74 
75     if (!definedIntf) {
76         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: interface is not defined.", __func__,
77             __LINE__).c_str());
78         return false;
79     }
80 
81     ASTAttr::Attribute attr = ast_->GetInterfaceDef()->GetAttribute()->GetValue();
82     if ((attr != ASTAttr::NONE) && (attr != ASTAttr::ONEWAY)) {
83         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: interface attr only support [oneway]", __func__,
84             __LINE__).c_str());
85         return false;
86     }
87 
88     if (!CheckIntfSaAstTypes() || !CheckIntfSaAstMethods()) {
89         return false;
90     }
91 
92     return true;
93 }
94 
CheckIntfSaAstTypes()95 bool IntfTypeChecker::CheckIntfSaAstTypes()
96 {
97     for (const auto &pair : ast_->GetTypes()) {
98         AutoPtr<ASTType> type = pair.second;
99         switch (type->GetTypeKind()) {
100             case TypeKind::TYPE_FILEDESCRIPTOR:
101             case TypeKind::TYPE_ASHMEM:
102             case TypeKind::TYPE_NATIVE_BUFFER:
103             case TypeKind::TYPE_POINTER:
104             case TypeKind::TYPE_SMQ:
105             case TypeKind::TYPE_ENUM:
106             case TypeKind::TYPE_STRUCT:
107             case TypeKind::TYPE_UNION:
108             case TypeKind::TYPE_UCHAR:
109             case TypeKind::TYPE_USHORT:
110             case TypeKind::TYPE_UINT:
111             case TypeKind::TYPE_ULONG:
112             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: type '%s' not support", __func__, __LINE__,
113                 pair.first.c_str()).c_str());
114                 return false;
115             default:
116                 break;
117         }
118     }
119     return true;
120 }
121 
CheckIntfSaAstMethods()122 bool IntfTypeChecker::CheckIntfSaAstMethods()
123 {
124     AutoPtr<ASTInterfaceType> interfaceType = ast_->GetInterfaceDef();
125     bool onewayInterface = (interfaceType->GetAttribute()->GetValue() == ASTAttr::ONEWAY);
126 
127     for (size_t i = 0; i < interfaceType->GetMethodNumber(); i++) {
128         AutoPtr<ASTMethod> method = interfaceType->GetMethod(i);
129         if (((method->GetAttribute()->GetValue()) & (~(ASTAttr::ONEWAY | ASTAttr::CACHEABLE))) != 0) {
130             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: method attr support oneway or cacheable",
131                 __func__, __LINE__).c_str());
132             return false;
133         }
134         if (method->GetAttribute()->HasValue(ASTAttr::CACHEABLE) &&
135             !method->GetAttribute()->HasValue(ASTAttr::ONEWAY)) {
136             auto ret = method->SetCacheableTime();
137             if (ret) {
138                 ast_->SetHasCacheableProxyMethods(true);
139             } else {
140                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sa: method attr cacheable time invalid",
141                     __func__, __LINE__).c_str());
142                 return false;
143             }
144         }
145         if ((onewayInterface || method->GetAttribute()->GetValue() == ASTAttr::ONEWAY) &&
146             !method->GetReturnType()->IsVoidType()) {
147             Logger::E(TAG, StringHelper::Format(
148                 "[%s:%d] error:intf sa: method return type must be void in [oneway] interface or method", __func__,
149                 __LINE__).c_str());
150             return false;
151         }
152     }
153     return true;
154 }
155 
CheckIntfHdiAst()156 bool IntfTypeChecker::CheckIntfHdiAst()
157 {
158     if (ast_->GetPackageName().empty()) {
159         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi ast's package name is empty.", __func__,
160             __LINE__).c_str());
161         return false;
162     }
163 
164     if (!CheckIntfHdiAstFileType() || !CheckIntfHdiAstTypes()) {
165         return false;
166     }
167 
168     AutoPtr<ASTInterfaceType> interfaceType = ast_->GetInterfaceDef();
169     if (interfaceType == nullptr) {
170         return true;
171     }
172 
173     if (interfaceType->IsExternal()) {
174         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface not support external", __func__,
175             __LINE__).c_str());
176         return false;
177     }
178 
179     for (size_t i = 0; i < interfaceType->GetMethodNumber(); i++) {
180         AutoPtr<ASTMethod> method = interfaceType->GetMethod(i);
181         for (size_t j = 0; j < method->GetParameterNumber(); j++) {
182             if (!CheckIntfHdiAstParam(method->GetParameter(j), i, j)) {
183                 return false;
184             }
185         }
186     }
187 
188     return true;
189 }
190 
CheckIntfHdiAstFileType()191 bool IntfTypeChecker::CheckIntfHdiAstFileType()
192 {
193     switch (ast_->GetASTFileType()) {
194         case ASTFileType::AST_IFACE:
195             return CheckInterfaceAst();
196         case ASTFileType::AST_ICALLBACK:
197             return CheckCallbackAst();
198         case ASTFileType::AST_SEQUENCEABLE:
199             Logger::E(TAG, StringHelper::Format("[%s:%d] error:it's impossible that ast is sequenceable.", __func__,
200                 __LINE__).c_str());
201             return false;
202         case ASTFileType::AST_TYPES:
203             if (ast_->GetInterfaceDef() != nullptr) {
204                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:custom ast cannot has interface.", __func__,
205                     __LINE__).c_str());
206                 return false;
207             }
208             return true;
209         default:
210             return true;
211     }
212 }
213 
CheckIntfHdiAstTypes()214 bool IntfTypeChecker::CheckIntfHdiAstTypes()
215 {
216     for (const auto &pair : ast_->GetTypes()) {
217         AutoPtr<ASTType> type = pair.second;
218         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
219             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: type '%s' not support", __func__, __LINE__,
220                 pair.first.c_str()).c_str());
221             return false;
222         }
223     }
224     return true;
225 }
226 
CheckIntfHdiAstParam(AutoPtr<ASTParameter> param,size_t methodIdx,size_t paramIdx)227 bool IntfTypeChecker::CheckIntfHdiAstParam(AutoPtr<ASTParameter> param, size_t methodIdx, size_t paramIdx)
228 {
229     ASTParamAttr::ParamAttr paramAttr = param->GetAttribute();
230     if (paramAttr == ASTParamAttr::PARAM_INOUT) {
231         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: method[%d] param[%d] attr not support "
232             "[inout] or [in, out]", __func__, __LINE__, methodIdx, paramIdx).c_str());
233         return false;
234     }
235 
236     AutoPtr<ASTType> paramType = param->GetType();
237     if (paramType != nullptr && paramType->IsInterfaceType()) {
238         AutoPtr<ASTInterfaceType> ifaceType = dynamic_cast<ASTInterfaceType *>(paramType.Get());
239         if (ifaceType->IsCallback() && paramAttr != ASTParamAttr::PARAM_IN) {
240             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: '%s' "
241                 "param of callback interface type must be 'in' attr", __func__, __LINE__,
242                 param->GetName().c_str()).c_str());
243             return false;
244         } else if (!ifaceType->IsCallback() && paramAttr != ASTParamAttr::PARAM_OUT) {
245             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: '%s' param of interface "
246                 "type must be 'out' attr", __func__, __LINE__, param->GetName().c_str()).c_str());
247             return false;
248         }
249     }
250 
251     return true;
252 }
CheckInterfaceAst()253 bool IntfTypeChecker::CheckInterfaceAst()
254 {
255     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef();
256     if (interface == nullptr) {
257         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: ast's interface is empty.", __func__,
258             __LINE__).c_str());
259         return false;
260     }
261 
262     if (ast_->GetTypeDefinitionNumber() > 0) {
263         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface ast cannot has custom types.", __func__,
264             __LINE__).c_str());
265         return false;
266     }
267 
268     if (interface->GetMethodNumber() == 0) {
269         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf hdi: interface ast has no method.", __func__,
270             __LINE__).c_str());
271         return false;
272     }
273     return true;
274 }
275 
CheckCallbackAst()276 bool IntfTypeChecker::CheckCallbackAst()
277 {
278     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef();
279     if (interface == nullptr) {
280         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast's interface is empty.", __func__, __LINE__).c_str());
281         return false;
282     }
283 
284     if (!interface->IsCallback()) {
285         Logger::E(TAG, StringHelper::Format("[%s:%d] error:ast is callback, but ast's interface is not callback.",
286             __func__, __LINE__).c_str());
287         return false;
288     }
289     return true;
290 }
291 
CheckIntfSmAst()292 bool IntfTypeChecker::CheckIntfSmAst()
293 {
294     if (ast_->GetPackageName().empty()) {
295         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm ast's package name is empty.", __func__,
296             __LINE__).c_str());
297         return false;
298     }
299 
300     if (!CheckIntfSmAstFileType()) {
301         return false;
302     }
303 
304     for (const auto &pair : ast_->GetTypes()) {
305         AutoPtr<ASTType> type = pair.second;
306         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
307         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: type '%s' not support", __func__, __LINE__,
308             pair.first.c_str()).c_str());
309             return false;
310         }
311     }
312 
313     return true;
314 }
315 
CheckIntfSmAstFileType()316 bool IntfTypeChecker::CheckIntfSmAstFileType()
317 {
318     switch (ast_->GetASTFileType()) {
319         case ASTFileType::AST_IFACE:
320             return CheckSmInterfaceAst();
321         case ASTFileType::AST_ICALLBACK:
322             return CheckCallbackAst();
323         case ASTFileType::AST_SEQUENCEABLE:
324             Logger::E(TAG, StringHelper::Format("[%s:%d] error:it's impossible that ast is sequenceable.",
325                 __func__, __LINE__).c_str());
326             return false;
327         case ASTFileType::AST_TYPES:
328             if (ast_->GetInterfaceDef() != nullptr) {
329                 Logger::E(TAG, StringHelper::Format("[%s:%d] error:custom ast cannot has interface.",
330                     __func__, __LINE__).c_str());
331                 return false;
332             }
333             return true;
334         default:
335             return true;
336     }
337 }
338 
CheckIntfSmAstTypes()339 bool IntfTypeChecker::CheckIntfSmAstTypes()
340 {
341     for (const auto &pair : ast_->GetTypes()) {
342         AutoPtr<ASTType> type = pair.second;
343         if (type->GetTypeKind() == TypeKind::TYPE_CHAR) {
344             Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: type '%s' not support", __func__, __LINE__,
345                 pair.first.c_str()).c_str());
346             return false;
347         }
348     }
349     return true;
350 }
351 
CheckSmInterfaceAst()352 bool IntfTypeChecker::CheckSmInterfaceAst()
353 {
354     size_t index = 0;
355     for (size_t i = 0; i < ast_->GetInterfaceDefNumber(); i++) {
356         if (!ast_->GetInterfaceDef(i)->IsExternal()) {
357             index = i;
358             break;
359         }
360     }
361     AutoPtr<ASTInterfaceType> interface = ast_->GetInterfaceDef(index);
362     if (interface == nullptr) {
363         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: ast's interface is empty.", __func__,
364             __LINE__).c_str());
365         return false;
366     }
367 
368     if (ast_->GetTypeDefinitionNumber() > 0) {
369         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: interface ast cannot has custom types.", __func__,
370             __LINE__).c_str());
371         return false;
372     }
373 
374     if (interface->GetMethodNumber() == 0) {
375         Logger::E(TAG, StringHelper::Format("[%s:%d] error:intf sm: interface ast has no method.", __func__,
376             __LINE__).c_str());
377         return false;
378     }
379     return true;
380 }
381 } // namespace Idl
382 } // namespace OHOS
383