From c2da2a8b16baac311c59d3d1655b511901dd35fb Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 31 Aug 2022 11:10:00 +0200 Subject: [PATCH 01/22] C#: Initial implementation of Type based summarymodel generation. --- .../CaptureDiscardedSummaryModels.ql | 8 +- .../CaptureNegativeSummaryModels.ql | 12 +- .../model-generator/CaptureSinkModels.ql | 4 +- .../model-generator/CaptureSourceModels.ql | 4 +- .../model-generator/CaptureSummaryModels.ql | 8 +- .../CaptureTheoremsForFreeSummaryModels.ql | 14 +++ .../internal/CaptureModels.qll | 30 +++-- .../internal/CaptureModelsSpecific.qll | 18 ++- .../internal/CaptureSummaryFlow.qll | 4 +- .../CaptureTheoremsForFreeSummaryModels.qll | 118 ++++++++++++++++++ 10 files changed, 184 insertions(+), 36 deletions(-) create mode 100644 csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql create mode 100644 csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll diff --git a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql index 6276f9793dc..b9e0cc23987 100644 --- a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql @@ -4,10 +4,10 @@ * @id csharp/utils/model-generator/discarded-summary-models */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string flow +from DataFlowTargetApi api, string flow where flow = captureFlow(api) and hasSummary(api, false) select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql index 09202f423ea..0e26d3eee7f 100644 --- a/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql @@ -6,10 +6,12 @@ * @tags model-generator */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string noflow -where noflow = captureNoFlow(api) and not hasSummary(api, false) +from DataFlowTargetApi api, string noflow +where + noflow = captureNoFlow(api) and + not hasSummary(api, false) select noflow order by noflow diff --git a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql index 03eeeeda273..ea249016427 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string sink +from DataFlowTargetApi api, string sink where sink = captureSink(api) select sink order by sink diff --git a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql index f60682b2b6d..72ce31d4b61 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string source +from DataFlowTargetApi api, string source where source = captureSource(api) select source order by source diff --git a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql index f6c91335428..f308c57c89d 100644 --- a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql @@ -6,10 +6,10 @@ * @tags model-generator */ -private import semmle.code.csharp.dataflow.ExternalFlow -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string flow +from DataFlowTargetApi api, string flow where flow = captureFlow(api) and not hasSummary(api, false) select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql new file mode 100644 index 00000000000..2eeb1fed949 --- /dev/null +++ b/csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql @@ -0,0 +1,14 @@ +/** + * @name Capture Theorems for Free summary models. + * @description Finds applicable summary models to be used by other queries. + * @kind diagnostic + * @id cs/utils/model-generator/summary-models-theorems-for-free + * @tags model-generator + */ + +import semmle.code.csharp.dataflow.ExternalFlow +import internal.CaptureTheoremsForFreeSummaryModels + +from TheoremTargetApi api, string flow +where flow = captureFlow(api) +select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll index c6ebc854edb..ed57c2d4751 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -5,7 +5,9 @@ private import CaptureModelsSpecific -class TargetApi = TargetApiSpecific; +class DataFlowTargetApi extends TargetApiSpecific { + DataFlowTargetApi() { isRelevantForFlowModels(this) } +} /** * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. @@ -40,7 +42,7 @@ private predicate isRelevantContent(DataFlow::Content c) { * Gets the summary model for `api` with `input`, `output` and `kind`. */ bindingset[input, output, kind] -private string asSummaryModel(TargetApi api, string input, string output, string kind) { +private string asSummaryModel(TargetApiSpecific api, string input, string output, string kind) { result = asPartialModel(api) + input + ";" // + output + ";" // @@ -48,13 +50,15 @@ private string asSummaryModel(TargetApi api, string input, string output, string + "generated" } -string asNegativeSummaryModel(TargetApi api) { result = asPartialNegativeModel(api) + "generated" } +string asNegativeSummaryModel(TargetApiSpecific api) { + result = asPartialNegativeModel(api) + "generated" +} /** * Gets the value summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asValueModel(TargetApi api, string input, string output) { +private string asValueModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "value") } @@ -62,7 +66,7 @@ private string asValueModel(TargetApi api, string input, string output) { * Gets the taint summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asTaintModel(TargetApi api, string input, string output) { +string asTaintModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "taint") } @@ -70,7 +74,7 @@ private string asTaintModel(TargetApi api, string input, string output) { * Gets the sink model for `api` with `input` and `kind`. */ bindingset[input, kind] -private string asSinkModel(TargetApi api, string input, string kind) { +private string asSinkModel(TargetApiSpecific api, string input, string kind) { result = asPartialModel(api) + input + ";" // + kind + ";" // @@ -81,7 +85,7 @@ private string asSinkModel(TargetApi api, string input, string kind) { * Gets the source model for `api` with `output` and `kind`. */ bindingset[output, kind] -private string asSourceModel(TargetApi api, string output, string kind) { +private string asSourceModel(TargetApiSpecific api, string output, string kind) { result = asPartialModel(api) + output + ";" // + kind + ";" // @@ -91,7 +95,7 @@ private string asSourceModel(TargetApi api, string output, string kind) { /** * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). */ -string captureQualifierFlow(TargetApi api) { +string captureQualifierFlow(TargetApiSpecific api) { exists(DataFlowImplCommon::ReturnNodeExt ret | api = returnNodeEnclosingCallable(ret) and isOwnInstanceAccessNode(ret) @@ -140,7 +144,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof TargetApi and + source.getEnclosingCallable() instanceof DataFlowTargetApi and state.(TaintRead).getStep() = 0 } @@ -184,7 +188,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { /** * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. */ -string captureThroughFlow(TargetApi api) { +string captureThroughFlow(DataFlowTargetApi api) { exists( ThroughFlowConfig config, DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input, string output @@ -211,7 +215,7 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) } override predicate isSink(DataFlow::Node sink) { - exists(TargetApi c | + exists(DataFlowTargetApi c | sink instanceof DataFlowImplCommon::ReturnNodeExt and sink.getEnclosingCallable() = c ) @@ -229,7 +233,7 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { /** * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. */ -string captureSource(TargetApi api) { +string captureSource(DataFlowTargetApi api) { exists(DataFlow::Node source, DataFlow::Node sink, FromSourceConfiguration config, string kind | config.hasFlow(source, sink) and ExternalFlow::sourceNode(source, kind) and @@ -259,7 +263,7 @@ private class PropagateToSinkConfiguration extends PropagateToSinkConfigurationS /** * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. */ -string captureSink(TargetApi api) { +string captureSink(DataFlowTargetApi api) { exists(DataFlow::Node src, DataFlow::Node sink, PropagateToSinkConfiguration config, string kind | config.hasFlow(src, sink) and ExternalFlow::sinkNode(sink, kind) and diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll index 57407dcc391..4a01f58ef4f 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll @@ -36,10 +36,21 @@ private predicate isRelevantForModels(CS::Callable api) { api.getDeclaringType().getNamespace().getQualifiedName() != "" and not api instanceof CS::ConversionOperator and not api instanceof Util::MainMethod and - not isHigherOrder(api) and not api instanceof CS::Destructor } +/** + * Holds if it is relevant to generate models for `api` based on data flow analysis. + */ +predicate isRelevantForFlowModels(CS::Callable api) { + isRelevantForModels(api) and not isHigherOrder(api) +} + +/** + * Holds if it is relevant to generate models for `api` based on Theorems for Free. + */ +predicate isRelevantForTheoremModels = isRelevantForModels/1; + /** * A class of callables that are relevant generating summary, source and sinks models for. * @@ -49,8 +60,7 @@ private predicate isRelevantForModels(CS::Callable api) { class TargetApiSpecific extends DotNet::Callable { TargetApiSpecific() { this.fromSource() and - this.isUnboundDeclaration() and - isRelevantForModels(this) + this.isUnboundDeclaration() } } @@ -100,7 +110,7 @@ predicate isRelevantType(CS::Type t) { */ string qualifierString() { result = "Argument[this]" } -private string parameterAccess(CS::Parameter p) { +string parameterAccess(CS::Parameter p) { if Collections::isCollectionType(p.getType()) then result = "Argument[" + p.getPosition() + "].Element" else result = "Argument[" + p.getPosition() + "]" diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll b/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll index 65a5181ee89..e06ea1a609a 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll @@ -75,7 +75,7 @@ private import CaptureModels * Captured Model: * ```Summaries;BasicFlow;false;AssignToArray;(System.Int32,System.Int32[]);Argument[0];Argument[1].Element;taint``` */ -string captureFlow(TargetApi api) { +string captureFlow(DataFlowTargetApi api) { result = captureQualifierFlow(api) or result = captureThroughFlow(api) } @@ -84,7 +84,7 @@ string captureFlow(TargetApi api) { * Gets the negative summary for `api`, if any. * A negative summary is generated, if there does not exist any positive flow. */ -string captureNoFlow(TargetApi api) { +string captureNoFlow(DataFlowTargetApi api) { not exists(captureFlow(api)) and result = asNegativeSummaryModel(api) } diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll new file mode 100644 index 00000000000..7d7a843e071 --- /dev/null +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll @@ -0,0 +1,118 @@ +private import csharp +private import semmle.code.csharp.commons.Collections as Collections +private import semmle.code.csharp.dataflow.internal.DataFlowPrivate +private import semmle.code.csharp.frameworks.system.linq.Expressions +private import CaptureModelsSpecific as Specific +private import CaptureModels + +/** + * A class of callables that are relevant generating summaries for based + * on the Theorems for Free approach. + */ +class TheoremTargetApi extends Specific::TargetApiSpecific { + TheoremTargetApi() { Specific::isRelevantForTheoremModels(this) } + + private predicate isClassTypeParameter(TypeParameter t) { + t = this.getDeclaringType().(UnboundGeneric).getATypeParameter() + } + + private predicate isMethodTypeParameter(TypeParameter t) { + t = this.(UnboundGeneric).getATypeParameter() + } + + bindingset[t] + private string getAccess(TypeParameter t) { + exists(string access | + if Collections::isCollectionType(this.getDeclaringType()) + then access = ".Element" + else access = "" + | + result = Specific::qualifierString() + ".SyntheticField[Arg" + t.getName() + "]" + access + ) + } + + private predicate returns(TypeParameter t) { this.getReturnType() = t } + + private predicate parameter(TypeParameter t, Parameter p) { + p = this.getAParameter() and + p.getType() = t + } + + /** + * Gets the string representation of a summary for `this`, where this has a signature like + * this : T -> unit + * where T is type parameter for the class declaring `this`. + */ + private string getSetterSummary() { + exists(TypeParameter t, Parameter p | + this.isClassTypeParameter(t) and + this.getReturnType() instanceof VoidType and + this.parameter(t, p) + | + result = asTaintModel(this, Specific::parameterAccess(p), this.getAccess(t)) + ) + } + + /** + * Gets the string representation of a summary for `this`, where this has a signature like + * this : unit -> T + * where T is type parameter for the class declaring `this`. + */ + private string getGetterSummary() { + exists(TypeParameter t | + this.isClassTypeParameter(t) and + this.returns(t) and + not this.parameter(t, _) + | + result = asTaintModel(this, this.getAccess(t), "ReturnValue") + ) + } + + /** + * Gets the string representation of a summary for `this`, where this has a signature like + * this : T -> T + */ + private string getTransformSummary() { + exists(TypeParameter t, Parameter p | + (this.isClassTypeParameter(t) or this.isMethodTypeParameter(t)) and + this.returns(t) and + this.parameter(t, p) + | + result = asTaintModel(this, Specific::parameterAccess(p), "ReturnValue") + ) + } + + /** + * Gets the string representation of a summary for `this`, where this has a signature like + * this : (T -> V1) -> V2 + * where T is type parameter for the class declaring `this`. + */ + private string getApplySummary() { + exists(TypeParameter t, Parameter p1, Parameter p2 | + this.isClassTypeParameter(t) and + p1 = this.getAParameter() and + p2 = p1.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType().getAParameter() and + p2.getType() = t + | + result = + asTaintModel(this, this.getAccess(t), + Specific::parameterAccess(p1) + ".Parameter[" + p2.getPosition() + "]") + ) + } + + /** + * Gets the string representation of all summaries based on the Theorems for Free approach. + */ + string getSummaries() { + result = + [ + this.getSetterSummary(), this.getGetterSummary(), this.getTransformSummary(), + this.getApplySummary() + ] + } +} + +/** + * Returns the Theorems for Free summaries for `api`. + */ +string captureFlow(TheoremTargetApi api) { result = api.getSummaries() } From dd44d71757a6c19e8ce9ae6c20d496edd1a80404 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 31 Aug 2022 11:12:15 +0200 Subject: [PATCH 02/22] C#: Add Type based summary test cases and move dataflow model generation test cases. --- .../CaptureNegativeSummaryModels.expected | 0 .../CaptureNegativeSummaryModels.qlref | 0 .../{ => dataflow}/CaptureSinkModels.expected | 0 .../{ => dataflow}/CaptureSinkModels.qlref | 0 .../CaptureSourceModels.expected | 0 .../{ => dataflow}/CaptureSourceModels.qlref | 0 .../CaptureSummaryModels.expected | 0 .../{ => dataflow}/CaptureSummaryModels.qlref | 0 .../{ => dataflow}/NoSummaries.cs | 0 .../model-generator/{ => dataflow}/Sinks.cs | 0 .../model-generator/{ => dataflow}/Sources.cs | 0 .../{ => dataflow}/Summaries.cs | 2 +- .../model-generator/{ => dataflow}/options | 2 +- ...ptureTheoremsForFreeSummaryModels.expected | 14 ++++++ .../CaptureTheoremsForFreeSummaryModels.qlref | 1 + .../theorems/TheoremSummaries.cs | 49 +++++++++++++++++++ 16 files changed, 66 insertions(+), 2 deletions(-) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureNegativeSummaryModels.expected (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureNegativeSummaryModels.qlref (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSinkModels.expected (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSinkModels.qlref (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSourceModels.expected (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSourceModels.qlref (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSummaryModels.expected (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/CaptureSummaryModels.qlref (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/NoSummaries.cs (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/Sinks.cs (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/Sources.cs (100%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/Summaries.cs (99%) rename csharp/ql/test/utils/model-generator/{ => dataflow}/options (52%) create mode 100644 csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected create mode 100644 csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref create mode 100644 csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs diff --git a/csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureNegativeSummaryModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureNegativeSummaryModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSinkModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSinkModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureSinkModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSinkModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSourceModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSourceModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureSourceModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSourceModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref diff --git a/csharp/ql/test/utils/model-generator/CaptureSummaryModels.expected b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSummaryModels.expected rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected diff --git a/csharp/ql/test/utils/model-generator/CaptureSummaryModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref similarity index 100% rename from csharp/ql/test/utils/model-generator/CaptureSummaryModels.qlref rename to csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref diff --git a/csharp/ql/test/utils/model-generator/NoSummaries.cs b/csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/NoSummaries.cs rename to csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs diff --git a/csharp/ql/test/utils/model-generator/Sinks.cs b/csharp/ql/test/utils/model-generator/dataflow/Sinks.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/Sinks.cs rename to csharp/ql/test/utils/model-generator/dataflow/Sinks.cs diff --git a/csharp/ql/test/utils/model-generator/Sources.cs b/csharp/ql/test/utils/model-generator/dataflow/Sources.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/Sources.cs rename to csharp/ql/test/utils/model-generator/dataflow/Sources.cs diff --git a/csharp/ql/test/utils/model-generator/Summaries.cs b/csharp/ql/test/utils/model-generator/dataflow/Summaries.cs similarity index 99% rename from csharp/ql/test/utils/model-generator/Summaries.cs rename to csharp/ql/test/utils/model-generator/dataflow/Summaries.cs index 28e777700f2..3db83726765 100644 --- a/csharp/ql/test/utils/model-generator/Summaries.cs +++ b/csharp/ql/test/utils/model-generator/dataflow/Summaries.cs @@ -259,4 +259,4 @@ public class EqualsGetHashCodeNoFlow { return intTainted; } -} \ No newline at end of file +} diff --git a/csharp/ql/test/utils/model-generator/options b/csharp/ql/test/utils/model-generator/dataflow/options similarity index 52% rename from csharp/ql/test/utils/model-generator/options rename to csharp/ql/test/utils/model-generator/dataflow/options index a55169c6e97..ed33eca5326 100644 --- a/csharp/ql/test/utils/model-generator/options +++ b/csharp/ql/test/utils/model-generator/dataflow/options @@ -1,2 +1,2 @@ semmle-extractor-options: /r:System.Linq.dll /r:System.Collections.Specialized.dll -semmle-extractor-options: ${testdir}/../../resources/stubs/System.Web.cs +semmle-extractor-options: ${testdir}/../../../resources/stubs/System.Web.cs diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected new file mode 100644 index 00000000000..d9fbea26bd6 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected @@ -0,0 +1,14 @@ +| Summaries;CollectionTheorems1<>;false;Add;(T);;Argument[0];Argument[this].SyntheticField[ArgT].Element;taint;generated | +| Summaries;CollectionTheorems1<>;false;First;();;Argument[this].SyntheticField[ArgT].Element;ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgT];Argument[0].Parameter[0];taint;generated | +| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[0];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgT];taint;generated | +| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | +| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | +| Summaries;Theorems1<>;false;Transform;(System.Int32,T);;Argument[1];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;Transform<>;(S);;Argument[0];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | +| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | +| Summaries;Theorems2;false;Transform<>;(T);;Argument[0];ReturnValue;taint;generated | diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref new file mode 100644 index 00000000000..7084f0a5aa0 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref @@ -0,0 +1 @@ +utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql \ No newline at end of file diff --git a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs new file mode 100644 index 00000000000..9b0a2a32de5 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using System.Collections; +using System.Collections.Generic; + +namespace Summaries; + +public class Theorems1 { + + public T Prop { + get { throw null; } + set { throw null; } + } + + public Theorems1(T t) { throw null; } + + public T Get() { throw null; } + + public T Get(object x) { throw null; } + + public T Id(T x) { throw null; } + + public T Transform(int x, T y) { throw null; } + + public S Transform(S x) { throw null; } + + public void Set(T x) { throw null; } + + public void Set(int x, T y) { throw null; } + + // No summary as S is unrelated to T + public void Set(S x) { throw null; } + + public int Apply(Func f) { throw null; } +} + +public class Theorems2 { + + public T Transform(T x) { throw null; } +} + +public class CollectionTheorems1 : IEnumerable { + IEnumerator IEnumerable.GetEnumerator() { throw null; } + IEnumerator IEnumerable.GetEnumerator() { throw null; } + + public T First() { throw null; } + + public void Add(T x) { throw null; } +} \ No newline at end of file From 13a802e2604f06c7a58a2e060e354395965c3758 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Fri, 2 Sep 2022 09:28:52 +0200 Subject: [PATCH 03/22] Java: Sync files and make adjusting changes. --- .../CaptureNegativeSummaryModels.ql | 6 ++-- .../model-generator/CaptureSinkModels.ql | 4 +-- .../model-generator/CaptureSourceModels.ql | 4 +-- .../model-generator/CaptureSummaryModels.ql | 6 ++-- .../internal/CaptureModels.qll | 30 +++++++++++-------- .../internal/CaptureModelsSpecific.qll | 5 ++++ .../internal/CaptureSummaryFlow.qll | 4 +-- 7 files changed, 34 insertions(+), 25 deletions(-) diff --git a/java/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql b/java/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql index 60bf8351de2..49ed16aa1dc 100644 --- a/java/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql +++ b/java/ql/src/utils/model-generator/CaptureNegativeSummaryModels.ql @@ -6,9 +6,9 @@ * @tags model-generator */ -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string noflow +from DataFlowTargetApi api, string noflow where noflow = captureNoFlow(api) select noflow order by noflow diff --git a/java/ql/src/utils/model-generator/CaptureSinkModels.ql b/java/ql/src/utils/model-generator/CaptureSinkModels.ql index 405b9fab772..154c87928fc 100644 --- a/java/ql/src/utils/model-generator/CaptureSinkModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSinkModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string sink +from DataFlowTargetApi api, string sink where sink = captureSink(api) select sink order by sink diff --git a/java/ql/src/utils/model-generator/CaptureSourceModels.ql b/java/ql/src/utils/model-generator/CaptureSourceModels.ql index d37cf5e78fb..8c7de037a90 100644 --- a/java/ql/src/utils/model-generator/CaptureSourceModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSourceModels.ql @@ -6,8 +6,8 @@ * @tags model-generator */ -private import internal.CaptureModels +import internal.CaptureModels -from TargetApi api, string source +from DataFlowTargetApi api, string source where source = captureSource(api) select source order by source diff --git a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql index a4eaea9c4e8..981c6fe73fc 100644 --- a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql +++ b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql @@ -6,9 +6,9 @@ * @tags model-generator */ -private import internal.CaptureModels -private import internal.CaptureSummaryFlow +import internal.CaptureModels +import internal.CaptureSummaryFlow -from TargetApi api, string flow +from DataFlowTargetApi api, string flow where flow = captureFlow(api) select flow order by flow diff --git a/java/ql/src/utils/model-generator/internal/CaptureModels.qll b/java/ql/src/utils/model-generator/internal/CaptureModels.qll index c6ebc854edb..ed57c2d4751 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -5,7 +5,9 @@ private import CaptureModelsSpecific -class TargetApi = TargetApiSpecific; +class DataFlowTargetApi extends TargetApiSpecific { + DataFlowTargetApi() { isRelevantForFlowModels(this) } +} /** * Holds if data can flow from `node1` to `node2` either via a read or a write of an intermediate field `f`. @@ -40,7 +42,7 @@ private predicate isRelevantContent(DataFlow::Content c) { * Gets the summary model for `api` with `input`, `output` and `kind`. */ bindingset[input, output, kind] -private string asSummaryModel(TargetApi api, string input, string output, string kind) { +private string asSummaryModel(TargetApiSpecific api, string input, string output, string kind) { result = asPartialModel(api) + input + ";" // + output + ";" // @@ -48,13 +50,15 @@ private string asSummaryModel(TargetApi api, string input, string output, string + "generated" } -string asNegativeSummaryModel(TargetApi api) { result = asPartialNegativeModel(api) + "generated" } +string asNegativeSummaryModel(TargetApiSpecific api) { + result = asPartialNegativeModel(api) + "generated" +} /** * Gets the value summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asValueModel(TargetApi api, string input, string output) { +private string asValueModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "value") } @@ -62,7 +66,7 @@ private string asValueModel(TargetApi api, string input, string output) { * Gets the taint summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asTaintModel(TargetApi api, string input, string output) { +string asTaintModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "taint") } @@ -70,7 +74,7 @@ private string asTaintModel(TargetApi api, string input, string output) { * Gets the sink model for `api` with `input` and `kind`. */ bindingset[input, kind] -private string asSinkModel(TargetApi api, string input, string kind) { +private string asSinkModel(TargetApiSpecific api, string input, string kind) { result = asPartialModel(api) + input + ";" // + kind + ";" // @@ -81,7 +85,7 @@ private string asSinkModel(TargetApi api, string input, string kind) { * Gets the source model for `api` with `output` and `kind`. */ bindingset[output, kind] -private string asSourceModel(TargetApi api, string output, string kind) { +private string asSourceModel(TargetApiSpecific api, string output, string kind) { result = asPartialModel(api) + output + ";" // + kind + ";" // @@ -91,7 +95,7 @@ private string asSourceModel(TargetApi api, string output, string kind) { /** * Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`). */ -string captureQualifierFlow(TargetApi api) { +string captureQualifierFlow(TargetApiSpecific api) { exists(DataFlowImplCommon::ReturnNodeExt ret | api = returnNodeEnclosingCallable(ret) and isOwnInstanceAccessNode(ret) @@ -140,7 +144,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) { source instanceof DataFlow::ParameterNode and - source.getEnclosingCallable() instanceof TargetApi and + source.getEnclosingCallable() instanceof DataFlowTargetApi and state.(TaintRead).getStep() = 0 } @@ -184,7 +188,7 @@ private class ThroughFlowConfig extends TaintTracking::Configuration { /** * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter. */ -string captureThroughFlow(TargetApi api) { +string captureThroughFlow(DataFlowTargetApi api) { exists( ThroughFlowConfig config, DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input, string output @@ -211,7 +215,7 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { ExternalFlow::sourceNode(source, _) } override predicate isSink(DataFlow::Node sink) { - exists(TargetApi c | + exists(DataFlowTargetApi c | sink instanceof DataFlowImplCommon::ReturnNodeExt and sink.getEnclosingCallable() = c ) @@ -229,7 +233,7 @@ private class FromSourceConfiguration extends TaintTracking::Configuration { /** * Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`. */ -string captureSource(TargetApi api) { +string captureSource(DataFlowTargetApi api) { exists(DataFlow::Node source, DataFlow::Node sink, FromSourceConfiguration config, string kind | config.hasFlow(source, sink) and ExternalFlow::sourceNode(source, kind) and @@ -259,7 +263,7 @@ private class PropagateToSinkConfiguration extends PropagateToSinkConfigurationS /** * Gets the sink model(s) of `api`, if there is flow from a parameter to an existing known sink. */ -string captureSink(TargetApi api) { +string captureSink(DataFlowTargetApi api) { exists(DataFlow::Node src, DataFlow::Node sink, PropagateToSinkConfiguration config, string kind | config.hasFlow(src, sink) and ExternalFlow::sinkNode(sink, kind) and diff --git a/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll b/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll index bcdd90caac5..238f96933da 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll @@ -59,6 +59,11 @@ private predicate isRelevantForModels(J::Callable api) { not api instanceof J::StaticInitializer } +/** + * Holds if it is relevant to generate models for `api` based on data flow analysis. + */ +predicate isRelevantForFlowModels = isRelevantForModels/1; + /** * A class of Callables that are relevant for generating summary, source and sinks models for. * diff --git a/java/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll b/java/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll index 196b2189e94..dce9ce9cfef 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureSummaryFlow.qll @@ -67,7 +67,7 @@ private import CaptureModels * Captured Model: * ```p;Foo;true;addToList;;Argument[0];Argument[1];taint``` */ -string captureFlow(TargetApi api) { +string captureFlow(DataFlowTargetApi api) { result = captureQualifierFlow(api) or result = captureThroughFlow(api) } @@ -76,7 +76,7 @@ string captureFlow(TargetApi api) { * Gets the negative summary for `api`, if any. * A negative summary is generated, if there does not exist any positive flow. */ -string captureNoFlow(TargetApi api) { +string captureNoFlow(DataFlowTargetApi api) { not exists(captureFlow(api)) and result = asNegativeSummaryModel(api) } From bb65485497de8f1270381aa80d208c6f5309cca3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 6 Sep 2022 10:14:32 +0200 Subject: [PATCH 04/22] C#: Address some review comments. --- .../internal/CaptureModels.qll | 4 +- .../CaptureTheoremsForFreeSummaryModels.qll | 91 +++++++++++-------- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll index ed57c2d4751..2fe6ce1e6d5 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -58,7 +58,7 @@ string asNegativeSummaryModel(TargetApiSpecific api) { * Gets the value summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asValueModel(TargetApiSpecific api, string input, string output) { +string asValueModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "value") } @@ -66,7 +66,7 @@ private string asValueModel(TargetApiSpecific api, string input, string output) * Gets the taint summary model for `api` with `input` and `output`. */ bindingset[input, output] -string asTaintModel(TargetApiSpecific api, string input, string output) { +private string asTaintModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "taint") } diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll index 7d7a843e071..5922027dc39 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll @@ -1,10 +1,22 @@ private import csharp -private import semmle.code.csharp.commons.Collections as Collections +private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.frameworks.system.linq.Expressions private import CaptureModelsSpecific as Specific private import CaptureModels +/** + * Holds if `t` is a subtype (reflexive/transitive) of `IEnumerable`, where `T` = `tp`. + */ +private predicate isGenericCollectionType(ValueOrRefType t, TypeParameter tp) { + exists(ConstructedGeneric t2 | + t2 = t.getABaseType*() and + t2.getUnboundDeclaration() instanceof + GenericCollections::SystemCollectionsGenericIEnumerableTInterface and + tp = t2.getATypeArgument() + ) +} + /** * A class of callables that are relevant generating summaries for based * on the Theorems for Free approach. @@ -16,69 +28,78 @@ class TheoremTargetApi extends Specific::TargetApiSpecific { t = this.getDeclaringType().(UnboundGeneric).getATypeParameter() } - private predicate isMethodTypeParameter(TypeParameter t) { - t = this.(UnboundGeneric).getATypeParameter() - } - bindingset[t] private string getAccess(TypeParameter t) { exists(string access | - if Collections::isCollectionType(this.getDeclaringType()) + if isGenericCollectionType(this.getDeclaringType(), t) then access = ".Element" - else access = "" + else access = ".SyntheticField[Arg" + t.getName() + "]" | - result = Specific::qualifierString() + ".SyntheticField[Arg" + t.getName() + "]" + access + result = Specific::qualifierString() + access ) } - private predicate returns(TypeParameter t) { this.getReturnType() = t } + bindingset[t] + private string getReturnAccess(TypeParameter t) { + exists(string access | + ( + if isGenericCollectionType(this.getReturnType(), t) + then access = ".Element" + else access = "" + ) and + result = "ReturnValue" + access + ) + } + /** + * Holds if `this` returns a value of type `t` or a collection of type `t`. + */ + private predicate returns(TypeParameter t) { + this.getReturnType() = t or isGenericCollectionType(this.getReturnType(), t) + } + + /** + * Holds if `this` has a parameter `p`, which is of type `t` + * or collection of type `t`. + */ private predicate parameter(TypeParameter t, Parameter p) { p = this.getAParameter() and - p.getType() = t + ( + // Parameter of type t + p.getType() = t + or + // Parameter is a collection of type t + isGenericCollectionType(p.getType(), t) + ) } /** * Gets the string representation of a summary for `this`, where this has a signature like - * this : T -> unit + * this : T -> S * where T is type parameter for the class declaring `this`. + * Important cases are S = unit (setter) and S = T (both getter and setter). */ private string getSetterSummary() { exists(TypeParameter t, Parameter p | this.isClassTypeParameter(t) and - this.getReturnType() instanceof VoidType and this.parameter(t, p) | - result = asTaintModel(this, Specific::parameterAccess(p), this.getAccess(t)) + result = asValueModel(this, Specific::parameterAccess(p), this.getAccess(t)) ) } /** * Gets the string representation of a summary for `this`, where this has a signature like - * this : unit -> T + * this : S -> T * where T is type parameter for the class declaring `this`. + * Important cases are S = unit (getter) and S = T (both getter and setter). */ private string getGetterSummary() { exists(TypeParameter t | this.isClassTypeParameter(t) and - this.returns(t) and - not this.parameter(t, _) + this.returns(t) | - result = asTaintModel(this, this.getAccess(t), "ReturnValue") - ) - } - - /** - * Gets the string representation of a summary for `this`, where this has a signature like - * this : T -> T - */ - private string getTransformSummary() { - exists(TypeParameter t, Parameter p | - (this.isClassTypeParameter(t) or this.isMethodTypeParameter(t)) and - this.returns(t) and - this.parameter(t, p) - | - result = asTaintModel(this, Specific::parameterAccess(p), "ReturnValue") + result = asValueModel(this, this.getAccess(t), this.getReturnAccess(t)) ) } @@ -95,7 +116,7 @@ class TheoremTargetApi extends Specific::TargetApiSpecific { p2.getType() = t | result = - asTaintModel(this, this.getAccess(t), + asValueModel(this, this.getAccess(t), Specific::parameterAccess(p1) + ".Parameter[" + p2.getPosition() + "]") ) } @@ -104,11 +125,7 @@ class TheoremTargetApi extends Specific::TargetApiSpecific { * Gets the string representation of all summaries based on the Theorems for Free approach. */ string getSummaries() { - result = - [ - this.getSetterSummary(), this.getGetterSummary(), this.getTransformSummary(), - this.getApplySummary() - ] + result = [this.getSetterSummary(), this.getGetterSummary(), this.getApplySummary()] } } From e66dce152444b8ba588881b403e7512b8b84cc04 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 6 Sep 2022 11:22:00 +0200 Subject: [PATCH 05/22] C#: Update test relevant test cases. --- .../theorems/TheoremSummaries.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs index 9b0a2a32de5..75f966e4290 100644 --- a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs +++ b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs @@ -20,8 +20,6 @@ public class Theorems1 { public T Id(T x) { throw null; } - public T Transform(int x, T y) { throw null; } - public S Transform(S x) { throw null; } public void Set(T x) { throw null; } @@ -32,13 +30,13 @@ public class Theorems1 { public void Set(S x) { throw null; } public int Apply(Func f) { throw null; } + + public IList GetMany() { throw null; } + + public void AddMany(IEnumerable xs) { throw null; } } -public class Theorems2 { - - public T Transform(T x) { throw null; } -} - +// It is assumed that this is a collection with elements of type T. public class CollectionTheorems1 : IEnumerable { IEnumerator IEnumerable.GetEnumerator() { throw null; } IEnumerator IEnumerable.GetEnumerator() { throw null; } @@ -46,4 +44,17 @@ public class CollectionTheorems1 : IEnumerable { public T First() { throw null; } public void Add(T x) { throw null; } + + public ICollection GetMany() { throw null; } + + public void AddMany(IEnumerable x) { throw null; } +} + +// It is assumed that this is NOT a collection with elements of type T. +public class CollectionTheorems2 : IEnumerable { + IEnumerator IEnumerable.GetEnumerator() { throw null; } + + public T Get() { throw null; } + + public void Set(T x) { throw null; } } \ No newline at end of file From f6e901343580bd28c4aaffb63ef3e502f8a23282 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 6 Sep 2022 11:05:00 +0200 Subject: [PATCH 06/22] C#: Update expected output of tests. --- ...ptureTheoremsForFreeSummaryModels.expected | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected index d9fbea26bd6..6e0ad96102d 100644 --- a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected @@ -1,14 +1,18 @@ -| Summaries;CollectionTheorems1<>;false;Add;(T);;Argument[0];Argument[this].SyntheticField[ArgT].Element;taint;generated | -| Summaries;CollectionTheorems1<>;false;First;();;Argument[this].SyntheticField[ArgT].Element;ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgT];Argument[0].Parameter[0];taint;generated | -| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[0];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgT];taint;generated | -| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | -| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | -| Summaries;Theorems1<>;false;Transform;(System.Int32,T);;Argument[1];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;Transform<>;(S);;Argument[0];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgT];ReturnValue;taint;generated | -| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgT];taint;generated | -| Summaries;Theorems2;false;Transform<>;(T);;Argument[0];ReturnValue;taint;generated | +| Summaries;CollectionTheorems1<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | +| Summaries;CollectionTheorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | +| Summaries;CollectionTheorems1<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | +| Summaries;CollectionTheorems1<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | +| Summaries;CollectionTheorems2<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | +| Summaries;CollectionTheorems2<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgT];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;GetMany;();;Argument[this].SyntheticField[ArgT];ReturnValue.Element;value;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | From 372a6107d64694a7c477f5459a76ae77f8182163 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 6 Sep 2022 15:21:44 +0200 Subject: [PATCH 07/22] C#: Use typeparameter index to generate synthetic field names in summaries. --- .../internal/CaptureTheoremsForFreeSummaryModels.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll index 5922027dc39..be6278ff20d 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll @@ -33,7 +33,7 @@ class TheoremTargetApi extends Specific::TargetApiSpecific { exists(string access | if isGenericCollectionType(this.getDeclaringType(), t) then access = ".Element" - else access = ".SyntheticField[Arg" + t.getName() + "]" + else access = ".SyntheticField[ArgType" + t.getIndex() + "]" | result = Specific::qualifierString() + access ) From d580a8a078f81234f4df50a7cab851fc49564eb8 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 6 Sep 2022 15:22:21 +0200 Subject: [PATCH 08/22] C#: Update expected test output. --- ...ptureTheoremsForFreeSummaryModels.expected | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected index 6e0ad96102d..ff9db0ef64c 100644 --- a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected @@ -2,17 +2,17 @@ | Summaries;CollectionTheorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | | Summaries;CollectionTheorems1<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | | Summaries;CollectionTheorems1<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | -| Summaries;CollectionTheorems2<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | -| Summaries;CollectionTheorems2<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgT];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;GetMany;();;Argument[this].SyntheticField[ArgT];ReturnValue.Element;value;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | -| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgT];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgT];value;generated | +| Summaries;CollectionTheorems2<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;CollectionTheorems2<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;GetMany;();;Argument[this].SyntheticField[ArgType0];ReturnValue.Element;value;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | From 2d57b7d56af0365891fd98d2f19a5c38eae57e23 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 7 Sep 2022 10:41:39 +0200 Subject: [PATCH 09/22] Java: Sync files. --- java/ql/src/utils/model-generator/internal/CaptureModels.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/utils/model-generator/internal/CaptureModels.qll b/java/ql/src/utils/model-generator/internal/CaptureModels.qll index ed57c2d4751..2fe6ce1e6d5 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -58,7 +58,7 @@ string asNegativeSummaryModel(TargetApiSpecific api) { * Gets the value summary model for `api` with `input` and `output`. */ bindingset[input, output] -private string asValueModel(TargetApiSpecific api, string input, string output) { +string asValueModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "value") } @@ -66,7 +66,7 @@ private string asValueModel(TargetApiSpecific api, string input, string output) * Gets the taint summary model for `api` with `input` and `output`. */ bindingset[input, output] -string asTaintModel(TargetApiSpecific api, string input, string output) { +private string asTaintModel(TargetApiSpecific api, string input, string output) { result = asSummaryModel(api, input, output, "taint") } From 1b7339aa1e5f200bdfc4b011d3f1b8a80086e3ae Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 8 Sep 2022 11:01:50 +0200 Subject: [PATCH 10/22] C#: Rewrite the typed based model generator. --- .../CaptureTheoremsForFreeSummaryModels.qll | 298 ++++++++++++------ 1 file changed, 197 insertions(+), 101 deletions(-) diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll index be6278ff20d..76f41231cf5 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll @@ -1,4 +1,5 @@ private import csharp +private import dotnet private import semmle.code.csharp.frameworks.system.collections.Generic as GenericCollections private import semmle.code.csharp.dataflow.internal.DataFlowPrivate private import semmle.code.csharp.frameworks.system.linq.Expressions @@ -8,7 +9,7 @@ private import CaptureModels /** * Holds if `t` is a subtype (reflexive/transitive) of `IEnumerable`, where `T` = `tp`. */ -private predicate isGenericCollectionType(ValueOrRefType t, TypeParameter tp) { +private predicate genericCollectionType(ValueOrRefType t, TypeParameter tp) { exists(ConstructedGeneric t2 | t2 = t.getABaseType*() and t2.getUnboundDeclaration() instanceof @@ -17,6 +18,176 @@ private predicate isGenericCollectionType(ValueOrRefType t, TypeParameter tp) { ) } +/** + * Holds if `tp` is a type parameter of `generic`. + */ +private predicate unboundGeneric(UnboundGeneric generic, TypeParameter tp) { + tp = generic.getATypeParameter() +} + +/** + * Holds if `tp` is a type parameter of the immediate type declaring `callable`. + */ +private predicate classTypeParameter(DotNet::Callable callable, TypeParameter tp) { + unboundGeneric(callable.getDeclaringType(), tp) +} + +/** + * Holds if `tp` is type parameter of `callable` or the type declaring `callable`. + */ +private predicate localTypeParameter(DotNet::Callable callable, TypeParameter tp) { + classTypeParameter(callable, tp) or unboundGeneric(callable, tp) +} + +private predicate constructedGeneric(ConstructedType t, TypeParameter tp) { + t.getATypeArgument() = tp +} + +/** + * Holds if `callable` has a parameter of type `tp` + * or collection parameterized over type `tp`. + */ +private predicate parameter(DotNet::Callable callable, string input, TypeParameter tp) { + exists(Parameter p | + input = Specific::parameterAccess(p) and + p = callable.getAParameter() and + ( + // Parameter of type tp + p.getType() = tp + or + // Parameter is a collection of type tp + genericCollectionType(p.getType(), tp) + ) + ) +} + +/** + * Gets the string representation of a synthetic field corresponding to `tp`. + */ +private string getSyntheticField(TypeParameter tp) { + result = ".SyntheticField[ArgType" + tp.getIndex() + "]" +} + +/** + * Gets a models as data string representation of, how a value of type `tp` + * can be read or stored implicitly in relation to `callable`. + */ +private string implicit(DotNet::Callable callable, TypeParameter tp) { + classTypeParameter(callable, tp) and + exists(string access | + if genericCollectionType(callable.getDeclaringType(), tp) + then access = ".Element" + else access = getSyntheticField(tp) + | + result = Specific::qualifierString() + access + ) +} + +/** + * Holds if `callable` has a delegate type parameter `tp` at parameter position `position`. + */ +private predicate delegate(DotNet::Callable callable, DelegateType dt, int position) { + exists(Parameter p | + p = callable.getAParameter() and + dt = p.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType() and + position = p.getPosition() + ) +} + +/** + * Gets models as data input/output access relative to the type parameter `tp` in the + * type `t` in the scope of `callable`. + * + * Note: This predicate has to be inlined as `callable` is not related to `return` or `tp` + * in every disjunction. + */ +pragma[inline] +private string getAccess(DotNet::Callable callable, Type return, TypeParameter tp) { + return = tp and result = "" + or + genericCollectionType(return, tp) and result = ".Element" + or + not genericCollectionType(return, tp) and + ( + constructedGeneric(return, tp) + or + callable.getDeclaringType() = return and unboundGeneric(return, tp) + ) and + result = getSyntheticField(tp) +} + +/** + * Holds if `input` is a models as data string representation of, how a value of type `tp` + * (or a generic parameterized over `tp`) can be generated by a delegate parameter of `callable`. + */ +private predicate source(DotNet::Callable callable, string input, TypeParameter tp) { + exists(DelegateType dt, int position, Type return, string access | + delegate(callable, dt, position) and + return = dt.getReturnType() and + access = getAccess(callable, return, tp) and + input = "Argument[" + position + "].ReturnValue" + access + ) +} + +/** + * Holds if `input` is a models as data string representation of, how a + * value of type `tp` (or a generic parameterized over `tp`) + * can be provided as input to `callable`. + * This includes + * (1) The implicit synthetic field(s) of the declaring type of `callable`. + * (2) The parameters of `callable`. + * (3) Any delegate parameters of `callable`. + */ +private predicate input(DotNet::Callable callable, string input, TypeParameter tp) { + input = implicit(callable, tp) + or + parameter(callable, input, tp) + or + source(callable, input, tp) +} + +/** + * Holds if `callable` returns a value of type `tp` (or a generic parameterized over `tp`) and `output` + * is a models as data string representation of, how data is routed to the return. + */ +private predicate returns(DotNet::Callable callable, TypeParameter tp, string output) { + exists(Type return, string access | return = callable.getReturnType() | + access = getAccess(callable, return, tp) and + output = "ReturnValue" + access + ) +} + +/** + * Holds if `callable` has a delegate parameter that accepts a value of type `tp` + * and `output` is the models as data string representation of, how data is routed to + * the delegate parameter. + */ +private predicate sink(DotNet::Callable callable, TypeParameter tp, string output) { + exists(DelegateType dt, int position, Type t, Parameter p | + delegate(callable, dt, position) and + p = dt.getAParameter() and + t = p.getType() and + t = tp and + output = "Argument[" + position + "]" + ".Parameter[" + p.getPosition() + "]" + ) +} + +/** + * Holds if `output` is a models as data string representation of, how values of type `tp` + * (or generics parameterized over `tp`) can be routed. + * This includes + * (1) The implicit synthetic field(s) of the declaring type of `callable`. + * (2) The return of `callable`. + * (3) Any delegate parameters of `callable`. + */ +private predicate output(DotNet::Callable callable, TypeParameter tp, string output) { + output = implicit(callable, tp) + or + returns(callable, tp, output) + or + sink(callable, tp, output) +} + /** * A class of callables that are relevant generating summaries for based * on the Theorems for Free approach. @@ -24,112 +195,37 @@ private predicate isGenericCollectionType(ValueOrRefType t, TypeParameter tp) { class TheoremTargetApi extends Specific::TargetApiSpecific { TheoremTargetApi() { Specific::isRelevantForTheoremModels(this) } - private predicate isClassTypeParameter(TypeParameter t) { - t = this.getDeclaringType().(UnboundGeneric).getATypeParameter() - } - - bindingset[t] - private string getAccess(TypeParameter t) { - exists(string access | - if isGenericCollectionType(this.getDeclaringType(), t) - then access = ".Element" - else access = ".SyntheticField[ArgType" + t.getIndex() + "]" - | - result = Specific::qualifierString() + access - ) - } - - bindingset[t] - private string getReturnAccess(TypeParameter t) { - exists(string access | - ( - if isGenericCollectionType(this.getReturnType(), t) - then access = ".Element" - else access = "" - ) and - result = "ReturnValue" + access - ) - } - /** - * Holds if `this` returns a value of type `t` or a collection of type `t`. - */ - private predicate returns(TypeParameter t) { - this.getReturnType() = t or isGenericCollectionType(this.getReturnType(), t) - } - - /** - * Holds if `this` has a parameter `p`, which is of type `t` - * or collection of type `t`. - */ - private predicate parameter(TypeParameter t, Parameter p) { - p = this.getAParameter() and - ( - // Parameter of type t - p.getType() = t - or - // Parameter is a collection of type t - isGenericCollectionType(p.getType(), t) - ) - } - - /** - * Gets the string representation of a summary for `this`, where this has a signature like - * this : T -> S - * where T is type parameter for the class declaring `this`. - * Important cases are S = unit (setter) and S = T (both getter and setter). - */ - private string getSetterSummary() { - exists(TypeParameter t, Parameter p | - this.isClassTypeParameter(t) and - this.parameter(t, p) - | - result = asValueModel(this, Specific::parameterAccess(p), this.getAccess(t)) - ) - } - - /** - * Gets the string representation of a summary for `this`, where this has a signature like - * this : S -> T - * where T is type parameter for the class declaring `this`. - * Important cases are S = unit (getter) and S = T (both getter and setter). - */ - private string getGetterSummary() { - exists(TypeParameter t | - this.isClassTypeParameter(t) and - this.returns(t) - | - result = asValueModel(this, this.getAccess(t), this.getReturnAccess(t)) - ) - } - - /** - * Gets the string representation of a summary for `this`, where this has a signature like - * this : (T -> V1) -> V2 - * where T is type parameter for the class declaring `this`. - */ - private string getApplySummary() { - exists(TypeParameter t, Parameter p1, Parameter p2 | - this.isClassTypeParameter(t) and - p1 = this.getAParameter() and - p2 = p1.getType().(SystemLinqExpressions::DelegateExtType).getDelegateType().getAParameter() and - p2.getType() = t - | - result = - asValueModel(this, this.getAccess(t), - Specific::parameterAccess(p1) + ".Parameter[" + p2.getPosition() + "]") - ) - } - - /** - * Gets the string representation of all summaries based on the Theorems for Free approach. + * Gets the string representation of all type based summaries inspired by + * the Theorems for Free approach. + * + * Basic example signatures could be + * this : T -> \alpha + * this : \beta -> T + * where T is type parameter on `this` or on the declaring type of `this`. + * + * Important special cases are \alpha = unit (setter), + * \alpha = T (getter, setter and id) and \beta = unit (getter). + * + * Complex example signatures could be + * this : (T -> S) -> S + * this : S1 x (S1 -> S2) -> S2 + * where T is type parameter of the class declaring `this` and S, S1 and S2 are type parameters + * of `this`. */ string getSummaries() { - result = [this.getSetterSummary(), this.getGetterSummary(), this.getApplySummary()] + exists(TypeParameter tp, string input, string output | + localTypeParameter(this, tp) and + input(this, input, tp) and + output(this, tp, output) and + input != output + | + result = asValueModel(this, input, output) + ) } } /** - * Returns the Theorems for Free summaries for `api`. + * Returns the Theorems for Free inspired typed based summaries for `api`. */ string captureFlow(TheoremTargetApi api) { result = api.getSummaries() } From 055072b1c086f6590808badd1c97e3daef562421 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 8 Sep 2022 14:09:55 +0200 Subject: [PATCH 11/22] C#: Add more test examples. --- .../theorems/TheoremSummaries.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs index 75f966e4290..d92a9baa0db 100644 --- a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs +++ b/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs @@ -29,11 +29,27 @@ public class Theorems1 { // No summary as S is unrelated to T public void Set(S x) { throw null; } - public int Apply(Func f) { throw null; } - public IList GetMany() { throw null; } public void AddMany(IEnumerable xs) { throw null; } + + public int Apply(Func f) { throw null; } + + public S Apply(Func f) { throw null; } + + public T2 Apply(T1 x, Func f) { throw null; } + + public S Map(Func f) { throw null; } + + public Theorems1 MapTheorem(Func f) { throw null; } + + public Theorems1 FlatMap(Func> f) { throw null; } + + public Theorems1 FlatMap(Func> f) { throw null; } + + public Theorems1 Return(Func> f) { throw null; } + // Examples still not working: + // public void Set(int x, Func f) { throw null;} } // It is assumed that this is a collection with elements of type T. From 5f161dfaad146bcefa5ec2cb7860d70a614385b9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 8 Sep 2022 11:07:39 +0200 Subject: [PATCH 12/22] C#: Update expected test output with further models. --- ...ptureTheoremsForFreeSummaryModels.expected | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected index ff9db0ef64c..8aec61a529a 100644 --- a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected @@ -1,18 +1,41 @@ | Summaries;CollectionTheorems1<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | | Summaries;CollectionTheorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | | Summaries;CollectionTheorems1<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | +| Summaries;CollectionTheorems1<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.SyntheticField[ArgType0];value;generated | | Summaries;CollectionTheorems1<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | | Summaries;CollectionTheorems2<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | | Summaries;CollectionTheorems2<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;Theorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Apply<,>;(T1,System.Func);;Argument[0];Argument[1].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Apply<,>;(T1,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Apply<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Apply<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;FlatMap<>;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;FlatMap<>;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | | Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | | Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | | Summaries;Theorems1<>;false;GetMany;();;Argument[this].SyntheticField[ArgType0];ReturnValue.Element;value;generated | | Summaries;Theorems1<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Id;(T);;Argument[0];ReturnValue;value;generated | | Summaries;Theorems1<>;false;Id;(T);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Map<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;Theorems1<>;false;Map<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;MapTheorem<>;(System.Func);;Argument[0].ReturnValue;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;MapTheorem<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | | Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;Theorems1<>;false;Transform<>;(S);;Argument[0];ReturnValue;value;generated | | Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | | Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | From c5949fad75f29d8725d1a9b806d8ac0132c37d2b Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 12:57:18 +0200 Subject: [PATCH 13/22] C#/Java: Rename to Typed based summary model generation. --- ...eSummaryModels.ql => CaptureTypeBasedSummaryModels.ql} | 8 ++++---- .../src/utils/model-generator/internal/CaptureModels.qll | 2 +- .../model-generator/internal/CaptureModelsSpecific.qll | 6 +++--- ...ummaryModels.qll => CaptureTypeBasedSummaryModels.qll} | 8 ++++---- .../theorems/CaptureTheoremsForFreeSummaryModels.qlref | 1 - .../CaptureTypeBasedSummaryModels.expected} | 0 .../typebasedflow/CaptureTypeBasedSummaryModels.qlref | 1 + .../TypeBasedSummaries.cs} | 0 .../src/utils/model-generator/internal/CaptureModels.qll | 2 +- .../model-generator/internal/CaptureModelsSpecific.qll | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) rename csharp/ql/src/utils/model-generator/{CaptureTheoremsForFreeSummaryModels.ql => CaptureTypeBasedSummaryModels.ql} (53%) rename csharp/ql/src/utils/model-generator/internal/{CaptureTheoremsForFreeSummaryModels.qll => CaptureTypeBasedSummaryModels.qll} (95%) delete mode 100644 csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref rename csharp/ql/test/utils/model-generator/{theorems/CaptureTheoremsForFreeSummaryModels.expected => typebasedflow/CaptureTypeBasedSummaryModels.expected} (100%) create mode 100644 csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref rename csharp/ql/test/utils/model-generator/{theorems/TheoremSummaries.cs => typebasedflow/TypeBasedSummaries.cs} (100%) diff --git a/csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql similarity index 53% rename from csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql rename to csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql index 2eeb1fed949..e3dcc9dc2f6 100644 --- a/csharp/ql/src/utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql +++ b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql @@ -1,14 +1,14 @@ /** - * @name Capture Theorems for Free summary models. + * @name Capture typed based summary models. * @description Finds applicable summary models to be used by other queries. * @kind diagnostic - * @id cs/utils/model-generator/summary-models-theorems-for-free + * @id cs/utils/model-generator/summary-models-typed-based * @tags model-generator */ import semmle.code.csharp.dataflow.ExternalFlow -import internal.CaptureTheoremsForFreeSummaryModels +import internal.CaptureTypeBasedSummaryModels -from TheoremTargetApi api, string flow +from TypeBasedFlowTargetApi api, string flow where flow = captureFlow(api) select flow order by flow diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll index 2fe6ce1e6d5..82c6fbd1bbb 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -6,7 +6,7 @@ private import CaptureModelsSpecific class DataFlowTargetApi extends TargetApiSpecific { - DataFlowTargetApi() { isRelevantForFlowModels(this) } + DataFlowTargetApi() { isRelevantForDataFlowModels(this) } } /** diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll index 4a01f58ef4f..3b0a33336c0 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll @@ -42,14 +42,14 @@ private predicate isRelevantForModels(CS::Callable api) { /** * Holds if it is relevant to generate models for `api` based on data flow analysis. */ -predicate isRelevantForFlowModels(CS::Callable api) { +predicate isRelevantForDataFlowModels(CS::Callable api) { isRelevantForModels(api) and not isHigherOrder(api) } /** - * Holds if it is relevant to generate models for `api` based on Theorems for Free. + * Holds if it is relevant to generate models for `api` based on its type. */ -predicate isRelevantForTheoremModels = isRelevantForModels/1; +predicate isRelevantForTypeBasedFlowModels = isRelevantForModels/1; /** * A class of callables that are relevant generating summary, source and sinks models for. diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll similarity index 95% rename from csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll rename to csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll index 76f41231cf5..8b8172741dd 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTheoremsForFreeSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll @@ -84,7 +84,7 @@ private string implicit(DotNet::Callable callable, TypeParameter tp) { } /** - * Holds if `callable` has a delegate type parameter `tp` at parameter position `position`. + * Holds if `callable` has a delegate parameter `dt` at parameter position `position`. */ private predicate delegate(DotNet::Callable callable, DelegateType dt, int position) { exists(Parameter p | @@ -192,8 +192,8 @@ private predicate output(DotNet::Callable callable, TypeParameter tp, string out * A class of callables that are relevant generating summaries for based * on the Theorems for Free approach. */ -class TheoremTargetApi extends Specific::TargetApiSpecific { - TheoremTargetApi() { Specific::isRelevantForTheoremModels(this) } +class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific { + TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) } /** * Gets the string representation of all type based summaries inspired by @@ -228,4 +228,4 @@ class TheoremTargetApi extends Specific::TargetApiSpecific { /** * Returns the Theorems for Free inspired typed based summaries for `api`. */ -string captureFlow(TheoremTargetApi api) { result = api.getSummaries() } +string captureFlow(TypeBasedFlowTargetApi api) { result = api.getSummaries() } diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref b/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref deleted file mode 100644 index 7084f0a5aa0..00000000000 --- a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.qlref +++ /dev/null @@ -1 +0,0 @@ -utils/model-generator/CaptureTheoremsForFreeSummaryModels.ql \ No newline at end of file diff --git a/csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected similarity index 100% rename from csharp/ql/test/utils/model-generator/theorems/CaptureTheoremsForFreeSummaryModels.expected rename to csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref new file mode 100644 index 00000000000..99c0975a4c2 --- /dev/null +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref @@ -0,0 +1 @@ +utils/model-generator/CaptureTypeBasedSummaryModels.ql \ No newline at end of file diff --git a/csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs similarity index 100% rename from csharp/ql/test/utils/model-generator/theorems/TheoremSummaries.cs rename to csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs diff --git a/java/ql/src/utils/model-generator/internal/CaptureModels.qll b/java/ql/src/utils/model-generator/internal/CaptureModels.qll index 2fe6ce1e6d5..82c6fbd1bbb 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureModels.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureModels.qll @@ -6,7 +6,7 @@ private import CaptureModelsSpecific class DataFlowTargetApi extends TargetApiSpecific { - DataFlowTargetApi() { isRelevantForFlowModels(this) } + DataFlowTargetApi() { isRelevantForDataFlowModels(this) } } /** diff --git a/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll b/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll index 238f96933da..2e630ec5214 100644 --- a/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll +++ b/java/ql/src/utils/model-generator/internal/CaptureModelsSpecific.qll @@ -62,7 +62,7 @@ private predicate isRelevantForModels(J::Callable api) { /** * Holds if it is relevant to generate models for `api` based on data flow analysis. */ -predicate isRelevantForFlowModels = isRelevantForModels/1; +predicate isRelevantForDataFlowModels = isRelevantForModels/1; /** * A class of Callables that are relevant for generating summary, source and sinks models for. From 001d3571ec54cd029a86fea86f2f0e53284274d9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 13:35:31 +0200 Subject: [PATCH 14/22] C#: Restructure test cases. --- .../typebasedflow/TypeBasedSummaries.cs | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs index d92a9baa0db..0857dcdb97d 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs +++ b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs @@ -5,14 +5,14 @@ using System.Collections.Generic; namespace Summaries; -public class Theorems1 { +public class TypeBasedSimple { public T Prop { get { throw null; } set { throw null; } } - public Theorems1(T t) { throw null; } + public TypeBasedSimple(T t) { throw null; } public T Get() { throw null; } @@ -20,16 +20,16 @@ public class Theorems1 { public T Id(T x) { throw null; } - public S Transform(S x) { throw null; } + public S Id(S x) { throw null; } public void Set(T x) { throw null; } public void Set(int x, T y) { throw null; } - // No summary as S is unrelated to T - public void Set(S x) { throw null; } + public void Set(S x) { throw null; } // No summary as S is unrelated to T +} - public IList GetMany() { throw null; } +public class TypeBasedComplex { public void AddMany(IEnumerable xs) { throw null; } @@ -39,35 +39,37 @@ public class Theorems1 { public T2 Apply(T1 x, Func f) { throw null; } + public TypeBasedComplex FlatMap(Func> f) { throw null; } + + public TypeBasedComplex FlatMap(Func> f) { throw null; } + + public IList GetMany() { throw null; } + public S Map(Func f) { throw null; } - public Theorems1 MapTheorem(Func f) { throw null; } + public TypeBasedComplex MapComplex(Func f) { throw null; } - public Theorems1 FlatMap(Func> f) { throw null; } - - public Theorems1 FlatMap(Func> f) { throw null; } - - public Theorems1 Return(Func> f) { throw null; } + public TypeBasedComplex Return(Func> f) { throw null; } // Examples still not working: // public void Set(int x, Func f) { throw null;} } // It is assumed that this is a collection with elements of type T. -public class CollectionTheorems1 : IEnumerable { +public class TypeBasedCollection : IEnumerable { IEnumerator IEnumerable.GetEnumerator() { throw null; } IEnumerator IEnumerable.GetEnumerator() { throw null; } - public T First() { throw null; } - public void Add(T x) { throw null; } - public ICollection GetMany() { throw null; } - public void AddMany(IEnumerable x) { throw null; } + + public T First() { throw null; } + + public ICollection GetMany() { throw null; } } // It is assumed that this is NOT a collection with elements of type T. -public class CollectionTheorems2 : IEnumerable { +public class TypeBasedNoCollection : IEnumerable { IEnumerator IEnumerable.GetEnumerator() { throw null; } public T Get() { throw null; } From 262c28b77a38ce4d9ba3b316503399d11c175971 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 13:35:46 +0200 Subject: [PATCH 15/22] C#: Update expected test output. --- .../CaptureTypeBasedSummaryModels.expected | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected index 8aec61a529a..438ea7c0413 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected @@ -1,41 +1,41 @@ -| Summaries;CollectionTheorems1<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | -| Summaries;CollectionTheorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | -| Summaries;CollectionTheorems1<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | -| Summaries;CollectionTheorems1<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;CollectionTheorems1<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | -| Summaries;CollectionTheorems2<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | -| Summaries;CollectionTheorems2<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Apply<,>;(T1,System.Func);;Argument[0];Argument[1].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Apply<,>;(T1,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Apply<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Apply<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;FlatMap<>;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;FlatMap<>;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;GetMany;();;Argument[this].SyntheticField[ArgType0];ReturnValue.Element;value;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Id;(T);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Map<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | -| Summaries;Theorems1<>;false;Map<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;MapTheorem<>;(System.Func);;Argument[0].ReturnValue;ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;MapTheorem<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | -| Summaries;Theorems1<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Theorems1;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | -| Summaries;Theorems1<>;false;Transform<>;(S);;Argument[0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;get_Prop;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | -| Summaries;Theorems1<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | +| Summaries;TypeBasedCollection<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | +| Summaries;TypeBasedCollection<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | +| Summaries;TypeBasedCollection<>;false;GetEnumerator;();;Argument[this].Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedCollection<>;false;GetMany;();;Argument[this].Element;ReturnValue.Element;value;generated | +| Summaries;TypeBasedComplex<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<,>;(T1,System.Func);;Argument[0];Argument[1].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<,>;(T1,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Apply<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap<>;(System.Func>);;Argument[0].ReturnValue.Element;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;FlatMap<>;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;GetMany;();;Argument[this].SyntheticField[ArgType0];ReturnValue.Element;value;generated | +| Summaries;TypeBasedComplex<>;false;Map<>;(System.Func);;Argument[0].ReturnValue;ReturnValue;value;generated | +| Summaries;TypeBasedComplex<>;false;Map<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;MapComplex<>;(System.Func);;Argument[0].ReturnValue;ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;MapComplex<>;(System.Func);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | +| Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedNoCollection<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedNoCollection<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Get;(System.Object);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id;(T);;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Id<>;(S);;Argument[0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;Set;(System.Int32,T);;Argument[1];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;TypeBasedSimple;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedSimple<>;false;get_Prop;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;TypeBasedSimple<>;false;set_Prop;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | From 20cb5daeb16119346bd52aab4892a134ed750fe7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 13:37:13 +0200 Subject: [PATCH 16/22] C#: Add testcase for implicit set. --- .../utils/model-generator/typebasedflow/TypeBasedSummaries.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs index 0857dcdb97d..33f82f59993 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs +++ b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs @@ -50,8 +50,8 @@ public class TypeBasedComplex { public TypeBasedComplex MapComplex(Func f) { throw null; } public TypeBasedComplex Return(Func> f) { throw null; } - // Examples still not working: - // public void Set(int x, Func f) { throw null;} + + public void Set(int x, Func f) { throw null;} } // It is assumed that this is a collection with elements of type T. From cdb892da43c0f1fc5bf4bd53acd132119a4024c3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 13:37:48 +0200 Subject: [PATCH 17/22] C#: Update test expected output. --- .../typebasedflow/CaptureTypeBasedSummaryModels.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected index 438ea7c0413..654a1852480 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected @@ -26,6 +26,7 @@ | Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[0].ReturnValue.SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | | Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];Argument[0].Parameter[0];value;generated | | Summaries;TypeBasedComplex<>;false;Return;(System.Func>);;Argument[this].SyntheticField[ArgType0];ReturnValue.SyntheticField[ArgType0];value;generated | +| Summaries;TypeBasedComplex<>;false;Set;(System.Int32,System.Func);;Argument[1].ReturnValue;Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;TypeBasedNoCollection<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | | Summaries;TypeBasedNoCollection<>;false;Set;(T);;Argument[0];Argument[this].SyntheticField[ArgType0];value;generated | | Summaries;TypeBasedSimple<>;false;Get;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | From 0f22828cb6ca9bd25da70334648fab58c460cab9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 16:00:29 +0200 Subject: [PATCH 18/22] C#: Add test cases corresponding to the System.Linq.Enumerable extensions methods. --- .../typebasedflow/TypeBasedSummaries.cs | 134 +++++++++++++++++- 1 file changed, 133 insertions(+), 1 deletion(-) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs index 33f82f59993..f87563b945d 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs +++ b/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs @@ -75,4 +75,136 @@ public class TypeBasedNoCollection : IEnumerable { public T Get() { throw null; } public void Set(T x) { throw null; } -} \ No newline at end of file +} + +/* + * Representative subset of Linq. + * + * Only methods that will get summaries generated correctly are commented in. + * The remaning methods and interfaces are commented out with a descriptive reason. + * In some cases we will not be able correctly generate a summary based purely on the + * type information. + */ +public static class SystemLinqEnumerable { + + public static TSource Aggregate(this IEnumerable source, Func func) { throw null; } + public static TAccumulate Aggregate(this IEnumerable source, TAccumulate seed, Func func) { throw null; } + public static TResult Aggregate(this IEnumerable source, TAccumulate seed, Func func, Func resultSelector) { throw null; } + public static bool All(this IEnumerable source, Func predicate) { throw null; } + public static bool Any(this IEnumerable source) { throw null; } + public static bool Any(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Append(this IEnumerable source, TSource element) { throw null; } + public static IEnumerable AsEnumerable(this IEnumerable source) { throw null; } + public static decimal Average(this IEnumerable source, Func selector) { throw null; } + // Summary will not be derivables based on type information. + // public static IEnumerable Cast(this IEnumerable source) { throw null; } + public static IEnumerable Chunk(this IEnumerable source, int size) { throw null; } + public static IEnumerable Concat(this IEnumerable first, IEnumerable second) { throw null; } + public static bool Contains(this IEnumerable source, TSource value) { throw null; } + public static int Count(this IEnumerable source) { throw null; } + public static int Count(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable DefaultIfEmpty(this IEnumerable source) { throw null; } + public static IEnumerable DefaultIfEmpty(this IEnumerable source, TSource defaultValue) { throw null; } + public static IEnumerable DistinctBy(this IEnumerable source, Func keySelector) { throw null; } + public static IEnumerable Distinct(this IEnumerable source) { throw null; } + public static TSource? ElementAtOrDefault(this IEnumerable source, int index) { throw null; } + public static TSource ElementAt(this IEnumerable source, int index) { throw null; } + public static IEnumerable Empty() { throw null; } + // These summaries will not be derivable based on type information. + // public static IEnumerable ExceptBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + // public static IEnumerable Except(this IEnumerable first, IEnumerable second) { throw null; } + public static TSource? FirstOrDefault(this IEnumerable source) { throw null; } + public static TSource FirstOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? FirstOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information. + // public static TSource FirstOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource First(this IEnumerable source) { throw null; } + public static TSource First(this IEnumerable source, Func predicate) { throw null; } + // Missing summary for Argument[0].Element -> Argument[2].Parameter[1].Element and similar problem for GroupJoin (issue with generator) + // public static IEnumerable GroupBy(this IEnumerable source, Func keySelector, Func, TResult> resultSelector) { throw null; } + // public static IEnumerable GroupJoin(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func, TResult> resultSelector) { throw null; } + public static IEnumerable IntersectBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + public static IEnumerable Intersect(this IEnumerable first, IEnumerable second) { throw null; } + public static IEnumerable Join(this IEnumerable outer, IEnumerable inner, Func outerKeySelector, Func innerKeySelector, Func resultSelector) { throw null; } + public static TSource? LastOrDefault(this IEnumerable source) { throw null; } + public static TSource LastOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? LastOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information (same problem as for FirstOrDefault) + // public static TSource LastOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource Last(this IEnumerable source) { throw null; } + public static TSource Last(this IEnumerable source, Func predicate) { throw null; } + public static long LongCount(this IEnumerable source, Func predicate) { throw null; } + public static TSource? MaxBy(this IEnumerable source, Func keySelector) { throw null; } + public static TSource? Max(this IEnumerable source) { throw null; } + public static decimal Max(this IEnumerable source, Func selector) { throw null; } + public static TResult? Max(this IEnumerable source, Func selector) { throw null; } + public static TSource? MinBy(this IEnumerable source, Func keySelector) { throw null; } + public static TSource? Min(this IEnumerable source) { throw null; } + public static TResult? Min(this IEnumerable source, Func selector) { throw null; } + // These summaries will not be derivable based on type information. + // public static IEnumerable OfType(this IEnumerable source) { throw null; } + public static IOrderedEnumerable OrderByDescending(this IEnumerable source, Func keySelector) { throw null; } + public static IOrderedEnumerable OrderBy(this IEnumerable source, Func keySelector) { throw null; } + public static IEnumerable Prepend(this IEnumerable source, TSource element) { throw null; } + public static IEnumerable Repeat(TResult element, int count) { throw null; } + public static IEnumerable Reverse(this IEnumerable source) { throw null; } + public static IEnumerable SelectMany(this IEnumerable source, Func> selector) { throw null; } + public static IEnumerable SelectMany(this IEnumerable source, Func> collectionSelector, Func resultSelector) { throw null; } + public static IEnumerable Select(this IEnumerable source, Func selector) { throw null; } + public static bool SequenceEqual(this IEnumerable first, IEnumerable second) { throw null; } + public static TSource? SingleOrDefault(this IEnumerable source) { throw null; } + public static TSource SingleOrDefault(this IEnumerable source, TSource defaultValue) { throw null; } + public static TSource? SingleOrDefault(this IEnumerable source, Func predicate) { throw null; } + // Summary will not be correctly derivable based on type information (same problem as for FirstOrDefault) + // public static TSource SingleOrDefault(this IEnumerable source, Func predicate, TSource defaultValue) { throw null; } + public static TSource Single(this IEnumerable source) { throw null; } + public static TSource Single(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable SkipLast(this IEnumerable source, int count) { throw null; } + public static IEnumerable SkipWhile(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Skip(this IEnumerable source, int count) { throw null; } + public static IEnumerable TakeLast(this IEnumerable source, int count) { throw null; } + public static IEnumerable TakeWhile(this IEnumerable source, Func predicate) { throw null; } + public static IEnumerable Take(this IEnumerable source, int count) { throw null; } + public static IOrderedEnumerable ThenByDescending(this IOrderedEnumerable source, Func keySelector) { throw null; } + public static IOrderedEnumerable ThenBy(this IOrderedEnumerable source, Func keySelector) { throw null; } + // Missing summary for Argument[0].Element -> ReturnValue.Element (issue with generator) + // public static TSource[] ToArray(this IEnumerable source) { throw null; } + // Summaries related to dictionaries is not generated correctly as dictionaries are not identified as collections of keys and values (issue with generator). + // public static Dictionary ToDictionary(this IEnumerable source, Func keySelector) where TKey : notnull { throw null; } + // public static Dictionary ToDictionary(this IEnumerable source, Func keySelector, Func elementSelector) where TKey : notnull { throw null; } + public static HashSet ToHashSet(this IEnumerable source) { throw null; } + public static List ToList(this IEnumerable source) { throw null; } + // Type to complicated to be handled by the generator (issue with generator). + // public static ILookup ToLookup(this IEnumerable source, Func keySelector) { throw null; } + // public static ILookup ToLookup(this IEnumerable source, Func keySelector, Func elementSelector) { throw null; } + public static IEnumerable UnionBy(this IEnumerable first, IEnumerable second, Func keySelector) { throw null; } + public static IEnumerable Union(this IEnumerable first, IEnumerable second) { throw null; } + public static IEnumerable Where(this IEnumerable source, Func predicate) { throw null; } + // Type to complicated to be handled by the generator (issue with generator). + // public static IEnumerable<(TFirst First, TSecond Second)> Zip(this IEnumerable first, IEnumerable second) { throw null; } + // public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip(this IEnumerable first, IEnumerable second, IEnumerable third) { throw null; } + public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func resultSelector) { throw null; } +} + +public interface IGrouping : IEnumerable, IEnumerable { + TKey Key { get; } +} + +// public interface ILookup : IEnumerable>, IEnumerable { +// IEnumerable this[TKey key] { get; } +// bool Contains(TKey key); +// } + +public interface IOrderedEnumerable : IEnumerable, IEnumerable { + IOrderedEnumerable CreateOrderedEnumerable(Func keySelector, IComparer? comparer, bool descending); +} + +// public partial class Lookup : IEnumerable>, IEnumerable, ILookup{ +// internal Lookup() { } +// public int Count { get { throw null; } } +// public IEnumerable this[TKey key] { get { throw null; } } +// public IEnumerable ApplyResultSelector(Func, TResult> resultSelector) { throw null; } +// public bool Contains(TKey key) { throw null; } +// public IEnumerator> GetEnumerator() { throw null; } +// IEnumerator IEnumerable.GetEnumerator() { throw null; } +// } From 4e57b40c2a271b147f7129ee7f2d28787bc946c6 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 16:00:53 +0200 Subject: [PATCH 19/22] C#: Update test expected output. --- .../CaptureTypeBasedSummaryModels.expected | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected index 654a1852480..6405ea3fab8 100644 --- a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected +++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected @@ -1,3 +1,126 @@ +| Summaries;IGrouping<,>;true;get_Key;();;Argument[this].SyntheticField[ArgType0];ReturnValue;value;generated | +| Summaries;IOrderedEnumerable<>;true;CreateOrderedEnumerable<>;(System.Func,System.Collections.Generic.IComparer,System.Boolean);;Argument[this].Element;Argument[0].Parameter[0];value;generated | +| Summaries;IOrderedEnumerable<>;true;CreateOrderedEnumerable<>;(System.Func,System.Collections.Generic.IComparer,System.Boolean);;Argument[this].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[0].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[1];Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[1];Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[2].ReturnValue;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[2].ReturnValue;Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func,System.Func);;Argument[3].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[0].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[1];Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[2].ReturnValue;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<,>;(System.Collections.Generic.IEnumerable,TAccumulate,System.Func);;Argument[2].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;Argument[1].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Aggregate<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;All<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Any<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Append<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Append<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;AsEnumerable<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Average<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Concat<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Concat<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Count<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DefaultIfEmpty<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Distinct<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;DistinctBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;DistinctBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ElementAt<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;ElementAtOrDefault<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;First<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;FirstOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Intersect<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Intersect<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;IntersectBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;IntersectBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[0].Element;Argument[4].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[1].Element;Argument[3].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[1].Element;Argument[4].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Join<,,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func,System.Func,System.Func);;Argument[4].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Last<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LastOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;LongCount<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Max<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Max<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Max<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Max<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MaxBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MaxBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Min<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Min<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Min<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;MinBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;MinBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;OrderBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;OrderBy<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;OrderByDescending<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;OrderByDescending<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Prepend<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Prepend<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Repeat<>;(TResult,System.Int32);;Argument[0];ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Reverse<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Select<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Select<,>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[1].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[1].ReturnValue.Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,,>;(System.Collections.Generic.IEnumerable,System.Func>,System.Func);;Argument[2].ReturnValue;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,>;(System.Collections.Generic.IEnumerable,System.Func>);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SelectMany<,>;(System.Collections.Generic.IEnumerable,System.Func>);;Argument[1].ReturnValue.Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Single<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[0].Element;ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;SingleOrDefault<>;(System.Collections.Generic.IEnumerable,TSource);;Argument[1];ReturnValue;value;generated | +| Summaries;SystemLinqEnumerable;false;Skip<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SkipLast<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;SkipWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;SkipWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Take<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;TakeLast<>;(System.Collections.Generic.IEnumerable,System.Int32);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;TakeWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;TakeWhile<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ThenBy<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;ThenBy<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ThenByDescending<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;ThenByDescending<,>;(Summaries.IOrderedEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ToHashSet<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;ToList<>;(System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Union<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Union<>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;UnionBy<,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Where<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[1].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Where<>;(System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;ReturnValue.Element;value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[0].Element;Argument[2].Parameter[0];value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[1].Element;Argument[2].Parameter[1];value;generated | +| Summaries;SystemLinqEnumerable;false;Zip<,,>;(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEnumerable,System.Func);;Argument[2].ReturnValue;ReturnValue.Element;value;generated | | Summaries;TypeBasedCollection<>;false;Add;(T);;Argument[0];Argument[this].Element;value;generated | | Summaries;TypeBasedCollection<>;false;AddMany;(System.Collections.Generic.IEnumerable);;Argument[0].Element;Argument[this].Element;value;generated | | Summaries;TypeBasedCollection<>;false;First;();;Argument[this].Element;ReturnValue;value;generated | From b05a1f4f39cf38af1b7877c1151bae973c95ba73 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 13 Sep 2022 16:40:56 +0200 Subject: [PATCH 20/22] C#: Support for type based model generation via python script. --- .../models-as-data/generate_flow_model.py | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/misc/scripts/models-as-data/generate_flow_model.py b/misc/scripts/models-as-data/generate_flow_model.py index 3a0583fb15b..bb46565ea3b 100644 --- a/misc/scripts/models-as-data/generate_flow_model.py +++ b/misc/scripts/models-as-data/generate_flow_model.py @@ -15,12 +15,13 @@ class Generator: self.generateSources = False self.generateSummaries = False self.generateNegativeSummaries = False + self.generateTypeBasedSummaries = False self.dryRun = False def printHelp(self): print(f"""Usage: -python3 GenerateFlowModel.py [] [--with-sinks] [--with-sources] [--with-summaries] [--dry-run] +python3 GenerateFlowModel.py [] [--with-sinks] [--with-sources] [--with-summaries] [--with-typebased-summaries] [--dry-run] This generates summary, source and sink models for the code in the database. The files will be placed in `{self.language}/ql/lib/semmle/code/{self.language}/frameworks/` where @@ -33,6 +34,7 @@ Which models are generated is controlled by the flags: --with-sources --with-summaries --with-negative-summaries + --with-typebased-summaries (Experimental - only for C#) If none of these flags are specified, all models are generated. --dry-run: Only run the queries, but don't write to file. @@ -62,6 +64,7 @@ Requirements: `codeql` should both appear on your path. self.codeQlRoot, f"{self.language}/ql/lib/semmle/code/{self.language}/frameworks/") self.frameworkTarget = os.path.join(self.generatedFrameworks, dirname, filename) self.negativeFrameworkTarget = os.path.join(self.generatedFrameworks, dirname, "Negative" + filename) + self.typeBasedFrameworkTarget = os.path.join(self.generatedFrameworks, dirname, "TypeBased" + filename) self.workDir = tempfile.mkdtemp() os.makedirs(self.generatedFrameworks, exist_ok=True) @@ -90,11 +93,15 @@ Requirements: `codeql` should both appear on your path. sys.argv.remove("--with-negative-summaries") generator.generateNegativeSummaries = True + if "--with-typebased-summaries" in sys.argv: + sys.argv.remove("--with-typebased-summaries") + generator.generateTypeBasedSummaries = True + if "--dry-run" in sys.argv: sys.argv.remove("--dry-run") generator.dryRun = True - if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNegativeSummaries: + if not generator.generateSinks and not generator.generateSources and not generator.generateSummaries and not generator.generateNegativeSummaries and not generator.generateTypeBasedSummaries: generator.generateSinks = generator.generateSources = generator.generateSummaries = generator.generateNegativeSummaries = True if len(sys.argv) < 3 or len(sys.argv) > 4: @@ -207,7 +214,7 @@ private import semmle.code.{self.language}.dataflow.ExternalFlow negativeSummaryCsv = "" return f""" -/** +/** * THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. * Definitions of negative summaries in the {self.friendlyname} framework. */ @@ -219,6 +226,25 @@ private import semmle.code.{self.language}.dataflow.ExternalFlow """ + def makeTypeBasedContent(self): + if self.generateTypeBasedSummaries: + typeBasedSummaryRows = self.runQuery("type based summary models", "CaptureTypeBasedSummaryModels.ql") + typeBasedSummaryCsv = self.asCsvModel("SummaryModelCsv", "TypeBasedSummary", typeBasedSummaryRows) + else: + typeBasedSummaryCsv = "" + + return f""" +/** + * THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. + * Definitions of type based summaries in the {self.friendlyname} framework. + */ + +import {self.language} +private import semmle.code.{self.language}.dataflow.ExternalFlow + +{typeBasedSummaryCsv} + + """ def save(self, content, target): with open(target, "w") as targetQll: @@ -237,6 +263,7 @@ private import semmle.code.{self.language}.dataflow.ExternalFlow def run(self): content = self.makeContent() negativeContent = self.makeNegativeContent() + typeBasedContent = self.makeTypeBasedContent() if self.dryRun: print("CSV Models generated, but not written to file.") @@ -247,3 +274,6 @@ private import semmle.code.{self.language}.dataflow.ExternalFlow if self.generateNegativeSummaries: self.save(negativeContent, self.negativeFrameworkTarget) + + if self.generateTypeBasedSummaries: + self.save(typeBasedContent, self.typeBasedFrameworkTarget) From a464e5be72d3f85c90bdb205b0915db966b097a3 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Sat, 17 Sep 2022 13:51:03 +0200 Subject: [PATCH 21/22] C#: Address review comments. --- .../CaptureTypeBasedSummaryModels.qll | 67 ++++++++----------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll index 8b8172741dd..478247e6174 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll @@ -18,29 +18,19 @@ private predicate genericCollectionType(ValueOrRefType t, TypeParameter tp) { ) } -/** - * Holds if `tp` is a type parameter of `generic`. - */ -private predicate unboundGeneric(UnboundGeneric generic, TypeParameter tp) { - tp = generic.getATypeParameter() -} - /** * Holds if `tp` is a type parameter of the immediate type declaring `callable`. */ private predicate classTypeParameter(DotNet::Callable callable, TypeParameter tp) { - unboundGeneric(callable.getDeclaringType(), tp) + callable.getDeclaringType().(UnboundGeneric).getATypeParameter() = tp } /** * Holds if `tp` is type parameter of `callable` or the type declaring `callable`. */ private predicate localTypeParameter(DotNet::Callable callable, TypeParameter tp) { - classTypeParameter(callable, tp) or unboundGeneric(callable, tp) -} - -private predicate constructedGeneric(ConstructedType t, TypeParameter tp) { - t.getATypeArgument() = tp + classTypeParameter(callable, tp) or + callable.(UnboundGeneric).getATypeParameter() = tp } /** @@ -101,7 +91,7 @@ private predicate delegate(DotNet::Callable callable, DelegateType dt, int posit * Note: This predicate has to be inlined as `callable` is not related to `return` or `tp` * in every disjunction. */ -pragma[inline] +bindingset[callable] private string getAccess(DotNet::Callable callable, Type return, TypeParameter tp) { return = tp and result = "" or @@ -109,9 +99,9 @@ private string getAccess(DotNet::Callable callable, Type return, TypeParameter t or not genericCollectionType(return, tp) and ( - constructedGeneric(return, tp) + return.(ConstructedGeneric).getATypeArgument() = tp or - callable.getDeclaringType() = return and unboundGeneric(return, tp) + callable.getDeclaringType() = return and return.(UnboundGeneric).getATypeParameter() = tp ) and result = getSyntheticField(tp) } @@ -120,7 +110,7 @@ private string getAccess(DotNet::Callable callable, Type return, TypeParameter t * Holds if `input` is a models as data string representation of, how a value of type `tp` * (or a generic parameterized over `tp`) can be generated by a delegate parameter of `callable`. */ -private predicate source(DotNet::Callable callable, string input, TypeParameter tp) { +private predicate delegateSource(DotNet::Callable callable, string input, TypeParameter tp) { exists(DelegateType dt, int position, Type return, string access | delegate(callable, dt, position) and return = dt.getReturnType() and @@ -143,7 +133,7 @@ private predicate input(DotNet::Callable callable, string input, TypeParameter t or parameter(callable, input, tp) or - source(callable, input, tp) + delegateSource(callable, input, tp) } /** @@ -162,12 +152,11 @@ private predicate returns(DotNet::Callable callable, TypeParameter tp, string ou * and `output` is the models as data string representation of, how data is routed to * the delegate parameter. */ -private predicate sink(DotNet::Callable callable, TypeParameter tp, string output) { - exists(DelegateType dt, int position, Type t, Parameter p | +private predicate delegateSink(DotNet::Callable callable, TypeParameter tp, string output) { + exists(DelegateType dt, int position, Parameter p | delegate(callable, dt, position) and p = dt.getAParameter() and - t = p.getType() and - t = tp and + p.getType() = tp and output = "Argument[" + position + "]" + ".Parameter[" + p.getPosition() + "]" ) } @@ -185,7 +174,7 @@ private predicate output(DotNet::Callable callable, TypeParameter tp, string out or returns(callable, tp, output) or - sink(callable, tp, output) + delegateSink(callable, tp, output) } /** @@ -196,22 +185,24 @@ class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific { TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) } /** - * Gets the string representation of all type based summaries inspired by - * the Theorems for Free approach. + * Gets the string representation of all type based summaries for `this` + * inspired by the Theorems for Free approach. * - * Basic example signatures could be - * this : T -> \alpha - * this : \beta -> T - * where T is type parameter on `this` or on the declaring type of `this`. - * - * Important special cases are \alpha = unit (setter), - * \alpha = T (getter, setter and id) and \beta = unit (getter). - * - * Complex example signatures could be - * this : (T -> S) -> S - * this : S1 x (S1 -> S2) -> S2 - * where T is type parameter of the class declaring `this` and S, S1 and S2 are type parameters - * of `this`. + * Examples could be (see C# psuedo code below) + * (1) `Get` returns a value of type `T`. We assume that the returned + * value was fetched from a (synthetic) field. + * (2) `Set` consumes a value of type `T`. We assume that the value is stored in + * a (synthetic) field. + * (3) `Apply` is assumed to apply the provided function to a value stored in + * a (synthetic) field and return the result. + * (4) `Apply` is assumed to apply the provided function to provided value + * and return the result. + * public class MyGeneric { + * public void Set(T x) { ... } + * public T Get() { ... } + * public S Apply(Func f) { ... } + * public S2 Apply(S1 x, Func f) { ... } + * } */ string getSummaries() { exists(TypeParameter tp, string input, string output | From 6e3bc38acf3a32c6b8f241c75e84088947e5b46f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 19 Sep 2022 16:03:50 +0200 Subject: [PATCH 22/22] C#: Fix minor issues in QL doc. --- .../model-generator/internal/CaptureTypeBasedSummaryModels.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll index 478247e6174..02f00986c3c 100644 --- a/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll +++ b/csharp/ql/src/utils/model-generator/internal/CaptureTypeBasedSummaryModels.qll @@ -197,12 +197,14 @@ class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific { * a (synthetic) field and return the result. * (4) `Apply` is assumed to apply the provided function to provided value * and return the result. + * ```csharp * public class MyGeneric { * public void Set(T x) { ... } * public T Get() { ... } * public S Apply(Func f) { ... } * public S2 Apply(S1 x, Func f) { ... } * } + * ``` */ string getSummaries() { exists(TypeParameter tp, string input, string output |