diff --git a/cldk/analysis/java/codeanalyzer/codeanalyzer.py b/cldk/analysis/java/codeanalyzer/codeanalyzer.py index fbe56f0f..fd4ff9d5 100644 --- a/cldk/analysis/java/codeanalyzer/codeanalyzer.py +++ b/cldk/analysis/java/codeanalyzer/codeanalyzer.py @@ -28,26 +28,51 @@ class JCodeanalyzer: - """A class for building the application view of a Java application using Codeanalyzer. - - Parameters - ---------- - project_dir : str or Path - The path to the root of the Java project. - analysis_json_path : str or Path or None - The path to save the intermediate codeanalysis ouputs. If None, we'll read from the pipe. - sdg : bool - If True, the system dependency graph will be generated with a more indepth analysis. Default is False. - eager_analysis : bool - If True, the analysis will be done eagerly, i.e., a new analysis will be done every time the object is created. - Default is False. - use_graalvm_binary : bool - If True, the codeanalyzer binary from GraalVM will be used. By default, the codeanalyzer jar from the latest - release on GitHub will be used. - Methods - ------- - _init_codeanalyzer(project_dir, analysis_json_path) - Initializes the codeanalyzer database. + """ A class for building the application view of a Java application using Codeanalyzer. + + Args: + project_dir (str or Path): The path to the root of the Java project. + source_code (str, optional): The source code of a single Java file to analyze. Defaults to None. + analysis_backend_path (str or Path, optional): The path to the analysis backend. Defaults to None. + analysis_json_path (str or Path, optional): The path to save the intermediate code analysis outputs. + If None, the analysis will be read from the pipe. + analysis_level (str): The level of analysis ('symbol_table' or 'call_graph'). + use_graalvm_binary (bool): If True, the GraalVM binary will be used instead of the codeanalyzer jar. + eager_analysis (bool): If True, the analysis will be performed every time the object is created. + + Methods: + _init_codeanalyzer(analysis_level=1): + Initializes the codeanalyzer database. + + _download_or_update_code_analyzer(filepath: Path) -> str: + Downloads the codeanalyzer jar from the latest release on GitHub. + + _get_application() -> JApplication: + Returns the application view of the Java code. + + _get_codeanalyzer_exec() -> List[str]: + Returns the executable command for codeanalyzer. + + _codeanalyzer_single_file() -> JApplication: + Invokes codeanalyzer in a single file mode. + + get_symbol_table() -> Dict[str, JCompilationUnit]: + Returns the symbol table of the Java code. + + get_application_view() -> JApplication: + Returns the application view of the Java code. + + get_system_dependency_graph() -> list[JGraphEdges]: + Runs the codeanalyzer to get the system dependency graph. + + _generate_call_graph(using_symbol_table: bool) -> DiGraph: + Generates the call graph of the Java code. + + get_class_hierarchy() -> DiGraph: + Returns the class hierarchy of the Java code. + + get_call_graph() -> DiGraph: + Returns the call graph of the Java code. """ def __init__( @@ -79,18 +104,13 @@ def __init__( @staticmethod def _download_or_update_code_analyzer(filepath: Path) -> str: - """ - Downloads the codeanalyzer jar from the latest release on GitHub. + """ Downloads the codeanalyzer jar from the latest release on GitHub. - Parameters - ---------- - filepath : str - The path to save the codeanalyzer jar. + Args: + filepath (Path): The path to save the codeanalyzer jar. - Returns - ------- - str - The path to the downloaded codeanalyzer jar file. + Returns: + str: The path to the downloaded codeanalyzer jar file. """ url = "https://api.github.com/repos/IBM/codenet-minerva-code-analyzer/releases/latest" response = requests.get(url) @@ -139,33 +159,25 @@ def _download_or_update_code_analyzer(filepath: Path) -> str: raise Exception(f"Failed to fetch release warn: {response.status_code} {response.text}") def _get_application(self) -> JApplication: - """ - Returns the application view of the Java code. + """ Returns the application view of the Java code. - Returns - ------- - JApplication - The application view of the Java code. + Returns: + JApplication: The application view of the Java code. """ if self.application is None: self.application = self._init_codeanalyzer() return self.application def _get_codeanalyzer_exec(self) -> List[str]: - """ - Returns the executable command for codeanalyzer. + """ Returns the executable command for codeanalyzer. - Returns - ------- - List[str] - The executable command for codeanalyzer. - - Notes - ----- - Some selection criteria for the codeanalyzer analysis_backend: - 1. If the use_graalvm_binary flag is set, the codeanalyzer binary from GraalVM will be used. - 2. If the analysis_backend_path is provided by the user, the codeanalyzer.jar from the analysis_backend_path will be used. - 3. If the analysis_backend_path is not provided, the latest codeanalyzer.jar from the GitHub release will be first downloaded. + Returns: + List[str]: The executable command for codeanalyzer. + + Notes: + - If the use_graalvm_binary flag is set, the codeanalyzer binary from GraalVM will be used. + - If the analysis_backend_path is provided, the codeanalyzer jar from that path will be used. + - If not provided, the latest codeanalyzer jar from GitHub will be downloaded. """ if self.use_graalvm_binary: @@ -197,17 +209,17 @@ def init_japplication(self, data: str) -> JApplication: return JApplication(**json.loads(data)) def _init_codeanalyzer(self, analysis_level=1) -> JApplication: - """Initializes the Codeanalyzer. - Returns - ------- - JApplication - The application view of the Java code with the analysis results. - Raises - ------ - CodeanalyzerExecutionException - If there is an error running Codeanalyzer. - """ + """ Initializes the Codeanalyzer. + + Args: + analysis_level (int): The level of analysis to be performed (1 for symbol table, 2 for call graph). + Returns: + JApplication: The application view of the Java code with the analysis results. + + Raises: + CodeanalyzerExecutionException: If there is an error running Codeanalyzer. + """ codeanalyzer_exec = self._get_codeanalyzer_exec() codeanalyzer_args = '' if self.analysis_json_path is None: @@ -276,13 +288,10 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: return JApplication(**data) def _codeanalyzer_single_file(self): - """ - Invokes codeanalyzer in a single file mode. + """ Invokes codeanalyzer in a single file mode. - Returns - ------- - JApplication - The application view of the Java code with the analysis results. + Returns: + JApplication: The application view of the Java code with the analysis results. """ codeanalyzer_exec = self._get_codeanalyzer_exec() codeanalyzer_args = ["--source-analysis", self.source_code] @@ -299,26 +308,20 @@ def _codeanalyzer_single_file(self): raise CodeanalyzerExecutionException(str(e)) from e def get_symbol_table(self) -> Dict[str, JCompilationUnit]: - """ - Returns the symbol table of the Java code. + """ Returns the symbol table of the Java code. - Returns - ------- - Dict[str, JCompilationUnit] - The symbol table of the Java code. + Returns: + Dict[str, JCompilationUnit]: The symbol table of the Java code. """ if self.application is None: self.application = self._init_codeanalyzer() return self.application.symbol_table def get_application_view(self) -> JApplication: - """ - Returns the application view of the Java code. + """ Returns the application view of the Java code. Returns: - -------- - JApplication - The application view of the Java code. + JApplication: The application view of the Java code. """ if self.source_code: # This branch is triggered when a single file is being analyzed. @@ -330,13 +333,10 @@ def get_application_view(self) -> JApplication: return self.application def get_system_dependency_graph(self) -> list[JGraphEdges]: - """ - Run the codeanalyzer to get the system dependency graph. + """ Runs the codeanalyzer to get the system dependency graph. - Returns - ------- - list[JGraphEdges] - The system dependency graph. + Returns: + list[JGraphEdges]: The system dependency graph. """ if self.application.system_dependency_graph is None: self.application = self._init_codeanalyzer(analysis_level=2) @@ -344,13 +344,13 @@ def get_system_dependency_graph(self) -> list[JGraphEdges]: return self.application.system_dependency_graph def _generate_call_graph(self, using_symbol_table) -> DiGraph: - """ - Generates the call graph of the Java code. + """ Generates the call graph of the Java code. + + Args: + using_symbol_table (bool): Whether to use the symbol table for generating the call graph. Returns: - -------- - DiGraph - The call graph of the Java code. + DiGraph: The call graph of the Java code. """ cg = nx.DiGraph() if using_symbol_table: @@ -384,23 +384,17 @@ def _generate_call_graph(self, using_symbol_table) -> DiGraph: return cg def get_class_hierarchy(self) -> DiGraph: - """ - Returns the class hierarchy of the Java code. + """ Returns the class hierarchy of the Java code. Returns: - -------- - DiGraph - The class hierarchy of the Java code. + DiGraph: The class hierarchy of the Java code. """ def get_call_graph(self) -> DiGraph: - """ - Get call graph of the Java code. + """ Returns the call graph of the Java code. Returns: - -------- - DiGraph - The call graph of the Java code. + DiGraph: The call graph of the Java code. """ if self.analysis_level == "symbol_table": self.call_graph = self._generate_call_graph(using_symbol_table=True) @@ -409,9 +403,11 @@ def get_call_graph(self) -> DiGraph: return self.call_graph def get_call_graph_json(self) -> str: - """ - serialize callgraph to json - """ + """ Get call graph in serialized json format. + + Returns: + str: Call graph in json. + """ callgraph_list = [] edges = list(self.call_graph.edges.data("calling_lines")) for edge in edges: @@ -427,13 +423,15 @@ def get_call_graph_json(self) -> str: return json.dumps(callgraph_list) def get_all_callers(self, target_class_name: str, target_method_signature: str, using_symbol_table: bool) -> Dict: - """ - Get all the caller details for a given java method. + """ Get all the caller details for a given Java method. + + Args: + target_class_name (str): The qualified class name of the target method. + target_method_signature (str): The signature of the target method. + using_symbol_table (bool): Whether to use the symbol table to generate the call graph. Returns: - -------- - Dict - Caller details in a dictionary. + Dict: A dictionary containing caller details. """ caller_detail_dict = {} @@ -465,13 +463,15 @@ def get_all_callers(self, target_class_name: str, target_method_signature: str, return caller_detail_dict def get_all_callees(self, source_class_name: str, source_method_signature: str, using_symbol_table: bool) -> Dict: - """ - Get all the callee details for a given java method. + """ Get all the callee details for a given Java method. + + Args: + source_class_name (str): The qualified class name of the source method. + source_method_signature (str): The signature of the source method. + using_symbol_table (bool): Whether to use the symbol table to generate the call graph. Returns: - -------- - Dict - Callee details in a dictionary. + Dict: A dictionary containing callee details. """ callee_detail_dict = {} call_graph = None @@ -495,15 +495,11 @@ def get_all_callees(self, source_class_name: str, source_method_signature: str, return callee_detail_dict def get_all_methods_in_application(self) -> Dict[str, Dict[str, JCallable]]: - """ - Returns a dictionary of all methods in the Java code with - qualified class name as key and dictionary of methods in that class - as value + """ Returns a dictionary of all methods in the Java code with qualified class name as the key + and a dictionary of methods in that class as the value. Returns: - -------- - Dict[str, Dict[str, JCallable]]: - A dictionary of dictionaries of all methods in the Java code. + Dict[str, Dict[str, JCallable]]: A dictionary of dictionaries of all methods in the Java code. """ class_method_dict = {} @@ -513,13 +509,10 @@ def get_all_methods_in_application(self) -> Dict[str, Dict[str, JCallable]]: return class_method_dict def get_all_classes(self) -> Dict[str, JType]: - """ - Returns a dictionary of all classes in the Java code. + """ Returns a dictionary of all classes in the Java code. Returns: - -------- - Dict[str, JType] - A dict of all classes in the Java code, with qualified class names as keys + Dict[str, JType]: A dictionary of all classes in the Java code, with qualified class names as keys. """ class_dict = {} @@ -529,39 +522,28 @@ def get_all_classes(self) -> Dict[str, JType]: return class_dict def get_class(self, qualified_class_name) -> JType: - """ - Returns a class given qualified class name. + """ Returns a class given the qualified class name. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - JClassOrInterface - A class for the given qualified class name. - """ + JType: A class for the given qualified class name. + """ symtab = self.get_symbol_table() for _, v in symtab.items(): if qualified_class_name in v.type_declarations.keys(): return v.type_declarations.get(qualified_class_name) def get_method(self, qualified_class_name, method_signature) -> JCallable: - """ - Returns a method given qualified method name. + """ Returns a method given the qualified method name. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. - method_signature : str - The signature of the method. + Args: + qualified_class_name (str): The qualified name of the class. + method_signature (str): The signature of the method. Returns: - -------- - JCallable - A method for the given qualified method name. + JCallable: A method for the given qualified method name. """ symtab = self.get_symbol_table() for v in symtab.values(): @@ -572,18 +554,13 @@ def get_method(self, qualified_class_name, method_signature) -> JCallable: return ci.callable_declarations[cd] def get_java_file(self, qualified_class_name) -> str: - """ - Returns a class given qualified class name. + """ Returns java file name given the qualified class name. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - str - Java file name containing the given qualified class. + str: Java file name containing the given qualified class. """ symtab = self.get_symbol_table() for k, v in symtab.items(): @@ -591,18 +568,13 @@ def get_java_file(self, qualified_class_name) -> str: return k def get_java_compilation_unit(self, file_path: str) -> JCompilationUnit: - """ - Given the path of a Java source file, returns the compilation unit object from the symbol table. + """ Given the path of a Java source file, returns the compilation unit object from the symbol table. - Parameters - ---------- - file_path : str - Absolute path to Java source file + Args: + file_path (str): Absolute path to the Java source file. - Returns - ------- - JCompilationUnit - Compilation unit object for Java source file + Returns: + JCompilationUnit: Compilation unit object for the Java source file. """ if self.application is None: @@ -610,18 +582,13 @@ def get_java_compilation_unit(self, file_path: str) -> JCompilationUnit: return self.application.symbol_table[file_path] def get_all_methods_in_class(self, qualified_class_name) -> Dict[str, JCallable]: - """ - Returns a dictionary of all methods in the given class. + """ Returns a dictionary of all methods in the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - Dict[str, JCallable] - A dictionary of all methods in the given class. + Dict[str, JCallable]: A dictionary of all methods in the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -630,18 +597,13 @@ def get_all_methods_in_class(self, qualified_class_name) -> Dict[str, JCallable] return methods def get_all_constructors(self, qualified_class_name) -> Dict[str, JCallable]: - """ - Returns a dictionary of all constructors of the given class. + """ Returns a dictionary of all constructors of the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - Dict[str, JCallable] - A dictionary of all constructors of the given class. + Dict[str, JCallable]: A dictionary of all constructors of the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -650,16 +612,15 @@ def get_all_constructors(self, qualified_class_name) -> Dict[str, JCallable]: return constructors def get_all_sub_classes(self, qualified_class_name) -> Dict[str, JType]: - """ - Returns a dictionary of all sub-classes of the given class - Parameters - ---------- - qualified_class_name + """ Returns a dictionary of all sub-classes of the given class. - Returns - ------- - Dict[str, JType]: A dictionary of all sub-classes of the given class, and class details + Args: + qualified_class_name (str): The qualified name of the class. + + Returns: + Dict[str, JType]: A dictionary of all sub-classes of the given class, and class details. """ + all_classes = self.get_all_classes() sub_classes = {} for cls in all_classes: @@ -669,18 +630,13 @@ def get_all_sub_classes(self, qualified_class_name) -> Dict[str, JType]: return sub_classes def get_all_fields(self, qualified_class_name) -> List[JField]: - """ - Returns a list of all fields of the given class. + """ Returns a list of all fields of the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - List[JField] - A list of all fields of the given class. + List[JField]: A list of all fields of the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -689,18 +645,13 @@ def get_all_fields(self, qualified_class_name) -> List[JField]: return ci.field_declarations def get_all_nested_classes(self, qualified_class_name) -> List[JType]: - """ - Returns a list of all nested classes for the given class. + """ Returns a list of all nested classes for the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - List[JType] - A list of nested classes for the given class. + List[JType]: A list of nested classes for the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -710,18 +661,13 @@ def get_all_nested_classes(self, qualified_class_name) -> List[JType]: return [self.get_class(c) for c in nested_classes] # Assuming qualified nested class names def get_extended_classes(self, qualified_class_name) -> List[str]: - """ - Returns a list of all extended classes for the given class. + """ Returns a list of all extended classes for the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - List[str] - A list of extended classes for the given class. + List[str]: A list of extended classes for the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -730,18 +676,13 @@ def get_extended_classes(self, qualified_class_name) -> List[str]: return ci.extends_list def get_implemented_interfaces(self, qualified_class_name) -> List[str]: - """ - Returns a list of all implemented interfaces for the given class. + """ Returns a list of all implemented interfaces for the given class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. Returns: - -------- - List[JType] - A list of implemented interfaces for the given class. + List[str]: A list of implemented interfaces for the given class. """ ci = self.get_class(qualified_class_name) if ci is None: @@ -752,8 +693,7 @@ def get_implemented_interfaces(self, qualified_class_name) -> List[str]: def get_class_call_graph_using_symbol_table(self, qualified_class_name: str, method_signature: str | None = None) -> ( List)[Tuple[JMethodDetail, JMethodDetail]]: - """ - Returns call graph using symbol table. The analysis will not be + """ Returns call graph using symbol table. The analysis will not be complete as symbol table has known limitation of resolving types Args: qualified_class_name: qualified name of the class @@ -778,9 +718,8 @@ def get_class_call_graph_using_symbol_table(self, qualified_class_name: str, def __call_graph_using_symbol_table(self, qualified_class_name: str, - method_signature: str, is_target_method: bool = False) -> DiGraph: - """ - Generate call graph using symbol table + method_signature: str, is_target_method: bool = False)-> DiGraph: + """ Generate call graph using symbol table Args: qualified_class_name: qualified class name method_signature: method signature @@ -826,8 +765,7 @@ def __raw_call_graph_using_symbol_table_target_method(self, target_class_name: str, target_method_signature: str, cg=None) -> list[JGraphEdgesST]: - """ - Generates call graph using symbol table information given the target method and target class + """ Generates call graph using symbol table information given the target method and target class Args: qualified_class_name: qualified class name method_signature: source method signature @@ -900,15 +838,15 @@ def __raw_call_graph_using_symbol_table(self, qualified_class_name: str, method_signature: str, cg=None) -> list[JGraphEdgesST]: - """ - Generates call graph using symbol table information + """ Generates a call graph using symbol table information. + Args: - qualified_class_name: qualified class name - method_signature: source method signature - cg: call graph + qualified_class_name (str): The qualified class name. + method_signature (str): The source method signature. + cg (list[JGraphEdgesST], optional): Existing call graph edges. Defaults to None. Returns: - list[JGraphEdgesST]: list of call edges + list[JGraphEdgesST]: A list of call edges. """ if cg is None: cg = [] @@ -979,28 +917,18 @@ def __raw_call_graph_using_symbol_table(self, def get_class_call_graph(self, qualified_class_name: str, method_name: str | None = None) -> List[ Tuple[JMethodDetail, JMethodDetail]]: - """ - A call graph for a given class and (optionally) filtered by a given method. + """ Generates a call graph for a given class and (optionally) filters by a given method. - Parameters - ---------- - qualified_class_name : str - The qualified name of the class. - method_name : str, optional - The name of the method in the class. - - Returns - ------- - List[Tuple[JMethodDetail, JMethodDetail]] - An edge list of the call graph for the given class and method. - - Notes - ----- - The class name must be fully qualified, e.g., "org.example.MyClass" and not "MyClass". - - Likewise, the + Args: + qualified_class_name (str): The qualified name of the class. + method_name (str, optional): The name of the method in the class. + Returns: + List[Tuple[JMethodDetail, JMethodDetail]]: An edge list of the call graph + for the given class and method. + Notes: + The class name must be fully qualified, e.g., "org.example.MyClass" and not "MyClass". """ # If the method name is not provided, we'll get the call graph for the entire class. @@ -1019,15 +947,12 @@ def get_class_call_graph(self, qualified_class_name: str, method_name: str | Non return graph_edges def get_all_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]: - """ - Returns a dictionary of all entry point methods in the Java code with - qualified class name as key and dictionary of methods in that class - as value + """ Returns a dictionary of all entry point methods in the Java code with + qualified class name as the key and a dictionary of methods in that class as the value. Returns: - -------- - Dict[str, Dict[str, JCallable]]: - A dictionary of dictionaries of entry point methods in the Java code. + Dict[str, Dict[str, JCallable]]: A dictionary of dictionaries of entry point + methods in the Java code. """ class_method_dict = {} @@ -1039,13 +964,11 @@ def get_all_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]: return class_method_dict def get_all_entry_point_classes(self) -> Dict[str, JType]: - """ - Returns a dictionary of all entry point classes in the Java code. + """ Returns a dictionary of all entry point classes in the Java code. Returns: - -------- - Dict[str, JType] - A dict of all entry point classes in the Java code, with qualified class names as keys + Dict[str, JType]: A dictionary of all entry point classes in the Java code, + with qualified class names as keys. """ class_dict = {} diff --git a/cldk/analysis/java/java.py b/cldk/analysis/java/java.py index f743d6b6..a37a895d 100644 --- a/cldk/analysis/java/java.py +++ b/cldk/analysis/java/java.py @@ -26,35 +26,27 @@ def __init__( use_graalvm_binary: bool, eager_analysis: bool, ) -> None: - """ - Parameters - ---------- - project_dir : str - The directory path of the project. - analysis_backend : str, optional - The analysis_backend used for analysis, defaults to "codeql". - analysis_backend_path : str, optional - The path to the analysis_backend, defaults to None and in the case of codeql, it is assumed that the cli is installed and - available in the PATH. In the case of codeanalyzer the codeanalyzer.jar is downloaded from the lastest release. - analysis_json_path : str or Path, optional - The path save the to the analysis database (analysis.json), defaults to None. If None, the analysis database is - not persisted. - use_graalvm_binary : bool, optional - A flag indicating whether to use the GraalVM binary for SDG analysis, defaults to False. If False, the default - Java binary is used and one needs to have Java 17 or higher installed. - eager_analysis : bool, optional - A flag indicating whether to perform eager analysis, defaults to False. If True, the analysis is performed - eagerly. That is, the analysis.json file is created during analysis every time even if it already exists. - target_files: str, optional - The target files for which the analysis will run or get modified. Currently, this feature only supported - with symbol table analysis. In the future, we will add this feature to other analysis levels. - Attributes - ---------- - analysis_backend : JCodeQL | JApplication - The analysis_backend used for analysis. - application : JApplication - The application view of the Java code. - """ + + """ Initialization method for Java Analysis backend. + + Args: + project_dir (str | Path | None): The directory path of the project. + source_code (str | None): Java file for single source file analysis. + analysis_backend (str): The analysis_backend used for analysis. Currently 'codeql' and 'codeanalyzer' are supported. + analysis_backend_path (str | None): The path to the analysis_backend, defaults to None and in the case of codeql, it is assumed that the cli is installed and available in the PATH. In the case of codeanalyzer the codeanalyzer.jar is downloaded from the lastest release. + analysis_json_path (str | Path | None): The path save the to the analysis database (analysis.json), defaults to None. If None, the analysis database is not persisted. + analysis_level (str): Analysis level (symbol-table, call-graph) + use_graalvm_binary (bool): A flag indicating whether to use the GraalVM binary for SDG analysis, defaults to False. If False, the default Java binary is used and one needs to have Java 17 or higher installed. + eager_analysis (bool): A flag indicating whether to perform eager analysis, defaults to False. If True, the analysis is performed eagerly. That is, the analysis.json file is created during analysis every time even if it already exists. + + Raises: + NotImplementedError: Raised when anaysis backend is not supported. + + Attributes: + application (JApplication): The application view of the Java code. + + """ + self.project_dir = project_dir self.source_code = source_code self.analysis_level = analysis_level @@ -82,153 +74,188 @@ def __init__( raise NotImplementedError(f"Support for {analysis_backend} has not been implemented yet.") def get_imports(self) -> List[str]: + """ Returns all the imports in the source code. + + Raises: + NotImplementedError: Raised when this functionality is not suported. + + Returns: + List[str]: List of all the imports. + """ raise NotImplementedError(f"Support for this functionality has not been implemented yet.") def get_variables(self, **kwargs): + """ _Returns all the variables. + + Raises: + NotImplementedError: Raised when this functionality is not suported. + """ raise NotImplementedError(f"Support for this functionality has not been implemented yet.") def get_service_entry_point_classes(self, **kwargs): + """ Returns all service entry point classes. + + Raises: + NotImplementedError: Raised when this functionality is not suported. + """ raise NotImplementedError(f"Support for this functionality has not been implemented yet.") def get_service_entry_point_methods(self, **kwargs): + """ Returns all the service entry point methods. + + Raises: + NotImplementedError: Raised when this functionality is not suported. + """ raise NotImplementedError(f"Support for this functionality has not been implemented yet.") def get_application_view(self) -> JApplication: - """ - Returns the application view of the Java code. + """ Returns application view of the java code. + + Raises: + NotImplementedError: Raised when this functionality is not suported. Returns: - -------- - JApplication - The application view of the Java code. - """ + JApplication: Application view of the java code. + """ if self.source_code: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_application_view() def get_symbol_table(self) -> Dict[str, JCompilationUnit]: - """ - Returns the symbol table of the Java code. + """ Returns symbol table. Returns: - -------- - Dict[str, JCompilationUnit] - The application view of the Java code. - """ + Dict[str, JCompilationUnit]: Symbol table + """ return self.backend.get_symbol_table() def get_compilation_units(self) -> List[JCompilationUnit]: - """ - Returns the compilation units of the Java code. + """ Returns a list of all compilation units in the java code. - Returns - ------- - Dict[str, JCompilationUnit] - The compilation units of the Java code. - """ + Raises: + NotImplementedError: Raised when this functionality is not suported. + + Returns: + List[JCompilationUnit]: Compilation units of the Java code. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_compilation_units() def get_class_hierarchy(self) -> DiGraph: - """ - Returns the class hierarchy of the Java code. + """ Returns class hierarchy of the java code. + + Raises: + NotImplementedError: Raised when this functionality is not suported. Returns: - -------- - DiGraph - The class hierarchy of the Java code. - """ + DiGraph: The class hierarchy of the Java code. + """ + if self.backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") raise NotImplementedError("Class hierarchy is not implemented yet.") def get_call_graph(self) -> DiGraph: - """ - Returns the call graph of the Java code. + """ Returns the call graph of the Java code. Returns: - -------- - DiGraph - The call graph of the Java code. - """ + DiGraph: The call graph of the Java code. + """ return self.backend.get_call_graph() def get_call_graph_json(self) -> str: - """ - serialize callgraph to json - """ + """ Returns a serialized call graph in json. + + Raises: + NotImplementedError: Raised when this functionality is not suported. + + Returns: + str: Call graph in json. + """ if self.source_code: raise NotImplementedError("Producing a call graph over a single file is not implemented yet.") return self.backend.get_call_graph_json() def get_callers(self, target_class_name: str, target_method_declaration: str, using_symbol_table: bool = False) -> Dict: - """ - Get all the caller details for a given java method. + """ Returns a dictionary of callers of the target method. + + Args: + target_class_name (str): Qualified target class name. + target_method_declaration (str): Target method names + using_symbol_table (bool, optional): Whether to use symbol table. Defaults to False. + + Raises: + NotImplementedError: Raised when this functionality is not suported. Returns: - -------- - Dict - Caller details in a dictionary. - """ + Dict: A dictionary of callers of target method. + """ + if self.source_code: raise NotImplementedError("Generating all callers over a single file is not implemented yet.") return self.backend.get_all_callers(target_class_name, target_method_declaration, using_symbol_table) - def get_callees(self, source_class_name: str, source_method_declaration: str, - using_symbol_table: bool = False): - """ - Get all the callee details for a given java method. + + def get_callees(self, source_class_name: str, source_method_declaration: str, using_symbol_table: bool = False) ->Dict: + """ Returns a dictionary of callees by the given method in the given class. + + Args: + source_class_name (str): Qualified class name where the given method is. + source_method_declaration (str): Given method + using_symbol_table (bool): Whether to use symbol table. Defaults to false. + + Raises: + NotImplementedError: Raised when this functionality is not suported. Returns: - -------- - Dict - Callee details in a dictionary. - """ + Dict: Dictionary with callee details. + """ if self.source_code: raise NotImplementedError("Generating all callees over a single file is not implemented yet.") return self.backend.get_all_callees(source_class_name, source_method_declaration, using_symbol_table) def get_methods(self) -> Dict[str, Dict[str, JCallable]]: - """ - Returns a dictionary of all methods in the Java code with - qualified class name as key and dictionary of methods in that class - as value + """ Returns all methods in the Java code. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, Dict[str, JCallable]]: - A dictionary of dictionaries of all methods in the Java code. - """ + Dict[str, Dict[str, JCallable]]: Dictionary of dictionaries of all methods in the Java code with qualified class name as key and dictionary of methods in that class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_methods_in_application() def get_classes(self) -> Dict[str, JType]: - """ - Returns a dictionary of all classes in the Java code. + """ Returns all classes in the Java code. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, JType] - A dict of all classes in the Java code, with qualified class names as keys - """ + Dict[str, JType]: A dictionary of all classes in the Java code, with qualified class names as keys. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_classes() def get_classes_by_criteria(self, inclusions=None, exclusions=None) -> Dict[str, JType]: - """ - Returns a dictionary of all classes in the Java code. + """ Returns a dictionary of all classes with the given criteria, in the Java code. - #TODO: Document the parameters inclusions and exclusions. + Args: + inclusions (List, optional): inlusion criteria for the classes. Defaults to None. + exclusions (List, optional): exclusion criteria for the classes. Defaults to None. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, JType] - A dict of all classes in the Java code, with qualified class names as keys - """ + Dict[str, JType]: A dict of all classes in the Java code, with qualified class names as keys + """ + if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") @@ -251,211 +278,190 @@ def get_classes_by_criteria(self, inclusions=None, exclusions=None) -> Dict[str, class_dict[application_class] = all_classes[application_class] return class_dict - def get_class(self, qualified_class_name) -> JType: - """ - Returns a class given qualified class name. + def get_class(self, qualified_class_name:str) -> JType: + """ Returns a class object given qualified class name. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Args: + qualified_class_name (str): The qualified name of the class. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - JType - A class for the given qualified class name. - """ + JType: Class object for the given qualified class name. + """ + if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_class(qualified_class_name) - def get_method(self, qualified_class_name, qualified_method_name) -> JCallable: - """ - Returns a method given qualified method name. + def get_method(self, qualified_class_name:str, qualified_method_name:str) -> JCallable: + """ Returns a method object given qualified class and method names. + + Args: + qualified_class_name (str): The qualified name of the class. + qualified_method_name (str): The qualified name of the method. - Parameters: - ----------- - qualified_method_name : str - The qualified name of the method. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - JCallable - A method for the given qualified method name. - """ + JCallable: A method for the given qualified method name. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_method(qualified_class_name, qualified_method_name) - def get_java_file(self, qualified_class_name) -> str: - """ - Returns a class given qualified class name. + def get_java_file(self, qualified_class_name: str) -> str: + """ Returns a class given qualified class name. + + Args: + qualified_class_name (str): The qualified name of the class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - str - Java file name containing the given qualified class. - """ + str: Java file name containing the given qualified class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_java_file(qualified_class_name) def get_java_compilation_unit(self, file_path: str) -> JCompilationUnit: - """ - Given the path of a Java source file, returns the compilation unit object from the symbol table. + """ Given the path of a Java source file, returns the compilation unit object from the symbol table. - Parameters - ---------- - file_path : str - Absolute path to Java source file + Args: + file_path (str): Absolute path to Java source file - Returns - ------- - JCompilationUnit - Compilation unit object for Java source file - """ + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. + + Returns: + JCompilationUnit: Compilation unit object for Java source file + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_java_compilation_unit(file_path) def get_methods_in_class(self, qualified_class_name) -> Dict[str, JCallable]: - """ - Returns a dictionary of all methods in the given class. + """ Returns a dictionary of all methods of the given class. + + Args: + qualified_class_name (str): qualified class name - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, JCallable] - A dictionary of all methods in the given class. - """ + Dict[str, JCallable]: A dictionary of all constructors of the given class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_methods_in_class(qualified_class_name) def get_constructors(self, qualified_class_name) -> Dict[str, JCallable]: - """ - Returns a dictionary of all constructors of the given class. + """ Returns a dictionary of all constructors of the given class. + + Args: + qualified_class_name (str): qualified class name - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, JCallable] - A dictionary of all constructors of the given class. - """ + Dict[str, JCallable]: A dictionary of all constructors of the given class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_constructors(qualified_class_name) def get_fields(self, qualified_class_name) -> List[JField]: - """ - Returns a list of all fields of the given class. + """ Returns a dictionary of all fields of the given class + + Args: + qualified_class_name (str): qualified class name - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - List[JField] - A list of all fields of the given class. - """ + List[JField]: A list of all fields of the given class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_fields(qualified_class_name) def get_nested_classes(self, qualified_class_name) -> List[JType]: - """ - Returns a list of all nested classes for the given class. + """ Returns a dictionary of all nested classes of the given class + + Args: + qualified_class_name (str): qualified class name - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - List[JType] - A list of nested classes for the given class. - """ + List[JType]: A list of nested classes for the given class. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_nested_classes(qualified_class_name) def get_sub_classes(self, qualified_class_name) -> Dict[str, JType]: - """ - Returns a dictionary of all sub-classes of the given class - Parameters - ---------- - qualified_class_name + """ Returns a dictionary of all sub-classes of the given class - Returns - ------- + Args: + qualified_class_name (str): qualified class name + + Returns: Dict[str, JType]: A dictionary of all sub-classes of the given class, and class details - """ + """ return self.backend.get_all_sub_classes(qualified_class_name=qualified_class_name) def get_extended_classes(self, qualified_class_name) -> List[str]: - """ - Returns a list of all extended classes for the given class. + """ Returns a list of all extended classes for the given class. + Args: + qualified_class_name (str): The qualified name of the class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - List[JType] - A list of extended classes for the given class. + List[str]: A list of extended classes for the given class. """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_extended_classes(qualified_class_name) - def get_implemented_interfaces(self, qualified_class_name) -> List[str]: - """ - Returns a list of all implemented interfaces for the given class. + def get_implemented_interfaces(self, qualified_class_name: str) -> List[str]: + """Returns a list of all implemented interfaces for the given class. + + Args: + qualified_class_name (str): The qualified name of the class. - Parameters: - ----------- - qualified_class_name : str - The qualified name of the class. + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - List[JType] - A list of implemented interfaces for the given class. + List[str]: A list of implemented interfaces for the given class. """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_implemented_interfaces(qualified_class_name) - def __get_class_call_graph_using_symbol_table(self, qualified_class_name: str, - method_signature: str | None = None) -> (List)[ - Tuple[JMethodDetail, JMethodDetail]]: - """ - A call graph using symbol table for a given class and a given method. + def __get_class_call_graph_using_symbol_table(self, qualified_class_name: str, method_signature: str | None = None) -> (List)[Tuple[JMethodDetail, JMethodDetail]]: + """A call graph using symbol table for a given class and a given method. + Args: - qualified_class_name: - method_signature: + qualified_class_name (str): The qualified name of the class. + method_signature (str | None, optional): The signature of the method in the class.. Defaults to None. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - List[Tuple[JMethodDetail, JMethodDetail]] - An edge list of the call graph for the given class and method. + List[Tuple[JMethodDetail, JMethodDetail]]: An edge list of the call graph for the given class and method. """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") @@ -463,27 +469,19 @@ def __get_class_call_graph_using_symbol_table(self, qualified_class_name: str, def get_class_call_graph(self, qualified_class_name: str, method_signature: str | None = None, using_symbol_table: bool = False) -> List[Tuple[JMethodDetail, JMethodDetail]]: - """ - A call graph for a given class and (optionally) a given method. - - Parameters - ---------- - using_symbol_table: bool - Generate call graph using symbol table - qualified_class_name : str - The qualified name of the class. - method_name : str, optional - The signature of the method in the class. - - Returns - ------- - List[Tuple[JMethodDetail, JMethodDetail]] - An edge list of the call graph for the given class and method. + """A call graph for a given class and (optionally) a given method. Args: - using_symbol_table: - using_symbol_table: - """ + qualified_class_name (str): The qualified name of the class. + method_signature (str | None, optional): The signature of the method in the class.. Defaults to None. + using_symbol_table (bool, optional): Generate call graph using symbol table. Defaults to False. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. + + Returns: + List[Tuple[JMethodDetail, JMethodDetail]]: An edge list of the call graph for the given class and method. + """ if using_symbol_table: return self.__get_class_call_graph_using_symbol_table(qualified_class_name=qualified_class_name, method_signature=method_signature) @@ -492,130 +490,108 @@ def get_class_call_graph(self, qualified_class_name: str, method_signature: str return self.backend.get_class_call_graph(qualified_class_name, method_signature) def get_entry_point_classes(self) -> Dict[str, JType]: - """ - Returns a dictionary of all entry point classes in the Java code. + """Returns a dictionary of all entry point classes in the Java code. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, JType] - A dict of all entry point classes in the Java code, with qualified class names as keys + Dict[str, JType]: A dict of all entry point classes in the Java code, with qualified class names as keys """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_entry_point_classes() def get_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]: - """ - Returns a dictionary of all entry point methods in the Java code with - qualified class name as key and dictionary of methods in that class - as value + """Returns a dictionary of all entry point methods in the Java code with qualified class name as key and dictionary of methods in that class as value + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str, Dict[str, JCallable]]: - A dictionary of dictionaries of entry point methods in the Java code. - """ + Dict[str, Dict[str, JCallable]]: A dictionary of dictionaries of entry point methods in the Java code. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_all_entry_point_methods() def remove_all_comments(self) -> str: - """ - Remove all comments from the source code. - - Parameters - ---------- - source_code : str - The source code to process. + """Remove all comments from the source code. - Returns - ------- - str - The source code with all comments removed. - """ + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. + Returns: + str: The source code with all comments removed. + """ # Remove any prefix comments/content before the package declaration if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.CODEANALYZER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.remove_all_comments(self.source_code) def get_methods_with_annotations(self, annotations: List[str]) -> Dict[str, List[Dict]]: - """ - Returns a dictionary of method names and method bodies. - - Parameters: - ----------- - source_class_code : str - String containing code for a java class. - annotations : List[str] - List of annotation strings. - Returns: - -------- - Dict[str,List[Dict]] - Dictionary with annotations as keys and - a list of dictionaries containing method names and bodies, as values. - """ + """Returns a dictionary of method names and method bodies. + + Args: + annotations (List[str]): List of annotation strings. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. + + Returns: + Dict[str, List[Dict]]: Dictionary with annotations as keys and a list of dictionaries containing method names and bodies, as values. + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.CODEANALYZER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_methods_with_annotations(self.source_code, annotations) - def get_test_methods(self, source_class_code: str) -> Dict[str, str]: - """ - Returns a dictionary of method names and method bodies. + def get_test_methods(self) -> Dict[str, str]: + """Returns a dictionary of method names and method bodies. - Parameters: - ----------- - source_class_code : str - String containing code for a java class. + Args: + source_class_code (str): String containing code for a java class. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - Dict[str,str] - Dictionary of method names and method bodies. - """ + Dict[str, str]: Dictionary of method names and method bodies. + """ + if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.CODEANALYZER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_test_methods(self.source_code) def get_calling_lines(self, target_method_name: str) -> List[int]: - """ - Returns a list of line numbers in source method where target method is called. + """Returns a list of line numbers in source method block where target method is called. - Parameters: - ----------- - source_method_code : str - source method code + Args: + target_method_name (str): target method name. - target_method_code : str - target method code + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. Returns: - -------- - List[int] - List of line numbers within in source method code block. - """ + List[int]: List of line numbers within in source method code block. + """ + if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_calling_lines(self.source_code, target_method_name) def get_call_targets(self, declared_methods: dict) -> Set[str]: - """Generate a list of call targets from the method body. - - Uses simple name resolution for finding the call targets. Nothing sophiscticed here. Just a simple search - over the AST. - - Parameters - ---------- - method_body : Node - The method body. - declared_methods : dict - A dictionary of all declared methods in the class. - - Returns - ------- - List[str] - A list of call targets (methods). - """ + """Uses simple name resolution for finding the call targets. Nothing sophiscticed here. Just a simple search over the AST. + + Args: + declared_methods (dict): A dictionary of all declared methods in the class. + + Raises: + NotImplementedError: Raised when current AnalysisEngine does not support this function. + + Returns: + Set[str]: A list of call targets (methods). + """ if self.analysis_backend in [AnalysisEngine.CODEQL, AnalysisEngine.TREESITTER]: raise NotImplementedError(f"Support for this functionality has not been implemented yet.") return self.backend.get_call_targets(self.source_code, declared_methods) + \ No newline at end of file diff --git a/cldk/models/java/models.py b/cldk/models/java/models.py index d34e3e9f..a4cd7e7c 100644 --- a/cldk/models/java/models.py +++ b/cldk/models/java/models.py @@ -10,27 +10,17 @@ class JField(BaseModel): - """ - Represents a field in a Java class or interface. - - Parameters - ---------- - comment : str - The comment associated with the field. - name : str - The name of the field. - type : str - The type of the field. - start_line : int - The starting line number of the field in the source file. - end_line : int - The ending line number of the field in the source file. - variables : List[str] - The variables declared in the field. - modifiers : List[str] - The modifiers applied to the field (e.g., public, static). - annotations : List[str] - The annotations applied to the field. + """ Represents a field in a Java class or interface. + + Attributes: + comment (str): The comment associated with the field. + name (str): The name of the field. + type (str): The type of the field. + start_line (int): The starting line number of the field in the source file. + end_line (int): The ending line number of the field in the source file. + variables (List[str]): The variables declared in the field. + modifiers (List[str]): The modifiers applied to the field (e.g., public, static). + annotations (List[str]): The annotations applied to the field. """ comment: str @@ -43,17 +33,16 @@ class JField(BaseModel): class JCallableParameter(BaseModel): - """ - Represents a parameter of a Java callable. - - Parameters - ---------- - name : str - The name of the parameter. - type : str - The type of the parameter. + """ Represents a parameter of a Java callable. + + Attributes: + name (str): The name of the parameter. + type (str): The type of the parameter. + annotations (List[str]): The annotations applied to the parameter. + modifiers (List[str]): The modifiers applied to the parameter. """ + name: str type: str annotations: List[str] @@ -61,40 +50,33 @@ class JCallableParameter(BaseModel): class JEnumConstant(BaseModel): + """ Represents a constant in an enumeration. + + Attributes: + name (str): The name of the enum constant. + arguments (List[str]): The arguments associated with the enum constant. + """ name: str arguments: List[str] class JCallSite(BaseModel): + """ Represents a call site. + + Attributes: + method_name (str): The name of the method called at the call site. + receiver_expr (str): Expression for the receiver of the method call. + receiver_type (str): Name of type declaring the called method. + argument_types (List[str]): Types of actual parameters for the call. + return_type (str): Return type of the method call (resolved type of the method call expression; empty string if expression is unresolved). + is_static_call (bool): Flag indicating whether the call is a static call. + is_constructor_call (bool): Flag indicating whether the call is a constructor call. + start_line (int): The starting line number of the call site. + start_column (int): The starting column of the call site. + end_line (int): The ending line number of the call site. + end_column (int): The ending column of the call site. """ - Represents a call site. - - Parameters - ---------- - method_name : str - The name of the method called at the call site. - receiver_expr : str - Expression for the receiver of the method call. - receiver_type : str - Name of type declaring the called method. - argument_types : List[str] - Types of actual parameters for the call. - return_type : str - Return type of the method call (resolved type of the method call expression; empty string if expression is - unresolved). - is_static_call: bool - Flag indicating whether the call is a static call - is_constructor_call: bool - Flag indicating whether the call is a constructor call - start_line : int - The starting line number of the call site. - start_column : int - The starting column of the call site. - end_line : int - The ending line number of the call site. - end_column : int - The ending column of the call site. - """ + method_name: str receiver_expr: str = "" @@ -115,25 +97,16 @@ class JCallSite(BaseModel): class JVariableDeclaration(BaseModel): - """ - Represents a variable declaration. - - Parameters - ---------- - name : str - The name of the variable. - type : str - The type of the variable. - initializer : str - The initialization expression (if persent) for the variable declaration. - start_line : int - The starting line number of the declaration. - start_column : int - The starting column of the declaration. - end_line : int - The ending line number of the declaration. - end_column : int - The ending column of the declaration. + """ Represents a variable declaration. + + Attributes: + name (str): The name of the variable. + type (str): The type of the variable. + initializer (str): The initialization expression (if present) for the variable declaration. + start_line (int): The starting line number of the declaration. + start_column (int): The starting column of the declaration. + end_line (int): The ending line number of the declaration. + end_column (int): The ending column of the declaration. """ name: str @@ -146,47 +119,27 @@ class JVariableDeclaration(BaseModel): class JCallable(BaseModel): - """ - Represents a callable entity such as a method or constructor in Java. - - Parameters - ---------- - signature : str - The signature of the callable. - is_implicit : bool - A flag indicating whether the callable is implicit (e.g., a default constructor). - is_constructor : bool - A flag indicating whether the callable is a constructor. - comment : str - The comment associated with the callable. - annotations : List[str] - The annotations applied to the callable. - modifiers : List[str] - The modifiers applied to the callable (e.g., public, static). - thrown_exceptions : List[str] - Exceptions declared via "throws". - declaration : str - The declaration of the callable. - parameters : List[ParameterInCallable] - The parameters of the callable. - return_type : Optional[str] - The return type of the callable. None if the callable does not return a value (e.g., a constructor). - code : str - The code block of the callable. - start_line : int - The starting line number of the callable in the source file. - end_line : int - The ending line number of the callable in the source file. - referenced_types : List[str] - The types referenced within the callable. - accessed_fields : List[str] - Fields accessed in the callable. - call_sites : List[JCallSite] - Call sites in the callable. - variable_declarations : List[JVariableDeclaration] - Local variable declarations in the callable. - cyclomatic_complexity : int - Cyclomatic complexity of the callable. + """ Represents a callable entity such as a method or constructor in Java. + + Attributes: + signature (str): The signature of the callable. + is_implicit (bool): A flag indicating whether the callable is implicit (e.g., a default constructor). + is_constructor (bool): A flag indicating whether the callable is a constructor. + comment (str): The comment associated with the callable. + annotations (List[str]): The annotations applied to the callable. + modifiers (List[str]): The modifiers applied to the callable (e.g., public, static). + thrown_exceptions (List[str]): Exceptions declared via "throws". + declaration (str): The declaration of the callable. + parameters (List[JCallableParameter]): The parameters of the callable. + return_type (Optional[str]): The return type of the callable. None if the callable does not return a value (e.g., a constructor). + code (str): The code block of the callable. + start_line (int): The starting line number of the callable in the source file. + end_line (int): The ending line number of the callable in the source file. + referenced_types (List[str]): The types referenced within the callable. + accessed_fields (List[str]): Fields accessed in the callable. + call_sites (List[JCallSite]): Call sites in the callable. + variable_declarations (List[JVariableDeclaration]): Local variable declarations in the callable. + cyclomatic_complexity (int): Cyclomatic complexity of the callable. """ signature: str @@ -244,41 +197,30 @@ def detect_entrypoint_method(self): class JType(BaseModel): - """ - Represents a Java class or interface. - - Parameters - ---------- - name : str - The name of the class or interface. - is_interface : bool - A flag indicating whether the object is an interface. - is_inner_class : bool - A flag indicating whether the object is an inner class. - is_local_class : bool - A flag indicating whether the object is a local class. - is_nested_type: bool - A flag indicating whether the object is a nested type. - comment : str - The comment of the class or interface. - extends_list : List[str] - The list of classes or interfaces that the object extends. - implements_list : List[str] - The list of interfaces that the object implements. - modifiers : List[str] - The list of modifiers of the object. - annotations : List[str] - The list of annotations of the object. - parent_class: - The name of the parent class (if it exists) - nested_class_declerations: List[str] - All the class declerations nested under this class. - constructor_declarations : List[JCallable] - The list of constructors of the object. - method_declarations : List[JCallable] - The list of methods of the object. - field_declarations : List[JField] - The list of fields of the object. + + """ Represents a Java class or interface. + + Attributes: + is_interface (bool): A flag indicating whether the object is an interface. + is_inner_class (bool): A flag indicating whether the object is an inner class. + is_local_class (bool): A flag indicating whether the object is a local class. + is_nested_type (bool): A flag indicating whether the object is a nested type. + is_class_or_interface_declaration (bool): A flag indicating whether the object is a class or interface declaration. + is_enum_declaration (bool): A flag indicating whether the object is an enum declaration. + is_annotation_declaration (bool): A flag indicating whether the object is an annotation declaration. + is_record_declaration (bool): A flag indicating whether this object is a record declaration. + is_concrete_class (bool): A flag indicating whether this is a concrete class. + is_entry_point (bool): A flag indicating whether this is an entry point class. + comment (str): The comment of the class or interface. + extends_list (List[str]): The list of classes or interfaces that the object extends. + implements_list (List[str]): The list of interfaces that the object implements. + modifiers (List[str]): The list of modifiers of the object. + annotations (List[str]): The list of annotations of the object. + parent_type (str): The name of the parent class (if it exists). + nested_type_declarations (List[str]): All the class declarations nested under this class. + callable_declarations (Dict[str, JCallable]): The list of constructors and methods of the object. + field_declarations (List[JField]): The list of fields of the object. + enum_constants (List[JEnumConstant]): The list of enum constants in the object. """ is_interface: bool = False @@ -307,6 +249,7 @@ class JType(BaseModel): # for abstract classes we will check the modifiers @model_validator(mode="before") def check_concrete_class(cls, values): + """Detects if the class is concrete based on its properties.""" values["is_concrete_class"] = False if values.get("is_class_or_interface_declaration") and not values.get("is_interface"): if "abstract" not in values.get("modifiers"): @@ -320,6 +263,7 @@ def check_concrete_class(cls, values): # if the class extends or implements known servlet classes @model_validator(mode="after") def check_concrete_entry_point(self): + """Detects if the class is entry point based on its properties.""" if self.is_concrete_class: if any(substring in string for substring in (self.extends_list + self.implements_list) for string in constants.ENTRY_POINT_SERVLET_CLASSES): @@ -338,6 +282,14 @@ def check_concrete_entry_point(self): class JCompilationUnit(BaseModel): + """ Represents a compilation unit in Java. + + Attributes: + comment (str): A comment associated with the compilation unit. + imports (List[str]): A list of import statements in the compilation unit. + type_declarations (Dict[str, JType]): A dictionary mapping type names to their corresponding JType representations. + """ + comment: str imports: List[str] type_declarations: Dict[str, JType] @@ -345,6 +297,13 @@ class JCompilationUnit(BaseModel): class JMethodDetail(BaseModel): + """ Represents details about a method in a Java class. + + Attributes: + method_declaration (str): The declaration string of the method. + klass (str): The name of the class containing the method. 'class' is a reserved keyword in Python. + method (JCallable): An instance of JCallable representing the callable details of the method. + """ method_declaration: str # class is a reserved keyword in python. we'll use klass. klass: str @@ -358,6 +317,16 @@ def __hash__(self): class JGraphEdgesST(BaseModel): + """ Represents an edge in a graph structure for method dependencies. + + Attributes: + source (JMethodDetail): The source method of the edge. + target (JMethodDetail): The target method of the edge. + type (str): The type of the edge. + weight (str): The weight of the edge, indicating the strength or significance of the connection. + source_kind (Optional[str]): The kind of the source method. Default is None. + destination_kind (Optional[str]): The kind of the target method. Default is None. + """ source: JMethodDetail target: JMethodDetail type: str @@ -367,6 +336,16 @@ class JGraphEdgesST(BaseModel): class JGraphEdges(BaseModel): + """ Represents an edge in a graph structure for method dependencies. + + Attributes: + source (JMethodDetail): The source method of the edge. + target (JMethodDetail): The target method of the edge. + type (str): The type of the edge. + weight (str): The weight of the edge, indicating the strength or significance of the connection. + source_kind (Optional[str]): The kind of the source method. Default is None. + destination_kind (Optional[str]): The kind of the target method. Default is None. + """ source: JMethodDetail target: JMethodDetail type: str @@ -377,6 +356,15 @@ class JGraphEdges(BaseModel): @field_validator("source", "target", mode="before") @classmethod def validate_source(cls, value) -> JMethodDetail: + """ Validates the source and target methods by parsing the input JSON string. + + Args: + value (str): A JSON string containing details about the method. + + Returns: + JMethodDetail: An instance of JMethodDetail representing the method details. + """ + callable_dict = json.loads(value) j_callable = JCallable(**json.loads(callable_dict["callable"])) # parse the value which is a quoted string class_name = callable_dict["class_interface_declarations"] @@ -389,15 +377,11 @@ def __hash__(self): class JApplication(BaseModel): - """ - Represents a Java application. - - Parameters - ---------- - symbol_table : List[JCompilationUnit] - The symbol table representation - system_dependency : List[JGraphEdges] - The edges of the system dependency graph. Default None. + """Represents a Java application. + + Attributes: + symbol_table (Dict[str, JCompilationUnit]): The symbol table representation containing compilation units. + system_dependency_graph (List[JGraphEdges], optional): The edges of the system dependency graph. Defaults to None. """ symbol_table: Dict[str, JCompilationUnit] system_dependency_graph: List[JGraphEdges] = None