8000 Merge pull request #85 from codellm-devkit/update-entrypoints-from-la… · codellm-devkit/python-sdk@2589257 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2589257

Browse files
authored
Merge pull request #85 from codellm-devkit/update-entrypoints-from-latest-codeanalyzer
Update get entrypoint classes and methods
2 parents 3891817 + a4f1546 commit 2589257

File tree

10 files changed

+141
-177
lines changed

10 files changed

+141
-177
lines changed

cldk/analysis/c/clang/clang_analyzer.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
from clang.cindex import Config
44
from pathlib import Path
55
from typing import List, Optional
6-
from cldk.models.c import CFunction, CMacro, CCallSite, CTranslationUnit, CApplication
6+
from cldk.models.c import CFunction, CCallSite, CTranslationUnit, CApplication
77
import logging
8-
from ipdb import set_trace
98

109
from cldk.models.c.models import CInclude, CParameter, CVariable, StorageClass
1110

@@ -34,14 +33,15 @@ def find_libclang() -> str:
3433

3534
# On Linux, we check various common installation paths
3635
elif system == "Linux":
36+
from pathlib import Path
37+
38+
lib_paths = [Path("/usr/lib"), Path("/usr/lib64")]
3739
possible_paths = [
38-
"/usr/lib/llvm-14/lib/libclang.so",
39-
"/usr/lib/llvm-13/lib/libclang.so",
40-
"/usr/lib/llvm-12/lib/libclang.so",
41-
"/usr/lib/x86_64-linux-gnu/libclang-14.so.1",
42-
"/usr/lib/libclang.so",
40+
str(p) for base in lib_paths if base.exists()
41+
for p in base.rglob("libclang*.so*")
4342
]
44-
install_instructions = "Install libclang using: sudo apt-get install libclang-dev"
43+
44+
install_instructions = "Install libclang development package using your system's package manager"
4545
else:
4646
raise RuntimeError(f"Unsupported operating system: {system}")
4747

