Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle constructors in extraction semantic. #94

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions test/baselines/semi/SemanticExtractionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,8 @@ void multilineStatement(int x, int y) {
void multipleStatementsPerLine(int x, int y) {
localMethod(x); localMethod(y);
}

SimpleMethods() { // first constructor
init();
}
}
69 changes: 42 additions & 27 deletions test/baselines/semi/test_extract_semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@

from veniq.baselines.semi.extract_semantic import extract_method_statements_semantic
from veniq.baselines.semi._common_types import StatementSemantic
from .utils import objects_semantic, get_method_ast
from veniq.ast_framework import AST
from .utils import objects_semantic, get_method_ast, get_constructor_ast


class ExtractStatementSemanticTestCase(TestCase):
def test_block_method(self):
self._test_helper("block", [StatementSemantic(), objects_semantic("x"), StatementSemantic()])
self._test_method("block", [StatementSemantic(), objects_semantic("x"), StatementSemantic()])

def test_for_cycle_method(self):
self._test_helper(
self._test_method(
"forCycle",
[objects_semantic("x", "i"), objects_semantic("x", "i", "result"), StatementSemantic()],
)

def test_while_cycle_method(self):
self._test_helper("whileCycle", [objects_semantic("x"), objects_semantic("x"), StatementSemantic()])
self._test_method("whileCycle", [objects_semantic("x"), objects_semantic("x"), StatementSemantic()])

def test_do_while_cycle_method(self):
self._test_helper("doWhileCycle", [objects_semantic("x"), objects_semantic("x"), StatementSemantic()])
self._test_method("doWhileCycle", [objects_semantic("x"), objects_semantic("x"), StatementSemantic()])

def test_if_branching_method(self):
self._test_helper(
self._test_method(
"ifBranching",
[
objects_semantic("x"),
Expand All @@ -38,12 +39,12 @@ def test_if_branching_method(self):
)

def test_synchronized_block_method(self):
self._test_helper(
self._test_method(
"synchronizedBlock", [objects_semantic("x"), objects_semantic("x"), StatementSemantic()]
)

def test_switch_branching_method(self):
self._test_helper(
self._test_method(
"switchBranching",
[
objects_semantic("x"),
Expand All @@ -55,7 +56,7 @@ def test_switch_branching_method(self):
)

def test_try_block_method(self):
self._test_helper(
self._test_method(
"tryBlock",
[
StatementSemantic(),
Expand All @@ -72,47 +73,47 @@ def test_try_block_method(self):
)

def test_assert_statement_method(self):
self._test_helper("assertStatement", [objects_semantic("x")])
self._test_method("assertStatement", [objects_semantic("x")])

def test_return_statement_method(self):
self._test_helper("returnStatement", [objects_semantic("x")])
self._test_method("returnStatement", [objects_semantic("x")])

def test_expression_method(self):
self._test_helper("expression", [objects_semantic("x")])
self._test_method("expression", [objects_semantic("x")])

def test_throw_statement_method(self):
self._test_helper("throwStatement", [objects_semantic("x")])
self._test_method("throwStatement", [objects_semantic("x")])

def test_local_variable_declaration_method(self):
self._test_helper("localVariableDeclaration", [objects_semantic("x")])
self._test_method("localVariableDeclaration", [objects_semantic("x")])

def test_break_statement_method(self):
self._test_helper("breakStatement", [StatementSemantic(), StatementSemantic(), StatementSemantic()])
self._test_method("breakStatement", [StatementSemantic(), StatementSemantic(), StatementSemantic()])

def test_continue_statement_method(self):
self._test_helper(
self._test_method(
"continueStatement", [StatementSemantic(), StatementSemantic(), StatementSemantic()]
)

def test_local_method_call_method(self):
self._test_helper("localMethodCall", [StatementSemantic(used_methods={"localMethod"})])
self._test_method("localMethodCall", [StatementSemantic(used_methods={"localMethod"})])

def test_object_method_call_method(self):
self._test_helper(
self._test_method(
"objectMethodCall", [StatementSemantic(used_objects={"o"}, used_methods={"method"})]
)

def test_nested_object_method(self):
self._test_helper("nestedObject", [StatementSemantic(used_objects={"o.x"})])
self._test_method("nestedObject", [StatementSemantic(used_objects={"o.x"})])

def test_nested_object_method_call_method(self):
self._test_helper(
self._test_method(
"nestedObjectMethodCall",
[StatementSemantic(used_objects={"o.nestedObject"}, used_methods={"method"})],
)

def test_several_statement_method(self):
self._test_helper(
self._test_method(
"severalStatements",
[
objects_semantic("x"),
Expand All @@ -124,7 +125,7 @@ def test_several_statement_method(self):
)

def test_deep_nesting_method(self):
self._test_helper(
self._test_method(
"deepNesting",
[
objects_semantic("i"),
Expand All @@ -140,7 +141,7 @@ def test_deep_nesting_method(self):
)

def test_complex_expressions_method(self):
self._test_helper(
self._test_method(
"complexExpressions",
[
objects_semantic("x", "y"),
Expand All @@ -156,20 +157,34 @@ def test_complex_expressions_method(self):
)

def test_multiline_statement_method(self):
self._test_helper("multilineStatement", [objects_semantic("x", "y", "o")])
self._test_method("multilineStatement", [objects_semantic("x", "y", "o")])

def test_multiple_statements_per_line_method(self):
self._test_helper(
self._test_method(
"multipleStatementsPerLine",
[
StatementSemantic(used_methods={"localMethod"}, used_objects={"x"}),
StatementSemantic(used_methods={"localMethod"}, used_objects={"y"}),
],
)

def _test_helper(self, method_name: str, expected_statements_semantics: List[StatementSemantic]):
def test_constructor(self):
self._test_constructor(1, [StatementSemantic(used_methods={"init"})])

def _test_method(self, method_name: str, expected_statements_semantics: List[StatementSemantic]):
method_ast = get_method_ast("SemanticExtractionTest.java", "SimpleMethods", method_name)
method_semantic = extract_method_statements_semantic(method_ast)
self._test_ast(method_ast, expected_statements_semantics)

def _test_constructor(
self, constructor_index: int, expected_statements_semantics: List[StatementSemantic]
):
constructor_ast = get_constructor_ast(
"SemanticExtractionTest.java", "SimpleMethods", constructor_index
)
self._test_ast(constructor_ast, expected_statements_semantics)

def _test_ast(self, ast: AST, expected_statements_semantics: List[StatementSemantic]):
method_semantic = extract_method_statements_semantic(ast)
for (
comparison_index,
(statement, actual_statement_semantic, expected_statement_semantic),
Expand Down
29 changes: 26 additions & 3 deletions test/baselines/semi/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from itertools import islice
from pathlib import Path
from typing import List, Tuple, Union

Expand Down Expand Up @@ -30,7 +31,7 @@ def fill_extraction_opportunity(node: Union[Block, Statement]):
return tuple(extraction_opportunity_list), block_statement_graph


def get_method_ast(filename: str, class_name: str, method_name: str) -> AST:
def get_class_ast(filename: str, class_name: str) -> Tuple[AST, Path]:
current_directory = Path(__file__).absolute().parent
filepath = current_directory / filename
ast = AST.build_from_javalang(build_ast(str(filepath)))
Expand All @@ -41,9 +42,31 @@ def get_method_ast(filename: str, class_name: str, method_name: str) -> AST:
for node in ast.get_root().types
if node.node_type == ASTNodeType.CLASS_DECLARATION and node.name == class_name
)
except StopIteration:
raise RuntimeError(f"Failed to find class {class_name} in file {filepath}")

return ast.get_subtree(class_declaration), filepath


method_declaration = next(node for node in class_declaration.methods if node.name == method_name)
def get_method_ast(filename: str, class_name: str, method_name: str) -> AST:
class_ast, filepath = get_class_ast(filename, class_name)

try:
method_declaration = next(node for node in class_ast.get_root().methods if node.name == method_name)
except StopIteration:
raise RuntimeError(f"Failed to find method {method_name} in class {class_name} in file {filepath}")

return ast.get_subtree(method_declaration)
return class_ast.get_subtree(method_declaration)


def get_constructor_ast(filename: str, class_name: str, constructor_index: int) -> AST:
class_ast, filepath = get_class_ast(filename, class_name)

try:
constructor_declaration = next(islice(class_ast.get_root().constructors, constructor_index - 1, None))
except StopIteration:
raise RuntimeError(
f"Failed to find {constructor_index}th constructor in class {class_name} in file {filepath}"
)

return class_ast.get_subtree(constructor_declaration)
1 change: 1 addition & 0 deletions veniq/baselines/semi/extract_semantic.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def _on_statement_entering(self, statement: Statement) -> None:
# "If" statements is handled separately in _on_block_entering due to "else if" construction
if extraction_statement.node_type in {
ASTNodeType.METHOD_DECLARATION,
ASTNodeType.CONSTRUCTOR_DECLARATION,
ASTNodeType.BLOCK_STATEMENT,
ASTNodeType.TRY_STATEMENT,
ASTNodeType.IF_STATEMENT,
Expand Down