1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16 17from typedef.detection import Output, ErrorMessage, ErrorType 18from utils.util import get_position_information, get_js_doc_info 19from typedef.process_three_type import get_three_label_value 20from utils.constants import label_comparison_dist 21 22 23def process_struct_type(dict_data: dict, label='default') -> list: 24 missing_tag_class_list = judgment_is_default(dict_data, label) 25 return missing_tag_class_list 26 27 28def process_class_type(dict_data: dict, label='default') -> list: 29 missing_tag_class_list = judgment_is_default(dict_data, label) 30 return missing_tag_class_list 31 32 33def process_namespace_type(dict_data: dict, label='default') -> list: 34 missing_tag_namespace_list = judgment_is_default(dict_data, label) 35 return missing_tag_namespace_list 36 37 38def process_interface_type(dict_data: dict, label='default') -> list: 39 missing_tag_interface_list = judgment_is_default(dict_data, label) 40 return missing_tag_interface_list 41 42 43def process_method_type(dict_data: dict, label='default') -> list: 44 missing_tag_method_list = judgment_is_default(dict_data, label) 45 return missing_tag_method_list 46 47 48def judgment_is_default(dict_data: dict, label) -> list: 49 result_data_total = [] 50 if 'default' == label: 51 result_data_total = default_processing_label(dict_data) 52 else: 53 if 'Method' == dict_data['apiType']: 54 for label_element in label: 55 change_label = label_comparison_dist[label_element] 56 result_data = process_method_tag(dict_data, change_label) 57 result_data_total.extend(result_data) 58 else: 59 for label_element in label: 60 change_label = label_comparison_dist[label_element] 61 result_data = process_tag(dict_data, change_label) 62 result_data_total.extend(result_data) 63 64 return result_data_total 65 66 67def process_method_tag(dict_data: dict, label): 68 missing_tag_data_list = [] 69 # 父没,不考虑 70 if 'jsDocInfos' not in dict_data: 71 return missing_tag_data_list 72 parent_information = get_js_doc_info(dict_data['jsDocInfos']) 73 if not parent_information: 74 return missing_tag_data_list 75 process_key = { 76 'typeLocations': 'typeLocations', 77 'objLocations': 'objLocations' 78 } 79 if 'params' in dict_data and len(dict_data['params']) > 0: 80 # 处理入参 81 result_param_list = process_func_param(dict_data, process_key, label, parent_information) 82 missing_tag_data_list.extend(result_param_list) 83 # 处理出参 84 result_return_list = process_func_anonymous_obj(dict_data, process_key, label, parent_information) 85 missing_tag_data_list.extend(result_return_list) 86 87 return missing_tag_data_list 88 89 90def process_func_param(dict_data: dict, key_info: dict, label: str, parent_info): 91 message_param_result_list = [] 92 # 处理每个参数 93 for param in dict_data['params']: 94 if 'typeLocations' in param and param['typeLocations']: 95 result_param_type = process_param_or_return(dict_data, key_info['typeLocations'], 96 parent_info, label, param) 97 message_param_result_list.extend(result_param_type) 98 if 'objLocations' in param and param['objLocations']: 99 result_param_obj = process_param_or_return(dict_data, key_info['objLocations'], 100 parent_info, label, param) 101 message_param_result_list.extend(result_param_obj) 102 103 return message_param_result_list 104 105 106def process_func_anonymous_obj(dict_data: dict, key_info: dict, label: str, parent_info): 107 message_obj_result_list = [] 108 if 'typeLocations' in dict_data and dict_data['typeLocations']: 109 result_return_type = process_param_or_return(dict_data, key_info['typeLocations'], parent_info, label) 110 message_obj_result_list.extend(result_return_type) 111 if 'objLocations' in dict_data and dict_data['objLocations']: 112 result_return_obj = process_param_or_return(dict_data, key_info['objLocations'], parent_info, label) 113 message_obj_result_list.extend(result_return_obj) 114 115 return message_obj_result_list 116 117 118def process_param_or_return(dict_data: dict, key_info: str, parent_info: dict, 119 label, process_data=None) -> list: 120 missing_tag_message_list = [] 121 new_label = label.replace('is', '') 122 error_result = {} 123 message_of_error = diff_of_param_obj(key_info).split('#') 124 if not process_data: 125 process_data = dict_data 126 message_of_error = diff_of_param_obj(key_info, in_out=1).split('#') 127 for child_info in process_data[key_info]: 128 # 父有,参or对象没 129 if label in parent_info and label in child_info and \ 130 parent_info[label] and (not child_info[label]): 131 error_type = message_of_error[0] 132 error_message = message_of_error[1].replace('&', new_label) 133 error_result.setdefault('error_type', error_type) 134 error_result.setdefault('error_message', error_message) 135 error_result.setdefault('error_quote_name', child_info.get('typeName')) 136 message_obj = get_message_obj(dict_data, error_result, process_data) 137 missing_tag_message_list.append(message_obj) 138 break 139 140 return missing_tag_message_list 141 142 143def diff_of_param_obj(key, in_out=0): 144 diff_data = { 145 'typeLocations': '{}#{}'.format(ErrorType.PARAM_NO_TAG.value, 146 ErrorMessage.METHOD_HAVE_INPUT_PARAM_NO.value), 147 'objLocations': '{}#{}'.format(ErrorType.PARAM_OBJ_NO_TAG.value, 148 ErrorMessage.METHOD_HAVE_PARAM_OBJ_NO.value) 149 } 150 if 1 == in_out: 151 diff_data['typeLocations'] = '{}#{}'.format(ErrorType.RETURN_NO_TAG.value, 152 ErrorMessage.METHOD_HAVE_OUTPUT_PARAM_NO.value) 153 diff_data['objLocations'] = '{}#{}'.format(ErrorType.RETURN_OBJ_NO_TAG.value, 154 ErrorMessage.METHOD_HAVE_RETURN_OBJ_NO.value) 155 error_info = '' 156 if key in diff_data: 157 error_info = diff_data[key] 158 159 return error_info 160 161 162def process_tag(dict_data: dict, label): 163 missing_tag_data_list = [] 164 if 'childApis' not in dict_data: 165 return missing_tag_data_list 166 # 处理property 167 for child_data in dict_data['childApis']: 168 if 'apiType' in child_data and 'Property' == child_data.get('apiType'): 169 result_list = process_child_quote_of_three(child_data, label) 170 missing_tag_data_list.extend(result_list) 171 # 节点没有jsDocInfos 172 if 'jsDocInfos' not in dict_data: 173 error_result = process_no_js_info(dict_data, label) 174 else: 175 error_result = process_js_info(dict_data, label) 176 if error_result: 177 message_obj = get_message_obj(dict_data, error_result) 178 missing_tag_data_list.append(message_obj) 179 180 return missing_tag_data_list 181 182 183def process_child_quote_of_three(child_data, label): 184 missing_tag_data_list = [] 185 if 'jsDocInfos' not in child_data: 186 return missing_tag_data_list 187 child_info = get_js_doc_info(child_data['jsDocInfos']) 188 if not child_info: 189 return missing_tag_data_list 190 if 'typeLocations' in child_data and child_data['typeLocations']: 191 process_key = 'typeLocations' 192 result_list_of_type = process_reference_type_child(child_data, child_info, label, process_key) 193 missing_tag_data_list.extend(result_list_of_type) 194 if 'objLocations' in child_data and child_data['objLocations']: 195 process_key = 'objLocations' 196 result_list_of_obj = process_reference_type_child(child_data, child_info, label, process_key) 197 missing_tag_data_list.extend(result_list_of_obj) 198 199 return missing_tag_data_list 200 201 202def process_reference_type_child(child_data, current_info, label, process_key): 203 missing_tag_message_list = [] 204 new_label = label.replace('is', '') 205 for refer_info in child_data[process_key]: 206 error_result = {} 207 if label in current_info and label in refer_info: 208 # property有,引用没 209 if current_info[label] and (not refer_info[label]): 210 error_result = reference_obj_or_type(process_key, new_label) 211 error_result.setdefault('error_quote_name', refer_info.get('typeName')) 212 213 if error_result: 214 message_obj = get_message_obj(child_data, error_result) 215 missing_tag_message_list.append(message_obj) 216 217 return missing_tag_message_list 218 219 220def reference_obj_or_type(process_key, new_label): 221 error_result = {} 222 error_type = '' 223 error_message = '' 224 if 'typeLocations' == process_key: 225 # property有,引用没 226 error_type = ErrorType.PROPERTY_REFERENCE_NO_TAG.value 227 error_message = ErrorMessage.PROPERTY_HAVE_REFERENCE_NO.value.replace('&', new_label) 228 229 elif 'objLocations' == process_key: 230 # property有,引用对象没 231 error_type = ErrorType.PROPERTY_REFERENCE_OBJ_NO_TAG.value 232 error_message = ErrorMessage.PROPERTY_HAVE_REFERENCE_OBJ_NO.value.replace('&', new_label) 233 234 error_result.setdefault('error_type', error_type) 235 error_result.setdefault('error_message', error_message) 236 237 return error_result 238 239 240def process_no_js_info(dict_data: dict, label): 241 error_result = {} 242 new_label = label.replace('is', '') 243 for child_data in dict_data['childApis']: 244 if 'jsDocInfos' not in child_data: 245 continue 246 data_tag_info = get_js_doc_info(child_data['jsDocInfos']) 247 if not data_tag_info: 248 continue 249 if label in data_tag_info and data_tag_info[label]: 250 error_type = ErrorType.PARENT_NO_TAG.value.replace('$', dict_data['apiType']) 251 error_message = (ErrorMessage.METHOD_HAVE_PARENT_NO.value 252 .replace('&', new_label) 253 .replace('$', dict_data['apiType'])) 254 error_result.setdefault('error_type', error_type) 255 error_result.setdefault('error_message', error_message) 256 break 257 258 return error_result 259 260 261def process_js_info(dict_data: dict, label): 262 new_label = label.replace('is', '') 263 parent_information = get_js_doc_info(dict_data['jsDocInfos']) 264 # 对应值是空值 265 if not parent_information: 266 error_result = process_no_js_info(dict_data, label) 267 return error_result 268 len_of_dict_data = len(dict_data['childApis']) 269 count_label, error_result = judgement_js_info(dict_data, parent_information, label, new_label) 270 # 父有,子一个都没有 271 if 0 != len_of_dict_data and count_label == len_of_dict_data: 272 error_type = ErrorType.CHILD_NO_TAG.value 273 error_message = (ErrorMessage.PARENT_HAVE_METHOD_NO.value 274 .replace('$', dict_data['apiType']) 275 .replace('&', new_label)) 276 error_result.setdefault('error_type', error_type) 277 error_result.setdefault('error_message', error_message) 278 279 return error_result 280 281 282def judgement_js_info(dict_data, parent_information, label, new_label): 283 count_label = 0 284 error_result = {} 285 for child_data in dict_data['childApis']: 286 if 'jsDocInfos' not in child_data: 287 if parent_information[label]: 288 count_label += 1 289 else: 290 child_tag_infor = get_js_doc_info(child_data['jsDocInfos']) 291 if not child_tag_infor: 292 count_label += 1 293 elif label in parent_information and label in child_tag_infor and \ 294 parent_information[label] and child_tag_infor[label]: 295 break 296 elif label in parent_information and label in child_tag_infor and \ 297 parent_information[label] and (not child_tag_infor[label]): 298 count_label += 1 299 # 父没,子有 300 elif label in parent_information and label in child_tag_infor and \ 301 (not parent_information[label]) and child_tag_infor[label]: 302 error_type = ErrorType.PARENT_NO_TAG.value.replace('$', dict_data['apiType']) 303 error_message = (ErrorMessage.METHOD_HAVE_PARENT_NO.value 304 .replace('$', dict_data['apiType']) 305 .replace('&', new_label)) 306 error_result.setdefault('error_type', error_type) 307 error_result.setdefault('error_message', error_message) 308 break 309 return count_label, error_result 310 311 312def get_message_obj(dict_data: dict, error_result: dict, in_or_out=None) -> Output: 313 if not in_or_out: 314 defined_text = dict_data['definedText'] 315 elif in_or_out != dict_data: 316 defined_text = in_or_out['definedText'] 317 else: 318 defined_text = dict_data['definedText'] 319 if 'error_quote_name' in error_result: 320 error_message = '({});{}'.format(error_result.get('error_quote_name'), 321 error_result['error_message']) 322 else: 323 error_message = error_result['error_message'] 324 message_obj = Output(dict_data['filePath'], error_result['error_type'], defined_text, 325 get_position_information(dict_data['pos']), error_message) 326 return message_obj 327 328 329def default_processing_label(dict_data: dict): 330 missing_tag_total_list = [] 331 label_dict = get_three_label_value() 332 for label in label_dict: 333 if 'Method' == dict_data['apiType']: 334 result_data = process_method_tag(dict_data, label_dict[label]) 335 else: 336 result_data = process_tag(dict_data, label_dict[label]) 337 missing_tag_total_list.extend(result_data) 338 339 return missing_tag_total_list 340 341 342def process_tag_dict(dict_data: dict, label: list): 343 # 绑定特定的节点对应标签处理函数 344 process_result_list = [] 345 process_special_tag = { 346 'Class': process_class_type, 347 'Namespace': process_namespace_type, 348 'Interface': process_interface_type, 349 'Method': process_method_type, 350 'Struct': process_struct_type 351 } 352 if 'apiType' in dict_data: 353 api_type = dict_data['apiType'] 354 if api_type in process_special_tag: 355 process_result = process_special_tag[api_type](dict_data, label) 356 process_result_list.extend(process_result) 357 358 return process_result_list 359