Java program dead code detection method based on abstract syntax tree and iteration
Patent Information
- Application Number
- CN202311248683.8
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2023-09-26
- Publication Date
- 2026-09-11
- Estimated Expiration
- 2043-09-26
AI Technical Summary
[0003]上述技术主要存在如下不足:(1)误报和漏报:死代码检测工具可能会产生误报,即实际可达的代码标记为死代码,或者漏报,即未能正确识死代码
[0024]1. This invention addresses the confusion surrounding determining whether a called method belongs to a subclass or superclass after method overriding by obtaining the complete path of the method and information such as the method's class or interface. Furthermore, by obtaining the method's parameter information, it resolves the issue of determining which overridden method is being called. In the dead method detection process, this invention incorporates the polymorphic characteristics of object-oriented programming, thereby improving the accuracy and extensibility of the method.
Smart Images

Figure CN117313088B_ABST
Abstract
Description
Technical Field
[0001] This invention belongs to the field of static code analysis and relates to the detection of code smells (dead code) in Java code. It mainly involves a method-level Java program dead code detection technology based on abstract syntax trees and iteration. Background Technology
[0002] Currently, there are various dead code detection technologies, some of the main ones being: (1) Static code analysis: Static code analysis detects code by analyzing the source code without actually executing the code. It can identify problems such as unused variables, unreachable code blocks, and inaccessible code. (2) Code coverage tools: Code coverage tools are used to determine whether a test suite covers all paths in the code. By analyzing coverage information during code execution, unexecuted code segments can be found. (3) Dynamic runtime analysis: Dynamic runtime analysis collects and analyzes data during actual code execution to detect dead code. This method can capture conditional branches and function call information during actual execution, thereby determining which code is reachable or unexecuted.
[0003] The above technologies have the following main shortcomings: (1) False alarms and false negatives: Dead code detection tools may generate false alarms, that is, actually reachable code is marked as dead code, or false negatives, that is, dead code is not correctly identified. This may lead developers to spend time and effort to deal with false warnings or ignore real dead code. (2) Complexity and performance overhead: Some dead code detection technologies require comprehensive analysis of the entire codebase, which may lead to long analysis time and a large amount of computing resources. This may become a problem, especially for large projects or complex codebases. (3) Limitations of dynamic runtime analysis: Dynamic runtime analysis requires actual running code, so it may not be able to capture all execution paths, especially under certain special conditions. This may result in dead code not being detected. (4) Dependencies and external calls: Modern software usually involves multiple modules and external dependencies. This makes dead code detection more complicated, because the reachability of code may be affected by external calls and dependencies. Current technologies may have certain limitations in dealing with this situation.
[0004] When focusing on Java programs and using static code analysis to detect dead code at the method level, these more specific problems also arise. (1) Multithreading: Java enables multithreaded programming. To execute a thread, the start() method must first be called to transition the thread from the "new" state to the "ready" state. Then, the run() method is executed to acquire CPU resources, thus transitioning the thread from the "ready" state to the "running" state. However, the run() method is a system scheduler and is transparent to the programmer. It is not explicitly called in the Java program, but it is indeed run. Therefore, the run() method in multithreaded programming cannot be considered a dead method in dead method detection. (2) Method overriding and overloading: Object-oriented programming involves the issues of method overriding and overloading. Overriding means that a subclass can override a method of its parent class. One overriding will result in two methods with the same name, parameters, and return type. In dead method detection, it is necessary to identify whether the subclass or the parent class method is being called. Overloading refers to the existence of multiple methods with the same name but different parameter lists within the same class. In dead method detection, it is necessary to determine which overloaded method was called based on the different parameter types. (3) Cross-file dead method identification: Most existing dead method detection tools based on static code analysis cannot solve the problem of cross-file dead method detection because of a lack of understanding of the project structure and limitations on the input format. (4) Complexity and performance overhead: Dead code detection requires scanning all the code in the project, which may lead to long analysis time and a large amount of computing resources consumed. This is especially true for large projects or complex code libraries. Summary of the Invention
[0005] In view of the above-mentioned problems in the existing technology, the technical problem to be solved by the present invention is: how to detect dead methods in projects with method overriding and overloading, how to detect dead methods in projects with multi-threaded programming, and how to detect dead methods in projects with cross-file method calls.
[0006] To solve the above technical problems, the present invention adopts the following technical solution: a Java program dead code detection method based on abstract syntax tree and iteration, comprising the following steps:
[0007] S101: Input a Java project in zip format, clean the project to obtain files containing only Java format, and retain the directory structure of the Java project.
[0008] S102: For the cleaned files, use the Java Parser tool to obtain the abstract syntax tree corresponding to each Java format file in the project.
[0009] S103: Traverse the nodes of the abstract syntax tree obtained in S102 to obtain a list of full pathnames of all methods in the Java project (fullMet ods); obtain a list of method names and imports of the class containing the method, stored using a hash map, represented as met odAndItsImports; obtain a method name and its location information, stored using a hash map, represented as met odAndItsPosition; obtain a class name and the types of variables in the class, stored using a hash map, represented as classAndArgumentType; obtain a method name and the methods called by that method, stored using a hash map, represented as met odCallsWit Callee; obtain a list of all entry methods (entryOfProgram).
[0010] S104: Define a list deadMet ods that is the same as the list of fullMet ods containing the complete pathnames of all methods to record dead methods.
[0011] S105: Define a stack S, initially pushing all methods in entryOfProgram onto the stack.
[0012] S106: Determine if stack S is empty. If stack S is not empty, execute S107. If stack S is empty, execute S112.
[0013] S107: Pop the top element of stack S, i.e., method m, and delete m from the deadMethods of the method.
[0014] S108: Get the import list imports of the class containing method m from metodAmdItsImports; get the setOfCallee of all methods called by method m from metodCallsWitCallee. This set can only get the method name of the called method, but cannot get the method name containing its full path.
[0015] S109: For all methods c in steOfCallee, iteratively check if c matches the method name f in fullMet ods. If they match, add c to the predefined set sameNames.
[0016] S110: Determine the number of elements in the set sameNames. If the number is equal to 1, push c onto stack S and delete c from the deadMethods method. If the number is greater than 1, execute S111.
[0017] S111: For all methods s in sameNames, compare them with all elements in the imports list obtained in S108. If s matches an element in the imports list, push s onto the stack S and delete s from the deadMethods of the method; if no element in the imports list matches s, execute S106.
[0018] S112: The iteration ends, and the dead method set deadMet ods is obtained.
[0019] Preferably, step S103 includes the following specific steps:
[0020] When retrieving fullMet ods, the Java Parser tool obtains the method name 'n', which lacks method path and parameter type information. By parsing the method nodes in the abstract syntax tree, the parameter type information is completed, thus obtaining the method name 'n' with parameter type information. arg Then, the Java project path is parsed to obtain the full path of the method, thus obtaining the method name with parameter type information and the full path. All This constitutes a complete list of pathnames for all methods in a Java project.
[0021] When retrieving metaCallsWit Callee, the Java Parser tool can only obtain the method name of the called method. It then searches for the type of the parameter in classAndArgementType and fills the parameter type information into the method name of the called method. Only in this way can it obtain a hash map where the key is the method name with path information and parameter type information, and the value is a set of called methods with parameter types.
[0022] Preferably, S109 includes the following steps when determining whether c and f match: first, determine whether the method names are the same; if they are the same, determine whether the number of parameters is equal; if they are equal, determine whether the parameter types are the same; if all the above determinations are successful, c and f match successfully; otherwise, if any determination fails, the match fails.
[0023] Compared with the prior art, the present invention has at least the following advantages:
[0024] 1. This invention addresses the confusion surrounding determining whether a called method belongs to a subclass or superclass after method overriding by obtaining the complete path of the method and information such as the method's class or interface. Furthermore, by obtaining the method's parameter information, it resolves the issue of determining which overridden method is being called. In the dead method detection process, this invention incorporates the polymorphic characteristics of object-oriented programming, thereby improving the accuracy and extensibility of the method.
[0025] 2. This invention identifies information about classes or interfaces used in multithreaded programming to set rules for the `run()` method, ensuring it is always called in multithreaded programming. This solves the problem of implicit calls to `run()` in multithreaded scenarios leading to methods being incorrectly identified as dead methods. Currently, Java multithreading is widely used, especially in high-concurrency scenarios, so resolving the implicit call identification issue improves the accuracy of dead code detection. This invention obtains the import list of the class containing the method and uses it as an interface for inter-file communication, thus obtaining cross-file method calls and constructing a more complete method call graph. Solving the cross-file call graph construction improves the accuracy of dead method detection. Furthermore, this invention offers good timeliness. Attached Figure Description
[0026] Figure 1 This is an example of Java multithreaded programming.
[0027] Figure 2 This is an example of overriding and overloading.
[0028] Figure 3 For comparison of experimental results (based on accuracy, recall, and F1 score).
[0029] Figure 4 This is the flow chart of the method of the present invention. Detailed Implementation
[0030] The present invention will now be described in further detail.
[0031] This invention uses the open-source tool Java Parser to obtain an abstract syntax tree, extracts method call information and file reference information from the nodes of the abstract syntax tree, and uses this information to obtain the call relationship between methods, thereby iteratively determining dead methods.
[0032] A method for detecting dead code in Java programs based on abstract syntax trees and iteration includes the following steps:
[0033] S101: Input a Java project in zip format, clean the project to obtain files containing only Java format, and retain the directory structure of the Java project;
[0034] S102: For the cleaned files (the Java project here only contains Java format files), use the JavaParser tool to obtain the abstract syntax tree corresponding to each Java format file in the project;
[0035] S103: Traverse the nodes of the abstract syntax tree obtained in S102 to obtain a list of full path names of all methods in the Java project (fullMethods); obtain a list of method names and the imports of the class containing the method, stored using a hash map, represented as metadAndItsImports; obtain a method name and the method's location information, stored using a hash map, represented as metadAndItsPosition; obtain a class name and the types of variables in the class, stored using a hash map, represented as classAndArgumentType; obtain a method name and the methods called by that method, stored using a hash map, represented as metadCallsWitCall; obtain a list of all entry methods (i.e., the main method) (entryOfProgram);
[0036] S104: Define a list deadMet ods that is the same as the list of fullMet ods of all methods' complete pathnames to record dead methods;
[0037] S105: Define a stack S, initially pushing all methods in entryOfProgram onto the stack;
[0038] S106: Determine if stack S is empty. If stack S is not empty, execute S107. If stack S is empty, execute S112.
[0039] S107: Pop the top element of stack S, i.e., method m, and delete m from the deadMetods of the method;
[0040] S108: Get the import list imports of the class containing method m from metadAndItsImports; get the setOfCallee of all methods called by method m from metadCallsWitCallee. This set can only get the method name of the called method, but cannot get the method name containing its full path.
[0041] S109: For all methods c in setOfCallee, iteratively check whether c matches the method name f in fullMet ods. If they match, add c to the predefined collection sameNames.
[0042] S110: Determine the number of elements in the set sameNames. If the number is equal to 1, push c onto stack S and delete c from the deadMethods method. If the number is greater than 1, execute S111.
[0043] S111: For all methods s in sameNames, compare them with all elements in the imports list obtained in S108. If s matches an element in the imports list, push s onto the stack S and delete s from the deadMethods of the method; if no element in the imports list matches s, execute S106.
[0044] S112: Iteration ends, and the dead method set deadMethods is obtained;
[0045] Specifically, step S103 includes the following steps:
[0046] When retrieving fullMet ods, the Java Parser tool obtains the method name 'n', which lacks method path and parameter type information. By parsing the method nodes in the abstract syntax tree, the parameter type information is completed, thus obtaining the method name 'n' with parameter type information. arg Then, the Java project path is parsed to obtain the full path of the method, thus obtaining the method name with parameter type information and the full path. All This constitutes a complete list of pathnames for all methods in a Java project.
[0047] When retrieving the metaCallsWit Callee, the Java Parser tool can only obtain the method name of the called method. It needs to parse the method nodes in the abstract syntax tree to obtain the actual parameters. However, we can only obtain the actual parameters, not their types. Therefore, we need to look up the parameter types in `classAndArgementType` and then append the parameter type information to the method name of the called method. Only then can we obtain a hash map where the key is the method name with path and parameter type information, and the value is a set of called methods with parameter types.
[0048] Specifically, in S109, the method c in setOfCallee only contains the method name and method parameters, while f contains parameter type information and a complete path. The process of determining whether c and f match includes the following steps: First, determine whether the method names are consistent. If they are consistent, then determine whether the number of parameters is equal. If they are equal, then determine whether the parameter types are consistent. If all the above determinations are successful, then c and f match successfully. Otherwise, if any determination fails, the match fails.
[0049] experiment:
[0050] (1) Implicit calls to the run() method in multithreaded programming
[0051] When programming with multiple threads in Java, we can call the `start()` method to transition a thread from a "new" state to a "ready" state. The system then automatically schedules the execution of the thread's `run()` method, transitioning the thread from the "ready" state to the "running" state to acquire CPU resources. Although the `run()` method is not explicitly called in the Java program, it is indeed scheduled and executed by the system. Therefore, when performing deadlock detection, we cannot treat the `run()` method in multithreaded programming as a dead method. In this invention, we actively mark the `run()` method in classes that inherit from the `Thread` class or implement the `Runnable` interface as a live method, thereby resolving the problem of implicit calls to the `run()` method.
[0052] (2) Detection of dead methods in projects with method overloading and overriding
[0053] In object-oriented programming, the issues of method overriding and overloading arise. Overriding refers to a subclass overriding a method of its parent class, resulting in two identical methods with the same name, parameters, and return type. We need to identify whether the subclass's method or the parent class's method is being called. Overloading, on the other hand, refers to multiple methods within the same class having the same name but different parameter lists. When calling these methods, we need to determine which overloaded method is being invoked based on the different parameter types. To address the overriding problem, this invention proposes using the fully qualified method name (or pathname) to represent the method. For example... Figure 2 The parent class `Animal` contains the method `*.Animal.move()`, and the subclass `Dog` contains the method `*.Dog.move()`. This unique representation allows for the identification of methods in the parent class and their corresponding overridden methods in the subclass. Regarding the issue of overloading, the solution of this invention is to use the method's parameter information to uniquely identify overloaded methods. For example, `*.Dog.move(int)` and `*.Dog.move(Integer)` in the `Dog` class.
[0054] (3) Detection of dead methods called across files
[0055] Due to a lack of understanding of project structure and input format, as well as other limitations, most existing static code analysis-based dead method detection tools cannot effectively solve the problem of detecting dead methods across files. To address this issue, the solution of this invention is to use the imports list of each Java file as its interface for communication with other files. When a method belonging to another file is identified, its affiliation is determined through the imports list.
[0056] (4) Complexity and performance overhead
[0057] Dead code detection techniques require comprehensive analysis of the entire codebase, which can lead to lengthy analysis times and significant computational resource consumption, especially for large projects or complex codebases. The core algorithm of this invention has a time complexity of O(|fullMethods|), where fullMethods is the collection of all methods in a Java project. This provides high timeliness when solving practical problems.
[0058] 2. Experiment
[0059] In our experiment, we need to evaluate the following properties:
[0060] Correctness: Reflects whether a method considered a dead method is indeed a dead method;
[0061] Completeness: Reflects whether a set of methods considered dead methods is complete relative to the actual total number of dead methods;
[0062] Accuracy: Reflects correctness and completeness.
[0063] The evaluation metrics are precision, recall, and F1-score. Precision is based on a formula. Recall is calculated based on the formula The F1 score is calculated as follows: TP (True Positives) is the set of methods correctly detected as dead methods; FP (False Positives) is the set of methods incorrectly detected as dead methods; and FN (False Negatives) is the set of dead methods that cannot be detected as dead methods. The F1 score is based on the formula... Pre and Re are abbreviations for Precision and Recall, respectively, representing the trade-off between the correctness and completeness of the results. Precision, Recall, and F1-score are all within the range [0,1], with 1 being the optimal value. Higher Precision indicates more accurate results from the dead method detection; higher Recall indicates more complete results from the dead method detection; and higher F1-score indicates more precise results from the dead method detection.
[0064] The invention selected two Java projects (PROJECT1 and PROJECT2) as experimental subjects. As shown in Table 1, PROJECT1 has a total of 2472 lines of code and contains 236 methods. Through manual identification, it is known that PROJECT1 contains 66 dead methods. PROJECT2 has a total of 7936 lines of code and contains 671 methods. Through manual identification, it is known that PROJECT2 contains 208 dead methods.
[0065] Table 1
[0066]
[0067] To verify whether the present invention effectively solves the above problems, we defined three rules for ablation experiments:
[0068] Rule 1: It can solve the detection of dead methods in projects where there are method overriding and overloading;
[0069] Rule 2: It can solve the problem of detecting dead methods in projects with multi-threaded programming;
[0070] Rule 3: A rule that can resolve dead method detection in projects with cross-file method calls;
[0071] like Figure 3As shown, for PROJECT1, in the experimental results with only Rule1 and with both Rule1 and Rule2, the precision and F1 score were relatively low. After adding Rule3, both the precision and F1 score reached over 90%. Similarly, for PROJECT2, after adding Rule1, Rule2, and Rule3, both the precision and F1 score were significantly improved. Regardless of whether it was PROJECT1 or PROJECT2, the recall rate was over 90%, indicating that this invention performs relatively well in terms of the completeness of dead method detection. It is worth mentioning that this invention also performs well in terms of timeliness; for PROJECT1 and PROJECT2, the detection time for dead methods is 1.294s and 2.836s, respectively.
[0072] In summary, this invention proposes a method for detecting dead methods in Java static code based on an abstract syntax tree. It can solve the problems of detecting dead methods in projects with method overriding and overloading, projects with multithreaded programming, and projects with cross-file method calls. It also boasts good timeliness.
[0073] Finally, it should be noted that the above embodiments are only used to illustrate the technical solutions of the present invention and are not intended to limit it. Although the present invention has been described in detail with reference to preferred embodiments, those skilled in the art should understand that modifications or equivalent substitutions can be made to the technical solutions of the present invention without departing from the spirit and scope of the technical solutions of the present invention, and all such modifications or substitutions should be covered within the scope of the claims of the present invention.
Claims
1. A Java program dead code detection method based on abstract syntax tree and iteration, characterized in that, Includes the following steps: S101: Input a Java project in zip format, clean the project to obtain files containing only Java format, and retain the directory structure of the Java project; S102: For the cleaned files, use the Java Parser tool to obtain the abstract syntax tree corresponding to each Java format file in the project; S103: Traverse the nodes of the abstract syntax tree obtained in S102 to obtain a list of full pathnames of all methods in the Java project (fullMethods); obtain a list of method names and imports of the class containing the method, stored using a hash map, represented as metodAndItsImports; obtain a method name and its location information, stored using a hash map, represented as metodAndItsPosition; obtain a class name and the types of variables in the class, stored using a hash map, represented as classAndArgumentType; obtain a method name and the methods called by that method, stored using a hash map, represented as metodCallsWitCallee; obtain a list of all entry methods (entryOfProgram); S104: Define a list deadMet ods that is the same as the list of fullMet ods of all methods' complete pathnames to record dead methods; S105: Define a stack S, initially pushing all methods in entryOfProgram onto the stack; S106: Determine if stack S is empty. If stack S is not empty, execute S107. If stack S is empty, execute S112. S107: Pop the top element of stack S, i.e., method m, and delete m from the deadMethods of the method; S108: Retrieve the import list of the class containing method m from metadAndItsImports; Get the setOfCallee from metodCallsWitCallee. This set can only get the method name of the called method, but not the method name containing its full path. S109: For all methods c in setOfCallee, iteratively check whether c matches the method name f in fullMet ods. If they match, add c to the predefined collection sameNames. S110: Determine the number of elements in the set sameNames. If the number is equal to 1, push c onto stack S and delete c from the deadMethods method. If the number is greater than 1, execute S111. S111: For all methods s in sameNames, compare them with all elements in the imports list obtained in S108. If s matches an element in the imports list, push s onto the stack S and delete s from the deadMethods of the method; if no element in the imports list matches s, execute S106. S112: The iteration ends, and the dead method set deadMet ods is obtained.
2. The Java program dead code detection method based on abstract syntax tree and iteration as described in claim 1, characterized in that: S103 includes the following specific steps: When retrieving fullMet ods, the Java Parser tool obtains the method name 'n', which is a method name without method path and parameter type information. By parsing the information of the method nodes in the abstract syntax tree, the parameter type information of the method is completed, thus obtaining the method name 'n' with parameter type information. arg Then, the Java project path is parsed to obtain the full path of the method, thus obtaining the method name with parameter type information and the full path. All This constitutes a complete list of pathnames for all methods in a Java project. When retrieving metaCallsWit Callee, the Java Parser tool can only obtain the method name of the called method. It then searches for the type of the parameter in classAndArgementType and fills the parameter type information into the method name of the called method. Only in this way can it obtain a hash map where the key is the method name with path information and parameter type information, and the value is a set of called methods with parameter types.
3. The Java program dead code detection method based on abstract syntax tree and iteration as described in claim 2, characterized in that: The steps in S109 for determining whether c and f match are as follows: First, determine whether the method names are the same. If they are the same, determine whether the number of parameters is equal. If they are equal, determine whether the parameter types are the same. If all the above determinations are successful, c and f match successfully. Otherwise, if any determination fails, the match fails.
Citation Information
Patent Citations
Method for detecting redundant code defects based on static analysis
CN102231134A
Software code processing method and electronic equipment
CN114003868A