Skip to content

Commit

Permalink
[#528] Fix chained method pattern and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
aravij committed Jul 29, 2020
1 parent 6ee0631 commit ad8e13d
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 42 deletions.
57 changes: 23 additions & 34 deletions aibolit/patterns/method_chaining/method_chaining.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,32 @@


class MethodChainFind:
'''
In this pattern we check whether
more than one method chaining
invocation is used or not.
'''
def _is_invocation_inside(self, node: ASTNode) -> bool:
# to process structures such as:
# obj.methodInv1(list).methodInv2("blabla")
for i in node.children:
if i.node_type == ASTNodeType.METHOD_INVOCATION:
return True

return False

def _check_chained_method(self, ast: AST, method_invocation: ASTNode) -> bool:
childs = 0
for node in method_invocation.children:
if node.node_type == ASTNodeType.METHOD_INVOCATION:
# we check structures such as:
# new MyObject().Start()
# .SpecifySomeParameter(list)
# .SpecifySomeOtherParameter("list")
if self._is_invocation_inside(node) or node.qualifier is None:
childs += 1
return childs > 0
"""
Finds chained methods, i.e. foo().bar()
"""

def value(self, filename: str) -> List[int]:
lines: List[int] = []
ast = AST.build_from_javalang(build_ast(filename))
for stetement_expression in ast.get_proxy_nodes(ASTNodeType.STATEMENT_EXPRESSION):
expression_child = stetement_expression.expression
if expression_child.node_type == ASTNodeType.METHOD_INVOCATION and \
self._check_chained_method(ast, expression_child):
lines.append(stetement_expression.line)

elif expression_child.node_type == ASTNodeType.CLASS_CREATOR and \
len(expression_child.selectors) > 1:
lines.append(stetement_expression.line)
for node in ast.get_proxy_nodes(ASTNodeType.CLASS_CREATOR,
ASTNodeType.METHOD_INVOCATION,
ASTNodeType.THIS):
selectors_qty = self._get_selectors_qty(node)
if selectors_qty > MethodChainFind._allowed_number_of_selectord[node.node_type]:
lines.append(node.line)

return lines

def _get_selectors_qty(self, node: ASTNode) -> int:
if not hasattr(node, "selectors") or node.selectors is None:
return 0

return len(node.selectors)

_allowed_number_of_selectord = {
# found node already is a method invocation, so no further invocations are allowed
ASTNodeType.METHOD_INVOCATION: 0,
ASTNodeType.THIS: 1,
# code example: new Object().foo().bar()
ASTNodeType.CLASS_CREATOR: 1,
}
6 changes: 4 additions & 2 deletions test/patterns/method_chaining/NestedChainWIthThis.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ public void start() {
);

obj = new Object();
obj.ohhhh().set(this.govno("Zh").zhopa(whaaat).concat(whaaat)).opopo(whaaat);
obj.ohhhh().set(
this.govno("Zh").zhopa(whaaat).concat(whaaat)
).opopo(whaaat);
System.out.println("asdasd" + aaa + "34234" + bbb);
list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(Boolean.FALSE);
list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(Boolean.FALSE);

}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ public void start() {

obj = new Object();
obj1 = new Object();
obj.dummy1().dummy2(obj1.foo1("Zh").foo2(whaaat).foo3(whaaat)).dummy3(whaaat);
obj.dummy1().dummy2(
obj1.foo1("Zh").foo2(whaaat).foo3(whaaat)
).dummy3(whaaat);
System.out.println("asdasd" + aaa + "34234" + bbb);
list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(Boolean.FALSE);
list = new ArrayList<>();
for (int i = 0; i < 10; i++)
list.add(Boolean.FALSE);

}


Expand Down
8 changes: 4 additions & 4 deletions test/patterns/method_chaining/test_method_chaining.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_empty_method_chain(self):

def test_chain_with_new_object(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'MethodChainNewObjectMethods.java'))
self.assertEqual(lines, [34])
self.assertEqual(lines, [23, 34])

def test_method_chain_in_different_methods(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'MethodChainInDifferentMethods.java'))
Expand Down Expand Up @@ -68,11 +68,11 @@ def test_chain_without_object_creating(self):

def test_nested_chain_with_this(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'NestedChainWIthThis.java'))
self.assertEqual(lines, [14])
self.assertEqual(lines, [14, 15])

def test_nested_chain_with_simple_method_invocation(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'NestedChainWithSimpleMethodInvocation.java'))
self.assertEqual(lines, [15])
self.assertEqual(lines, [15, 16])

def test_nested_chain_complicated_structure(self):
"""
Expand All @@ -84,7 +84,7 @@ def test_nested_chain_complicated_structure(self):

def test_smallest_chain(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'SmallestChain.java'))
self.assertEqual(lines, [31])
self.assertEqual(lines, [31, 83, 84])

def test_fake_chain(self):
lines = self.method_chain_finder.value(Path(self.dir_path, 'FakeChain.java'))
Expand Down

0 comments on commit ad8e13d

Please sign in to comment.