@@ -89,6 +89,15 @@ extensible predicate summaryModel(
8989 QlBuiltins:: ExtensionId madId
9090) ;
9191
92+ /**
93+ * Holds if a neutral model of kind `kind` exists for the function with canonical path `path`. The
94+ * only effect of a neutral model is to prevent generated and inherited models of the corresponding
95+ * `kind` (`source`, `sink` or `summary`) from being applied.
96+ */
97+ extensible predicate neutralModel (
98+ string path , string kind , string provenance , QlBuiltins:: ExtensionId madId
99+ ) ;
100+
92101/**
93102 * Holds if the given extension tuple `madId` should pretty-print as `model`.
94103 *
@@ -109,6 +118,11 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
109118 summaryModel ( path , input , output , kind , _, madId ) and
110119 model = "Summary: " + path + "; " + input + "; " + output + "; " + kind
111120 )
121+ or
122+ exists ( string path , string kind |
123+ neutralModel ( path , kind , _, madId ) and
124+ model = "Neutral: " + path + "; " + kind
125+ )
112126}
113127
114128private predicate summaryModel (
@@ -133,16 +147,19 @@ private predicate summaryModelRelevant(
133147) {
134148 summaryModel ( f , input , output , kind , provenance , isInherited , madId ) and
135149 // Only apply generated or inherited models to functions in library code and
136- // when no strictly better model exists
137- if provenance .isGenerated ( ) or isInherited = true
138- then
139- not f .fromSource ( ) and
140- not exists ( Provenance other | summaryModel ( f , _, _, _, other , false , _) |
141- provenance .isGenerated ( ) and other .isManual ( )
142- or
143- provenance = other and isInherited = true
144- )
145- else any ( )
150+ // when no strictly better model (or neutral model) exists
151+ (
152+ if provenance .isGenerated ( ) or isInherited = true
153+ then
154+ not f .fromSource ( ) and
155+ not exists ( Provenance other | summaryModel ( f , _, _, _, other , false , _) |
156+ provenance .isGenerated ( ) and other .isManual ( )
157+ or
158+ provenance = other and isInherited = true
159+ ) and
160+ not neutralModel ( f .getCanonicalPath ( ) , "summary" , _, _)
161+ else any ( )
162+ )
146163}
147164
148165private class SummarizedCallableFromModel extends SummarizedCallable:: Range {
@@ -180,6 +197,11 @@ private class FlowSourceFromModel extends FlowSource::Range {
180197 exists ( QlBuiltins:: ExtensionId madId |
181198 sourceModel ( path , output , kind , provenance , madId ) and
182199 model = "MaD:" + madId .toString ( )
200+ ) and
201+ // Only apply generated models when no neutral model exists
202+ not (
203+ provenance .isGenerated ( ) and
204+ neutralModel ( path , "source" , _, _)
183205 )
184206 }
185207}
@@ -196,6 +218,11 @@ private class FlowSinkFromModel extends FlowSink::Range {
196218 exists ( QlBuiltins:: ExtensionId madId |
197219 sinkModel ( path , input , kind , provenance , madId ) and
198220 model = "MaD:" + madId .toString ( )
221+ ) and
222+ // Only apply generated models when no neutral model exists
223+ not (
224+ provenance .isGenerated ( ) and
225+ neutralModel ( path , "sink" , _, _)
199226 )
200227 }
201228}
0 commit comments