cldk/analysis/java/codeanalyzer/codeanalyzer.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515
################################################################################
16+
from itertools import chain, groupby
1617
from pdb import set_trace
1718
import re
1819
import json
@@ -863,20 +864,20 @@ def get_class_call_graph(self, qualified_class_name: str, method_name: str | Non
863864
return graph_edges
864865

865866
def get_all_entry_point_methods(self) -> Dict[str, Dict[str, JCallable]]:
866-
"""Returns a dictionary of all entry point methods in the Java code with
867-
qualified class name as the key and a dictionary of methods in that class as the value.
867+
"""Returns a dictionary of all entry point methods in the Java code.
868868
869869
Returns:
870-
Dict[str, Dict[str, JCallable]]: A dictionary of dictionaries of entry point
871-
methods in the Java code.
870+
Dict[str, Dict[str, JCallable]]: A dictionary of all entry point methods in the Java code.
872871
"""
873-
874-
class_method_dict = {}
875-
class_dict = self.get_all_classes()
876-
for k, v in class_dict.items():
877-
entry_point_methods = {method_name: callable_decl for (method_name, callable_decl) in v.callable_declarations.items() if callable_decl.is_entry_point is True}
878-
class_method_dict[k] = entry_point_methods
879-
return class_method_dict
872+
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()
876+
)
877+
return {
878+
typename: {method: callable for _, method, callable in group}
879+
for typename, group in groupby(methods, key=lambda x: x[0])
880+
}
880881

881882
def get_all_entry_point_classes(self) -> Dict[str, JType]:
882883
"""Returns a dictionary of all entry point classes in the Java code.
@@ -886,8 +887,8 @@ def get_all_entry_point_classes(self) -> Dict[str, JType]:
886887
with qualified class names as keys.
887888
"""
888889

889-
class_dict = {}
890-
symtab = self.get_symbol_table()
891-
for val in symtab.values():
892-
class_dict.update((k, v) for k, v in val.type_declarations.items() if v.is_entry_point is True)
893-
return class_dict
890+
return {
891+
typename: klass
892+
for typename, klass in self.get_all_classes().items()
893+
if klass.is_entrypoint_class
894+
}

cldk/models/java/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,4 @@
2626
JGraphEdges,
2727
)
2828

29-
from .constants_namespace import ConstantsNamespace
30-
3129
__all__ = ["JApplication", "JCallable", "JType", "JCompilationUnit", "JGraphEdges", "ConstantsNamespace"]

cldk/models/java/constants_namespace.py

Lines changed: 0 additions & 41 deletions
This file was deleted.

cldk/models/java/models.py

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@
2323
from pdb import set_trace
2424
from pydantic import BaseModel, field_validator, model_validator
2525

26-
from .constants_namespace import ConstantsNamespace
27-
28-
constants = ConstantsNamespace()
29-
context_concrete_class = ContextVar("context_concrete_class") # context var to store class concreteness
3026
_CALLABLES_LOOKUP_TABLE = dict()
3127

3228

@@ -179,6 +175,7 @@ class JCallable(BaseModel):
179175
referenced_types: List[str]
180176
accessed_fields: List[str]
181177
call_sites: List[JCallSite]
178+
is_entrypoint: bool = False
182179
variable_declarations: List[JVariableDeclaration]
183180
cyclomatic_complexity: int | None
184181

@@ -188,33 +185,6 @@ def __hash__(self):
188185
"""
189186
return hash(self.declaration)
190187

191-
@model_validator(mode="after")
192-
def detect_entrypoint_method(self):
193-
# check first if the class in which this method exists is concrete or not, by looking at the context var
194-
if context_concrete_class.get():
195-
# convert annotations to the form GET, POST even if they are @GET or @GET('/ID') etc.
196-
annotations_cleaned = [match for annotation in self.annotations for match in re.findall(r"@(.*?)(?:\(|$)", annotation)]
197-
198-
param_type_list = [val.type for val in self.parameters]
199-
# check the param types against known servlet param types
200-
if any(substring in string for substring in param_type_list for string in constants.ENTRY_POINT_METHOD_SERVLET_PARAM_TYPES):
201-
# check if this method is over-riding (only methods that override doGet / doPost etc. will be flagged as first level entry points)
202-
if "Override" in annotations_cleaned:
203-
self.is_entry_point = True
204-
return self
205-
206-
# now check the cleaned annotations against known javax ws annotations
207-
if any(substring in string for substring in annotations_cleaned for string in constants.ENTRY_POINT_METHOD_JAVAX_WS_ANNOTATIONS):
208-
self.is_entry_point = True
209-
return self
210-
211-
# check the cleaned annotations against known spring rest method annotations
212-
if any(substring in string for substring in annotations_cleaned for string in constants.ENTRY_POINT_METHOD_SPRING_ANNOTATIONS):
213-
self.is_entry_point = True
214-
return self
215-
return self
216-
217-
218188
class JType(BaseModel):
219189
"""Represents a Java class or interface.
220190
@@ -257,44 +227,12 @@ class JType(BaseModel):
257227
modifiers: List[str] = []
258228
annotations: List[str] = []
259229
parent_type: str
230+
is_entrypoint_class: bool = False
260231
nested_type_declerations: List[str] = []
261232
callable_declarations: Dict[str, JCallable] = {}
262233
field_declarations: List[JField] = []
263234
enum_constants: List[JEnumConstant] = []
264235

265-
# first get the data in raw form and check if the class is concrete or not, before any model validation is done
266-
# for this we assume if a class is not an interface or abstract it is concrete
267-
# for abstract classes we will check the modifiers
268-
@model_validator(mode="before")
269-
def check_concrete_class(cls, values):
270-
"""Detects if the class is concrete based on its properties."""
271-
values["is_concrete_class"] = False
272-
if values.get("is_class_or_interface_declaration") and not values.get("is_interface"):
273-
if "abstract" not in values.get("modifiers"):
274-
values["is_concrete_class"] = True
275-
# since the methods in this class need access to the concrete class flag,
276-
# we will store this in a context var - this is a hack
277-
token = context_concrete_class.set(values["is_concrete_class"])
278-
return values
279-
280-
# after model validation is done we populate the is_entry_point flag by checking
281-
# if the class extends or implements known servlet classes
282-
@model_validator(mode="after")
283-
def check_concrete_entry_point(self):
284-
"""Detects if the class is entry point based on its properties."""
285-
if self.is_concrete_class:
286-
if any(substring in string for substring in (self.extends_list + self.implements_list) for string in constants.ENTRY_POINT_SERVLET_CLASSES):
287-
self.is_entry_point = True
288-
return self
289-
# Handle spring classes
290-
# clean annotations - take out @ and any paranehesis along with info in them.
291-
annotations_cleaned = [match for annotation in self.annotations for match in re.findall(r"@(.*?)(?:\(|$)", annotation)]
292-
if any(substring in string for substring in annotations_cleaned for string in constants.ENTRY_POINT_CLASS_SPRING_ANNOTATIONS):
293-
self.is_entry_point = True
294-
return self
295-
# context_concrete.reset()
296-
return self
297-
298236

299237
class JCompilationUnit(BaseModel):
300238
"""Represents a compilation unit in Java.

0 commit comments

Comments
 (0)
0