Skip to content

Shared: Model generator cleanup. #19311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 28, 2025
Merged
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2a8fe53
Shared: Remove --with-mixed-summaries logic.
michaelnebel Apr 15, 2025
fa5162f
Shared: Remove the backwards compatbility flag.
michaelnebel Apr 15, 2025
ae70c76
Shared: Use the CaptureSummaryModels instead of CaptureMixedSummaryMo…
michaelnebel Apr 15, 2025
2357a69
Shared: Remove the --with-mixed-neutrals logic.
michaelnebel Apr 15, 2025
f78be91
Shared: Re-factor the model generator and put the heuristic queries i…
michaelnebel Apr 15, 2025
2a0097e
C#/Java/Rust: Use Mixed flow from capture summary models queries and …
michaelnebel Apr 15, 2025
7801fc3
C#: Re-factor tests to use the new implementations.
michaelnebel Apr 15, 2025
da99c75
C#: Rename some of the model generator tests.
michaelnebel Apr 15, 2025
539a06d
C#: Re-factor the heuristic summary test to use heuristic-summary tag…
michaelnebel Apr 15, 2025
1d6c367
C#: Change the capture neutral model test to use the content/heuristi…
michaelnebel Apr 16, 2025
08f7caa
Java: Adjust model generator test cases to the new implementation.
michaelnebel Apr 16, 2025
7e51dae
Java: Change the heuristic summary test tag to heuristic-summary.
michaelnebel Apr 16, 2025
71d0409
Java: Convert the model generator neutral test to use the combined ne…
michaelnebel Apr 16, 2025
2155396
Rust: Adjust tests.
michaelnebel Apr 16, 2025
32125d2
C#/Java/Rust: Add change notes.
michaelnebel Apr 16, 2025
d187a7d
Java: Update integration test that tracks queries not included in a q…
michaelnebel Apr 22, 2025
f6135d5
Shared: Address review comments.
michaelnebel Apr 23, 2025
d05f604
C++: Adjust the model generator queries to the new shared implementat…
michaelnebel Apr 24, 2025
a589014
C++: Update model generator tests.
michaelnebel Apr 24, 2025
de12222
C#/Rust: Update integration test expected output.
michaelnebel Apr 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions cpp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql

This file was deleted.

13 changes: 0 additions & 13 deletions cpp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql

This file was deleted.

2 changes: 1 addition & 1 deletion cpp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSummaryTargetApi api, string noflow
where noflow = captureNoFlow(api)
where noflow = captureNeutral(api)
select noflow order by noflow
1 change: 1 addition & 0 deletions cpp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
*/

import internal.CaptureModels
import Heuristic

from DataFlowSinkTargetApi api, string sink
where sink = captureSink(api)
1 change: 1 addition & 0 deletions cpp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
*/

import internal.CaptureModels
import Heuristic

from DataFlowSourceTargetApi api, string source
where source = captureSource(api)
2 changes: 1 addition & 1 deletion cpp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSummaryTargetApi api, string flow
where flow = captureFlow(api)
where flow = captureFlow(api, _)
select flow order by flow
Original file line number Diff line number Diff line change
@@ -3,9 +3,9 @@ import utils.modelgenerator.internal.CaptureModels
import InlineModelsAsDataTest

module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(MadRelevantFunction c) { result = captureFlow(c) }
string getCapturedModel(MadRelevantFunction c) { result = Heuristic::captureFlow(c) }

string getKind() { result = "summary" }
string getKind() { result = "heuristic-summary" }
}

