def _calculate_patterns_and_metrics( file_path: str, is_decomposition_requested: bool) -> List[Dict[str, Any]]: results: List[Dict[str, Any]] = [] config = Config.get_patterns_config() patterns_info = [ pattern_info for pattern_info in config["patterns"] if pattern_info["code"] not in config["patterns_exclude"] ] metrics_info = [ metric_info for metric_info in config["metrics"] if metric_info["code"] not in config["metrics_exclude"] ] ast = AST.build_from_javalang(build_ast(file_path)) classes_ast = [ ast.get_subtree(node) for node in ast.get_root().types if node.node_type == ASTNodeType.CLASS_DECLARATION ] for class_ast in classes_ast: components = (decompose_java_class( class_ast, "strong", ignore_getters=True, ignore_setters=True) if is_decomposition_requested else [class_ast]) for index, component_ast in enumerate(components): calculation_result = { "filepath": file_path, "class_name": class_ast.get_root().name, "component_index": index, } for pattern_info in patterns_info: try: pattern = pattern_info["make"]() pattern_result = pattern.value(component_ast) calculation_result[pattern_info["code"]] = len( pattern_result) calculation_result["lines_" + pattern_info["code"]] = pattern_result except Exception as cause: raise FileProcessingError(file_path, pattern_info["name"], cause) for metric_info in metrics_info: try: metric = metric_info["make"]() metric_result = metric.value(component_ast) calculation_result[metric_info["code"]] = metric_result except Exception as cause: raise FileProcessingError(file_path, metric_info["name"], cause) results.append(calculation_result) return results
def calculate_patterns_and_metrics_with_decomposition(file_path: str, args): error_exc = None patterns_to_suppress = args.suppress results_for_components = [] try: config = Config.get_patterns_config() patterns_info = [ pattern_info for pattern_info in config["patterns"] if pattern_info["code"] not in config["patterns_exclude"] ] metrics_info = [ metric_info for metric_info in config["metrics"] if metric_info["code"] not in config["metrics_exclude"] ] ast = AST.build_from_javalang(build_ast(file_path)) classes_ast = [ ast.get_subtree(node) for node in ast.get_root().types if node.node_type == ASTNodeType.CLASS_DECLARATION ] for class_ast in classes_ast: for index, component_ast in enumerate( decompose_java_class(class_ast, "strong")): result_for_component: Dict[Any, Any] = {} code_lines_dict: Dict[Any, Any] = OrderedDict() input_params = OrderedDict() # type: ignore for pattern_info in patterns_info: if pattern_info['code'] in config['patterns_exclude']: continue if pattern_info['code'] in patterns_to_suppress: input_params[pattern_info["code"]] = 0 code_lines_dict["lines_" + pattern_info["code"]] = [] else: pattern = pattern_info["make"]() pattern_result = pattern.value(component_ast) input_params[pattern_info["code"]] = len( pattern_result) code_lines_dict["lines_" + pattern_info["code"]] = pattern_result for metric_info in metrics_info: metric = metric_info["make"]() metric_result = metric.value(component_ast) input_params[metric_info["code"]] = metric_result result_for_component['code_lines_dict'] = code_lines_dict result_for_component['input_params'] = input_params result_for_component['index'] = index results_for_components.append(result_for_component) except Exception as ex: error_exc = ex return results_for_components, error_exc
def __decompose_with_setter_functionality(self, ignore_getters=False, ignore_setters=False): file = str(Path(self.cur_dir, 'LottieImageAsset.java')) ast = AST.build_from_javalang(build_ast(file)) classes_ast = [ ast.get_subtree(node) for node in ast.get_root().types if node.node_type == ASTNodeType.CLASS_DECLARATION ] components = list(decompose_java_class( classes_ast[0], "strong", ignore_setters=ignore_setters, ignore_getters=ignore_getters)) function_names = flatten([ [x.name for x in list(c.get_proxy_nodes(ASTNodeType.METHOD_DECLARATION))] for c in components]) return function_names
def test_ncss(self): test_data_folder = self.cur_dir / "ncss" for filepath in test_data_folder.glob("*.java"): with self.subTest(f"Testing decomposition of {filepath}"): ast = AST.build_from_javalang(build_ast(filepath)) classes_ast = [ ast.get_subtree(node) for node in ast.get_root().types if node.node_type == ASTNodeType.CLASS_DECLARATION ] ncss_metric = NCSSMetric() # NCSS of a class may not be equal to sum of ncss of methods and fields # due to presence of nested classes. To bypass it we calculate NCSS only # of methods and fields. methods_ncss = 0 fields_ncss = 0 components_ncss = 0 components_qty = 0 for class_ast in classes_ast: class_declaration = class_ast.get_root() for method in class_declaration.methods: methods_ncss += ncss_metric.value(class_ast.get_subtree(method)) for field in class_declaration.fields: fields_ncss += ncss_metric.value(class_ast.get_subtree(field)) for component in decompose_java_class(class_ast, "strong"): components_qty += 1 components_ncss += ncss_metric.value(component) # Each component has a CLASS_DECLARATION node. It increase NCSS of each component by 1. # To achieve equality we add number of components to the sum of NCSS of just methods and fields. self.assertEqual(methods_ncss + fields_ncss + components_qty, components_ncss)
def test_weak_decomposition(self): class_ast = self._get_class_ast("MethodUseOtherMethodExample.java", "MethodUseOtherMethod") class_components = decompose_java_class(class_ast, "weak") self.assertEqual(len(class_components), 5)