@@ -96,11 +96,16 @@ def get_ql_ipa_class(cls: schema.Class):
9696 if cls .ipa and cls .ipa .from_class is not None :
9797 source = cls .ipa .from_class
9898 _final_db_class_lookup .setdefault (source , ql .Synth .FinalClassDb (source )).subtract_type (cls .name )
99- return ql .Synth .FinalClassDerivedIpa (name = cls .name , params = [ql .Synth .Param ("id" , _to_db_type (source ))])
99+ return ql .Synth .FinalClassDerivedIpa (name = cls .name ,
100+ params = [ql .Synth .Param ("id" , _to_db_type (source ))])
100101 if cls .ipa and cls .ipa .on_arguments is not None :
101- return ql .Synth .FinalClassFreshIpa (name = cls .name , params = [ql .Synth .Param (k , _to_db_type (v )) for k , v in
102- cls .ipa .on_arguments .items ()])
103- return _final_db_class_lookup .setdefault (cls .name , ql .Synth .FinalClassDb (cls .name ))
102+ return ql .Synth .FinalClassFreshIpa (name = cls .name ,
103+ params = [ql .Synth .Param (k , _to_db_type (v ))
104+ for k , v in cls .ipa .on_arguments .items ()])
105+ ret = ql .Synth .FinalClassDb (name = cls .name ,
106+ params = [ql .Synth .Param ("id" , _to_db_type (cls .name ))])
107+ _final_db_class_lookup [cls .name ] = ret
108+ return ret
104109
105110
106111def get_import (file : pathlib .Path , swift_dir : pathlib .Path ):
@@ -119,14 +124,10 @@ def get_classes_used_by(cls: ql.Class):
119124 return sorted (set (t for t in get_types_used_by (cls ) if t [0 ].isupper ()))
120125
121126
122- _generated_stub_re = re .compile (r"\n*private import .*\n+("
123- r"class \w+ extends \w+ \{[ \n]?\}"
124- "|"
125- r"predicate construct\w+\(.*?\) \{ none\(\) \}"
126- ")" , re .MULTILINE )
127+ _generated_stub_re = re .compile (r"\n*private import .*\n+class \w+ extends \w+ \{[ \n]?\}" , re .MULTILINE )
127128
128129
129- def _is_generated_stub (file ) :
130+ def _is_generated_stub (file : pathlib . Path ) -> bool :
130131 with open (file ) as contents :
131132 for line in contents :
132133 if not line .startswith ("// generated" ):
@@ -135,12 +136,14 @@ def _is_generated_stub(file):
135136 else :
136137 # no lines
137138 return False
138- # one line already read, if we can read 5 other we are past the normal stub generation
139- line_threshold = 5
140- first_lines = list (itertools .islice (contents , line_threshold ))
141- if len (first_lines ) == line_threshold or not _generated_stub_re .match ("" .join (first_lines )):
142- raise ModifiedStubMarkedAsGeneratedError (
143- f"{ file .name } stub was modified but is still marked as generated" )
139+ # we still do not detect modified synth constructors
140+ if not file .name .endswith ("Constructor.qll" ):
141+ # one line already read, if we can read 5 other we are past the normal stub generation
142+ line_threshold = 5
143+ first_lines = list (itertools .islice (contents , line_threshold ))
144+ if len (first_lines ) == line_threshold or not _generated_stub_re .match ("" .join (first_lines )):
145+ raise ModifiedStubMarkedAsGeneratedError (
146+ f"{ file .name } stub was modified but is still marked as generated" )
144147 return True
145148
146149
@@ -268,20 +271,24 @@ def generate(opts, renderer):
268271 final_ipa_types = []
269272 non_final_ipa_types = []
270273 constructor_imports = []
274+ ipa_constructor_imports = []
271275 for cls in sorted (data .classes .values (), key = lambda cls : (cls .dir , cls .name )):
272276 ipa_type = get_ql_ipa_class (cls )
273277 if ipa_type .is_final :
274278 final_ipa_types .append (ipa_type )
275- if ipa_type .is_ipa and ipa_type .has_params :
276- stub_file = stub_out / cls .dir / f"{ cls .name } Constructor.qll"
277- if not stub_file .is_file () or _is_generated_stub (stub_file ):
278- renderer .render (ql .Synth .ConstructorStub (ipa_type ), stub_file )
279- constructor_imports .append (get_import (stub_file , opts .swift_dir ))
279+ stub_file = stub_out / cls .dir / f"{ cls .name } Constructor.qll"
280+ if not stub_file .is_file () or _is_generated_stub (stub_file ):
281+ renderer .render (ql .Synth .ConstructorStub (ipa_type ), stub_file )
282+ constructor_import = get_import (stub_file , opts .swift_dir )
283+ constructor_imports .append (constructor_import )
284+ if ipa_type .is_ipa :
285+ ipa_constructor_imports .append (constructor_import )
280286 else :
281287 non_final_ipa_types .append (ipa_type )
282288
283289 renderer .render (ql .Synth .Types (schema .root_class_name , final_ipa_types , non_final_ipa_types ), out / "Synth.qll" )
284290 renderer .render (ql .ImportList (constructor_imports ), out / "SynthConstructors.qll" )
291+ renderer .render (ql .ImportList (ipa_constructor_imports ), out / "PureSynthConstructors.qll" )
285292
286293 renderer .cleanup (existing )
287294 if opts .ql_format :
0 commit comments