From 0640b84ed619450ff0cf2f4d7e64344797f5c9c5 Mon Sep 17 00:00:00 2001 From: Rangeet Pan Date: Thu, 12 Sep 2024 11:42:31 -0400 Subject: [PATCH 1/2] fixing caller method --- .../java/codeanalyzer/codeanalyzer.py | 86 +++++++------------ 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/cldk/analysis/java/codeanalyzer/codeanalyzer.py b/cldk/analysis/java/codeanalyzer/codeanalyzer.py index 41d260b..e6bbf27 100644 --- a/cldk/analysis/java/codeanalyzer/codeanalyzer.py +++ b/cldk/analysis/java/codeanalyzer/codeanalyzer.py @@ -51,15 +51,14 @@ class JCodeanalyzer: """ def __init__( - self, - project_dir: Union[str, Path], - source_code: str | None, - analysis_backend_path: Union[str, Path, None], - analysis_json_path: Union[str, Path, None], - analysis_level: str, - use_graalvm_binary: bool, - eager_analysis: bool, - target_files: List[str] | None + self, + project_dir: Union[str, Path], + source_code: str | None, + analysis_backend_path: Union[str, Path, None], + analysis_json_path: Union[str, Path, None], + analysis_level: str, + use_graalvm_binary: bool, + eager_analysis: bool, ) -> None: self.project_dir = project_dir self.source_code = source_code @@ -68,7 +67,6 @@ def __init__( self.use_graalvm_binary = use_graalvm_binary self.eager_analysis = eager_analysis self.analysis_level = analysis_level - self.target_files = target_files self.application = self._init_codeanalyzer( analysis_level=1 if analysis_level == AnalysisLevel.symbol_table else 2) # Attributes related the Java code analysis... @@ -173,7 +171,7 @@ def _get_codeanalyzer_exec(self) -> List[str]: resources.files("cldk.analysis.java.codeanalyzer.bin") / "codeanalyzer") as codeanalyzer_bin_path: codeanalyzer_exec = shlex.split(codeanalyzer_bin_path.__str__()) else: - + if self.analysis_backend_path: analysis_backend_path = Path(self.analysis_backend_path) logger.info(f"Using codeanalyzer.jar from {analysis_backend_path}") @@ -200,19 +198,11 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: """ codeanalyzer_exec = self._get_codeanalyzer_exec() - codeanalyzer_args = '' + if self.analysis_json_path is None: logger.info("Reading analysis from the pipe.") - # If target file is provided, the input is merged into a single string and passed to codeanalyzer - if self.target_files: - target_file_options = ' -t '.join([s.strip() for s in self.target_files]) - codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -t {target_file_options}" - ) - else: - codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level}" - ) + codeanalyzer_args = codeanalyzer_exec + shlex.split( + f"-i {Path(self.project_dir)} --analysis-level={analysis_level}") try: logger.info(f"Running codeanalyzer: {' '.join(codeanalyzer_args)}") console_out: CompletedProcess[str] = subprocess.run( @@ -226,29 +216,15 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: raise CodeanalyzerExecutionException(str(e)) from e else: - # Check if the code analyzer needs to be run - is_run_code_analyzer = False analysis_json_path_file = Path(self.analysis_json_path).joinpath("analysis.json") - # If target file is provided, the input is merged into a single string and passed to codeanalyzer - if self.target_files: - target_file_options = ' -t '.join([s.strip() for s in self.target_files]) + if not analysis_json_path_file.exists() or self.eager_analysis: + # If the analysis file does not exist, we'll run the analysis. Alternately, if the eager_analysis + # flag is set, we'll run the analysis every time the object is created. This will happen regradless + # of the existence of the analysis file. + # Create the executable command for codeanalyzer. codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level}" - f" -o {self.analysis_json_path} -t {target_file_options}" - ) - is_run_code_analyzer = True - else: - if not analysis_json_path_file.exists() or self.eager_analysis: - # If the analysis file does not exist, we'll run the analysis. Alternately, if the eager_analysis - # flag is set, we'll run the analysis every time the object is created. This will happen regradless - # of the existence of the analysis file. - # Create the executable command for codeanalyzer. - codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -o {self.analysis_json_path}" - ) - is_run_code_analyzer = True - - if is_run_code_analyzer: + f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -o {self.analysis_json_path}") + try: logger.info(f"Running codeanalyzer subprocess with args {codeanalyzer_args}") subprocess.run( @@ -262,6 +238,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: except Exception as e: raise CodeanalyzerExecutionException(str(e)) from e + with open(analysis_json_path_file) as f: data = json.load(f) return JApplication(**data) @@ -275,6 +252,7 @@ def _codeanalyzer_single_file(self): JApplication The application view of the Java code with the analysis results. """ + # self.source_code: str = re.sub(r"[\r\n\t\f\v]+", lambda x: " " if x.group() in "\t\f\v" else " ", self.source_code) codeanalyzer_exec = self._get_codeanalyzer_exec() codeanalyzer_args = ["--source-analysis", self.source_code] codeanalyzer_cmd = codeanalyzer_exec + codeanalyzer_args @@ -430,8 +408,9 @@ def get_all_callers(self, target_class_name: str, target_method_signature: str, caller_detail_dict = {} call_graph = None if using_symbol_table: - call_graph = self.__raw_call_graph_using_symbol_table_target_method(target_class_name=target_class_name, - target_method_signature=target_method_signature) + call_graph = self.__call_graph_using_symbol_table(qualified_class_name=target_class_name, + method_signature=target_method_signature, + is_target_method=True) else: call_graph = self.call_graph if (target_method_signature, target_class_name) not in call_graph.nodes(): @@ -768,7 +747,7 @@ 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: + method_signature: str, is_target_method: bool = False) -> DiGraph: """ Generate call graph using symbol table Args: @@ -782,10 +761,11 @@ def __call_graph_using_symbol_table(self, cg = nx.DiGraph() sdg = None if is_target_method: - sdg = None + sdg = self.__raw_call_graph_using_symbol_table_target_method(target_class_name=qualified_class_name, + target_method_signature=method_signature) else: sdg = self.__raw_call_graph_using_symbol_table(qualified_class_name=qualified_class_name, - method_signature=method_signature) + method_signature=method_signature) tsu = JavaSitter() edge_list = [ ( @@ -812,8 +792,8 @@ def __call_graph_using_symbol_table(self, return cg def __raw_call_graph_using_symbol_table_target_method(self, - target_class_name: str, - target_method_signature: str, + 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 @@ -832,7 +812,7 @@ def __raw_call_graph_using_symbol_table_target_method(self, for class_name in self.get_all_classes(): for method in self.get_all_methods_in_class(qualified_class_name=class_name): method_details = self.get_method(qualified_class_name=class_name, - method_signature=method) + method_signature=method) for call_site in method_details.call_sites: source_method_details = None source_class = '' @@ -856,9 +836,9 @@ def __raw_call_graph_using_symbol_table_target_method(self, if call_site.receiver_type != "": # call to any class if self.get_class(qualified_class_name=call_site.receiver_type): - if callee_signature==target_method_signature and call_site.receiver_type == target_class_name: + if callee_signature == target_method_signature and call_site.receiver_type == target_class_name: source_method_details = self.get_method(method_signature=method, - qualified_class_name=class_name) + qualified_class_name=class_name) source_class = class_name else: # check if any method exists with the signature in the class even if the receiver type is blank From c8777ad32a4083c1b8304bd442f2b64f9fdd2c7e Mon Sep 17 00:00:00 2001 From: Rangeet Pan Date: Thu, 12 Sep 2024 12:08:17 -0400 Subject: [PATCH 2/2] fixing caller method --- .../java/codeanalyzer/codeanalyzer.py | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/cldk/analysis/java/codeanalyzer/codeanalyzer.py b/cldk/analysis/java/codeanalyzer/codeanalyzer.py index e6bbf27..7dccd9b 100644 --- a/cldk/analysis/java/codeanalyzer/codeanalyzer.py +++ b/cldk/analysis/java/codeanalyzer/codeanalyzer.py @@ -59,6 +59,7 @@ def __init__( analysis_level: str, use_graalvm_binary: bool, eager_analysis: bool, + target_files: List[str] | None ) -> None: self.project_dir = project_dir self.source_code = source_code @@ -67,6 +68,7 @@ def __init__( self.use_graalvm_binary = use_graalvm_binary self.eager_analysis = eager_analysis self.analysis_level = analysis_level + self.target_files = target_files self.application = self._init_codeanalyzer( analysis_level=1 if analysis_level == AnalysisLevel.symbol_table else 2) # Attributes related the Java code analysis... @@ -198,11 +200,19 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: """ codeanalyzer_exec = self._get_codeanalyzer_exec() - + codeanalyzer_args = '' if self.analysis_json_path is None: logger.info("Reading analysis from the pipe.") - codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level}") + # If target file is provided, the input is merged into a single string and passed to codeanalyzer + if self.target_files: + target_file_options = ' -t '.join([s.strip() for s in self.target_files]) + codeanalyzer_args = codeanalyzer_exec + shlex.split( + f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -t {target_file_options}" + ) + else: + codeanalyzer_args = codeanalyzer_exec + shlex.split( + f"-i {Path(self.project_dir)} --analysis-level={analysis_level}" + ) try: logger.info(f"Running codeanalyzer: {' '.join(codeanalyzer_args)}") console_out: CompletedProcess[str] = subprocess.run( @@ -216,15 +226,29 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: raise CodeanalyzerExecutionException(str(e)) from e else: + # Check if the code analyzer needs to be run + is_run_code_analyzer = False analysis_json_path_file = Path(self.analysis_json_path).joinpath("analysis.json") - if not analysis_json_path_file.exists() or self.eager_analysis: - # If the analysis file does not exist, we'll run the analysis. Alternately, if the eager_analysis - # flag is set, we'll run the analysis every time the object is created. This will happen regradless - # of the existence of the analysis file. - # Create the executable command for codeanalyzer. + # If target file is provided, the input is merged into a single string and passed to codeanalyzer + if self.target_files: + target_file_options = ' -t '.join([s.strip() for s in self.target_files]) codeanalyzer_args = codeanalyzer_exec + shlex.split( - f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -o {self.analysis_json_path}") + f"-i {Path(self.project_dir)} --analysis-level={analysis_level}" + f" -o {self.analysis_json_path} -t {target_file_options}" + ) + is_run_code_analyzer = True + else: + if not analysis_json_path_file.exists() or self.eager_analysis: + # If the analysis file does not exist, we'll run the analysis. Alternately, if the eager_analysis + # flag is set, we'll run the analysis every time the object is created. This will happen regradless + # of the existence of the analysis file. + # Create the executable command for codeanalyzer. + codeanalyzer_args = codeanalyzer_exec + shlex.split( + f"-i {Path(self.project_dir)} --analysis-level={analysis_level} -o {self.analysis_json_path}" + ) + is_run_code_analyzer = True + if is_run_code_analyzer: try: logger.info(f"Running codeanalyzer subprocess with args {codeanalyzer_args}") subprocess.run( @@ -238,7 +262,6 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication: except Exception as e: raise CodeanalyzerExecutionException(str(e)) from e - with open(analysis_json_path_file) as f: data = json.load(f) return JApplication(**data) @@ -252,7 +275,6 @@ def _codeanalyzer_single_file(self): JApplication The application view of the Java code with the analysis results. """ - # self.source_code: str = re.sub(r"[\r\n\t\f\v]+", lambda x: " " if x.group() in "\t\f\v" else " ", self.source_code) codeanalyzer_exec = self._get_codeanalyzer_exec() codeanalyzer_args = ["--source-analysis", self.source_code] codeanalyzer_cmd = codeanalyzer_exec + codeanalyzer_args