diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs index 5bf2882b31d..4f82ac800b9 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs @@ -565,6 +565,8 @@ protected override ShapedQueryExpression TranslateJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); return null; @@ -618,6 +620,8 @@ protected override ShapedQueryExpression TranslateLeftJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); return null; diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingReadItemExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingReadItemExpressionVisitor.cs index 3c95dd9364a..a89c430083a 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingReadItemExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.CosmosProjectionBindingRemovingReadItemExpressionVisitor.cs @@ -1,8 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Query; namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs index 3b85b524b31..0e1ae7ce05c 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryProjectionBindingExpressionVisitor.cs @@ -122,7 +122,7 @@ public override Expression Visit(Expression expression) _queryableMethodTranslatingExpressionVisitor.TranslateSubquery( materializeCollectionNavigationExpression.Subquery), materializeCollectionNavigationExpression.Navigation, - null); + materializeCollectionNavigationExpression.Navigation.ClrType.TryGetSequenceType()); case MethodCallExpression methodCallExpression: { diff --git a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index db9df7c7130..489dcae9b15 100644 --- a/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Internal/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -560,6 +560,8 @@ protected override ShapedQueryExpression TranslateJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); (outerKeySelector, innerKeySelector) = ProcessJoinKeySelector(outer, inner, outerKeySelector, innerKeySelector); @@ -726,6 +728,8 @@ protected override ShapedQueryExpression TranslateLeftJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); (outerKeySelector, innerKeySelector) = ProcessJoinKeySelector(outer, inner, outerKeySelector, innerKeySelector); diff --git a/src/EFCore.InMemory/Storage/InMemoryDatabaseRoot.cs b/src/EFCore.InMemory/Storage/InMemoryDatabaseRoot.cs index 4f53ba64e9e..5d0654927db 100644 --- a/src/EFCore.InMemory/Storage/InMemoryDatabaseRoot.cs +++ b/src/EFCore.InMemory/Storage/InMemoryDatabaseRoot.cs @@ -10,7 +10,7 @@ namespace Microsoft.EntityFrameworkCore.Storage /// across context instances and service providers as long as the same instance /// of this type is passed to /// + /// cref="InMemoryDbContextOptionsExtensions.UseInMemoryDatabase{TContext}(DbContextOptionsBuilder{TContext},string,System.Action{InMemoryDbContextOptionsBuilder})" /> /// public sealed class InMemoryDatabaseRoot { diff --git a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs index 9880fccc1c0..0e3ac1966c0 100644 --- a/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs +++ b/src/EFCore.Relational/Extensions/RelationalDatabaseFacadeExtensions.cs @@ -639,7 +639,7 @@ public static void SetCommandTimeout([NotNull] this DatabaseFacade databaseFacad /// /// /// This is a sugar method allowing a to be used to set the value. It delegates to - /// . + /// . /// /// /// The for the context. diff --git a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs index f245bff2b3a..e15ceee0707 100644 --- a/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/RelationalProjectionBindingExpressionVisitor.cs @@ -163,7 +163,8 @@ public override Expression Visit(Expression expression) return _selectExpression.AddCollectionProjection( _queryableMethodTranslatingExpressionVisitor.TranslateSubquery( materializeCollectionNavigationExpression.Subquery), - materializeCollectionNavigationExpression.Navigation, null); + materializeCollectionNavigationExpression.Navigation, + materializeCollectionNavigationExpression.Navigation.ClrType.TryGetSequenceType()); case MethodCallExpression methodCallExpression: { diff --git a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 2ff0452beab..dac3deb55ab 100644 --- a/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -586,6 +586,8 @@ protected override ShapedQueryExpression TranslateJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); var joinPredicate = CreateJoinPredicate(outer, outerKeySelector, inner, innerKeySelector); @@ -611,6 +613,8 @@ protected override ShapedQueryExpression TranslateLeftJoin( { Check.NotNull(outer, nameof(outer)); Check.NotNull(inner, nameof(inner)); + Check.NotNull(outerKeySelector, nameof(outerKeySelector)); + Check.NotNull(innerKeySelector, nameof(innerKeySelector)); Check.NotNull(resultSelector, nameof(resultSelector)); var joinPredicate = CreateJoinPredicate(outer, outerKeySelector, inner, innerKeySelector); diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs index 506ac1815ab..51e4e57e795 100644 --- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs +++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs @@ -1332,7 +1332,7 @@ static Expression RemoveConvert(Expression expression) public CollectionShaperExpression AddCollectionProjection( [NotNull] ShapedQueryExpression shapedQueryExpression, [CanBeNull] INavigationBase navigation, - [CanBeNull] Type elementType) + [NotNull] Type elementType) { Check.NotNull(shapedQueryExpression, nameof(shapedQueryExpression)); diff --git a/src/EFCore.Relational/Storage/RelationalConnection.cs b/src/EFCore.Relational/Storage/RelationalConnection.cs index 47c6d79b428..522429c9677 100644 --- a/src/EFCore.Relational/Storage/RelationalConnection.cs +++ b/src/EFCore.Relational/Storage/RelationalConnection.cs @@ -233,7 +233,7 @@ public virtual void EnlistTransaction(Transaction transaction) } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// /// The transaction to be used. @@ -322,7 +322,7 @@ public virtual IDbContextTransaction BeginTransaction(IsolationLevel isolationLe } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// /// The isolation level to use for the transaction. @@ -376,7 +376,7 @@ public virtual async Task BeginTransactionAsync( } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// /// The isolation level to use for the transaction. @@ -682,7 +682,7 @@ private void OpenInternal(bool errorsExpected) } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// /// Indicates if the connection errors are expected and should be logged as debug message. @@ -836,7 +836,7 @@ public virtual bool Close() } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// protected virtual void CloseDbConnection() @@ -988,7 +988,7 @@ public virtual async ValueTask DisposeAsync() } /// - /// Template method that by default calls but can be overriden + /// Template method that by default calls but can be overriden /// by providers to make a different call instead. /// protected virtual ValueTask DisposeDbConnectionAsync() diff --git a/src/EFCore.Relational/Storage/RelationalDataReader.cs b/src/EFCore.Relational/Storage/RelationalDataReader.cs index c6d16ecbecf..58e438a7bbf 100644 --- a/src/EFCore.Relational/Storage/RelationalDataReader.cs +++ b/src/EFCore.Relational/Storage/RelationalDataReader.cs @@ -76,7 +76,7 @@ public virtual DbCommand DbCommand => _command; /// - /// Calls on the underlying . + /// Calls on the underlying . /// /// if there are more rows; otherwise . public virtual bool Read() @@ -87,7 +87,7 @@ public virtual bool Read() } /// - /// Calls on the underlying + /// Calls on the underlying /// . /// /// if there are more rows; otherwise . diff --git a/src/EFCore.Relational/Storage/StringTypeMapping.cs b/src/EFCore.Relational/Storage/StringTypeMapping.cs index 8f1460378a7..5410a6988cf 100644 --- a/src/EFCore.Relational/Storage/StringTypeMapping.cs +++ b/src/EFCore.Relational/Storage/StringTypeMapping.cs @@ -22,7 +22,7 @@ public class StringTypeMapping : RelationalTypeMapping /// Initializes a new instance of the class. /// /// The name of the database type. - /// The to be used. + /// The to be used. /// A value indicating whether the type should handle Unicode data or not. /// The size of data the property is configured to store, or null if no size is configured. public StringTypeMapping( diff --git a/src/EFCore.Relational/Update/ModificationCommand.cs b/src/EFCore.Relational/Update/ModificationCommand.cs index a5d027d1db6..c90a4c19101 100644 --- a/src/EFCore.Relational/Update/ModificationCommand.cs +++ b/src/EFCore.Relational/Update/ModificationCommand.cs @@ -99,9 +99,9 @@ public virtual IReadOnlyList Entries /// /// The that indicates whether the row will be - /// inserted (), - /// updated (), - /// or deleted ((). + /// inserted (), + /// updated (), + /// or deleted ((). /// public virtual EntityState EntityState { diff --git a/src/EFCore.SqlServer/Scaffolding/Internal/SqlDataReaderExtension.cs b/src/EFCore.SqlServer/Scaffolding/Internal/SqlDataReaderExtension.cs index 15abddbfb8d..32015ae2fb1 100644 --- a/src/EFCore.SqlServer/Scaffolding/Internal/SqlDataReaderExtension.cs +++ b/src/EFCore.SqlServer/Scaffolding/Internal/SqlDataReaderExtension.cs @@ -21,7 +21,7 @@ public static class SqlDataReaderExtension /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [return: CA.MaybeNullAttribute] + [return: CA.MaybeNull] public static T GetValueOrDefault([NotNull] this DbDataReader reader, [NotNull] string name) { var idx = reader.GetOrdinal(name); @@ -36,7 +36,7 @@ public static T GetValueOrDefault([NotNull] this DbDataReader reader, [NotNul /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - [return: CA.MaybeNullAttribute] + [return: CA.MaybeNull] public static T GetValueOrDefault([NotNull] this DbDataRecord record, [NotNull] string name) { var idx = record.GetOrdinal(name); diff --git a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteStringTypeMapping.cs b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteStringTypeMapping.cs index 37dc0fc2560..6e4bcead4a7 100644 --- a/src/EFCore.Sqlite.Core/Storage/Internal/SqliteStringTypeMapping.cs +++ b/src/EFCore.Sqlite.Core/Storage/Internal/SqliteStringTypeMapping.cs @@ -21,7 +21,7 @@ public class SqliteStringTypeMapping : StringTypeMapping /// Initializes a new instance of the class. /// /// The name of the database type. - /// The to be used. + /// The to be used. /// A value indicating whether the type should handle Unicode data or not. /// The size of data the property is configured to store, or null if no size is configured. public SqliteStringTypeMapping( diff --git a/src/EFCore/ChangeTracking/ChangeTracker.cs b/src/EFCore/ChangeTracking/ChangeTracker.cs index e5574dcc7de..37ca85169e8 100644 --- a/src/EFCore/ChangeTracking/ChangeTracker.cs +++ b/src/EFCore/ChangeTracking/ChangeTracker.cs @@ -105,7 +105,7 @@ public ChangeTracker( /// and methods. /// /// - /// The default value is . This means the change tracker will + /// The default value is . This means the change tracker will /// keep track of changes for all entities that are returned from a LINQ query. /// /// @@ -203,7 +203,7 @@ private void TryDetectChanges() /// /// Checks if any new, deleted, or changed entities are being tracked /// such that these changes will be sent to the database if - /// or is called. + /// or is called. /// /// /// Note that this method calls unless diff --git a/src/EFCore/ChangeTracking/NavigationEntry.cs b/src/EFCore/ChangeTracking/NavigationEntry.cs index 0e33c71d88b..69537450dc8 100644 --- a/src/EFCore/ChangeTracking/NavigationEntry.cs +++ b/src/EFCore/ChangeTracking/NavigationEntry.cs @@ -144,7 +144,7 @@ private static INavigationBase GetNavigation(InternalEntityEntry internalEntry, /// Loading entities from the database using /// or /// + /// cref="EntityFrameworkQueryableExtensions.ThenInclude{TEntity,TPreviousProperty,TProperty}(Query.IIncludableQueryable{TEntity,IEnumerable{TPreviousProperty}},System.Linq.Expressions.Expression{Func{TPreviousProperty,TProperty}})" /> /// , , or will set this flag. Subsequent calls to /// or will then be a no-op. /// diff --git a/src/EFCore/DbContext.cs b/src/EFCore/DbContext.cs index d63a38ec922..867e43d97f2 100644 --- a/src/EFCore/DbContext.cs +++ b/src/EFCore/DbContext.cs @@ -448,9 +448,9 @@ protected internal virtual void OnModelCreating(ModelBuilder modelBuilder) /// Saves all changes made in this context to the database. /// /// - /// This method will automatically call to discover any + /// This method will automatically call to discover any /// changes to entity instances before saving to the underlying database. This can be disabled via - /// . + /// . /// /// /// @@ -472,13 +472,13 @@ public virtual int SaveChanges() /// Saves all changes made in this context to the database. /// /// - /// This method will automatically call to discover any + /// This method will automatically call to discover any /// changes to entity instances before saving to the underlying database. This can be disabled via - /// . + /// . /// /// /// - /// Indicates whether is called after the changes have + /// Indicates whether is called after the changes have /// been sent successfully to the database. /// /// @@ -555,9 +555,9 @@ private void TryDetectChanges(EntityEntry entry) /// Saves all changes made in this context to the database. /// /// - /// This method will automatically call to discover any + /// This method will automatically call to discover any /// changes to entity instances before saving to the underlying database. This can be disabled via - /// . + /// . /// /// /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure @@ -585,9 +585,9 @@ public virtual Task SaveChangesAsync(CancellationToken cancellationToken = /// Saves all changes made in this context to the database. /// /// - /// This method will automatically call to discover any + /// This method will automatically call to discover any /// changes to entity instances before saving to the underlying database. This can be disabled via - /// . + /// . /// /// /// Multiple active operations on the same context instance are not supported. Use 'await' to ensure @@ -595,7 +595,7 @@ public virtual Task SaveChangesAsync(CancellationToken cancellationToken = /// /// /// - /// Indicates whether is called after the changes have + /// Indicates whether is called after the changes have /// been sent successfully to the database. /// /// A to observe while waiting for the task to complete. @@ -1010,7 +1010,7 @@ await SetEntityStateAsync(entry.GetInfrastructure(), EntityState.Added, cancella /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1053,7 +1053,7 @@ public virtual EntityEntry Attach([NotNull] TEntity entity) /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1215,7 +1215,7 @@ await SetEntityStateAsync(entry.GetInfrastructure(), EntityState.Added, cancella /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1256,7 +1256,7 @@ public virtual EntityEntry Attach([NotNull] object entity) /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1387,7 +1387,7 @@ public virtual Task AddRangeAsync([NotNull] params object[] entities) /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1424,7 +1424,7 @@ public virtual void AttachRange([NotNull] params object[] entities) /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1543,7 +1543,7 @@ await SetEntityStateAsync( /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities @@ -1580,7 +1580,7 @@ public virtual void AttachRange([NotNull] IEnumerable entities) /// when a different state will be used. /// /// - /// Generally, no database interaction will be performed until is called. + /// Generally, no database interaction will be performed until is called. /// /// /// A recursive search of the navigation properties will be performed to find reachable entities diff --git a/src/EFCore/DbContextOptionsBuilder.cs b/src/EFCore/DbContextOptionsBuilder.cs index 096d423cd0f..fb18095fbee 100644 --- a/src/EFCore/DbContextOptionsBuilder.cs +++ b/src/EFCore/DbContextOptionsBuilder.cs @@ -117,7 +117,7 @@ public virtual DbContextOptionsBuilder UseLoggerFactory([CanBeNull] ILoggerFacto /// This overload allows the minimum level of logging and the log formatting to be controlled. /// Use the /// + /// cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,DbContextLoggerOptions?)" /> /// overload to log only specific events. /// Use the /// overload to log only events in specific categories. @@ -459,7 +459,7 @@ public virtual DbContextOptionsBuilder EnableServiceProviderCaching(bool cacheSe /// and methods. /// /// - /// The default value is . This means + /// The default value is . This means /// the change tracker will keep track of changes for all entities that are returned from a LINQ query. /// /// diff --git a/src/EFCore/DbContextOptionsBuilder`.cs b/src/EFCore/DbContextOptionsBuilder`.cs index dba16ee93cb..11d82d37ebe 100644 --- a/src/EFCore/DbContextOptionsBuilder`.cs +++ b/src/EFCore/DbContextOptionsBuilder`.cs @@ -93,7 +93,7 @@ public DbContextOptionsBuilder([NotNull] DbContextOptions options) /// This overload allows the minimum level of logging and the log formatting to be controlled. /// Use the /// + /// cref="LogTo(Action{string},IEnumerable{EventId},LogLevel,DbContextLoggerOptions?)" /> /// overload to log only specific events. /// Use the /// overload to log only events in specific categories. @@ -345,7 +345,7 @@ public DbContextOptionsBuilder([NotNull] DbContextOptions options) /// and methods. /// /// - /// The default value is . This means the + /// The default value is . This means the /// change tracker will keep track of changes for all entities that are returned from a LINQ query. /// /// diff --git a/src/EFCore/Diagnostics/EventDefinitionBase.cs b/src/EFCore/Diagnostics/EventDefinitionBase.cs index 11150e259ca..9cfda6b11b6 100644 --- a/src/EFCore/Diagnostics/EventDefinitionBase.cs +++ b/src/EFCore/Diagnostics/EventDefinitionBase.cs @@ -18,7 +18,7 @@ public abstract class EventDefinitionBase /// Creates an event definition instance. /// /// Logging options. - /// The . + /// The . /// The at which the event will be logged. /// /// A string representing the code that should be passed to . diff --git a/src/EFCore/Metadata/Builders/ReferenceCollectionBuilder`.cs b/src/EFCore/Metadata/Builders/ReferenceCollectionBuilder`.cs index a1a9616a291..262917dbf8c 100644 --- a/src/EFCore/Metadata/Builders/ReferenceCollectionBuilder`.cs +++ b/src/EFCore/Metadata/Builders/ReferenceCollectionBuilder`.cs @@ -70,7 +70,7 @@ protected ReferenceCollectionBuilder( /// of the entity class. /// /// - /// If is not specified, + /// If is not specified, /// then an attempt will be made to match the data type and order of foreign key properties against /// the primary key of the principal entity type. If they do not match, new shadow state properties /// that form a unique index will be added to the principal entity type to serve as the reference key. diff --git a/src/EFCore/Metadata/Builders/ReferenceReferenceBuilder.cs b/src/EFCore/Metadata/Builders/ReferenceReferenceBuilder.cs index 4388b599652..d8499abdead 100644 --- a/src/EFCore/Metadata/Builders/ReferenceReferenceBuilder.cs +++ b/src/EFCore/Metadata/Builders/ReferenceReferenceBuilder.cs @@ -83,7 +83,7 @@ public virtual ReferenceReferenceBuilder HasAnnotation([NotNull] string annotati /// of the entity class. /// /// - /// If is not specified, then an attempt will be made to + /// If is not specified, then an attempt will be made to /// match the data type and order of foreign key properties against the primary key of the principal /// entity type. If they do not match, new shadow state properties that form a unique index will be /// added to the principal entity type to serve as the reference key. @@ -121,7 +121,7 @@ public virtual ReferenceReferenceBuilder HasForeignKey( /// of the entity class. /// /// - /// If is not specified, then an attempt will be made to + /// If is not specified, then an attempt will be made to /// match the data type and order of foreign key properties against the primary key of the principal /// entity type. If they do not match, new shadow state properties that form a unique index will be /// added to the principal entity type to serve as the reference key. diff --git a/src/EFCore/Properties/TypeForwards.cs b/src/EFCore/Properties/TypeForwards.cs index 8b4fb17ee75..10e904d3c71 100644 --- a/src/EFCore/Properties/TypeForwards.cs +++ b/src/EFCore/Properties/TypeForwards.cs @@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.ChangeTracking.Internal; -[assembly: TypeForwardedToAttribute(typeof(ObservableBackedBindingList<>))] -[assembly: TypeForwardedToAttribute(typeof(ObservableCollectionExtensions))] -[assembly: TypeForwardedToAttribute(typeof(ObservableCollectionListSource<>))] -[assembly: TypeForwardedToAttribute(typeof(SortableBindingList<>))] +[assembly: TypeForwardedTo(typeof(ObservableBackedBindingList<>))] +[assembly: TypeForwardedTo(typeof(ObservableCollectionExtensions))] +[assembly: TypeForwardedTo(typeof(ObservableCollectionListSource<>))] +[assembly: TypeForwardedTo(typeof(SortableBindingList<>))] diff --git a/src/EFCore/Query/CollectionShaperExpression.cs b/src/EFCore/Query/CollectionShaperExpression.cs index ce6aeec7449..de7be628ee5 100644 --- a/src/EFCore/Query/CollectionShaperExpression.cs +++ b/src/EFCore/Query/CollectionShaperExpression.cs @@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -31,8 +33,8 @@ public class CollectionShaperExpression : Expression, IPrintableExpression public CollectionShaperExpression( [NotNull] Expression projection, [NotNull] Expression innerShaper, - [CanBeNull] INavigationBase navigation, - [CanBeNull] Type elementType) + [CanBeNull] INavigationBase? navigation, + [NotNull] Type elementType) { Check.NotNull(projection, nameof(projection)); Check.NotNull(innerShaper, nameof(innerShaper)); @@ -40,7 +42,7 @@ public CollectionShaperExpression( Projection = projection; InnerShaper = innerShaper; Navigation = navigation; - ElementType = elementType ?? navigation.ClrType.TryGetSequenceType(); + ElementType = elementType; } /// @@ -56,7 +58,7 @@ public CollectionShaperExpression( /// /// The navigation if associated with the collection. /// - public virtual INavigationBase Navigation { get; } + public virtual INavigationBase? Navigation { get; } /// /// The clr type of elements of the collection. diff --git a/src/EFCore/Query/CompiledQueryCacheKeyGenerator.cs b/src/EFCore/Query/CompiledQueryCacheKeyGenerator.cs index bdd5241c170..3f97e5554f3 100644 --- a/src/EFCore/Query/CompiledQueryCacheKeyGenerator.cs +++ b/src/EFCore/Query/CompiledQueryCacheKeyGenerator.cs @@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -112,7 +114,7 @@ public CompiledQueryCacheKey( /// if the object is a and is for the same query, otherwise /// . /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is CompiledQueryCacheKey other && Equals(other); /// diff --git a/src/EFCore/Query/CompiledQueryCacheKeyGeneratorDependencies.cs b/src/EFCore/Query/CompiledQueryCacheKeyGeneratorDependencies.cs index 956cc7cdf9e..38515f511d2 100644 --- a/src/EFCore/Query/CompiledQueryCacheKeyGeneratorDependencies.cs +++ b/src/EFCore/Query/CompiledQueryCacheKeyGeneratorDependencies.cs @@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/EntityShaperExpression.cs b/src/EFCore/Query/EntityShaperExpression.cs index 3fd1cc92700..5e3ae2344c5 100644 --- a/src/EFCore/Query/EntityShaperExpression.cs +++ b/src/EFCore/Query/EntityShaperExpression.cs @@ -15,6 +15,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -64,7 +66,7 @@ protected EntityShaperExpression( [NotNull] IEntityType entityType, [NotNull] Expression valueBufferExpression, bool nullable, - [CanBeNull] LambdaExpression materializationCondition) + [CanBeNull] LambdaExpression? materializationCondition) { Check.NotNull(entityType, nameof(entityType)); Check.NotNull(valueBufferExpression, nameof(valueBufferExpression)); @@ -251,7 +253,8 @@ public virtual EntityShaperExpression Update([NotNull] Expression valueBufferExp /// public override Type Type - => EntityType.ClrType; + // No shadow entities at runtime + => EntityType.ClrType!; /// public sealed override ExpressionType NodeType diff --git a/src/EFCore/Query/EvaluatableExpressionFilter.cs b/src/EFCore/Query/EvaluatableExpressionFilter.cs index 34eaffa5b7d..29e1ca767d9 100644 --- a/src/EFCore/Query/EvaluatableExpressionFilter.cs +++ b/src/EFCore/Query/EvaluatableExpressionFilter.cs @@ -10,6 +10,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/EvaluatableExpressionFilterDependencies.cs b/src/EFCore/Query/EvaluatableExpressionFilterDependencies.cs index d7f7d6e9b4a..f7e8d46ccd4 100644 --- a/src/EFCore/Query/EvaluatableExpressionFilterDependencies.cs +++ b/src/EFCore/Query/EvaluatableExpressionFilterDependencies.cs @@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/ExpressionEqualityComparer.cs b/src/EFCore/Query/ExpressionEqualityComparer.cs index 98a464fa993..f964780639c 100644 --- a/src/EFCore/Query/ExpressionEqualityComparer.cs +++ b/src/EFCore/Query/ExpressionEqualityComparer.cs @@ -8,6 +8,8 @@ using System.Reflection; using Microsoft.EntityFrameworkCore.Diagnostics; +#nullable enable + // ReSharper disable SwitchStatementMissingSomeCases // ReSharper disable ForCanBeConvertedToForeach // ReSharper disable LoopCanBeConvertedToQuery diff --git a/src/EFCore/Query/ExpressionPrinter.cs b/src/EFCore/Query/ExpressionPrinter.cs index 020c7cfdadb..38f8cdfe66a 100644 --- a/src/EFCore/Query/ExpressionPrinter.cs +++ b/src/EFCore/Query/ExpressionPrinter.cs @@ -12,6 +12,9 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query { @@ -81,7 +84,7 @@ public ExpressionPrinter() /// A join action to use when joining printout of individual item in the collection. public virtual void VisitCollection( [NotNull] IReadOnlyCollection items, - [CanBeNull] Action joinAction = null) + [CanBeNull] Action? joinAction = null) where T : Expression { Check.NotNull(items, nameof(items)); @@ -216,7 +219,8 @@ public virtual string GenerateBinaryOperator(ExpressionType expressionType) } /// - public override Expression Visit(Expression expression) + [return: CA.NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) { if (expression == null) { @@ -697,7 +701,7 @@ var argumentNames : method.GetParameters().Select(p => p.Name).ToList() : new List(); - IDisposable indent = null; + IDisposable? indent = null; if (!isSimpleMethodOrProperty) { @@ -779,7 +783,7 @@ protected override Expression VisitNew(NewExpression newExpression) appendAction("{ "); } - IDisposable indent = null; + IDisposable? indent = null; if (isComplex) { indent = _stringBuilder.Indent(); @@ -819,12 +823,12 @@ protected override Expression VisitNewArray(NewArrayExpression newArrayExpressio Check.NotNull(newArrayExpression, nameof(newArrayExpression)); var isComplex = newArrayExpression.Expressions.Count > 1; - var appendAction = isComplex ? (Func)AppendLine : Append; + var appendAction = isComplex ? s => AppendLine(s) : (Action)(s => Append(s)); appendAction("new " + newArrayExpression.Type.GetElementType().ShortDisplayName() + "[]"); appendAction("{ "); - IDisposable indent = null; + IDisposable? indent = null; if (isComplex) { indent = _stringBuilder.Indent(); @@ -994,7 +998,6 @@ protected override Expression VisitIndex(IndexExpression indexExpression) indexExpression.Arguments, s => { _stringBuilder.Append(s); - return null; }); _stringBuilder.Append("]"); @@ -1075,7 +1078,7 @@ protected override Expression VisitExtension(Expression extensionExpression) private void VisitArguments( IReadOnlyList arguments, - Func appendAction, + Action appendAction, string lastSeparator = "", bool areConnected = false) { diff --git a/src/EFCore/Query/GroupByShaperExpression.cs b/src/EFCore/Query/GroupByShaperExpression.cs index d399e95437e..29d387b0d10 100644 --- a/src/EFCore/Query/GroupByShaperExpression.cs +++ b/src/EFCore/Query/GroupByShaperExpression.cs @@ -7,6 +7,8 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IAsyncQueryProvider.cs b/src/EFCore/Query/IAsyncQueryProvider.cs index cd81996de41..7311c232a33 100644 --- a/src/EFCore/Query/IAsyncQueryProvider.cs +++ b/src/EFCore/Query/IAsyncQueryProvider.cs @@ -7,6 +7,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/ICompiledQueryCacheKeyGenerator.cs b/src/EFCore/Query/ICompiledQueryCacheKeyGenerator.cs index 46eebd1a0e4..fb74bc059d1 100644 --- a/src/EFCore/Query/ICompiledQueryCacheKeyGenerator.cs +++ b/src/EFCore/Query/ICompiledQueryCacheKeyGenerator.cs @@ -5,6 +5,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IEntityMaterializerSource.cs b/src/EFCore/Query/IEntityMaterializerSource.cs index 1dd57bd9fb0..fc7320bfba7 100644 --- a/src/EFCore/Query/IEntityMaterializerSource.cs +++ b/src/EFCore/Query/IEntityMaterializerSource.cs @@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IEvaluatableExpressionFilter.cs b/src/EFCore/Query/IEvaluatableExpressionFilter.cs index 5cc64d4a090..92b057e6340 100644 --- a/src/EFCore/Query/IEvaluatableExpressionFilter.cs +++ b/src/EFCore/Query/IEvaluatableExpressionFilter.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IEvaluatableExpressionFilterPlugin.cs b/src/EFCore/Query/IEvaluatableExpressionFilterPlugin.cs index f5c0588e05a..41fd74b5e74 100644 --- a/src/EFCore/Query/IEvaluatableExpressionFilterPlugin.cs +++ b/src/EFCore/Query/IEvaluatableExpressionFilterPlugin.cs @@ -5,6 +5,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IIncludableQueryable.cs b/src/EFCore/Query/IIncludableQueryable.cs index bb1cc694e19..4de67f415cd 100644 --- a/src/EFCore/Query/IIncludableQueryable.cs +++ b/src/EFCore/Query/IIncludableQueryable.cs @@ -3,6 +3,8 @@ using System.Linq; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IPrintableExpression.cs b/src/EFCore/Query/IPrintableExpression.cs index fc4f28ae87b..9e234012bea 100644 --- a/src/EFCore/Query/IPrintableExpression.cs +++ b/src/EFCore/Query/IPrintableExpression.cs @@ -3,6 +3,8 @@ using JetBrains.Annotations; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryCompilationContextFactory.cs b/src/EFCore/Query/IQueryCompilationContextFactory.cs index 74a05adabe9..d3c910b4347 100644 --- a/src/EFCore/Query/IQueryCompilationContextFactory.cs +++ b/src/EFCore/Query/IQueryCompilationContextFactory.cs @@ -3,6 +3,8 @@ using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryContextFactory.cs b/src/EFCore/Query/IQueryContextFactory.cs index f74b9265832..ec1bc3028e9 100644 --- a/src/EFCore/Query/IQueryContextFactory.cs +++ b/src/EFCore/Query/IQueryContextFactory.cs @@ -3,6 +3,8 @@ using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryTranslationPostprocessorFactory.cs b/src/EFCore/Query/IQueryTranslationPostprocessorFactory.cs index eb89acbeeec..3fcefba6224 100644 --- a/src/EFCore/Query/IQueryTranslationPostprocessorFactory.cs +++ b/src/EFCore/Query/IQueryTranslationPostprocessorFactory.cs @@ -4,6 +4,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryTranslationPreprocessorFactory.cs b/src/EFCore/Query/IQueryTranslationPreprocessorFactory.cs index dd5c48f0fc5..c2511155259 100644 --- a/src/EFCore/Query/IQueryTranslationPreprocessorFactory.cs +++ b/src/EFCore/Query/IQueryTranslationPreprocessorFactory.cs @@ -4,6 +4,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryableMethodTranslatingExpressionVisitorFactory.cs b/src/EFCore/Query/IQueryableMethodTranslatingExpressionVisitorFactory.cs index 13c86adfaaf..b63b43c90cd 100644 --- a/src/EFCore/Query/IQueryableMethodTranslatingExpressionVisitorFactory.cs +++ b/src/EFCore/Query/IQueryableMethodTranslatingExpressionVisitorFactory.cs @@ -4,6 +4,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IQueryingEnumerable.cs b/src/EFCore/Query/IQueryingEnumerable.cs index f66f9a9163e..222e90d82a4 100644 --- a/src/EFCore/Query/IQueryingEnumerable.cs +++ b/src/EFCore/Query/IQueryingEnumerable.cs @@ -3,6 +3,8 @@ using System.Collections; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IShapedQueryCompilingExpressionVisitorFactory.cs b/src/EFCore/Query/IShapedQueryCompilingExpressionVisitorFactory.cs index a9468692c41..ec726cf0a04 100644 --- a/src/EFCore/Query/IShapedQueryCompilingExpressionVisitorFactory.cs +++ b/src/EFCore/Query/IShapedQueryCompilingExpressionVisitorFactory.cs @@ -4,6 +4,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/IncludeExpression.cs b/src/EFCore/Query/IncludeExpression.cs index 3459faa4db3..6af33aee150 100644 --- a/src/EFCore/Query/IncludeExpression.cs +++ b/src/EFCore/Query/IncludeExpression.cs @@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/Internal/CompiledQueryBase.cs b/src/EFCore/Query/Internal/CompiledQueryBase.cs index a873d9ab2f6..0e129da1048 100644 --- a/src/EFCore/Query/Internal/CompiledQueryBase.cs +++ b/src/EFCore/Query/Internal/CompiledQueryBase.cs @@ -11,6 +11,8 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// @@ -24,7 +26,7 @@ public abstract class CompiledQueryBase { private readonly LambdaExpression _queryExpression; - private Func _executor; + private Func? _executor; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to diff --git a/src/EFCore/Query/Internal/CompiledQueryCache.cs b/src/EFCore/Query/Internal/CompiledQueryCache.cs index a8ac848fcc3..5609a6c8862 100644 --- a/src/EFCore/Query/Internal/CompiledQueryCache.cs +++ b/src/EFCore/Query/Internal/CompiledQueryCache.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/EntityMaterializerSource.cs b/src/EFCore/Query/Internal/EntityMaterializerSource.cs index 5b3697f5803..0dd6fa1defb 100644 --- a/src/EFCore/Query/Internal/EntityMaterializerSource.cs +++ b/src/EFCore/Query/Internal/EntityMaterializerSource.cs @@ -16,6 +16,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// @@ -33,7 +35,7 @@ namespace Microsoft.EntityFrameworkCore.Query.Internal /// public class EntityMaterializerSource : IEntityMaterializerSource { - private ConcurrentDictionary> _materializers; + private ConcurrentDictionary>? _materializers; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -66,7 +68,7 @@ public virtual Expression CreateMaterializeExpression( throw new InvalidOperationException(CoreStrings.CannotMaterializeAbstractType(entityType)); } - var constructorBinding = (InstantiationBinding)entityType[CoreAnnotationNames.ConstructorBinding]; + var constructorBinding = (InstantiationBinding?)entityType[CoreAnnotationNames.ConstructorBinding]; if (constructorBinding == null) { @@ -149,7 +151,8 @@ static Expression CreateMemberAssignment(Expression parameter, MemberInfo member private ConcurrentDictionary> Materializers => LazyInitializer.EnsureInitialized( - ref _materializers, + // TODO: Even though we should be able to pass nullable here for some reason it is inferring generic type incorrectly + ref _materializers!, () => new ConcurrentDictionary>()); /// diff --git a/src/EFCore/Query/Internal/EntityMaterializerSourceDependencies.cs b/src/EFCore/Query/Internal/EntityMaterializerSourceDependencies.cs index 1e513672fac..d0c23f82398 100644 --- a/src/EFCore/Query/Internal/EntityMaterializerSourceDependencies.cs +++ b/src/EFCore/Query/Internal/EntityMaterializerSourceDependencies.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/EntityQueryProvider.cs b/src/EFCore/Query/Internal/EntityQueryProvider.cs index 8169f96721d..d7f0607ec25 100644 --- a/src/EFCore/Query/Internal/EntityQueryProvider.cs +++ b/src/EFCore/Query/Internal/EntityQueryProvider.cs @@ -9,6 +9,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/EntityQueryable`.cs b/src/EFCore/Query/Internal/EntityQueryable`.cs index d5e48862357..3b5acab127f 100644 --- a/src/EFCore/Query/Internal/EntityQueryable`.cs +++ b/src/EFCore/Query/Internal/EntityQueryable`.cs @@ -14,6 +14,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/ICompiledQueryCache.cs b/src/EFCore/Query/Internal/ICompiledQueryCache.cs index 28dd751ca2e..df76c14e653 100644 --- a/src/EFCore/Query/Internal/ICompiledQueryCache.cs +++ b/src/EFCore/Query/Internal/ICompiledQueryCache.cs @@ -5,6 +5,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/IParameterValues.cs b/src/EFCore/Query/Internal/IParameterValues.cs index ca63c1aa943..25ff48999f3 100644 --- a/src/EFCore/Query/Internal/IParameterValues.cs +++ b/src/EFCore/Query/Internal/IParameterValues.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using JetBrains.Annotations; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/IQueryCompiler.cs b/src/EFCore/Query/Internal/IQueryCompiler.cs index f3edcba39e4..a615ca585aa 100644 --- a/src/EFCore/Query/Internal/IQueryCompiler.cs +++ b/src/EFCore/Query/Internal/IQueryCompiler.cs @@ -7,6 +7,8 @@ using JetBrains.Annotations; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/InvocationExpressionRemovingExpressionVisitor.cs b/src/EFCore/Query/Internal/InvocationExpressionRemovingExpressionVisitor.cs index 8068906679b..2ed5607b6e2 100644 --- a/src/EFCore/Query/Internal/InvocationExpressionRemovingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/InvocationExpressionRemovingExpressionVisitor.cs @@ -6,6 +6,8 @@ using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs index 94cf9a181ac..083b991507d 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.ExpressionVisitors.cs @@ -12,6 +12,9 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query.Internal { @@ -97,7 +100,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return base.VisitMethodCall(methodCallExpression); } - private Expression TryExpandNavigation(Expression root, MemberIdentity memberIdentity) + private Expression? TryExpandNavigation(Expression root, MemberIdentity memberIdentity) { var innerExpression = root.UnwrapTypeConversion(out var convertedType); if (UnwrapEntityReference(innerExpression) is EntityReference entityReference) @@ -204,8 +207,9 @@ protected Expression ExpandSkipNavigation( { // First pseudo-navigation is a reference // ExpandFK handles both collection & reference navigation for second psuedo-navigation + // Value known to be non-null secondaryExpansion = ExpandForeignKey( - primaryExpansion, UnwrapEntityReference(primaryExpansion), inverseNavigation.ForeignKey, + primaryExpansion, UnwrapEntityReference(primaryExpansion)!, inverseNavigation.ForeignKey, !inverseNavigation.IsOnDependent, derivedTypeConversion: false); } else @@ -222,7 +226,8 @@ protected Expression ExpandSkipNavigation( if (includeTree != null) { - UnwrapEntityReference(innerSource.PendingSelector).IncludePaths.Merge(includeTree); + // Value known to be non-null + UnwrapEntityReference(innerSource.PendingSelector)!.IncludePaths.Merge(includeTree); } var sourceElementType = primaryExpansion.Type.GetSequenceType(); @@ -269,7 +274,8 @@ protected Expression ExpandSkipNavigation( if (includeTree != null) { - UnwrapEntityReference(innerSource.PendingSelector).IncludePaths.Merge(includeTree); + // Value known to be non-null + UnwrapEntityReference(innerSource.PendingSelector)!.IncludePaths.Merge(includeTree); } var sourceElementType = primaryExpansion.Type.GetSequenceType(); @@ -337,7 +343,8 @@ private Expression ExpandForeignKey( // We detect and copy over include for navigation being expanded automatically var navigation = onDependent ? foreignKey.DependentToPrincipal : foreignKey.PrincipalToDependent; - var innerEntityReference = UnwrapEntityReference(innerSource.PendingSelector); + // Value known to be non-null + var innerEntityReference = UnwrapEntityReference(innerSource.PendingSelector)!; if (navigation != null && entityReference.IncludePaths.TryGetValue(navigation, out var includeTree)) { @@ -603,7 +610,10 @@ protected override Expression VisitNew(NewExpression newExpression) return newExpression.Update(arguments); } - private bool ReconstructAnonymousType(Expression currentRoot, NewExpression newExpression, out Expression replacement) + private bool ReconstructAnonymousType( + Expression currentRoot, + NewExpression newExpression, + [CA.NotNullWhen(true)] out Expression? replacement) { replacement = null; var changed = false; @@ -676,7 +686,7 @@ private void VerifyNoCycles(IncludeTreeNode includeTreeNode) } } - private Expression ExpandIncludesHelper(Expression root, EntityReference entityReference, INavigationBase previousNavigation) + private Expression ExpandIncludesHelper(Expression root, EntityReference entityReference, INavigationBase? previousNavigation) { var result = root; var convertedRoot = root; @@ -709,9 +719,8 @@ private Expression ExpandIncludesHelper(Expression root, EntityReference entityR // Collection will expand it's includes when reducing the navigationExpansionExpression if (!navigationBase.IsCollection) { - var innerEntityReference = UnwrapEntityReference(included); - - included = ExpandIncludesHelper(included, innerEntityReference, navigationBase); + // Value known to be non-null + included = ExpandIncludesHelper(included, UnwrapEntityReference(included)!, navigationBase); } else { @@ -723,7 +732,7 @@ private Expression ExpandIncludesHelper(Expression root, EntityReference entityR && subquery is MethodCallExpression subqueryMethodCallExpression && subqueryMethodCallExpression.Method.IsGenericMethod) { - EntityReference innerEntityReference = null; + EntityReference? innerEntityReference = null; if (subqueryMethodCallExpression.Method.GetGenericMethodDefinition() == QueryableMethods.Where && subqueryMethodCallExpression.Arguments[0] is NavigationExpansionExpression navigationExpansionExpression) { @@ -1060,7 +1069,11 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return base.VisitMethodCall(methodCallExpression); } - private bool TryRemoveNavigationComparison(ExpressionType nodeType, Expression left, Expression right, out Expression result) + private bool TryRemoveNavigationComparison( + ExpressionType nodeType, + Expression left, + Expression right, + [CA.NotNullWhen(true)] out Expression? result) { result = null; var leftNavigationData = ProcessNavigationPath(left) as NavigationDataExpression; @@ -1075,16 +1088,17 @@ private bool TryRemoveNavigationComparison(ExpressionType nodeType, Expression l if (left.IsNullConstantExpression() || right.IsNullConstantExpression()) { - var nonNullNavigationData = left.IsNullConstantExpression() - ? rightNavigationData - : leftNavigationData; + NavigationDataExpression nonNullNavigationData = left.IsNullConstantExpression() + ? rightNavigationData! + : leftNavigationData!; if (nonNullNavigationData.Navigation?.IsCollection == true) { _logger.PossibleUnintendedCollectionNavigationNullComparisonWarning(nonNullNavigationData.Navigation); + // Inner would be non-null when navigation is non-null result = Expression.MakeBinary( - nodeType, nonNullNavigationData.Inner.Current, Expression.Constant(null, nonNullNavigationData.Inner.Type)); + nodeType, nonNullNavigationData.Inner!.Current, Expression.Constant(null, nonNullNavigationData.Inner.Type)); return true; } @@ -1097,8 +1111,8 @@ private bool TryRemoveNavigationComparison(ExpressionType nodeType, Expression l if (leftNavigationData.Navigation == rightNavigationData.Navigation) { _logger.PossibleUnintendedReferenceComparisonWarning(leftNavigationData.Current, rightNavigationData.Current); - - result = Expression.MakeBinary(nodeType, leftNavigationData.Inner.Current, rightNavigationData.Inner.Current); + // Inner would be non-null when navigation is non-null + result = Expression.MakeBinary(nodeType, leftNavigationData.Inner!.Current, rightNavigationData.Inner!.Current); } else { @@ -1182,10 +1196,10 @@ public override Type Type public override ExpressionType NodeType => ExpressionType.Extension; - public INavigation Navigation { get; } + public INavigation? Navigation { get; } public Expression Current { get; } - public NavigationDataExpression Inner { get; } - public IEntityType EntityType { get; } + public NavigationDataExpression? Inner { get; } + public IEntityType? EntityType { get; } } } } diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs index f9afd57ca99..568b54dfa49 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.Expressions.cs @@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { public partial class NavigationExpandingExpressionVisitor @@ -28,13 +30,14 @@ public EntityReference(IEntityType entityType) public bool IsOptional { get; private set; } public IncludeTreeNode IncludePaths { get; private set; } - public IncludeTreeNode LastIncludeTreeNode { get; private set; } + public IncludeTreeNode? LastIncludeTreeNode { get; private set; } public override ExpressionType NodeType => ExpressionType.Extension; public override Type Type - => EntityType.ClrType; + // No shadow entities at runtime + => EntityType.ClrType!; protected override Expression VisitChildren(ExpressionVisitor visitor) { @@ -83,21 +86,21 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) /// private sealed class IncludeTreeNode : Dictionary { - private EntityReference _entityReference; + private EntityReference? _entityReference; public IncludeTreeNode(IEntityType entityType) { EntityType = entityType; } - public IncludeTreeNode(IEntityType entityType, EntityReference entityReference) + public IncludeTreeNode(IEntityType entityType, EntityReference? entityReference) { EntityType = entityType; _entityReference = entityReference; } public IEntityType EntityType { get; } - public LambdaExpression FilterExpression { get; private set; } + public LambdaExpression? FilterExpression { get; private set; } public IncludeTreeNode AddNavigation(INavigationBase navigation) { @@ -106,22 +109,25 @@ public IncludeTreeNode AddNavigation(INavigationBase navigation) return existingValue; } - IncludeTreeNode nodeToAdd = null; + IncludeTreeNode? nodeToAdd = null; if (_entityReference != null) { if (navigation is INavigation concreteNavigation && _entityReference.ForeignKeyExpansionMap.TryGetValue( (concreteNavigation.ForeignKey, concreteNavigation.IsOnDependent), out var expansion)) { - nodeToAdd = UnwrapEntityReference(expansion).IncludePaths; + // Value known to be non-null + nodeToAdd = UnwrapEntityReference(expansion)!.IncludePaths; } else if (navigation is ISkipNavigation skipNavigation && _entityReference.ForeignKeyExpansionMap.TryGetValue( (skipNavigation.ForeignKey, skipNavigation.IsOnDependent), out var firstExpansion) - && UnwrapEntityReference(firstExpansion).ForeignKeyExpansionMap.TryGetValue( + // Value known to be non-null + && UnwrapEntityReference(firstExpansion)!.ForeignKeyExpansionMap.TryGetValue( (skipNavigation.Inverse.ForeignKey, !skipNavigation.Inverse.IsOnDependent), out var secondExpansion)) { - nodeToAdd = UnwrapEntityReference(secondExpansion).IncludePaths; + // Value known to be non-null + nodeToAdd = UnwrapEntityReference(secondExpansion)!.IncludePaths; } } @@ -135,7 +141,7 @@ public IncludeTreeNode AddNavigation(INavigationBase navigation) return this[navigation]; } - public IncludeTreeNode Snapshot(EntityReference entityReference) + public IncludeTreeNode Snapshot(EntityReference? entityReference) { var result = new IncludeTreeNode(EntityType, entityReference) { FilterExpression = FilterExpression }; @@ -163,7 +169,7 @@ public void AssignEntityReference(EntityReference entityReference) public void ApplyFilter(LambdaExpression filterExpression) => FilterExpression = filterExpression; - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj != null && (ReferenceEquals(this, obj) || obj is IncludeTreeNode includeTreeNode @@ -203,7 +209,7 @@ private sealed class NavigationExpansionExpression : Expression, IPrintableExpre private readonly string _parameterName; - private NavigationTreeNode _currentTree; + private NavigationTreeNode? _currentTree; public NavigationExpansionExpression( Expression source, @@ -220,11 +226,13 @@ public NavigationExpansionExpression( public Expression Source { get; private set; } public ParameterExpression CurrentParameter - => CurrentTree.CurrentParameter; + // CurrentParameter would be non-null if CurrentTree is non-null + => CurrentTree.CurrentParameter!; public NavigationTreeNode CurrentTree { - get => _currentTree; + // _currentTree is always non-null. Field is to override the setter to set parameter + get => _currentTree!; private set { _currentTree = value; @@ -233,7 +241,7 @@ private set } public Expression PendingSelector { get; private set; } - public MethodInfo CardinalityReducingGenericMethodInfo { get; private set; } + public MethodInfo? CardinalityReducingGenericMethodInfo { get; private set; } public Type SourceElementType => CurrentParameter.Type; @@ -354,32 +362,25 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) /// private class NavigationTreeNode : Expression { - private NavigationTreeNode _parent; + private NavigationTreeNode? _parent; - public NavigationTreeNode(NavigationTreeNode left, NavigationTreeNode right) + public NavigationTreeNode(NavigationTreeNode? left, NavigationTreeNode? right) { Left = left; Right = right; - if (left != null) - { - Left.Parent = this; - Right.Parent = this; - } - } - - public NavigationTreeNode Parent - { - get => _parent; - private set + if (left != null + && right != null) { - _parent = value; - CurrentParameter = null; + left._parent = this; + left.CurrentParameter = null; + right._parent = this; + right.CurrentParameter = null; } } - public NavigationTreeNode Left { get; } - public NavigationTreeNode Right { get; } - public ParameterExpression CurrentParameter { get; private set; } + public NavigationTreeNode? Left { get; } + public NavigationTreeNode? Right { get; } + public ParameterExpression? CurrentParameter { get; private set; } public void SetParameter(string parameterName) => CurrentParameter = Parameter(Type, parameterName); @@ -388,17 +389,19 @@ public override ExpressionType NodeType => ExpressionType.Extension; public override Type Type - => TransparentIdentifierFactory.Create(Left.Type, Right.Type); + // Left/Right could be null for NavigationTreeExpression (derived type) but it overrides this property. + => TransparentIdentifierFactory.Create(Left!.Type, Right!.Type); public Expression GetExpression() { - if (Parent == null) + if (_parent == null) { - return CurrentParameter; + // If parent is null and CurrentParameter is non-null & vice-versa + return CurrentParameter!; } - var parentExperssion = Parent.GetExpression(); - return Parent.Left == this + var parentExperssion = _parent.GetExpression(); + return _parent.Left == this ? MakeMemberAccess(parentExperssion, parentExperssion.Type.GetMember("Outer")[0]) : MakeMemberAccess(parentExperssion, parentExperssion.Type.GetMember("Inner")[0]); } diff --git a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs index c8199807251..190661641d3 100644 --- a/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NavigationExpandingExpressionVisitor.cs @@ -14,6 +14,8 @@ using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// @@ -97,10 +99,9 @@ public NavigationExpandingExpressionVisitor( parameterize: false, generateContextAccessors: true); - if (!_queryCompilationContext.IgnoreAutoIncludes) - { - _nonCyclicAutoIncludeEntityTypes = new HashSet(); - } + // TODO: Use MemberNotNullWhen + // Value won't be accessed when condition is not met. + _nonCyclicAutoIncludeEntityTypes = !_queryCompilationContext.IgnoreAutoIncludes ? new HashSet() : null!; } /// @@ -605,7 +606,7 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) private Expression ProcessAllAnyCountLongCount( NavigationExpansionExpression source, MethodInfo genericMethod, - LambdaExpression predicate) + LambdaExpression? predicate) { if (predicate != null) { @@ -618,7 +619,7 @@ private Expression ProcessAllAnyCountLongCount( return Expression.Call(genericMethod.MakeGenericMethod(source.SourceElementType), source.Source); } - private Expression ProcessAverageMaxMinSum(NavigationExpansionExpression source, MethodInfo method, LambdaExpression selector) + private Expression ProcessAverageMaxMinSum(NavigationExpansionExpression source, MethodInfo method, LambdaExpression? selector) { if (selector != null) { @@ -761,7 +762,7 @@ private NavigationExpansionExpression ProcessSkipTake( private NavigationExpansionExpression ProcessFirstSingleLastOrDefault( NavigationExpansionExpression source, MethodInfo genericMethod, - LambdaExpression predicate, + LambdaExpression? predicate, Type returnType) { if (predicate != null) @@ -783,8 +784,8 @@ private NavigationExpansionExpression ProcessFirstSingleLastOrDefault( private NavigationExpansionExpression ProcessGroupBy( NavigationExpansionExpression source, LambdaExpression keySelector, - LambdaExpression elementSelector, - LambdaExpression resultSelector) + LambdaExpression? elementSelector, + LambdaExpression? resultSelector) { var keySelectorBody = ExpandNavigationsForSource(source, RemapLambdaExpression(source, keySelector)); // Need to generate lambda after processing element/result selector @@ -867,7 +868,8 @@ private NavigationExpansionExpression ProcessInclude(NavigationExpansionExpressi else { var currentIncludeTreeNode = thenInclude - ? entityReference.LastIncludeTreeNode + // LastIncludeTreeNode would be non-null for ThenInclude + ? entityReference.LastIncludeTreeNode! : entityReference.IncludePaths; var includeLambda = expression.UnwrapLambdaFromQuote(); @@ -895,7 +897,7 @@ private NavigationExpansionExpression ProcessInclude(NavigationExpansionExpressi throw new InvalidOperationException(CoreStrings.IncludeOnNonEntity(expression.Print())); - static (Expression result, LambdaExpression filterExpression) ExtractIncludeFilter( + static (Expression result, LambdaExpression? filterExpression) ExtractIncludeFilter( Expression currentExpression, Expression includeExpression) { @@ -1124,7 +1126,7 @@ private NavigationExpansionExpression ProcessSelect(NavigationExpansionExpressio private NavigationExpansionExpression ProcessSelectMany( NavigationExpansionExpression source, LambdaExpression collectionSelector, - LambdaExpression resultSelector) + LambdaExpression? resultSelector) { var collectionSelectorBody = ExpandNavigationsForSource(source, RemapLambdaExpression(source, collectionSelector)); if (collectionSelectorBody is MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression) @@ -1476,7 +1478,7 @@ private MethodCallExpression ConvertToEnumerable(MethodInfo queryableMethod, IEn { var genericTypeArguments = queryableMethod.IsGenericMethod ? queryableMethod.GetGenericArguments() - : null; + : Array.Empty(); var enumerableArguments = arguments.Select( arg => arg is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Quote @@ -1658,9 +1660,12 @@ private static IEnumerable FindNavigations(IEntityType entityTy else { foreach (var derivedSkipNavigation in entityType.GetDerivedTypes() - .Select(et => et.FindDeclaredSkipNavigation(navigationName)).Where(n => n != null)) + .Select(et => et.FindDeclaredSkipNavigation(navigationName))) { - yield return derivedSkipNavigation; + if (derivedSkipNavigation != null) + { + yield return derivedSkipNavigation; + } } } } @@ -1860,7 +1865,7 @@ private Expression SnapshotExpression(Expression selector) } } - private static EntityReference UnwrapEntityReference(Expression expression) + private static EntityReference? UnwrapEntityReference(Expression expression) { switch (expression) { diff --git a/src/EFCore/Query/Internal/NullAsyncQueryProvider.cs b/src/EFCore/Query/Internal/NullAsyncQueryProvider.cs index 5669a08ed23..df8ced66055 100644 --- a/src/EFCore/Query/Internal/NullAsyncQueryProvider.cs +++ b/src/EFCore/Query/Internal/NullAsyncQueryProvider.cs @@ -7,6 +7,8 @@ using System.Threading; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs b/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs index 5eb79edc4c2..afdc6662bbc 100644 --- a/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/NullCheckRemovingExpressionVisitor.cs @@ -4,6 +4,9 @@ using System.Collections.Generic; using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Utilities; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query.Internal { @@ -73,7 +76,7 @@ protected override Expression VisitConditional(ConditionalExpression conditional return base.VisitConditional(conditionalExpression); } - private Expression TryOptimizeConditionalEquality(Expression expression) + private Expression? TryOptimizeConditionalEquality(Expression expression) { // Simplify (a ? b : null) == null => !a || b == null // Simplify (a ? null : b) == null => a || b == null @@ -89,7 +92,7 @@ private Expression TryOptimizeConditionalEquality(Expression expression) } else { - conditionalExpression = binaryExpression.Right as ConditionalExpression; + conditionalExpression = (ConditionalExpression)binaryExpression.Right; comparedExpression = binaryExpression.Left; } @@ -126,7 +129,8 @@ public bool Verify(Expression caller, Expression result) return _nullSafeAccesses.Contains(result); } - public override Expression Visit(Expression expression) + [return: CA.NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) => expression == null || _nullSafeAccesses.Contains(expression) ? expression : base.Visit(expression); diff --git a/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs b/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs index bedbb7b1b3d..76f2801bd9f 100644 --- a/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/ParameterExtractingExpressionVisitor.cs @@ -11,6 +11,9 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query.Internal { @@ -35,7 +38,7 @@ private readonly Dictionary _evaluatedValues = new Dictionary(ExpressionEqualityComparer.Instance); private IDictionary _evaluatableExpressions; - private IQueryProvider _currentQueryProvider; + private IQueryProvider? _currentQueryProvider; /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -58,10 +61,13 @@ public ParameterExtractingExpressionVisitor( _logger = logger; _parameterize = parameterize; _generateContextAccessors = generateContextAccessors; - if (_generateContextAccessors) - { - _contextParameterReplacingExpressionVisitor = new ContextParameterReplacingExpressionVisitor(contextType); - } + // The entry method will take care of populating this field always. So accesses should be safe. + _evaluatableExpressions = null!; + // TODO: Use MemberNotNullWhen + // Value won't be accessed when condition is not met. + _contextParameterReplacingExpressionVisitor = _generateContextAccessors + ? new ContextParameterReplacingExpressionVisitor(contextType) + : null!; } /// @@ -92,7 +98,8 @@ public virtual Expression ExtractParameters([NotNull] Expression expression) /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// - public override Expression Visit(Expression expression) + [return: CA.NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) { if (expression == null) { @@ -215,7 +222,7 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) } } - private Expression TryGetConstantValue(Expression expression) + private Expression? TryGetConstantValue(Expression expression) { if (_evaluatableExpressions.ContainsKey(expression)) { @@ -367,7 +374,8 @@ private static Expression RemoveConvert(Expression expression) return expression; } - private object GetValue(Expression expression, out string parameterName) + [return: CA.NotNullIfNotNull("expression")] + private object? GetValue(Expression? expression, out string? parameterName) { parameterName = null; @@ -473,6 +481,8 @@ public EvaluatableExpressionFindingExpressionVisitor( _evaluatableExpressionFilter = evaluatableExpressionFilter; _model = model; _parameterize = parameterize; + // The entry method will take care of populating this field always. So accesses should be safe. + _evaluatableExpressions = null!; } public IDictionary Find(Expression expression) diff --git a/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs b/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs index 939f07d5c52..109b3a34f14 100644 --- a/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs +++ b/src/EFCore/Query/Internal/QueryCompilationContextFactory.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/QueryCompiler.cs b/src/EFCore/Query/Internal/QueryCompiler.cs index 258272cb165..6b9715792cc 100644 --- a/src/EFCore/Query/Internal/QueryCompiler.cs +++ b/src/EFCore/Query/Internal/QueryCompiler.cs @@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/QueryDebugView.cs b/src/EFCore/Query/Internal/QueryDebugView.cs index fd4630a655a..30b1ebb0f31 100644 --- a/src/EFCore/Query/Internal/QueryDebugView.cs +++ b/src/EFCore/Query/Internal/QueryDebugView.cs @@ -5,6 +5,8 @@ using System.Diagnostics; using JetBrains.Annotations; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs b/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs index 8a0d88758a6..5c9b8dcb595 100644 --- a/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/QueryOptimizingExpressionVisitor.cs @@ -6,6 +6,9 @@ using System.Reflection; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Utilities; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query.Internal { @@ -193,7 +196,11 @@ protected override Expression VisitUnary(UnaryExpression unaryExpression) return base.VisitUnary(unaryExpression); } - private bool TryExtractEqualityOperands(Expression expression, out Expression left, out Expression right, out bool negated) + private bool TryExtractEqualityOperands( + Expression expression, + [CA.NotNullWhen(true)] out Expression? left, + [CA.NotNullWhen(true)] out Expression? right, + out bool negated) { (left, right, negated) = (default, default, default); @@ -223,14 +230,18 @@ private bool TryExtractEqualityOperands(Expression expression, out Expression le && methodCallExpression.Object.Type == methodCallExpression.Arguments[0].Type) { (left, right) = (methodCallExpression.Object, methodCallExpression.Arguments[0]); + + return true; } else if (methodCallExpression.Arguments.Count == 2 && methodCallExpression.Arguments[0].Type == methodCallExpression.Arguments[1].Type) { (left, right) = (methodCallExpression.Arguments[0], methodCallExpression.Arguments[1]); + + return true; } - return true; + return false; } case UnaryExpression unaryExpression @@ -245,7 +256,7 @@ when unaryExpression.IsLogicalNot(): return false; } - private Expression TryOptimizeMemberAccessOverConditional(Expression expression) + private Expression? TryOptimizeMemberAccessOverConditional(Expression expression) { // Simplify (a != null ? new { Member = b, ... } : null).Member // to a != null ? b : null diff --git a/src/EFCore/Query/Internal/QueryTranslationPostprocessorFactory.cs b/src/EFCore/Query/Internal/QueryTranslationPostprocessorFactory.cs index 41e8fb76882..c03bfda0f3b 100644 --- a/src/EFCore/Query/Internal/QueryTranslationPostprocessorFactory.cs +++ b/src/EFCore/Query/Internal/QueryTranslationPostprocessorFactory.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/QueryTranslationPreprocessorFactory.cs b/src/EFCore/Query/Internal/QueryTranslationPreprocessorFactory.cs index d71bb40d6c2..3c8fb35d9d1 100644 --- a/src/EFCore/Query/Internal/QueryTranslationPreprocessorFactory.cs +++ b/src/EFCore/Query/Internal/QueryTranslationPreprocessorFactory.cs @@ -5,6 +5,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs index 2025e7ce373..42e458f962a 100644 --- a/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs @@ -13,6 +13,8 @@ using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// @@ -61,7 +63,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return expression; } - Expression visitedExpression = null; + Expression? visitedExpression = null; if (method.DeclaringType == typeof(Enumerable)) { visitedExpression = TryConvertEnumerableToQueryable(methodCallExpression); @@ -173,7 +175,7 @@ private void VerifyReturnType(Expression expression, ParameterExpression lambdaP } } - private Expression ExtractQueryMetadata(MethodCallExpression methodCallExpression) + private Expression? ExtractQueryMetadata(MethodCallExpression methodCallExpression) { // We visit innerQueryable first so that we can get information in the same order operators are applied. var genericMethodDefinition = methodCallExpression.Method.GetGenericMethodDefinition(); @@ -251,7 +253,7 @@ private Expression TryConvertEnumerableToQueryable(MethodCallExpression methodCa var enumerableMethod = methodCallExpression.Method; var enumerableParameters = enumerableMethod.GetParameters(); - Type[] genericTypeArguments = null; + Type[] genericTypeArguments = Array.Empty(); if (enumerableMethod.Name == nameof(Enumerable.Min) || enumerableMethod.Name == nameof(Enumerable.Max)) { @@ -633,7 +635,7 @@ private sealed class SelectManyVerifyingExpressionVisitor : ExpressionVisitor private readonly List _allowedParameters = new List(); private readonly ISet _allowedMethods = new HashSet { nameof(Queryable.Where), nameof(Queryable.AsQueryable) }; - private ParameterExpression _rootParameter; + private ParameterExpression? _rootParameter; private int _rootParameterCount; private bool _correlated; diff --git a/src/EFCore/Query/Internal/SubqueryMemberPushdownExpressionVisitor.cs b/src/EFCore/Query/Internal/SubqueryMemberPushdownExpressionVisitor.cs index 4ec711c9f81..9065b1ec957 100644 --- a/src/EFCore/Query/Internal/SubqueryMemberPushdownExpressionVisitor.cs +++ b/src/EFCore/Query/Internal/SubqueryMemberPushdownExpressionVisitor.cs @@ -10,6 +10,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query.Internal { /// diff --git a/src/EFCore/Query/MaterializeCollectionNavigationExpression.cs b/src/EFCore/Query/MaterializeCollectionNavigationExpression.cs index 9e2b910296e..442c9025aa2 100644 --- a/src/EFCore/Query/MaterializeCollectionNavigationExpression.cs +++ b/src/EFCore/Query/MaterializeCollectionNavigationExpression.cs @@ -7,6 +7,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/ProjectionBindingExpression.cs b/src/EFCore/Query/ProjectionBindingExpression.cs index 669f5d07555..94a5fab35d9 100644 --- a/src/EFCore/Query/ProjectionBindingExpression.cs +++ b/src/EFCore/Query/ProjectionBindingExpression.cs @@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -87,7 +89,7 @@ public ProjectionBindingExpression( /// /// The projection member to bind if binding is via projection member. /// - public virtual ProjectionMember ProjectionMember { get; } + public virtual ProjectionMember? ProjectionMember { get; } /// /// The projection member to bind if binding is via projection index. @@ -97,7 +99,7 @@ public ProjectionBindingExpression( /// /// The projection member to bind if binding is via index map for a value buffer. /// - public virtual IDictionary IndexMap { get; } + public virtual IDictionary? IndexMap { get; } /// public override Type Type { get; } @@ -128,7 +130,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) { expressionPrinter.Append(Index.ToString()); } - else + else if (IndexMap != null) { using (expressionPrinter.Indent()) { @@ -141,7 +143,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) } /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj != null && (ReferenceEquals(this, obj) || obj is ProjectionBindingExpression projectionBindingExpression diff --git a/src/EFCore/Query/ProjectionMember.cs b/src/EFCore/Query/ProjectionMember.cs index 6d520c703a7..d2a130ac248 100644 --- a/src/EFCore/Query/ProjectionMember.cs +++ b/src/EFCore/Query/ProjectionMember.cs @@ -9,6 +9,8 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -95,7 +97,7 @@ public override int GetHashCode() } /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj != null && (obj is ProjectionMember projectionMember && Equals(projectionMember)); diff --git a/src/EFCore/Query/QueryCompilationContext.cs b/src/EFCore/Query/QueryCompilationContext.cs index 0f1723eb0ff..ba57ca4542a 100644 --- a/src/EFCore/Query/QueryCompilationContext.cs +++ b/src/EFCore/Query/QueryCompilationContext.cs @@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -54,7 +56,7 @@ public class QueryCompilationContext private readonly ExpressionPrinter _expressionPrinter; - private Dictionary _runtimeParameters; + private Dictionary? _runtimeParameters; /// /// Creates a new instance of the class. diff --git a/src/EFCore/Query/QueryCompilationContextDependencies.cs b/src/EFCore/Query/QueryCompilationContextDependencies.cs index e2b466c47b1..a5654034986 100644 --- a/src/EFCore/Query/QueryCompilationContextDependencies.cs +++ b/src/EFCore/Query/QueryCompilationContextDependencies.cs @@ -10,6 +10,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryContext.cs b/src/EFCore/Query/QueryContext.cs index dbe61d7d497..9568ebfe42b 100644 --- a/src/EFCore/Query/QueryContext.cs +++ b/src/EFCore/Query/QueryContext.cs @@ -14,6 +14,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -28,7 +30,7 @@ namespace Microsoft.EntityFrameworkCore.Query public abstract class QueryContext : IParameterValues { private readonly IDictionary _parameterValues = new Dictionary(); - private IStateManager _stateManager; + private IStateManager? _stateManager; /// /// @@ -69,7 +71,8 @@ public virtual void SetNavigationIsLoaded([NotNull] object entity, [NotNull] INa Check.NotNull(entity, nameof(entity)); Check.NotNull(navigation, nameof(navigation)); - _stateManager.TryGetEntry(entity).SetIsLoaded(navigation); + // InitializeStateManager will populate the field before calling here + _stateManager!.TryGetEntry(entity).SetIsLoaded(navigation); } /// @@ -154,7 +157,8 @@ public virtual InternalEntityEntry TryGetEntry( [NotNull] object[] keyValues, bool throwOnNullKey, out bool hasNullKey) - => _stateManager.TryGetEntry(key, keyValues, throwOnNullKey, out hasNullKey); + // InitializeStateManager will populate the field before calling here + => _stateManager!.TryGetEntry(key, keyValues, throwOnNullKey, out hasNullKey); /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to @@ -167,6 +171,7 @@ public virtual InternalEntityEntry StartTracking( [NotNull] IEntityType entityType, [NotNull] object entity, ValueBuffer valueBuffer) - => _stateManager.StartTrackingFromQuery(entityType, entity, valueBuffer); + // InitializeStateManager will populate the field before calling here + => _stateManager!.StartTrackingFromQuery(entityType, entity, valueBuffer); } } diff --git a/src/EFCore/Query/QueryContextDependencies.cs b/src/EFCore/Query/QueryContextDependencies.cs index b666d156474..9181d6c5ab4 100644 --- a/src/EFCore/Query/QueryContextDependencies.cs +++ b/src/EFCore/Query/QueryContextDependencies.cs @@ -12,6 +12,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryRootExpression.cs b/src/EFCore/Query/QueryRootExpression.cs index f180cf39bcb..00fbf6201fb 100644 --- a/src/EFCore/Query/QueryRootExpression.cs +++ b/src/EFCore/Query/QueryRootExpression.cs @@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -53,7 +55,7 @@ public QueryRootExpression([NotNull] IEntityType entityType) /// /// The query provider associated with this query root. /// - public virtual IAsyncQueryProvider QueryProvider { get; } + public virtual IAsyncQueryProvider? QueryProvider { get; } /// /// The entity type reprenseted by this query root. @@ -105,7 +107,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter) => Print(expressionPrinter); /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj != null && (ReferenceEquals(this, obj) || obj is QueryRootExpression queryRootExpression diff --git a/src/EFCore/Query/QueryTranslationPostprocessor.cs b/src/EFCore/Query/QueryTranslationPostprocessor.cs index dbe159e6522..f0d98eb6b71 100644 --- a/src/EFCore/Query/QueryTranslationPostprocessor.cs +++ b/src/EFCore/Query/QueryTranslationPostprocessor.cs @@ -5,6 +5,8 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryTranslationPostprocessorDependencies.cs b/src/EFCore/Query/QueryTranslationPostprocessorDependencies.cs index 639307af0e2..fa7d75b264b 100644 --- a/src/EFCore/Query/QueryTranslationPostprocessorDependencies.cs +++ b/src/EFCore/Query/QueryTranslationPostprocessorDependencies.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryTranslationPreprocessor.cs b/src/EFCore/Query/QueryTranslationPreprocessor.cs index d819ec8f3ac..b0e5cafba00 100644 --- a/src/EFCore/Query/QueryTranslationPreprocessor.cs +++ b/src/EFCore/Query/QueryTranslationPreprocessor.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs b/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs index a5a06e67c3e..55f071b1054 100644 --- a/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs +++ b/src/EFCore/Query/QueryTranslationPreprocessorDependencies.cs @@ -6,6 +6,8 @@ using Microsoft.EntityFrameworkCore.Utilities; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs index 088298656af..12c82aabae7 100644 --- a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitor.cs @@ -13,6 +13,8 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -57,7 +59,7 @@ protected QueryableMethodTranslatingExpressionVisitor( /// /// Detailed information about errors encountered during translation. /// - public virtual string TranslationErrorDetails { get; private set; } + public virtual string? TranslationErrorDetails { get; private set; } /// /// Adds detailed information about errors encountered during translation. @@ -96,7 +98,7 @@ protected override Expression VisitExtension(Expression extensionExpression) } /// - protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) + protected override Expression? VisitMethodCall(MethodCallExpression methodCallExpression) { Check.NotNull(methodCallExpression, nameof(methodCallExpression)); @@ -493,7 +495,7 @@ LambdaExpression GetLambdaExpressionFromArgument(int argumentIndex) } return _subquery - ? (Expression)null + ? (Expression?)null : throw new InvalidOperationException(CoreStrings.TranslationFailed(methodCallExpression.Print())); } @@ -598,7 +600,8 @@ protected override Expression VisitExtension(Expression extensionExpression) return extensionExpression is ProjectionBindingExpression projectionBindingExpression ? new ProjectionBindingExpression( _queryExpression, - projectionBindingExpression.ProjectionMember.Prepend(_memberShift), + // ProjectionMember would be non-null here as we are shifting members + projectionBindingExpression.ProjectionMember!.Prepend(_memberShift), projectionBindingExpression.Type) : base.VisitExtension(extensionExpression); } @@ -629,7 +632,7 @@ private static Expression AccessInnerTransparentField( /// /// The subquery expression to translate. /// The translation of the given subquery. - public virtual ShapedQueryExpression TranslateSubquery([NotNull] Expression expression) + public virtual ShapedQueryExpression? TranslateSubquery([NotNull] Expression expression) { Check.NotNull(expression, nameof(expression)); @@ -680,7 +683,7 @@ public virtual ShapedQueryExpression TranslateSubquery([NotNull] Expression expr /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateAny( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate); + [CanBeNull] LambdaExpression? predicate); /// /// Translates method and other overloads over the given source. @@ -691,7 +694,7 @@ protected abstract ShapedQueryExpression TranslateAny( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateAverage( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression selector, + [CanBeNull] LambdaExpression? selector, [NotNull] Type resultType); /// @@ -728,7 +731,7 @@ protected abstract ShapedQueryExpression TranslateConcat( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateCount( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate); + [CanBeNull] LambdaExpression? predicate); /// /// Translates method and other overloads over the given source. @@ -738,7 +741,7 @@ protected abstract ShapedQueryExpression TranslateCount( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateDefaultIfEmpty( [NotNull] ShapedQueryExpression source, - [CanBeNull] Expression defaultValue); + [CanBeNull] Expression? defaultValue); /// /// Translates method over the given source. @@ -781,7 +784,7 @@ protected abstract ShapedQueryExpression TranslateExcept( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateFirstOrDefault( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate, + [CanBeNull] LambdaExpression? predicate, [NotNull] Type returnType, bool returnDefault); @@ -797,8 +800,8 @@ protected abstract ShapedQueryExpression TranslateFirstOrDefault( protected abstract ShapedQueryExpression TranslateGroupBy( [NotNull] ShapedQueryExpression source, [NotNull] LambdaExpression keySelector, - [CanBeNull] LambdaExpression elementSelector, - [CanBeNull] LambdaExpression resultSelector); + [CanBeNull] LambdaExpression? elementSelector, + [CanBeNull] LambdaExpression? resultSelector); /// /// Translates @@ -844,8 +847,8 @@ protected abstract ShapedQueryExpression TranslateIntersect( protected abstract ShapedQueryExpression TranslateJoin( [NotNull] ShapedQueryExpression outer, [NotNull] ShapedQueryExpression inner, - [CanBeNull] LambdaExpression outerKeySelector, - [CanBeNull] LambdaExpression innerKeySelector, + [NotNull] LambdaExpression outerKeySelector, + [NotNull] LambdaExpression innerKeySelector, [NotNull] LambdaExpression resultSelector); /// @@ -866,8 +869,8 @@ protected abstract ShapedQueryExpression TranslateJoin( protected abstract ShapedQueryExpression TranslateLeftJoin( [NotNull] ShapedQueryExpression outer, [NotNull] ShapedQueryExpression inner, - [CanBeNull] LambdaExpression outerKeySelector, - [CanBeNull] LambdaExpression innerKeySelector, + [NotNull] LambdaExpression outerKeySelector, + [NotNull] LambdaExpression innerKeySelector, [NotNull] LambdaExpression resultSelector); /// @@ -881,7 +884,7 @@ protected abstract ShapedQueryExpression TranslateLeftJoin( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateLastOrDefault( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate, + [CanBeNull] LambdaExpression? predicate, [NotNull] Type returnType, bool returnDefault); @@ -893,7 +896,7 @@ protected abstract ShapedQueryExpression TranslateLastOrDefault( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateLongCount( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate); + [CanBeNull] LambdaExpression? predicate); /// /// Translates method and other overloads over the given source. @@ -904,7 +907,7 @@ protected abstract ShapedQueryExpression TranslateLongCount( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateMax( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression selector, + [CanBeNull] LambdaExpression? selector, [NotNull] Type resultType); /// @@ -916,7 +919,7 @@ protected abstract ShapedQueryExpression TranslateMax( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateMin( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression selector, + [CanBeNull] LambdaExpression? selector, [NotNull] Type resultType); /// @@ -997,7 +1000,7 @@ protected abstract ShapedQueryExpression TranslateSelectMany( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateSingleOrDefault( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression predicate, + [CanBeNull] LambdaExpression? predicate, [NotNull] Type returnType, bool returnDefault); @@ -1031,7 +1034,7 @@ protected abstract ShapedQueryExpression TranslateSkipWhile( /// The shaped query after translation. protected abstract ShapedQueryExpression TranslateSum( [NotNull] ShapedQueryExpression source, - [CanBeNull] LambdaExpression selector, + [CanBeNull] LambdaExpression? selector, [NotNull] Type resultType); /// diff --git a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitorDependencies.cs b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitorDependencies.cs index ed92c797b8f..8cc4a416dca 100644 --- a/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitorDependencies.cs +++ b/src/EFCore/Query/QueryableMethodTranslatingExpressionVisitorDependencies.cs @@ -4,6 +4,8 @@ using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/QueryableMethods.cs b/src/EFCore/Query/QueryableMethods.cs index 96a0bcf81a5..008a069ce1d 100644 --- a/src/EFCore/Query/QueryableMethods.cs +++ b/src/EFCore/Query/QueryableMethods.cs @@ -9,6 +9,8 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -43,7 +45,7 @@ public static class QueryableMethods /// /// The for - /// + /// /// public static MethodInfo AnyWithPredicate { get; } @@ -79,7 +81,7 @@ public static class QueryableMethods /// /// The for - /// + /// /// public static MethodInfo CountWithPredicate { get; } diff --git a/src/EFCore/Query/ReplacingExpressionVisitor.cs b/src/EFCore/Query/ReplacingExpressionVisitor.cs index 4e0ede84eb6..d8c2d281ff1 100644 --- a/src/EFCore/Query/ReplacingExpressionVisitor.cs +++ b/src/EFCore/Query/ReplacingExpressionVisitor.cs @@ -8,6 +8,9 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Utilities; +using CA = System.Diagnostics.CodeAnalysis; + +#nullable enable namespace Microsoft.EntityFrameworkCore.Query { @@ -56,7 +59,8 @@ public ReplacingExpressionVisitor([NotNull] IReadOnlyList originals, } /// - public override Expression Visit(Expression expression) + [return: CA.NotNullIfNotNull("expression")] + public override Expression? Visit(Expression? expression) { if (expression == null || expression is ShapedQueryExpression diff --git a/src/EFCore/Query/ResultCardinality.cs b/src/EFCore/Query/ResultCardinality.cs index 451299c13a2..f22d7c78398 100644 --- a/src/EFCore/Query/ResultCardinality.cs +++ b/src/EFCore/Query/ResultCardinality.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs index f132f729cfc..e277e16c3f7 100644 --- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitor.cs @@ -17,6 +17,8 @@ using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// @@ -41,7 +43,7 @@ public abstract class ShapedQueryCompilingExpressionVisitor : ExpressionVisitor private static readonly PropertyInfo _cancellationTokenMemberInfo = typeof(QueryContext).GetProperty(nameof(QueryContext.CancellationToken)); - private readonly Expression _cancellationTokenParameter; + private readonly Expression? _cancellationTokenParameter; private readonly EntityMaterializerInjectingExpressionVisitor _entityMaterializerInjectingExpressionVisitor; private readonly ConstantVerifyingExpressionVisitor _constantVerifyingExpressionVisitor; @@ -161,7 +163,9 @@ private static async Task SingleOrDefaultAsync( await using var enumerator = asyncEnumerable.GetAsyncEnumerator(cancellationToken); if (!(await enumerator.MoveNextAsync().ConfigureAwait(false))) { - return default; + // TODO: Convert return to Task when changing to C# 9 + // There is currently no way to specify that this method can return Task where TSource is not constrainted. + return default!; } var result = enumerator.Current; @@ -275,7 +279,7 @@ protected override Expression VisitExtension(Expression extensionExpression) : base.VisitExtension(extensionExpression); } - private static Expression RemoveConvert(Expression expression) + private static Expression? RemoveConvert(Expression? expression) { while (expression != null && (expression.NodeType == ExpressionType.Convert @@ -343,7 +347,7 @@ public Expression Inject(Expression expression) } } - bool ContainsOwner(IEntityType owner) + bool ContainsOwner(IEntityType? owner) => owner != null && (_visitedEntityTypes.Contains(owner) || ContainsOwner(owner.BaseType)); } @@ -476,7 +480,7 @@ private Expression MaterializeEntity( ParameterExpression materializationContextVariable, ParameterExpression concreteEntityTypeVariable, ParameterExpression instanceVariable, - ParameterExpression entryVariable) + ParameterExpression? entryVariable) { var entityType = entityShaperExpression.EntityType; @@ -492,7 +496,8 @@ private Expression MaterializeEntity( shadowValuesVariable, Expression.Constant(ValueBuffer.Empty))); - var returnType = entityType.ClrType; + // No shadow entities at runtime + var returnType = entityType.ClrType!; Expression materializationExpression; var valueBufferExpression = Expression.Call(materializationContextVariable, MaterializationContext.GetValueBufferMethod); var expressionContext = (returnType, materializationContextVariable, concreteEntityTypeVariable, shadowValuesVariable); diff --git a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitorDependencies.cs b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitorDependencies.cs index 5c9f248d7bc..1217614aeda 100644 --- a/src/EFCore/Query/ShapedQueryCompilingExpressionVisitorDependencies.cs +++ b/src/EFCore/Query/ShapedQueryCompilingExpressionVisitorDependencies.cs @@ -8,6 +8,8 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/ShapedQueryExpression.cs b/src/EFCore/Query/ShapedQueryExpression.cs index 84b9545fc58..c981cba087f 100644 --- a/src/EFCore/Query/ShapedQueryExpression.cs +++ b/src/EFCore/Query/ShapedQueryExpression.cs @@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/EFCore/Query/TransparentIdentifierFactory.cs b/src/EFCore/Query/TransparentIdentifierFactory.cs index 9f30e743638..2e98f2c272d 100644 --- a/src/EFCore/Query/TransparentIdentifierFactory.cs +++ b/src/EFCore/Query/TransparentIdentifierFactory.cs @@ -5,6 +5,8 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Utilities; +#nullable enable + namespace Microsoft.EntityFrameworkCore.Query { /// diff --git a/src/Shared/Check.cs b/src/Shared/Check.cs index d06aa69dfdb..0a3ab5dc2da 100644 --- a/src/Shared/Check.cs +++ b/src/Shared/Check.cs @@ -112,7 +112,7 @@ public static IReadOnlyList HasNoEmptyElements( } [Conditional("DEBUG")] - public static void DebugAssert([CA.DoesNotReturnIfAttribute(false)] bool condition, string message) + public static void DebugAssert([CA.DoesNotReturnIf(false)] bool condition, string message) { if (!condition) { diff --git a/src/Shared/NonCapturingLazyInitializer.cs b/src/Shared/NonCapturingLazyInitializer.cs index 749d0d6ed8b..cb38ffb5a01 100644 --- a/src/Shared/NonCapturingLazyInitializer.cs +++ b/src/Shared/NonCapturingLazyInitializer.cs @@ -16,7 +16,7 @@ internal static class NonCapturingLazyInitializer { public static TValue EnsureInitialized( [CanBeNull, CA.NotNull] ref TValue? target, - [CanBeNull] TParam param, + [NotNull] TParam param, [NotNull] Func valueFactory) where TValue : class { @@ -34,8 +34,8 @@ public static TValue EnsureInitialized( public static TValue EnsureInitialized( [CanBeNull, CA.NotNull] ref TValue? target, - [CanBeNull] TParam1 param1, - [CanBeNull] TParam2 param2, + [NotNull] TParam1 param1, + [NotNull] TParam2 param2, [NotNull] Func valueFactory) where TValue : class { @@ -48,7 +48,7 @@ public static TValue EnsureInitialized( Interlocked.CompareExchange(ref target, valueFactory(param1, param2), null); - return target!; + return target; } public static TValue EnsureInitialized( @@ -65,27 +65,28 @@ public static TValue EnsureInitialized( Interlocked.CompareExchange(ref target, value, null); - return target!; + return target; } public static TValue EnsureInitialized( [CanBeNull, CA.NotNull] ref TValue? target, - [CanBeNull] TParam param, + [NotNull] TParam param, [NotNull] Action valueFactory) where TValue : class { - if (Volatile.Read(ref target) != null) + var tmp = Volatile.Read(ref target); + if (tmp != null) { Check.DebugAssert(target != null, $"target was null in {nameof(EnsureInitialized)} after check"); - return target!; + return tmp; } valueFactory(param); - var tmp = Volatile.Read(ref target); - Check.DebugAssert(target != null && tmp != null, + var tmp2 = Volatile.Read(ref target); + Check.DebugAssert(target != null && tmp2 != null, $"{nameof(valueFactory)} did not initialize {nameof(target)} in {nameof(EnsureInitialized)}"); - return tmp; + return tmp2; } } } diff --git a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs index c0d21dc31c0..6393ea98f40 100644 --- a/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs +++ b/test/EFCore.Design.Tests/Migrations/ModelSnapshotSqlServerTest.cs @@ -1547,7 +1547,7 @@ public virtual void Shared_columns_are_stored_in_the_snapshot() builder.Entity(b => { b.ToTable("EntityWithProperties"); - b.Property(e => e.AlternateId).HasColumnName("AlternateId"); + b.Property(e => e.AlternateId).HasColumnName("AlternateId"); b.HasOne(e => e.EntityWithOneProperty).WithOne(e => e.EntityWithTwoProperties) .HasForeignKey(e => e.Id); }); diff --git a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs index ab80a7fc823..de5a222b310 100644 --- a/test/EFCore.Relational.Tests/RelationalEventIdTest.cs +++ b/test/EFCore.Relational.Tests/RelationalEventIdTest.cs @@ -43,7 +43,7 @@ public void Every_eventId_has_a_logger_method_and_logs_when_level_enabled() var property = entityType.AddProperty("A", typeof(int), ConfigurationSource.Convention, ConfigurationSource.Convention); var key = entityType.AddKey(property, ConfigurationSource.Convention); var foreignKey = new ForeignKey(new List { property }, key, entityType, entityType, ConfigurationSource.Convention); - var index = new Metadata.Internal.Index(new List { property }, "IndexName", entityType, ConfigurationSource.Convention); + var index = new Index(new List { property }, "IndexName", entityType, ConfigurationSource.Convention); var contextServices = RelationalTestHelpers.Instance.CreateContextServices(model.FinalizeModel()); var fakeFactories = new Dictionary>