Solve the problem of duplicate coding rules for custom codes

Hello Community
I wrote the following JAVA code to implement the rule to find duplicate blocks of code, but I have been unable to implement the function, I hope to get help from the good people! :sob: :sob:

@Rule(key = "AvoidRepeatCode")
public class AvoidRepeatCode extends IssuableSubscriptionVisitor {
    private Set<Integer> codeBlockHashes =new HashSet<>();

    private static final Logger LOGGER = Loggers.get(AvoidRepeatCode.class);
    @Override
    public List<Tree.Kind> nodesToVisit() {
        return Collections.singletonList(Tree.Kind.METHOD);
    }

    @Override
    public void visitNode(Tree tree) {
        MethodTree methodTree= (MethodTree) tree;
        BlockTree block = methodTree.block();
        if (block!=null)
        {

            String codeBlock = blockTreeToString(block);
            if (StringUtils.isNotBlank(codeBlock))
            {
                int hash = Objects.hash(codeBlock);
                if (codeBlockHashes.contains(hash))
                {
                    LOGGER.debug("Method Name {}", codeBlock);
                    reportIssue(block,"Repeat Code Block!");
                }
                else {
                    codeBlockHashes.add(hash);
                }
            }

        }
        super.visitNode(tree);
    }


    private String blockTreeToString(BlockTree block) {
        StringBuilder sb=new StringBuilder();
        for (StatementTree statementTree : block.body()) {
            sb.append(statementTree.toString());
        }

        return sb.toString();
    }
}

Hi,

Are you trying to develop this for Java?

 
Ann

1 Like

yes!!

I won’t be able to help you write this rule in itself but I’m curious to understand why can’t you just rely on the Duplication feature of Sonar to find duplicated blocks?
I may have wrongly understood what you are trying to achieve. Can you give an example of what you are trying to detect by providing one noncompliant code example?

First of all, it is a great honor to receive your reply.
I’d like to write some rules about code smells myself, such as the following example:
1.Two functions of the same class contain the same expression
class A {
public void method1() {
doSomething1
doSomething2
doSomething3
}
public void method2() {
doSomething1
doSomething2
doSomething4
}
}
Optimization method: using Extract Method (extract public function) to extract repeated code logic to form a public method.
class A {
public void method1() {
commonMethod();
doSomething3
}
public void method2() {
commonMethod();
doSomething4
}

public void commonMethod(){
   doSomething1
   doSomething2
}

}
I would like to write the rules for the example above and give advice on how to refactor.

Hey there Yaosheng,
so, I can see 2 different issues with you current implementation.
First, in the blockTreeToString method, you are using the statementTree.toString() to get the content of the statement, but the toString method there actually returns the string representation of the object, something like: “org.sonar.java.model.statement.ExpressionStatementTreeImpl@27467fb1” .
So you should find another way to get the content of the method body.
Second issue that I can see is that by comparing the hashed computed from the whole method body, you cannot differentiate between line and line, so that would mean that you could find an issue for these two methods:

  void foo() {
    System.out.println("hey there");
  }
  void boo() {
    System.out.println("hey there");
  }

But you would not find any issue on something like:

  void foo() {
    method1();
    method2();
    method3();
  }
  void boo() {
    method1();
    method2();
    method4();
  }

because by comparing the whole method bodies you cannot see that only 1 line is different, and so they would just resolve as different methods bodies, not raising an issue.

Let me know if this helps!