mirror of
https://github.com/github/codeql.git
synced 2026-04-21 23:14:03 +02:00
Merge pull request #4378 from tamasvajk/feature/flow-summary-nullable
Flow summary nullable
This commit is contained in:
@@ -347,7 +347,7 @@ abstract class LibraryTypeDataFlow extends Type {
|
||||
* Holds if data may flow from `source` to `sink` when calling callable `c`.
|
||||
*
|
||||
* `sourceAp` describes the contents of `source` that flows to `sink`
|
||||
* (if any), and `sinkContent` describes the contents of `sink` that it
|
||||
* (if any), and `sinkAp` describes the contents of `sink` that it
|
||||
* flows to (if any).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
@@ -736,6 +736,49 @@ class SystemLazyFlow extends LibraryTypeDataFlow, SystemLazyClass {
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Nullable<>`. */
|
||||
class SystemNullableFlow extends LibraryTypeDataFlow, SystemNullableStruct {
|
||||
override predicate callableFlow(
|
||||
CallableFlowSource source, AccessPath sourceAp, CallableFlowSink sink, AccessPath sinkAp,
|
||||
SourceDeclarationCallable c, boolean preservesValue
|
||||
) {
|
||||
preservesValue = true and
|
||||
c.(Constructor).getDeclaringType() = this and
|
||||
source = getFlowSourceArg(c, 0, sourceAp) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::property(this.getValueProperty())
|
||||
or
|
||||
preservesValue = true and
|
||||
c = this.getAGetValueOrDefaultMethod() and
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
sourceAp = AccessPath::property(this.getValueProperty()) and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
preservesValue = false and
|
||||
c = this.getHasValueProperty().getGetter() and
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
sourceAp = AccessPath::property(this.getValueProperty()) and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
preservesValue = true and
|
||||
c = this.getAGetValueOrDefaultMethod() and
|
||||
source = getFlowSourceArg(c, 0, _) and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
or
|
||||
preservesValue = false and
|
||||
c = this.getValueProperty().getGetter() and
|
||||
source = TCallableFlowSourceQualifier() and
|
||||
sourceAp = AccessPath::empty() and
|
||||
sink = TCallableFlowSinkReturn() and
|
||||
sinkAp = AccessPath::empty()
|
||||
}
|
||||
}
|
||||
|
||||
/** Data flow for `System.Collections.IEnumerable` (and sub types). */
|
||||
class IEnumerableFlow extends LibraryTypeDataFlow, RefType {
|
||||
IEnumerableFlow() { this.getABaseType*() instanceof SystemCollectionsIEnumerableInterface }
|
||||
|
||||
@@ -21,6 +21,11 @@ class SystemUnboundGenericClass extends UnboundGenericClass {
|
||||
SystemUnboundGenericClass() { this.getNamespace() instanceof SystemNamespace }
|
||||
}
|
||||
|
||||
/** An unbound generic struct in the `System` namespace. */
|
||||
class SystemUnboundGenericStruct extends UnboundGenericStruct {
|
||||
SystemUnboundGenericStruct() { this.getNamespace() instanceof SystemNamespace }
|
||||
}
|
||||
|
||||
/** An interface in the `System` namespace. */
|
||||
class SystemInterface extends Interface {
|
||||
SystemInterface() { this.getNamespace() instanceof SystemNamespace }
|
||||
@@ -215,6 +220,35 @@ class SystemLazyClass extends SystemUnboundGenericClass {
|
||||
}
|
||||
}
|
||||
|
||||
/** The `System.Nullable<T>` struct. */
|
||||
class SystemNullableStruct extends SystemUnboundGenericStruct {
|
||||
SystemNullableStruct() {
|
||||
this.hasName("Nullable<>") and
|
||||
this.getNumberOfTypeParameters() = 1
|
||||
}
|
||||
|
||||
/** Gets the `Value` property. */
|
||||
Property getValueProperty() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("Value") and
|
||||
result.getType() = getTypeParameter(0)
|
||||
}
|
||||
|
||||
/** Gets the `HasValue` property. */
|
||||
Property getHasValueProperty() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("HasValue") and
|
||||
result.getType() instanceof BoolType
|
||||
}
|
||||
|
||||
/** Gets a `GetValueOrDefault()` method. */
|
||||
Method getAGetValueOrDefaultMethod() {
|
||||
result.getDeclaringType() = this and
|
||||
result.hasName("GetValueOrDefault") and
|
||||
result.getReturnType() = getTypeParameter(0)
|
||||
}
|
||||
}
|
||||
|
||||
/** The `System.NullReferenceException` class. */
|
||||
class SystemNullReferenceExceptionClass extends SystemClass {
|
||||
SystemNullReferenceExceptionClass() { this.hasName("NullReferenceException") }
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
class C
|
||||
{
|
||||
sbyte x1;
|
||||
sbyte? x2;
|
||||
int x1;
|
||||
int? x2;
|
||||
Nullable<int> x3;
|
||||
Nullable<char> x4;
|
||||
|
||||
// Verify conversions
|
||||
void M()
|
||||
{
|
||||
x2 = x1;
|
||||
x3 = x4;
|
||||
x2 = x1; // T -> T? conversion: implicit, nullable -> implicit cast
|
||||
x3 = x4; // T1? -> T2? conversion: implicit, nullable -> implicit cast
|
||||
|
||||
x12 = x1; // T1 -> T2? conversion: implicit, nullable -> implicit cast
|
||||
x12 = null; // null -> T? conversion: implicit, null literal -> no cast
|
||||
|
||||
x3 = x2; // T? -> T? no conversion
|
||||
|
||||
x14 = x15; // T1? -> T2? conversion: implicit, user defined -> implicit cast
|
||||
}
|
||||
|
||||
// Cause the following types to exist in the database:
|
||||
sbyte? x0;
|
||||
byte? x5;
|
||||
short? x6;
|
||||
ushort? x7;
|
||||
@@ -24,4 +33,19 @@ class C
|
||||
double? x11;
|
||||
long? x12;
|
||||
float? x13;
|
||||
|
||||
A? x14;
|
||||
B? x15;
|
||||
|
||||
struct A
|
||||
{
|
||||
}
|
||||
|
||||
struct B
|
||||
{
|
||||
public static implicit operator A(B value)
|
||||
{
|
||||
return new A();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,6 +494,8 @@ callableFlow
|
||||
| System.Net.WebUtility.HtmlEncode(string) | argument 0 -> return | false |
|
||||
| System.Net.WebUtility.HtmlEncode(string, TextWriter) | argument 0 -> return | false |
|
||||
| System.Net.WebUtility.UrlEncode(string) | argument 0 -> return | false |
|
||||
| System.Nullable<>.GetValueOrDefault(T) | argument 0 -> return | true |
|
||||
| System.Nullable<>.get_Value() | qualifier -> return | false |
|
||||
| System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | qualifier -> argument 0 | false |
|
||||
| System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | argument 0 -> qualifier | false |
|
||||
| System.Security.Cryptography.CryptoStream.Read(Byte[], int, int) | qualifier -> argument 0 | false |
|
||||
@@ -1767,6 +1769,10 @@ callableFlowAccessPath
|
||||
| System.Net.NetworkInformation.IPAddressCollection.Add(IPAddress) | argument 0 [<empty>] -> qualifier [[]] | true |
|
||||
| System.Net.NetworkInformation.IPAddressCollection.CopyTo(IPAddress[], int) | qualifier [[]] -> argument 0 [[]] | true |
|
||||
| System.Net.NetworkInformation.IPAddressCollection.GetEnumerator() | qualifier [[]] -> return [Current] | true |
|
||||
| System.Nullable<>.GetValueOrDefault() | qualifier [Value] -> return [<empty>] | true |
|
||||
| System.Nullable<>.GetValueOrDefault(T) | qualifier [Value] -> return [<empty>] | true |
|
||||
| System.Nullable<>.Nullable(T) | argument 0 [<empty>] -> return [Value] | true |
|
||||
| System.Nullable<>.get_HasValue() | qualifier [Value] -> return [<empty>] | false |
|
||||
| System.Resources.ResourceReader.GetEnumerator() | qualifier [[]] -> return [Current] | true |
|
||||
| System.Resources.ResourceSet.GetEnumerator() | qualifier [[]] -> return [Current] | true |
|
||||
| System.Runtime.CompilerServices.ConditionalWeakTable<,>.GetEnumerator() | qualifier [[]] -> return [Current] | true |
|
||||
|
||||
Reference in New Issue
Block a user