Exemple #1
0
def determine_algorithm_insertion_type(
        ast: AST, method_node: ASTNode, invocation_node: ASTNode,
        dict_original_nodes: Dict[str,
                                  List[ASTNode]]) -> InlineTypesAlgorithms:
    """

    :param ast: ast tree
    :param dict_original_nodes: dict with names of function as key
    and list of ASTNode as values
    :param method_node: Method declaration. In this method invocation occurred
    :param invocation_node: invocation node
    :return: InlineTypesAlgorithms enum
    """

    original_invoked_method = dict_original_nodes.get(invocation_node.member,
                                                      [])
    # ignore overridden functions
    if (len(original_invoked_method)
            == 0) or (len(original_invoked_method) > 1):
        return InlineTypesAlgorithms.DO_NOTHING
    else:
        original_method = original_invoked_method[0]
        if not original_method.parameters:
            if not original_method.return_type:
                # Find the original method declaration by the name of method invocation
                var_decls = set(
                    get_variables_decl_in_node(
                        ast.get_subtree(original_method)))
                return check_whether_method_has_return_type(
                    ast.get_subtree(method_node), var_decls)
            else:
                return InlineTypesAlgorithms.WITH_RETURN_WITHOUT_ARGUMENTS
        else:
            return InlineTypesAlgorithms.DO_NOTHING
def _filter_class_methods_and_fields(class_ast: AST,
                                     allowed_fields_names: Set[str],
                                     allowed_methods_names: Set[str]) -> AST:
    class_declaration = class_ast.get_root()
    allowed_nodes = {class_declaration.node_index}

    for field_declaration in class_declaration.fields:
        if len(allowed_fields_names & set(field_declaration.names)) != 0:
            field_ast = class_ast.get_subtree(field_declaration)
            allowed_nodes.update(node.node_index for node in field_ast)

    for method_declaration in class_declaration.methods:
        if method_declaration.name in allowed_methods_names:
            method_ast = class_ast.get_subtree(method_declaration)
            allowed_nodes.update(node.node_index for node in method_ast)

    return AST(class_ast.tree.subgraph(allowed_nodes),
               class_declaration.node_index)
def find_patterns(tree: AST, patterns: List[Any]) -> Set[str]:
    """
    Searches all setters in a component
    :param patterns: list of patterns to check
    :param tree: ast tree
    :return: list of method name which are setters
    """

    patterns_method_names: Set[str] = set()
    for method_declaration in tree.get_root().methods:
        method_ast = tree.get_subtree(method_declaration)
        for pattern in patterns:
            if is_ast_pattern(method_ast, pattern):
                patterns_method_names.add(method_declaration.name)

    return patterns_method_names
def _create_usage_graph(class_ast: AST) -> DiGraph:
    usage_graph = DiGraph()
    fields_ids: Dict[str, int] = {}
    methods_ids: Dict[str, int] = {}

    class_declaration = class_ast.get_root()

    for field_declaration in class_declaration.fields:
        # several fields can be declared at one line
        for field_name in field_declaration.names:
            fields_ids[field_name] = len(fields_ids)
            usage_graph.add_node(fields_ids[field_name],
                                 type="field",
                                 name=field_name)

    for method_declaration in class_declaration.methods:
        method_name = method_declaration.name

        # overloaded methods considered as single node in usage_graph
        if method_name not in methods_ids:
            methods_ids[method_name] = len(fields_ids) + 1 + len(methods_ids)
            usage_graph.add_node(methods_ids[method_name],
                                 type="method",
                                 name=method_name)

    for method_declaration in class_declaration.methods:
        method_ast = class_ast.get_subtree(method_declaration)

        for invoked_method_name in _find_local_method_invocations(method_ast):
            if invoked_method_name in methods_ids:
                usage_graph.add_edge(
                    methods_ids[method_declaration.name],
                    methods_ids[invoked_method_name],
                )

        for used_field_name in _find_fields_usage(method_ast):
            if used_field_name in fields_ids:
                usage_graph.add_edge(methods_ids[method_declaration.name],
                                     fields_ids[used_field_name])

    return usage_graph
