diff --git a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll b/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll index 36cb62e655fc..517531ecfbf7 100644 --- a/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll +++ b/csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll @@ -130,7 +130,13 @@ class SinkTargetApi extends SourceOrSinkTargetApi { * A class of callables that are potentially relevant for generating source models. */ class SourceTargetApi extends SourceOrSinkTargetApi { - SourceTargetApi() { not hasManualSourceModel(this) } + SourceTargetApi() { + not hasManualSourceModel(this) and + // Do not generate source models for overridable callables + // as virtual dispatch implies that too many methods + // will be considered sources. + not this.(Overridable).overridesOrImplements(_) + } } /** diff --git a/csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs index 855f70185572..3165dfa2f904 100644 --- a/csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs +++ b/csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs @@ -52,25 +52,38 @@ public bool WrapConsoleReadLineGetBool() return s == "hello"; } - public class MyConsoleReader + public abstract class ValueReader { - // source=Sources;NewSources+MyConsoleReader;false;ToString;();;ReturnValue;local;df-generated - // neutral=Sources;NewSources+MyConsoleReader;ToString;();summary;df-generated - public override string ToString() + // neutral=Sources;NewSources+ValueReader;GetValue;();summary;df-generated + public abstract string GetValue(); + } + + public class MyConsoleReader : ValueReader + { + // neutral=Sources;NewSources+MyConsoleReader;GetValue;();summary;df-generated + public override string GetValue() { return Console.ReadLine(); } } + public class MyOtherReader : ValueReader + { + // neutral=Sources;NewSources+MyOtherReader;GetValue;();summary;df-generated + public override string GetValue() + { + return ""; + } + } - public class MyContainer + public class MyContainer where T : ValueReader { public T Value { get; set; } - // summary=Sources;NewSources+MyContainer;false;Read;();;Argument[this];ReturnValue;taint;df-generated + // neutral=Sources;NewSources+MyContainer;Read;();summary;df-generated public string Read() { - return Value.ToString(); + return Value.GetValue(); } } @@ -97,7 +110,6 @@ public abstract class DataReader public class DataReaderKind1 : DataReader { - // source=Sources;NewSources+DataReaderKind1;true;Read;();;ReturnValue;source-kind-1;df-generated // neutral=Sources;NewSources+DataReaderKind1;Read;();summary;df-generated public override string Read() { @@ -105,13 +117,31 @@ public override string Read() } } - public class DataReaderKind2 : DataReader + public sealed class DataReaderKind2 : DataReader { - // source=Sources;NewSources+DataReaderKind2;true;Read;();;ReturnValue;source-kind-2;df-generated // neutral=Sources;NewSources+DataReaderKind2;Read;();summary;df-generated public override string Read() { return Source2(); } } + + public class C1 + { + // neutral=Sources;NewSources+C1;ToString;();summary;df-generated + public override string ToString() + { + return Source1(); + } + } + + public sealed class C2 + { + // neutral=Sources;NewSources+C2;ToString;();summary;df-generated + public override string ToString() + { + return Source1(); + } + } + } diff --git a/misc/scripts/models-as-data/generate_flow_model.py b/misc/scripts/models-as-data/generate_flow_model.py index 26dd961f4019..7654713d2804 100644 --- a/misc/scripts/models-as-data/generate_flow_model.py +++ b/misc/scripts/models-as-data/generate_flow_model.py @@ -193,7 +193,7 @@ def run(self): print("Models as data extensions generated, but not written to file.") sys.exit(0) - if self.generateSinks or self.generateSinks or self.generateSummaries: + if self.generateSinks or self.generateSources or self.generateSummaries or self.generateNeutrals: self.save(content, ".model.yml") if self.generateTypeBasedSummaries: