Skip to content

Commit

Permalink
Merge pull request #91 from cqfn/issue-86
Browse files Browse the repository at this point in the history
Constructor support in block statement graph.
  • Loading branch information
aravij authored Nov 3, 2020
2 parents 8830a0c + 1d5909e commit a5bbb3a
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 24 deletions.
4 changes: 4 additions & 0 deletions test/ast_framework/BlockStatementGraphExamples.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,8 @@ void complexExample1(int x) {

return x;
}

BlockStatementGraphExamples() { // First constructor
System.out.println("Inside constructor.");
}
}
79 changes: 55 additions & 24 deletions test/ast_framework/test_block_statement_graph.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,47 @@
from typing import List, Union
from itertools import islice
from typing import List, Tuple, Union
from pathlib import Path
from unittest import TestCase

from veniq.ast_framework.block_statement_graph import build_block_statement_graph, Block, Statement
from veniq.ast_framework.block_statement_graph.constants import BlockReason
from veniq.ast_framework import AST, ASTNodeType
from veniq.ast_framework import AST, ASTNode, ASTNodeType
from veniq.utils.ast_builder import build_ast


class BlockStatementTestCase(TestCase):
def test_single_assert_statement(self):
block_statement_graph = self._get_block_statement_graph("singleAssertStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleAssertStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[ASTNodeType.METHOD_DECLARATION, BlockReason.SINGLE_BLOCK, ASTNodeType.ASSERT_STATEMENT],
)

def test_single_return_statement(self):
block_statement_graph = self._get_block_statement_graph("singleReturnStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleReturnStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[ASTNodeType.METHOD_DECLARATION, BlockReason.SINGLE_BLOCK, ASTNodeType.RETURN_STATEMENT],
)

def test_single_statement_expression(self):
block_statement_graph = self._get_block_statement_graph("singleStatementExpression")
block_statement_graph = self._get_block_statement_graph_from_method("singleStatementExpression")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[ASTNodeType.METHOD_DECLARATION, BlockReason.SINGLE_BLOCK, ASTNodeType.STATEMENT_EXPRESSION],
)

def test_single_throw_statement(self):
block_statement_graph = self._get_block_statement_graph("singleThrowStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleThrowStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[ASTNodeType.METHOD_DECLARATION, BlockReason.SINGLE_BLOCK, ASTNodeType.THROW_STATEMENT],
)

def test_single_local_variable_declaration(self):
block_statement_graph = self._get_block_statement_graph("singleVariableDeclarationStatement")
block_statement_graph = self._get_block_statement_graph_from_method(
"singleVariableDeclarationStatement"
)
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -49,7 +52,7 @@ def test_single_local_variable_declaration(self):
)

def test_single_block_statement(self):
block_statement_graph = self._get_block_statement_graph("singleBlockStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleBlockStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -62,7 +65,7 @@ def test_single_block_statement(self):
)

def test_single_do_statement(self):
block_statement_graph = self._get_block_statement_graph("singleDoStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleDoStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -75,7 +78,7 @@ def test_single_do_statement(self):
)

def test_single_for_statement(self):
block_statement_graph = self._get_block_statement_graph("singleForStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleForStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -88,7 +91,7 @@ def test_single_for_statement(self):
)

def test_single_synchronize_statement(self):
block_statement_graph = self._get_block_statement_graph("singleSynchronizeStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleSynchronizeStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -101,7 +104,7 @@ def test_single_synchronize_statement(self):
)

def test_single_while_statement(self):
block_statement_graph = self._get_block_statement_graph("singleWhileStatement")
block_statement_graph = self._get_block_statement_graph_from_method("singleWhileStatement")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -114,7 +117,7 @@ def test_single_while_statement(self):
)

def test_cycle_with_break(self):
block_statement_graph = self._get_block_statement_graph("cycleWithBreak")
block_statement_graph = self._get_block_statement_graph_from_method("cycleWithBreak")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -127,7 +130,7 @@ def test_cycle_with_break(self):
)

def test_cycle_with_continue(self):
block_statement_graph = self._get_block_statement_graph("cycleWithContinue")
block_statement_graph = self._get_block_statement_graph_from_method("cycleWithContinue")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -140,7 +143,7 @@ def test_cycle_with_continue(self):
)

def test_single_if_then_branch(self):
block_statement_graph = self._get_block_statement_graph("singleIfThenBranch")
block_statement_graph = self._get_block_statement_graph_from_method("singleIfThenBranch")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -153,7 +156,7 @@ def test_single_if_then_branch(self):
)

def test_single_if_then_else_branches(self):
block_statement_graph = self._get_block_statement_graph("singleIfThenElseBranches")
block_statement_graph = self._get_block_statement_graph_from_method("singleIfThenElseBranches")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -168,7 +171,7 @@ def test_single_if_then_else_branches(self):
)

def test_several_else_if_branches(self):
block_statement_graph = self._get_block_statement_graph("severalElseIfBranches")
block_statement_graph = self._get_block_statement_graph_from_method("severalElseIfBranches")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -185,7 +188,7 @@ def test_several_else_if_branches(self):
)

def test_if_branches_without_curly_braces(self):
block_statement_graph = self._get_block_statement_graph("ifBranchingWithoutCurlyBraces")
block_statement_graph = self._get_block_statement_graph_from_method("ifBranchingWithoutCurlyBraces")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -200,7 +203,7 @@ def test_if_branches_without_curly_braces(self):
)

def test_switch_branches(self):
block_statement_graph = self._get_block_statement_graph("switchBranches")
block_statement_graph = self._get_block_statement_graph_from_method("switchBranches")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -219,7 +222,7 @@ def test_switch_branches(self):
)

def test_single_try_block(self):
block_statement_graph = self._get_block_statement_graph("singleTryBlock")
block_statement_graph = self._get_block_statement_graph_from_method("singleTryBlock")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -234,7 +237,7 @@ def test_single_try_block(self):
)

def test_full_try_block(self):
block_statement_graph = self._get_block_statement_graph("fullTryBlock")
block_statement_graph = self._get_block_statement_graph_from_method("fullTryBlock")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -255,7 +258,7 @@ def test_full_try_block(self):
)

def test_try_without_catch(self):
block_statement_graph = self._get_block_statement_graph("tryWithoutCatch")
block_statement_graph = self._get_block_statement_graph_from_method("tryWithoutCatch")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -269,7 +272,7 @@ def test_try_without_catch(self):
)

def test_complex_example1(self):
block_statement_graph = self._get_block_statement_graph("complexExample1")
block_statement_graph = self._get_block_statement_graph_from_method("complexExample1")
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
Expand All @@ -286,7 +289,18 @@ def test_complex_example1(self):
],
)

def _get_block_statement_graph(self, method_name: str) -> Block:
def test_simple_constructor(self):
block_statement_graph = self._get_block_statement_graph_from_constructor(1)
self.assertEqual(
self._flatten_block_statement_graph(block_statement_graph),
[
ASTNodeType.CONSTRUCTOR_DECLARATION,
BlockReason.SINGLE_BLOCK,
ASTNodeType.STATEMENT_EXPRESSION,
],
)

def _get_class_declaration(self) -> Tuple[str, str, ASTNode, AST]:
current_directory = Path(__file__).absolute().parent
filename = "BlockStatementGraphExamples.java"
ast = AST.build_from_javalang(build_ast(str(current_directory / filename)))
Expand All @@ -301,13 +315,30 @@ def _get_block_statement_graph(self, method_name: str) -> Block:
except StopIteration:
raise RuntimeError(f"Can't find class {class_name} in file {filename}")

return filename, class_name, class_declaration, ast

def _get_block_statement_graph_from_method(self, method_name: str) -> Block:
filename, class_name, class_declaration, ast = self._get_class_declaration()

try:
method_declaration = next(node for node in class_declaration.methods if node.name == method_name)
except StopIteration:
raise ValueError(f"Can't find method {method_name} in class {class_name} in file {filename}")

return build_block_statement_graph(ast.get_subtree(method_declaration))

def _get_block_statement_graph_from_constructor(self, constructor_index: int = 1) -> Block:
filename, class_name, class_declaration, ast = self._get_class_declaration()

try:
method_declaration = next(islice(class_declaration.constructors, constructor_index - 1, None))
except StopIteration:
raise ValueError(
f"Can't find {constructor_index}th constructor in class {class_name} in file {filename}"
)

return build_block_statement_graph(ast.get_subtree(method_declaration))

