@@ -796,7 +796,7 @@ def __call_graph_using_symbol_table(self,
796796 def __raw_call_graph_using_symbol_table_target_method (self ,
797797 target_class_name : str ,
798798 target_method_signature : str ,
799- cg : list [ JGraphEdgesST ] = [] ) -> list [JGraphEdgesST ]:
799+ cg = None ) -> list [JGraphEdgesST ]:
800800 """
801801 Generates call graph using symbol table information given the target method and target class
802802 Args:
@@ -807,6 +807,8 @@ def __raw_call_graph_using_symbol_table_target_method(self,
807807 Returns:
808808 list[JGraphEdgesST]: list of call edges
809809 """
810+ if cg is None :
811+ cg = []
810812 target_method_details = self .get_method (qualified_class_name = target_class_name ,
811813 method_signature = target_method_signature )
812814 for class_name in self .get_all_classes ():
@@ -840,18 +842,13 @@ def __raw_call_graph_using_symbol_table_target_method(self,
840842 source_method_details = self .get_method (method_signature = method ,
841843 qualified_class_name = class_name )
842844 source_class = class_name
843- # private calls
844- if call_site .is_private :
845- if callee_signature == target_method_signature and class_name == target_class_name :
846- source_method_details = self .get_method (method_signature = method ,
847- qualified_class_name = class_name )
848- source_class = class_name
849- if source_class == '' :
850- # check if any method exists with the signature in the class even if the receiver type is blank
851- if callee_signature == target_method_signature and class_name == target_class_name :
852- source_method_details = self .get_method (method_signature = method ,
853- qualified_class_name = class_name )
854- source_class = class_name
845+ else :
846+ # check if any method exists with the signature in the class even if the receiver type is blank
847+ if callee_signature == target_method_signature and class_name == target_class_name :
848+ source_method_details = self .get_method (method_signature = method ,
849+ qualified_class_name = class_name )
850+ source_class = class_name
851+
855852 if source_class != '' and source_method_details is not None :
856853 source : JMethodDetail
857854 target : JMethodDetail
@@ -873,7 +870,7 @@ def __raw_call_graph_using_symbol_table_target_method(self,
873870 def __raw_call_graph_using_symbol_table (self ,
874871 qualified_class_name : str ,
875872 method_signature : str ,
876- cg : list [ JGraphEdgesST ] = [] ) -> list [JGraphEdgesST ]:
873+ cg = None ) -> list [JGraphEdgesST ]:
877874 """
878875 Generates call graph using symbol table information
879876 Args:
@@ -884,69 +881,71 @@ def __raw_call_graph_using_symbol_table(self,
884881 Returns:
885882 list[JGraphEdgesST]: list of call edges
886883 """
884+ if cg is None :
885+ cg = []
887886 source_method_details = self .get_method (qualified_class_name = qualified_class_name ,
888887 method_signature = method_signature )
889- if source_method_details is not None :
890- for call_site in source_method_details . call_sites :
891- target_method_details = None
892- target_class = ''
893- callee_signature = ''
894- if call_site . callee_signature ! = '' :
895- pattern = r'\b(?:[a-zA-Z_][\w\.]*\.)+([a-zA-Z_][\w]*)\b|<[^>]*> '
896-
897- # Find the part within the parentheses
898- start = call_site . callee_signature . find ( '(' ) + 1
899- end = call_site . callee_signature . rfind ( ')' )
900-
901- # Extract the elements inside the parentheses
902- elements = call_site . callee_signature [ start : end ]. split ( ',' )
903-
904- # Apply the regex to each element
905- simplified_elements = [ re . sub ( pattern , r'\1' , element . strip ()) for element in elements ]
906-
907- # Reconstruct the string with simplified elements
908- callee_signature = f" { call_site . callee_signature [: start ] } { ', ' . join ( simplified_elements ) } { call_site . callee_signature [ end :] } "
909-
910- if call_site . receiver_type != "" :
911- # call to any class
912- if self . get_class ( qualified_class_name = call_site . receiver_type ):
913- tmd = self . get_method ( method_signature = callee_signature ,
914- qualified_class_name = call_site . receiver_type )
915- if tmd is not None :
916- target_method_details = tmd
917- target_class = call_site .receiver_type
918- else :
919- # private calls
920- if call_site . is_private :
921- target_method_details = self . get_method ( qualified_class_name = qualified_class_name ,
922- method_signature = callee_signature )
923- target_class = qualified_class_name
924- if target_class == '' :
925- # check if any method exists with the signature in the class even if the receiver type is blank
926- tmd = self . get_method ( method_signature = callee_signature ,
927- qualified_class_name = qualified_class_name )
928- if tmd is not None :
929- target_method_details = tmd
930- target_class = qualified_class_name
931- if target_class != '' and target_method_details is not None :
932- source : JMethodDetail
933- target : JMethodDetail
934- type : str
935- weight : str
936- call_edge = JGraphEdgesST (
937- source = JMethodDetail (method_declaration = source_method_details .declaration ,
938- klass = qualified_class_name ,
939- method = source_method_details ),
940- target = JMethodDetail (method_declaration = target_method_details .declaration ,
941- klass = target_class ,
942- method = target_method_details ),
943- type = 'CALL_DEP' ,
944- weight = '1' )
945- if call_edge not in cg :
946- cg .append (call_edge )
947- cg = self .__raw_call_graph_using_symbol_table (qualified_class_name = target_class ,
948- method_signature = target_method_details .signature ,
949- cg = cg )
888+ # If the provided classname and method signature combination do not exist
889+ if source_method_details is None :
890+ return cg
891+ for call_site in source_method_details . call_sites :
892+ target_method_details = None
893+ target_class = ''
894+ callee_signature = ' '
895+ if call_site . callee_signature != '' :
896+ # Currently the callee signature returns the fully qualified type, whereas
897+ # the key for JCallable does not. The below logic converts the fully qualified signature
898+ # to the desider format. Only limitation is the nested generic type.
899+ pattern = r'\b(?:[a-zA-Z_][\w\.]*\.)+([a-zA-Z_][\w]*)\b|<[^>]*>'
900+
901+ # Find the part within the parentheses
902+ start = call_site . callee_signature . find ( '(' ) + 1
903+ end = call_site . callee_signature . rfind ( ')' )
904+
905+ # Extract the elements inside the parentheses
906+ elements = call_site . callee_signature [ start : end ]. split ( ',' )
907+
908+ # Apply the regex to each element
909+ simplified_elements = [ re . sub ( pattern , r'\1' , element . strip ()) for element in elements ]
910+
911+ # Reconstruct the string with simplified elements
912+ callee_signature = f" { call_site . callee_signature [: start ] } { ', ' . join ( simplified_elements ) } { call_site . callee_signature [ end :] } "
913+
914+ if call_site . receiver_type != "" :
915+ # call to any class
916+ if self . get_class ( qualified_class_name = call_site .receiver_type ):
917+ tmd = self . get_method ( method_signature = callee_signature ,
918+ qualified_class_name = call_site . receiver_type )
919+ if tmd is not None :
920+ target_method_details = tmd
921+ target_class = call_site . receiver_type
922+ else :
923+ # check if any method exists with the signature in the class even if the receiver type is blank
924+ tmd = self . get_method ( method_signature = callee_signature ,
925+ qualified_class_name = qualified_class_name )
926+ if tmd is not None :
927+ target_method_details = tmd
928+ target_class = qualified_class_name
929+
930+ if target_class != '' and target_method_details is not None :
931+ source : JMethodDetail
932+ target : JMethodDetail
933+ type : str
934+ weight : str
935+ call_edge = JGraphEdgesST (
936+ source = JMethodDetail (method_declaration = source_method_details .declaration ,
937+ klass = qualified_class_name ,
938+ method = source_method_details ),
939+ target = JMethodDetail (method_declaration = target_method_details .declaration ,
940+ klass = target_class ,
941+ method = target_method_details ),
942+ type = 'CALL_DEP' ,
943+ weight = '1' )
944+ if call_edge not in cg :
945+ cg .append (call_edge )
946+ cg = self .__raw_call_graph_using_symbol_table (qualified_class_name = target_class ,
947+ method_signature = target_method_details .signature ,
948+ cg = cg )
950949 return cg
951950
952951 def get_class_call_graph (self , qualified_class_name : str , method_name : str | None = None ) -> List [
0 commit comments