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)
示例#2
0
def run_recommend_for_file(file: str, args):  # flake8: noqa
    """
    Calculate patterns and metrics, pass values to model and suggest pattern to change
    :param file: file to analyze
    :param args: different command line arguments
    :return: dict with code lines, filename and pattern name
    """
    java_file = str(Path(os.getcwd(), file))
    ncss = 0
    try:
        tree = build_ast(file)
        classes_with_annonations = find_annotation_by_node_type(
            tree, javalang.tree.ClassDeclaration)
        functions_with_annotations = find_annotation_by_node_type(
            tree, javalang.tree.MethodDeclaration)
        fields_with_annotations = find_annotation_by_node_type(
            tree, javalang.tree.FieldDeclaration)
        classes_with_patterns_ignored = flatten([
            pattern_code
            for node, pattern_code in classes_with_annonations.items()
        ])
        patterns_ignored = defaultdict(list)

        for node, patterns_list in functions_with_annotations.items():
            start_pos, end_pos = find_start_and_end_lines(node)
            for p in patterns_list:
                patterns_ignored[p].append([start_pos, end_pos])

        for node, patterns_list in fields_with_annotations.items():
            for p in patterns_list:
                patterns_ignored[p].append(
                    [node.position.line, node.position.line])

        components, error_exception = calculate_patterns_and_metrics_with_decomposition(
            java_file, args)

        if not components:
            results_list = []  # type: ignore
            error_exception = 'Empty java file; ncss = 0'
        else:
            results_list = []
            for lcom_component in components:
                code_lines_dict = lcom_component.get('code_lines_dict')
                input_params = lcom_component.get('input_params')
                # ncss += input_params['M4']
                # print('ncss comp', ncss)
                ranked_results = create_results(input_params, code_lines_dict,
                                                args,
                                                classes_with_patterns_ignored,
                                                patterns_ignored)
                if ranked_results:
                    results_list.append(ranked_results)

        ncss = NCSSMetric().value(AST.build_from_javalang(build_ast(file)))
    except Exception as e:
        error_exception = e
        ncss = 0
        results_list = []

    return {
        'filename': file,
        'results': results_list,
        'exception': error_exception,
        'ncss': ncss,
    }
示例#3
0
def main():
    exit_status = -1
    patterns_list = [
        'var_middle_number', 'this_find_number', 'string_concat_number',
        'instance_of_number', 'method_chain_number', 'var_decl_diff_number_11',
        'var_decl_diff_number_7', 'var_decl_diff_number_5',
        'super_method_call_number', 'force_type_cast_number', 'asserts_number',
        'setter_number', 'empty_rethrow_number',
        'prohibited_class_names_number', 'return_in_if_number',
        'impl_multi_number', 'many_prim_ctors_number', 'multiple_try_number',
        'non_final_field_number', 'null_check_number', 'part_sync_number',
        'red_catch_number', 'return_null_number'
    ]
    try:
        parser = argparse.ArgumentParser(
            description=
            'Find the pattern which has the largest impact on readability')
        parser.add_argument('--filename', help='path for Java file')
        parser.add_argument(
            '--version',
            action='version',
            version='%(prog)s {version}'.format(version=__version__))

        args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])

        if args:
            java_file = str(Path(os.getcwd(), args.filename))
            halstead_volume = find_halstead(java_file)
            var_numbers = VarMiddle().value(java_file)
            entropy = Entropy().value(java_file)
            left_space_variance, right_space_variance, max_left_space_diff, max_right_space_diff \
                = IndentationCounter().value(java_file)
            concat_str_number = StringConcatFinder().value(java_file)
            instance_of_lines = InstanceOf().value(java_file)
            method_chain_lines = MethodChainFind().value(java_file)
            var_decl_diff_lines_5 = VarDeclarationDistance(
                lines_th=5).value(java_file)
            var_decl_diff_lines_7 = VarDeclarationDistance(
                lines_th=7).value(java_file)
            var_decl_diff_lines_11 = VarDeclarationDistance(
                lines_th=11).value(java_file)
            super_m_lines = SuperMethod().value(java_file)
            force_type_cast_number = ForceTypeCastingFinder().value(java_file)
            this_lines = ThisFinder().value(java_file)
            asserts_lines = AssertInCode().value(java_file)
            setter_lines = ClassicSetter().value(java_file)
            empty_rethrow_lines = EmptyRethrow().value(java_file)
            prohibited_class_names = ErClass().value(java_file)
            if_return_lines = CountIfReturn().value(java_file)
            impl_multi_lines = ImplementsMultiFinder().value(java_file)
            many_prim_ctors_lines = ManyPrimaryCtors().value(java_file)
            multiple_try_lines = MultipleTry().value(java_file)
            non_final_field_lines = NonFinalAttribute().value(java_file)
            null_check_lines = NullCheck().value(java_file)
            part_sync_lines = PartialSync().value(java_file)
            red_catch_lines = RedundantCatch().value(java_file)
            return_null_lines = ReturnNull().value(java_file)
            ncss_lightweight = NCSSMetric().value(java_file)

            code_lines_dict = {
                'var_middle_number': var_numbers,
                'string_concat_number': concat_str_number,
                'instance_of_number': instance_of_lines,
                'method_chain_number': method_chain_lines,
                'var_decl_diff_number_5': var_decl_diff_lines_5,
                'var_decl_diff_number_7': var_decl_diff_lines_7,
                'var_decl_diff_number_11': var_decl_diff_lines_11,
                'super_method_call_number': super_m_lines,
                'force_type_cast_number': force_type_cast_number,
                'this_find_number': this_lines,
                'asserts_number': asserts_lines,
                'setter_number': setter_lines,
                'empty_rethrow_number': empty_rethrow_lines,
                'prohibited_class_names_number': prohibited_class_names,
                'return_in_if_number': if_return_lines,
                'impl_multi_number': impl_multi_lines,
                'many_prim_ctors_number': many_prim_ctors_lines,
                'multiple_try_number': multiple_try_lines,
                'non_final_field_number': non_final_field_lines,
                'null_check_number': null_check_lines,
                'part_sync_number': part_sync_lines,
                'red_catch_number': red_catch_lines,
                'return_null_number': return_null_lines,
            }
            input_params = {
                'var_middle_number': len(var_numbers),
                'string_concat_number': len(concat_str_number),
                'instance_of_number': len(instance_of_lines),
                'method_chain_number': len(method_chain_lines),
                'var_decl_diff_number_5': len(var_decl_diff_lines_5),
                'var_decl_diff_number_7': len(var_decl_diff_lines_7),
                'var_decl_diff_number_11': len(var_decl_diff_lines_11),
                'super_method_call_number': len(super_m_lines),
                'force_type_cast_number': len(force_type_cast_number),
                'this_find_number': len(this_lines),
                'asserts_number': len(asserts_lines),
                'setter_number': len(setter_lines),
                'empty_rethrow_number': len(empty_rethrow_lines),
                'prohibited_class_names_number': len(prohibited_class_names),
                'return_in_if_number': len(if_return_lines),
                'impl_multi_number': len(impl_multi_lines),
                'many_prim_ctors_number': len(many_prim_ctors_lines),
                'multiple_try_number': len(multiple_try_lines),
                'non_final_field_number': len(non_final_field_lines),
                'null_check_number': len(null_check_lines),
                'part_sync_number': len(part_sync_lines),
                'red_catch_number': len(red_catch_lines),
                'return_null_number': len(return_null_lines),
                'entropy': entropy,
                'halstead volume': halstead_volume,
                'left_spaces_var': left_space_variance,
                'right_spaces_var': right_space_variance,
                'max_left_diff_spaces': max_left_space_diff,
                'max_right_diff_spaces': max_right_space_diff,
                'ncss_lightweight': ncss_lightweight,
            }

            sorted_result = predict(input_params)
            found_pattern = False
            code_lines = None
            value = None
            for iter, (key, val) in enumerate(sorted_result.items()):
                if key in patterns_list:
                    if not found_pattern:
                        pattern = key
                        code_lines = code_lines_dict.get(key)
                        # We show only positive gradient, we won't add patterns
                        if code_lines and val > 1.00000e-20:
                            found_pattern = True
                            value = val

            if not code_lines:
                print('Your code is perfect in aibolit\'s opinion')
            else:
                output_str = \
                    'The largest contribution for {file} is {val} for \"{pattern}\" pattern'.format(
                        file=java_file,
                        pattern=pattern,
                        val=value)
                print(output_str)
                for line in code_lines:
                    if line:
                        print('Line {}. Low readability due to: {}'.format(
                            line, pattern))
            exit_status = 0
    except KeyboardInterrupt:
        exit_status = -1
    sys.exit(exit_status)