Exemple #5
0
def insert_code_with_new_file_creation(
        class_name: str, ast: AST, method_node: ASTNode,
        invocation_node: ASTNode, file_path: Path, output_path: Path,
        dict_original_invocations: Dict[str, List[ASTNode]]) -> Dict[str, Any]:
    """
    If invocations of class methods were found,
    we process through all of them and for each
    substitution opportunity by method's body,
    we create new file.
    """
    file_name = file_path.stem
    if not os.path.exists(output_path):
        output_path.mkdir(parents=True)

    new_full_filename = Path(
        output_path,
        f'{file_name}_{method_node.name}_{invocation_node.line}.java')
    original_func = dict_original_invocations.get(
        invocation_node.member)[0]  # type: ignore
    ncss = NCSSMetric().value(ast.get_subtree(original_func))
    line_to_csv = {}
    # @acheshkov asked to consider only methods with ncss > 3, that's all.
    if ncss > 3:
        body_start_line, body_end_line = method_body_lines(
            original_func, file_path)
        text_lines = read_text_with_autodetected_encoding(
            str(file_path)).split('\n')
        # we do not inline one-line methods like
        # public String getRemainingString() {return str.substring(index);}
        if body_start_line != body_end_line:
            algorithm_type = determine_algorithm_insertion_type(
                ast, method_node, invocation_node, dict_original_invocations)
            algorithm_for_inlining = AlgorithmFactory().create_obj(
                algorithm_type)
            if algorithm_type != InlineTypesAlgorithms.DO_NOTHING:
                line_to_csv = {
                    'input_filename':
                    file_path,
                    'class_name':
                    class_name,
                    'invocation_text_string':
                    text_lines[invocation_node.line - 1].lstrip(),
                    'method_where_invocation_occurred':
                    method_node.name,
                    'invocation_method_name':
                    original_func.name,
                    'output_filename':
                    new_full_filename
                }

                inline_method_bounds = algorithm_for_inlining(
                ).inline_function(
                    file_path,
                    invocation_node.line,
                    body_start_line,
                    body_end_line,
                    new_full_filename,
                )
                if inline_method_bounds is not None:
                    line_to_csv[
                        'inline_insertion_line_start'] = inline_method_bounds[
                            0]
                    line_to_csv[
                        'inline_insertion_line_end'] = inline_method_bounds[1]

                    if get_ast_if_possible(new_full_filename):
                        rest_of_csv_row_for_changed_file = find_lines_in_changed_file(
                            class_name=class_name,
                            method_node=method_node,
                            new_full_filename=new_full_filename,
                            original_func=original_func)

                        can_be_parsed = True
                        line_to_csv.update(rest_of_csv_row_for_changed_file)
                    else:
                        can_be_parsed = False

                    line_to_csv['can_be_parsed'] = can_be_parsed

    return line_to_csv
Exemple #6
0
def is_match_to_the_conditions(ast: AST,
                               method_invoked: ASTNode,
                               found_method_decl=None) -> bool:
    if method_invoked.parent.node_type == ASTNodeType.THIS:
        parent = method_invoked.parent.parent
        class_names = [
            x for x in method_invoked.parent.children if hasattr(x, 'string')
        ]
        member_references = [
            x for x in method_invoked.parent.children if hasattr(x, 'member')
        ]
        lst = [
            x for x in member_references if x.member != method_invoked.member
        ] + class_names
        no_children = not lst
    else:
        parent = method_invoked.parent
        no_children = True

    maybe_if = parent.parent
    is_not_method_inv_single_statement_in_if = True
    if maybe_if.node_type == ASTNodeType.IF_STATEMENT:
        if hasattr(maybe_if.then_statement, 'expression'):
            if maybe_if.then_statement.expression.node_type == ASTNodeType.METHOD_INVOCATION:
                is_not_method_inv_single_statement_in_if = False

    is_not_assign_value_with_return_type = True
    is_not_several_returns = True
    if found_method_decl.return_type:
        if parent.node_type == ASTNodeType.VARIABLE_DECLARATOR:
            is_not_assign_value_with_return_type = False

        ast_subtree = ast.get_subtree(found_method_decl)
        stats = [
            x
            for x in ast_subtree.get_proxy_nodes(ASTNodeType.RETURN_STATEMENT)
        ]
        if len(stats) > 1:
            is_not_several_returns = False

    is_not_parent_member_ref = not (method_invoked.parent.node_type
                                    == ASTNodeType.MEMBER_REFERENCE)
    is_not_chain_before = not (
        parent.node_type == ASTNodeType.METHOD_INVOCATION) and no_children
    chains_after = [
        x for x in method_invoked.children
        if x.node_type == ASTNodeType.METHOD_INVOCATION
    ]
    is_not_chain_after = not chains_after
    is_not_inside_if = not (parent.node_type == ASTNodeType.IF_STATEMENT)
    is_not_inside_while = not (parent.node_type == ASTNodeType.WHILE_STATEMENT)
    is_not_inside_for = not (parent.node_type == ASTNodeType.FOR_STATEMENT)
    is_not_enhanced_for_control = not (parent.node_type
                                       == ASTNodeType.ENHANCED_FOR_CONTROL)
    # ignore case else if (getServiceInterface() != null) {
    is_not_binary_operation = not (parent.node_type
                                   == ASTNodeType.BINARY_OPERATION)
    is_not_ternary = not (parent.node_type == ASTNodeType.TERNARY_EXPRESSION)
    # if a parameter is any expression, we ignore it,
    # since it is difficult to extract with AST
    is_actual_parameter_simple = all(
        [hasattr(x, 'member') for x in method_invoked.arguments])
    is_not_class_creator = not (parent.node_type == ASTNodeType.CLASS_CREATOR)
    is_not_cast = not (parent.node_type == ASTNodeType.CAST)
    is_not_array_creator = not (parent.node_type == ASTNodeType.ARRAY_CREATOR)
    is_not_lambda = not (parent.node_type == ASTNodeType.LAMBDA_EXPRESSION)
    is_not_at_the_same_line_as_prohibited_stats = check_nesting_statements(
        method_invoked)
    other_requirements = all([
        is_not_chain_before, is_actual_parameter_simple, is_not_chain_after,
        is_not_inside_if, is_not_inside_while, is_not_binary_operation,
        is_not_ternary, is_not_class_creator, is_not_cast,
        is_not_array_creator, is_not_parent_member_ref, is_not_inside_for,
        is_not_enhanced_for_control, is_not_lambda,
        is_not_method_inv_single_statement_in_if,
        is_not_assign_value_with_return_type, is_not_several_returns,
        is_not_at_the_same_line_as_prohibited_stats,
        not method_invoked.arguments
    ])

    if (not method_invoked.qualifier and other_requirements) or \
            (method_invoked.qualifier == 'this' and other_requirements):
        return True
    else:
        return False