13
13
# See the License for the specific language governing permissions and
14
14
# limitations under the License.
15
15
################################################################################
16
- from itertools import chain , groupby
17
- from pdb import set_trace
18
- import re
19
16
import json
17
+ import logging
18
+ import re
20
19
import shlex
21
- import requests
22
- import networkx as nx
23
- from pathlib import Path
24
20
import subprocess
25
- from subprocess import CompletedProcess
26
- from urllib .request import urlretrieve
27
- from datetime import datetime
28
21
from importlib import resources
22
+ from itertools import chain , groupby
23
+ from pathlib import Path
24
+ from subprocess import CompletedProcess
25
+ from typing import Any , Dict , List , Tuple
26
+ from typing import Union
29
27
28
+ import networkx as nx
30
29
from networkx import DiGraph
31
30
32
31
from cldk .analysis import AnalysisLevel
33
32
from cldk .analysis .java .treesitter import JavaSitter
34
33<
F438
/code>
from cldk .models .java import JGraphEdges
35
- from cldk .models .java .models import JApplication , JCallable , JField , JMethodDetail , JType , JCompilationUnit , JGraphEdgesST
36
- from typing import Dict , List , Tuple
37
- from typing import Union
38
-
34
+ from cldk .models .java .enums import CRUDOperationType
35
+ from cldk .models .java .models import JApplication , JCRUDOperation , JCallable , JField , JMethodDetail , JType , JCompilationUnit , JGraphEdgesST
39
36
from cldk .utils .exceptions .exceptions import CodeanalyzerExecutionException
40
37
41
- import logging
42
-
43
38
logger = logging .getLogger (__name__ )
44
39
45
40
@@ -143,28 +138,31 @@ def _get_codeanalyzer_exec(self) -> List[str]:
143
138
with resources .as_file (resources .files ("cldk.analysis.java.codeanalyzer.bin" ) / "codeanalyzer" ) as codeanalyzer_bin_path :
144
139
codeanalyzer_exec = shlex .split (codeanalyzer_bin_path .__str__ ())
145
140
else :
146
-
147
141
if self .analysis_backend_path :
148
142
analysis_backend_path = Path (self .analysis_backend_path )
149
143
logger .info (f"Using codeanalyzer jar from { analysis_backend_path } " )
150
144
codeanalyzer_jar_file = next (analysis_backend_path .rglob ("codeanalyzer-*.jar" ), None )
145
+ if codeanalyzer_jar_file is None :
146
+ raise CodeanalyzerExecutionException ("Codeanalyzer jar not found in the provided path." )
151
147
codeanalyzer_exec = shlex .split (f"java -jar { codeanalyzer_jar_file } " )
152
148
else :
153
- # Since the path to codeanalyzer.jar was not provided, we'll download the latest version from GitHub.
149
+ # Since the path to codeanalyzer.jar we will use the default jar from the cldk/analysis/java/codeanalyzer/jar folder
154
150
with resources .as_file (resources .files ("cldk.analysis.java.codeanalyzer.jar" )) as codeanalyzer_jar_path :
155
- # Download the codeanalyzer jar if it doesn't exist, update if it's outdated,
156
- # do nothing if it's up-to-date.
157
151
codeanalyzer_jar_file = next (codeanalyzer_jar_path .rglob ("codeanalyzer-*.jar" ), None )
158
152
codeanalyzer_exec = shlex .split (f"java -jar { codeanalyzer_jar_file } " )
159
153
return codeanalyzer_exec
160
154
161
- def init_japplication (self , data : str ) -> JApplication :
155
+ @staticmethod
156
+ def _init_japplication (data : str ) -> JApplication :
162
157
"""Return JApplication giving the stringified JSON as input.
163
158
Returns
164
159
-------
165
160
JApplication
166
161
The application view of the Java code with the analysis results.
167
162
"""
163
+ # from ipdb import set_trace
164
+
165
+ # set_trace()
168
166
return JApplication (** json .loads (data ))
169
167
170
168
def _init_codeanalyzer (self , analysis_level = 1 ) -> JApplication :
@@ -197,7 +195,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication:
197
195
text = True ,
198
196
check = True ,
199
197
)
200
- return JApplication ( ** json . loads (console_out .stdout ) )
198
+ return self . _init_japplication (console_out .stdout )
201
199
except Exception as e :
202
200
raise CodeanalyzerExecutionException (str (e )) from e
203
201
else :
@@ -217,7 +215,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication:
217
215
# flag is set, we'll run the analysis every time the object is created. This will happen regradless
218
216
# of the existence of the analysis file.
219
217
# Create the executable command for codeanalyzer.
220
- codeanalyzer_args = codeanalyzer_exec + shlex .split (f"-i { Path (self .project_dir )} --analysis-level={ analysis_level } -o { self .analysis_json_path } " )
218
+ codeanalyzer_args = codeanalyzer_exec + shlex .split (f"-i { Path (self .project_dir )} --analysis-level={ analysis_level } -o { self .analysis_json_path } -v " )
221
219
is_run_code_analyzer = True
222
220
223
221
if is_run_code_analyzer :
@@ -236,7 +234,7 @@ def _init_codeanalyzer(self, analysis_level=1) -> JApplication:
236
234
raise CodeanalyzerExecutionException (str (e )) from e
237
235
with open (analysis_json_path_file ) as f :
238
236
data = json .load (f )
239
- return JApplication ( ** data )
237
+ return self . _init_japplication ( json . dumps ( data ) )
240
238
241
239
def _codeanalyzer_single_file (self ) -> JApplication :
242
240
"""Invokes codeanalyzer in a single file mode.
@@ -248,12 +246,11 @@ def _codeanalyzer_single_file(self) -> JApplication:
248
246
codeanalyzer_args = ["--source-analysis" , self .source_code ]
249
247
codeanalyzer_cmd = codeanalyzer_exec + codeanalyzer_args
250
248
try :
251
- print (f"Running { ' ' .join (codeanalyzer_cmd )} " )
252
249
logger .info (f"Running { ' ' .join (codeanalyzer_cmd )} " )
253
250
console_out : CompletedProcess [str ] = subprocess .run (codeanalyzer_cmd , capture_output = True , text = True , check = True )
254
251
if console_out .returncode != 0 :
255
252
raise CodeanalyzerExecutionException (console_out .stderr )
256
- return JApplication ( ** json . loads (console_out .stdout ) )
253
+ return self . _init_japplication (console_out .stdout )
257
254
except Exception as e :
258
255
raise CodeanalyzerExecutionException (str (e )) from e
259
256
@@ -870,14 +867,9 @@ def get_all_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]:
870
867
Dict[str, Dict[str, JCallable]]: A dictionary of all entry point methods in the Java code.
871
868
"""
872
869
methods = chain .from_iterable (
873
- ((typename , method , callable )
874
- for method , callable in methods .items () if callable .is_entrypoint )
875
- for typename , methods in self .get_all_methods_in_application ().items ()
870
+ ((typename , method , callable ) for method , callable in methods .items () if callable .is_entrypoint ) for typename , methods in self .get_all_methods_in_application ().items ()
876
871
)
877
- return {
878
- typename : {method : callable for _ , method , callable in group }
879
- for typename , group in groupby (methods , key = lambda x : x [0 ])
880
- }
872
+ return {typename : {method : callable for _ , method , callable in group } for typename , group in groupby (methods , key = lambda x : x [0 ])}
881
873
882
874
def get_all_entry_point_classes (self ) -> Dict [str , JType ]:
883
875
"""Returns a dictionary of all entry point classes in the Java code.
@@ -887,8 +879,110 @@ def get_all_entry_point_classes(self) -> Dict[str, JType]:
887
879
with qualified class names as keys.
888
880
"""
889
881
890
- return {
891
- typename : klass
892
- for typename , klass in self .get_all_classes ().items ()
893
- if klass .is_entrypoint_class
894
- }
882
+ return {typename : klass for typename , klass in self .get_all_classes ().items () if klass .is_entrypoint_class }
883
+
884
+ def get_all_crud_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
885
+ """Returns a dictionary of all CRUD operations in the source code.
886
+
887
+ Raises:
888
+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
889
+
890
+ Returns:
891
+ Dict[str, List[str]]: A dictionary of all CRUD operations in the source code.
892
+ """
893
+
894
+ crud_operations = []
895
+ for class_name , class_details in self .get_all_classes ().items ():
896
+ for method_name , method_details in class_details .callable_declarations .items ():
897
+ if len (method_details .crud_operations ) > 0 :
898
+ crud_operations .append ({class_name : class_details , method_name : method_details , "crud_operations" : method_details .crud_operations })
899
+ return crud_operations
900
+
901
+ def get_all_read_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
902
+ """Returns a list of all read operations in the source code.
903
+
904
+ Raises:
905
+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
906
+
907
+ Returns:
908
+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]:: A list of all read operations in the source code.
909
+ """
910
+ crud_read_operations = []
911
+ for class_name , class_details in self .get_all_classes ().items ():
912
+ for method_name , method_details in class_details .callable_declarations .items ():
913
+ if len (method_details .crud_operations ) > 0 :
914
+ crud_read_operations .append (
915
+ {
916
+ class_name : class_details ,
917
+ method_name : method_details ,
918
+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .READ ],
919
+ }
920
+ )
921
+ return crud_read_operations
922
+
923
+ def get_all_create_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
924
+ """Returns a list of all create operations in the source code.
925
+
926
+ Raises:
927
+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
928
+
929
+ Returns:
930
+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all create operations in the source code.
931
+ """
932
+ crud_create_operations = []
933
+ for class_name , class_details in self .get_all_classes ().items ():
934
+ for method_name , method_details in class_details .callable_declarations .items ():
935
+ if len (method_details .crud_operations ) > 0 :
936
+ crud_create_operations .append (
937
+ {
938
+ class_name : class_details ,
939
+ method_name : method_details ,
940
+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .CREATE ],
941
+ }
942
+ )
943
+ return crud_create_operations
944
+
945
+ def get_all_update_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
946
+ """Returns a list of all update operations in the source code.
947
+
948
+ Raises:
949
+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
950
+
951
+ Returns:
952
+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all update operations in the source code.
953
+ """
954
+ crud_update_operations = []
955
+ for class_name , class_details in self .get_all_classes ().items ():
956
+ for method_name , method_details in class_details .callable_declarations .items ():
957
+ if len (method_details .crud_operations ) > 0 :
958
+ crud_update_operations .append (
959
+ {
960
+ class_name : class_details ,
961
+ method_name : method_details ,
962
+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .UPDATE ],
963
+ }
964
+ )
965
+
966
+ return crud_update_operations
967
+
968
+ def get_all_delete_operations (self ) -> List [Dict [str , Union [JType , JCallable , List [JCRUDOperation ]]]]:
969
+ """Returns a list of all delete operations in the source code.
970
+
971
+ Raises:
972
+ NotImplementedError: Raised when current AnalysisEngine does not support this function.
973
+
974
+ Returns:
975
+ List[Dict[str, Union[str, JCallable, List[CRUDOperation]]]]: A list of all delete operations in the source code.
976
+ """
977
+ crud_delete_operations = []
978
+ for class_name , class_details in self .get_all_classes ().items ():
979
+ for method_name , method_details in class_details .callable_declarations .items ():
980
+ if len (method_details .crud_operations ) > 0 :
981
+ crud_delete_operations .append (
982
+ {
983
+ class_name : class_details ,
984
+ method_name : method_details ,
985
+ "crud_operations" : [crud_op for crud_op in method_details .crud_operations if crud_op .operation_type == CRUDOperationType .DELETE ],
986
+ }
987
+ )
988
+ return crud_delete_operations
0 commit comments