javalang icon indicating copy to clipboard operation
javalang copied to clipboard

How to associate methods to a class in a java file

Open aditi9292 opened this issue 4 years ago • 2 comments

A java file can contain multiple classes as well as inner classes. I want to associate methods to the class it belongs to. How can I do this>

aditi9292 avatar Sep 10 '20 02:09 aditi9292

I had the same issue and ended up with the following code:

import javalang


def traverse_for_methods(node, fn, klass='', level=0):
    # print('  ' * level, type(node), node.name if hasattr(node, 'name') else "")

    if isinstance(node, javalang.tree.ConstructorDeclaration) or isinstance(node, javalang.tree.MethodDeclaration):
        fn(node, klass)
    elif isinstance(node, javalang.tree.ClassDeclaration):
        klass = node.name
    elif isinstance(node, javalang.tree.ClassCreator):
        # Anonymous classes
        klass = node.type.name

    if hasattr(node, 'children'):
        for child in node.children:
            if isinstance(child, list) and (len(child) > 0):
                for item in child:
                    traverse_for_methods(item, fn, klass, level+1)
            else:
                traverse_for_methods(child, fn, klass, level+1)


with open('src/Foo.java', mode='r') as f:
    source = f.read()

tree = javalang.parse.parse(source)

def do_with_node(node, klass):
    # Do whatever you like for each method node (e.g. pushing them to a list outside)
    print(klass, node.name, node.position.line)

traverse_for_methods(tree, do_with_node)

(I borrowed the traverse logic from https://github.com/c2nes/javalang/issues/68#issuecomment-654793446. Thanks.)

fits-ikawa avatar Sep 15 '20 02:09 fits-ikawa

Actually, you cannot know the source class name. Because you can only iterate to the end of the tree: class->method->member ref. Here, when you have reached member ref leaf, you do not know where you are exactly in the tree. You can't also iterate over parents nodes.

But you can do the following trick:

import javalang

ast = javalang.parse.parse(open(r'D:\target\0001\ReconfigurableBase.java').read())
#  Get main class among all classes, declared in a file
main_class = list(ast.filter(javalang.tree.ClassDeclaration))[0][1]
for _, inner_class_ast in main_class.filter(javalang.tree.ClassDeclaration):
    if main_class.name != inner_class_ast.name:
        for method_inner in inner_class_ast.methods:
            print(f'class {inner_class_ast.name}, method name {method_inner.name}')

So, the method is to iterate over the other class declarations and remember class name from the outer loop. The original filname is ReconfigurableBase.txt The output will be the following:

class ReconfigurationThread, method name run

lyriccoder avatar Oct 12 '20 15:10 lyriccoder