22from typing import Optional
33
44from pytype import config
5- from pytype .pytd .pytd import CallableType
5+ from pytype .pytd .pytd import CallableType , GenericType , ClassType , UnionType , NothingType , TypeParameter
66from pytype .tools .annotate_ast .annotate_ast import AnnotateAstVisitor , PytypeError , infer_types
77
88from ..java import JavaType
99
1010
1111class PythonTypeMapping :
1212 __enabled = False
13+ __cache : dict [str , JavaType ] = {}
1314
1415 def __init__ (self , source : str ):
15- pytype_options = config .Options .create (python_version = '3.12' , check = False , precise_return = True , output_debug = False )
16+ pytype_options = config .Options .create (python_version = '3.12' , check = False , precise_return = True ,
17+ output_debug = False )
1618 try :
1719 self ._source_with_types = infer_types (source , pytype_options ) if self .__enabled else None
1820 except PytypeError :
1921 self ._source_with_types = None
2022
2123 def resolve_types (self , node ):
2224 if self ._source_with_types :
23- type_visitor = AnnotateAstVisitor (self ._source_with_types , ast )
25+ type_visitor = MyAnnotateAstVisitor (self ._source_with_types , ast )
2426 type_visitor .visit (node )
2527
2628 def type (self , node ) -> Optional [JavaType ]:
29+ if hasattr (node , 'resolved_annotation' ) and (result := self .__cache .get (node .resolved_annotation )):
30+ return result
2731 if isinstance (node , ast .Constant ):
2832 if isinstance (node .value , str ):
2933 return JavaType .Primitive .String
@@ -45,11 +49,59 @@ def method_invocation_type(self, node) -> Optional[JavaType.Method]:
4549 return self .__map_type (node .func .resolved_type , node ) if self .__enabled else None
4650
4751 def __map_type (self , type , node ):
48- if isinstance (type , CallableType ):
52+ signature = get_type_string (type )
53+ result = self .__cache .get (signature )
54+ if result :
55+ return result
56+
57+ if isinstance (type , ClassType ):
58+ self .__cache [signature ] = (result := JavaType .Class ())
59+ result ._kind = JavaType .FullyQualified .Kind .Class
60+ result ._fully_qualified_name = type .name
61+ result ._interfaces = [self .__map_type (i , node ) for i in type .cls .bases ]
62+ elif isinstance (type , CallableType ):
4963 if isinstance (node , ast .Name ):
5064 name = node .id
5165 elif isinstance (node , ast .Call ) and isinstance (node .func , ast .Attribute ):
5266 name = node .func .attr
5367 else :
5468 name = ''
5569 return JavaType .Method (_name = name )
70+ elif isinstance (type , GenericType ):
71+ self .__cache [signature ] = (result := JavaType .Parameterized )
72+ result ._type = self .__map_type (type .base_type , node )
73+ result ._type_parameters = [self .__map_type (t , node ) for t in type .parameters ]
74+ elif isinstance (type , NothingType ):
75+ self .__cache [signature ] = (result := JavaType .Unknown ())
76+ return result
77+
78+
79+ def get_type_string (typ ):
80+ if typ is None :
81+ return "None"
82+ elif isinstance (typ , ClassType ):
83+ return typ .name
84+ elif isinstance (typ , GenericType ):
85+ base = get_type_string (typ .base_type )
86+ params = [get_type_string (p ) for p in typ .parameters ]
87+ return f"{ base } [{ ', ' .join (params )} ]"
88+ elif isinstance (typ , CallableType ):
89+ args = [get_type_string (a ) for a in typ .args ]
90+ ret = get_type_string (typ .ret )
91+ return f"[{ ', ' .join (args )} ] -> { ret } "
92+ elif isinstance (typ , UnionType ):
93+ types = [get_type_string (t ) for t in typ .type_list ]
94+ return '|' .join (types )
95+ elif isinstance (typ , TypeParameter ):
96+ types = [get_type_string (t ) for t in typ .constraints ]
97+ return f"{ typ .full_name } { [{', ' .join (types )}] if types else '' } "
98+ elif hasattr (typ , "name" ):
99+ return typ .name
100+ else :
101+ return str (typ )
102+
103+
104+ class MyAnnotateAstVisitor (AnnotateAstVisitor ):
105+ # TODO check if we really should have this
106+ def visit_Call (self , node ):
107+ self ._maybe_annotate (node )
0 commit comments