import InlineMadTest<InlineMadTestConfig>
Original file line number Diff line number Diff line change
@@ -10,32 +10,32 @@ namespace Models {
//No model as destructors are excluded from model generation.
~BasicFlow() = default;

//summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnThis;(int *);;Argument[-1];ReturnValue[*];value;dfc-generated
BasicFlow* returnThis(int* input) {
return this;
}

//summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[0];ReturnValue;value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnParam0;(int *,int *);;Argument[*0];ReturnValue[*];value;dfc-generated
int* returnParam0(int* input0, int* input1) {
return input0;
}

//summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[1];ReturnValue;value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnParam1;(int *,int *);;Argument[*1];ReturnValue[*];value;dfc-generated
int* returnParam1(int* input0, int* input1) {
return input1;
}

//summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
//summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*2];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*2];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[1];ReturnValue;value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[*1];ReturnValue[*];value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnParamMultiple;(bool,int *,int *);;Argument[2];ReturnValue;value;dfc-generated
@@ -44,11 +44,11 @@ namespace Models {
return b ? input0 : input1;
}

//summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];Argument[*1];taint;df-generated
//summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];ReturnValue[*];taint;df-generated
//summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];taint;df-generated
//summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[1];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];Argument[*1];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];Argument[*1];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[1];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];Argument[*1];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];Argument[*1];taint;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[0];ReturnValue[*];taint;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnSubstring;(const char *,char *);;Argument[*0];ReturnValue[*];value;dfc-generated
@@ -58,16 +58,16 @@ namespace Models {
return strcpy(dest, source + 1);
}

//summary=Models;BasicFlow;true;setField;(int *);;Argument[0];Argument[-1];taint;df-generated
//summary=Models;BasicFlow;true;setField;(int *);;Argument[*0];Argument[-1];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;setField;(int *);;Argument[0];Argument[-1];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;setField;(int *);;Argument[*0];Argument[-1];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;setField;(int *);;Argument[0];Argument[-1].Field[*tainted];value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;setField;(int *);;Argument[*0];Argument[-1].Field[**tainted];value;dfc-generated
void setField(int* s) {
tainted = s;
}

//summary=Models;BasicFlow;true;returnField;();;Argument[-1];ReturnValue;taint;df-generated
//summary=Models;BasicFlow;true;returnField;();;Argument[-1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnField;();;Argument[-1];ReturnValue;taint;df-generated
//heuristic-summary=Models;BasicFlow;true;returnField;();;Argument[-1];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;BasicFlow;true;returnField;();;Argument[-1].Field[*tainted];ReturnValue;value;dfc-generated
//contentbased-summary=Models;BasicFlow;true;returnField;();;Argument[-1].Field[**tainted];ReturnValue[*];value;dfc-generated
int* returnField() {
@@ -79,34 +79,34 @@ namespace Models {
struct TemplatedFlow {
T tainted;

//summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnThis;(T);;Argument[-1];ReturnValue[*];value;dfc-generated
TemplatedFlow<T>* template_returnThis(T input) {
return this;
}

//summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;taint;df-generated
//summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[0];ReturnValue;value;dfc-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnParam0;(T *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated
T* template_returnParam0(T* input0, T* input1) {
return input0;
}

//summary=Models;TemplatedFlow<T>;true;template_setField;(T);;Argument[0];Argument[-1];taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;template_setField;(T);;Argument[0];Argument[-1];taint;df-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;template_setField;(T);;Argument[0];Argument[-1].Field[*tainted];value;dfc-generated
void template_setField(T s) {
tainted = s;
}

//summary=Models;TemplatedFlow<T>;true;template_returnField;();;Argument[-1];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;template_returnField;();;Argument[-1];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;template_returnField;();;Argument[-1].Field[*tainted];ReturnValue[*];value;dfc-generated
T& template_returnField() {
return tainted;
}

//summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;taint;df-generated
//summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];taint;df-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[0];ReturnValue;value;dfc-generated
//contentbased-summary=Models;TemplatedFlow<T>;true;templated_function<U>;(U *,T *);;Argument[*0];ReturnValue[*];value;dfc-generated
template<typename U>
@@ -129,8 +129,8 @@ namespace Models {
}
}

//summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;df-generated
//summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;taint;df-generated
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;taint;df-generated
//contentbased-summary=;;true;toplevel_function;(int *);;Argument[0];ReturnValue;taint;dfc-generated
//contentbased-summary=;;true;toplevel_function;(int *);;Argument[*0];ReturnValue;value;dfc-generated
int toplevel_function(int* p) {
@@ -143,13 +143,13 @@ static int static_toplevel_function(int* p) {
}

struct NonFinalStruct {
//summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
//contentbased-summary=;NonFinalStruct;true;public_not_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated
virtual int public_not_final_member_function(int x) {
return x;
}

//summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;taint;df-generated
//contentbased-summary=;NonFinalStruct;false;public_final_member_function;(int);;Argument[0];ReturnValue;value;dfc-generated
virtual int public_final_member_function(int x) final {
return x;
@@ -169,13 +169,13 @@ struct NonFinalStruct {
};

struct FinalStruct final {
//summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
//contentbased-summary=;FinalStruct;false;public_not_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated
virtual int public_not_final_member_function_2(int x) {
return x;
}

//summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;taint;df-generated
//contentbased-summary=;FinalStruct;false;public_final_member_function_2;(int);;Argument[0];ReturnValue;value;dfc-generated
virtual int public_final_member_function_2(int x) final {
return x;
@@ -186,16 +186,16 @@ union U {
int x, y;
};

//summary=;;true;get_x_from_union;(U *);;Argument[0];ReturnValue;taint;df-generated
//summary=;;true;get_x_from_union;(U *);;Argument[*0];ReturnValue;taint;df-generated
//heuristic-summary=;;true;get_x_from_union;(U *);;Argument[0];ReturnValue;taint;df-generated
//heuristic-summary=;;true;get_x_from_union;(U *);;Argument[*0];ReturnValue;taint;df-generated
//contentbased-summary=;;true;get_x_from_union;(U *);;Argument[0];ReturnValue;taint;dfc-generated
//contentbased-summary=;;true;get_x_from_union;(U *);;Argument[*0].Union[*U];ReturnValue;value;dfc-generated
int get_x_from_union(U* u) {
return u->x;
}

//summary=;;true;set_x_in_union;(U *,int);;Argument[1];Argument[*0];taint;df-generated
//heuristic-summary=;;true;set_x_in_union;(U *,int);;Argument[1];Argument[*0];taint;df-generated
//contentbased-summary=;;true;set_x_in_union;(U *,int);;Argument[1];Argument[*0].Union[*U];value;dfc-generated
void set_x_in_union(U* u, int x) {
u->x = x;
}
}
Original file line number Diff line number Diff line change
@@ -117,8 +117,6 @@ ql/csharp/ql/src/utils/modelconverter/ExtractSummaries.ql
ql/csharp/ql/src/utils/modeleditor/ApplicationModeEndpoints.ql
ql/csharp/ql/src/utils/modeleditor/FrameworkModeEndpoints.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
ql/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
4 changes: 4 additions & 0 deletions csharp/ql/src/change-notes/2025-04-16-model-generation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Changes to the MaD model generation infrastructure: Changed the query `cs/utils/modelgenerator/summary-models` to use the implementation from `cs/utils/modelgenerator/mixed-summary-models`. Removed the now-redundant `cs/utils/modelgenerator/mixed-summary-models` query. Similar replacement was made for `cs/utils/modelgenerator/neutral-models`. That is, if `GenerateFlowModel.py` is provided with `--with-summaries` combined/mixed models are now generated instead of heuristic models (and similar for `--with-neutrals`).
13 changes: 0 additions & 13 deletions csharp/ql/src/utils/modelgenerator/CaptureMixedNeutralModels.ql

This file was deleted.

13 changes: 0 additions & 13 deletions csharp/ql/src/utils/modelgenerator/CaptureMixedSummaryModels.ql

This file was deleted.

Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSummaryTargetApi api, string noflow
where noflow = captureNoFlow(api)
where noflow = captureNeutral(api)
select noflow order by noflow
2 changes: 1 addition & 1 deletion csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSinkTargetApi api, string sink
where sink = captureSink(api)
where sink = Heuristic::captureSink(api)
select sink order by sink
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSourceTargetApi api, string source
where source = captureSource(api)
where source = Heuristic::captureSource(api)
select source order by source
Original file line number Diff line number Diff line change
@@ -9,5 +9,5 @@
import internal.CaptureModels

from DataFlowSummaryTargetApi api, string flow
where flow = captureFlow(api)
where flow = captureFlow(api, _)
select flow order by flow
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ import PartialFlow::PartialPathGraph

int explorationLimit() { result = 3 }

module PartialFlow = PropagateFlow::FlowExplorationFwd<explorationLimit/0>;
module PartialFlow = Heuristic::PropagateFlow::FlowExplorationFwd<explorationLimit/0>;

from
PartialFlow::PartialPathNode source, PartialFlow::PartialPathNode sink,
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@

import csharp
import utils.modelgenerator.internal.CaptureModels
import Heuristic
import PropagateFlow::PathGraph

from
Original file line number Diff line number Diff line change
@@ -3,9 +3,9 @@ import utils.modelgenerator.internal.CaptureModels
import utils.test.InlineMadTest

module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureFlow(c) }
string getCapturedModel(Callable c) { result = Heuristic::captureFlow(c) }

string getKind() { result = "summary" }
string getKind() { result = "heuristic-summary" }
}

import InlineMadTest<InlineMadTestConfig>
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels
import utils.test.InlineMadTest

module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureNoFlow(c) }
string getCapturedModel(Callable c) { result = captureNeutral(c) }

string getKind() { result = "neutral" }
}
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import utils.modelgenerator.internal.CaptureModels
import utils.test.InlineMadTest

module InlineMadTestConfig implements InlineMadTestConfigSig {
string getCapturedModel(Callable c) { result = captureSink(c) }
string getCapturedModel(Callable c) { result = Heuristic::captureSink(c) }

string getKind() { result = "sink" }
}
Loading
Oops, something went wrong.
Loading
Oops, something went wrong.