@staticmethod
def _flatten_block_statement_graph(
root: Union[Block, Statement]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def _unwrap_block_to_statements_list(
ASTNodeType.TRY_RESOURCE: _extract_blocks_from_plain_statement,
# single block statements
ASTNodeType.BLOCK_STATEMENT: _extract_blocks_from_single_block_statement_factory("statements"),
ASTNodeType.CONSTRUCTOR_DECLARATION: _extract_blocks_from_single_block_statement_factory("body"),
ASTNodeType.DO_STATEMENT: _extract_blocks_from_single_block_statement_factory("body"),
ASTNodeType.FOR_STATEMENT: _extract_blocks_from_single_block_statement_factory("body"),
ASTNodeType.METHOD_DECLARATION: _extract_blocks_from_single_block_statement_factory("body"),
Expand Down

1 comment on commit a5bbb3a

@0pdd
Copy link

@0pdd 0pdd commented on a5bbb3a Nov 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to retrieve PDD puzzles from the code base and submit them to GitHub. If you think that it's a bug on our side, please submit it to yegor256/0pdd:

set -x && set -e && set -o pipefail && cd /tmp/0pdd20200927-12-1vn5scd/cqfn/veniq && pdd -v -f /tmp/20201103-21622-1l05wfu [1]: + set -e + set -o pipefail + cd /tmp/0pdd20200927-12-1vn5scd/cqfn/veniq + pdd -v -f /tmp/20201103-21622-1l05wfu My version is 0.20.5 Ruby version is 2.6.0 at...

Please, copy and paste this stack trace to GitHub:

UserError
set -x && set -e && set -o pipefail && cd /tmp/0pdd20200927-12-1vn5scd/cqfn/veniq && pdd -v -f /tmp/20201103-21622-1l05wfu [1]:
+ set -e
+ set -o pipefail
+ cd /tmp/0pdd20200927-12-1vn5scd/cqfn/veniq
+ pdd -v -f /tmp/20201103-21622-1l05wfu

My version is 0.20.5
Ruby version is 2.6.0 at x86_64-linux
Reading /tmp/0pdd20200927-12-1vn5scd/cqfn/veniq
166 file(s) found, 1374 excluded
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/utils/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/ast_framework/computed_fields_catalog/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/patterns/classic_getter/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/patterns/classic_setter/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/metrics/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/dataset_collection/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/baselines/semi/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/veniq/baselines/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/augmentation/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/augmentation/test_augmentation.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/utils/Lines/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/utils/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/validation/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/ast_framework/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/dataset_collection/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/baselines/semi/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/baselines/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/__init__.py is a binary file (0 bytes)
/tmp/0pdd20200927-12-1vn5scd/cqfn/veniq/test/integration/__init__.py is a binary file (0 bytes)
Reading LICENSE...
Reading .gitignore...
Reading README.md...
Reading .gitattributes...
Reading stubs/javalang/util.pyi...
Reading stubs/javalang/ast.pyi...
ERROR: stubs/javalang/ast.pyi; puzzle at line #16; TODO found, but puzzle can't be parsed, most probably because TODO is not followed by a puzzle marker, as this page explains: https://github.com/yegor256/pdd#how-to-format
If you can't understand the cause of this issue or you don't know how to fix it, please submit a GitHub issue, we will try to help you: https://github.com/yegor256/pdd/issues. This tool is still in its beta version and we will appreciate your feedback. Here is where you can find more documentation: https://github.com/yegor256/pdd/blob/master/README.md.
Exit code is 1

/app/objects/git_repo.rb:66:in `rescue in block in xml'
/app/objects/git_repo.rb:63:in `block in xml'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/tempfile.rb:295:in `open'
/app/objects/git_repo.rb:62:in `xml'
/app/objects/puzzles.rb:36:in `deploy'
/app/objects/job.rb:38:in `proceed'
/app/objects/job_starred.rb:33:in `proceed'
/app/objects/job_recorded.rb:32:in `proceed'
/app/objects/job_emailed.rb:35:in `proceed'
/app/objects/job_commiterrors.rb:36:in `proceed'
/app/objects/job_detached.rb:48:in `exclusive'
/app/objects/job_detached.rb:36:in `block in proceed'
/app/objects/job_detached.rb:36:in `fork'
/app/objects/job_detached.rb:36:in `proceed'
/app/0pdd.rb:358:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1635:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1635:in `block in compile!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:992:in `block (3 levels) in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1011:in `route_eval'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:992:in `block (2 levels) in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1040:in `block in process_route'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1038:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1038:in `process_route'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:990:in `block in route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:989:in `each'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:989:in `route!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1097:in `block in dispatch!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `block in invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1094:in `dispatch!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:924:in `block in call!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `block in invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `catch'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1076:in `invoke'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:924:in `call!'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:913:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/xss_header.rb:18:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/path_traversal.rb:16:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/json_csrf.rb:26:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-protection-2.0.4/lib/rack/protection/frame_options.rb:31:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/logger.rb:15:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/common_logger.rb:33:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:231:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:224:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/head.rb:12:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/method_override.rb:22:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:194:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1957:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1502:in `block in call'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1729:in `synchronize'
/app/vendor/bundle/ruby/2.6.0/gems/sinatra-2.0.4/lib/sinatra/base.rb:1502:in `call'
/app/vendor/bundle/ruby/2.6.0/gems/rack-2.0.6/lib/rack/handler/webrick.rb:86:in `service'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/httpserver.rb:140:in `service'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/httpserver.rb:96:in `run'
/app/vendor/ruby-2.6.0/lib/ruby/2.6.0/webrick/server.rb:307:in `block in start_thread'

Please sign in to comment.