示例#4
0
 def testAnotherScore(self):
     file = 'test/metrics/ncss/WebAppsImpl.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 1429)
示例#5
0
 def testBasicExample(self):
     file = 'test/metrics/ncss/BasicExample.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 12)
示例#6
0
 def testHighScore(self):
     file = 'test/metrics/ncss/YarnConfiguration.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 1301)
示例#7
0
 def testMediumScore(self):
     file = 'test/metrics/ncss/WorkflowRunActionRepetitionDefinitionInner.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 73)
示例#8
0
 def testLowScore(self):
     file = 'test/metrics/ncss/GraalSDK.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 2)
示例#9
0
 def testZeroScore(self):
     file = 'test/metrics/ncss/Empty.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 0)
示例#10
0
 def testFinallyBlock(self):
     file = "test/metrics/ncss/FinallyBlock.java"
     ast = AST.build_from_javalang(build_ast(file))
     metric = NCSSMetric()
     res = metric.value(ast)
     self.assertEqual(res, 7)
示例#11
0
 def testChainedIfElseWithTrailingElse(self):
     file = "test/metrics/ncss/ChainedIfElseWithTrailingElse.java"
     ast = AST.build_from_javalang(build_ast(file))
     metric = NCSSMetric()
     res = metric.value(ast)
     self.assertEqual(res, 12)
示例#12
0
 def testSimpleExample2(self):
     file = "test/metrics/ncss/SimpleExample2.java"
     ast = AST.build_from_javalang(build_ast(file))
     metric = NCSSMetric()
     res = metric.value(ast)
     self.assertEqual(res, 19)
示例#13
0
 def testZeroScore(self):
     file = "test/metrics/ncss/Empty.java"
     ast = AST.build_from_javalang(build_ast(file))
     metric = NCSSMetric()
     res = metric.value(ast)
     self.assertEqual(res, 0)
示例#14
0
 def testFinallyBlock(self):
     file = 'test/metrics/ncss/FinallyBlock.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 7)
示例#15
0
 def testChainedIfElseWithTrailingElse(self):
     file = 'test/metrics/ncss/ChainedIfElseWithTrailingElse.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 12)
示例#16
0
 def testSimpleExample2(self):
     file = 'test/metrics/ncss/SimpleExample2.java'
     metric = NCSSMetric()
     res = metric.value(file)
     self.assertEqual(res, 19)