@@ -14,6 +14,7 @@ def __init__ (self, language):
1414 self .generateSinks = False
1515 self .generateSources = False
1616 self .generateSummaries = False
17+ self .generateNegativeSummaries = False
1718 self .dryRun = False
1819
1920
@@ -25,11 +26,13 @@ def printHelp(self):
2526The files will be placed in `{ self .language } /ql/lib/semmle/code/{ self .language } /frameworks/<outputQll>` where
2627outputQll is the name (and path) of the output QLL file. Usually, models are grouped by their
2728respective frameworks.
29+ If negative summaries are produced a file prefixed with `Negative` will be generated and stored in the same folder.
2830
2931Which models are generated is controlled by the flags:
3032 --with-sinks
3133 --with-sources
3234 --with-summaries
35+ --with-negative-summaries
3336If none of these flags are specified, all models are generated.
3437
3538 --dry-run: Only run the queries, but don't write to file.
@@ -46,12 +49,14 @@ def setenvironment(self, target, database):
4649 self .codeQlRoot = subprocess .check_output (["git" , "rev-parse" , "--show-toplevel" ]).decode ("utf-8" ).strip ()
4750 if not target .endswith (".qll" ):
4851 target += ".qll"
49- self .filename = os .path .basename (target )
50- self .shortname = self .filename [:- 4 ]
52+ filename = os .path .basename (target )
53+ dirname = os .path .dirname (target )
54+ self .shortname = filename [:- 4 ]
5155 self .database = database
5256 self .generatedFrameworks = os .path .join (
5357 self .codeQlRoot , f"{ self .language } /ql/lib/semmle/code/{ self .language } /frameworks/" )
54- self .frameworkTarget = os .path .join (self .generatedFrameworks , target )
58+ self .frameworkTarget = os .path .join (self .generatedFrameworks , dirname , filename )
59+ self .negativeFrameworkTarget = os .path .join (self .generatedFrameworks , dirname , "Negative" + filename )
5560
5661 self .workDir = tempfile .mkdtemp ()
5762 os .makedirs (self .generatedFrameworks , exist_ok = True )
@@ -76,12 +81,16 @@ def make(language):
7681 sys .argv .remove ("--with-summaries" )
7782 generator .generateSummaries = True
7883
84+ if "--with-negative-summaries" in sys .argv :
85+ sys .argv .remove ("--with-negative-summaries" )
86+ generator .generateNegativeSummaries = True
87+
7988 if "--dry-run" in sys .argv :
8089 sys .argv .remove ("--dry-run" )
8190 generator .dryRun = True
8291
83- if not generator .generateSinks and not generator .generateSources and not generator .generateSummaries :
84- generator .generateSinks = generator .generateSources = generator .generateSummaries = True
92+ if not generator .generateSinks and not generator .generateSources and not generator .generateSummaries and not generator . generateNegativeSummaries :
93+ generator .generateSinks = generator .generateSources = generator .generateSummaries = generator . generateNegativeSummaries = True
8594
8695 if len (sys .argv ) != 3 :
8796 generator .printHelp ()
@@ -181,26 +190,51 @@ def makeContent(self):
181190
182191 """
183192
193+ def makeNegativeContent (self ):
194+ if self .generateNegativeSummaries :
195+ negativeSummaryRows = self .runQuery ("negative summary models" , "CaptureNegativeSummaryModels.ql" )
196+ negativeSummaryCsv = self .asCsvModel ("NegativeSummaryModelCsv" , "NegativeSummary" , negativeSummaryRows )
197+ else :
198+ negativeSummaryCsv = ""
184199
185- def save (self , content ):
186- with open (self .frameworkTarget , "w" ) as frameworkQll :
187- frameworkQll .write (content )
200+ return f"""
201+ /**
202+ * THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT.
203+ * Definitions of negative summaries in the { self .shortname } framework.
204+ */
188205
189- cmd = ['codeql' , 'query' , 'format' , '--in-place' , self .frameworkTarget ]
206+ import { self .language }
207+ private import semmle.code.{ self .language } .dataflow.ExternalFlow
208+
209+ { negativeSummaryCsv }
210+
211+ """
212+
213+
214+ def save (self , content , target ):
215+ with open (target , "w" ) as targetQll :
216+ targetQll .write (content )
217+
218+ cmd = ['codeql' , 'query' , 'format' , '--in-place' , target ]
190219 ret = subprocess .call (cmd )
191220 if ret != 0 :
192221 print ("Failed to format query. Failed command was: " + shlex .join (cmd ))
193222 sys .exit (1 )
194223
195224 print ("" )
196- print ("CSV model written to " + self . frameworkTarget )
225+ print ("CSV model written to " + target )
197226
198227
199228 def run (self ):
200229 content = self .makeContent ()
230+ negativeContent = self .makeNegativeContent ()
201231
202232 if self .dryRun :
203233 print ("CSV Models generated, but not written to file." )
204234 sys .exit (0 )
205235
206- self .save (content )
236+ if self .generateSinks or self .generateSinks or self .generateSummaries :
237+ self .save (content , self .frameworkTarget )
238+
239+ if self .generateNegativeSummaries :
240+ self .save (negativeContent , self .negativeFrameworkTarget )
0 commit comments