diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 6a17fe1dd08..6f6592b4a6b 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"microsoft.dotnet.darc": {
- "version": "1.1.0-beta.25358.3",
+ "version": "1.1.0-beta.25366.1",
"commands": [
"darc"
]
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 428c37a15dc..3e4e0b1bed1 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -10,9 +10,9 @@
https://github.com/dotnet/dotnet
67889d9d2f21a890ac29bcd175c0d1937a401781
-
+
https://github.com/dotnet/arcade-services
- afa79da3b68fd0fe48d90ea7fcbffbf7789c6d7f
+ 3a31b413f81d10b329db1c91aef860a77d5f3ab9
diff --git a/src/efcore/eng/Version.Details.xml b/src/efcore/eng/Version.Details.xml
index a88e269d18e..0090de09b77 100644
--- a/src/efcore/eng/Version.Details.xml
+++ b/src/efcore/eng/Version.Details.xml
@@ -1,80 +1,80 @@
-
+
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
-
+
https://github.com/dotnet/dotnet
- 3c34a3f0178f5a637d21c3f0ba5a4ee86ab8e976
+ 78061f4bcc414fa2054be6237b1fd3813d8edf6b
diff --git a/src/efcore/eng/Versions.props b/src/efcore/eng/Versions.props
index e2a9f7d63f0..8d7ef6a18e8 100644
--- a/src/efcore/eng/Versions.props
+++ b/src/efcore/eng/Versions.props
@@ -16,24 +16,24 @@
False
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
- 10.0.0-preview.7.25364.102
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
+ 10.0.0-preview.7.25365.101
- 10.0.0-beta.25364.102
+ 10.0.0-beta.25365.101
17.14.8
diff --git a/src/efcore/global.json b/src/efcore/global.json
index 7cb1bad5cb7..b7232466c10 100644
--- a/src/efcore/global.json
+++ b/src/efcore/global.json
@@ -18,7 +18,7 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25364.102",
- "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25364.102"
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25365.101",
+ "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25365.101"
}
}
diff --git a/src/efcore/src/EFCore.Relational/EFExtensions.cs b/src/efcore/src/EFCore.Relational/EFExtensions.cs
index c2677cb8706..c790c6256f2 100644
--- a/src/efcore/src/EFCore.Relational/EFExtensions.cs
+++ b/src/efcore/src/EFCore.Relational/EFExtensions.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Collections;
+
namespace Microsoft.EntityFrameworkCore;
///
@@ -25,10 +27,10 @@ public static class EFExtensions
/// Within the context of an EF LINQ query, forces its argument to be inserted into the query as a multiple parameter expressions.
///
/// Note that this is a static method accessed through the top-level static type.
- /// The type of collection element.
+ /// The type of collection.
/// The collection to be integrated as parameters into the query.
/// The same value for further use in the query.
- public static IEnumerable MultipleParameters(IEnumerable argument)
+ public static TSource MultipleParameters(TSource argument) where TSource : IEnumerable
=> throw new InvalidOperationException(RelationalStrings.EFMultipleParametersInvoked);
}
}
diff --git a/src/efcore/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs b/src/efcore/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs
index 269a68bfb0a..01935a24036 100644
--- a/src/efcore/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs
+++ b/src/efcore/src/EFCore.Relational/Infrastructure/RelationalDbContextOptionsBuilder.cs
@@ -179,7 +179,7 @@ public virtual TBuilder ExecutionStrategy(
///
[Obsolete("Use UseParameterizedCollectionMode instead.")]
public virtual TBuilder TranslateParameterizedCollectionsToConstants()
- => UseParameterizedCollectionMode(ParameterizedCollectionMode.Constants);
+ => UseParameterizedCollectionMode(ParameterTranslationMode.Constant);
///
/// Configures the context to translate parameterized collections to a single array-like parameter.
@@ -202,13 +202,13 @@ public virtual TBuilder TranslateParameterizedCollectionsToConstants()
///
[Obsolete("Use UseParameterizedCollectionMode instead.")]
public virtual TBuilder TranslateParameterizedCollectionsToParameters()
- => UseParameterizedCollectionMode(ParameterizedCollectionMode.Parameter);
+ => UseParameterizedCollectionMode(ParameterTranslationMode.Parameter);
///
- /// Configures the to use when translating parameterized collections.
+ /// Configures the mode to use when translating parameterized collections.
///
/// The same builder instance so that multiple calls can be chained.
- public virtual TBuilder UseParameterizedCollectionMode(ParameterizedCollectionMode parameterizedCollectionMode)
+ public virtual TBuilder UseParameterizedCollectionMode(ParameterTranslationMode parameterizedCollectionMode)
=> WithOption(e => (TExtension)e.WithUseParameterizedCollectionMode(parameterizedCollectionMode));
///
diff --git a/src/efcore/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs b/src/efcore/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs
index e2cc09b80c8..a052b74c1eb 100644
--- a/src/efcore/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs
+++ b/src/efcore/src/EFCore.Relational/Infrastructure/RelationalOptionsExtension.cs
@@ -36,7 +36,7 @@ public abstract class RelationalOptionsExtension : IDbContextOptionsExtension
private string? _migrationsHistoryTableName;
private string? _migrationsHistoryTableSchema;
private Func? _executionStrategyFactory;
- private ParameterizedCollectionMode? _parameterizedCollectionMode;
+ private ParameterTranslationMode? _parameterizedCollectionMode;
///
/// Creates a new set of options with everything set to default values.
@@ -386,8 +386,8 @@ public virtual RelationalOptionsExtension WithExecutionStrategyFactory(
///
/// Configured translation mode for parameterized collections.
///
- public virtual ParameterizedCollectionMode ParameterizedCollectionMode
- => _parameterizedCollectionMode ?? ParameterizedCollectionMode.MultipleParameters;
+ public virtual ParameterTranslationMode ParameterizedCollectionMode
+ => _parameterizedCollectionMode ?? ParameterTranslationMode.MultipleParameters;
///
/// Creates a new instance with all options the same as for this instance, but with the given option changed.
@@ -395,7 +395,7 @@ public virtual ParameterizedCollectionMode ParameterizedCollectionMode
///
/// The option to change.
public virtual RelationalOptionsExtension WithUseParameterizedCollectionMode(
- ParameterizedCollectionMode parameterizedCollectionMode)
+ ParameterTranslationMode parameterizedCollectionMode)
{
var clone = Clone();
diff --git a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs
index 4d19a2b3eaa..e7ba5c61764 100644
--- a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs
+++ b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalCommandCache.cs
@@ -35,13 +35,13 @@ public RelationalCommandCache(
IRelationalParameterBasedSqlProcessorFactory relationalParameterBasedSqlProcessorFactory,
Expression queryExpression,
bool useRelationalNulls,
- ParameterizedCollectionMode parameterizedCollectionMode)
+ ParameterTranslationMode collectionParameterTranslationMode)
{
_memoryCache = memoryCache;
_querySqlGeneratorFactory = querySqlGeneratorFactory;
_queryExpression = queryExpression;
_relationalParameterBasedSqlProcessor = relationalParameterBasedSqlProcessorFactory.Create(
- new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, parameterizedCollectionMode));
+ new RelationalParameterBasedSqlProcessorParameters(useRelationalNulls, collectionParameterTranslationMode));
}
///
diff --git a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs
index b955ccae286..f1ed4b087b1 100644
--- a/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs
+++ b/src/efcore/src/EFCore.Relational/Query/Internal/RelationalParameterProcessor.cs
@@ -128,7 +128,7 @@ private SqlParameterExpression VisitSqlParameter(SqlParameterExpression paramete
uniquifiedName,
parameter.Type,
parameter.IsNullable,
- parameter.ShouldBeConstantized,
+ parameter.TranslationMode,
parameter.TypeMapping);
return _sqlParameters[newParameter.InvariantName] = newParameter;
diff --git a/src/efcore/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs b/src/efcore/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs
index 415a8db6e54..d0bc742fd83 100644
--- a/src/efcore/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs
+++ b/src/efcore/src/EFCore.Relational/Query/RelationalParameterBasedSqlProcessorParameters.cs
@@ -16,17 +16,17 @@ public sealed record RelationalParameterBasedSqlProcessorParameters
///
/// Which parametrized collection translation mode should be used.
///
- public ParameterizedCollectionMode ParameterizedCollectionMode { get; init; }
+ public ParameterTranslationMode CollectionParameterTranslationMode { get; init; }
///
/// Creates a new instance of .
///
/// A value indicating if relational nulls should be used.
- /// Which translation mode should be used.
+ /// Which translation mode should be used.
[EntityFrameworkInternal]
- public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, ParameterizedCollectionMode parameterizedCollectionMode)
+ public RelationalParameterBasedSqlProcessorParameters(bool useRelationalNulls, ParameterTranslationMode collectionParameterTranslationMode)
{
UseRelationalNulls = useRelationalNulls;
- ParameterizedCollectionMode = parameterizedCollectionMode;
+ CollectionParameterTranslationMode = collectionParameterTranslationMode;
}
}
diff --git a/src/efcore/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/efcore/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
index 848973552c6..18bb222f2f1 100644
--- a/src/efcore/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
+++ b/src/efcore/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs
@@ -21,7 +21,7 @@ public partial class RelationalQueryableMethodTranslatingExpressionVisitor : Que
private readonly IRelationalTypeMappingSource _typeMappingSource;
private readonly ISqlExpressionFactory _sqlExpressionFactory;
private readonly bool _subquery;
- private readonly ParameterizedCollectionMode _parameterizedCollectionMode;
+ private readonly ParameterTranslationMode _collectionParameterTranslationMode;
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
@@ -64,7 +64,7 @@ public RelationalQueryableMethodTranslatingExpressionVisitor(
_typeMappingSource = relationalDependencies.TypeMappingSource;
_sqlExpressionFactory = sqlExpressionFactory;
_subquery = false;
- _parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
+ _collectionParameterTranslationMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
}
///
@@ -90,7 +90,7 @@ protected RelationalQueryableMethodTranslatingExpressionVisitor(
_typeMappingSource = parentVisitor._typeMappingSource;
_sqlExpressionFactory = parentVisitor._sqlExpressionFactory;
_subquery = true;
- _parameterizedCollectionMode = RelationalOptionsExtension.Extract(parentVisitor._queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
+ _collectionParameterTranslationMode = RelationalOptionsExtension.Extract(parentVisitor._queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
}
///
@@ -244,7 +244,8 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
&& methodCallExpression.Arguments[0] is ParameterQueryRootExpression parameterSource
&& TranslateExpression(methodCallExpression.Arguments[1]) is SqlExpression item
&& _sqlTranslator.Visit(parameterSource.QueryParameterExpression) is SqlParameterExpression sqlParameterExpression
- && !parameterSource.QueryParameterExpression.ShouldNotBeConstantized)
+ && (parameterSource.QueryParameterExpression.TranslationMode is ParameterTranslationMode.Constant
+ or null))
{
var inExpression = _sqlExpressionFactory.In(item, sqlParameterExpression);
var selectExpression = new SelectExpression(inExpression, _sqlAliasManager);
@@ -298,26 +299,24 @@ JsonScalarExpression jsonScalar
var tableAlias = _sqlAliasManager.GenerateTableAlias(sqlParameterExpression.Name.TrimStart('_'));
- var constants = queryParameter.ShouldBeConstantized
- || (_parameterizedCollectionMode is ParameterizedCollectionMode.Constants
- && !queryParameter.ShouldNotBeConstantized);
- var multipleParameters = _parameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
- && !queryParameter.ShouldNotBeConstantized;
- if (constants || multipleParameters)
- {
- var valuesExpression = new ValuesExpression(
- tableAlias,
- sqlParameterExpression,
- [ValuesOrderingColumnName, ValuesValueColumnName]);
- return CreateShapedQueryExpressionForValuesExpression(
- valuesExpression,
- tableAlias,
- parameterQueryRootExpression.ElementType,
- sqlParameterExpression.TypeMapping,
- sqlParameterExpression.IsNullable);
- }
-
- return TranslatePrimitiveCollection(sqlParameterExpression, property: null, tableAlias);
+ return (queryParameter.TranslationMode ?? _collectionParameterTranslationMode) switch
+ {
+ ParameterTranslationMode.Constant or ParameterTranslationMode.MultipleParameters
+ => CreateShapedQueryExpressionForValuesExpression(
+ new ValuesExpression(
+ tableAlias,
+ sqlParameterExpression,
+ [ValuesOrderingColumnName, ValuesValueColumnName]),
+ tableAlias,
+ parameterQueryRootExpression.ElementType,
+ sqlParameterExpression.TypeMapping,
+ sqlParameterExpression.IsNullable),
+
+ ParameterTranslationMode.Parameter
+ => TranslatePrimitiveCollection(sqlParameterExpression, property: null, tableAlias),
+
+ _ => throw new UnreachableException()
+ };
}
///
diff --git a/src/efcore/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs b/src/efcore/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs
index aec6e3cc14d..dbbe1c92358 100644
--- a/src/efcore/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs
+++ b/src/efcore/src/EFCore.Relational/Query/RelationalShapedQueryCompilingExpressionVisitor.cs
@@ -19,7 +19,7 @@ public partial class RelationalShapedQueryCompilingExpressionVisitor : ShapedQue
private readonly bool _threadSafetyChecksEnabled;
private readonly bool _detailedErrorsEnabled;
private readonly bool _useRelationalNulls;
- private readonly ParameterizedCollectionMode _parameterizedCollectionMode;
+ private readonly ParameterTranslationMode _collectionParameterTranslationMode;
private readonly bool _isPrecompiling;
private readonly RelationalParameterBasedSqlProcessor _relationalParameterBasedSqlProcessor;
@@ -55,7 +55,7 @@ public RelationalShapedQueryCompilingExpressionVisitor(
_relationalParameterBasedSqlProcessor =
relationalDependencies.RelationalParameterBasedSqlProcessorFactory.Create(
- new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls, _parameterizedCollectionMode));
+ new RelationalParameterBasedSqlProcessorParameters(_useRelationalNulls, _collectionParameterTranslationMode));
_querySqlGeneratorFactory = relationalDependencies.QuerySqlGeneratorFactory;
_contextType = queryCompilationContext.ContextType;
@@ -63,7 +63,7 @@ public RelationalShapedQueryCompilingExpressionVisitor(
_threadSafetyChecksEnabled = dependencies.CoreSingletonOptions.AreThreadSafetyChecksEnabled;
_detailedErrorsEnabled = dependencies.CoreSingletonOptions.AreDetailedErrorsEnabled;
_useRelationalNulls = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).UseRelationalNulls;
- _parameterizedCollectionMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
+ _collectionParameterTranslationMode = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).ParameterizedCollectionMode;
_isPrecompiling = queryCompilationContext.IsPrecompiling;
}
@@ -500,7 +500,7 @@ private Expression CreateRelationalCommandResolverExpression(Expression queryExp
RelationalDependencies.RelationalParameterBasedSqlProcessorFactory,
queryExpression,
_useRelationalNulls,
- _parameterizedCollectionMode);
+ _collectionParameterTranslationMode);
var commandLiftableConstant = RelationalDependencies.RelationalLiftableConstantFactory.CreateLiftableConstant(
relationalCommandCache,
@@ -751,7 +751,7 @@ Expression> Generate
_relationalDependenciesRelationalParameterBasedSqlProcessorFactoryProperty),
Constant(queryExpression),
Constant(_useRelationalNulls),
- Constant(_parameterizedCollectionMode, typeof(ParameterizedCollectionMode))),
+ Constant(_collectionParameterTranslationMode, typeof(ParameterTranslationMode))),
contextParameter);
}
}
diff --git a/src/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
index c8f4ec36332..fb89e8c214e 100644
--- a/src/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
+++ b/src/efcore/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs
@@ -516,7 +516,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
name: queryParameter.Name,
queryParameter.Type,
nullable: false,
- queryParameter.ShouldBeConstantized,
+ queryParameter.TranslationMode,
typeMapping: null);
}
@@ -525,7 +525,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
name: queryParameter.Name,
queryParameter.Type,
queryParameter.Type.IsNullableType(),
- queryParameter.ShouldBeConstantized,
+ queryParameter.TranslationMode,
typeMapping: null);
case StructuralTypeShaperExpression shaper:
diff --git a/src/efcore/src/EFCore.Relational/Query/SqlExpressions/SqlParameterExpression.cs b/src/efcore/src/EFCore.Relational/Query/SqlExpressions/SqlParameterExpression.cs
index 48c1602fbaa..a279f21889f 100644
--- a/src/efcore/src/EFCore.Relational/Query/SqlExpressions/SqlParameterExpression.cs
+++ b/src/efcore/src/EFCore.Relational/Query/SqlExpressions/SqlParameterExpression.cs
@@ -17,7 +17,7 @@ public sealed class SqlParameterExpression : SqlExpression
/// The of the expression.
/// The associated with the expression.
public SqlParameterExpression(string name, Type type, RelationalTypeMapping? typeMapping)
- : this(invariantName: name, name: name, type.UnwrapNullableType(), type.IsNullableType(), shouldBeConstantized: false, typeMapping)
+ : this(invariantName: name, name: name, type.UnwrapNullableType(), type.IsNullableType(), translationMode: null, typeMapping)
{
}
@@ -31,21 +31,21 @@ public SqlParameterExpression(string name, Type type, RelationalTypeMapping? typ
///
/// The of the expression.
/// Whether this parameter can have null values.
- /// Whether the user has indicated that this query parameter should be inlined as a constant.
+ /// How the parameter should be handled.
/// The associated with the expression.
public SqlParameterExpression(
string invariantName,
string name,
Type type,
bool nullable,
- bool shouldBeConstantized,
+ ParameterTranslationMode? translationMode,
RelationalTypeMapping? typeMapping)
: base(type.UnwrapNullableType(), typeMapping)
{
InvariantName = invariantName;
Name = name;
IsNullable = nullable;
- ShouldBeConstantized = shouldBeConstantized;
+ TranslationMode = translationMode;
}
///
@@ -65,9 +65,9 @@ public SqlParameterExpression(
public bool IsNullable { get; }
///
- /// Whether the user has indicated that this query parameter should be inlined as a constant.
+ /// How the parameter should be handled.
///
- public bool ShouldBeConstantized { get; }
+ public ParameterTranslationMode? TranslationMode { get; }
///
/// Applies supplied type mapping to this expression.
@@ -75,7 +75,7 @@ public SqlParameterExpression(
/// A relational type mapping to apply.
/// A new expression which has supplied type mapping.
public SqlExpression ApplyTypeMapping(RelationalTypeMapping? typeMapping)
- => new SqlParameterExpression(InvariantName, Name, Type, IsNullable, ShouldBeConstantized, typeMapping);
+ => new SqlParameterExpression(InvariantName, Name, Type, IsNullable, TranslationMode, typeMapping);
///
protected override Expression VisitChildren(ExpressionVisitor visitor)
diff --git a/src/efcore/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs b/src/efcore/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
index 32af300b2c1..190d56525b8 100644
--- a/src/efcore/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
+++ b/src/efcore/src/EFCore.Relational/Query/SqlNullabilityProcessor.cs
@@ -39,7 +39,7 @@ public SqlNullabilityProcessor(
{
Dependencies = dependencies;
UseRelationalNulls = parameters.UseRelationalNulls;
- ParameterizedCollectionMode = parameters.ParameterizedCollectionMode;
+ CollectionParameterTranslationMode = parameters.CollectionParameterTranslationMode;
_sqlExpressionFactory = dependencies.SqlExpressionFactory;
_nonNullableColumns = [];
@@ -61,7 +61,7 @@ public SqlNullabilityProcessor(
///
/// A value indicating what translation mode to use.
///
- public virtual ParameterizedCollectionMode ParameterizedCollectionMode { get; }
+ public virtual ParameterTranslationMode CollectionParameterTranslationMode { get; }
///
/// Dictionary of current parameter values in use.
@@ -126,10 +126,9 @@ protected override Expression VisitExtension(Expression node)
var processedValues = new List();
- switch (ParameterizedCollectionMode)
+ switch (valuesParameter.TranslationMode ?? CollectionParameterTranslationMode)
{
- case ParameterizedCollectionMode.MultipleParameters
- when !valuesParameter.ShouldBeConstantized:
+ case ParameterTranslationMode.MultipleParameters:
{
var expandedParameters = _collectionParameterExpansionMap.GetOrAddNew(valuesParameter);
for (var i = 0; i < values.Count; i++)
@@ -155,11 +154,7 @@ protected override Expression VisitExtension(Expression node)
break;
}
- case ParameterizedCollectionMode.Constants:
- case ParameterizedCollectionMode.Parameter
- when valuesParameter.ShouldBeConstantized:
- case ParameterizedCollectionMode.MultipleParameters
- when valuesParameter.ShouldBeConstantized:
+ case ParameterTranslationMode.Constant:
{
foreach (var value in values)
{
@@ -819,18 +814,6 @@ InExpression ProcessInExpressionValues(
processedValues = [];
- var useParameters = ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
- && !valuesParameter.ShouldBeConstantized;
- var useConstants =
- ParameterizedCollectionMode is ParameterizedCollectionMode.Constants
- ||
- (ParameterizedCollectionMode is ParameterizedCollectionMode.Parameter
- && valuesParameter.ShouldBeConstantized)
- ||
- (ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
- && valuesParameter.ShouldBeConstantized);
- var useParameter = ParameterizedCollectionMode is ParameterizedCollectionMode.Parameter
- && !valuesParameter.ShouldBeConstantized;
var expandedParameters = _collectionParameterExpansionMap.GetOrAddNew(valuesParameter);
var expandedParametersCounter = 0;
for (var i = 0; i < values.Count; i++)
@@ -841,11 +824,11 @@ ParameterizedCollectionMode is ParameterizedCollectionMode.Constants
continue;
}
- switch (useParameters, useConstants, useParameter)
+ switch (valuesParameter.TranslationMode ?? CollectionParameterTranslationMode)
{
- case (true, false, false):
+ case ParameterTranslationMode.MultipleParameters:
// see #36311 for more info
- case (false, false, true):
+ case ParameterTranslationMode.Parameter:
{
// Create parameter for value if we didn't create it yet,
// otherwise reuse it.
@@ -863,7 +846,7 @@ ParameterizedCollectionMode is ParameterizedCollectionMode.Constants
break;
}
- case (false, true, false):
+ case ParameterTranslationMode.Constant:
{
processedValues.Add(_sqlExpressionFactory.Constant(values[i], values[i]?.GetType() ?? typeof(object), sensitive: true, elementTypeMapping));
@@ -1425,7 +1408,7 @@ protected virtual SqlExpression VisitSqlParameter(
nullable = false;
- if (sqlParameterExpression.ShouldBeConstantized)
+ if (sqlParameterExpression.TranslationMode is ParameterTranslationMode.Constant)
{
var parameters = ParametersFacade.GetParametersAndDisableSqlCaching();
diff --git a/src/efcore/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs b/src/efcore/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
index ea4b96ed806..3215b65578e 100644
--- a/src/efcore/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
+++ b/src/efcore/src/EFCore.SqlServer/Query/Internal/SqlServerSqlNullabilityProcessor.cs
@@ -187,8 +187,7 @@ protected override Expression VisitExtension(Expression node)
switch (node)
{
case ValuesExpression { ValuesParameter: SqlParameterExpression valuesParameter } valuesExpression
- when ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
- && !valuesParameter.ShouldBeConstantized:
+ when (valuesParameter.TranslationMode ?? CollectionParameterTranslationMode) is ParameterTranslationMode.MultipleParameters:
{
Check.DebugAssert(valuesParameter.TypeMapping is not null);
Check.DebugAssert(valuesParameter.TypeMapping.ElementTypeMapping is not null);
@@ -234,8 +233,7 @@ protected override SqlExpression VisitIn(InExpression inExpression, bool allowOp
switch (inExpression.ValuesParameter)
{
case SqlParameterExpression valuesParameter
- when ParameterizedCollectionMode is ParameterizedCollectionMode.MultipleParameters
- && !valuesParameter.ShouldBeConstantized:
+ when (valuesParameter.TranslationMode ?? CollectionParameterTranslationMode) is ParameterTranslationMode.MultipleParameters:
{
Check.DebugAssert(valuesParameter.TypeMapping is not null);
Check.DebugAssert(valuesParameter.TypeMapping.ElementTypeMapping is not null);
diff --git a/src/efcore/src/EFCore.Relational/ParameterizedCollectionMode.cs b/src/efcore/src/EFCore/ParameterTranslationMode.cs
similarity index 88%
rename from src/efcore/src/EFCore.Relational/ParameterizedCollectionMode.cs
rename to src/efcore/src/EFCore/ParameterTranslationMode.cs
index 89f48bea90a..964a53688e9 100644
--- a/src/efcore/src/EFCore.Relational/ParameterizedCollectionMode.cs
+++ b/src/efcore/src/EFCore/ParameterTranslationMode.cs
@@ -6,8 +6,21 @@ namespace Microsoft.EntityFrameworkCore;
///
/// Indicates how parameterized collections are translated into SQL.
///
-public enum ParameterizedCollectionMode
+public enum ParameterTranslationMode
{
+ ///
+ /// Instructs EF to translate the collection to a set of parameters:
+ /// WHERE [x].[Id] IN (@ids1, @ids2, @ids3).
+ ///
+ ///
+ ///
+ /// Note that it's possible to cause EF to translate a specific collection in a specific query to parameter by wrapping the
+ /// parameterized collection in EF.MultipleParameters: Where(x => EF.MultipleParameters(ids).Contains(x.Id). This overrides
+ /// the default.
+ ///
+ ///
+ MultipleParameters = 0,
+
///
/// Instructs EF to translate the collection to a set of constants:
/// WHERE [x].[Id] IN (1, 2, 3).
@@ -23,7 +36,7 @@ public enum ParameterizedCollectionMode
/// the default.
///
///
- Constants,
+ Constant = 1,
///
/// Instructs EF to translate the collection to a single array-like parameter:
@@ -39,18 +52,5 @@ public enum ParameterizedCollectionMode
/// the default.
///
///
- Parameter,
-
- ///
- /// Instructs EF to translate the collection to a set of parameters:
- /// WHERE [x].[Id] IN (@ids1, @ids2, @ids3).
- ///
- ///
- ///
- /// Note that it's possible to cause EF to translate a specific collection in a specific query to parameter by wrapping the
- /// parameterized collection in : Where(x => EF.MultipleParameters(ids).Contains(x.Id). This overrides
- /// the default.
- ///
- ///
- MultipleParameters,
+ Parameter = 2,
}
diff --git a/src/efcore/src/EFCore/Properties/CoreStrings.Designer.cs b/src/efcore/src/EFCore/Properties/CoreStrings.Designer.cs
index 2de56528926..e38cb0db359 100644
--- a/src/efcore/src/EFCore/Properties/CoreStrings.Designer.cs
+++ b/src/efcore/src/EFCore/Properties/CoreStrings.Designer.cs
@@ -358,14 +358,6 @@ public static string CanOnlyConfigureExistingNavigations(object? navigationName,
GetString("CanOnlyConfigureExistingNavigations", "0_navigationName", "1_entityType"),
navigationName, entityType);
- ///
- /// The entity type '{entityType}' is configured to use the '{changeTrackingStrategy}' change tracking strategy, but does not implement the required '{notificationInterface}' interface. Implement '{notificationInterface}' on '{entityType}' or use a different change tracking strategy.
- ///
- public static string ChangeTrackingInterfaceMissing(object? entityType, object? changeTrackingStrategy, object? notificationInterface)
- => string.Format(
- GetString("ChangeTrackingInterfaceMissing", nameof(entityType), nameof(changeTrackingStrategy), nameof(notificationInterface)),
- entityType, changeTrackingStrategy, notificationInterface);
-
///
/// Unable to save changes because a circular dependency was detected in the data to be saved: '{cycle}'.
///
@@ -1125,10 +1117,12 @@ public static string EFConstantNotSupportedInPrecompiledQueries
=> GetString("EFConstantNotSupportedInPrecompiledQueries");
///
- /// The EF.Constant<T> method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
+ /// The {methodName} method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
///
- public static string EFConstantWithNonEvaluatableArgument
- => GetString("EFConstantWithNonEvaluatableArgument");
+ public static string EFMethodWithNonEvaluatableArgument(object? methodName)
+ => string.Format(
+ GetString("EFMethodWithNonEvaluatableArgument", nameof(methodName)),
+ methodName);
///
/// The EF.Parameter<T> method may only be used within Entity Framework LINQ queries.
@@ -1136,12 +1130,6 @@ public static string EFConstantWithNonEvaluatableArgument
public static string EFParameterInvoked
=> GetString("EFParameterInvoked");
- ///
- /// The EF.Parameter<T> method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
- ///
- public static string EFParameterWithNonEvaluatableArgument
- => GetString("EFParameterWithNonEvaluatableArgument");
-
///
/// Complex type '{complexType}' has no properties defines. Configure at least one property or don't include this type in the model.
///
@@ -1452,6 +1440,14 @@ public static string GraphDoesNotContainVertex(object? vertex)
public static string HiLoBadBlockSize
=> GetString("HiLoBadBlockSize");
+ ///
+ /// The entity type '{entityType}' is configured to use the '{changeTrackingStrategy}' change tracking strategy, but does not implement the required '{notificationInterface}' interface. Implement '{notificationInterface}' on '{entityType}' or use a different change tracking strategy.
+ ///
+ public static string ChangeTrackingInterfaceMissing(object? entityType, object? changeTrackingStrategy, object? notificationInterface)
+ => string.Format(
+ GetString("ChangeTrackingInterfaceMissing", nameof(entityType), nameof(changeTrackingStrategy), nameof(notificationInterface)),
+ entityType, changeTrackingStrategy, notificationInterface);
+
///
/// A relationship cycle involving the primary keys of the following entity types was detected: '{entityType}'. This would prevent any entity to be inserted without violating the store constraints. Review the foreign keys defined on the primary keys and either remove or use other properties for at least one of them.
///
diff --git a/src/efcore/src/EFCore/Properties/CoreStrings.resx b/src/efcore/src/EFCore/Properties/CoreStrings.resx
index 3df16dbe847..ad5fc60c153 100644
--- a/src/efcore/src/EFCore/Properties/CoreStrings.resx
+++ b/src/efcore/src/EFCore/Properties/CoreStrings.resx
@@ -243,9 +243,6 @@
Navigation '{1_entityType}.{0_navigationName}' was not found. Please add the navigation to the entity type before configuring it.
-
- The entity type '{entityType}' is configured to use the '{changeTrackingStrategy}' change tracking strategy, but does not implement the required '{notificationInterface}' interface. Implement '{notificationInterface}' on '{entityType}' or use a different change tracking strategy.
-
Unable to save changes because a circular dependency was detected in the data to be saved: '{cycle}'.
@@ -537,15 +534,12 @@
The EF.Constant<T> method is not supported when using precompiled queries.
-
- The EF.Constant<T> method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
+
+ The {methodName} method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
The EF.Parameter<T> method may only be used within Entity Framework LINQ queries.
-
- The EF.Parameter<T> method may only be used with an argument that can be evaluated client-side and does not contain any reference to database-side entities.
-
Complex type '{complexType}' has no properties defines. Configure at least one property or don't include this type in the model.
@@ -666,6 +660,9 @@
The block size used for Hi-Lo value generation is not positive. The Hi-Lo generator is usually backed by a SQL sequence and this means that the sequence increment must be positive.
+
+ The entity type '{entityType}' is configured to use the '{changeTrackingStrategy}' change tracking strategy, but does not implement the required '{notificationInterface}' interface. Implement '{notificationInterface}' on '{entityType}' or use a different change tracking strategy.
+
A relationship cycle involving the primary keys of the following entity types was detected: '{entityType}'. This would prevent any entity to be inserted without violating the store constraints. Review the foreign keys defined on the primary keys and either remove or use other properties for at least one of them.
diff --git a/src/efcore/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs b/src/efcore/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs
index 44fdec7dbc0..afb319d52c0 100644
--- a/src/efcore/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs
+++ b/src/efcore/src/EFCore/Query/Internal/ExpressionTreeFuncletizer.cs
@@ -939,7 +939,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
if (!argumentState.IsEvaluatable)
{
- throw new InvalidOperationException(CoreStrings.EFConstantWithNonEvaluatableArgument);
+ throw new InvalidOperationException(CoreStrings.EFMethodWithNonEvaluatableArgument("EF.Constant"));
}
// Even EF.Constant will be parameter here.
@@ -952,21 +952,17 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCall)
case nameof(EF.Parameter):
{
- var argument = Visit(methodCall.Arguments[0], out var argumentState);
-
- if (!argumentState.IsEvaluatable)
- {
- throw new InvalidOperationException(CoreStrings.EFParameterWithNonEvaluatableArgument);
- }
-
- argumentState = argumentState with { StateType = StateType.EvaluatableWithCapturedVariable };
- var evaluatedArgument = ProcessEvaluatableRoot(argument, ref argumentState, forceEvaluation: true);
- _state = argumentState;
- return Call(method, evaluatedArgument);
+ return HandleParameter(methodCall, "EF.Parameter");
}
}
}
+ // EF.MultipleParameters is defined in Relational, hence the hardcoded values here.
+ if (method is { Name: "MultipleParameters", DeclaringType.FullName: "Microsoft.EntityFrameworkCore.EFExtensions" })
+ {
+ return HandleParameter(methodCall, "EF.MultipleParameters");
+ }
+
// .NET 10 made changes to overload resolution to prefer Span-based overloads when those exist ("first-class spans").
// Unfortunately, the LINQ interpreter does not support ref structs, so we rewrite e.g. MemoryExtensions.Contains to
// Enumerable.Contains here. See https://github.com/dotnet/runtime/issues/109757,.
@@ -1116,6 +1112,21 @@ static bool TryUnwrapSpanImplicitCast(Expression expression, [NotNullWhen(true)]
}
return methodCall.Update(@object, ((IReadOnlyList?)arguments) ?? methodCall.Arguments);
+
+ Expression HandleParameter(MethodCallExpression methodCall, string methodName)
+ {
+ var argument = Visit(methodCall.Arguments[0], out var argumentState);
+
+ if (!argumentState.IsEvaluatable)
+ {
+ throw new InvalidOperationException(CoreStrings.EFMethodWithNonEvaluatableArgument(methodName));
+ }
+
+ argumentState = argumentState with { StateType = StateType.EvaluatableWithCapturedVariable };
+ var evaluatedArgument = ProcessEvaluatableRoot(argument, ref argumentState, forceEvaluation: true);
+ _state = argumentState;
+ return Call(methodCall.Method, evaluatedArgument);
+ }
}
///
@@ -1977,8 +1988,7 @@ private static StateType CombineStateTypes(StateType stateType1, StateType state
return _parameterizedValues[evaluatableRoot] = new QueryParameterExpression(
parameterName,
evaluatableRoot.Type,
- shouldBeConstantized: false,
- shouldNotBeConstantized: false,
+ translationMode: null,
isNonNullableReferenceType);
}
diff --git a/src/efcore/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs b/src/efcore/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs
index 187b0b7263c..80dbb37f040 100644
--- a/src/efcore/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs
+++ b/src/efcore/src/EFCore/Query/Internal/QueryableMethodNormalizingExpressionVisitor.cs
@@ -127,20 +127,23 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
var queryParameter = (QueryParameterExpression)Visit(methodCallExpression.Arguments[0]);
return new QueryParameterExpression(
- queryParameter.Name, queryParameter.Type, shouldBeConstantized: true, shouldNotBeConstantized: false,
+ queryParameter.Name, queryParameter.Type, translationMode: ParameterTranslationMode.Constant,
queryParameter.IsNonNullableReferenceType);
}
case nameof(EF.Parameter):
{
- var queryParameter = (QueryParameterExpression)Visit(methodCallExpression.Arguments[0]);
- return new QueryParameterExpression(
- queryParameter.Name, queryParameter.Type, shouldBeConstantized: false, shouldNotBeConstantized: true,
- queryParameter.IsNonNullableReferenceType);
+ return HandleParameter(methodCallExpression, ParameterTranslationMode.Parameter);
}
}
}
+ // EF.MultipleParameters is defined in Relational, hence the hardcoded values here.
+ if (method is { Name: "MultipleParameters", DeclaringType.FullName: "Microsoft.EntityFrameworkCore.EFExtensions" })
+ {
+ return HandleParameter(methodCallExpression, ParameterTranslationMode.MultipleParameters);
+ }
+
// Normalize list[x] to list.ElementAt(x)
if (methodCallExpression is
{
@@ -236,6 +239,14 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp
}
return visitedExpression;
+
+ Expression HandleParameter(MethodCallExpression methodCallExpression, ParameterTranslationMode parameterTranslationMode)
+ {
+ var queryParameter = (QueryParameterExpression)Visit(methodCallExpression.Arguments[0]);
+ return new QueryParameterExpression(
+ queryParameter.Name, queryParameter.Type, parameterTranslationMode,
+ queryParameter.IsNonNullableReferenceType);
+ }
}
private static void VerifyReturnType(Expression expression, ParameterExpression lambdaParameter)
diff --git a/src/efcore/src/EFCore/Query/QueryParameterExpression.cs b/src/efcore/src/EFCore/Query/QueryParameterExpression.cs
index 696ff1f3b16..dde4c03c09f 100644
--- a/src/efcore/src/EFCore/Query/QueryParameterExpression.cs
+++ b/src/efcore/src/EFCore/Query/QueryParameterExpression.cs
@@ -14,31 +14,30 @@ namespace Microsoft.EntityFrameworkCore.Query;
public class QueryParameterExpression : Expression, IPrintableExpression
{
///
- /// Creates a new instance of the class with associated query provider.
+ /// Creates a new instance of the class with associated query provider.
///
public QueryParameterExpression(string name, Type type)
- : this(name, type, shouldBeConstantized: false, shouldNotBeConstantized: false, isNonNullableReferenceType: false)
+ : this(name, type, translationMode: null, isNonNullableReferenceType: false)
{
}
///
- /// Creates a new instance of the class with associated query provider.
+ /// Creates a new instance of the class with associated query provider.
///
- public QueryParameterExpression(string name, Type type, bool shouldBeConstantized, bool shouldNotBeConstantized)
- : this(name, type, shouldBeConstantized, shouldNotBeConstantized, isNonNullableReferenceType: false)
+ public QueryParameterExpression(string name, Type type, ParameterTranslationMode translationMode)
+ : this(name, type, translationMode, isNonNullableReferenceType: false)
{
}
///
- /// Creates a new instance of the class with associated query provider.
+ /// Creates a new instance of the class with associated query provider.
///
[Experimental(EFDiagnostics.PrecompiledQueryExperimental)]
- public QueryParameterExpression(string name, Type type, bool shouldBeConstantized, bool shouldNotBeConstantized, bool isNonNullableReferenceType)
+ public QueryParameterExpression(string name, Type type, ParameterTranslationMode? translationMode, bool isNonNullableReferenceType)
{
Name = name;
Type = type;
- ShouldBeConstantized = shouldBeConstantized;
- ShouldNotBeConstantized = shouldNotBeConstantized;
+ TranslationMode = translationMode;
IsNonNullableReferenceType = isNonNullableReferenceType;
}
@@ -61,14 +60,9 @@ public QueryParameterExpression(string name, Type type, bool shouldBeConstantize
public virtual bool IsNonNullableReferenceType { get; }
///
- /// Whether the user has indicated that this query parameter should be inlined as a constant.
+ /// How should the parameter be handled.
///
- public virtual bool ShouldBeConstantized { get; }
-
- ///
- /// Whether the user has indicated that this query parameter shouldn't be inlined as a constant.
- ///
- public virtual bool ShouldNotBeConstantized { get; }
+ public virtual ParameterTranslationMode? TranslationMode { get; }
///
public override ExpressionType NodeType
@@ -92,11 +86,10 @@ public override bool Equals(object? obj)
private bool Equals(QueryParameterExpression queryParameterExpression)
=> Name == queryParameterExpression.Name
&& Type == queryParameterExpression.Type
- && ShouldBeConstantized == queryParameterExpression.ShouldBeConstantized
- && ShouldNotBeConstantized == queryParameterExpression.ShouldNotBeConstantized
+ && TranslationMode == queryParameterExpression.TranslationMode
&& IsNonNullableReferenceType == queryParameterExpression.IsNonNullableReferenceType;
///
public override int GetHashCode()
- => HashCode.Combine(Name, Type, ShouldBeConstantized, ShouldNotBeConstantized, IsNonNullableReferenceType);
+ => HashCode.Combine(Name, Type, TranslationMode, IsNonNullableReferenceType);
}
diff --git a/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs b/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs
index 1cd086ec586..97180c4cf39 100644
--- a/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs
+++ b/src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/NorthwindWhereQueryCosmosTest.cs
@@ -2338,8 +2338,8 @@ public override async Task EF_Constant_does_not_parameterized_as_part_of_bigger_
public override async Task EF_Constant_with_non_evaluatable_argument_throws(bool async)
{
await base.EF_Constant_with_non_evaluatable_argument_throws(async);
- AssertSql(
- );
+
+ AssertSql();
}
public override Task EF_Parameter(bool async)
diff --git a/src/efcore/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs b/src/efcore/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs
index 2496b692e1d..a572b1d9090 100644
--- a/src/efcore/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs
+++ b/src/efcore/test/EFCore.Relational.Specification.Tests/Query/AdHocMiscellaneousQueryRelationalTestBase.cs
@@ -20,6 +20,8 @@ protected void ClearLog()
protected void AssertSql(params string[] expected)
=> TestSqlLoggerFactory.AssertBaseline(expected);
+ protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterTranslationMode parameterizedCollectionMode);
+
#region 2951
[ConditionalFact]
@@ -268,8 +270,6 @@ public class Entity
#region Inlined redacting
- protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode);
-
[ConditionalTheory]
[MemberData(nameof(InlinedRedactingData))]
public virtual async Task Check_inlined_constants_redacting(bool async, bool enableSensitiveDataLogging)
@@ -277,7 +277,7 @@ public virtual async Task Check_inlined_constants_redacting(bool async, bool ena
var contextFactory = await InitializeAsync(
onConfiguring: o =>
{
- SetParameterizedCollectionMode(o, ParameterizedCollectionMode.Constants);
+ SetParameterizedCollectionMode(o, ParameterTranslationMode.Constant);
o.EnableSensitiveDataLogging(enableSensitiveDataLogging);
});
using var context = contextFactory.CreateContext();
@@ -324,7 +324,7 @@ public class TestEntity
public async Task Entity_equality_with_Contains_and_Parameter(bool async)
{
var contextFactory = await InitializeAsync(
- onConfiguring: o => SetParameterizedCollectionMode(o, ParameterizedCollectionMode.Parameter));
+ onConfiguring: o => SetParameterizedCollectionMode(o, ParameterTranslationMode.Parameter));
using var context = contextFactory.CreateContext();
List details = [new Context36311.BlogDetails { Id = 1 }, new Context36311.BlogDetails { Id = 2 }];
diff --git a/src/efcore/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs b/src/efcore/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs
index 2cc15f6fafd..e5132067c77 100644
--- a/src/efcore/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs
+++ b/src/efcore/test/EFCore.Relational.Specification.Tests/Query/NonSharedPrimitiveCollectionsQueryRelationalTestBase.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Linq;
+
namespace Microsoft.EntityFrameworkCore.Query;
#nullable disable
@@ -12,7 +14,7 @@ public abstract class NonSharedPrimitiveCollectionsQueryRelationalTestBase(NonSh
public override Task Array_of_byte()
=> AssertTranslationFailed(() => TestArray((byte)1, (byte)2));
- protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterizedCollectionMode parameterizedCollectionMode);
+ protected abstract DbContextOptionsBuilder SetParameterizedCollectionMode(DbContextOptionsBuilder optionsBuilder, ParameterTranslationMode parameterizedCollectionMode);
[ConditionalFact]
public virtual async Task Column_collection_inside_json_owned_entity()
@@ -36,11 +38,15 @@ public virtual async Task Column_collection_inside_json_owned_entity()
Assert.Equivalent(new[] { "foo", "bar" }, result.Owned.Strings);
}
- [ConditionalFact]
- public virtual async Task Parameter_collection_Count_with_column_predicate_with_default_constants()
+ protected static IEnumerable
-
+
https://github.com/dotnet/arcade
- aea743edf7c9345cfdbdf9593756973baadc6b37
+ 4e526204e83e615efe8eb5743be7fbccfa4e492a
https://github.com/nuget/nuget.client
eb38c4a6cccfce5ee9415da1a930fc6534194b2b
-
+
https://github.com/dotnet/roslyn
- 334d4c7ade78170d7b06448a2807627ddb96d742
+ d3571ef089ef13c74ea786dce8ef615916a097cd
-
+
https://github.com/dotnet/arcade
- aea743edf7c9345cfdbdf9593756973baadc6b37
+ 4e526204e83e615efe8eb5743be7fbccfa4e492a
diff --git a/src/msbuild/eng/Versions.props b/src/msbuild/eng/Versions.props
index 2631a1cb620..0826882f7da 100644
--- a/src/msbuild/eng/Versions.props
+++ b/src/msbuild/eng/Versions.props
@@ -79,10 +79,10 @@
$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\global.json')), '"dotnet": "([^"]*)"').Groups.get_Item(1))
- 4.2.0-1.22102.8
- 10.0.0-beta.25353.1
+ 5.0.0-1.25277.114
+ 10.0.0-beta.25358.3
6.15.0-preview.1.86
- 5.0.0-1.25358.1
+ 5.0.0-1.25361.3
10.0.100-preview.6.25315.102
diff --git a/src/msbuild/global.json b/src/msbuild/global.json
index 1a7cba33e66..c3fb763918e 100644
--- a/src/msbuild/global.json
+++ b/src/msbuild/global.json
@@ -15,6 +15,6 @@
"xcopy-msbuild": "17.13.0"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25353.1"
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25358.3"
}
}
diff --git a/src/msbuild/src/Build.UnitTests/BackEnd/MSBuild_Tests.cs b/src/msbuild/src/Build.UnitTests/BackEnd/MSBuild_Tests.cs
index 1922000b7c7..cefd001921f 100644
--- a/src/msbuild/src/Build.UnitTests/BackEnd/MSBuild_Tests.cs
+++ b/src/msbuild/src/Build.UnitTests/BackEnd/MSBuild_Tests.cs
@@ -1895,5 +1895,107 @@ public void ProjectFileWithoutNamespaceBuilds()
File.Delete(projectFile2);
}
}
+
+ [Fact]
+ public void InMemoryProject_Build()
+ {
+ Project project = ObjectModelHelpers.CreateInMemoryProject("""
+
+
+
+
+
+
+
+
+ """);
+
+ var logger = new MockLogger();
+ bool result = project.Build(logger);
+ _testOutput.WriteLine(logger.FullLog);
+ Assert.True(result);
+ logger.AssertLogContains("test message from other");
+ }
+
+ [Fact]
+ public void InMemoryProject_Error()
+ {
+ Project project = ObjectModelHelpers.CreateInMemoryProject("""
+
+
+
+
+
+
+
+
+ """);
+
+ var logger = new MockLogger();
+ bool result = project.Build(logger);
+ _testOutput.WriteLine(logger.FullLog);
+ Assert.False(result);
+ logger.AssertLogDoesntContain("test message from other");
+ logger.AssertLogContains("MSB3202"); // error MSB3202: The project file was not found.
+ }
+
+ ///
+ /// This is used by file-based apps (dotnet run file.cs) which use in-memory projects
+ /// and want to support existing targets which often invoke the MSBuild task on the current project.
+ ///
+ [Fact]
+ public void InMemoryProject_BuildByDefault()
+ {
+ Project project = ObjectModelHelpers.CreateInMemoryProject("""
+
+
+
+
+
+
+
+
+ """);
+
+ project.SetGlobalProperty(PropertyNames.BuildNonexistentProjectsByDefault, bool.TrueString);
+
+ var logger = new MockLogger();
+ bool result = project.Build(logger);
+ _testOutput.WriteLine(logger.FullLog);
+ Assert.True(result);
+ logger.AssertLogContains("test message from other");
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void NonExistentProject(bool? buildNonexistentProjectsByDefault)
+ {
+ Project project = ObjectModelHelpers.CreateInMemoryProject("""
+
+
+
+
+
+
+
+
+ """);
+
+ if (buildNonexistentProjectsByDefault is { } b)
+ {
+ project.SetGlobalProperty(PropertyNames.BuildNonexistentProjectsByDefault, b.ToString());
+ }
+
+ var logger = new MockLogger();
+ bool result = project.Build(logger);
+ _testOutput.WriteLine(logger.FullLog);
+ Assert.False(result);
+ logger.AssertLogDoesntContain("test message from other");
+ logger.AssertLogContains(buildNonexistentProjectsByDefault == true
+ ? "MSB4025" // error MSB4025: The project file could not be loaded.
+ : "MSB3202"); // error MSB3202: The project file was not found.
+ }
}
}
diff --git a/src/msbuild/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs b/src/msbuild/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs
index d3c1c9820db..46ec826e287 100644
--- a/src/msbuild/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs
+++ b/src/msbuild/src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs
@@ -161,29 +161,22 @@ protected void ShutdownAllNodes(bool nodeReuse, NodeContextTerminateDelegate ter
int timeout = 30;
// Attempt to connect to the process with the handshake without low priority.
- using Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false));
- if (nodeStream != null)
- {
- ShutdownNode(terminateNode, factory, nodeProcess, nodeStream);
- }
- else
+ Stream nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, false));
+
+ if (nodeStream == null)
{
// If we couldn't connect attempt to connect to the process with the handshake including low priority.
- using Stream lowPriorityConnection = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true));
-
- if (lowPriorityConnection != null)
- {
- ShutdownNode(terminateNode, factory, nodeProcess, lowPriorityConnection);
- }
+ nodeStream = TryConnectToProcess(nodeProcess.Id, timeout, NodeProviderOutOfProc.GetHandshake(nodeReuse, true));
}
- }
- static void ShutdownNode(NodeContextTerminateDelegate terminateNode, INodePacketFactory factory, Process nodeProcess, Stream nodeStream)
- {
- // If we're able to connect to such a process, send a packet requesting its termination
- CommunicationsUtilities.Trace("Shutting down node with pid = {0}", nodeProcess.Id);
- NodeContext nodeContext = new NodeContext(0, nodeProcess, nodeStream, factory, terminateNode);
- nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */));
+ if (nodeStream != null)
+ {
+ // If we're able to connect to such a process, send a packet requesting its termination
+ CommunicationsUtilities.Trace("Shutting down node with pid = {0}", nodeProcess.Id);
+ NodeContext nodeContext = new NodeContext(0, nodeProcess, nodeStream, factory, terminateNode);
+ nodeContext.SendData(new NodeBuildComplete(false /* no node reuse */));
+ nodeStream.Dispose();
+ }
}
}
@@ -607,14 +600,19 @@ private enum ExitPacketState
private readonly NodeContextTerminateDelegate _terminateDelegate;
///
- /// A task representing the work to consume enqueued packets.
+ /// A dedicated thread to consume enqueued packets.
+ ///
+ private readonly Thread _drainPacketQueueThread;
+
+ ///
+ /// Used to signal the consuming thread that a packet has been enqueued;
///
- private readonly Task _packetWriteDrainTask;
+ private readonly AutoResetEvent _packetEnqueued;
///
- /// Used to signal the consuming task that a packet has been enqueued.
+ /// Used to signal that the exit packet has been sent and we no longer need to wait for the queue to drain.
///
- private readonly SemaphoreSlim _packetEnqueued;
+ private readonly CancellationTokenSource _packetQueueDrainDelayCancellation;
///
/// Tracks the state of the packet sent to terminate the node.
@@ -650,9 +648,13 @@ public NodeContext(int nodeId, Process process,
#endif
_packetWriteQueue = new ConcurrentQueue();
- _packetEnqueued = new SemaphoreSlim(0, 1);
+ _packetEnqueued = new AutoResetEvent(false);
+ _packetQueueDrainDelayCancellation = new CancellationTokenSource();
- _packetWriteDrainTask = DrainPacketQueue();
+ // specify the smallest stack size - 64kb
+ _drainPacketQueueThread = new Thread(DrainPacketQueue, 64 * 1024);
+ _drainPacketQueueThread.IsBackground = true;
+ _drainPacketQueueThread.Start(this);
}
///
@@ -758,35 +760,30 @@ public void SendData(INodePacket packet)
{
_exitPacketState = ExitPacketState.ExitPacketQueued;
}
-
_packetWriteQueue.Enqueue(packet);
-
- if (_packetEnqueued.CurrentCount == 0)
- {
- // If the semaphore is not already signaled, signal it to wake up the draining task.
- _packetEnqueued.Release();
- }
+ _packetEnqueued.Set();
}
///
- /// Use a threadpool thread to drain the queue and be careful not to block it where possible.
+ /// We use a dedicated thread to avoid blocking a threadpool thread.
///
/// Usually there'll be a single packet in the queue, but sometimes
/// a burst of SendData comes in, with 10-20 packets scheduled.
- private async Task DrainPacketQueue()
+ private void DrainPacketQueue(object state)
{
- MemoryStream writeStream = _writeBufferMemoryStream;
- Stream serverToClientStream = _pipeStream;
- ITranslator writeTranslator = _writeTranslator;
+ NodeContext context = (NodeContext)state;
+ MemoryStream writeStream = context._writeBufferMemoryStream;
+ Stream serverToClientStream = context._pipeStream;
while (true)
{
- await _packetEnqueued.WaitAsync();
- while (_packetWriteQueue.TryDequeue(out INodePacket packet))
+ context._packetEnqueued.WaitOne();
+ while (context._packetWriteQueue.TryDequeue(out INodePacket packet))
{
// clear the buffer but keep the underlying capacity to avoid reallocations
writeStream.SetLength(0);
+ ITranslator writeTranslator = context._writeTranslator;
try
{
writeStream.WriteByte((byte)packet.Type);
@@ -806,29 +803,22 @@ private async Task DrainPacketQueue()
for (int i = 0; i < writeStreamLength; i += MaxPacketWriteSize)
{
int lengthToWrite = Math.Min(writeStreamLength - i, MaxPacketWriteSize);
-#if NET
- await serverToClientStream.WriteAsync(writeStreamBuffer.AsMemory(i, lengthToWrite));
-#else
- await serverToClientStream.WriteAsync(writeStreamBuffer, i, lengthToWrite);
-#endif
+
+ serverToClientStream.Write(writeStreamBuffer, i, lengthToWrite);
}
if (IsExitPacket(packet))
{
- _exitPacketState = ExitPacketState.ExitPacketSent;
+ context._exitPacketState = ExitPacketState.ExitPacketSent;
+ context._packetQueueDrainDelayCancellation.Cancel();
return;
}
-
- if (packet is NodeBuildComplete)
- {
- return;
- }
}
catch (IOException e)
{
// Do nothing here because any exception will be caught by the async read handler
- CommunicationsUtilities.Trace(_nodeId, "EXCEPTION in SendData: {0}", e);
+ CommunicationsUtilities.Trace(context._nodeId, "EXCEPTION in SendData: {0}", e);
}
catch (ObjectDisposedException) // This happens if a child dies unexpectedly
{
@@ -860,7 +850,6 @@ private static void WriteInt32(MemoryStream stream, int value)
private void Close()
{
_pipeStream.Dispose();
- _packetEnqueued.Dispose();
_terminateDelegate(_nodeId);
}
@@ -874,16 +863,14 @@ public async Task WaitForExitAsync(ILoggingService loggingService)
// Wait up to 100ms until all remaining packets are sent.
// We don't need to wait long, just long enough for the Task to start running on the ThreadPool.
#if NET
- await _packetWriteDrainTask.WaitAsync(TimeSpan.FromMilliseconds(100)).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
+ await Task.Delay(100, _packetQueueDrainDelayCancellation.Token).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
#else
- using (var cts = new CancellationTokenSource(100))
- {
- await Task.WhenAny(_packetWriteDrainTask, Task.Delay(100, cts.Token));
- cts.Cancel();
- }
+ await Task.WhenAny(Task.Delay(100, _packetQueueDrainDelayCancellation.Token));
#endif
}
+ _packetQueueDrainDelayCancellation?.Dispose();
+
if (_exitPacketState == ExitPacketState.ExitPacketSent)
{
CommunicationsUtilities.Trace("Waiting for node with pid = {0} to exit", _process.Id);
diff --git a/src/msbuild/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/MSBuild.cs b/src/msbuild/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/MSBuild.cs
index ac3e5aab535..8142e3266d4 100644
--- a/src/msbuild/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/MSBuild.cs
+++ b/src/msbuild/src/Build/BackEnd/Components/RequestBuilder/IntrinsicTasks/MSBuild.cs
@@ -330,6 +330,12 @@ public async Task ExecuteInternal()
{
skipNonExistProjects = behavior;
}
+ else if (BuildEngine is IBuildEngine6 buildEngine6 && buildEngine6.GetGlobalProperties()
+ .TryGetValue(PropertyNames.BuildNonexistentProjectsByDefault, out var buildNonexistentProjectsByDefault) &&
+ ConversionUtilities.ConvertStringToBool(buildNonexistentProjectsByDefault))
+ {
+ skipNonExistProjects = SkipNonExistentProjectsBehavior.Build;
+ }
else
{
skipNonExistProjects = SkipNonExistentProjectsBehavior.Error;
diff --git a/src/msbuild/src/Build/BackEnd/Components/Scheduler/Scheduler.cs b/src/msbuild/src/Build/BackEnd/Components/Scheduler/Scheduler.cs
index a8cc5967168..0598341fa5b 100644
--- a/src/msbuild/src/Build/BackEnd/Components/Scheduler/Scheduler.cs
+++ b/src/msbuild/src/Build/BackEnd/Components/Scheduler/Scheduler.cs
@@ -185,6 +185,13 @@ internal bool ForceAffinityOutOfProc
///
private string _noLoggingCompletedSubmissionDetails;
+ ///
+ /// Static variable to track whether this is the first write to the debug dump file.
+ /// If true, indicates that a header should be written to the file.
+ /// After the first write, this is set to false to prevent writing the header in subsequent writes.
+ ///
+ private static bool _debugDumpIsFirstWrite = true;
+
#pragma warning restore IDE0052 // Remove unread private members
#pragma warning restore CS0414 // The field is assigned but its value is never used
@@ -1713,7 +1720,7 @@ private void HandleRequestBlockedByNewRequests(SchedulableRequest parentRequest,
}
int nodeForResults = (parentRequest == null) ? InvalidNodeId : parentRequest.AssignedNode;
- TraceScheduler("Received request {0} (node request {1}) with parent {2} from node {3}", request.GlobalRequestId, request.NodeRequestId, request.ParentGlobalRequestId, nodeForResults);
+ TraceScheduler("Received request {0} (node request {1}) with parent {2} from node {3} for project {4} with targets {5}", request.GlobalRequestId, request.NodeRequestId, request.ParentGlobalRequestId, nodeForResults, _configCache![request.ConfigurationId].ProjectFullPath, request.Targets.Count == 0 ? "default" : string.Join(";", request.Targets));
// First, determine if we have already built this request and have results for it. If we do, we prepare the responses for it
// directly here. We COULD simply report these as blocking the parent request and let the scheduler pick them up later when the parent
@@ -2625,8 +2632,25 @@ private void DumpSchedulerState()
try
{
FileUtilities.EnsureDirectoryExists(_debugDumpPath);
+
+ bool shouldWriteHeader = _debugDumpIsFirstWrite;
+ if (shouldWriteHeader)
+ {
+ shouldWriteHeader = !File.Exists(string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, "SchedulerState_{0}.txt"), EnvironmentUtilities.CurrentProcessId));
+ _debugDumpIsFirstWrite = false;
+ }
using StreamWriter file = FileUtilities.OpenWrite(string.Format(CultureInfo.CurrentCulture, Path.Combine(_debugDumpPath, "SchedulerState_{0}.txt"), EnvironmentUtilities.CurrentProcessId), append: true);
+
+ if (shouldWriteHeader)
+ {
+ file.WriteLine("SchedulerState Log Symbols:");
+ file.WriteLine("! - Blocked request: A build request waiting for dependencies or resources.");
+ file.WriteLine("> - Executing request: A build request currently being processed by a node.");
+ file.WriteLine("------------------------------------------------");
+ file.WriteLine();
+ }
+
file.WriteLine("Scheduler state at timestamp {0}:", _schedulingData.EventTime.Ticks);
file.WriteLine("------------------------------------------------");
diff --git a/src/msbuild/src/Build/Logging/TerminalLogger/Terminal.cs b/src/msbuild/src/Build/Logging/TerminalLogger/Terminal.cs
index 01a3065cd93..fd9133a2fa9 100644
--- a/src/msbuild/src/Build/Logging/TerminalLogger/Terminal.cs
+++ b/src/msbuild/src/Build/Logging/TerminalLogger/Terminal.cs
@@ -36,7 +36,15 @@ internal sealed class Terminal : ITerminal
private const int BigUnknownDimension = 2 << 23;
- ///
+ ///
+ /// Gets the height of the of the underlying .
+ /// If the , returns a large number to indicate that the height is unknown.
+ /// If the is zero, returns a large number to indicate that the height is unknown/synthetic.
+ ///
+ ///
+ /// We also try to prevent TerminalLogger from being used in scenarios where the console buffer is not set up correctly, such as in some CI environments,
+ /// but a user can always force the use of TerminalLogger so we must be defensive in the implementation.
+ ///
public int Height
{
get
@@ -46,11 +54,19 @@ public int Height
return BigUnknownDimension;
}
- return Console.BufferHeight;
+ return Console.BufferHeight == 0 ? BigUnknownDimension : Console.BufferHeight;
}
}
- ///
+ ///
+ /// Gets the width of the of the underlying .
+ /// If the , returns a large number to indicate that the width is unknown.
+ /// If the is zero, returns a large number to indicate that the width is unknown/synthetic.
+ ///
+ ///
+ /// We also try to prevent TerminalLogger from being used in scenarios where the console buffer is not set up correctly, such as in some CI environments,
+ /// but a user can always force the use of TerminalLogger so we must be defensive in the implementation.
+ ///
public int Width
{
get
@@ -60,7 +76,7 @@ public int Width
return BigUnknownDimension;
}
- return Console.BufferWidth;
+ return Console.BufferWidth == 0 ? BigUnknownDimension : Console.BufferWidth;
}
}
@@ -209,7 +225,7 @@ public void Dispose()
{
// In some terminal emulators setting back the previous console output encoding fails.
// See https://github.com/dotnet/msbuild/issues/9662.
- // We do not want to throw an exception if it happens, since it is a non-essentual failure in the logger.
+ // We do not want to throw an exception if it happens, since it is a non-essential failure in the logger.
}
}
}
diff --git a/src/msbuild/src/Build/Logging/TerminalLogger/TerminalLogger.cs b/src/msbuild/src/Build/Logging/TerminalLogger/TerminalLogger.cs
index deb07b5405c..4bfb2299932 100644
--- a/src/msbuild/src/Build/Logging/TerminalLogger/TerminalLogger.cs
+++ b/src/msbuild/src/Build/Logging/TerminalLogger/TerminalLogger.cs
@@ -885,12 +885,15 @@ private void MessageRaised(object sender, BuildMessageEventArgs e)
{
if (e.Code == "NETSDK1057" && !_loggedPreviewMessage)
{
- // The SDK will log the high-pri "not-a-warning" message NETSDK1057
- // when it's a preview version up to MaxCPUCount times, but that's
- // an implementation detail--the user cares about at most one.
-
- RenderImmediateMessage(message);
- _loggedPreviewMessage = true;
+ // ensure we only log the preview message once for the entire build.
+ if (!_loggedPreviewMessage)
+ {
+ // The SDK will log the high-pri "not-a-warning" message NETSDK1057
+ // when it's a preview version up to MaxCPUCount times, but that's
+ // an implementation detail--the user cares about at most one.
+ RenderImmediateMessage(FormatSimpleMessageWithoutFileData(e, DoubleIndentation));
+ _loggedPreviewMessage = true;
+ }
return;
}
}
@@ -1223,6 +1226,29 @@ private string FormatWarningMessage(BuildWarningEventArgs e, string indent)
indent);
}
+ ///
+ /// Renders message with just code/category/message data.
+ /// No file data is included. This can be used for immediate/one-time
+ /// messages that lack a specific project context, such as the .NET
+ /// SDK's 'preview version' message, while not removing the code.
+ ///
+ private string FormatSimpleMessageWithoutFileData(BuildMessageEventArgs e, string indent)
+ {
+ return FormatEventMessage(
+ category: AnsiCodes.Colorize("info", TerminalColor.Default),
+ subcategory: null,
+ message: e.Message,
+ code: AnsiCodes.Colorize(e.Code, TerminalColor.Default),
+ file: null,
+ lineNumber: 0,
+ endLineNumber: 0,
+ columnNumber: 0,
+ endColumnNumber: 0,
+ indent,
+ requireFileAndLinePortion: false,
+ prependIndentation: true);
+ }
+
private string FormatErrorMessage(BuildErrorEventArgs e, string indent)
{
return FormatEventMessage(
@@ -1240,7 +1266,7 @@ private string FormatErrorMessage(BuildErrorEventArgs e, string indent)
private string FormatEventMessage(
string category,
- string subcategory,
+ string? subcategory,
string? message,
string code,
string? file,
@@ -1248,44 +1274,53 @@ private string FormatEventMessage(
int endLineNumber,
int columnNumber,
int endColumnNumber,
- string indent)
+ string indent,
+ bool requireFileAndLinePortion = true,
+ bool prependIndentation = false)
{
message ??= string.Empty;
StringBuilder builder = new(128);
-
- if (string.IsNullOrEmpty(file))
+ if (prependIndentation)
{
- builder.Append("MSBUILD : "); // Should not be localized.
+ builder.Append(indent);
}
- else
- {
- builder.Append(file);
- if (lineNumber == 0)
+ if (requireFileAndLinePortion)
+ {
+ if (string.IsNullOrEmpty(file))
{
- builder.Append(" : ");
+ builder.Append("MSBUILD : "); // Should not be localized.
}
else
{
- if (columnNumber == 0)
+ builder.Append(file);
+
+ if (lineNumber == 0)
{
- builder.Append(endLineNumber == 0 ?
- $"({lineNumber}): " :
- $"({lineNumber}-{endLineNumber}): ");
+ builder.Append(" : ");
}
else
{
- if (endLineNumber == 0)
+ if (columnNumber == 0)
{
- builder.Append(endColumnNumber == 0 ?
- $"({lineNumber},{columnNumber}): " :
- $"({lineNumber},{columnNumber}-{endColumnNumber}): ");
+ builder.Append(endLineNumber == 0 ?
+ $"({lineNumber}): " :
+ $"({lineNumber}-{endLineNumber}): ");
}
else
{
- builder.Append(endColumnNumber == 0 ?
- $"({lineNumber}-{endLineNumber},{columnNumber}): " :
- $"({lineNumber},{columnNumber},{endLineNumber},{endColumnNumber}): ");
+ if (endLineNumber == 0)
+ {
+ builder.Append(endColumnNumber == 0 ?
+ $"({lineNumber},{columnNumber}): " :
+ $"({lineNumber},{columnNumber}-{endColumnNumber}): ");
+ }
+ else
+ {
+ builder.Append(endColumnNumber == 0 ?
+ $"({lineNumber}-{endLineNumber},{columnNumber}): " :
+ $"({lineNumber},{columnNumber},{endLineNumber},{endColumnNumber}): ");
+ }
}
}
}
diff --git a/src/msbuild/src/Build/Microsoft.Build.csproj b/src/msbuild/src/Build/Microsoft.Build.csproj
index 7adeacbb321..0c9cd1c3da9 100644
--- a/src/msbuild/src/Build/Microsoft.Build.csproj
+++ b/src/msbuild/src/Build/Microsoft.Build.csproj
@@ -38,6 +38,8 @@
+
+
@@ -80,6 +82,9 @@
BackEnd\Components\RequestBuilder\IntrinsicTasks\CanonicalError.cs
+
+ IConstrainedEqualityComparer.cs
+
BackEnd\Components\RequestBuilder\IntrinsicTasks\PropertyParser.cs
@@ -121,9 +126,6 @@
BackEnd\Components\RequestBuilder\IntrinsicTasks\TaskLoggingHelperExtension.cs
-
- BuildCheck\Utilities\IsExternalInit.cs
-
@@ -378,6 +380,7 @@
Collections\CopyOnWriteDictionary.cs
+
diff --git a/src/msbuild/src/Framework/AssemblyUtilities.cs b/src/msbuild/src/Framework/AssemblyUtilities.cs
index 5eb6e996a6e..6b21b7d22eb 100644
--- a/src/msbuild/src/Framework/AssemblyUtilities.cs
+++ b/src/msbuild/src/Framework/AssemblyUtilities.cs
@@ -10,15 +10,8 @@
using Microsoft.Build.Framework;
#endif
-
-// Declare this to get init properties. See https://github.com/dotnet/roslyn/issues/45510#issuecomment-694977239
#nullable disable
-namespace System.Runtime.CompilerServices
-{
- internal static class IsExternalInit { }
-}
-
namespace Microsoft.Build.Shared
{
///
diff --git a/src/msbuild/src/Framework/Microsoft.Build.Framework.csproj b/src/msbuild/src/Framework/Microsoft.Build.Framework.csproj
index da61a612686..296bff029bd 100644
--- a/src/msbuild/src/Framework/Microsoft.Build.Framework.csproj
+++ b/src/msbuild/src/Framework/Microsoft.Build.Framework.csproj
@@ -15,7 +15,7 @@
-
+
@@ -29,8 +29,9 @@
-
+
+
diff --git a/src/msbuild/src/Framework/NativeMethods.cs b/src/msbuild/src/Framework/NativeMethods.cs
index 352723a6e53..3dece87f8a4 100644
--- a/src/msbuild/src/Framework/NativeMethods.cs
+++ b/src/msbuild/src/Framework/NativeMethods.cs
@@ -1593,6 +1593,13 @@ internal static (bool acceptAnsiColorCodes, bool outputIsScreen, uint? originalC
return (acceptAnsiColorCodes: false, outputIsScreen: false, originalConsoleMode: null);
}
+ if (Console.BufferHeight == 0 || Console.BufferWidth == 0)
+ {
+ // The current console doesn't have a valid buffer size, which means it is not a real console. let's default to not using TL
+ // in those scenarios.
+ return (acceptAnsiColorCodes: false, outputIsScreen: false, originalConsoleMode: null);
+ }
+
bool acceptAnsiColorCodes = false;
bool outputIsScreen = false;
uint? originalConsoleMode = null;
diff --git a/src/msbuild/src/MSBuild/MSBuild.csproj b/src/msbuild/src/MSBuild/MSBuild.csproj
index 8df57c447ab..686e78276ab 100644
--- a/src/msbuild/src/MSBuild/MSBuild.csproj
+++ b/src/msbuild/src/MSBuild/MSBuild.csproj
@@ -76,6 +76,9 @@
FileUtilitiesRegex.cs
+
+ IConstrainedEqualityComparer.cs
+
RegisteredTaskObjectCacheBase.cs
@@ -88,6 +91,7 @@
+
diff --git a/src/msbuild/src/MSBuild/XMake.cs b/src/msbuild/src/MSBuild/XMake.cs
index a2f925408b6..2239b55d156 100644
--- a/src/msbuild/src/MSBuild/XMake.cs
+++ b/src/msbuild/src/MSBuild/XMake.cs
@@ -2789,7 +2789,9 @@ private static bool ProcessCommandLineSwitches(
verbosity = LoggerVerbosity.Diagnostic;
}
- if (originalVerbosity == LoggerVerbosity.Diagnostic)
+ // we don't want to write the MSBuild command line to the display because TL by intent is a
+ // highly-controlled visual experience and we don't want to clutter it with the command line switches.
+ if (originalVerbosity == LoggerVerbosity.Diagnostic && !useTerminalLogger)
{
string equivalentCommandLine = commandLineSwitches.GetEquivalentCommandLineExceptProjectFile();
Console.WriteLine($"{Path.Combine(s_exePath, s_exeName)} {equivalentCommandLine} {projectFile}");
diff --git a/src/msbuild/src/MSBuildTaskHost/MSBuildTaskHost.csproj b/src/msbuild/src/MSBuildTaskHost/MSBuildTaskHost.csproj
index 5f812c4b7a6..83345b0c8ae 100644
--- a/src/msbuild/src/MSBuildTaskHost/MSBuildTaskHost.csproj
+++ b/src/msbuild/src/MSBuildTaskHost/MSBuildTaskHost.csproj
@@ -70,6 +70,7 @@
CopyOnWriteDictionary.cs
+
@@ -202,6 +203,7 @@
+
@@ -220,8 +222,6 @@
-
-
diff --git a/src/msbuild/src/Framework/Polyfills/NullableAttributes.cs b/src/msbuild/src/MSBuildTaskHost/NullableAttributes.cs
similarity index 97%
rename from src/msbuild/src/Framework/Polyfills/NullableAttributes.cs
rename to src/msbuild/src/MSBuildTaskHost/NullableAttributes.cs
index b6698fce618..2c086ba5622 100644
--- a/src/msbuild/src/Framework/Polyfills/NullableAttributes.cs
+++ b/src/msbuild/src/MSBuildTaskHost/NullableAttributes.cs
@@ -3,6 +3,8 @@
// This was copied from https://github.com/dotnet/runtime/blob/39b9607807f29e48cae4652cd74735182b31182e/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs
// and updated to have the scope of the attributes be internal.
+// This file is used only by MSBuildTaskHost; other projects should get the polyfills from the
+// Microsoft.CodeAnalysis.Contracts package, through the Microsoft.Build.Framework project.
#nullable disable
diff --git a/src/msbuild/src/Shared/Constants.cs b/src/msbuild/src/Shared/Constants.cs
index 3418ad8b214..dcbe23d78bf 100644
--- a/src/msbuild/src/Shared/Constants.cs
+++ b/src/msbuild/src/Shared/Constants.cs
@@ -154,6 +154,11 @@ internal static class PropertyNames
internal const string TargetFrameworks = nameof(TargetFrameworks);
internal const string TargetFramework = nameof(TargetFramework);
internal const string UsingMicrosoftNETSdk = nameof(UsingMicrosoftNETSdk);
+
+ ///
+ /// When true, `SkipNonexistentProjects=Build` becomes the default setting of MSBuild tasks.
+ ///
+ internal const string BuildNonexistentProjectsByDefault = "_" + nameof(BuildNonexistentProjectsByDefault);
}
// TODO: Remove these when VS gets updated to setup project cache plugins.
diff --git a/src/msbuild/src/Framework/IConstrainedEqualityComparer.cs b/src/msbuild/src/Shared/IConstrainedEqualityComparer.cs
similarity index 89%
rename from src/msbuild/src/Framework/IConstrainedEqualityComparer.cs
rename to src/msbuild/src/Shared/IConstrainedEqualityComparer.cs
index 04ad75b4082..c66dc8925f1 100644
--- a/src/msbuild/src/Framework/IConstrainedEqualityComparer.cs
+++ b/src/msbuild/src/Shared/IConstrainedEqualityComparer.cs
@@ -11,11 +11,7 @@ namespace Microsoft.Build.Collections
/// Defines methods to support the comparison of objects for
/// equality over constrained inputs.
///
-#if TASKHOST
- internal interface IConstrainedEqualityComparer : IEqualityComparer
-#else
internal interface IConstrainedEqualityComparer : IEqualityComparer
-#endif
{
///
/// Determines whether the specified objects are equal, factoring in the specified bounds when comparing .
diff --git a/src/msbuild/src/Shared/IsExternalInit.cs b/src/msbuild/src/Shared/IsExternalInit.cs
index ae2ffb321cd..f0a0588d1df 100644
--- a/src/msbuild/src/Shared/IsExternalInit.cs
+++ b/src/msbuild/src/Shared/IsExternalInit.cs
@@ -1,9 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+#if NET
+using System.Runtime.CompilerServices;
+
+// Type-forward to the inbox class where available, in order to maintain binary compatibility
+// between the .NET and .NET Standard 2.0 assemblies.
+[assembly: TypeForwardedTo(typeof(IsExternalInit))]
+
+#else
+
+using System.ComponentModel;
+
namespace System.Runtime.CompilerServices
{
// Needed so we can use init setters in full fw or netstandard
// (details: https://developercommunity.visualstudio.com/t/error-cs0518-predefined-type-systemruntimecompiler/1244809)
+ [EditorBrowsable(EditorBrowsableState.Never)]
internal static class IsExternalInit { }
}
+#endif
diff --git a/src/msbuild/src/Framework/MSBuildNameIgnoreCaseComparer.cs b/src/msbuild/src/Shared/MSBuildNameIgnoreCaseComparer.cs
similarity index 92%
rename from src/msbuild/src/Framework/MSBuildNameIgnoreCaseComparer.cs
rename to src/msbuild/src/Shared/MSBuildNameIgnoreCaseComparer.cs
index 3a829bec6d2..e8e9a65b9eb 100644
--- a/src/msbuild/src/Framework/MSBuildNameIgnoreCaseComparer.cs
+++ b/src/msbuild/src/Shared/MSBuildNameIgnoreCaseComparer.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
-using Microsoft.Build.Framework;
+using Microsoft.Build.Shared;
#nullable disable
@@ -22,7 +22,7 @@ internal class MSBuildNameIgnoreCaseComparer : IConstrainedEqualityComparer
/// The processor architecture on which we are running, but default it will be x86
///
- private static readonly NativeMethods.ProcessorArchitectures s_runningProcessorArchitecture = NativeMethods.ProcessorArchitecture;
+ private static readonly NativeMethodsShared.ProcessorArchitectures s_runningProcessorArchitecture = NativeMethodsShared.ProcessorArchitecture;
///
/// The default immutable comparer instance.
@@ -46,12 +46,12 @@ public bool Equals(string compareToString, string constrainedString, int start,
{
if (lengthToCompare < 0)
{
- EscapeHatches.ThrowInternalError("Invalid lengthToCompare '{0}' {1} {2}", constrainedString, start, lengthToCompare);
+ ErrorUtilities.ThrowInternalError("Invalid lengthToCompare '{0}' {1} {2}", constrainedString, start, lengthToCompare);
}
if (start < 0 || start > (constrainedString?.Length ?? 0) - lengthToCompare)
{
- EscapeHatches.ThrowInternalError("Invalid start '{0}' {1} {2}", constrainedString, start, lengthToCompare);
+ ErrorUtilities.ThrowInternalError("Invalid start '{0}' {1} {2}", constrainedString, start, lengthToCompare);
}
if (ReferenceEquals(compareToString, constrainedString))
@@ -72,8 +72,8 @@ public bool Equals(string compareToString, string constrainedString, int start,
return false;
}
- if ((s_runningProcessorArchitecture != NativeMethods.ProcessorArchitectures.IA64)
- && (s_runningProcessorArchitecture != NativeMethods.ProcessorArchitectures.ARM))
+ if ((s_runningProcessorArchitecture != NativeMethodsShared.ProcessorArchitectures.IA64)
+ && (s_runningProcessorArchitecture != NativeMethodsShared.ProcessorArchitectures.ARM))
{
// The use of unsafe here is quite a bit faster than the regular
// mechanism in the BCL. This is because we can make assumptions
@@ -120,8 +120,8 @@ public int GetHashCode(string obj, int start, int length)
return 0; // per BCL convention
}
- if ((s_runningProcessorArchitecture != NativeMethods.ProcessorArchitectures.IA64)
- && (s_runningProcessorArchitecture != NativeMethods.ProcessorArchitectures.ARM))
+ if ((s_runningProcessorArchitecture != NativeMethodsShared.ProcessorArchitectures.IA64)
+ && (s_runningProcessorArchitecture != NativeMethodsShared.ProcessorArchitectures.ARM))
{
unsafe
{
diff --git a/src/msbuild/src/Shared/TaskParameter.cs b/src/msbuild/src/Shared/TaskParameter.cs
index 12bac552ded..2e397ebab7b 100644
--- a/src/msbuild/src/Shared/TaskParameter.cs
+++ b/src/msbuild/src/Shared/TaskParameter.cs
@@ -5,10 +5,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using System.Reflection;
-using Microsoft.Build.Collections;
-
#if FEATURE_APPDOMAIN
using System.Security;
#endif
@@ -137,7 +134,7 @@ public TaskParameter(object wrappedParameter)
{
if (inputAsITaskItemArray[i] != null)
{
- taskItemArrayParameter[i] = new TaskParameterTaskItem(inputAsITaskItemArray[i]);
+ taskItemArrayParameter[i] = CreateNewTaskItemFrom(inputAsITaskItemArray[i]);
}
}
@@ -176,7 +173,7 @@ public TaskParameter(object wrappedParameter)
else if (typeof(ITaskItem).IsAssignableFrom(wrappedParameterType))
{
_parameterType = TaskParameterType.ITaskItem;
- _wrappedParameter = new TaskParameterTaskItem((ITaskItem)wrappedParameter);
+ _wrappedParameter = CreateNewTaskItemFrom((ITaskItem)wrappedParameter);
}
else if (wrappedParameterType.GetTypeInfo().IsValueType)
{
@@ -279,29 +276,97 @@ public override object InitializeLifetimeService()
///
internal static TaskParameter FactoryForDeserialization(ITranslator translator)
{
- TaskParameter taskParameter = new();
+ TaskParameter taskParameter = new TaskParameter();
taskParameter.Translate(translator);
return taskParameter;
}
+ ///
+ /// Creates a new ITaskItem with the contents of the old one.
+ ///
+ private ITaskItem CreateNewTaskItemFrom(ITaskItem copyFrom)
+ {
+ ITaskItem2 copyFromAsITaskItem2 = copyFrom as ITaskItem2;
+ string escapedItemSpec;
+ string escapedDefiningProject;
+ Dictionary escapedMetadata;
+ if (copyFromAsITaskItem2 != null)
+ {
+ escapedItemSpec = copyFromAsITaskItem2.EvaluatedIncludeEscaped;
+ escapedDefiningProject = copyFromAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath);
+ IDictionary nonGenericEscapedMetadata = copyFromAsITaskItem2.CloneCustomMetadataEscaped();
+
+ escapedMetadata = nonGenericEscapedMetadata as Dictionary;
+ if (escapedMetadata is null)
+ {
+ escapedMetadata = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (object key in nonGenericEscapedMetadata.Keys)
+ {
+ escapedMetadata[(string)key] = (string)nonGenericEscapedMetadata[key] ?? String.Empty;
+ }
+ }
+ }
+ else
+ {
+ // If we don't have ITaskItem2 to fall back on, we have to make do with the fact that
+ // CloneCustomMetadata, GetMetadata, & ItemSpec returns unescaped values, and
+ // TaskParameterTaskItem's constructor expects escaped values, so escaping them all
+ // is the closest approximation to correct we can get.
+ escapedItemSpec = EscapingUtilities.Escape(copyFrom.ItemSpec);
+
+ escapedDefiningProject = EscapingUtilities.EscapeWithCaching(copyFrom.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath));
+
+ IDictionary customMetadata = copyFrom.CloneCustomMetadata();
+ escapedMetadata = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ if (customMetadata?.Count > 0)
+ {
+ foreach (string key in customMetadata.Keys)
+ {
+ escapedMetadata.Add(key, EscapingUtilities.Escape((string)customMetadata[key] ?? String.Empty));
+ }
+ }
+ }
+
+ TaskParameterTaskItem taskItem = new TaskParameterTaskItem(escapedItemSpec, escapedDefiningProject, escapedMetadata);
+ return taskItem;
+ }
+
///
/// Serialize / deserialize this item.
///
private void TranslateITaskItemArray(ITranslator translator)
{
- ITaskItem[] wrappedItems = (ITaskItem[])_wrappedParameter;
- int length = wrappedItems?.Length ?? 0;
- translator.Translate(ref length);
- wrappedItems ??= new ITaskItem[length];
+ if (!TranslateNullable(translator, _wrappedParameter))
+ {
+ return;
+ }
- for (int i = 0; i < wrappedItems.Length; i++)
+ if (translator.Mode == TranslationDirection.WriteToStream)
{
- TaskParameterTaskItem taskItem = (TaskParameterTaskItem)wrappedItems[i];
- translator.Translate(ref taskItem, TaskParameterTaskItem.FactoryForDeserialization);
- wrappedItems[i] = taskItem;
+ ITaskItem[] wrappedItems = (ITaskItem[])_wrappedParameter;
+
+ int length = wrappedItems.Length;
+ translator.Translate(ref length);
+
+ foreach (ITaskItem wrappedItem in wrappedItems)
+ {
+ WriteITaskItem(translator, wrappedItem);
+ }
}
+ else
+ {
+ int length = 0;
+ translator.Translate(ref length);
+ ITaskItem[] wrappedItems = new ITaskItem[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ ReadITaskItem(translator, ref wrappedItems[i]);
+ }
- _wrappedParameter = wrappedItems;
+ _wrappedParameter = wrappedItems;
+ }
}
///
@@ -309,9 +374,127 @@ private void TranslateITaskItemArray(ITranslator translator)
///
private void TranslateITaskItem(ITranslator translator)
{
- TaskParameterTaskItem taskItem = (TaskParameterTaskItem)_wrappedParameter;
- translator.Translate(ref taskItem, TaskParameterTaskItem.FactoryForDeserialization);
- _wrappedParameter = taskItem;
+ if (translator.Mode == TranslationDirection.WriteToStream)
+ {
+ WriteITaskItem(translator, (ITaskItem)_wrappedParameter);
+ }
+ else // TranslationDirection.ReadFromStream
+ {
+ ITaskItem wrappedItem = null;
+ ReadITaskItem(translator, ref wrappedItem);
+ _wrappedParameter = wrappedItem;
+ }
+ }
+
+ ///
+ /// Write the given ITaskItem, using the given write translator
+ ///
+ private void WriteITaskItem(ITranslator translator, ITaskItem wrappedItem)
+ {
+ ErrorUtilities.VerifyThrow(translator.Mode == TranslationDirection.WriteToStream, "Cannot call this method when reading!");
+
+ if (!TranslateNullable(translator, wrappedItem))
+ {
+ return;
+ }
+
+ string escapedItemSpec;
+ string escapedDefiningProject;
+ IDictionary wrappedMetadata;
+ bool wrappedMetadataIsEscaped;
+
+ ITaskItem2 wrappedItemAsITaskItem2 = wrappedItem as ITaskItem2;
+
+ if (wrappedItemAsITaskItem2 != null)
+ {
+ escapedItemSpec = wrappedItemAsITaskItem2.EvaluatedIncludeEscaped;
+ escapedDefiningProject = wrappedItemAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath);
+ wrappedMetadata = wrappedItemAsITaskItem2.CloneCustomMetadataEscaped();
+ wrappedMetadataIsEscaped = true;
+ }
+ else
+ {
+ // We know that the ITaskItem constructor expects an escaped string, and that ITaskItem.ItemSpec
+ // is expected to be unescaped, so make sure we give the constructor what it wants.
+ escapedItemSpec = EscapingUtilities.Escape(wrappedItem.ItemSpec);
+ escapedDefiningProject = EscapingUtilities.EscapeWithCaching(wrappedItem.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath));
+ wrappedMetadata = wrappedItem.CloneCustomMetadata();
+ wrappedMetadataIsEscaped = false;
+ }
+
+ Dictionary escapedGenericWrappedMetadata = wrappedMetadata as Dictionary;
+
+ if (escapedGenericWrappedMetadata == null)
+ {
+ escapedGenericWrappedMetadata = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ foreach (object key in wrappedMetadata.Keys)
+ {
+ string value = (string)wrappedMetadata[key];
+
+ if (!wrappedMetadataIsEscaped)
+ {
+ value = (value == null) ? value : EscapingUtilities.Escape(value);
+ }
+
+ escapedGenericWrappedMetadata.Add((string)key, value);
+ }
+ }
+ else if (!wrappedMetadataIsEscaped)
+ {
+ foreach (KeyValuePair entry in escapedGenericWrappedMetadata)
+ {
+ escapedGenericWrappedMetadata[entry.Key] = entry.Value == null ? entry.Value : EscapingUtilities.Escape(entry.Value);
+ }
+ }
+
+ translator.Translate(ref escapedItemSpec);
+ translator.Translate(ref escapedDefiningProject);
+ translator.TranslateDictionary(ref escapedGenericWrappedMetadata, StringComparer.OrdinalIgnoreCase);
+ }
+
+ ///
+ /// Read an ITaskItem into the given parameter, using the given read translator
+ ///
+ private void ReadITaskItem(ITranslator translator, ref ITaskItem wrappedItem)
+ {
+ ErrorUtilities.VerifyThrow(translator.Mode == TranslationDirection.ReadFromStream, "Cannot call this method when writing!");
+
+ if (!TranslateNullable(translator, wrappedItem))
+ {
+ return;
+ }
+
+ string escapedItemSpec = null;
+ string escapedDefiningProject = null;
+ Dictionary escapedMetadata = null;
+
+ translator.Translate(ref escapedItemSpec);
+ translator.Translate(ref escapedDefiningProject);
+ translator.TranslateDictionary(ref escapedMetadata, StringComparer.OrdinalIgnoreCase);
+
+ wrappedItem = new TaskParameterTaskItem(escapedItemSpec, escapedDefiningProject, escapedMetadata);
+ }
+
+ ///
+ /// Writes out the boolean which says if this object is null or not.
+ ///
+ /// The nullable type to translate.
+ private bool TranslateNullable(ITranslator translator, T value)
+ {
+ bool haveRef = false;
+
+ if (translator.Mode == TranslationDirection.WriteToStream)
+ {
+ haveRef = (value != null);
+ translator.Translate(ref haveRef);
+ }
+ else // TranslationDirection.ReadFromStream
+ {
+ translator.Translate(ref haveRef);
+ }
+
+ return haveRef;
}
///
@@ -539,8 +722,7 @@ private class TaskParameterTaskItem :
MarshalByRefObject,
#endif
ITaskItem,
- ITaskItem2,
- ITranslatable
+ ITaskItem2
#if !TASKHOST
, IMetadataContainer
#endif
@@ -568,51 +750,13 @@ private class TaskParameterTaskItem :
///
/// Constructor for serialization
///
- internal TaskParameterTaskItem(ITaskItem copyFrom)
+ public TaskParameterTaskItem(string escapedItemSpec, string escapedDefiningProject, Dictionary escapedMetadata)
{
- if (copyFrom is ITaskItem2 copyFromAsITaskItem2)
- {
- _escapedItemSpec = copyFromAsITaskItem2.EvaluatedIncludeEscaped;
- _escapedDefiningProject = copyFromAsITaskItem2.GetMetadataValueEscaped(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath);
+ ErrorUtilities.VerifyThrowInternalNull(escapedItemSpec);
- IDictionary nonGenericEscapedMetadata = copyFromAsITaskItem2.CloneCustomMetadataEscaped();
- _customEscapedMetadata = nonGenericEscapedMetadata as Dictionary;
-
- if (_customEscapedMetadata is null)
- {
- _customEscapedMetadata = new Dictionary(MSBuildNameIgnoreCaseComparer.Default);
- foreach (DictionaryEntry entry in nonGenericEscapedMetadata)
- {
- _customEscapedMetadata[(string)entry.Key] = (string)entry.Value ?? string.Empty;
- }
- }
- }
- else
- {
- // If we don't have ITaskItem2 to fall back on, we have to make do with the fact that
- // CloneCustomMetadata, GetMetadata, & ItemSpec returns unescaped values, and
- // TaskParameterTaskItem's constructor expects escaped values, so escaping them all
- // is the closest approximation to correct we can get.
- _escapedItemSpec = EscapingUtilities.Escape(copyFrom.ItemSpec);
- _escapedDefiningProject = EscapingUtilities.EscapeWithCaching(copyFrom.GetMetadata(FileUtilities.ItemSpecModifiers.DefiningProjectFullPath));
-
- IDictionary customMetadata = copyFrom.CloneCustomMetadata();
- _customEscapedMetadata = new Dictionary(MSBuildNameIgnoreCaseComparer.Default);
-
- if (customMetadata?.Count > 0)
- {
- foreach (DictionaryEntry entry in customMetadata)
- {
- _customEscapedMetadata[(string)entry.Key] = EscapingUtilities.Escape((string)entry.Value) ?? string.Empty;
- }
- }
- }
-
- ErrorUtilities.VerifyThrowInternalNull(_escapedItemSpec);
- }
-
- private TaskParameterTaskItem()
- {
+ _escapedItemSpec = escapedItemSpec;
+ _escapedDefiningProject = escapedDefiningProject;
+ _customEscapedMetadata = escapedMetadata;
}
///
@@ -705,7 +849,7 @@ public void SetMetadata(string metadataName, string metadataValue)
// That's why this is IsItemSpecModifier and not IsDerivableItemSpecModifier.
ErrorUtilities.VerifyThrowArgument(!FileUtilities.ItemSpecModifiers.IsDerivableItemSpecModifier(metadataName), "Shared.CannotChangeItemSpecModifiers", metadataName);
- _customEscapedMetadata ??= new Dictionary(MSBuildNameIgnoreCaseComparer.Default);
+ _customEscapedMetadata ??= new Dictionary(StringComparer.OrdinalIgnoreCase);
_customEscapedMetadata[metadataName] = metadataValue ?? String.Empty;
}
@@ -745,25 +889,6 @@ public void CopyMetadataTo(ITaskItem destinationItem)
// between items, and need to know the source item where the metadata came from
string originalItemSpec = destinationItem.GetMetadata("OriginalItemSpec");
-#if !TASKHOST
- if (_customEscapedMetadata != null && destinationItem is IMetadataContainer destinationItemAsMetadataContainer)
- {
- // The destination implements IMetadataContainer so we can use the ImportMetadata bulk-set operation.
- IEnumerable> metadataToImport = _customEscapedMetadata
- .Where(metadatum => string.IsNullOrEmpty(destinationItem.GetMetadata(metadatum.Key)));
-
-#if FEATURE_APPDOMAIN
- if (!AppDomain.CurrentDomain.IsDefaultAppDomain())
- {
- // Linq is not serializable so materialize the collection before making the call.
- metadataToImport = metadataToImport.ToList();
- }
-#endif
-
- destinationItemAsMetadataContainer.ImportMetadata(metadataToImport);
- }
- else
-#endif
if (_customEscapedMetadata != null)
{
foreach (KeyValuePair entry in _customEscapedMetadata)
@@ -794,7 +919,7 @@ public void CopyMetadataTo(ITaskItem destinationItem)
/// Dictionary of cloned metadata
public IDictionary CloneCustomMetadata()
{
- IDictionary clonedMetadata = new Dictionary(MSBuildNameIgnoreCaseComparer.Default);
+ IDictionary clonedMetadata = new Dictionary(StringComparer.OrdinalIgnoreCase);
if (_customEscapedMetadata != null)
{
@@ -913,23 +1038,6 @@ public void ImportMetadata(IEnumerable> metadata)
SetMetadata(kvp.Key, kvp.Value);
}
}
-
- public void Translate(ITranslator translator)
- {
- translator.Translate(ref _escapedItemSpec);
- translator.Translate(ref _escapedDefiningProject);
- translator.TranslateDictionary(ref _customEscapedMetadata, MSBuildNameIgnoreCaseComparer.Default);
-
- ErrorUtilities.VerifyThrowInternalNull(_escapedItemSpec);
- ErrorUtilities.VerifyThrowInternalNull(_customEscapedMetadata);
- }
-
- internal static TaskParameterTaskItem FactoryForDeserialization(ITranslator translator)
- {
- TaskParameterTaskItem taskItem = new();
- taskItem.Translate(translator);
- return taskItem;
- }
}
}
}
diff --git a/src/msbuild/src/Tasks/MSBuild.cs b/src/msbuild/src/Tasks/MSBuild.cs
index 12426e0c9aa..d3c24bd0f1d 100644
--- a/src/msbuild/src/Tasks/MSBuild.cs
+++ b/src/msbuild/src/Tasks/MSBuild.cs
@@ -296,6 +296,12 @@ public override bool Execute()
{
skipNonExistProjects = behavior;
}
+ else if (BuildEngine is IBuildEngine6 buildEngine6 && buildEngine6.GetGlobalProperties()
+ .TryGetValue(PropertyNames.BuildNonexistentProjectsByDefault, out var buildNonexistentProjectsByDefault) &&
+ ConversionUtilities.ConvertStringToBool(buildNonexistentProjectsByDefault))
+ {
+ skipNonExistProjects = SkipNonExistentProjectsBehavior.Build;
+ }
else
{
skipNonExistProjects = SkipNonExistentProjectsBehavior.Error;
diff --git a/src/msbuild/src/Tasks/Microsoft.Build.Tasks.csproj b/src/msbuild/src/Tasks/Microsoft.Build.Tasks.csproj
index 4fa44bebcbf..48d3df90c79 100644
--- a/src/msbuild/src/Tasks/Microsoft.Build.Tasks.csproj
+++ b/src/msbuild/src/Tasks/Microsoft.Build.Tasks.csproj
@@ -87,6 +87,7 @@
FileDelegates.cs
+
PropertyParser.cs
@@ -131,6 +132,7 @@
Modifiers.cs
+
diff --git a/src/msbuild/src/Tasks/Microsoft.Common.CurrentVersion.targets b/src/msbuild/src/Tasks/Microsoft.Common.CurrentVersion.targets
index 0513ae5bcb8..25552982719 100644
--- a/src/msbuild/src/Tasks/Microsoft.Common.CurrentVersion.targets
+++ b/src/msbuild/src/Tasks/Microsoft.Common.CurrentVersion.targets
@@ -3189,8 +3189,7 @@ Copyright (C) Microsoft Corporation. All rights reserved.
AssignTargetPaths;
SplitResourcesByCulture;
CreateManifestResourceNames;
- CreateCustomManifestResourceNames;
- AssignEmbeddedResourceOutputPaths;
+ CreateCustomManifestResourceNames
@@ -3248,17 +3247,6 @@ Copyright (C) Microsoft Corporation. All rights reserved.
-
-
-
-
- $(IntermediateOutputPath)%(EmbeddedResource.ManifestResourceName).resources
-
-
-
-
-
+
Shared\FrameworkLocationHelper.cs
+
+ Shared\IConstrainedEqualityComparer.cs
+
Shared\IKeyed.cs
+
+ Shared\MSBuildNameIgnoreCaseComparer.cs
+
Shared\Modifiers.cs
diff --git a/src/roslyn/eng/Directory.Packages.props b/src/roslyn/eng/Directory.Packages.props
index 917a8e7b547..aa611b4cbb4 100644
--- a/src/roslyn/eng/Directory.Packages.props
+++ b/src/roslyn/eng/Directory.Packages.props
@@ -273,7 +273,7 @@
-
+
diff --git a/src/roslyn/eng/Versions.props b/src/roslyn/eng/Versions.props
index 316b98b4558..a70c9228798 100644
--- a/src/roslyn/eng/Versions.props
+++ b/src/roslyn/eng/Versions.props
@@ -8,7 +8,7 @@
5
0
0
- 1
+ 2
$(MajorVersion).$(MinorVersion).$(PatchVersion)
- 17.5.0
+ 17.13.0
diff --git a/src/roslyn/eng/config/PublishData.json b/src/roslyn/eng/config/PublishData.json
index 9727fa29ce6..4ad30f47e37 100644
--- a/src/roslyn/eng/config/PublishData.json
+++ b/src/roslyn/eng/config/PublishData.json
@@ -176,6 +176,15 @@
"insertionTitlePrefix": "[d17.14]",
"insertionCreateDraftPR": false
},
+ "release/dev-next": {
+ "nugetKind": [
+ "Shipping",
+ "NonShipping"
+ ],
+ "vsBranch": "main",
+ "insertionTitlePrefix": "[dNext]",
+ "insertionCreateDraftPR": false
+ },
"main": {
"nugetKind": [
"Shipping",
@@ -191,8 +200,8 @@
"NonShipping"
],
"vsBranch": "main",
- "insertionCreateDraftPR": false,
- "insertionTitlePrefix": "[d17.15 P1]"
+ "insertionCreateDraftPR": true,
+ "insertionTitlePrefix": "[dNext.1]"
}
}
}
diff --git a/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs b/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs
index 0e57a94e02e..a755f4763ee 100644
--- a/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs
+++ b/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceCodeFixProvider.cs
@@ -24,7 +24,4 @@ internal sealed class CSharpImplementInterfaceCodeFixProvider()
public sealed override ImmutableArray FixableDiagnosticIds { get; }
= [CS0535, CS0737, CS0738];
-
- protected override bool IsTypeInInterfaceBaseList(TypeSyntax type)
- => type.Parent is BaseTypeSyntax { Parent: BaseListSyntax } baseTypeParent && baseTypeParent.Type == type;
}
diff --git a/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs b/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs
index 23efc1a7f4f..b9fd6197a06 100644
--- a/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs
+++ b/src/roslyn/src/Analyzers/CSharp/CodeFixes/ImplementInterface/CSharpImplementInterfaceService.cs
@@ -16,6 +16,7 @@
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.ImplementInterface;
+using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface;
@@ -23,7 +24,7 @@ namespace Microsoft.CodeAnalysis.CSharp.ImplementInterface;
[ExportLanguageService(typeof(IImplementInterfaceService), LanguageNames.CSharp), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
-internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService
+internal sealed class CSharpImplementInterfaceService() : AbstractImplementInterfaceService
{
protected override ISyntaxFormatting SyntaxFormatting
=> CSharpSyntaxFormatting.Instance;
@@ -37,6 +38,18 @@ protected override string ToDisplayString(IMethodSymbol disposeImplMethod, Symbo
protected override bool AllowDelegateAndEnumConstraints(ParseOptions options)
=> options.LanguageVersion() >= LanguageVersion.CSharp7_3;
+ protected override bool IsTypeInInterfaceBaseList(SyntaxNode? type)
+ => type?.Parent is BaseTypeSyntax { Parent: BaseListSyntax } baseTypeParent && baseTypeParent.Type == type;
+
+ protected override void AddInterfaceTypes(TypeDeclarationSyntax typeDeclaration, ArrayBuilder result)
+ {
+ if (typeDeclaration.BaseList != null)
+ {
+ foreach (var baseType in typeDeclaration.BaseList.Types)
+ result.Add(baseType.Type);
+ }
+ }
+
protected override bool TryInitializeState(
Document document, SemanticModel model, SyntaxNode node, CancellationToken cancellationToken,
[NotNullWhen(true)] out SyntaxNode? classOrStructDecl,
diff --git a/src/roslyn/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/roslyn/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
index 2fb30453912..26423cafb96 100644
--- a/src/roslyn/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
+++ b/src/roslyn/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
@@ -43,8 +43,8 @@
-
-
+
+
diff --git a/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs b/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.cs
similarity index 99%
rename from src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs
rename to src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.cs
index ec10365e15a..e7e6d5dbf14 100644
--- a/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests.cs
+++ b/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.cs
@@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface;
CSharpImplementInterfaceCodeFixProvider>;
[Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
-public sealed class ImplementInterfaceTests
+public sealed class ImplementInterfaceCodeFixTests
{
private readonly NamingStylesTestOptionSets _options = new(LanguageNames.CSharp);
diff --git a/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs b/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.cs
similarity index 99%
rename from src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs
rename to src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.cs
index 761d785b2ea..afc9042b849 100644
--- a/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.cs
+++ b/src/roslyn/src/Analyzers/CSharp/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.cs
@@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ImplementInterface;
EmptyDiagnosticAnalyzer,
CSharpImplementInterfaceCodeFixProvider>;
-public sealed class ImplementInterfaceTests_FixAllTests
+public sealed class ImplementInterfaceCodeFixTests_FixAllTests
{
#region "Fix all occurrences tests"
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs
index da11cdb7fca..7fffec0d40d 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceCodeFixProvider.cs
@@ -2,28 +2,16 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-using System.Collections.Generic;
-using System.Collections.Immutable;
using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
-using Microsoft.CodeAnalysis.ImplementType;
-using Microsoft.CodeAnalysis.LanguageService;
-using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.ImplementInterface;
-using static ImplementHelpers;
-
internal abstract class AbstractImplementInterfaceCodeFixProvider : CodeFixProvider
where TTypeSyntax : SyntaxNode
{
- protected abstract bool IsTypeInInterfaceBaseList(TTypeSyntax type);
-
public sealed override FixAllProvider GetFixAllProvider()
=> WellKnownFixAllProviders.BatchFixer;
@@ -39,173 +27,11 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
if (!token.Span.IntersectsWith(span))
return;
- var options = await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(false);
-
- foreach (var type in token.Parent.GetAncestorsOrThis())
- {
- if (this.IsTypeInInterfaceBaseList(type))
- {
- var service = document.GetRequiredLanguageService();
-
- var info = await service.AnalyzeAsync(
- document, type, cancellationToken).ConfigureAwait(false);
- if (info is not null)
- {
- using var _ = ArrayBuilder.GetInstance(out var codeActions);
- await foreach (var implementOptions in GetImplementOptionsAsync(document, info, cancellationToken))
- {
- var title = GetTitle(implementOptions);
- var equivalenceKey = GetEquivalenceKey(info, implementOptions);
- codeActions.Add(CodeAction.Create(
- title,
- cancellationToken => service.ImplementInterfaceAsync(
- document, info, options, implementOptions, cancellationToken),
- equivalenceKey));
- }
-
- context.RegisterFixes(codeActions, context.Diagnostics);
- }
-
- break;
- }
- }
- }
-
- private static string GetTitle(ImplementInterfaceConfiguration options)
- {
- if (options.ImplementDisposePattern)
- {
- return options.Explicitly
- ? CodeFixesResources.Implement_interface_explicitly_with_Dispose_pattern
- : CodeFixesResources.Implement_interface_with_Dispose_pattern;
- }
- else if (options.Explicitly)
- {
- return options.OnlyRemaining
- ? CodeFixesResources.Implement_remaining_members_explicitly
- : CodeFixesResources.Implement_all_members_explicitly;
- }
- else if (options.Abstractly)
- {
- return CodeFixesResources.Implement_interface_abstractly;
- }
- else if (options.ThroughMember != null)
- {
- return string.Format(CodeFixesResources.Implement_interface_through_0, options.ThroughMember.Name);
- }
- else
- {
- return CodeFixesResources.Implement_interface;
- }
- }
-
- private static string GetEquivalenceKey(
- ImplementInterfaceInfo state,
- ImplementInterfaceConfiguration options)
- {
- var interfaceType = state.InterfaceTypes.First();
- var typeName = interfaceType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
-
- // Legacy part of the equivalence key. Kept the same to avoid test churn.
- var codeActionTypeName = options.ImplementDisposePattern
- ? "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction"
- : "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction";
-
- // Consider code actions equivalent if they correspond to the same interface being implemented elsewhere
- // in the same manner. Note: 'implement through member' means implementing the same interface through
- // an applicable member with the same name in the destination.
- return options.Explicitly.ToString() + ";" +
- options.Abstractly.ToString() + ";" +
- options.OnlyRemaining.ToString() + ":" +
- typeName + ";" +
- codeActionTypeName + ";" +
- options.ThroughMember?.Name;
- }
-
- private static async IAsyncEnumerable GetImplementOptionsAsync(
- Document document, ImplementInterfaceInfo state, [EnumeratorCancellation] CancellationToken cancellationToken)
- {
- var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
- var syntaxFacts = document.GetRequiredLanguageService();
- var supportsImplicitImplementationOfNonPublicInterfaceMembers = syntaxFacts.SupportsImplicitImplementationOfNonPublicInterfaceMembers(document.Project.ParseOptions!);
- if (state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented.Length > 0)
- {
- var totalMemberCount = 0;
- var inaccessibleMemberCount = 0;
-
- foreach (var (_, members) in state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented)
- {
- foreach (var member in members)
- {
- totalMemberCount++;
-
- if (ContainsTypeLessAccessibleThan(member, state.ClassOrStructType, supportsImplicitImplementationOfNonPublicInterfaceMembers))
- inaccessibleMemberCount++;
- }
- }
-
- // If all members to implement are inaccessible, then "Implement interface" codeaction
- // will be the same as "Implement interface explicitly", so there is no point in having both of them
- if (totalMemberCount != inaccessibleMemberCount)
- yield return new() { OnlyRemaining = true };
-
- if (ShouldImplementDisposePattern(compilation, state, explicitly: false))
- yield return new() { OnlyRemaining = true, ImplementDisposePattern = true, };
-
- var delegatableMembers = GetDelegatableMembers(document, state, cancellationToken);
- foreach (var member in delegatableMembers)
- yield return new() { ThroughMember = member };
+ var type = token.Parent.GetAncestorsOrThis().LastOrDefault();
- if (state.ClassOrStructType.IsAbstract)
- yield return new() { OnlyRemaining = true, Abstractly = true };
- }
-
- if (state.MembersWithoutExplicitImplementation.Length > 0)
- {
- yield return new() { Explicitly = true };
-
- if (ShouldImplementDisposePattern(compilation, state, explicitly: true))
- yield return new() { ImplementDisposePattern = true, Explicitly = true };
- }
-
- if (AnyImplementedImplicitly(state))
- yield return new() { OnlyRemaining = true, Explicitly = true };
- }
-
- private static bool AnyImplementedImplicitly(ImplementInterfaceInfo state)
- {
- if (state.MembersWithoutExplicitOrImplicitImplementation.Length != state.MembersWithoutExplicitImplementation.Length)
- {
- return true;
- }
-
- for (var i = 0; i < state.MembersWithoutExplicitOrImplicitImplementation.Length; i++)
- {
- var (typeA, membersA) = state.MembersWithoutExplicitOrImplicitImplementation[i];
- var (typeB, membersB) = state.MembersWithoutExplicitImplementation[i];
- if (!typeA.Equals(typeB))
- {
- return true;
- }
-
- if (!membersA.SequenceEqual(membersB))
- {
- return true;
- }
- }
-
- return false;
- }
-
- private static ImmutableArray GetDelegatableMembers(
- Document document, ImplementInterfaceInfo state, CancellationToken cancellationToken)
- {
- var firstInterfaceType = state.InterfaceTypes.First();
+ var service = document.GetRequiredLanguageService();
+ var codeActions = await service.GetCodeActionsAsync(document, type, cancellationToken).ConfigureAwait(false);
- return ImplementHelpers.GetDelegatableMembers(
- document,
- state.ClassOrStructType,
- t => t.GetAllInterfacesIncludingThis().Contains(firstInterfaceType),
- cancellationToken);
+ context.RegisterFixes(codeActions, context.Diagnostics);
}
}
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs
index 282036cd5b4..cff4072d33c 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.State.cs
@@ -9,7 +9,7 @@
namespace Microsoft.CodeAnalysis.ImplementInterface;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
internal sealed class State(
Document document,
@@ -40,7 +40,7 @@ internal sealed class State(
public ImmutableArray<(INamedTypeSymbol type, ImmutableArray members)> MembersWithoutExplicitImplementation => Info.MembersWithoutExplicitImplementation;
public static State? Generate(
- AbstractImplementInterfaceService service,
+ AbstractImplementInterfaceService service,
Document document,
SemanticModel model,
SyntaxNode interfaceNode,
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs
index 9ccbb6fe9ce..0d85020a1be 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/AbstractImplementInterfaceService.cs
@@ -3,10 +3,14 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.ImplementType;
@@ -19,7 +23,8 @@ namespace Microsoft.CodeAnalysis.ImplementInterface;
using static ImplementHelpers;
-internal abstract partial class AbstractImplementInterfaceService() : IImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService : IImplementInterfaceService
+ where TTypeDeclarationSyntax : SyntaxNode
{
protected const string DisposingName = "disposing";
@@ -39,6 +44,18 @@ protected abstract bool TryInitializeState(Document document, SemanticModel mode
protected abstract SyntaxNode AddCommentInsideIfStatement(SyntaxNode ifDisposingStatement, SyntaxTriviaList trivia);
protected abstract SyntaxNode CreateFinalizer(SyntaxGenerator generator, INamedTypeSymbol classType, string disposeMethodDisplayString);
+ protected abstract bool IsTypeInInterfaceBaseList([NotNullWhen(true)] SyntaxNode? type);
+ protected abstract void AddInterfaceTypes(TTypeDeclarationSyntax typeDeclaration, ArrayBuilder result);
+
+ public ImmutableArray GetInterfaceTypes(SyntaxNode typeDeclaration)
+ {
+ using var _ = ArrayBuilder.GetInstance(out var result);
+ if (typeDeclaration is TTypeDeclarationSyntax typeSyntax)
+ AddInterfaceTypes(typeSyntax, result);
+
+ return result.ToImmutableAndClear();
+ }
+
public async Task ImplementInterfaceAsync(
Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken)
{
@@ -59,7 +76,7 @@ public async Task ImplementInterfaceAsync(
}
}
- public async Task AnalyzeAsync(Document document, SyntaxNode interfaceType, CancellationToken cancellationToken)
+ private async Task AnalyzeAsync(Document document, SyntaxNode interfaceType, CancellationToken cancellationToken)
{
var model = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);
return State.Generate(this, document, model, interfaceType, cancellationToken)?.Info;
@@ -88,7 +105,7 @@ protected SyntaxTriviaList CreateCommentTrivia(
return [.. trivia];
}
- public async Task ImplementInterfaceAsync(
+ private async Task ImplementInterfaceAsync(
Document document,
ImplementInterfaceInfo info,
ImplementTypeOptions options,
@@ -126,4 +143,169 @@ public ImmutableArray ImplementInterfaceMember(
return implementedMembers;
}
+
+ public async Task> GetCodeActionsAsync(Document document, SyntaxNode? interfaceType, CancellationToken cancellationToken)
+ {
+ var options = await document.GetImplementTypeOptionsAsync(cancellationToken).ConfigureAwait(false);
+
+ if (!this.IsTypeInInterfaceBaseList(interfaceType))
+ return [];
+
+ var info = await this.AnalyzeAsync(
+ document, interfaceType, cancellationToken).ConfigureAwait(false);
+ if (info is null)
+ return [];
+
+ using var _ = ArrayBuilder.GetInstance(out var codeActions);
+ await foreach (var implementOptions in GetImplementOptionsAsync(document, info, cancellationToken))
+ {
+ var title = GetTitle(implementOptions);
+ var equivalenceKey = GetEquivalenceKey(info, implementOptions);
+ codeActions.Add(CodeAction.Create(
+ title,
+ cancellationToken => this.ImplementInterfaceAsync(
+ document, info, options, implementOptions, cancellationToken),
+ equivalenceKey));
+ }
+
+ return codeActions.ToImmutableAndClear();
+ }
+
+ private static async IAsyncEnumerable GetImplementOptionsAsync(
+ Document document, ImplementInterfaceInfo state, [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ var compilation = await document.Project.GetRequiredCompilationAsync(cancellationToken).ConfigureAwait(false);
+ var syntaxFacts = document.GetRequiredLanguageService();
+ var supportsImplicitImplementationOfNonPublicInterfaceMembers = syntaxFacts.SupportsImplicitImplementationOfNonPublicInterfaceMembers(document.Project.ParseOptions!);
+ if (state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented.Length > 0)
+ {
+ var totalMemberCount = 0;
+ var inaccessibleMemberCount = 0;
+
+ foreach (var (_, members) in state.MembersWithoutExplicitOrImplicitImplementationWhichCanBeImplicitlyImplemented)
+ {
+ foreach (var member in members)
+ {
+ totalMemberCount++;
+
+ if (ContainsTypeLessAccessibleThan(member, state.ClassOrStructType, supportsImplicitImplementationOfNonPublicInterfaceMembers))
+ inaccessibleMemberCount++;
+ }
+ }
+
+ // If all members to implement are inaccessible, then "Implement interface" codeaction
+ // will be the same as "Implement interface explicitly", so there is no point in having both of them
+ if (totalMemberCount != inaccessibleMemberCount)
+ yield return new() { OnlyRemaining = true };
+
+ if (ShouldImplementDisposePattern(compilation, state, explicitly: false))
+ yield return new() { OnlyRemaining = true, ImplementDisposePattern = true, };
+
+ var delegatableMembers = GetDelegatableMembers(document, state, cancellationToken);
+ foreach (var member in delegatableMembers)
+ yield return new() { ThroughMember = member };
+
+ if (state.ClassOrStructType.IsAbstract)
+ yield return new() { OnlyRemaining = true, Abstractly = true };
+ }
+
+ if (state.MembersWithoutExplicitImplementation.Length > 0)
+ {
+ yield return new() { Explicitly = true };
+
+ if (ShouldImplementDisposePattern(compilation, state, explicitly: true))
+ yield return new() { ImplementDisposePattern = true, Explicitly = true };
+ }
+
+ if (AnyImplementedImplicitly(state))
+ yield return new() { OnlyRemaining = true, Explicitly = true };
+ }
+
+ private static string GetTitle(ImplementInterfaceConfiguration options)
+ {
+ if (options.ImplementDisposePattern)
+ {
+ return options.Explicitly
+ ? CodeFixesResources.Implement_interface_explicitly_with_Dispose_pattern
+ : CodeFixesResources.Implement_interface_with_Dispose_pattern;
+ }
+ else if (options.Explicitly)
+ {
+ return options.OnlyRemaining
+ ? CodeFixesResources.Implement_remaining_members_explicitly
+ : CodeFixesResources.Implement_all_members_explicitly;
+ }
+ else if (options.Abstractly)
+ {
+ return CodeFixesResources.Implement_interface_abstractly;
+ }
+ else if (options.ThroughMember != null)
+ {
+ return string.Format(CodeFixesResources.Implement_interface_through_0, options.ThroughMember.Name);
+ }
+ else
+ {
+ return CodeFixesResources.Implement_interface;
+ }
+ }
+
+ private static string GetEquivalenceKey(
+ ImplementInterfaceInfo state,
+ ImplementInterfaceConfiguration options)
+ {
+ var interfaceType = state.InterfaceTypes.First();
+ var typeName = interfaceType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+
+ // Legacy part of the equivalence key. Kept the same to avoid test churn.
+ var codeActionTypeName = options.ImplementDisposePattern
+ ? "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceWithDisposePatternCodeAction"
+ : "Microsoft.CodeAnalysis.ImplementInterface.AbstractImplementInterfaceService+ImplementInterfaceCodeAction";
+
+ // Consider code actions equivalent if they correspond to the same interface being implemented elsewhere
+ // in the same manner. Note: 'implement through member' means implementing the same interface through
+ // an applicable member with the same name in the destination.
+ return options.Explicitly.ToString() + ";" +
+ options.Abstractly.ToString() + ";" +
+ options.OnlyRemaining.ToString() + ":" +
+ typeName + ";" +
+ codeActionTypeName + ";" +
+ options.ThroughMember?.Name;
+ }
+
+ private static bool AnyImplementedImplicitly(ImplementInterfaceInfo state)
+ {
+ if (state.MembersWithoutExplicitOrImplicitImplementation.Length != state.MembersWithoutExplicitImplementation.Length)
+ {
+ return true;
+ }
+
+ for (var i = 0; i < state.MembersWithoutExplicitOrImplicitImplementation.Length; i++)
+ {
+ var (typeA, membersA) = state.MembersWithoutExplicitOrImplicitImplementation[i];
+ var (typeB, membersB) = state.MembersWithoutExplicitImplementation[i];
+ if (!typeA.Equals(typeB))
+ {
+ return true;
+ }
+
+ if (!membersA.SequenceEqual(membersB))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static ImmutableArray GetDelegatableMembers(
+ Document document, ImplementInterfaceInfo state, CancellationToken cancellationToken)
+ {
+ var firstInterfaceType = state.InterfaceTypes.First();
+
+ return ImplementHelpers.GetDelegatableMembers(
+ document,
+ state.ClassOrStructType,
+ t => t.GetAllInterfacesIncludingThis().Contains(firstInterfaceType),
+ cancellationToken);
+ }
}
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs
index 55b0b6d99cd..32df9beb853 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/IImplementInterfaceService.cs
@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.ImplementType;
@@ -23,15 +24,6 @@ internal interface IImplementInterfaceService : ILanguageService
{
Task ImplementInterfaceAsync(Document document, ImplementTypeOptions options, SyntaxNode node, CancellationToken cancellationToken);
- Task AnalyzeAsync(Document document, SyntaxNode interfaceType, CancellationToken cancellationToken);
-
- Task ImplementInterfaceAsync(
- Document document,
- ImplementInterfaceInfo info,
- ImplementTypeOptions options,
- ImplementInterfaceConfiguration configuration,
- CancellationToken cancellationToken);
-
///
/// Produces the symbol that implements that provided within the corresponding
/// , based on the provided and
@@ -44,4 +36,9 @@ ImmutableArray ImplementInterfaceMember(
ImplementInterfaceConfiguration configuration,
Compilation compilation,
ISymbol interfaceMember);
+
+ Task> GetCodeActionsAsync(
+ Document document, SyntaxNode? interfaceType, CancellationToken cancellationToken);
+
+ ImmutableArray GetInterfaceTypes(SyntaxNode typeDeclaration);
}
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs
index fc5078f1ea9..b0b61f3fdbc 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator.cs
@@ -22,12 +22,12 @@ namespace Microsoft.CodeAnalysis.ImplementInterface;
using static ImplementHelpers;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
private sealed partial class ImplementInterfaceGenerator
{
private readonly Document Document;
- private readonly AbstractImplementInterfaceService Service;
+ private readonly AbstractImplementInterfaceService Service;
private readonly ImplementInterfaceInfo State;
private readonly ImplementTypeOptions Options;
@@ -40,7 +40,7 @@ private sealed partial class ImplementInterfaceGenerator
private ISymbol? ThroughMember => Configuration.ThroughMember;
internal ImplementInterfaceGenerator(
- AbstractImplementInterfaceService service,
+ AbstractImplementInterfaceService service,
Document document,
ImplementInterfaceInfo state,
ImplementTypeOptions options,
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs
index fb554b99f44..f9ce33830bc 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Conflicts.cs
@@ -12,7 +12,7 @@
namespace Microsoft.CodeAnalysis.ImplementInterface;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
private sealed partial class ImplementInterfaceGenerator
{
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs
index 0887f5f52ce..4bc54edb2fc 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_DisposePattern.cs
@@ -22,7 +22,7 @@ namespace Microsoft.CodeAnalysis.ImplementInterface;
using static ImplementHelpers;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
private sealed partial class ImplementInterfaceGenerator
{
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs
index 48a343cdcfe..a08aa2daff3 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Method.cs
@@ -11,7 +11,7 @@
namespace Microsoft.CodeAnalysis.ImplementInterface;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
private sealed partial class ImplementInterfaceGenerator
{
diff --git a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs
index b31a55c26bb..75b8cd535f3 100644
--- a/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs
+++ b/src/roslyn/src/Analyzers/Core/CodeFixes/ImplementInterface/ImplementInterfaceGenerator_Property.cs
@@ -16,7 +16,7 @@
namespace Microsoft.CodeAnalysis.ImplementInterface;
-internal abstract partial class AbstractImplementInterfaceService
+internal abstract partial class AbstractImplementInterfaceService
{
private sealed partial class ImplementInterfaceGenerator
{
diff --git a/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb b/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb
index 8aa097942b9..634e140216f 100644
--- a/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb
+++ b/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceCodeFixProvider.vb
@@ -23,9 +23,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
End Sub
Public Overrides ReadOnly Property FixableDiagnosticIds As ImmutableArray(Of String) = ImmutableArray.Create(BC30149)
-
- Protected Overrides Function IsTypeInInterfaceBaseList(type As TypeSyntax) As Boolean
- Return TypeOf type.Parent Is ImplementsStatementSyntax
- End Function
End Class
End Namespace
diff --git a/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb b/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb
index 161a9857bd4..eb0d4a2a879 100644
--- a/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb
+++ b/src/roslyn/src/Analyzers/VisualBasic/CodeFixes/ImplementInterface/VisualBasicImplementInterfaceService.vb
@@ -10,14 +10,15 @@ Imports Microsoft.CodeAnalysis.Editing
Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.ImplementInterface
+Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Imports Microsoft.CodeAnalysis.VisualBasic.Formatting
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
- Partial Friend Class VisualBasicImplementInterfaceService
- Inherits AbstractImplementInterfaceService
+ Partial Friend NotInheritable Class VisualBasicImplementInterfaceService
+ Inherits AbstractImplementInterfaceService(Of TypeBlockSyntax)
@@ -39,6 +40,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
Return False
End Function
+ Protected Overrides Function IsTypeInInterfaceBaseList(type As SyntaxNode) As Boolean
+ Return TypeOf type?.Parent Is ImplementsStatementSyntax
+ End Function
+
+ Protected Overrides Sub AddInterfaceTypes(typeDeclaration As TypeBlockSyntax, result As ArrayBuilder(Of SyntaxNode))
+ For Each implementsStatement In typeDeclaration.Implements
+ For Each interfaceType In implementsStatement.Types
+ result.Add(interfaceType)
+ Next
+ Next
+ End Sub
+
Protected Overrides Function TryInitializeState(
document As Document, model As SemanticModel, node As SyntaxNode, cancellationToken As CancellationToken,
ByRef classOrStructDecl As SyntaxNode, ByRef classOrStructType As INamedTypeSymbol,
diff --git a/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb b/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.vb
similarity index 99%
rename from src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb
rename to src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.vb
index 9b9f0deaa81..583aba10158 100644
--- a/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests.vb
+++ b/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests.vb
@@ -10,7 +10,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementInterface
- Partial Public Class ImplementInterfaceTests
+ Partial Public Class ImplementInterfaceCodeFixTests
Inherits AbstractVisualBasicDiagnosticProviderBasedUserDiagnosticTest_NoEditor
Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace) As (DiagnosticAnalyzer, CodeFixProvider)
diff --git a/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb b/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.vb
similarity index 99%
rename from src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb
rename to src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.vb
index 46138758ecf..4f5fd12b08d 100644
--- a/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceTests_FixAllTests.vb
+++ b/src/roslyn/src/Analyzers/VisualBasic/Tests/ImplementInterface/ImplementInterfaceCodeFixTests_FixAllTests.vb
@@ -3,7 +3,7 @@
' See the LICENSE file in the project root for more information.
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementInterface
- Partial Public Class ImplementInterfaceTests
+ Partial Public Class ImplementInterfaceCodeFixTests
diff --git a/src/roslyn/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems b/src/roslyn/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems
index 9f5434bfc46..fcfafc799ce 100644
--- a/src/roslyn/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems
+++ b/src/roslyn/src/Analyzers/VisualBasic/Tests/VisualBasicAnalyzers.UnitTests.projitems
@@ -29,8 +29,8 @@
-
-
+
+
diff --git a/src/roslyn/src/Compilers/CSharp/Portable/CSharpParseOptions.cs b/src/roslyn/src/Compilers/CSharp/Portable/CSharpParseOptions.cs
index 650f5b27cf0..bc3804f6725 100644
--- a/src/roslyn/src/Compilers/CSharp/Portable/CSharpParseOptions.cs
+++ b/src/roslyn/src/Compilers/CSharp/Portable/CSharpParseOptions.cs
@@ -162,9 +162,15 @@ protected override ParseOptions CommonWithFeatures(IEnumerable
public new CSharpParseOptions WithFeatures(IEnumerable>? features)
{
- ImmutableDictionary dictionary =
- features?.ToImmutableDictionary(StringComparer.OrdinalIgnoreCase)
- ?? ImmutableDictionary.Empty;
+ if (Features == features)
+ {
+ return this;
+ }
+
+ if (features is not ImmutableDictionary dictionary || dictionary.KeyComparer != StringComparer.OrdinalIgnoreCase)
+ {
+ dictionary = (features ?? []).ToImmutableDictionary(StringComparer.OrdinalIgnoreCase);
+ }
return new CSharpParseOptions(this) { _features = dictionary };
}
diff --git a/src/roslyn/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/roslyn/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index b9f8452c5a4..e77cf92a40e 100644
--- a/src/roslyn/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/roslyn/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -6598,7 +6598,7 @@ private TypeWithState VisitAndCheckReceiver(BoundExpression? receiverOpt, Method
}
private (MethodSymbol method, ImmutableArray results, bool returnNotNull) ReInferMethodAndVisitArguments(
- BoundExpression node,
+ BoundNode node,
BoundExpression? receiverOpt,
TypeWithState receiverType,
MethodSymbol method,
@@ -6615,7 +6615,7 @@ private TypeWithState VisitAndCheckReceiver(BoundExpression? receiverOpt, Method
refKindsOpt = GetArgumentRefKinds(refKindsOpt, adjustForNewExtension, method, arguments.Length);
- if (!receiverType.HasNullType)
+ if (!method.GetIsNewExtensionMember() && !receiverType.HasNullType)
{
// Update method based on inferred receiver type.
method = (MethodSymbol)AsMemberOfType(receiverType.Type, method);
@@ -7094,17 +7094,11 @@ private static TypeWithAnnotations ApplyUnconditionalAnnotations(TypeWithAnnotat
// invocation (such as a synthesized call from a query interpretation).
private static bool HasImplicitTypeArguments(BoundNode node)
{
- if (node is BoundCollectionElementInitializer { AddMethod: { TypeArgumentsWithAnnotations: { IsEmpty: false } } })
- {
- return true;
- }
-
- if (node is BoundForEachStatement { EnumeratorInfoOpt: { GetEnumeratorInfo: { Method: { TypeArgumentsWithAnnotations: { IsEmpty: false } } } } })
- {
- return true;
- }
-
- if (node is BoundPropertyAccess or BoundIncrementOperator or BoundCompoundAssignmentOperator)
+ if (node is BoundCollectionElementInitializer
+ or BoundForEachStatement
+ or BoundPropertyAccess
+ or BoundIncrementOperator
+ or BoundCompoundAssignmentOperator)
{
return true;
}
@@ -8662,6 +8656,8 @@ private TypeWithState GetAdjustedResult(TypeWithState type, int slot)
private static Symbol AsMemberOfType(TypeSymbol? type, Symbol symbol)
{
Debug.Assert((object)symbol != null);
+ // https://github.com/dotnet/roslyn/issues/78828: This method should not be used with new extension members.
+ //Debug.Assert(!symbol.GetIsNewExtensionMember());
var containingType = type as NamedTypeSymbol;
if (containingType is null || containingType.IsErrorType() || symbol is ErrorMethodSymbol)
@@ -11586,25 +11582,28 @@ private void VisitForEachExpression(
MethodSymbol? reinferredGetEnumeratorMethod = null;
- if (enumeratorInfoOpt?.GetEnumeratorInfo is { Method: { IsExtensionMethod: true, Parameters: var parameters } } enumeratorMethodInfo) // Tracked by https://github.com/dotnet/roslyn/issues/78828: Test this code path with new extensions
+ if (enumeratorInfoOpt?.GetEnumeratorInfo is { } enumeratorMethodInfo
+ && (enumeratorMethodInfo.Method.IsExtensionMethod || enumeratorMethodInfo.Method.GetIsNewExtensionMember()))
{
// this is case 7
// We do not need to do this same analysis for non-extension methods because they do not have generic parameters that
// can be inferred from usage like extension methods can. We don't warn about default arguments at the call site, so
// there's nothing that can be learned from the non-extension case.
- var (method, results, _) = VisitArguments(
- node,
- enumeratorMethodInfo.Arguments,
+ (reinferredGetEnumeratorMethod, var results, _) = ReInferMethodAndVisitArguments(
+ node: node,
+ receiverOpt: expr,
+ receiverType: resultTypeWithState,
+ method: enumeratorMethodInfo.Method,
+ arguments: enumeratorMethodInfo.Arguments,
refKindsOpt: default,
- parameters,
argsToParamsOpt: default,
defaultArguments: enumeratorMethodInfo.DefaultArguments,
expanded: enumeratorMethodInfo.Expanded,
invokedAsExtensionMethod: true,
- enumeratorMethodInfo.Method);
+ suppressAdjustmentForNewExtension: false,
+ firstArgumentResult: _visitResult);
targetTypeWithAnnotations = results[0].LValueType;
- reinferredGetEnumeratorMethod = method;
}
else if (conversion.IsIdentity ||
(conversion.Kind == ConversionKind.ExplicitReference && resultType.SpecialType == SpecialType.System_String))
@@ -11633,12 +11632,14 @@ private void VisitForEachExpression(
{
// This is case 8. There was not a successful binding, as a successful binding will _always_ generate one of the
// above conversions. Just return, as we want to suppress further errors.
+ Debug.Assert(node.HasErrors);
return;
}
}
else
{
// This is also case 8.
+ Debug.Assert(node.HasErrors);
return;
}
@@ -11653,7 +11654,8 @@ private void VisitForEachExpression(
useLegacyWarnings: false,
AssignmentKind.Assignment);
- bool reportedDiagnostic = enumeratorInfoOpt?.GetEnumeratorInfo.Method is { IsExtensionMethod: true } // Tracked by https://github.com/dotnet/roslyn/issues/78828: Test this code path with new extensions
+ bool reportedDiagnostic = enumeratorInfoOpt?.GetEnumeratorInfo.Method is { } getEnumeratorMethod
+ && (getEnumeratorMethod.IsExtensionMethod || getEnumeratorMethod.GetIsNewExtensionMember())
? false
: CheckPossibleNullReceiver(expr);
diff --git a/src/roslyn/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs b/src/roslyn/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs
index e718340a931..3aa43a2359d 100644
--- a/src/roslyn/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs
+++ b/src/roslyn/src/Compilers/CSharp/Portable/Lowering/ExtensionMethodReferenceRewriter.cs
@@ -168,6 +168,8 @@ static RefKind argumentRefKindFromReceiverRefKind(RefKind receiverRefKind)
Debug.Assert(method?.GetIsNewExtensionMember() != true ||
method.OriginalDefinition.TryGetCorrespondingExtensionImplementationMethod() is null);
// All possibly interesting methods should go through VisitMethodSymbolWithExtensionRewrite first
+
+ /*
Debug.Assert(method is null ||
method.ContainingSymbol is not NamedTypeSymbol ||
method.MethodKind is (MethodKind.Constructor or MethodKind.StaticConstructor) ||
@@ -185,6 +187,7 @@ method.OriginalDefinition is ErrorMethodSymbol ||
{ Name: nameof(VisitMethodSymbolWithExtensionRewrite), DeclaringType: { } declaringType } => declaringType == typeof(ExtensionMethodReferenceRewriter),
_ => false
});
+ */
return base.VisitMethodSymbol(method);
}
diff --git a/src/roslyn/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/roslyn/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
index 0acffc55fc7..f873604e966 100644
--- a/src/roslyn/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
+++ b/src/roslyn/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
@@ -8630,7 +8630,7 @@ public static int Main()
CleanupAllGeneratedFiles(source);
}
- [Fact(), WorkItem(546025, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546025")]
+ [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79351"), WorkItem(546025, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546025")]
public void TestWin32ResWithBadResFile_CS1583ERR_BadWin32Res_01()
{
string source = Temp.CreateFile(prefix: "", extension: ".cs").WriteAllText(@"class Test { static void Main() {} }").Path;
diff --git a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
index 12429fe1f83..29e1df3a942 100644
--- a/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
+++ b/src/roslyn/src/Compilers/CSharp/Test/Emit3/Semantics/ExtensionTests.cs
@@ -13073,7 +13073,63 @@ static class E
Assert.Null(model.GetForEachStatementInfo(loop).CurrentProperty);
}
- [Fact]
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
+ public void InstanceMethodInvocation_PatternBased_ForEach_GetEnumerator_Conversion_Classic()
+ {
+ var src = """
+foreach (var x in new C())
+{
+ System.Console.Write(x);
+ break;
+}
+
+class C { }
+class D
+{
+ public bool MoveNext() => true;
+ public int Current => 42;
+}
+
+static class E
+{
+ public static D GetEnumerator(this object obj) => new D();
+}
+""";
+ var comp = CreateCompilation(src);
+ CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
+ public void Foreach_GetEnumerator_ReceiverNullableWarning()
+ {
+ var src = """
+#nullable enable
+
+foreach (var x in ((C?)null).Id()) // 1
+{
+}
+
+class C
+{
+ public C Id() => this;
+}
+
+static class E
+{
+ extension(C c)
+ {
+ public System.Collections.Generic.IEnumerator GetEnumerator() => throw null!;
+ }
+}
+""";
+ var comp = CreateCompilation(src);
+ comp.VerifyEmitDiagnostics(
+ // (3,20): warning CS8602: Dereference of a possibly null reference.
+ // foreach (var x in ((C?)null).Id()) // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(C?)null").WithLocation(3, 20));
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
public void InstanceMethodInvocation_PatternBased_ForEach_GetEnumerator_Conversion()
{
var src = """
@@ -13098,15 +13154,110 @@ static class E
}
}
""";
- try
- {
- // Tracked by https://github.com/dotnet/roslyn/issues/78828 : assertion in NullableWalker
- var comp = CreateCompilation(src);
- CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
- }
- catch (InvalidOperationException)
- {
- }
+ var comp = CreateCompilation(src);
+ CompileAndVerify(comp, expectedOutput: "42").VerifyDiagnostics();
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
+ public void ExtensionGetEnumerator_NullReceiver()
+ {
+ var src = """
+ #nullable enable
+ C? c = null;
+ foreach (var x in c) // 1
+ {
+ System.Console.Write(x);
+ break;
+ }
+
+ class C
+ {
+ }
+
+ static class E
+ {
+ extension(C c)
+ {
+ public System.Collections.Generic.IEnumerator GetEnumerator() => throw null!;
+ }
+ }
+ """;
+ var comp = CreateCompilation(src);
+ // Tracked by https://github.com/dotnet/roslyn/issues/78830 : diagnostic quality consider reporting a better containing symbol
+ comp.VerifyEmitDiagnostics(
+ // (3,19): warning CS8604: Possible null reference argument for parameter 'c' in 'extension(C)'.
+ // foreach (var x in c) // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c").WithArguments("c", "extension(C)").WithLocation(3, 19));
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
+ public void ExtensionGetEnumerator_NullReceiver_Classic()
+ {
+ var src = """
+ #nullable enable
+ C? c = null;
+ foreach (var x in c) // 1
+ {
+ System.Console.Write(x);
+ break;
+ }
+
+ class C
+ {
+ }
+
+ static class E
+ {
+ public static System.Collections.Generic.IEnumerator GetEnumerator(this C c) => throw null!;
+ }
+ """;
+ var comp = CreateCompilation(src);
+ comp.VerifyEmitDiagnostics(
+ // (3,19): warning CS8604: Possible null reference argument for parameter 'c' in 'IEnumerator E.GetEnumerator(C c)'.
+ // foreach (var x in c) // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceArgument, "c").WithArguments("c", "IEnumerator E.GetEnumerator(C c)").WithLocation(3, 19));
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78828")]
+ public void ExtensionGetEnumerator_Reinference()
+ {
+ var src = """
+ #nullable enable
+ var s = "a";
+ if (string.Empty == "")
+ s = null;
+
+ var c = M(s); // 'C'
+ foreach (var x in c)
+ {
+ x.ToString(); // 1
+ }
+
+ var d = M("a"); // 'C'
+ foreach (var x in d)
+ {
+ x.ToString(); // ok
+ }
+
+ C M(T item) => throw null!;
+
+ class C
+ {
+ }
+
+ static class E
+ {
+ extension(C c)
+ {
+ public System.Collections.Generic.IEnumerator GetEnumerator() => throw null!;
+ }
+ }
+ """;
+ var comp = CreateCompilation(src);
+ comp.VerifyEmitDiagnostics(
+ // (9,5): warning CS8602: Dereference of a possibly null reference.
+ // x.ToString(); // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(9, 5));
}
[Fact]
@@ -35643,7 +35794,7 @@ public static class Extensions
public C.Enumerator GetEnumerator(int x = 1) => new C.Enumerator(x);
}
}";
- var verifier = CompileAndVerify(source, expectedOutput: "23", parseOptions: TestOptions.RegularPreview.WithFeature("run-nullable-analysis", "never")); // Tracked by https://github.com/dotnet/roslyn/issues/78828: Nullable analysis asserts
+ var verifier = CompileAndVerify(source, expectedOutput: "23");
VerifyFlowGraphAndDiagnosticsForTest((CSharpCompilation)verifier.Compilation,
@"
@@ -42134,10 +42285,12 @@ public void Nullability_ForEach_01()
using System.Collections.Generic;
object? oNull = null;
-foreach (var x in oNull) { x.ToString(); }
+foreach (var x in oNull)
+ x.ToString(); // 1
object? oNotNull = new object();
-foreach (var y in oNotNull) { y.ToString(); }
+foreach (var y in oNotNull)
+ y.ToString();
static class E
{
@@ -42152,9 +42305,9 @@ public IEnumerator GetEnumerator()
""";
var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
- // (5,19): warning CS8602: Dereference of a possibly null reference.
- // foreach (var x in oNull) { x.ToString(); }
- Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "oNull").WithLocation(5, 19));
+ // (6,5): warning CS8602: Dereference of a possibly null reference.
+ // x.ToString(); // 1
+ Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(6, 5));
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
diff --git a/src/roslyn/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs b/src/roslyn/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs
index 95acc81fd07..f050cdf9b6e 100644
--- a/src/roslyn/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs
+++ b/src/roslyn/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs
@@ -45,10 +45,23 @@ public void WithXxx()
TestProperty((old, value) => old.WithLanguageVersion(value), opt => opt.LanguageVersion, LanguageVersion.CSharp3);
TestProperty((old, value) => old.WithDocumentationMode(value), opt => opt.DocumentationMode, DocumentationMode.None);
TestProperty((old, value) => old.WithPreprocessorSymbols(value), opt => opt.PreprocessorSymbols, ImmutableArray.Create("A", "B", "C"));
+ }
+
+ [Fact]
+ public void WithPreprocessorSymbols()
+ {
+ Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols(default(ImmutableArray)).PreprocessorSymbols.Length);
+ Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols((IEnumerable)null).PreprocessorSymbols.Length);
+ Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols((string[])null).PreprocessorSymbols.Length);
+ }
- Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols(default(ImmutableArray)).PreprocessorSymbols.Length);
- Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols((IEnumerable)null).PreprocessorSymbols.Length);
- Assert.Equal(0, CSharpParseOptions.Default.WithPreprocessorSymbols(ImmutableArray.Create("A", "B")).WithPreprocessorSymbols((string[])null).PreprocessorSymbols.Length);
+ [Fact]
+ public void WithFeatures()
+ {
+ var options1 = CSharpParseOptions.Default.WithFeatures(new Dictionary() { { "F1", "V1" }, { "F2", "V2" } });
+ var options2 = CSharpParseOptions.Default.WithFeatures(new Dictionary() { { "f2", "V2" }, { "F1", "V1" } });
+
+ Assert.True(options1.Equals(options2));
}
///
diff --git a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs
index a21427abe5c..201ce70c0cc 100644
--- a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs
+++ b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/AnalyzerAssemblyLoaderTests.cs
@@ -1160,7 +1160,7 @@ public void AssemblyLoading_MultipleVersions_MissingVersion(AnalyzerTestKind kin
/// Test the case where a utility is loaded by multiple analyzers at different versions. Ensure that no matter
/// what order we load the analyzers we correctly resolve the utility version.
///
- [Theory]
+ [ConditionalTheory(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79352")]
[CombinatorialData]
public void AssemblyLoading_MultipleVersions_AnalyzerDependency(AnalyzerTestKind kind, bool normalOrder)
{
diff --git a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs
index 546546ba3f6..e47630d984c 100644
--- a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs
+++ b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/CompilerResolverTests.cs
@@ -4,10 +4,12 @@
#if NET
using System;
+using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.CodeAnalysis.Test.Utilities;
+using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
@@ -16,7 +18,7 @@ namespace Microsoft.CodeAnalysis.UnitTests;
public sealed class CompilerResolverTests : IDisposable
{
public TempRoot TempRoot { get; }
- public int DefaultLoadContextCount { get; }
+ public ImmutableArray DefaultLoadContextAssemblies { get; }
public AssemblyLoadContext CompilerContext { get; }
public AssemblyLoadContext ScratchContext { get; }
public Assembly AssemblyInCompilerContext { get; }
@@ -25,7 +27,7 @@ public sealed class CompilerResolverTests : IDisposable
public CompilerResolverTests()
{
TempRoot = new TempRoot();
- DefaultLoadContextCount = AssemblyLoadContext.Default.Assemblies.Count();
+ DefaultLoadContextAssemblies = AssemblyLoadContext.Default.Assemblies.SelectAsArray(a => a.FullName);
CompilerContext = new AssemblyLoadContext(nameof(CompilerResolverTests), isCollectible: true);
AssemblyInCompilerContext = CompilerContext.LoadFromAssemblyPath(typeof(AnalyzerAssemblyLoader).Assembly.Location);
ScratchContext = new AssemblyLoadContext("Scratch", isCollectible: true);
@@ -35,7 +37,7 @@ public CompilerResolverTests()
public void Dispose()
{
// This test should not pollute the default load context and hence interfere with other tests.
- Assert.Equal(DefaultLoadContextCount, AssemblyLoadContext.Default.Assemblies.Count());
+ AssertEx.SetEqual(DefaultLoadContextAssemblies, AssemblyLoadContext.Default.Assemblies.SelectAsArray(a => a.FullName));
CompilerContext.Unload();
ScratchContext.Unload();
TempRoot.Dispose();
@@ -49,7 +51,7 @@ public void ResolveReturnsNullForNonHostAssembly()
Assert.Null(assembly);
}
- [Fact]
+ [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79352")]
public void ResolveReturnsForHostAssembly()
{
var assembly = Loader.CompilerAnalyzerAssemblyResolver.Resolve(Loader, AssemblyInCompilerContext.GetName(), ScratchContext, TempRoot.CreateDirectory().Path);
diff --git a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs
index a7879283bce..408434fc7e3 100644
--- a/src/roslyn/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs
+++ b/src/roslyn/src/Compilers/Core/CodeAnalysisTest/InvokeUtil.cs
@@ -63,7 +63,7 @@ internal void Exec(
}
var loader = new AnalyzerAssemblyLoader(pathResolvers, assemblyResolvers, compilerLoadContext: null);
- var compilerContextAssemblyCount = loader.CompilerLoadContext.Assemblies.Count();
+ var compilerContextAssemblies = loader.CompilerLoadContext.Assemblies.SelectAsArray(a => a.FullName);
try
{
Exec(testOutputHelper, fixture, loader, typeName, methodName, state);
@@ -72,7 +72,7 @@ internal void Exec(
{
// When using the actual compiler load context (the one shared by all of our unit tests) the test
// did not load any additional assemblies that could interfere with later tests.
- Assert.Equal(compilerContextAssemblyCount, loader.CompilerLoadContext.Assemblies.Count());
+ AssertEx.SetEqual(compilerContextAssemblies, loader.CompilerLoadContext.Assemblies.SelectAsArray(a => a.FullName));
}
}
@@ -89,7 +89,7 @@ internal void Exec(
// load into the compiler or directory load context.
//
// Not only is this bad behavior it also pollutes future test results.
- var defaultContextCount = AssemblyLoadContext.Default.Assemblies.Count();
+ var defaultContextAssemblies = AssemblyLoadContext.Default.Assemblies.SelectAsArray(a => a.FullName);
using var tempRoot = new TempRoot();
try
@@ -120,7 +120,7 @@ internal void Exec(
testOutputHelper.WriteLine($"\t{pair.OriginalAssemblyPath} -> {pair.ResolvedAssemblyPath}");
}
- Assert.Equal(defaultContextCount, AssemblyLoadContext.Default.Assemblies.Count());
+ AssertEx.SetEqual(defaultContextAssemblies, AssemblyLoadContext.Default.Assemblies.SelectAsArray(a => a.FullName));
}
}
}
diff --git a/src/roslyn/src/Compilers/Core/Portable/Compilation/ParseOptions.cs b/src/roslyn/src/Compilers/Core/Portable/Compilation/ParseOptions.cs
index 51aa13c8191..1e0377a8382 100644
--- a/src/roslyn/src/Compilers/Core/Portable/Compilation/ParseOptions.cs
+++ b/src/roslyn/src/Compilers/Core/Portable/Compilation/ParseOptions.cs
@@ -141,7 +141,7 @@ protected bool EqualsHelper([NotNullWhen(true)] ParseOptions? other)
return
this.SpecifiedKind == other.SpecifiedKind &&
this.DocumentationMode == other.DocumentationMode &&
- this.Features.SequenceEqual(other.Features) &&
+ FeaturesEqual(Features, other.Features) &&
(this.PreprocessorSymbolNames == null ? other.PreprocessorSymbolNames == null : this.PreprocessorSymbolNames.SequenceEqual(other.PreprocessorSymbolNames, StringComparer.Ordinal));
}
@@ -156,6 +156,29 @@ protected int GetHashCodeHelper()
Hash.Combine(Hash.CombineValues(this.PreprocessorSymbolNames, StringComparer.Ordinal), 0))));
}
+ private static bool FeaturesEqual(IReadOnlyDictionary features, IReadOnlyDictionary other)
+ {
+ if (ReferenceEquals(features, other))
+ {
+ return true;
+ }
+
+ if (features.Count != other.Count)
+ {
+ return false;
+ }
+
+ foreach (var (key, value) in features)
+ {
+ if (!other.TryGetValue(key, out var otherValue) || value != otherValue)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
private static int HashFeatures(IReadOnlyDictionary features)
{
int value = 0;
diff --git a/src/roslyn/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWithEvents.vb b/src/roslyn/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWithEvents.vb
index d72ff6403a9..3eed68c69a7 100644
--- a/src/roslyn/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWithEvents.vb
+++ b/src/roslyn/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenWithEvents.vb
@@ -10,7 +10,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
Public Class CodeGenWithEvents
Inherits BasicTestBase
-
+
Public Sub SimpleWithEventsTest()
Dim compilation1 = CompileAndVerify(
@@ -400,7 +400,7 @@ handled1
End Sub
-
+
Public Sub SimpleSharedWithEvents()
Dim compilation1 = CompileAndVerify(
@@ -2003,7 +2003,7 @@ End Class
CompileAndVerify(source)
End Sub
-
+
Public Sub MultipleInitializationsWithAsNew_01()
Dim source =
@@ -2067,7 +2067,7 @@ False
]]>)
End Sub
-
+
Public Sub MultipleInitializationsWithAsNew_02()
Dim source =
diff --git a/src/roslyn/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb b/src/roslyn/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb
index bcc4cbcb6bb..daec12f553a 100644
--- a/src/roslyn/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb
+++ b/src/roslyn/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Retargeting/RetargetingTests.vb
@@ -1962,7 +1962,7 @@ MethodOverload(Base)
End Sub
-
+
Public Sub Retarget_Events()
'The test involves compilation with/without retargeting and ensuring same behavior at runtime
'same diagnostics (or lack off) as compile time
diff --git a/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.DocumentActiveContextChangedEventSource.cs b/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.DocumentActiveContextChangedEventSource.cs
index ce3dc9480a1..ee02ce7ef6c 100644
--- a/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.DocumentActiveContextChangedEventSource.cs
+++ b/src/roslyn/src/EditorFeatures/Core/Shared/Tagging/EventSources/TaggerEventSources.DocumentActiveContextChangedEventSource.cs
@@ -13,8 +13,9 @@ private sealed class DocumentActiveContextChangedEventSource(ITextBuffer subject
{
private WorkspaceEventRegistration? _documentActiveContextChangedDisposer;
+ // Require main thread on the callback as RaiseChanged implementors may have main thread dependencies.
protected override void ConnectToWorkspace(Workspace workspace)
- => _documentActiveContextChangedDisposer = workspace.RegisterDocumentActiveContextChangedHandler(OnDocumentActiveContextChanged);
+ => _documentActiveContextChangedDisposer = workspace.RegisterDocumentActiveContextChangedHandler(OnDocumentActiveContextChanged, WorkspaceEventOptions.RequiresMainThreadOptions);
protected override void DisconnectFromWorkspace(Workspace workspace)
=> _documentActiveContextChangedDisposer?.Dispose();
diff --git a/src/roslyn/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs b/src/roslyn/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs
index 5bc6e17c726..1a8e1f613fe 100644
--- a/src/roslyn/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs
+++ b/src/roslyn/src/EditorFeatures/Core/Tagging/ITaggerEventSource.cs
@@ -41,7 +41,7 @@ internal interface ITaggerEventSource
///
/// An event has happened on the thing the tagger is attached to. The tagger should
- /// recompute tags. May be raised on any thread.
+ /// recompute tags.
///
event EventHandler Changed;
}
diff --git a/src/roslyn/src/EditorFeatures/XunitHook/XunitDisposeHook.cs b/src/roslyn/src/EditorFeatures/XunitHook/XunitDisposeHook.cs
index 96297521040..9aaf3668028 100644
--- a/src/roslyn/src/EditorFeatures/XunitHook/XunitDisposeHook.cs
+++ b/src/roslyn/src/EditorFeatures/XunitHook/XunitDisposeHook.cs
@@ -18,7 +18,7 @@ public void Execute()
if (!AppDomain.CurrentDomain.IsDefaultAppDomain())
throw new InvalidOperationException();
- var xunitUtilities = AppDomain.CurrentDomain.GetAssemblies().Where(static assembly => assembly.GetName().Name.StartsWith("xunit.runner.utility")).ToArray();
+ var xunitUtilities = AppDomain.CurrentDomain.GetAssemblies().Where(static assembly => assembly.GetName().Name.StartsWith("xunit.runner.visualstudio")).ToArray();
foreach (var xunitUtility in xunitUtilities)
{
var appDomainManagerType = xunitUtility.GetType("Xunit.AppDomainManager_AppDomain");
diff --git a/src/roslyn/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs b/src/roslyn/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
index 9794ced6bf2..13de4a97b56 100644
--- a/src/roslyn/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
+++ b/src/roslyn/src/Features/CSharp/Portable/EditAndContinue/CSharpEditAndContinueAnalyzer.cs
@@ -3074,4 +3074,29 @@ private static bool DeclareSameIdentifiers(SyntaxToken[] oldVariables, SyntaxTok
}
#endregion
+
+ protected override IEnumerable GetParseOptionsRudeEdits(ParseOptions oldOptions, ParseOptions newOptions)
+ {
+ foreach (var rudeEdit in base.GetParseOptionsRudeEdits(oldOptions, newOptions))
+ {
+ yield return rudeEdit;
+ }
+
+ var oldCSharpOptions = (CSharpParseOptions)oldOptions;
+ var newCSharpOptions = (CSharpParseOptions)newOptions;
+
+ if (oldCSharpOptions.LanguageVersion != newCSharpOptions.LanguageVersion)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.LangVersion,
+ oldCSharpOptions.SpecifiedLanguageVersion.ToDisplayString(),
+ newCSharpOptions.SpecifiedLanguageVersion.ToDisplayString());
+ }
+
+ if (!oldCSharpOptions.PreprocessorSymbolNames.SequenceEqual(newCSharpOptions.PreprocessorSymbolNames, StringComparer.Ordinal))
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.DefineConstants,
+ string.Join(",", oldCSharpOptions.PreprocessorSymbolNames),
+ string.Join(",", newCSharpOptions.PreprocessorSymbolNames));
+ }
+ }
}
diff --git a/src/roslyn/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs b/src/roslyn/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs
index 046a9fd0a91..fc37e62f148 100644
--- a/src/roslyn/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs
+++ b/src/roslyn/src/Features/CSharpTest/EditAndContinue/CSharpEditAndContinueAnalyzerTests.cs
@@ -368,8 +368,9 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId));
Assert.True(result.HasChanges);
- Assert.True(result.HasChangesAndErrors);
- Assert.True(result.HasChangesAndSyntaxErrors);
+ Assert.True(result.AnalysisBlocked);
+ Assert.NotNull(result.SyntaxError);
+ Assert.False(result.HasBlockingRudeEdits);
}
[Fact]
@@ -393,8 +394,9 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, oldDocument);
Assert.False(result.HasChanges);
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.AnalysisBlocked);
+ Assert.Null(result.SyntaxError);
+ Assert.False(result.HasBlockingRudeEdits);
}
[Fact]
@@ -430,8 +432,9 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId));
Assert.False(result.HasChanges);
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.AnalysisBlocked);
+ Assert.Null(result.SyntaxError);
+ Assert.False(result.HasBlockingRudeEdits);
}
[Fact]
@@ -462,8 +465,9 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, oldDocument);
Assert.False(result.HasChanges);
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.AnalysisBlocked);
+ Assert.False(result.HasBlockingRudeEdits);
+ Assert.Null(result.SyntaxError);
Assert.True(result.RudeEdits.IsEmpty);
}
@@ -510,8 +514,8 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId));
Assert.True(result.HasChanges);
- Assert.True(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.True(result.AnalysisBlocked);
+ Assert.False(result.HasBlockingRudeEdits);
Assert.Equal(RudeEditKind.ExperimentalFeaturesEnabled, result.RudeEdits.Single().Kind);
}
}
@@ -540,8 +544,9 @@ public static void Main()
var result = await AnalyzeDocumentAsync(oldProject, oldDocument);
Assert.False(result.HasChanges);
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.HasBlockingRudeEdits);
+ Assert.False(result.AnalysisBlocked);
+ Assert.Null(result.SyntaxError);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/10683")]
@@ -581,8 +586,9 @@ public static void Main()
Assert.True(result.HasChanges);
// no declaration errors (error in method body is only reported when emitting):
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.HasBlockingRudeEdits);
+ Assert.False(result.AnalysisBlocked);
+ Assert.Null(result.SyntaxError);
}
[Fact, WorkItem("https://github.com/dotnet/roslyn/issues/10683")]
@@ -621,8 +627,8 @@ public static void Main(Bar x)
// No errors reported: EnC analyzer is resilient against semantic errors.
// They will be reported by 1) compiler diagnostic analyzer 2) when emitting delta - if still present.
- Assert.False(result.HasChangesAndErrors);
- Assert.False(result.HasChangesAndSyntaxErrors);
+ Assert.False(result.AnalysisBlocked);
+ Assert.False(result.HasBlockingRudeEdits);
}
[Fact]
diff --git a/src/roslyn/src/Features/CSharpTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.cs b/src/roslyn/src/Features/CSharpTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.cs
new file mode 100644
index 00000000000..820dbc26a4f
--- /dev/null
+++ b/src/roslyn/src/Features/CSharpTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.cs
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
+using Microsoft.CodeAnalysis.ImplementInterface;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Roslyn.Test.Utilities;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.CSharp.UnitTests.ImplementInterface;
+
+using VerifyCS = CSharpCodeRefactoringVerifier<
+ ImplementInterfaceCodeRefactoringProvider>;
+
+[UseExportProvider]
+[Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
+public sealed class ImplementInterfaceCodeRefactoringTests
+{
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78294")]
+ public Task TestInBody()
+ => VerifyCS.VerifyRefactoringAsync("""
+ interface IGoo
+ {
+ void Goo();
+ }
+
+ class C : {|CS0535:IGoo|}
+ {
+ $$
+ }
+ """, """
+ interface IGoo
+ {
+ void Goo();
+ }
+
+ class C : IGoo
+ {
+ public void Goo()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+ """);
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/78294")]
+ public Task TestNotOnInterfaceInBody()
+ => VerifyCS.VerifyRefactoringAsync("""
+ interface IGoo
+ {
+ void Goo();
+ }
+
+ interface IBar : IGoo
+ {
+ $$
+ }
+ """);
+}
diff --git a/src/roslyn/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs b/src/roslyn/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs
index c6e7daf484e..47c3cd2a86a 100644
--- a/src/roslyn/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs
+++ b/src/roslyn/src/Features/Core/Portable/CodeRefactorings/PredefinedCodeRefactoringProviderNames.cs
@@ -47,6 +47,7 @@ internal static class PredefinedCodeRefactoringProviderNames
public const string GenerateConstructorFromMembers = "Generate Constructor From Members Code Action Provider";
public const string GenerateEqualsAndGetHashCodeFromMembers = "Generate Equals and GetHashCode Code Action Provider";
public const string GenerateOverrides = "Generate Overrides Code Action Provider";
+ public const string ImplementInterface = nameof(ImplementInterface);
public const string ImplementInterfaceExplicitly = nameof(ImplementInterfaceExplicitly);
public const string ImplementInterfaceImplicitly = nameof(ImplementInterfaceImplicitly);
public const string InitializeMemberFromParameter = nameof(InitializeMemberFromParameter);
diff --git a/src/roslyn/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs b/src/roslyn/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
index 9fbca617af8..62ccb84a89d 100644
--- a/src/roslyn/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
+++ b/src/roslyn/src/Features/Core/Portable/Diagnostics/CodeAnalysisDiagnosticAnalyzerService.cs
@@ -49,7 +49,9 @@ public CodeAnalysisDiagnosticAnalyzerService(
_workspace = workspace;
_diagnosticAnalyzerService = _workspace.Services.GetRequiredService();
- _ = workspace.RegisterWorkspaceChangedHandler(OnWorkspaceChanged);
+ // Main thread as OnWorkspaceChanged's call to IDiagnosticAnalyzerService.RequestDiagnosticRefresh isn't clear on
+ // threading requirements
+ _ = workspace.RegisterWorkspaceChangedHandler(OnWorkspaceChanged, WorkspaceEventOptions.RequiresMainThreadOptions);
}
private void OnWorkspaceChanged(WorkspaceChangeEventArgs e)
diff --git a/src/roslyn/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs b/src/roslyn/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
index 52e6bb235e3..77381fe91a7 100644
--- a/src/roslyn/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
+++ b/src/roslyn/src/Features/Core/Portable/Diagnostics/IDiagnosticAnalyzerService.cs
@@ -22,9 +22,6 @@ internal interface IDiagnosticAnalyzerService : IWorkspaceService
///
/// Re-analyze all projects and documents. This will cause an LSP diagnostic refresh request to be sent.
///
- ///
- /// This implementation must be safe to call on any thread.
- ///
void RequestDiagnosticRefresh();
///
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
index 9e6c0d9456a..c2630e369f7 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/AbstractEditAndContinueAnalyzer.cs
@@ -561,7 +561,7 @@ public async Task AnalyzeDocumentAsync(
// Bail, since we can't do syntax diffing on broken trees (it would not produce useful results anyways).
// If we needed to do so for some reason, we'd need to harden the syntax tree comparers.
log.Write($"Syntax errors found in '{filePath}'");
- return DocumentAnalysisResults.SyntaxErrors(documentId, filePath, [], syntaxError, analysisStopwatch.Elapsed, hasChanges);
+ return DocumentAnalysisResults.Blocked(documentId, filePath, [], syntaxError, analysisStopwatch.Elapsed, hasChanges);
}
// Disallow modification of a file with experimental features enabled.
@@ -569,7 +569,21 @@ public async Task AnalyzeDocumentAsync(
if (ExperimentalFeaturesEnabled(newTree))
{
log.Write($"Experimental features enabled in '{filePath}'");
- return DocumentAnalysisResults.SyntaxErrors(documentId, filePath, [new RudeEditDiagnostic(RudeEditKind.ExperimentalFeaturesEnabled, default)], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
+ return DocumentAnalysisResults.Blocked(documentId, filePath, [new RudeEditDiagnostic(RudeEditKind.ExperimentalFeaturesEnabled, span: default)], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
+ }
+
+ // Changes in parse options might change the meaning of the code even if nothing else changed.
+ // If we allowed changing parse options such as preprocessor directives, enabled features, or language version
+ // it would lead to degraded experience for the user -- the parts of the source file that haven't changed
+ // since the option changed would have different semantics than the parts that have changed.
+ //
+ // Skip further analysis of the document if we detect any such change (classified as rude edits) in parse options.
+ if (GetParseOptionsRudeEdits(oldTree.Options, newTree.Options).Any())
+ {
+ log.Write($"Parse options differ for '{filePath}'");
+
+ // All rude edits related to project-level setting changes will be reported during delta emit.
+ return DocumentAnalysisResults.Blocked(documentId, filePath, rudeEdits: [], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
}
var capabilities = new EditAndContinueCapabilitiesGrantor(await lazyCapabilities.GetValueAsync(cancellationToken).ConfigureAwait(false));
@@ -578,14 +592,9 @@ public async Task AnalyzeDocumentAsync(
// If the document has changed at all, lets make sure Edit and Continue is supported
if (!capabilities.Grant(EditAndContinueCapabilities.Baseline))
{
- return DocumentAnalysisResults.SyntaxErrors(documentId, filePath, [new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
+ return DocumentAnalysisResults.Blocked(documentId, filePath, [new RudeEditDiagnostic(RudeEditKind.NotSupportedByRuntime, default)], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
}
- // TODO: https://github.com/dotnet/roslyn/issues/78486
- // Changes in parse options might change the meaning of the code even if nothing else changed.
- // The IDE should disallow changing the options during debugging session.
- Debug.Assert(oldTree.Options.Equals(newTree.Options));
-
// We are in break state when there are no active statements.
var inBreakState = !oldActiveStatementMap.IsEmpty;
@@ -681,7 +690,7 @@ public async Task AnalyzeDocumentAsync(
hasBlockingRudeEdits ? default : capabilities.GrantedCapabilities,
analysisStopwatch.Elapsed,
hasChanges: true,
- hasSyntaxErrors: false,
+ analysisBlocked: false,
hasBlockingRudeEdits);
}
catch (Exception e) when (FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken))
@@ -694,8 +703,7 @@ public async Task AnalyzeDocumentAsync(
? new RudeEditDiagnostic(RudeEditKind.SourceFileTooBig, span: default, arguments: [filePath])
: new RudeEditDiagnostic(RudeEditKind.InternalError, span: default, arguments: [filePath, e.ToString()]);
- // Report as "syntax error" - we can't analyze the document
- return DocumentAnalysisResults.SyntaxErrors(documentId, filePath, [diagnostic], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
+ return DocumentAnalysisResults.Blocked(documentId, filePath, [diagnostic], syntaxError: null, analysisStopwatch.Elapsed, hasChanges);
}
void LogRudeEdits(ImmutableArray diagnostics, SourceText text, string filePath)
@@ -817,6 +825,117 @@ internal Dictionary BuildEditMap(EditScript ed
return map;
}
+ protected static Diagnostic CreateProjectRudeEdit(ProjectSettingKind kind, string oldValue, string newValue)
+ => Diagnostic.Create(
+ EditAndContinueDiagnosticDescriptors.GetDescriptor(kind),
+ Location.None,
+ [kind.ToString(), oldValue, newValue]);
+
+ protected virtual IEnumerable GetParseOptionsRudeEdits(ParseOptions oldOptions, ParseOptions newOptions)
+ {
+ if (!FeaturesEqual(oldOptions.Features, newOptions.Features))
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.Features, ToDisplay(oldOptions.Features), ToDisplay(newOptions.Features));
+ }
+
+ static string ToDisplay(IReadOnlyDictionary features)
+ => string.Join(",", features.OrderBy(kvp => kvp.Key).Select(kvp => $"{kvp.Key}={kvp.Value}"));
+
+ static bool FeaturesEqual(IReadOnlyDictionary features, IReadOnlyDictionary other)
+ {
+ if (ReferenceEquals(features, other))
+ {
+ return true;
+ }
+
+ if (features.Count != other.Count)
+ {
+ return false;
+ }
+
+ foreach (var (key, value) in features)
+ {
+ if (!other.TryGetValue(key, out var otherValue) || value != otherValue)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ protected static string DefaultProjectSettingValue
+ => $"<{FeaturesResources.@default}>";
+
+ protected virtual IEnumerable GetCompilationOptionsRudeEdits(CompilationOptions oldOptions, CompilationOptions newOptions)
+ {
+ if (oldOptions.CheckOverflow != newOptions.CheckOverflow)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.CheckForOverflowUnderflow, oldOptions.CheckOverflow.ToString(), newOptions.CheckOverflow.ToString());
+ }
+
+ if (oldOptions.OutputKind != newOptions.OutputKind)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.OutputType, ToProjectPropertyValue(oldOptions.OutputKind), ToProjectPropertyValue(newOptions.OutputKind));
+
+ static string ToProjectPropertyValue(OutputKind kind)
+ => kind switch
+ {
+ OutputKind.ConsoleApplication => "Exe",
+ OutputKind.WindowsApplication => "WinExe",
+ OutputKind.DynamicallyLinkedLibrary => "Library",
+ OutputKind.NetModule => "Module",
+ OutputKind.WindowsRuntimeApplication => "AppContainerExe",
+ OutputKind.WindowsRuntimeMetadata => "WinMDObj",
+ _ => throw ExceptionUtilities.UnexpectedValue(kind)
+ };
+ }
+
+ if (oldOptions.Platform != newOptions.Platform)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.Platform, oldOptions.Platform.ToString(), newOptions.Platform.ToString());
+ }
+
+ if (oldOptions.MainTypeName != newOptions.MainTypeName)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.StartupObject, oldOptions.MainTypeName ?? DefaultProjectSettingValue, newOptions.MainTypeName ?? DefaultProjectSettingValue);
+ }
+
+ if (oldOptions.ModuleName != newOptions.ModuleName)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.ModuleAssemblyName, oldOptions.ModuleName ?? DefaultProjectSettingValue, newOptions.ModuleName ?? DefaultProjectSettingValue);
+ }
+
+ if (oldOptions.OptimizationLevel != newOptions.OptimizationLevel)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.OptimizationLevel, oldOptions.OptimizationLevel.ToString(), newOptions.OptimizationLevel.ToString());
+ }
+ }
+
+ public IEnumerable GetProjectSettingRudeEdits(Project oldProject, Project newProject)
+ {
+ Contract.ThrowIfNull(oldProject.ParseOptions);
+ Contract.ThrowIfNull(newProject.ParseOptions);
+ Contract.ThrowIfNull(oldProject.CompilationOptions);
+ Contract.ThrowIfNull(newProject.CompilationOptions);
+
+ foreach (var rudeEdit in GetParseOptionsRudeEdits(oldProject.ParseOptions, newProject.ParseOptions))
+ {
+ yield return rudeEdit;
+ }
+
+ foreach (var rudeEdit in GetCompilationOptionsRudeEdits(oldProject.CompilationOptions, newProject.CompilationOptions))
+ {
+ yield return rudeEdit;
+ }
+
+ if (oldProject.AssemblyName != newProject.AssemblyName)
+ {
+ yield return CreateProjectRudeEdit(ProjectSettingKind.AssemblyName, oldProject.AssemblyName, newProject.AssemblyName);
+ }
+ }
+
#endregion
#region Syntax Analysis
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
index 5bbc2faf124..2cf51f34fb9 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSession.cs
@@ -12,6 +12,7 @@
using System.Reflection.Metadata;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Contracts.EditAndContinue;
using Microsoft.CodeAnalysis.Debugging;
using Microsoft.CodeAnalysis.Emit;
@@ -331,6 +332,18 @@ internal ImmutableList GetOrCreateEmitBaselines(
return [];
}
+ // It is possible to compile a project with assembly references that have
+ // the same name but different versions, cultures, or public key tokens,
+ // although the SDK targets prevent such references in practice.
+ var initiallyReferencedAssemblies = ImmutableDictionary.CreateBuilder>();
+
+ foreach (var identity in baselineCompilation.ReferencedAssemblyNames)
+ {
+ initiallyReferencedAssemblies[identity.Name] = initiallyReferencedAssemblies.TryGetValue(identity.Name, out var value)
+ ? value.Add(identity)
+ : OneOrMany.Create(identity);
+ }
+
lock (_projectEmitBaselinesGuard)
{
if (TryGetBaselinesContainingModuleVersion(moduleId, out existingBaselines))
@@ -340,7 +353,7 @@ internal ImmutableList GetOrCreateEmitBaselines(
return existingBaselines;
}
- var newBaseline = new ProjectBaseline(moduleId, baselineProject.Id, initialBaseline, generation: 0);
+ var newBaseline = new ProjectBaseline(moduleId, baselineProject.Id, initialBaseline, initiallyReferencedAssemblies.ToImmutableDictionary(), generation: 0);
var baselines = (existingBaselines ?? []).Add(newBaseline);
_projectBaselines[baselineProject.Id] = baselines;
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
index 30ea313eb36..6790b42ebf1 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DebuggingSessionTelemetry.cs
@@ -96,14 +96,18 @@ public static void Log(Data data, Action log, Func
map[SessionId] = debugSessionId;
map[EditSessionId] = editSessionId;
- map["HadCompilationErrors"] = editSessionData.HadCompilationErrors;
- map["HadRudeEdits"] = editSessionData.HadRudeEdits;
+ // Syntax errors
+ map["HadCompilationErrors"] = editSessionData.HasSyntaxErrors;
+
+ // Blocking rude edits
+ map["HadRudeEdits"] = editSessionData.HadBlockingRudeEdits;
// Changes made to source code during the edit session were valid - they were significant and no rude edits were reported.
// The changes still might fail to emit (see EmitDeltaErrorIdCount).
map["HadValidChanges"] = editSessionData.HadValidChanges;
map["HadValidInsignificantChanges"] = editSessionData.HadValidInsignificantChanges;
+ // all rude edits (errors and warnings)
map["RudeEditsCount"] = editSessionData.RudeEdits.Length;
// Number of emit errors. These are any errors only produced during emitting deltas and do not include document analysis errors.
@@ -149,7 +153,7 @@ public static void Log(Data data, Action log, Func
map["RudeEditKind"] = editKind;
map["RudeEditSyntaxKind"] = syntaxKind;
- map["RudeEditBlocking"] = editSessionData.HadRudeEdits;
+ map["RudeEditBlocking"] = editSessionData.HadBlockingRudeEdits;
map["RudeEditProjectId"] = ProjectIdToPii(projectId);
}));
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs
index ff62953f3d4..7e834af88f4 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/DocumentAnalysisResults.cs
@@ -36,7 +36,7 @@ internal sealed class DocumentAnalysisResults
public ImmutableArray RudeEdits { get; }
///
- /// The first syntax error, or null if the document does not have syntax errors reported by the compiler.
+ /// The first syntax error, if the document and a syntax error. Null otherwise.
///
public Diagnostic? SyntaxError { get; }
@@ -90,9 +90,9 @@ internal sealed class DocumentAnalysisResults
public TimeSpan ElapsedTime { get; }
///
- /// Document contains errors that block EnC analysis.
+ /// True if the document and contains errors that block EnC analysis.
///
- public bool HasSyntaxErrors { get; }
+ public bool AnalysisBlocked { get; }
///
/// Document contains changes.
@@ -116,13 +116,13 @@ public DocumentAnalysisResults(
EditAndContinueCapabilities requiredCapabilities,
TimeSpan elapsedTime,
bool hasChanges,
- bool hasSyntaxErrors,
+ bool analysisBlocked,
bool hasBlockingRudeEdits)
{
Debug.Assert(!rudeEdits.IsDefault);
Debug.Assert(hasBlockingRudeEdits == (!rudeEdits.IsDefault && rudeEdits.HasBlockingRudeEdits()));
- if (hasSyntaxErrors || !hasChanges)
+ if (analysisBlocked || !hasChanges)
{
Debug.Assert(activeStatementsOpt.IsDefault);
Debug.Assert(semanticEditsOpt.IsDefault);
@@ -171,24 +171,18 @@ public DocumentAnalysisResults(
LineEdits = lineEditsOpt;
RequiredCapabilities = requiredCapabilities;
ElapsedTime = elapsedTime;
- HasSyntaxErrors = hasSyntaxErrors;
+ AnalysisBlocked = analysisBlocked;
HasChanges = hasChanges;
HasBlockingRudeEdits = hasBlockingRudeEdits;
}
- public bool HasChangesAndErrors
- => HasChanges && (HasSyntaxErrors || HasBlockingRudeEdits);
-
- public bool HasChangesAndSyntaxErrors
- => HasChanges && HasSyntaxErrors;
-
public bool HasSignificantValidChanges
=> HasChanges && (!SemanticEdits.IsDefaultOrEmpty || !LineEdits.IsDefaultOrEmpty);
///
/// Report errors blocking the document analysis.
///
- public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, string filePath, ImmutableArray rudeEdits, Diagnostic? syntaxError, TimeSpan elapsedTime, bool hasChanges)
+ public static DocumentAnalysisResults Blocked(DocumentId documentId, string filePath, ImmutableArray rudeEdits, Diagnostic? syntaxError, TimeSpan elapsedTime, bool hasChanges)
=> new(
documentId,
filePath,
@@ -201,7 +195,7 @@ public static DocumentAnalysisResults SyntaxErrors(DocumentId documentId, string
EditAndContinueCapabilities.None,
elapsedTime,
hasChanges,
- hasSyntaxErrors: true,
+ analysisBlocked: true,
hasBlockingRudeEdits: !rudeEdits.IsEmpty);
///
@@ -220,6 +214,6 @@ public static DocumentAnalysisResults Unchanged(DocumentId documentId, string fi
EditAndContinueCapabilities.None,
elapsedTime,
hasChanges: false,
- hasSyntaxErrors: false,
+ analysisBlocked: false,
hasBlockingRudeEdits: false);
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs
index 42ff3017dc2..f78ebea1454 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueDiagnosticDescriptors.cs
@@ -78,6 +78,16 @@ void AddRudeEdit(RudeEditKind kind, string resourceName, DiagnosticSeverity seve
void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, DiagnosticSeverity severity = DiagnosticSeverity.Error, bool noEffect = false)
=> Add(GetDescriptorIndex(code), GeneralDiagnosticIdPrefix, (int)code, resourceName, s_encLocString, severity, noEffect);
+ void AddProjectRudeEdit(ProjectSettingKind kind)
+ {
+ var code = EditAndContinueErrorCode.ChangingProjectSettingBase + (int)kind;
+ var resourceName = nameof(FeaturesResources.Changing_project_setting_0_from_1_to_2_requires_restarting_the_application);
+ var noEffect = kind.IsWarning();
+ var severity = noEffect ? DiagnosticSeverity.Warning : DiagnosticSeverity.Error;
+
+ Add(GetDescriptorIndex(code), GeneralDiagnosticIdPrefix, (int)code, resourceName, s_encLocString, severity, noEffect);
+ }
+
//
// rude edits
//
@@ -189,6 +199,20 @@ void AddGeneralDiagnostic(EditAndContinueErrorCode code, string resourceName, Di
AddGeneralDiagnostic(EditAndContinueErrorCode.AddingTypeRuntimeCapabilityRequired, nameof(FeaturesResources.ChangesRequiredSynthesizedType));
AddGeneralDiagnostic(EditAndContinueErrorCode.UpdatingDocumentInStaleProject, nameof(FeaturesResources.Changing_source_file_0_in_a_stale_project_has_no_effect_until_the_project_is_rebuit), DiagnosticSeverity.Warning, noEffect: true);
+ // Project setting rude edits. Defines a distinct error code per setting to simplify telemetry tracking even though some errors share the same message.
+
+ AddGeneralDiagnostic(EditAndContinueErrorCode.ChangingMultiVersionReferences, nameof(FeaturesResources.Project_references_mutliple_assemblies_of_the_same_simple_name_0_1_Changing_a_reference_to_such_an_assembly_requires_restarting_the_application));
+ AddGeneralDiagnostic(EditAndContinueErrorCode.ChangingReference, nameof(FeaturesResources.Changing_project_or_package_reference_caused_the_identity_of_referenced_assembly_to_change_from_0_to_1_which_requires_restarting_the_application));
+
+#if NET
+ foreach (var value in Enum.GetValues())
+#else
+ foreach (ProjectSettingKind value in Enum.GetValues(typeof(ProjectSettingKind)))
+#endif
+ {
+ AddProjectRudeEdit(value);
+ }
+
s_descriptors = builder.ToImmutable();
s_noEffectDiagnosticIds = noEffectDiagnosticIds.ToImmutable();
}
@@ -199,6 +223,9 @@ internal static ImmutableArray GetDescriptors()
internal static DiagnosticDescriptor GetDescriptor(RudeEditKind kind)
=> s_descriptors[GetDescriptorIndex(kind)];
+ internal static DiagnosticDescriptor GetDescriptor(ProjectSettingKind kind)
+ => s_descriptors[GetDescriptorIndex(kind)];
+
internal static DiagnosticDescriptor GetDescriptor(EditAndContinueErrorCode errorCode)
=> s_descriptors[GetDescriptorIndex(errorCode)];
@@ -236,6 +263,9 @@ private static string GetDiagnosticId(ManagedHotReloadAvailabilityStatus status)
private static int GetDescriptorIndex(RudeEditKind kind)
=> (int)kind;
+ private static int GetDescriptorIndex(ProjectSettingKind kind)
+ => GetDescriptorIndex(EditAndContinueErrorCode.ChangingProjectSettingBase + (int)kind);
+
private static int GetDescriptorIndex(EditAndContinueErrorCode errorCode)
=> s_generalDiagnosticBaseIndex + (int)errorCode;
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueErrorCode.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueErrorCode.cs
index 95b7aa239ff..481f46e5bb7 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueErrorCode.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditAndContinueErrorCode.cs
@@ -14,4 +14,13 @@ internal enum EditAndContinueErrorCode
UnableToReadSourceFileOrPdb = 6,
AddingTypeRuntimeCapabilityRequired = 7,
UpdatingDocumentInStaleProject = 8,
+
+ ChangingMultiVersionReferences = 98,
+ ChangingReference = 99,
+
+ ///
+ /// Base code for project setting rude edits.
+ /// is added to this value.
+ ///
+ ChangingProjectSettingBase = 100,
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSession.cs
index e0f2065908a..3d538d5aadb 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSession.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSession.cs
@@ -11,6 +11,7 @@
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Contracts.EditAndContinue;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.ErrorReporting;
@@ -154,8 +155,6 @@ public TraceLog Log
/// Non-null diagnostic id if the module blocks EnC operation.
public async Task ReportModuleDiagnosticsAsync(Guid mvid, Project oldProject, Project newProject, ImmutableArray documentAnalyses, ArrayBuilder diagnostics, CancellationToken cancellationToken)
{
- Contract.ThrowIfTrue(documentAnalyses.IsEmpty);
-
var availability = await DebuggingSession.DebuggerService.GetAvailabilityAsync(mvid, cancellationToken).ConfigureAwait(false);
if (availability.Status is ManagedHotReloadAvailabilityStatus.ModuleNotLoaded or ManagedHotReloadAvailabilityStatus.Available)
{
@@ -200,7 +199,7 @@ private static async IAsyncEnumerable CreateChangedLocationsAsync(Proj
}
// project location:
- if (hasRemovedOrAddedDocument)
+ if (hasRemovedOrAddedDocument || documentAnalyses.IsEmpty)
{
yield return Location.None;
}
@@ -291,7 +290,7 @@ public static async ValueTask HasChangesAsync(Solution oldSolution, Soluti
}
var oldProject = oldSolution.GetProject(newProject.Id);
- if (oldProject == null || await HasDocumentDifferencesAsync(oldProject, newProject, documentDifferences: null, cancellationToken).ConfigureAwait(false))
+ if (oldProject == null || await HasDifferencesAsync(oldProject, newProject, differences: null, cancellationToken).ConfigureAwait(false))
{
// project added or has changes
return true;
@@ -332,7 +331,7 @@ private static async ValueTask ContentEqualsAsync(TextDocument oldDocument
return oldSource.ContentEquals(newSource);
}
- internal static async ValueTask HasDocumentDifferencesAsync(Project oldProject, Project newProject, ProjectDocumentDifferences? documentDifferences, CancellationToken cancellationToken)
+ internal static async ValueTask HasDifferencesAsync(Project oldProject, Project newProject, ProjectDifferences? differences, CancellationToken cancellationToken)
{
if (!newProject.SupportsEditAndContinue())
{
@@ -357,12 +356,12 @@ internal static async ValueTask HasDocumentDifferencesAsync(Project oldPro
continue;
}
- if (!documentDifferences.HasValue)
+ if (differences == null)
{
return true;
}
- documentDifferences.Value.ChangedOrAdded.Add(document);
+ differences.Value.ChangedOrAddedDocuments.Add(document);
}
foreach (var documentId in newProject.State.DocumentStates.GetAddedStateIds(oldProject.State.DocumentStates))
@@ -373,12 +372,12 @@ internal static async ValueTask HasDocumentDifferencesAsync(Project oldPro
continue;
}
- if (!documentDifferences.HasValue)
+ if (differences == null)
{
return true;
}
- documentDifferences.Value.ChangedOrAdded.Add(document);
+ differences.Value.ChangedOrAddedDocuments.Add(document);
}
foreach (var documentId in newProject.State.DocumentStates.GetRemovedStateIds(oldProject.State.DocumentStates))
@@ -389,18 +388,21 @@ internal static async ValueTask HasDocumentDifferencesAsync(Project oldPro
continue;
}
- if (!documentDifferences.HasValue)
+ if (differences == null)
{
return true;
}
- documentDifferences.Value.Deleted.Add(document);
+ differences.Value.DeletedDocuments.Add(document);
}
- // Any changes in non-generated document content might affect source generated documents as well,
- // no need to check further in that case.
+ // The following will check for any changes in non-generated document content (editorconfig, additional docs).
+ // If we already have changes and we are collecting document differences, we don't need to check for these as
+ // tey do not contribute directly to changed documents. They may trigger changes in source-generated documents though, so
+ // if we are not collecting differences and no changes have been observed so far (if they were we would have returned above),
+ // we need to check for changes in editorconfig and additional documents.
- if (documentDifferences?.Any() == true)
+ if (differences?.Any() == true)
{
return true;
}
@@ -434,11 +436,11 @@ internal static async ValueTask HasDocumentDifferencesAsync(Project oldPro
return false;
}
- internal static async Task GetDocumentDifferencesAsync(TraceLog log, Project oldProject, Project newProject, ProjectDocumentDifferences documentDifferences, ArrayBuilder diagnostics, CancellationToken cancellationToken)
+ internal static async Task GetProjectDifferencesAsync(TraceLog log, Project oldProject, Project newProject, ProjectDifferences documentDifferences, ArrayBuilder diagnostics, CancellationToken cancellationToken)
{
documentDifferences.Clear();
- if (!await HasDocumentDifferencesAsync(oldProject, newProject, documentDifferences, cancellationToken).ConfigureAwait(false))
+ if (!await HasDifferencesAsync(oldProject, newProject, documentDifferences, cancellationToken).ConfigureAwait(false))
{
return;
}
@@ -457,7 +459,7 @@ internal static async Task GetDocumentDifferencesAsync(TraceLog log, Project old
continue;
}
- documentDifferences.ChangedOrAdded.Add(newProject.GetOrCreateSourceGeneratedDocument(newState));
+ documentDifferences.ChangedOrAddedDocuments.Add(newProject.GetOrCreateSourceGeneratedDocument(newState));
}
foreach (var documentId in newSourceGeneratedDocumentStates.GetAddedStateIds(oldSourceGeneratedDocumentStates))
@@ -468,7 +470,7 @@ internal static async Task GetDocumentDifferencesAsync(TraceLog log, Project old
continue;
}
- documentDifferences.ChangedOrAdded.Add(newProject.GetOrCreateSourceGeneratedDocument(newState));
+ documentDifferences.ChangedOrAddedDocuments.Add(newProject.GetOrCreateSourceGeneratedDocument(newState));
}
foreach (var documentId in newSourceGeneratedDocumentStates.GetRemovedStateIds(oldSourceGeneratedDocumentStates))
@@ -479,7 +481,7 @@ internal static async Task GetDocumentDifferencesAsync(TraceLog log, Project old
continue;
}
- documentDifferences.Deleted.Add(oldProject.GetOrCreateSourceGeneratedDocument(oldState));
+ documentDifferences.DeletedDocuments.Add(oldProject.GetOrCreateSourceGeneratedDocument(oldState));
}
}
@@ -545,9 +547,9 @@ internal static async IAsyncEnumerable GetChangedDocumentsAsync(Trac
}
}
- private async Task<(ImmutableArray results, bool hasOutOfSyncDocument)> AnalyzeDocumentsAsync(
+ private async Task<(ImmutableArray results, bool hasOutOfSyncDocument)> AnalyzeProjectDifferencesAsync(
Solution newSolution,
- ProjectDocumentDifferences documentDifferences,
+ ProjectDifferences differences,
ActiveStatementSpanProvider newDocumentActiveStatementSpanProvider,
ArrayBuilder diagnostics,
CancellationToken cancellationToken)
@@ -555,7 +557,7 @@ internal static async IAsyncEnumerable GetChangedDocumentsAsync(Trac
using var _ = ArrayBuilder<(Document? oldDocument, Document? newDocument)>.GetInstance(out var documents);
var hasOutOfSyncDocument = false;
- foreach (var newDocument in documentDifferences.ChangedOrAdded)
+ foreach (var newDocument in differences.ChangedOrAddedDocuments)
{
var (oldDocument, oldDocumentState) = await DebuggingSession.LastCommittedSolution.GetDocumentAndStateAsync(newDocument, cancellationToken, reloadOutOfSyncDocument: true).ConfigureAwait(false);
switch (oldDocumentState)
@@ -587,7 +589,7 @@ internal static async IAsyncEnumerable GetChangedDocumentsAsync(Trac
}
}
- foreach (var oldDocument in documentDifferences.Deleted)
+ foreach (var oldDocument in differences.DeletedDocuments)
{
documents.Add((oldDocument, newDocument: null));
}
@@ -614,15 +616,9 @@ private static ProjectAnalysisSummary GetProjectAnalysisSummary(ImmutableArray diagnostics)
+ {
+ Contract.ThrowIfFalse(oldProject.Language == newProject.Language);
+
+ var analyzer = newProject.GetRequiredLanguageService();
+
+ var hasBlockingRudeEdit = false;
+
+ foreach (var diagnostic in analyzer.GetProjectSettingRudeEdits(oldProject, newProject))
+ {
+ hasBlockingRudeEdit |= diagnostic.Severity == DiagnosticSeverity.Error;
+ diagnostics.Add(diagnostic);
+ }
+
+ return hasBlockingRudeEdit;
+ }
+
+ private static bool HasReferenceRudeEdits(ImmutableDictionary> oldReferencedAssemblies, Compilation newCompilation, ArrayBuilder projectDiagnostics)
+ {
+ var hasRudeEdit = false;
+
+ foreach (var newReference in newCompilation.ReferencedAssemblyNames)
+ {
+ if (oldReferencedAssemblies.TryGetValue(newReference.Name, out var oldReferences))
+ {
+ if (oldReferences.Contains(newReference))
+ {
+ // found exact match
+ continue;
+ }
+
+ hasRudeEdit = true;
+
+ if (oldReferences.Count > 1)
+ {
+ // For simplicity we disallow changing references to assembly references that don't have unique simple name.
+ // This case should be very rare in practice.
+
+ projectDiagnostics.Add(Diagnostic.Create(
+ EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ChangingMultiVersionReferences),
+ Location.None,
+ [newReference.Name, string.Join(", ", oldReferences.ToImmutable().Select(static r => $"'{r}'"))]));
+
+ break;
+ }
+
+ // Reference identity changed.
+
+ projectDiagnostics.Add(Diagnostic.Create(
+ EditAndContinueDiagnosticDescriptors.GetDescriptor(EditAndContinueErrorCode.ChangingReference),
+ Location.None,
+ [oldReferences[0].ToString(), newReference.ToString()]));
+ }
+ }
+
+ return hasRudeEdit;
+ }
+
internal static async ValueTask GetProjectChangesAsync(
ActiveStatementsMap baseActiveStatements,
Compilation oldCompilation,
@@ -668,9 +722,6 @@ internal static async ValueTask GetProjectChangesAsync(
continue;
}
- // we shouldn't be asking for deltas in presence of errors:
- Contract.ThrowIfTrue(analysis.HasChangesAndErrors);
-
// Active statements are calculated if document changed and has no syntax errors:
Contract.ThrowIfTrue(analysis.ActiveStatements.IsDefault);
@@ -851,14 +902,14 @@ public async ValueTask EmitSolutionUpdateAsync(
using var _3 = ArrayBuilder.GetInstance(out var newProjectBaselines);
using var _4 = ArrayBuilder.GetInstance(out var projectsToStale);
using var _5 = PooledDictionary>.GetInstance(out var diagnosticBuilders);
- using var documentDifferences = new ProjectDocumentDifferences();
+ using var projectDifferences = new ProjectDifferences();
// After all projects have been analyzed "true" value indicates changed document that is only included in stale projects.
var changedDocumentsStaleness = new Dictionary(SolutionState.FilePathComparer);
void UpdateChangedDocumentsStaleness(bool isStale)
{
- foreach (var changedDocument in documentDifferences.ChangedOrAdded)
+ foreach (var changedDocument in projectDifferences.ChangedOrAddedDocuments)
{
var path = changedDocument.FilePath;
@@ -877,6 +928,7 @@ void UpdateChangedDocumentsStaleness(bool isStale)
}
Diagnostic? syntaxError = null;
+ ProjectAnalysisSummary? projectSummaryToReport = null;
var oldSolution = DebuggingSession.LastCommittedSolution;
@@ -909,15 +961,22 @@ void UpdateChangedDocumentsStaleness(bool isStale)
continue;
}
- projectDiagnostics = ArrayBuilder.GetInstance();
+ Debug.Assert(oldProject.SupportsEditAndContinue());
- await GetDocumentDifferencesAsync(Log, oldProject, newProject, documentDifferences, projectDiagnostics, cancellationToken).ConfigureAwait(false);
- if (documentDifferences.IsEmpty)
+ if (!oldProject.ProjectSettingsSupportEditAndContinue(Log))
{
+ // reason alrady reported
continue;
}
- Log.Write($"Found {documentDifferences.ChangedOrAdded.Count} potentially changed and {documentDifferences.Deleted.Count} deleted document(s) in project {newProject.GetLogDisplay()}");
+ projectDiagnostics = ArrayBuilder.GetInstance();
+
+ await GetProjectDifferencesAsync(Log, oldProject, newProject, projectDifferences, projectDiagnostics, cancellationToken).ConfigureAwait(false);
+
+ if (projectDifferences.HasDocumentChanges)
+ {
+ Log.Write($"Found {projectDifferences.ChangedOrAddedDocuments.Count} potentially changed, {projectDifferences.DeletedDocuments.Count} deleted document(s) in project {newProject.GetLogDisplay()}");
+ }
var isStaleProject = oldSolution.IsStaleProject(newProject.Id);
@@ -936,8 +995,7 @@ void UpdateChangedDocumentsStaleness(bool isStale)
// The MVID is required for emit so we consider the error permanent and report it here.
// Bail before analyzing documents as the analysis needs to read the PDB which will likely fail if we can't even read the MVID.
projectDiagnostics.Add(mvidReadError);
-
- Telemetry.LogProjectAnalysisSummary(ProjectAnalysisSummary.ValidChanges, newProject.State.ProjectInfo.Attributes.TelemetryId, projectDiagnostics);
+ projectSummaryToReport = ProjectAnalysisSummary.ValidChanges;
continue;
}
@@ -964,7 +1022,7 @@ void UpdateChangedDocumentsStaleness(bool isStale)
// instead of the true C.M(string).
var (changedDocumentAnalyses, hasOutOfSyncChangedDocument) =
- await AnalyzeDocumentsAsync(solution, documentDifferences, solutionActiveStatementSpanProvider, projectDiagnostics, cancellationToken).ConfigureAwait(false);
+ await AnalyzeProjectDifferencesAsync(solution, projectDifferences, solutionActiveStatementSpanProvider, projectDiagnostics, cancellationToken).ConfigureAwait(false);
if (hasOutOfSyncChangedDocument)
{
@@ -999,9 +1057,22 @@ void UpdateChangedDocumentsStaleness(bool isStale)
}
var projectSummary = GetProjectAnalysisSummary(changedDocumentAnalyses);
+
+ if (HasProjectSettingsBlockingRudeEdits(oldProject, newProject, projectDiagnostics))
+ {
+ // If the project settings have changed and the change is a rude edit,
+ // block applying the changes even if there no other changes to the project documents.
+ // This is to avoid advancing the solution snapshot to an inconsistent state.
+ projectSummary = ProjectAnalysisSummary.InvalidChanges;
+ }
+
+ projectSummaryToReport = projectSummary;
Log.Write($"Project summary for {newProject.GetLogDisplay()}: {projectSummary}");
- if (projectSummary is ProjectAnalysisSummary.NoChanges or ProjectAnalysisSummary.ValidInsignificantChanges)
+ // Unsupported changes in referenced assemblies will be reported below.
+ if (projectSummary is ProjectAnalysisSummary.NoChanges or ProjectAnalysisSummary.ValidInsignificantChanges &&
+ oldProject.MetadataReferences.SequenceEqual(newProject.MetadataReferences) &&
+ oldProject.ProjectReferences.SequenceEqual(newProject.ProjectReferences))
{
continue;
}
@@ -1028,34 +1099,47 @@ void UpdateChangedDocumentsStaleness(bool isStale)
}
}
- if (moduleBlockingDiagnosticId != null || projectSummary != ProjectAnalysisSummary.ValidChanges)
+ if (projectSummary == ProjectAnalysisSummary.InvalidChanges)
{
- Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, projectDiagnostics);
-
+ // Write document changes to log directory so that we can inspect them for rude edits:
await LogDocumentChangesAsync(generation: null, cancellationToken).ConfigureAwait(false);
continue;
}
+ if (moduleBlockingDiagnosticId != null)
+ {
+ continue;
+ }
+
var oldCompilation = await oldProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
Contract.ThrowIfNull(oldCompilation);
+ // Report diagnosics even when the module is never going to be loaded (e.g. in multi-targeting scenario, where only one framework being debugged).
+ // This is consistent with reporting compilation errors - the IDE reports them for all TFMs regardless of what framework the app is running on.
var projectBaselines = DebuggingSession.GetOrCreateEmitBaselines(mvid, oldProject, oldCompilation, projectDiagnostics, out var baselineAccessLock);
if (projectBaselines.IsEmpty)
{
- // Report diagnosics even when the module is never going to be loaded (e.g. in multi-targeting scenario, where only one framework being debugged).
- // This is consistent with reporting compilation errors - the IDE reports them for all TFMs regardless of what framework the app is running on.
- Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, projectDiagnostics);
+ continue;
+ }
- await LogDocumentChangesAsync(generation: null, cancellationToken).ConfigureAwait(false);
+ var newCompilation = await newProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
+ Contract.ThrowIfNull(newCompilation);
+
+ // Compare referenced assemblies against the baseline. The runtime does not provide means to replace already loaded assemblies
+ // and therefore the versions of referenced assemblies in the new compilation can't change from the baseline.
+ if (projectBaselines.Any(baseline => HasReferenceRudeEdits(baseline.InitiallyReferencedAssemblies, newCompilation, projectDiagnostics)))
+ {
continue;
}
- Log.Write($"Emitting update of {newProject.GetLogDisplay()}");
+ if (projectSummary is ProjectAnalysisSummary.NoChanges or ProjectAnalysisSummary.ValidInsignificantChanges)
+ {
+ continue;
+ }
- var newCompilation = await newProject.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
+ Log.Write($"Emitting update of {newProject.GetLogDisplay()}");
- // project must support compilations since it supports EnC
- Contract.ThrowIfNull(newCompilation);
+ await LogDocumentChangesAsync(projectBaselines.First().Generation + 1, cancellationToken).ConfigureAwait(false);
var oldActiveStatementsMap = await BaseActiveStatements.GetValueAsync(cancellationToken).ConfigureAwait(false);
var projectChanges = await GetProjectChangesAsync(oldActiveStatementsMap, oldCompilation, newCompilation, oldProject, newProject, changedDocumentAnalyses, cancellationToken).ConfigureAwait(false);
@@ -1076,8 +1160,6 @@ void UpdateChangedDocumentsStaleness(bool isStale)
foreach (var projectBaseline in projectBaselines)
{
- await LogDocumentChangesAsync(projectBaseline.Generation + 1, cancellationToken).ConfigureAwait(false);
-
using var pdbStream = SerializableBytes.CreateWritableStream();
using var metadataStream = SerializableBytes.CreateWritableStream();
using var ilStream = SerializableBytes.CreateWritableStream();
@@ -1168,7 +1250,7 @@ void UpdateChangedDocumentsStaleness(bool isStale)
deltas.Add(delta);
nonRemappableRegions.Add((mvid, moduleNonRemappableRegions));
- newProjectBaselines.Add(new ProjectBaseline(mvid, projectBaseline.ProjectId, emitResult.Baseline, projectBaseline.Generation + 1));
+ newProjectBaselines.Add(new ProjectBaseline(mvid, projectBaseline.ProjectId, emitResult.Baseline, projectBaseline.InitiallyReferencedAssemblies, projectBaseline.Generation + 1));
var fileLog = Log.FileLog;
if (fileLog != null)
@@ -1177,8 +1259,6 @@ void UpdateChangedDocumentsStaleness(bool isStale)
}
}
- Telemetry.LogProjectAnalysisSummary(projectSummary, newProject.State.ProjectInfo.Attributes.TelemetryId, projectDiagnostics);
-
async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cancellationToken)
{
var fileLog = Log.FileLog;
@@ -1198,6 +1278,11 @@ async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cance
}
finally
{
+ if (projectSummaryToReport.HasValue)
+ {
+ Telemetry.LogProjectAnalysisSummary(projectSummaryToReport.Value, newProject.State.ProjectInfo.Attributes.TelemetryId, projectDiagnostics);
+ }
+
if (!projectDiagnostics.IsEmpty)
{
diagnosticBuilders.Add(newProject.Id, projectDiagnostics);
@@ -1226,11 +1311,19 @@ async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cance
Telemetry.LogRuntimeCapabilities(await Capabilities.GetValueAsync(cancellationToken).ConfigureAwait(false));
+ if (syntaxError != null)
+ {
+ Telemetry.LogSyntaxError();
+ }
+
if (hasPersistentErrors)
{
return SolutionUpdate.Empty(diagnostics, syntaxError, ModuleUpdateStatus.Blocked);
}
+ // syntax error is a persistent error
+ Contract.ThrowIfTrue(syntaxError != null);
+
var updates = deltas.ToImmutable();
EmitSolutionUpdateResults.GetProjectsToRebuildAndRestart(
@@ -1249,7 +1342,7 @@ async ValueTask LogDocumentChangesAsync(int? generation, CancellationToken cance
nonRemappableRegions.ToImmutable(),
newProjectBaselines.ToImmutable(),
diagnostics,
- syntaxError,
+ syntaxError: null,
projectsToRestart,
projectsToRebuild);
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs
index ac882f11e94..a64fa9a6235 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/EditSessionTelemetry.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using Microsoft.CodeAnalysis.Collections;
namespace Microsoft.CodeAnalysis.EditAndContinue;
@@ -19,8 +20,8 @@ internal readonly struct Data(EditSessionTelemetry telemetry)
public readonly ImmutableArray ProjectsWithValidDelta = telemetry._projectsWithValidDelta.AsImmutable();
public readonly ImmutableArray ProjectsWithUpdatedBaselines = telemetry._projectsWithUpdatedBaselines.AsImmutable();
public readonly EditAndContinueCapabilities Capabilities = telemetry._capabilities;
- public readonly bool HadCompilationErrors = telemetry._hadCompilationErrors;
- public readonly bool HadRudeEdits = telemetry._hadRudeEdits;
+ public readonly bool HasSyntaxErrors = telemetry._hadSyntaxErrors;
+ public readonly bool HadBlockingRudeEdits = telemetry._hadBlockingRudeEdits;
public readonly bool HadValidChanges = telemetry._hadValidChanges;
public readonly bool HadValidInsignificantChanges = telemetry._hadValidInsignificantChanges;
public readonly bool InBreakState = telemetry._inBreakState!.Value;
@@ -40,8 +41,8 @@ internal readonly struct Data(EditSessionTelemetry telemetry)
private readonly HashSet _projectsWithValidDelta = [];
private readonly HashSet _projectsWithUpdatedBaselines = [];
- private bool _hadCompilationErrors;
- private bool _hadRudeEdits;
+ private bool _hadSyntaxErrors;
+ private bool _hadBlockingRudeEdits;
private bool _hadValidChanges;
private bool _hadValidInsignificantChanges;
private bool? _inBreakState;
@@ -60,8 +61,8 @@ public Data GetDataAndClear()
_emitErrorIds.Clear();
_projectsWithValidDelta.Clear();
_projectsWithUpdatedBaselines.Clear();
- _hadCompilationErrors = false;
- _hadRudeEdits = false;
+ _hadSyntaxErrors = false;
+ _hadBlockingRudeEdits = false;
_hadValidChanges = false;
_hadValidInsignificantChanges = false;
_inBreakState = null;
@@ -72,7 +73,7 @@ public Data GetDataAndClear()
}
}
- public bool IsEmpty => !(_hadCompilationErrors || _hadRudeEdits || _hadValidChanges || _hadValidInsignificantChanges);
+ public bool IsEmpty => !(_hadSyntaxErrors || _hadBlockingRudeEdits || _hadValidChanges || _hadValidInsignificantChanges);
public void SetBreakState(bool value)
=> _inBreakState = value;
@@ -83,6 +84,9 @@ public void LogEmitDifferenceTime(TimeSpan span)
public void LogAnalysisTime(TimeSpan span)
=> _analysisTime += span;
+ public void LogSyntaxError()
+ => _hadSyntaxErrors = true;
+
public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid projectTelemetryId, IEnumerable diagnostics)
{
lock (_guard)
@@ -90,10 +94,17 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid proje
var hasError = false;
foreach (var diagnostic in diagnostics)
{
- if (diagnostic.Severity == DiagnosticSeverity.Error && !diagnostic.IsRudeEdit())
+ if (diagnostic.Severity == DiagnosticSeverity.Error)
{
- _emitErrorIds.Add(diagnostic.Id);
- hasError = true;
+ if (diagnostic.IsRudeEdit())
+ {
+ _hadBlockingRudeEdits = true;
+ }
+ else
+ {
+ _emitErrorIds.Add(diagnostic.Id);
+ hasError = true;
+ }
}
}
@@ -102,12 +113,7 @@ public void LogProjectAnalysisSummary(ProjectAnalysisSummary summary, Guid proje
case ProjectAnalysisSummary.NoChanges:
break;
- case ProjectAnalysisSummary.SyntaxErrors:
- _hadCompilationErrors = true;
- break;
-
- case ProjectAnalysisSummary.RudeEdits:
- _hadRudeEdits = true;
+ case ProjectAnalysisSummary.InvalidChanges:
break;
case ProjectAnalysisSummary.ValidChanges:
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs
index 5a587d5975f..45cd58b5c57 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/IEditAndContinueAnalyzer.cs
@@ -2,6 +2,8 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
@@ -24,4 +26,6 @@ Task AnalyzeDocumentAsync(
CancellationToken cancellationToken);
ActiveStatementExceptionRegions GetExceptionRegions(SyntaxNode syntaxRoot, TextSpan unmappedActiveStatementSpan, bool isNonLeaf, CancellationToken cancellationToken);
+
+ IEnumerable GetProjectSettingRudeEdits(Project oldProject, Project newProject);
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectAnalysisSummary.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectAnalysisSummary.cs
index 8f03cc087b8..663db12a780 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectAnalysisSummary.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectAnalysisSummary.cs
@@ -12,14 +12,9 @@ internal enum ProjectAnalysisSummary
NoChanges,
///
- /// Project contains syntax errors that block EnC analysis.
+ /// Project contains rude edits or a document whose analysis is blocked due to syntax error or rude edit in parse options.
///
- SyntaxErrors,
-
- ///
- /// Project contains rude edits.
- ///
- RudeEdits,
+ InvalidChanges,
///
/// The project only changed in comments, whitespaces, etc. that don't require compilation.
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectBaseline.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectBaseline.cs
index 8b80110e4f2..5b75ecf61ac 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectBaseline.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectBaseline.cs
@@ -3,14 +3,17 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Emit;
namespace Microsoft.CodeAnalysis.EditAndContinue;
-internal sealed class ProjectBaseline(Guid moduleId, ProjectId projectId, EmitBaseline emitBaseline, int generation)
+internal sealed class ProjectBaseline(Guid moduleId, ProjectId projectId, EmitBaseline emitBaseline, ImmutableDictionary> initiallyReferencedAssemblies, int generation)
{
public Guid ModuleId { get; } = moduleId;
public ProjectId ProjectId { get; } = projectId;
public EmitBaseline EmitBaseline { get; } = emitBaseline;
+ public ImmutableDictionary> InitiallyReferencedAssemblies { get; } = initiallyReferencedAssemblies;
public int Generation { get; } = generation;
}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDifferences.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDifferences.cs
new file mode 100644
index 00000000000..aaad8f29664
--- /dev/null
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDifferences.cs
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using Microsoft.CodeAnalysis.PooledObjects;
+
+namespace Microsoft.CodeAnalysis.EditAndContinue;
+
+///
+/// Differences between documents of old and new projects.
+///
+internal readonly struct ProjectDifferences() : IDisposable
+{
+ public readonly ArrayBuilder ChangedOrAddedDocuments = ArrayBuilder.GetInstance();
+ public readonly ArrayBuilder DeletedDocuments = ArrayBuilder.GetInstance();
+
+ public void Dispose()
+ {
+ ChangedOrAddedDocuments.Free();
+ DeletedDocuments.Free();
+ }
+
+ public bool HasDocumentChanges
+ => !ChangedOrAddedDocuments.IsEmpty || !DeletedDocuments.IsEmpty;
+
+ public bool Any()
+ => HasDocumentChanges;
+
+ public bool IsEmpty
+ => !Any();
+
+ public void Clear()
+ {
+ ChangedOrAddedDocuments.Clear();
+ DeletedDocuments.Clear();
+ }
+}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDocumentDifferences.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDocumentDifferences.cs
deleted file mode 100644
index 9b39626ffd0..00000000000
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectDocumentDifferences.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using Microsoft.CodeAnalysis.PooledObjects;
-
-namespace Microsoft.CodeAnalysis.EditAndContinue;
-
-///
-/// Differences between documents of old and new projects.
-///
-internal readonly struct ProjectDocumentDifferences() : IDisposable
-{
- public readonly ArrayBuilder ChangedOrAdded = ArrayBuilder.GetInstance();
- public readonly ArrayBuilder Deleted = ArrayBuilder.GetInstance();
-
- public void Dispose()
- {
- ChangedOrAdded.Free();
- Deleted.Free();
- }
-
- public bool IsEmpty
- => ChangedOrAdded.IsEmpty && Deleted.IsEmpty;
-
- public bool Any()
- => !IsEmpty;
-
- public void Clear()
- {
- ChangedOrAdded.Clear();
- Deleted.Clear();
- }
-}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectSettingKind.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectSettingKind.cs
new file mode 100644
index 00000000000..9ea9ec6c60b
--- /dev/null
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/ProjectSettingKind.cs
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.CodeAnalysis.EditAndContinue;
+
+///
+/// Represents project properties and items that impact parse options, compilation options and source file context interpretation.
+///
+/// Project settings fall into following categories:
+/// 1) Change requires restart. Error is reported.
+/// E.g. language version
+///
+/// 2) Change has no-effect until restart. Warning is reported if tracked by .
+/// E.g. output type, platform, emit options
+/// Not all project settings are tracked by Roslyn. Only those that are are reported.
+/// If we want to enable auto-restart when a setting is changed we need to track it in .
+///
+/// 5) Change has no effect on emitted IL/metadata, the effect is not observable to the application. Not reported.
+/// E.g. analyzer settings, allow unsafe, nullable, code page, delay sign, no warn, xml doc file, embedded sources, etc.
+///
+/// The enum only includes settings from categories [1] and [2].
+/// The names of the enum members should match the corresponding msbuild property names.
+///
+internal enum ProjectSettingKind
+{
+ ///
+ /// Error to avoid confusion and inconsistencies.
+ /// If changed we would interpret changed syntax trees using one language version while unchanged would use another language version.
+ /// We would also compile changed members using one version while unchanged would use another.
+ ///
+ LangVersion = 0,
+
+ ///
+ /// Error for the same reasons as .
+ ///
+ Features = 1,
+
+ ///
+ /// Error for the same reasons as .
+ ///
+ DefineConstants = 2,
+
+ ///
+ /// Error for the same reasons as .
+ ///
+ CheckForOverflowUnderflow = 3,
+
+ ///
+ /// Warning since output type only affects entry point.
+ ///
+ OutputType = 4,
+
+ ///
+ /// Warning.
+ ///
+ StartupObject = 5,
+
+ ///
+ /// Error, need to preserve the module name.
+ ///
+ ModuleAssemblyName = 9,
+
+ ///
+ /// Error, need to preserve the assembly name.
+ ///
+ AssemblyName = 10,
+
+ ///
+ /// Warning, can't be changed without restarting the application but not blocking.
+ ///
+ Platform = 11,
+
+ ///
+ /// Must be .
+ ///
+ OptimizationLevel = 12,
+
+ // VB specific settings
+
+ ///
+ /// Error. Can't change namespace of existing types.
+ ///
+ RootNamespace = 50,
+
+ OptionStrict = 51,
+ OptionInfer = 52,
+ OptionExplicit = 53,
+ OptionCompare = 54,
+}
+
+internal static class ProjectSettingKindExtensions
+{
+ public static bool IsWarning(this ProjectSettingKind kind)
+ => kind is
+ ProjectSettingKind.OutputType or
+ ProjectSettingKind.StartupObject or
+ ProjectSettingKind.Platform;
+}
diff --git a/src/roslyn/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs b/src/roslyn/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs
index e0eb40acb4b..2b8fb6b2627 100644
--- a/src/roslyn/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs
+++ b/src/roslyn/src/Features/Core/Portable/EditAndContinue/Utilities/Extensions.cs
@@ -72,6 +72,26 @@ void LogReason(string message)
return true;
}
+ ///
+ /// True if project settings are compatible with Edit and Continue.
+ ///
+ public static bool ProjectSettingsSupportEditAndContinue(this Project project, TraceLog? log = null)
+ {
+ Contract.ThrowIfFalse(project.SupportsEditAndContinue());
+ Contract.ThrowIfNull(project.CompilationOptions);
+
+ if (project.CompilationOptions.OptimizationLevel != OptimizationLevel.Debug)
+ {
+ LogReason(nameof(ProjectSettingKind.OptimizationLevel), project.CompilationOptions.OptimizationLevel.ToString());
+ return false;
+ }
+
+ void LogReason(string settingName, string value)
+ => log?.Write($"Project '{project.GetLogDisplay()}' setting '{settingName}' value '{value}' is not compatible with EnC");
+
+ return true;
+ }
+
public static string GetLogDisplay(this Project project)
=> project.FilePath != null
? $"'{project.FilePath}'" + (project.State.NameAndFlavor.flavor is { } flavor ? $" ('{flavor}')" : "")
diff --git a/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx b/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx
index 139d6ea4d40..726a5036b07 100644
--- a/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx
+++ b/src/roslyn/src/Features/Core/Portable/FeaturesResources.resx
@@ -369,6 +369,18 @@
Adding or moving {0} of a COM interface requires restarting the application.
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
+ default>
+
Updating the modifiers of {0} requires restarting the application.
diff --git a/src/roslyn/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceCodeRefactoringProvider.cs b/src/roslyn/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceCodeRefactoringProvider.cs
new file mode 100644
index 00000000000..c75c4a473a4
--- /dev/null
+++ b/src/roslyn/src/Features/Core/Portable/ImplementInterface/ImplementInterfaceCodeRefactoringProvider.cs
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Composition;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeActions;
+using Microsoft.CodeAnalysis.CodeRefactorings;
+using Microsoft.CodeAnalysis.Collections;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+
+namespace Microsoft.CodeAnalysis.ImplementInterface;
+
+[ExportCodeRefactoringProvider(LanguageNames.CSharp, LanguageNames.VisualBasic,
+ Name = PredefinedCodeRefactoringProviderNames.ImplementInterface), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class ImplementInterfaceCodeRefactoringProvider() : CodeRefactoringProvider
+{
+ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
+ {
+ var (document, textSpan, cancellationToken) = context;
+
+ var helpers = document.GetRequiredLanguageService();
+ var sourceText = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);
+ var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
+
+ // We offer the refactoring when the user is between any members of a class/struct and are on a blank line.
+ if (!helpers.IsBetweenTypeMembers(sourceText, root, textSpan.Start, out var typeDeclaration))
+ return;
+
+ var service = document.GetRequiredLanguageService();
+ using var allCodeActions = TemporaryArray.Empty;
+
+ foreach (var typeNode in service.GetInterfaceTypes(typeDeclaration))
+ {
+ var codeActions = await service.GetCodeActionsAsync(
+ document, typeNode, cancellationToken).ConfigureAwait(false);
+
+ allCodeActions.AddRange(codeActions);
+ }
+
+ context.RegisterRefactorings(allCodeActions.ToImmutableAndClear(), textSpan);
+ }
+}
diff --git a/src/roslyn/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs b/src/roslyn/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs
deleted file mode 100644
index 895018ce8d4..00000000000
--- a/src/roslyn/src/Features/Core/Portable/SemanticSearch/ISemanticSearchCopilotService.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.CodeAnalysis.SemanticSearch;
-
-internal interface ISemanticSearchCopilotService
-{
- bool IsAvailable { get; }
-
- ///
- /// Translates natural language to C# query.
- ///
- ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken);
-}
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
index f03c674e673..631eacc18ba 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.cs.xlf
@@ -450,6 +450,16 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn
Změna typů parametrů u {0} vyžaduje restartování aplikace.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Změna pseudovlastního atributu {0} u {1} vyžaduje restartování aplikace.
@@ -1350,6 +1360,11 @@ Ujistěte se, že specifikátor tt použijete pro jazyky, pro které je nezbytn
Zjistil se pravděpodobný řetězec JSON
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Vlastnosti nejsou v poli povolené
@@ -3628,6 +3643,11 @@ Pokud se specifikátor formátu d použije bez dalších specifikátorů vlastn
Specifikátor vlastního formátu dddd (a libovolný počet dalších specifikátorů d) reprezentuje celý název dne v týdnu. Lokalizovaný název dne v týdnu se načítá z vlastnosti DateTimeFormatInfo.DayNames aktuální nebo zadané jazykové verze.
+
+ default>
+ default>
+
+
discard
proměnná typu discard
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
index 20c77de3dee..3f9bae573d5 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.de.xlf
@@ -450,6 +450,16 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d
Das Ändern von Parametertypen von {0} erfordert einen Neustart der Anwendung.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Das Ändern des pseudobenutzerdefinierten Attributs „{0}“ von {1} erfordert einen Neustart der Anwendung.
@@ -1350,6 +1360,11 @@ Stellen Sie sicher, dass Sie den Bezeichner "tt" für Sprachen verwenden, für d
Wahrscheinliche JSON-Zeichenfolge erkannt
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Nicht zulässige Eigenschaften in einem Array
@@ -3628,6 +3643,11 @@ Bei Verwendung des Formatbezeichners "d" ohne weitere benutzerdefinierte Formatb
Der benutzerdefinierte Formatbezeichner "dddd" (plus beliebig viele zusätzliche d-Bezeichner) repräsentiert den vollständigen Namen des Wochentags. Der lokalisierte Name des Wochentags wird aus der DateTimeFormatInfo.DayNames-Eigenschaft der aktuellen oder angegebenen Kultur abgerufen.
+
+ default>
+ default>
+
+
discard
Ausschussvariable
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
index f09a4f93961..e934912a85f 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.es.xlf
@@ -450,6 +450,16 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa
Para cambiar los tipos de parámetros de {0}se requiere reiniciar la aplicación.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Para cambiar el atributo pseudo-personalizado "{0}" de {1} se requiere reiniciar la aplicación
@@ -1350,6 +1360,11 @@ Asegúrese de usar el especificador "tt" para los idiomas para los que es necesa
Cadena JSON probable detectada
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Propiedades no permitidas en una matriz
@@ -3628,6 +3643,11 @@ Si el especificador de formato "d" se usa sin otros especificadores de formato p
El especificador de formato personalizado "dddd" (más cualquier número de especificadores "d" adicionales) representa el nombre completo del día de la semana. El nombre localizado del día de la semana se recupera de la propiedad DateTimeFormatInfo.DayNames de la referencia cultural actual o especificada.
+
+ default>
+ default>
+
+
discard
descartar
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
index cb28a6e18d4..222317bf738 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.fr.xlf
@@ -450,6 +450,16 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai
La modification des types de paramètres de {0} requiert le redémarrage de l’application.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
La modification de l’attribut pseudo-personnalisé « {0} » de {1} requiert le redémarrage de l’application
@@ -1350,6 +1360,11 @@ Veillez à utiliser le spécificateur "tt" pour les langues où il est nécessai
Chaîne JSON probable détectée
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Propriétés non autorisées dans un tableau
@@ -3628,6 +3643,11 @@ Si le spécificateur de format "d" est utilisé sans autres spécificateurs de f
Le spécificateur de format personnalisé "dddd" (plus n'importe quel nombre de spécificateurs "d" supplémentaires) représente le nom complet du jour de la semaine. Le nom localisé du jour de la semaine est récupéré à partir de la propriété DateTimeFormatInfo.DayNames de la culture actuelle ou spécifiée.
+
+ default>
+ default>
+
+
discard
discard
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
index 35c70870dc3..2045461386a 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.it.xlf
@@ -450,6 +450,16 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa
Se si modificano i tipi di parametro di {0}, è necessario riavviare l'applicazione.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Se si modifica l'attributo pseudo-personalizzato '{0}' di {1}, è necessario riavviare l'applicazione
@@ -1350,6 +1360,11 @@ Assicurarsi di usare l'identificatore "tt" per le lingue per le quali è necessa
Rilevata probabile stringa JSON
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Proprietà non consentite in una matrice
@@ -3628,6 +3643,11 @@ Se l'identificatore di formato "d" viene usato senza altri identificatori di for
L'identificatore di formato personalizzato "dddd" (più qualsiasi numero di identificatori "d" aggiuntivi) rappresenta il nome esteso del giorno della settimana. Il nome localizzato del giorno della settimana viene recuperato dalla proprietà DateTimeFormatInfo.DayNames delle impostazioni cultura correnti o specificate.
+
+ default>
+ default>
+
+
discard
variabile discard
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
index 8af8702ddeb..9751a5bad4b 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ja.xlf
@@ -450,6 +450,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
{0} のパラメーターの種類を変更するには、アプリケーションを再起動する必要があります。
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
{0} の擬似カスタム属性 '{1}' を変更するには、アプリケーションを再起動する必要があります
@@ -1350,6 +1360,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
JSON の可能性のある文字列が検出されました
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
配列ではプロパティは使用できません
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
"dddd" カスタム書式指定子 (任意の数の "d" 指定子を追加できます) は、曜日の完全名を表します。曜日のローカライズされた名前は、現在の、または指定したカルチャの DateTimeFormatInfo.DayNames プロパティから取得されます。
+
+ default>
+ default>
+
+
discard
破棄
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
index 2824699a97b..f8bfe41bae4 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ko.xlf
@@ -450,6 +450,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
{0}의 매개 변수 유형을 변경하려면 애플리케이션을 다시 시작해야 합니다.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
{1}의 허위 사용자 지정 특성 '{0}'을(를) 변경하려면 애플리케이션을 다시 시작해야 합니다.
@@ -1350,6 +1360,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
가능한 JSON 문자열이 탐지됨
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
배열에는 속성을 사용할 수 없습니다.
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
"dddd" 사용자 지정 형식 지정자(및 임의 개수의 추가 "d" 지정자)는 요일의 전체 이름을 나타냅니다. 요일의 지역화된 이름은 현재 문화권 또는 지정된 문화권의 DateTimeFormatInfo.DayNames 속성에서 검색됩니다.
+
+ default>
+ default>
+
+
discard
무시 항목
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
index 7111aa3e62a..666306e98bd 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pl.xlf
@@ -450,6 +450,16 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k
Zmiana typów parametrów elementów {0} wymaga ponownego uruchomienia aplikacji.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Zmiana atrybutu pseudoniestandardowego elementu „{0}” z {1} wymaga ponownego uruchomienia aplikacji
@@ -1350,6 +1360,11 @@ Pamiętaj, aby nie używać specyfikatora „tt” dla wszystkich języków, w k
Wykryto prawdopodobnie ciąg JSON
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Właściwości niedozwolone w tablicy
@@ -3628,6 +3643,11 @@ Jeśli specyfikator formatu „d” zostanie użyty bez innych indywidualnych sp
Indywidualny specyfikator formatu „dddd” (wraz z dowolną liczbą dodatkowych specyfikatorów „d”) reprezentuje pełną nazwę dnia tygodnia. Zlokalizowana nazwa dnia tygodnia jest pobierana z właściwości DateTimeFormatInfo.DayNames bieżącej lub określonej kultury.
+
+ default>
+ default>
+
+
discard
odrzuć
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
index 3eaf8d35ad4..107cec3b69f 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.pt-BR.xlf
@@ -450,6 +450,16 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess
A alteração dos tipos de parâmetro de {0} requer o reinício do aplicativo.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Alterar o atributo pseudo-personalizado '{0}' de {1} requer o reinício do aplicativo
@@ -1350,6 +1360,11 @@ Verifique se o especificador "tt" foi usado para idiomas para os quais é necess
Provável cadeia de caracteres JSON detectada
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Propriedades não permitidas em uma matriz
@@ -3628,6 +3643,11 @@ Se o especificador de formato "d" for usado sem outros especificadores de format
O especificador de formato personalizado "dddd" (mais qualquer número de especificadores "d" adicionais) representa o nome completo do dia da semana. O nome localizado do dia da semana é recuperado da propriedade DateTimeFormatInfo.DayNames da cultura atual ou especificada.
+
+ default>
+ default>
+
+
discard
discard
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
index d09cff14956..9b1d6388d44 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.ru.xlf
@@ -450,6 +450,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
Для изменения типов параметров {0} требуется перезапустить приложение.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
Для изменения псевдонастраиваемого атрибута "{0}" для {1} требуется перезапустить приложение.
@@ -1350,6 +1360,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
Обнаружена возможная строка JSON
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Свойства не разрешены в массиве
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
Описатель пользовательского формата "dddd" (плюс любое число дополнительных описателей "d") представляет полное название дня недели. Локализованное название дня недели извлекается из свойства DateTimeFormatInfo.DayNames текущих или заданных языка и региональных параметров.
+
+ default>
+ default>
+
+
discard
отменить
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
index d7943aef7b3..eff0b6ed434 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.tr.xlf
@@ -450,6 +450,16 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be
{0} öğesinin parametre türlerinin değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir.
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
{1} öğesinin '{0}' sahte özel özniteliğinin değiştirilmesi, uygulamanın yeniden başlatılmasını gerektirir
@@ -1350,6 +1360,11 @@ AM ve PM arasındaki farkın korunmasının gerekli olduğu diller için "tt" be
Olası JSON dizesi algılandı
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
Dizide özelliklere izin verilmiyor
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
"dddd" özel biçim belirticisi (ve herhangi bir sayıda "d" belirticisi) haftanın gününün tam adını temsil eder. Haftanın gününün yerelleştirilmiş adı, geçerli veya belirtilen kültürün DateTimeFormatInfo.DayNames özelliğinden alınır.
+
+ default>
+ default>
+
+
discard
at
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
index c4751ccee9a..f182f12a29c 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hans.xlf
@@ -450,6 +450,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
更改 {0} 的参数类型需要重启应用程序。
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
更改 {1} 的伪自定义属性“{0}”需要重启应用程序
@@ -1350,6 +1360,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
检测到可能的 JSON 字符串
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
数组中不允许有属性
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
"dddd" 自定义格式说明符(另加任意数量的其他 "d" 说明符)表示一周中某天的完整名称。可从当前或指定区域性的 DateTimeFormatInfo.DayNames 属性中检索一周中某天的本地化名称。
+
+ default>
+ default>
+
+
discard
放弃
diff --git a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
index dc551e792c7..5b5af86284d 100644
--- a/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
+++ b/src/roslyn/src/Features/Core/Portable/xlf/FeaturesResources.zh-Hant.xlf
@@ -450,6 +450,16 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
變更 {0} 的參數類型需要重新啟動應用程式。
+
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+ Changing project or package reference caused the identity of referenced assembly to change from '{0}' to '{1}', which requires restarting the application.
+
+
+
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+ Changing project setting '{0}' from '{1}' to '{2}' requires restarting the application.
+
+
Changing pseudo-custom attribute '{0}' of {1} requires restarting the application
變更 {1} 的虛擬自訂屬性 '{0}' 需要重新啟動應用程式
@@ -1350,6 +1360,11 @@ Make sure to use the "tt" specifier for languages for which it's necessary to ma
偵測到可能的 JSON 字串
+
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+ Project references mutliple assemblies of the same simple name '{0}': {1}. Changing a reference to such an assembly requires restarting the application.
+
+
Properties not allowed in an array
在陣列中不允許屬性
@@ -3628,6 +3643,11 @@ If the "d" format specifier is used without other custom format specifiers, it's
"dddd" 自訂格式規範 (加上任意數目的其他 "d" 規範) 代表星期幾的完整名稱。系統會從目前文化特性或指定文化特性的 DateTimeFormatInfo.DayNames 屬性,擷取星期幾的當地語系化名稱。
+
+ default>
+ default>
+
+
discard
捨棄
diff --git a/src/roslyn/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1.cs b/src/roslyn/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1.cs
index 1a31a8b1f8b..d45791c0dbb 100644
--- a/src/roslyn/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1.cs
+++ b/src/roslyn/src/Features/DiagnosticsTestUtilities/CodeActions/VisualBasicCodeRefactoringVerifier`1.cs
@@ -12,6 +12,13 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
public static partial class VisualBasicCodeRefactoringVerifier
where TCodeRefactoring : CodeRefactoringProvider, new()
{
+ ///
+ public static Task VerifyRefactoringAsync(
+ string source)
+ {
+ return VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, source);
+ }
+
///
public static Task VerifyRefactoringAsync(string source, string fixedSource)
{
diff --git a/src/roslyn/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs b/src/roslyn/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs
deleted file mode 100644
index 472cbc8d06f..00000000000
--- a/src/roslyn/src/Features/ExternalAccess/Copilot/Internal/SemanticSearch/SemanticSearchCopilotServiceWrapper.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Composition;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
-using Microsoft.CodeAnalysis.Host.Mef;
-using Microsoft.CodeAnalysis.SemanticSearch;
-
-namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.Internal.SemanticSearch;
-
-[Export(typeof(ISemanticSearchCopilotService)), Shared]
-[method: ImportingConstructor]
-[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
-internal sealed class SemanticSearchCopilotServiceWrapper(
- [Import(AllowDefault = true)] Lazy? impl) : ISemanticSearchCopilotService
-{
- bool ISemanticSearchCopilotService.IsAvailable
- => impl != null;
-
- async ValueTask ISemanticSearchCopilotService.TryGetQueryAsync(string text, SemanticSearchCopilotContext context, CancellationToken cancellationToken)
- {
- Contract.ThrowIfNull(impl);
-
- var result = await impl.Value.TryGetQueryAsync(
- text,
- new SemanticSearchCopilotContextImpl()
- {
- ModelName = context.ModelName,
- AvailablePackages = context.AvailablePackages,
- },
- cancellationToken).ConfigureAwait(false);
-
- return new SemanticSearchCopilotGeneratedQuery()
- {
- IsError = result.IsError,
- Text = result.Text,
- };
- }
-}
diff --git a/src/roslyn/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs b/src/roslyn/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs
deleted file mode 100644
index 4b3a34a53bb..00000000000
--- a/src/roslyn/src/Features/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotServiceImpl.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
-
-internal interface ISemanticSearchCopilotServiceImpl
-{
- ValueTask TryGetQueryAsync(string text, SemanticSearchCopilotContextImpl context, CancellationToken cancellationToken);
-}
-
-internal sealed class SemanticSearchCopilotContextImpl
-{
- public required string ModelName { get; init; }
-
- ///
- /// List of package names and versions that to include in the prompt.
- ///
- public required IEnumerable<(string name, Version version)> AvailablePackages { get; init; }
-}
-
-internal readonly struct SemanticSearchCopilotGeneratedQueryImpl
-{
- ///
- /// True if is an error message.
- ///
- public required bool IsError { get; init; }
-
- ///
- /// The generated code or an error message.
- ///
- public required string Text { get; init; }
-}
diff --git a/src/roslyn/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs b/src/roslyn/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
index e0273bb6ac7..ac6178629ce 100644
--- a/src/roslyn/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
+++ b/src/roslyn/src/Features/Test/EditAndContinue/EditAndContinueWorkspaceServiceTests.cs
@@ -300,6 +300,439 @@ class C { int Y => 2; }
EndDebuggingSession(debuggingSession);
}
+ [Theory]
+ [CombinatorialData]
+ internal async Task Project_ParseOptions(
+ [CombinatorialValues(ProjectSettingKind.LangVersion, ProjectSettingKind.Features, ProjectSettingKind.DefineConstants)] ProjectSettingKind settingKind,
+ [CombinatorialValues(LanguageNames.CSharp, LanguageNames.VisualBasic)] string language)
+ {
+ var source = language == LanguageNames.CSharp
+ ? """
+ class C;
+ """
+ : """
+ Class C
+ End Class
+ """;
+
+ var sourceFile1 = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", language, out var projectId).
+ AddTestDocument(source, sourceFile1.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ var (code, settingName) = settingKind switch
+ {
+ ProjectSettingKind.LangVersion => ("ENC1100", "LangVersion"),
+ ProjectSettingKind.Features => ("ENC1101", "Features"),
+ ProjectSettingKind.DefineConstants => ("ENC1102", "DefineConstants"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+
+ ParseOptions newOptions;
+ string oldValue;
+ string newValue;
+
+ if (language == LanguageNames.CSharp)
+ {
+ var oldOptions = (CSharpParseOptions)project.ParseOptions;
+
+ (newOptions, oldValue, newValue) = settingKind switch
+ {
+ ProjectSettingKind.LangVersion => (oldOptions.WithLanguageVersion(CSharp.LanguageVersion.CSharp11), "default", "11.0"),
+ ProjectSettingKind.Features => (oldOptions.WithFeatures([new("f1", "1"), new("f2", "2")]), "noRefSafetyRulesAttribute=true", "f1=1,f2=2"),
+ ProjectSettingKind.DefineConstants => (oldOptions.WithPreprocessorSymbols("S1", "S2"), "", "S1,S2"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+ }
+ else
+ {
+ var oldOptions = (VisualBasic.VisualBasicParseOptions)project.ParseOptions;
+
+ (newOptions, oldValue, newValue) = settingKind switch
+ {
+ ProjectSettingKind.LangVersion => (oldOptions.WithLanguageVersion(VisualBasic.LanguageVersion.VisualBasic11), "default", "11"),
+ ProjectSettingKind.Features => (oldOptions.WithFeatures([new("f1", "1"), new("f2", "2")]), "", "f1=1,f2=2"),
+ ProjectSettingKind.DefineConstants => (oldOptions.WithPreprocessorSymbols(new("S1", 1), new("S2", 2)), "_MYTYPE=Empty", "S1=1,S2=2"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+ }
+
+ solution = project.WithParseOptions(newOptions).Solution;
+
+ // Rude edits not reported for document, will be reported when emitting updates:
+ var diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetRequiredDocument(documentId), s_noActiveSpans, CancellationToken.None);
+ AssertEx.Empty(diagnostics);
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : Error {code}: {string.Format(FeaturesResources.Changing_project_setting_0_from_1_to_2_requires_restarting_the_application, settingName, oldValue, newValue)}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ debuggingSession.DiscardSolutionUpdate();
+
+ EndDebuggingSession(debuggingSession);
+ }
+
+ [Theory]
+ [CombinatorialData]
+ internal async Task Project_CompilationOptions(
+ [CombinatorialValues(
+ ProjectSettingKind.CheckForOverflowUnderflow,
+ ProjectSettingKind.OutputType,
+ ProjectSettingKind.StartupObject,
+ ProjectSettingKind.ModuleAssemblyName,
+ ProjectSettingKind.Platform,
+ ProjectSettingKind.OptimizationLevel
+ )] ProjectSettingKind settingKind,
+ [CombinatorialValues(LanguageNames.CSharp, LanguageNames.VisualBasic)] string language)
+ {
+ var source = language == LanguageNames.CSharp
+ ? """
+ class C;
+ """
+ : """
+ Class C
+ End Class
+ """;
+
+ var sourceFile1 = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", language, out var projectId).
+ AddTestDocument(source, sourceFile1.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ var (code, settingName, isWarning) = settingKind switch
+ {
+ ProjectSettingKind.CheckForOverflowUnderflow => ("ENC1103", "CheckForOverflowUnderflow", isWarning: false),
+ ProjectSettingKind.OutputType => ("ENC1104", "OutputType", isWarning: true),
+ ProjectSettingKind.StartupObject => ("ENC1105", "StartupObject", isWarning: true),
+ ProjectSettingKind.ModuleAssemblyName => ("ENC1109", "ModuleAssemblyName", isWarning: false),
+ ProjectSettingKind.Platform => ("ENC1111", "Platform", isWarning: true),
+ ProjectSettingKind.OptimizationLevel => ("ENC1112", "OptimizationLevel", isWarning: false),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+
+ CompilationOptions newOptions;
+ string oldValue;
+ string newValue;
+
+ var oldOptions = project.CompilationOptions;
+ var defaultOverflowChecks = oldOptions.CheckOverflow;
+
+ (newOptions, oldValue, newValue) = settingKind switch
+ {
+ ProjectSettingKind.CheckForOverflowUnderflow => (oldOptions.WithOverflowChecks(!defaultOverflowChecks), defaultOverflowChecks.ToString(), (!defaultOverflowChecks).ToString()),
+ ProjectSettingKind.OutputType => (oldOptions.WithOutputKind(OutputKind.WindowsRuntimeApplication), "Library", "AppContainerExe"),
+ ProjectSettingKind.StartupObject => (oldOptions.WithMainTypeName("NewProgram"), $"<{FeaturesResources.@default}>", "NewProgram"),
+ ProjectSettingKind.ModuleAssemblyName => (oldOptions.WithModuleName("mod"), $"<{FeaturesResources.@default}>", "mod"),
+ ProjectSettingKind.Platform => (oldOptions.WithPlatform(Platform.Arm64), "AnyCpu", "Arm64"),
+ ProjectSettingKind.OptimizationLevel => (oldOptions.WithOptimizationLevel(OptimizationLevel.Release), "Debug", "Release"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+
+ solution = project.WithCompilationOptions(newOptions).Solution;
+
+ // Rude edits not reported for document, will be reported when emitting updates:
+ var diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetRequiredDocument(documentId), s_noActiveSpans, CancellationToken.None);
+ AssertEx.Empty(diagnostics);
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(isWarning ? ModuleUpdateStatus.None : ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : {(isWarning ? "Warning" : "Error")} {code}: {string.Format(FeaturesResources.Changing_project_setting_0_from_1_to_2_requires_restarting_the_application, settingName, oldValue, newValue)}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ if (!isWarning)
+ {
+ debuggingSession.DiscardSolutionUpdate();
+ }
+
+ EndDebuggingSession(debuggingSession);
+ }
+
+ [Theory]
+ [InlineData(ProjectSettingKind.RootNamespace)]
+ [InlineData(ProjectSettingKind.OptionStrict)]
+ [InlineData(ProjectSettingKind.OptionInfer)]
+ [InlineData(ProjectSettingKind.OptionExplicit)]
+ [InlineData(ProjectSettingKind.OptionCompare)]
+ internal async Task Project_CompilationOptions_VB(ProjectSettingKind settingKind)
+ {
+ var source = """
+ Class C
+ End Class
+ """;
+
+ var sourceFile1 = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", LanguageNames.VisualBasic, out var projectId).
+ AddTestDocument(source, sourceFile1.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ var (code, settingName) = settingKind switch
+ {
+ ProjectSettingKind.RootNamespace => ("ENC1150", "RootNamespace"),
+ ProjectSettingKind.OptionStrict => ("ENC1151", "OptionStrict"),
+ ProjectSettingKind.OptionInfer => ("ENC1152", "OptionInfer"),
+ ProjectSettingKind.OptionExplicit => ("ENC1153", "OptionExplicit"),
+ ProjectSettingKind.OptionCompare => ("ENC1154", "OptionCompare"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+
+ CompilationOptions newOptions;
+ string oldValue;
+ string newValue;
+
+ var oldOptions = (VisualBasic.VisualBasicCompilationOptions)project.CompilationOptions;
+
+ (newOptions, oldValue, newValue) = settingKind switch
+ {
+ ProjectSettingKind.RootNamespace => (oldOptions.WithRootNamespace("N"), "", "N"),
+ ProjectSettingKind.OptionStrict => (oldOptions.WithOptionStrict(VisualBasic.OptionStrict.On), "Off", "On"),
+ ProjectSettingKind.OptionInfer => (oldOptions.WithOptionInfer(false), "On", "Off"),
+ ProjectSettingKind.OptionExplicit => (oldOptions.WithOptionExplicit(false), "On", "Off"),
+ ProjectSettingKind.OptionCompare => (oldOptions.WithOptionCompareText(true), "Binary", "Text"),
+ _ => throw ExceptionUtilities.UnexpectedValue(settingKind)
+ };
+
+ solution = project.WithCompilationOptions(newOptions).Solution;
+
+ // Rude edits not reported for document, will be reported when emitting updates:
+ var diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetRequiredDocument(documentId), s_noActiveSpans, CancellationToken.None);
+ AssertEx.Empty(diagnostics);
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : Error {code}: {string.Format(FeaturesResources.Changing_project_setting_0_from_1_to_2_requires_restarting_the_application, settingName, oldValue, newValue)}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ debuggingSession.DiscardSolutionUpdate();
+ EndDebuggingSession(debuggingSession);
+ }
+
+ private static MetadataReference EmitLibraryReference(Version version, bool useStrongName = false)
+ {
+ var libSource = $$"""
+ [assembly: System.Reflection.AssemblyVersion("{{version}}")]
+ public class Lib;
+ """;
+
+ var libCompilation = CSharpCompilation.Create(
+ assemblyName: "Lib",
+ syntaxTrees: [SyntaxFactory.ParseSyntaxTree(libSource, options: TestOptions.Regular, path: "Lib.cs", Encoding.UTF8)],
+ references: TargetFrameworkUtil.GetReferences(TargetFramework.NetStandard20),
+ useStrongName ? TestOptions.SigningDebugDll.WithCryptoKeyFile(SigningTestHelpers.KeyPairFile) : TestOptions.DebugDll);
+
+ return libCompilation.EmitToImageReference();
+ }
+
+ [Fact]
+ internal async Task Project_MetadataReferences()
+ {
+ var source = "class C;";
+ var sourceFile = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ var libV1 = EmitLibraryReference(new Version(1, 0, 0, 0));
+ var libV2 = EmitLibraryReference(new Version(2, 0, 0, 0));
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", out var projectId).
+ AddMetadataReference(libV1).
+ AddTestDocument(source, sourceFile.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ // change version of the dependency:
+ solution = project.RemoveMetadataReference(libV1).AddMetadataReference(libV2).Solution;
+
+ // Rude edits not reported for document, will be reported when emitting updates:
+ var diagnostics = await service.GetDocumentDiagnosticsAsync(solution.GetRequiredDocument(documentId), s_noActiveSpans, CancellationToken.None);
+ AssertEx.Empty(diagnostics);
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : Error ENC1099: {string.Format(
+ FeaturesResources.Changing_project_or_package_reference_caused_the_identity_of_referenced_assembly_to_change_from_0_to_1_which_requires_restarting_the_application,
+ "Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
+ "Lib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ debuggingSession.DiscardSolutionUpdate();
+
+ EndDebuggingSession(debuggingSession);
+ }
+
+ [Fact]
+ internal async Task Project_MetadataReferences_RemoveAdd()
+ {
+ var source = "class C;";
+ var sourceFile = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ var libV1 = EmitLibraryReference(new Version(1, 0, 0, 0));
+ var libV2 = EmitLibraryReference(new Version(2, 0, 0, 0));
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", out var projectId).
+ AddMetadataReference(libV1).
+ AddTestDocument(source, sourceFile.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ // remove dependency:
+ solution = project.RemoveMetadataReference(libV1).Solution;
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.None, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+ Assert.Empty(results.Diagnostics);
+
+ // add newer version:
+ solution = project.AddMetadataReference(libV2).Solution;
+
+ results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : Error ENC1099: {string.Format(
+ FeaturesResources.Changing_project_or_package_reference_caused_the_identity_of_referenced_assembly_to_change_from_0_to_1_which_requires_restarting_the_application,
+ "Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",
+ "Lib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null")}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ debuggingSession.DiscardSolutionUpdate();
+
+ EndDebuggingSession(debuggingSession);
+ }
+
+ [Fact]
+ internal async Task Project_MetadataReferences_Add()
+ {
+ var source = "class C;";
+ var sourceFile = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ var libV1 = EmitLibraryReference(new Version(1, 0, 0, 0));
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", out var projectId).
+ AddTestDocument(source, sourceFile.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ // add dependency:
+ solution = project.AddMetadataReference(libV1).Solution;
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.None, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+ Assert.Empty(results.Diagnostics);
+
+ EndDebuggingSession(debuggingSession);
+ }
+
+ [Fact]
+ internal async Task Project_MetadataReferences_MultipleVersions()
+ {
+ var source = "class C;";
+ var sourceFile = Temp.CreateFile().WriteAllText(source, Encoding.UTF8);
+
+ var libV1 = EmitLibraryReference(new Version(1, 0, 0, 0), useStrongName: true);
+ var libV2 = EmitLibraryReference(new Version(2, 0, 0, 0), useStrongName: true);
+ var libV3 = EmitLibraryReference(new Version(3, 0, 0, 0), useStrongName: true);
+
+ using var w = CreateWorkspace(out var solution, out var service);
+
+ solution = solution.
+ AddTestProject("test", out var projectId).
+ AddMetadataReference(libV1).
+ AddMetadataReference(libV2).
+ AddTestDocument(source, sourceFile.Path, out var documentId).Project.Solution;
+
+ var project = solution.GetRequiredProject(projectId);
+
+ EmitAndLoadLibraryToDebuggee(project);
+
+ var debuggingSession = await StartDebuggingSessionAsync(service, solution);
+
+ // add version 3:
+ solution = project.AddMetadataReference(libV3).Solution;
+
+ var results = await EmitSolutionUpdateAsync(debuggingSession, solution, allowPartialUpdate: true);
+ Assert.Equal(ModuleUpdateStatus.Ready, results.ModuleUpdates.Status);
+ Assert.Empty(results.ModuleUpdates.Updates);
+
+ AssertEx.Equal(
+ [
+ $"test: : Error ENC1098: {string.Format(
+ FeaturesResources.Project_references_mutliple_assemblies_of_the_same_simple_name_0_1_Changing_a_reference_to_such_an_assembly_requires_restarting_the_application,
+ "Lib",
+ "'Lib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2', 'Lib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=ce65828c82a341f2'")}"
+ ], InspectDiagnostics(results.Diagnostics));
+
+ debuggingSession.DiscardSolutionUpdate();
+
+ EndDebuggingSession(debuggingSession);
+ }
+
[Fact]
public async Task DesignTimeOnlyDocument()
{
@@ -661,10 +1094,11 @@ public async Task ErrorReadingSourceFile()
debuggingSession.DiscardSolutionUpdate();
EndDebuggingSession(debuggingSession);
- AssertEx.Equal(
+ AssertEx.SequenceEqual(
[
"Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=1|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1",
- "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=|ProjectIdsWithUpdatedBaselines="
+ "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=True|HadValidInsignificantChanges=False|RudeEditsCount=0|EmitDeltaErrorIdCount=1|InBreakState=True|Capabilities=31|ProjectIdsWithAppliedChanges=|ProjectIdsWithUpdatedBaselines=",
+ "Debugging_EncSession_EditSession_EmitDeltaErrorId: SessionId=1|EditSessionId=2|ErrorId=ENC1006"
], _telemetryLog);
}
@@ -1742,7 +2176,7 @@ public async Task HasChanges_Documents(TextDocumentKind documentKind)
EnterBreakState(debuggingSession);
Assert.Equal(1, generatorExecutionCount);
- var documentDifferences = new ProjectDocumentDifferences();
+ var projectDifferences = new ProjectDifferences();
//
// Add document
@@ -1771,10 +2205,10 @@ public async Task HasChanges_Documents(TextDocumentKind documentKind)
await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None));
var diagnostics = new ArrayBuilder();
- await EditSession.GetDocumentDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), documentDifferences, diagnostics, CancellationToken.None);
+ await EditSession.GetProjectDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), projectDifferences, diagnostics, CancellationToken.None);
Assert.Empty(diagnostics);
- Assert.Empty(documentDifferences.Deleted);
- AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], documentDifferences.ChangedOrAdded.Select(d => d.Id));
+ Assert.Empty(projectDifferences.DeletedDocuments);
+ AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], projectDifferences.ChangedOrAddedDocuments.Select(d => d.Id));
Assert.Equal(1, generatorExecutionCount);
@@ -1801,9 +2235,9 @@ public async Task HasChanges_Documents(TextDocumentKind documentKind)
AssertEx.Equal(documentKind == TextDocumentKind.Document ? new[] { documentId } : [],
await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None));
- await EditSession.GetDocumentDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), documentDifferences, diagnostics, CancellationToken.None);
+ await EditSession.GetProjectDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), projectDifferences, diagnostics, CancellationToken.None);
Assert.Empty(diagnostics);
- Assert.True(documentDifferences.IsEmpty);
+ Assert.True(projectDifferences.IsEmpty);
Assert.Equal(1, generatorExecutionCount);
@@ -1826,10 +2260,10 @@ public async Task HasChanges_Documents(TextDocumentKind documentKind)
AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId],
await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None));
- await EditSession.GetDocumentDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), documentDifferences, diagnostics, CancellationToken.None);
+ await EditSession.GetProjectDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), projectDifferences, diagnostics, CancellationToken.None);
Assert.Empty(diagnostics);
- Assert.Empty(documentDifferences.Deleted);
- AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], documentDifferences.ChangedOrAdded.Select(d => d.Id));
+ Assert.Empty(projectDifferences.DeletedDocuments);
+ AssertEx.Equal(documentKind == TextDocumentKind.Document ? [documentId, generatedDocumentId] : [generatedDocumentId], projectDifferences.ChangedOrAddedDocuments.Select(d => d.Id));
Assert.Equal(1, generatorExecutionCount);
@@ -1854,19 +2288,19 @@ public async Task HasChanges_Documents(TextDocumentKind documentKind)
AssertEx.Equal([generatedDocumentId],
await EditSession.GetChangedDocumentsAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None));
- await EditSession.GetDocumentDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), documentDifferences, diagnostics, CancellationToken.None);
+ await EditSession.GetProjectDifferencesAsync(log, oldSolution.GetProject(projectId), solution.GetProject(projectId), projectDifferences, diagnostics, CancellationToken.None);
Assert.Empty(diagnostics);
if (documentKind == TextDocumentKind.Document)
{
- AssertEx.Equal([documentId], documentDifferences.Deleted.Select(d => d.Id));
+ AssertEx.Equal([documentId], projectDifferences.DeletedDocuments.Select(d => d.Id));
}
else
{
- AssertEx.Empty(documentDifferences.Deleted);
+ AssertEx.Empty(projectDifferences.DeletedDocuments);
}
- AssertEx.Equal([generatedDocumentId], documentDifferences.ChangedOrAdded.Select(d => d.Id));
+ AssertEx.Equal([generatedDocumentId], projectDifferences.ChangedOrAddedDocuments.Select(d => d.Id));
Assert.Equal(1, generatorExecutionCount);
}
@@ -1919,7 +2353,7 @@ public async Task HasChanges_SourceGeneratorFailure()
var debuggingSession = await StartDebuggingSessionAsync(service, solution);
EnterBreakState(debuggingSession);
- var documentDiffences = new ProjectDocumentDifferences();
+ var diffences = new ProjectDifferences();
//
// Update document content
@@ -1937,10 +2371,10 @@ public async Task HasChanges_SourceGeneratorFailure()
AssertEx.Empty(await EditSession.GetChangedDocumentsAsync(log, oldProject, project, CancellationToken.None).ToImmutableArrayAsync(CancellationToken.None));
var diagnostics = new ArrayBuilder();
- await EditSession.GetDocumentDifferencesAsync(log, oldProject, project, documentDiffences, diagnostics, CancellationToken.None);
+ await EditSession.GetProjectDifferencesAsync(log, oldProject, project, diffences, diagnostics, CancellationToken.None);
Assert.Contains("System.InvalidOperationException: Source generator failed", diagnostics.Single().GetMessage());
- AssertEx.Empty(documentDiffences.ChangedOrAdded);
- AssertEx.Equal(["generated.cs"], documentDiffences.Deleted.Select(d => d.Name));
+ AssertEx.Empty(diffences.ChangedOrAddedDocuments);
+ AssertEx.Equal(["generated.cs"], diffences.DeletedDocuments.Select(d => d.Name));
Assert.Equal(2, generatorExecutionCount);
@@ -3437,7 +3871,8 @@ public async Task ValidInsignificantChange()
AssertEx.SequenceEqual(
[
- "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=0|EmptyHotReloadSessionCount=1",
+ "Debugging_EncSession: SolutionSessionId={00000000-AAAA-AAAA-AAAA-000000000000}|SessionId=1|SessionCount=0|EmptySessionCount=0|HotReloadSessionCount=1|EmptyHotReloadSessionCount=0",
+ "Debugging_EncSession_EditSession: SessionId=1|EditSessionId=2|HadCompilationErrors=False|HadRudeEdits=False|HadValidChanges=False|HadValidInsignificantChanges=True|RudeEditsCount=0|EmitDeltaErrorIdCount=0|InBreakState=False|Capabilities=31|ProjectIdsWithAppliedChanges=|ProjectIdsWithUpdatedBaselines="
], _telemetryLog);
}
diff --git a/src/roslyn/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs b/src/roslyn/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs
index 3f55d58c5b4..308fc11242d 100644
--- a/src/roslyn/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs
+++ b/src/roslyn/src/Features/TestUtilities/EditAndContinue/EditAndContinueWorkspaceTestBase.cs
@@ -305,12 +305,13 @@ internal Guid EmitAndLoadLibraryToDebuggee(Project project, TargetFramework targ
internal Guid EmitAndLoadLibraryToDebuggee(
ProjectId projectId,
string source,
+ string language = LanguageNames.CSharp,
string? sourceFilePath = null,
Encoding? encoding = null,
SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithms.Default,
- string assemblyName = "",
+ string? assemblyName = null,
TargetFramework targetFramework = DefaultTargetFramework)
- => LoadLibraryToDebuggee(EmitLibrary(projectId, source, sourceFilePath, encoding, checksumAlgorithm, assemblyName, targetFramework: targetFramework));
+ => LoadLibraryToDebuggee(EmitLibrary(projectId, source, sourceFilePath, language, encoding, checksumAlgorithm, assemblyName, targetFramework: targetFramework));
internal Guid LoadLibraryToDebuggee(Guid moduleId, ManagedHotReloadAvailability availability = default)
{
@@ -322,6 +323,7 @@ internal Guid EmitLibrary(Project project, TargetFramework targetFramework = Def
=> EmitLibrary(
project.Id,
project.Documents.Select(d => (d.GetTextSynchronously(CancellationToken.None), d.FilePath ?? throw ExceptionUtilities.UnexpectedValue(null))),
+ project.Language,
project.AssemblyName,
targetFramework: targetFramework);
@@ -329,9 +331,10 @@ internal Guid EmitLibrary(
ProjectId projectId,
string source,
string? sourceFilePath = null,
+ string language = LanguageNames.CSharp,
Encoding? encoding = null,
SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithms.Default,
- string assemblyName = "",
+ string? assemblyName = null,
DebugInformationFormat pdbFormat = DebugInformationFormat.PortablePdb,
Project? generatorProject = null,
string? additionalFileText = null,
@@ -340,6 +343,7 @@ internal Guid EmitLibrary(
=> EmitLibrary(
projectId,
[(source, sourceFilePath ?? Path.Combine(TempRoot.Root, "test1.cs"))],
+ language,
encoding,
checksumAlgorithm,
assemblyName,
@@ -352,20 +356,20 @@ internal Guid EmitLibrary(
internal Guid EmitLibrary(
ProjectId projectId,
(string content, string filePath)[] sources,
+ string language = LanguageNames.CSharp,
Encoding? encoding = null,
SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithms.Default,
- string assemblyName = "",
+ string? assemblyName = null,
DebugInformationFormat pdbFormat = DebugInformationFormat.PortablePdb,
Project? generatorProject = null,
string? additionalFileText = null,
IEnumerable<(string, string)>? analyzerOptions = null,
TargetFramework targetFramework = DefaultTargetFramework)
{
- encoding ??= Encoding.UTF8;
-
return EmitLibrary(
projectId,
- sources.Select(source => (SourceText.From(new MemoryStream(encoding.GetBytesWithPreamble(source.content.ToString())), encoding, checksumAlgorithm), source.filePath)),
+ sources.Select(source => (CreateText(source.content, encoding, checksumAlgorithm), source.filePath)),
+ language,
assemblyName,
pdbFormat,
generatorProject,
@@ -374,34 +378,70 @@ internal Guid EmitLibrary(
targetFramework);
}
+ internal static SourceText CreateText(string source, Encoding? encoding = null, SourceHashAlgorithm checksumAlgorithm = SourceHashAlgorithms.Default)
+ {
+ encoding ??= Encoding.UTF8;
+ return SourceText.From(new MemoryStream(encoding.GetBytesWithPreamble(source)), encoding, checksumAlgorithm);
+ }
+
internal Guid EmitLibrary(
ProjectId projectId,
IEnumerable<(SourceText text, string filePath)> sources,
- string assemblyName = "",
+ string language = LanguageNames.CSharp,
+ string? assemblyName = null,
DebugInformationFormat pdbFormat = DebugInformationFormat.PortablePdb,
Project? generatorProject = null,
string? additionalFileText = null,
IEnumerable<(string, string)>? analyzerOptions = null,
TargetFramework targetFramework = DefaultTargetFramework)
{
- var parseOptions = TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute();
+ Compilation compilation;
+ CSharpParseOptions? csParseOptions = null;
+ VisualBasic.VisualBasicParseOptions? vbParseOptions = null;
- var trees = sources.Select(source => SyntaxFactory.ParseSyntaxTree(source.text, parseOptions, source.filePath));
+ var references = TargetFrameworkUtil.GetReferences(targetFramework);
+ assemblyName ??= "TestAssembly";
- Compilation compilation = CSharpTestBase.CreateCompilation(trees.ToArray(), options: TestOptions.DebugDll, targetFramework: targetFramework, assemblyName: assemblyName);
+ if (language == LanguageNames.CSharp)
+ {
+ csParseOptions = TestOptions.RegularPreview.WithNoRefSafetyRulesAttribute();
+ var trees = sources.Select(source => SyntaxFactory.ParseSyntaxTree(source.text, csParseOptions, source.filePath));
+ compilation = CSharpCompilation.Create(assemblyName, trees, references, TestOptions.DebugDll);
+ }
+ else
+ {
+ vbParseOptions = VisualBasic.UnitTests.TestOptions.Regular;
+ var trees = sources.Select(source => VisualBasic.SyntaxFactory.ParseSyntaxTree(source.text, vbParseOptions, source.filePath));
+ compilation = VisualBasic.VisualBasicCompilation.Create(assemblyName, trees, references, VisualBasic.UnitTests.TestOptions.DebugDll);
+ }
if (generatorProject != null)
{
var generators = generatorProject.AnalyzerReferences.SelectMany(r => r.GetGenerators(language: generatorProject.Language));
+ var driverOptions = new GeneratorDriverOptions(baseDirectory: generatorProject.CompilationOutputInfo.GetEffectiveGeneratedFilesOutputDirectory()!);
var optionsProvider = (analyzerOptions != null) ? new EditAndContinueTestAnalyzerConfigOptionsProvider(analyzerOptions) : null;
var additionalTexts = (additionalFileText != null) ? new[] { new InMemoryAdditionalText("additional_file", additionalFileText) } : null;
- var generatorDriver = CSharpGeneratorDriver.Create(
- generators,
- additionalTexts,
- parseOptions,
- optionsProvider,
- driverOptions: new GeneratorDriverOptions(baseDirectory: generatorProject.CompilationOutputInfo.GetEffectiveGeneratedFilesOutputDirectory()!));
+
+ GeneratorDriver generatorDriver;
+ if (language == LanguageNames.CSharp)
+ {
+ generatorDriver = CSharpGeneratorDriver.Create(
+ generators,
+ additionalTexts,
+ csParseOptions!,
+ optionsProvider,
+ driverOptions);
+ }
+ else
+ {
+ generatorDriver = VisualBasic.VisualBasicGeneratorDriver.Create(
+ [.. generators],
+ additionalTexts.ToImmutableArrayOrEmpty(),
+ vbParseOptions!,
+ optionsProvider,
+ driverOptions);
+ }
generatorDriver.RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var generatorDiagnostics);
generatorDiagnostics.Verify();
diff --git a/src/roslyn/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb b/src/roslyn/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb
index 3d92612f569..30ce9c4296c 100644
--- a/src/roslyn/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb
+++ b/src/roslyn/src/Features/VisualBasic/Portable/EditAndContinue/VisualBasicEditAndContinueAnalyzer.vb
@@ -2357,5 +2357,67 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
End Sub
#End Region
+
+ Protected Overrides Iterator Function GetParseOptionsRudeEdits(oldOptions As ParseOptions, newOptions As ParseOptions) As IEnumerable(Of Diagnostic)
+ For Each rudeEdit In MyBase.GetParseOptionsRudeEdits(oldOptions, newOptions)
+ Yield rudeEdit
+ Next
+
+ Dim oldVBOptions = DirectCast(oldOptions, VisualBasicParseOptions)
+ Dim newVBOptions = DirectCast(newOptions, VisualBasicParseOptions)
+
+ If oldVBOptions.LanguageVersion <> newVBOptions.LanguageVersion Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.LangVersion,
+ oldVBOptions.SpecifiedLanguageVersion.ToDisplayString(),
+ newVBOptions.SpecifiedLanguageVersion.ToDisplayString())
+ End If
+
+ If Not oldVBOptions.PreprocessorSymbols.SequenceEqual(newVBOptions.PreprocessorSymbols) Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.DefineConstants,
+ GetPreprocessorSymbolsDisplay(oldVBOptions.PreprocessorSymbols),
+ GetPreprocessorSymbolsDisplay(newVBOptions.PreprocessorSymbols))
+ End If
+ End Function
+
+ Private Shared Function GetPreprocessorSymbolsDisplay(symbols As ImmutableArray(Of KeyValuePair(Of String, Object))) As String
+ Return String.Join(",", symbols.Select(Function(kvp) kvp.Key & "=" & kvp.Value.ToString()))
+ End Function
+
+ Protected Overrides Iterator Function GetCompilationOptionsRudeEdits(oldOptions As CompilationOptions, newOptions As CompilationOptions) As IEnumerable(Of Diagnostic)
+ For Each rudeEdit In MyBase.GetCompilationOptionsRudeEdits(oldOptions, newOptions)
+ Yield rudeEdit
+ Next
+
+ Dim oldVBOptions = DirectCast(oldOptions, VisualBasicCompilationOptions)
+ Dim newVBOptions = DirectCast(newOptions, VisualBasicCompilationOptions)
+
+ If oldVBOptions.RootNamespace <> newVBOptions.RootNamespace Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.RootNamespace, oldVBOptions.RootNamespace, newVBOptions.RootNamespace)
+ End If
+
+ If oldVBOptions.OptionStrict <> newVBOptions.OptionStrict Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.OptionStrict, oldVBOptions.OptionStrict.ToString(), newVBOptions.OptionStrict.ToString())
+ End If
+
+ If oldVBOptions.OptionInfer <> newVBOptions.OptionInfer Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.OptionInfer, GetOptionDisplay(oldVBOptions.OptionInfer), GetOptionDisplay(newVBOptions.OptionInfer))
+ End If
+
+ If oldVBOptions.OptionExplicit <> newVBOptions.OptionExplicit Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.OptionExplicit, GetOptionDisplay(oldVBOptions.OptionExplicit), GetOptionDisplay(newVBOptions.OptionExplicit))
+ End If
+
+ If oldVBOptions.OptionCompareText <> newVBOptions.OptionCompareText Then
+ Yield CreateProjectRudeEdit(ProjectSettingKind.OptionCompare, GetOptionCompareTextDisplay(oldVBOptions.OptionCompareText), GetOptionCompareTextDisplay(newVBOptions.OptionCompareText))
+ End If
+ End Function
+
+ Private Shared Function GetOptionDisplay(value As Boolean) As String
+ Return If(value, "On", "Off")
+ End Function
+
+ Private Shared Function GetOptionCompareTextDisplay(value As Boolean) As String
+ Return If(value, "Text", "Binary")
+ End Function
End Class
End Namespace
diff --git a/src/roslyn/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb b/src/roslyn/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb
index 27829387115..86c7757678d 100644
--- a/src/roslyn/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb
+++ b/src/roslyn/src/Features/VisualBasicTest/EditAndContinue/VisualBasicEditAndContinueAnalyzerTests.vb
@@ -522,8 +522,9 @@ End Class
Dim result = Await AnalyzeDocumentAsync(oldProject, oldDocument)
Assert.False(result.HasChanges)
- Assert.False(result.HasChangesAndErrors)
- Assert.False(result.HasChangesAndSyntaxErrors)
+ Assert.False(result.AnalysisBlocked)
+ Assert.False(result.HasBlockingRudeEdits)
+ Assert.Null(result.SyntaxError)
End Using
End Function
@@ -554,8 +555,9 @@ End Class
Dim result = Await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId))
Assert.False(result.HasChanges)
- Assert.False(result.HasChangesAndErrors)
- Assert.False(result.HasChangesAndSyntaxErrors)
+ Assert.False(result.AnalysisBlocked)
+ Assert.False(result.HasBlockingRudeEdits)
+ Assert.Null(result.SyntaxError)
End Using
End Function
@@ -578,8 +580,9 @@ End Class
Dim result = Await AnalyzeDocumentAsync(oldProject, oldDocument)
Assert.False(result.HasChanges)
- Assert.False(result.HasChangesAndErrors)
- Assert.False(result.HasChangesAndSyntaxErrors)
+ Assert.False(result.AnalysisBlocked)
+ Assert.False(result.HasBlockingRudeEdits)
+ Assert.Null(result.SyntaxError)
End Using
End Function
@@ -612,8 +615,9 @@ End Class
Dim result = Await AnalyzeDocumentAsync(oldProject, newSolution.GetDocument(documentId))
' no declaration errors (error in method body is only reported when emitting)
- Assert.False(result.HasChangesAndErrors)
- Assert.False(result.HasChangesAndSyntaxErrors)
+ Assert.False(result.AnalysisBlocked)
+ Assert.False(result.HasBlockingRudeEdits)
+ Assert.Null(result.SyntaxError)
End Using
End Function
@@ -645,8 +649,9 @@ End Class
' No errors reported: EnC analyzer is resilient against semantic errors.
' They will be reported by 1) compiler diagnostic analyzer 2) when emitting delta - if still present.
- Assert.False(result.HasChangesAndErrors)
- Assert.False(result.HasChangesAndSyntaxErrors)
+ Assert.False(result.AnalysisBlocked)
+ Assert.False(result.HasBlockingRudeEdits)
+ Assert.Null(result.SyntaxError)
End Using
End Function
diff --git a/src/roslyn/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.vb b/src/roslyn/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.vb
new file mode 100644
index 00000000000..6d26e13134e
--- /dev/null
+++ b/src/roslyn/src/Features/VisualBasicTest/ImplementInterface/ImplementInterfaceCodeRefactoringTests.vb
@@ -0,0 +1,55 @@
+' Licensed to the .NET Foundation under one or more agreements.
+' The .NET Foundation licenses this file to you under the MIT license.
+' See the LICENSE file in the project root for more information.
+
+Imports VerifyVb = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.VisualBasicCodeRefactoringVerifier(Of
+ Microsoft.CodeAnalysis.ImplementInterface.ImplementInterfaceCodeRefactoringProvider)
+
+Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.ImplementInterface
+
+
+ Public NotInheritable Class ImplementInterfaceCodeRefactoringTests
+
+
+ Public Function TestInBody() As Task
+ Return VerifyVb.VerifyRefactoringAsync("
+interface IGoo
+ sub Goo()
+end interface
+
+class C
+ implements {|BC30149:IGoo|}
+
+ $$
+end class
+ ", "
+interface IGoo
+ sub Goo()
+end interface
+
+class C
+ implements IGoo
+
+ Public Sub Goo() Implements IGoo.Goo
+ Throw New System.NotImplementedException()
+ End Sub
+end class
+ ")
+ End Function
+
+
+ Public Function TestNotOnInterfaceInBody() As Task
+ Return VerifyVb.VerifyRefactoringAsync("
+interface IGoo
+ sub Goo()
+end interface
+
+interface IBar
+ inherits IGoo
+
+ $$
+end interface
+ ")
+ End Function
+ End Class
+End Namespace
diff --git a/src/roslyn/src/Interactive/HostTest/AbstractInteractiveHostTests.cs b/src/roslyn/src/Interactive/HostTest/AbstractInteractiveHostTests.cs
index a733de3dad0..ea9e007039d 100644
--- a/src/roslyn/src/Interactive/HostTest/AbstractInteractiveHostTests.cs
+++ b/src/roslyn/src/Interactive/HostTest/AbstractInteractiveHostTests.cs
@@ -22,6 +22,7 @@
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
using InteractiveHost::Microsoft.CodeAnalysis.Interactive;
+ using Xunit.Abstractions;
public abstract class AbstractInteractiveHostTests : CSharpTestBase, IAsyncLifetime
{
@@ -30,6 +31,7 @@ public abstract class AbstractInteractiveHostTests : CSharpTestBase, IAsyncLifet
private int[] _outputReadPosition = [0, 0];
internal readonly InteractiveHost Host;
+ internal readonly ITestOutputHelper TestOutputHelper;
// DOTNET_ROOT must be set in order to run host process on .NET Core on machines (like CI)
// that do not have the required version of the runtime installed globally.
@@ -57,12 +59,13 @@ static AbstractInteractiveHostTests()
}
}
- protected AbstractInteractiveHostTests()
+ protected AbstractInteractiveHostTests(ITestOutputHelper testOutputHelper)
{
+ TestOutputHelper = testOutputHelper;
Host = new InteractiveHost(typeof(CSharpReplServiceProvider), ".", millisecondsTimeout: -1, joinOutputWritingThreadsOnDisposal: true);
Host.InteractiveHostProcessCreationFailed += (exception, exitCode) =>
- Assert.False(true, (exception?.Message ?? "Host process terminated unexpectedly.") + $" Exit code: {exitCode?.ToString() ?? ""}");
+ testOutputHelper.WriteLine((exception?.Message ?? "Host process terminated unexpectedly.") + $" Exit code: {exitCode?.ToString() ?? ""}");
RedirectOutput();
}
diff --git a/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreInitTests.cs b/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreInitTests.cs
index 6dff687d2e2..a635abd68b5 100644
--- a/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreInitTests.cs
+++ b/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreInitTests.cs
@@ -14,9 +14,10 @@
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
using InteractiveHost::Microsoft.CodeAnalysis.Interactive;
+ using Xunit.Abstractions;
[Trait(Traits.Feature, Traits.Features.InteractiveHost)]
- public sealed class InteractiveHostCoreInitTests : AbstractInteractiveHostTests
+ public sealed class InteractiveHostCoreInitTests(ITestOutputHelper testOutputHelper) : AbstractInteractiveHostTests(testOutputHelper)
{
internal override InteractiveHostPlatform DefaultPlatform => InteractiveHostPlatform.Core;
internal override bool UseDefaultInitializationFile => true;
diff --git a/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreTests.cs b/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreTests.cs
index 39a0bc1148f..4ca3b11379e 100644
--- a/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreTests.cs
+++ b/src/roslyn/src/Interactive/HostTest/InteractiveHostCoreTests.cs
@@ -10,9 +10,10 @@
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
using InteractiveHost::Microsoft.CodeAnalysis.Interactive;
+ using Xunit.Abstractions;
[Trait(Traits.Feature, Traits.Features.InteractiveHost)]
- public sealed class InteractiveHostCoreTests : AbstractInteractiveHostTests
+ public sealed class InteractiveHostCoreTests(ITestOutputHelper testOutputHelper) : AbstractInteractiveHostTests(testOutputHelper)
{
internal override InteractiveHostPlatform DefaultPlatform => InteractiveHostPlatform.Core;
internal override bool UseDefaultInitializationFile => false;
diff --git a/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopInitTests.cs b/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopInitTests.cs
index 3db92fbef3a..7749771c81c 100644
--- a/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopInitTests.cs
+++ b/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopInitTests.cs
@@ -13,9 +13,10 @@
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
using InteractiveHost::Microsoft.CodeAnalysis.Interactive;
+ using Xunit.Abstractions;
[Trait(Traits.Feature, Traits.Features.InteractiveHost)]
- public sealed class InteractiveHostDesktopInitTests : AbstractInteractiveHostTests
+ public sealed class InteractiveHostDesktopInitTests(ITestOutputHelper testOutputHelper) : AbstractInteractiveHostTests(testOutputHelper)
{
internal override InteractiveHostPlatform DefaultPlatform => InteractiveHostPlatform.Desktop32;
internal override bool UseDefaultInitializationFile => true;
diff --git a/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopTests.cs b/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopTests.cs
index eda6c32516d..e25a04752fe 100644
--- a/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopTests.cs
+++ b/src/roslyn/src/Interactive/HostTest/InteractiveHostDesktopTests.cs
@@ -18,9 +18,10 @@
namespace Microsoft.CodeAnalysis.UnitTests.Interactive
{
using InteractiveHost::Microsoft.CodeAnalysis.Interactive;
+ using Xunit.Abstractions;
[Trait(Traits.Feature, Traits.Features.InteractiveHost)]
- public sealed class InteractiveHostDesktopTests : AbstractInteractiveHostTests
+ public sealed class InteractiveHostDesktopTests(ITestOutputHelper testOutputHelper) : AbstractInteractiveHostTests(testOutputHelper)
{
internal override InteractiveHostPlatform DefaultPlatform => InteractiveHostPlatform.Desktop64;
internal override bool UseDefaultInitializationFile => false;
diff --git a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs
index 35f3406c1bb..1b7a230ddb6 100644
--- a/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs
+++ b/src/roslyn/src/LanguageServer/Protocol/Workspaces/LspWorkspaceRegistrationService.cs
@@ -39,7 +39,9 @@ public virtual void Register(Workspace? workspace)
m["WorkspacePartialSemanticsEnabled"] = workspace.PartialSemanticsEnabled;
}, workspace));
- var workspaceChangedDisposer = workspace.RegisterWorkspaceChangedHandler(OnLspWorkspaceChanged);
+ // Forward workspace change events for all registered LSP workspaces. Requires main thread as it
+ // fires LspSolutionChanged which hasn't been guaranteed to be thread safe.
+ var workspaceChangedDisposer = workspace.RegisterWorkspaceChangedHandler(OnLspWorkspaceChanged, WorkspaceEventOptions.RequiresMainThreadOptions);
lock (_gate)
{
@@ -92,7 +94,9 @@ public void Dispose()
}
///
- /// Indicates whether the LSP solution has changed in a non-tracked document context. May be raised on any thread.
+ /// Indicates whether the LSP solution has changed in a non-tracked document context.
+ ///
+ /// IMPORTANT: Implementations of this event handler should do as little synchronous work as possible since this will block.
///
public EventHandler? LspSolutionChanged;
}
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_False/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_True/Resources.Designer.cs
index c7688ac134b..f73138317b9 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsCSharpAsync_True/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public const string @Name = "Name";
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_False/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_False/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_False/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_False/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_True/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_True/Resources.Designer.vb
index 3a7ff2a36a2..51007fe2741 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_True/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_AsConstantsVisualBasicAsync_True/Resources.Designer.vb
@@ -26,4 +26,4 @@ Namespace Global.TestProject
Public Const [Name] As String = "Name"
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS/Resources.Designer.cs
index 88c52285685..7e9c3d31869 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS/Resources.Designer.cs
@@ -20,4 +20,3 @@ internal static partial class NS
public static string @Name => GetResourceString("Name")!;
}
-
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS1.NS2/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS1.NS2/Resources.Designer.cs
index 4ded4b004c5..0b14582ae4d 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS1.NS2/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameCSharpAsync_NS1.NS2/Resources.Designer.cs
@@ -21,4 +21,4 @@ internal static partial class NS2
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS/Resources.Designer.vb
index 84a8ca15a65..99fb93d5066 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS/Resources.Designer.vb
@@ -33,4 +33,3 @@ Friend Partial Class NS
End Property
End Class
-
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS1.NS2/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS1.NS2/Resources.Designer.vb
index 866c481c2e8..aec967ea7e6 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS1.NS2/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_ClassNameVisualBasicAsync_NS1.NS2/Resources.Designer.vb
@@ -33,4 +33,4 @@ Namespace Global.NS1
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp5/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp5/Resources.Designer.cs
index ff7d2796857..1add95c0120 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp5/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp5/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name");
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp6/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp6/Resources.Designer.cs
index ff7d2796857..1add95c0120 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp6/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp6/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name");
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp7/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp7/Resources.Designer.cs
index ff7d2796857..1add95c0120 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp7/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp7/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name");
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp8/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp8/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp8/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp8/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp9/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp9/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp9/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultCSharpAsync_CSharp9/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultVisualBasicAsync/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_DefaultVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_False/Resources.Designer.cs
index 5d380b3db16..a3bf560ad79 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_True/Resources.Designer.cs
index b3919a15c4f..12087eef572 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_0_True/Resources.Designer.cs
@@ -14,7 +14,6 @@ internal static partial class Resources
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("defaultValue")]
internal static string? GetResourceString(string resourceKey, string? defaultValue = null) => ResourceManager.GetString(resourceKey, Culture) ?? defaultValue;
-
private static string GetResourceString(string resourceKey, string[]? formatterNames)
{
var value = GetResourceString(resourceKey) ?? "";
@@ -27,7 +26,6 @@ private static string GetResourceString(string resourceKey, string[]? formatterN
}
return value;
}
-
/// value {0}
public static string @Name => GetResourceString("Name")!;
/// value {0}
@@ -36,4 +34,4 @@ internal static string FormatName(object? p0)
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_False/Resources.Designer.cs
index 4feef75d44d..590417cc803 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_True/Resources.Designer.cs
index fa77240ec63..06520b226cd 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_replacement_True/Resources.Designer.cs
@@ -14,7 +14,6 @@ internal static partial class Resources
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("defaultValue")]
internal static string? GetResourceString(string resourceKey, string? defaultValue = null) => ResourceManager.GetString(resourceKey, Culture) ?? defaultValue;
-
private static string GetResourceString(string resourceKey, string[]? formatterNames)
{
var value = GetResourceString(resourceKey) ?? "";
@@ -27,7 +26,6 @@ private static string GetResourceString(string resourceKey, string[]? formatterN
}
return value;
}
-
/// value {replacement}
public static string @Name => GetResourceString("Name")!;
/// value {replacement}
@@ -36,4 +34,4 @@ internal static string FormatName(object? replacement)
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_False/Resources.Designer.cs
index 19b20ba8116..2587512dce4 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_True/Resources.Designer.cs
index fe057e9cbfc..a7f8f5585ef 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsCSharpAsync_x_True/Resources.Designer.cs
@@ -14,7 +14,6 @@ internal static partial class Resources
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
[return: global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("defaultValue")]
internal static string? GetResourceString(string resourceKey, string? defaultValue = null) => ResourceManager.GetString(resourceKey, Culture) ?? defaultValue;
-
private static string GetResourceString(string resourceKey, string[]? formatterNames)
{
var value = GetResourceString(resourceKey) ?? "";
@@ -27,7 +26,6 @@ private static string GetResourceString(string resourceKey, string[]? formatterN
}
return value;
}
-
/// value {x}
public static string @Name => GetResourceString("Name")!;
/// value {x}
@@ -36,4 +34,4 @@ internal static string FormatName(object? x)
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsVisualBasicAsync_False/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsVisualBasicAsync_False/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsVisualBasicAsync_False/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_EmitFormatMethodsVisualBasicAsync_False/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_False/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_True/Resources.Designer.cs
index 1473a8f809b..63a7569d3f4 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesCSharpAsync_True/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name", @"value");
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_False/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_False/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_False/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_False/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_True/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_True/Resources.Designer.vb
index a7d121e8de9..efd9799c93b 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_True/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_IncludeDefaultValuesVisualBasicAsync_True/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591/Resources.Designer.cs
index 2de335ef912..18d0d80d628 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591/Resources.Designer.cs
@@ -22,4 +22,4 @@ internal static partial class Resources
}
}
-#pragma warning restore CS1591
+#pragma warning restore CS1591
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591_IDE0010/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591_IDE0010/Resources.Designer.cs
index 62cee7c3c5d..0d2a9ee2c9c 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591_IDE0010/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsCSharpAsync_CS1591_IDE0010/Resources.Designer.cs
@@ -22,4 +22,4 @@ internal static partial class Resources
}
}
-#pragma warning restore CS1591, IDE0010
+#pragma warning restore CS1591, IDE0010
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591/Resources.Designer.vb
index 17132d5e682..d6bc23deb51 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591/Resources.Designer.vb
@@ -34,4 +34,4 @@ Namespace Global.TestProject
End Class
End Namespace
-#Enable Warning CS1591
+#Enable Warning CS1591
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591_IDE0010/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591_IDE0010/Resources.Designer.vb
index 72d82353a18..13a14784266 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591_IDE0010/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_NoWarnsVisualBasicAsync_CS1591_IDE0010/Resources.Designer.vb
@@ -34,4 +34,4 @@ Namespace Global.TestProject
End Class
End Namespace
-#Enable Warning CS1591, IDE0010
+#Enable Warning CS1591, IDE0010
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_False/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_True/Resources.Designer.cs
index 82e188c9794..4dcdb8ee2d7 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringCSharpAsync_True/Resources.Designer.cs
@@ -15,4 +15,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_False/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_False/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_False/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_False/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_True/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_True/Resources.Designer.vb
index 2a310c4b2fc..e09b6fa5270 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_True/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_OmitGetResourceStringVisualBasicAsync_True/Resources.Designer.vb
@@ -26,4 +26,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_False/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_False/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_False/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_False/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_True/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_True/Resources.Designer.cs
index 5aec8c10768..fa8c5ef10b5 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_True/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicCSharpAsync_True/Resources.Designer.cs
@@ -18,4 +18,4 @@ public static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_False/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_False/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_False/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_False/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_True/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_True/Resources.Designer.vb
index 64be47f98a0..93940b29acd 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_True/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_PublicVisualBasicAsync_True/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync/Resources.Designer.cs
index c1c925afa5a..2fac9e79a91 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS/Resources.Designer.cs
index 1f3c879f307..a6af5bd3745 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class NSResources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS1.NS2/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS1.NS2/Resources.Designer.cs
index f32431e7877..c1d9e6b1313 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS1.NS2/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirCSharpAsync_NS1.NS2/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class NS2Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync/Resources.Designer.vb
index 7e5e0abe937..1881b74aa2f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS/Resources.Designer.vb
index 8bd90c0fae2..847700ea28f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS1.NS2/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS1.NS2/Resources.Designer.vb
index c0a22ef9916..af17bb8acc0 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS1.NS2/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RelativeDirVisualBasicAsync_NS1.NS2/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject.NS1
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync/Resources.Designer.cs
index f82cd001930..030e93a3845 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync/Resources.Designer.cs
@@ -17,4 +17,3 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS/Resources.Designer.cs
index e92f3ef2ade..a843b814f1f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS1.NS2/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS1.NS2/Resources.Designer.cs
index 9bdce5dfefd..523f57c6448 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS1.NS2/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceCSharpAsync_NS1.NS2/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync/Resources.Designer.vb
index 0b157c51018..9359a0d0fa1 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,3 @@ Friend Partial Class Resources
End Property
End Class
-
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS/Resources.Designer.vb
index 1d7d203bc1f..ca6eedd3ab0 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.NS
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS1.NS2/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS1.NS2/Resources.Designer.vb
index 25ea9cf6a93..8e004bd0a81 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS1.NS2/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/SingleString_RootNamespaceVisualBasicAsync_NS1.NS2/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.NS1.NS2
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources.Designer.cs
index ec47ea64240..6074150a4e4 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources0.Designer.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources0.Designer.cs
index 26e3d38af15..35ec698372f 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources0.Designer.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultCSharpAsync/Resources0.Designer.cs
@@ -18,4 +18,4 @@ internal static partial class Resources
public static string @Name => GetResourceString("Name")!;
}
-}
+}
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources.Designer.vb
index dd7fa8fdeb5..24298d6b5a7 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject.First
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources0.Designer.vb b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources0.Designer.vb
index b4a921a70e1..2bc55392ba0 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources0.Designer.vb
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator.UnitTests/Resources/TwoResourcesSameName_DefaultVisualBasicAsync/Resources0.Designer.vb
@@ -30,4 +30,4 @@ Namespace Global.TestProject.Second
End Property
End Class
-End Namespace
+End Namespace
\ No newline at end of file
diff --git a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator/AbstractResxGenerator.cs b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator/AbstractResxGenerator.cs
index dfa509b9a44..1d9bb6027c9 100644
--- a/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator/AbstractResxGenerator.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Microsoft.CodeAnalysis.ResxSourceGenerator/Microsoft.CodeAnalysis.ResxSourceGenerator/AbstractResxGenerator.cs
@@ -519,6 +519,7 @@ public bool Execute(CancellationToken cancellationToken)
if (ResourceInformation.EmitFormatMethods)
{
getStringMethod += $$"""
+
{{memberIndent}}private static string GetResourceString(string resourceKey, string[]? formatterNames)
{{memberIndent}}{
{{memberIndent}} var value = GetResourceString(resourceKey) ?? "";
diff --git a/src/roslyn/src/RoslynAnalyzers/Utilities.UnitTests/FlowAnalysis/Analysis/PropertySetAnalysis/PropertySetAnalysisTests.cs b/src/roslyn/src/RoslynAnalyzers/Utilities.UnitTests/FlowAnalysis/Analysis/PropertySetAnalysis/PropertySetAnalysisTests.cs
index a512fd506f5..434026e4ce0 100644
--- a/src/roslyn/src/RoslynAnalyzers/Utilities.UnitTests/FlowAnalysis/Analysis/PropertySetAnalysis/PropertySetAnalysisTests.cs
+++ b/src/roslyn/src/RoslynAnalyzers/Utilities.UnitTests/FlowAnalysis/Analysis/PropertySetAnalysis/PropertySetAnalysisTests.cs
@@ -163,54 +163,53 @@ static string MethodOrReturnString(string? method)
}
}
- private readonly string TestTypeToTrackSource = """
- public class TestTypeToTrack
- {
- public TestEnum AnEnum { get; set; }
- public object AnObject { get; set; }
- public string AString { get; set; }
+ private readonly string TestTypeToTrackSource = @"
+public class TestTypeToTrack
+{
+ public TestEnum AnEnum { get; set; }
+ public object AnObject { get; set; }
+ public string AString { get; set; }
- public void Method()
- {
- }
- }
+ public void Method()
+ {
+ }
+}
- public class TestTypeToTrackWithConstructor : TestTypeToTrack
- {
- private TestTypeToTrackWithConstructor()
- {
- }
+public class TestTypeToTrackWithConstructor : TestTypeToTrack
+{
+ private TestTypeToTrackWithConstructor()
+ {
+ }
- public TestTypeToTrackWithConstructor(TestEnum enu, object obj, string str)
- {
- this.AnEnum = enu;
- this.AnObject = obj;
- this.AString = str;
- }
- }
+ public TestTypeToTrackWithConstructor(TestEnum enu, object obj, string str)
+ {
+ this.AnEnum = enu;
+ this.AnObject = obj;
+ this.AString = str;
+ }
+}
- public enum TestEnum
- {
- Value0,
- Value1,
- Value2,
- }
+public enum TestEnum
+{
+ Value0,
+ Value1,
+ Value2,
+}
- public class OtherClass
- {
- public void OtherMethod(TestTypeToTrack t)
- {
- }
+public class OtherClass
+{
+ public void OtherMethod(TestTypeToTrack t)
+ {
+ }
- public void OtherMethod(string s, TestTypeToTrack t)
- {
- }
+ public void OtherMethod(string s, TestTypeToTrack t)
+ {
+ }
- public static void StaticMethod(TestTypeToTrack staticMethodParameter)
- {
- }
- }
- """;
+ public static void StaticMethod(TestTypeToTrack staticMethodParameter)
+ {
+ }
+}";
///
/// Parameters for PropertySetAnalysis to flag hazardous usage when the TestTypeToTrack.AString property is not null
@@ -288,17 +287,16 @@ public static void StaticMethod(TestTypeToTrack staticMethodParameter)
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNull_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull,
(8, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -306,19 +304,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNull_StringEmpty_Flagged()
{
- VerifyCSharp("""
- using System;
+ VerifyCSharp(@"
+using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = String.Empty;
- t.Method();
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = String.Empty;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull,
(10, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -326,35 +323,33 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNull_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = null;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = null;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull);
}
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNull_OtherMethod_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- OtherClass o = new OtherClass();
- o.OtherMethod("this string parameter is ignored", t);
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ OtherClass o = new OtherClass();
+ o.OtherMethod(""this string parameter is ignored"", t);
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull,
(9, 9, "void OtherClass.OtherMethod(string s, TestTypeToTrack t)", HazardousUsageEvaluationResult.Flagged));
}
@@ -362,17 +357,16 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNull_StaticMethod_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- OtherClass.StaticMethod(t);
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ OtherClass.StaticMethod(t);
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull,
(8, 9, "void OtherClass.StaticMethod(TestTypeToTrack staticMethodParameter)", HazardousUsageEvaluationResult.Flagged));
}
@@ -380,19 +374,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNull_OtherClassBothMethods_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- OtherClass o = new OtherClass();
- o.OtherMethod("this string parameter is ignored", t);
- OtherClass.StaticMethod(t);
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ OtherClass o = new OtherClass();
+ o.OtherMethod(""this string parameter is ignored"", t);
+ OtherClass.StaticMethod(t);
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNull,
(9, 9, "void OtherClass.OtherMethod(string s, TestTypeToTrack t)", HazardousUsageEvaluationResult.Flagged),
(10, 9, "void OtherClass.StaticMethod(TestTypeToTrack staticMethodParameter)", HazardousUsageEvaluationResult.Flagged));
@@ -456,16 +449,15 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfStringIsNull_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, "A non-null string");
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, ""A non-null string"");
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfStringIsNonNull,
(7, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -473,18 +465,17 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfStringIsNull_StringEmpty_Flagged()
{
- VerifyCSharp("""
- using System;
+ VerifyCSharp(@"
+using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, String.Empty);
- t.Method();
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, String.Empty);
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfStringIsNonNull,
(9, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -492,33 +483,31 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfStringIsNull_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, null);
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, null);
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfStringIsNonNull);
}
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfStringIsNull_PropertyAssigned_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, null);
- t.AString = "";
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, null);
+ t.AString = """";
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfStringIsNonNull,
(8, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -559,17 +548,16 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfEnumIsValue0_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AnEnum = TestEnum.Value0;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AnEnum = TestEnum.Value0;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfEnumIsValue0,
(8, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -577,17 +565,16 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfEnumIsValue0_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AnEnum = TestEnum.Value2;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AnEnum = TestEnum.Value2;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfEnumIsValue0);
}
@@ -634,32 +621,30 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfEnumIsValue0_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(TestEnum.Value2, null, null);
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(TestEnum.Value2, null, null);
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfEnumIsValue0);
}
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfEnumIsValue0_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(TestEnum.Value0, null, null);
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(TestEnum.Value0, null, null);
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfEnumIsValue0,
(7, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -718,18 +703,17 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringStartsWithTAndValue2_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "The beginning of knowledge is the discovery of something we do not understand.";
- t.AnEnum = TestEnum.Value2;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""The beginning of knowledge is the discovery of something we do not understand."";
+ t.AnEnum = TestEnum.Value2;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringStartsWithTAndValue2,
(9, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -737,30 +721,29 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringStartsWithTAndValue2_BothMaybe_MaybeFlagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- Random r = new Random();
- t.AString = "T";
- t.AnEnum = TestEnum.Value2;
- if (r.Next(6) == 4)
- {
- t.AString = "A different string.";
- }
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ Random r = new Random();
+ t.AString = ""T"";
+ t.AnEnum = TestEnum.Value2;
+ if (r.Next(6) == 4)
+ {
+ t.AString = ""A different string."";
+ }
- if (r.Next(6) == 4)
- {
- t.AnEnum = TestEnum.Value1;
- }
+ if (r.Next(6) == 4)
+ {
+ t.AnEnum = TestEnum.Value1;
+ }
- t.Method();
- }/**/
- }
- """,
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringStartsWithTAndValue2,
(21, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.MaybeFlagged));
}
@@ -768,25 +751,24 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringStartsWithTAndValue2_FirstMaybe_MaybeFlagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- Random r = new Random();
- t.AString = "T";
- t.AnEnum = TestEnum.Value2;
- if (r.Next(6) == 4)
- {
- t.AString = "A different string.";
- }
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ Random r = new Random();
+ t.AString = ""T"";
+ t.AnEnum = TestEnum.Value2;
+ if (r.Next(6) == 4)
+ {
+ t.AString = ""A different string."";
+ }
- t.Method();
- }/**/
- }
- """,
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringStartsWithTAndValue2,
(16, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.MaybeFlagged));
}
@@ -794,25 +776,24 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringStartsWithTAndValue2_SecondMaybe_MaybeFlagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- Random r = new Random();
- t.AString = "T";
- t.AnEnum = TestEnum.Value2;
- if (r.Next(6) == 4)
- {
- t.AnEnum = TestEnum.Value1;
- }
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ Random r = new Random();
+ t.AString = ""T"";
+ t.AnEnum = TestEnum.Value2;
+ if (r.Next(6) == 4)
+ {
+ t.AnEnum = TestEnum.Value1;
+ }
- t.Method();
- }/**/
- }
- """,
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringStartsWithTAndValue2,
(16, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.MaybeFlagged));
}
@@ -820,19 +801,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringStartsWithTAndValue2_FirstFlagged_Unflagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- Random r = new Random();
- t.AString = "T";
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ Random r = new Random();
+ t.AString = ""T"";
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringStartsWithTAndValue2);
}
@@ -901,19 +881,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray_Constructor_Flagged()
{
- VerifyCSharp("""
- using System;
- using System.Collections;
+ VerifyCSharp(@"
+using System;
+using System.Collections;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), new BitArray(4), "string");
- t.Method();
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), new BitArray(4), ""string"");
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray,
(10, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -921,23 +900,22 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray_Constructor_TwoPaths_Flagged()
{
- VerifyCSharp("""
- using System;
- using System.Collections;
+ VerifyCSharp(@"
+using System;
+using System.Collections;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t;
- if (new Random().Next(6) == 4)
- t = new TestTypeToTrackWithConstructor(default(TestEnum), new BitArray(6), "string");
- else
- t = new TestTypeToTrackWithConstructor(default(TestEnum), "object string", "string");
- t.Method(); // PropertySetAnalysis is aggressive--at least one previous code path being Flagged means it's Flagged at this point.
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t;
+ if (new Random().Next(6) == 4)
+ t = new TestTypeToTrackWithConstructor(default(TestEnum), new BitArray(6), ""string"");
+ else
+ t = new TestTypeToTrackWithConstructor(default(TestEnum), ""object string"", ""string"");
+ t.Method(); // PropertySetAnalysis is aggressive--at least one previous code path being Flagged means it's Flagged at this point.
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray,
(14, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -945,19 +923,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray_Constructor_NotFlagged()
{
- VerifyCSharp("""
- using System;
- using System.Collections;
+ VerifyCSharp(@"
+using System;
+using System.Collections;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, "string");
- t.Method();
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, ""string"");
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfObjectIsBitArray);
}
@@ -1008,19 +985,18 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfAStringStartsWithA_Flagged()
{
- VerifyCSharp("""
- using System;
- using System.Collections;
+ VerifyCSharp(@"
+using System;
+using System.Collections;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, "A string");
- t.Method();
- }/**/
- }
- """,
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = new TestTypeToTrackWithConstructor(default(TestEnum), null, ""A string"");
+ t.Method();
+ }/**/
+}",
TestTypeToTrackWithConstructor_HazardousIfAStringStartsWithA,
(10, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -1028,24 +1004,23 @@ void TestMethod()
[Fact]
public void TestTypeToTrackWithConstructor_HazardousIfAStringStartsWithA_Interprocedural_Flagged()
{
- VerifyCSharp("""
- using System;
- using System.Collections;
+ VerifyCSharp(@"
+using System;
+using System.Collections;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrackWithConstructor t = GetTestType();
- t.Method();
- }/**/
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrackWithConstructor t = GetTestType();
+ t.Method();
+ }/**/
- TestTypeToTrackWithConstructor GetTestType()
- {
- return new TestTypeToTrackWithConstructor(default(TestEnum), null, "A string");
- }
- }
- """,
+ TestTypeToTrackWithConstructor GetTestType()
+ {
+ return new TestTypeToTrackWithConstructor(default(TestEnum), null, ""A string"");
+ }
+}",
TestTypeToTrackWithConstructor_HazardousIfAStringStartsWithA,
(10, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -1090,17 +1065,16 @@ TestTypeToTrackWithConstructor GetTestType()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNullOnReturn_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- TestTypeToTrack TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- return t;
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ TestTypeToTrack TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ return t;
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNullOnReturn,
(8, 16, null, HazardousUsageEvaluationResult.Flagged));
}
@@ -1108,18 +1082,17 @@ TestTypeToTrack TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNullOnReturn_StringEmpty_Flagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- TestTypeToTrack TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = String.Empty;
- return t;
- }/**/
- }
- """,
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ TestTypeToTrack TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = String.Empty;
+ return t;
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNullOnReturn,
(9, 16, null, HazardousUsageEvaluationResult.Flagged));
}
@@ -1127,34 +1100,32 @@ TestTypeToTrack TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNullOnReturns_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- TestTypeToTrack TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = null;
- return t;
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ TestTypeToTrack TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = null;
+ return t;
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNullOnReturn);
}
[Fact]
public void TestTypeToTrack_HazardousIfStringIsNonNullOnReturns_ReturnObject_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- object TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- return new object();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ object TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ return new object();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringIsNonNullOnReturn);
}
@@ -1214,17 +1185,16 @@ object TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringObjectIsNonNull_AStringNonNull_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringObjectIsNonNull,
(8, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -1232,17 +1202,16 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringObjectIsNonNull_AnObjectNonNull_Flagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AnObject = new System.Random();
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AnObject = new System.Random();
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringObjectIsNonNull,
(8, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -1250,18 +1219,17 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringObjectIsNonNull_StringEmpty_Flagged()
{
- VerifyCSharp("""
- using System;
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = String.Empty;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+using System;
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = String.Empty;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringObjectIsNonNull,
(9, 9, "void TestTypeToTrack.Method()", HazardousUsageEvaluationResult.Flagged));
}
@@ -1269,36 +1237,34 @@ void TestMethod()
[Fact]
public void TestTypeToTrack_HazardousIfStringObjectIsNonNull_StringNonNull_ObjectNull_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AString = "A non-null string";
- t.AnObject = null;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AString = ""A non-null string"";
+ t.AnObject = null;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringObjectIsNonNull);
}
[Fact]
public void TestTypeToTrack_HazardousIfStringObjectIsNonNull_AnObjectNonNull_StringNull_Unflagged()
{
- VerifyCSharp("""
- class TestClass
- {
- void TestMethod()
- /**/{
- TestTypeToTrack t = new TestTypeToTrack();
- t.AnObject = new System.Random();
- t.AString = null;
- t.Method();
- }/**/
- }
- """,
+ VerifyCSharp(@"
+class TestClass
+{
+ void TestMethod()
+ /**/{
+ TestTypeToTrack t = new TestTypeToTrack();
+ t.AnObject = new System.Random();
+ t.AString = null;
+ t.Method();
+ }/**/
+}",
TestTypeToTrack_HazardousIfStringObjectIsNonNull);
}
diff --git a/src/roslyn/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs b/src/roslyn/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs
index d8d39eb32d1..7761f6faaab 100644
--- a/src/roslyn/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs
+++ b/src/roslyn/src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -15,6 +16,8 @@
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Test.Utilities;
+using Roslyn.Utilities;
+using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests;
@@ -22,11 +25,11 @@ namespace Microsoft.CodeAnalysis.ExternalAccess.Razor.UnitTests;
public sealed class RazorAnalyzerAssemblyResolverTests : IDisposable
{
private TempRoot TempRoot { get; } = new TempRoot();
- private int InitialAssemblyCount { get; }
+ private ImmutableArray InitialAssemblies { get; }
public RazorAnalyzerAssemblyResolverTests()
{
- InitialAssemblyCount = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.Count();
+ InitialAssemblies = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.SelectAsArray(a => a.FullName);
}
public void Dispose()
@@ -34,8 +37,8 @@ public void Dispose()
TempRoot.Dispose();
// This test should not change the set of assemblies loaded in the current context.
- var count = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.Count();
- Assert.Equal(InitialAssemblyCount, count);
+ var count = AssemblyLoadContext.GetLoadContext(this.GetType().Assembly)!.Assemblies.SelectAsArray(a => a.FullName);
+ AssertEx.SetEqual(InitialAssemblies, count);
}
private void CreateRazorAssemblies(string directory, string versionNumber = "1.0.0.0")
@@ -93,7 +96,7 @@ private static void RunWithLoader(Action
- [Fact]
+ [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79352")]
public void FallbackToCompilerContext()
{
var dir1 = TempRoot.CreateDirectory().Path;
@@ -127,7 +130,7 @@ public void FallbackToCompilerContext()
});
}
- [Fact]
+ [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79352")]
public void FirstLoadWins()
{
var dir1 = TempRoot.CreateDirectory().Path;
@@ -151,7 +154,7 @@ public void FirstLoadWins()
});
}
- [Fact]
+ [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/79352")]
public void ChooseServiceHubFolder()
{
var dir = TempRoot.CreateDirectory().Path;
diff --git a/src/roslyn/src/Tools/Source/RunTests/HelixTestRunner.cs b/src/roslyn/src/Tools/Source/RunTests/HelixTestRunner.cs
index e1592f9a637..ddb9f8d9cdb 100644
--- a/src/roslyn/src/Tools/Source/RunTests/HelixTestRunner.cs
+++ b/src/roslyn/src/Tools/Source/RunTests/HelixTestRunner.cs
@@ -227,7 +227,7 @@ static void AppendHelixWorkItemProject(
{workItemPayloadDir}
{commandPrefix}{commandFileName}
{commandPrefix}{postCommandFileName}
- 00:30:00
+ 01:00:00
{helixWorkItem.EstimatedExecutionTime}
""");
@@ -421,9 +421,15 @@ private static string GetRspFileContent(
// The xml file must end in test-results.xml for the Azure Pipelines reporter to pick it up.
builder.AppendLine($@"/Logger:xunit;LogFilePath=work-item-test-results.xml");
+ // Also add a console logger so that the helix log reports results as we go.
+ builder.AppendLine($@"/Logger:console;verbosity=detailed");
+
// Specifies the results directory - this is where dumps from the blame options will get published.
builder.AppendLine($"/ResultsDirectory:.");
+ var blameOption = "CollectDump;CollectHangDump";
+ builder.AppendLine($"/Blame:{blameOption};TestTimeout=15minutes;DumpType=full");
+
// Build the filter string
if (testMethodNames.Any())
{
diff --git a/src/roslyn/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs b/src/roslyn/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs
index 1c4c8e61664..3814232331d 100644
--- a/src/roslyn/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs
+++ b/src/roslyn/src/VisualStudio/Core/Def/StackTraceExplorer/StackTraceExplorerViewModel.cs
@@ -50,6 +50,9 @@ public StackTraceExplorerViewModel(IThreadingContext threadingContext, Workspace
_threadingContext = threadingContext;
_workspace = workspace;
+ // Main thread dependency as Workspace_WorkspaceChanged modifies an ObservableCollection
+ _ = workspace.RegisterWorkspaceChangedHandler(Workspace_WorkspaceChanged, WorkspaceEventOptions.RequiresMainThreadOptions);
+
_classificationTypeMap = classificationTypeMap;
_formatMap = formatMap;
@@ -100,6 +103,15 @@ private void CallstackLines_CollectionChanged(object sender, System.Collections.
NotifyPropertyChanged(nameof(IsInstructionTextVisible));
}
+ private void Workspace_WorkspaceChanged(WorkspaceChangeEventArgs e)
+ {
+ if (e.Kind == WorkspaceChangeKind.SolutionChanged)
+ {
+ Selection = null;
+ Frames.Clear();
+ }
+ }
+
private FrameViewModel GetViewModel(ParsedFrame frame)
=> frame switch
{
diff --git a/src/roslyn/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs b/src/roslyn/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs
index f5d797ba1df..0525b9c7cc1 100644
--- a/src/roslyn/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs
+++ b/src/roslyn/src/VisualStudio/Core/Impl/SolutionExplorer/DiagnosticItem/CpsDiagnosticItemSource.cs
@@ -19,7 +19,6 @@ internal sealed partial class CpsDiagnosticItemSource : BaseDiagnosticAndGenerat
{
private readonly IVsHierarchyItem _item;
private readonly string _projectDirectoryPath;
- private readonly string? _analyzerFilePath;
private WorkspaceEventRegistration? _workspaceChangedDisposer;
@@ -38,8 +37,6 @@ public CpsDiagnosticItemSource(
_item = item;
_projectDirectoryPath = Path.GetDirectoryName(projectPath);
- _analyzerFilePath = CpsUtilities.ExtractAnalyzerFilePath(_projectDirectoryPath, _item.CanonicalName);
-
this.AnalyzerReference = TryGetAnalyzerReference(Workspace.CurrentSolution);
if (this.AnalyzerReference == null)
{
@@ -50,7 +47,9 @@ public CpsDiagnosticItemSource(
// then connect to it.
if (workspace.CurrentSolution.ContainsProject(projectId))
{
- _workspaceChangedDisposer = Workspace.RegisterWorkspaceChangedHandler(OnWorkspaceChangedLookForAnalyzer);
+ // Main thread dependency as OnWorkspaceChangedLookForAnalyzer accesses the IVsHierarchy
+ // and fires the PropertyChanged event
+ _workspaceChangedDisposer = Workspace.RegisterWorkspaceChangedHandler(OnWorkspaceChangedLookForAnalyzer, WorkspaceEventOptions.RequiresMainThreadOptions);
item.PropertyChanged += IVsHierarchyItem_PropertyChanged;
// Now that we've subscribed, check once more in case we missed the event
@@ -119,11 +118,14 @@ private void OnWorkspaceChangedLookForAnalyzer(WorkspaceChangeEventArgs e)
return null;
}
- if (string.IsNullOrEmpty(_analyzerFilePath))
+ var canonicalName = _item.CanonicalName;
+ var analyzerFilePath = CpsUtilities.ExtractAnalyzerFilePath(_projectDirectoryPath, canonicalName);
+
+ if (string.IsNullOrEmpty(analyzerFilePath))
{
return null;
}
- return project.AnalyzerReferences.FirstOrDefault(r => string.Equals(r.FullPath, _analyzerFilePath, StringComparison.OrdinalIgnoreCase));
+ return project.AnalyzerReferences.FirstOrDefault(r => string.Equals(r.FullPath, analyzerFilePath, StringComparison.OrdinalIgnoreCase));
}
}
diff --git a/src/roslyn/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs b/src/roslyn/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs
deleted file mode 100644
index be636585901..00000000000
--- a/src/roslyn/src/VisualStudio/ExternalAccess/Copilot/SemanticSearch/ISemanticSearchCopilotUIProviderImpl.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Windows.Controls;
-using Microsoft.VisualStudio.OLE.Interop;
-using Microsoft.VisualStudio.Text.Editor;
-
-namespace Microsoft.CodeAnalysis.ExternalAccess.Copilot.SemanticSearch;
-
-internal interface ITextBoxControlImpl
-{
- Control Control { get; }
- string Text { get; set; }
- IOleCommandTarget CommandTarget { get; }
- IWpfTextView View { get; }
-}
-
-internal interface ISemanticSearchCopilotUIProviderImpl
-{
- ITextBoxControlImpl GetTextBox();
-}
diff --git a/src/runtime/docs/workflow/requirements/macos-requirements.md b/src/runtime/docs/workflow/requirements/macos-requirements.md
index 67e7840a64d..cd1aed4b8f1 100644
--- a/src/runtime/docs/workflow/requirements/macos-requirements.md
+++ b/src/runtime/docs/workflow/requirements/macos-requirements.md
@@ -18,7 +18,6 @@ To build the runtime repo, you will also need to install the following dependenc
- `CMake` 3.20 or newer
- `icu4c`
-- `openssl@1.1` or `openssl@3`
- `pkg-config`
- `python3`
- `ninja` (This one is optional. It is an alternative tool to `make` for building native code)
diff --git a/src/runtime/eng/native/build-commons.sh b/src/runtime/eng/native/build-commons.sh
index 2bc1faf27e7..a3bdc2ac190 100755
--- a/src/runtime/eng/native/build-commons.sh
+++ b/src/runtime/eng/native/build-commons.sh
@@ -70,7 +70,7 @@ build_native()
# Let users provide additional compiler/linker flags via EXTRA_CFLAGS/EXTRA_CXXFLAGS/EXTRA_LDFLAGS.
# If users directly override CFLAG/CXXFLAGS/LDFLAGS, that may lead to some configure tests working incorrectly.
# See https://github.com/dotnet/runtime/issues/35727 for more information.
- #
+ #
# These flags MUST be exported before gen-buildsys.sh runs or cmake will ignore them
#
export CFLAGS="${CFLAGS} ${EXTRA_CFLAGS}"
@@ -547,6 +547,9 @@ elif [[ "$__TargetOS" == ios || "$__TargetOS" == iossimulator ]]; then
elif [[ "$__TargetOS" == tvos || "$__TargetOS" == tvossimulator ]]; then
# nothing to do here
true
+elif [[ "$__TargetOS" == osx || "$__TargetOS" == maccatalyst ]]; then
+ # nothing to do here
+ true
elif [[ "$__TargetOS" == android ]]; then
# nothing to do here
true
diff --git a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml
index 417241706c4..fa627d38ddd 100644
--- a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml
+++ b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-android.yml
@@ -76,7 +76,7 @@ jobs:
nameSuffix: AllSubsets_Mono
isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:EnableAdditionalTimezoneChecks=true
- timeoutInMinutes: 480
+ timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
@@ -107,7 +107,7 @@ jobs:
nameSuffix: AllSubsets_CoreCLR
isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg)
- timeoutInMinutes: 480
+ timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
diff --git a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml
index b7b3774f0b5..6b8698f3bdc 100644
--- a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml
+++ b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-androidemulator.yml
@@ -111,7 +111,7 @@ jobs:
nameSuffix: AllSubsets_Mono
isExtraPlatforms: ${{ parameters.isExtraPlatformsBuild }}
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg)
- timeoutInMinutes: 180
+ timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
diff --git a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml
index 7f10d317464..82726e28094 100644
--- a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml
+++ b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslike.yml
@@ -42,7 +42,7 @@ jobs:
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=false
${{ else }}:
buildArgs: -s mono+libs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true $(_runSmokeTestsOnlyArg) /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:IsManualOrRollingBuild=true /p:EnableAggressiveTrimming=true
- timeoutInMinutes: 480
+ timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
@@ -81,7 +81,7 @@ jobs:
testGroup: innerloop
nameSuffix: AllSubsets_Mono_RuntimeTests
buildArgs: -s mono+libs -c $(_BuildConfig)
- timeoutInMinutes: 480
+ timeoutInMinutes: 240
# extra steps, run tests
extraVariablesTemplates:
- template: /eng/pipelines/common/templates/runtimes/test-variables.yml
@@ -152,7 +152,7 @@ jobs:
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests
- timeoutInMinutes: 480
+ timeoutInMinutes: 240
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
# extra steps, run tests
extraVariablesTemplates:
diff --git a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml
index 9f483dbbe75..03cc2d926a0 100644
--- a/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml
+++ b/src/runtime/eng/pipelines/extra-platforms/runtime-extra-platforms-ioslikesimulator.yml
@@ -36,7 +36,7 @@ jobs:
testGroup: innerloop
nameSuffix: AllSubsets_Mono
buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true $(_runSmokeTestsOnlyArg) /p:RunAOTCompilation=true /p:MonoForceInterpreter=true
- timeoutInMinutes: 180
+ timeoutInMinutes: 240
# extra steps, run tests
postBuildSteps:
- template: /eng/pipelines/libraries/helix.yml
@@ -119,7 +119,7 @@ jobs:
jobParameters:
testGroup: innerloop
nameSuffix: AllSubsets_NativeAOT_RuntimeTests
- timeoutInMinutes: 240
+ timeoutInMinutes: 180
buildArgs: --cross -s clr.alljits+clr.tools+clr.nativeaotruntime+clr.nativeaotlibs+libs -c $(_BuildConfig)
# extra steps, run tests
extraVariablesTemplates:
diff --git a/src/runtime/eng/pipelines/runtime.yml b/src/runtime/eng/pipelines/runtime.yml
index 305bb899368..e213156d849 100644
--- a/src/runtime/eng/pipelines/runtime.yml
+++ b/src/runtime/eng/pipelines/runtime.yml
@@ -931,7 +931,7 @@ extends:
testGroup: innerloop
nameSuffix: AllSubsets_Mono
buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true /p:EnableAdditionalTimezoneChecks=true
- timeoutInMinutes: 480
+ timeoutInMinutes: 120
condition: >-
or(
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
@@ -961,7 +961,8 @@ extends:
buildConfig: Release
runtimeFlavor: coreclr
platforms:
- - android_x64
+ # Tracking issue: https://github.com/dotnet/dnceng/issues/5909
+ # - android_x64
- android_arm64
variables:
# map dependencies variables to local variables
@@ -973,7 +974,7 @@ extends:
testGroup: innerloop
nameSuffix: AllSubsets_CoreCLR
buildArgs: -s clr.runtime+clr.alljits+clr.corelib+clr.nativecorelib+clr.tools+clr.packages+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:RunSmokeTestsOnly=true
- timeoutInMinutes: 480
+ timeoutInMinutes: 120
condition: >-
or(
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
@@ -1017,7 +1018,7 @@ extends:
testGroup: innerloop
nameSuffix: AllSubsets_Mono
buildArgs: -s mono+libs+libs.tests+host+packs -c $(_BuildConfig) /p:ArchiveTests=true /p:DevTeamProvisioning=- /p:RunAOTCompilation=true /p:RunSmokeTestsOnly=true /p:BuildTestsOnHelix=true /p:EnableAdditionalTimezoneChecks=true /p:UsePortableRuntimePack=false /p:EnableAggressiveTrimming=true
- timeoutInMinutes: 480
+ timeoutInMinutes: 120
condition: >-
or(
eq(stageDependencies.EvaluatePaths.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
diff --git a/src/runtime/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/runtime/src/coreclr/debug/daccess/dacdbiimpl.cpp
index 80f3ca01758..a676f7f5fed 100644
--- a/src/runtime/src/coreclr/debug/daccess/dacdbiimpl.cpp
+++ b/src/runtime/src/coreclr/debug/daccess/dacdbiimpl.cpp
@@ -4963,9 +4963,21 @@ void DacDbiInterfaceImpl::Hijack(
// Setup context for hijack
//
T_CONTEXT ctx;
+#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS) && (defined(DTCONTEXT_IS_AMD64) || defined(DTCONTEXT_IS_ARM64))
+ // If the host or target is not Windows, then we can assume that the DT_CONTEXT
+ // is the same as the T_CONTEXT, except for the XSTATE registers.
+ static_assert(sizeof(DT_CONTEXT) == offsetof(T_CONTEXT, XStateFeaturesMask), "DT_CONTEXT does not include the XSTATE registers");
+#else
+ // Since Dac + DBI are tightly coupled, context sizes should be the same.
+ static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size");
+#endif
HRESULT hr = m_pTarget->GetThreadContext(
dwThreadId,
- CONTEXT_FULL,
+ CONTEXT_FULL | CONTEXT_FLOATING_POINT
+#ifdef CONTEXT_EXTENDED_REGISTERS
+ | CONTEXT_EXTENDED_REGISTERS
+#endif
+ ,
sizeof(DT_CONTEXT),
(BYTE*) &ctx);
IfFailThrow(hr);
diff --git a/src/runtime/src/coreclr/debug/daccess/stdafx.h b/src/runtime/src/coreclr/debug/daccess/stdafx.h
index bb7b7b2365d..bff6a4f6603 100644
--- a/src/runtime/src/coreclr/debug/daccess/stdafx.h
+++ b/src/runtime/src/coreclr/debug/daccess/stdafx.h
@@ -42,6 +42,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/runtime/src/coreclr/debug/di/process.cpp b/src/runtime/src/coreclr/debug/di/process.cpp
index 28de989969e..132e8ab031d 100644
--- a/src/runtime/src/coreclr/debug/di/process.cpp
+++ b/src/runtime/src/coreclr/debug/di/process.cpp
@@ -5061,6 +5061,23 @@ void CordbProcess::RawDispatchEvent(
case DB_IPCE_LOAD_MODULE:
{
+ LOG((LF_CORDB, LL_INFO100,
+ "RCET::HRCE: load module (includes assembly loading) on thread %#x Asm:0x%08x AD:0x%08x \n",
+ dwVolatileThreadId,
+ VmPtrToCookie(pEvent->LoadModuleData.vmDomainAssembly),
+ VmPtrToCookie(pEvent->vmAppDomain)));
+
+ _ASSERTE (pAppDomain != NULL);
+
+ // Determine if this Assembly is cached.
+ CordbAssembly * pAssembly = pAppDomain->LookupOrCreateAssembly(pEvent->LoadModuleData.vmDomainAssembly);
+ _ASSERTE(pAssembly != NULL); // throws on error
+
+ // If created, or have, an Assembly, notify callback.
+ {
+ PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
+ hr = pCallback1->LoadAssembly(pAppDomain, pAssembly);
+ }
_ASSERTE (pAppDomain != NULL);
CordbModule * pModule = pAppDomain->LookupOrCreateModule(pEvent->LoadModuleData.vmDomainAssembly);
@@ -5375,29 +5392,6 @@ void CordbProcess::RawDispatchEvent(
break;
- case DB_IPCE_LOAD_ASSEMBLY:
- {
- LOG((LF_CORDB, LL_INFO100,
- "RCET::HRCE: load assembly on thread %#x Asm:0x%08x AD:0x%08x \n",
- dwVolatileThreadId,
- VmPtrToCookie(pEvent->AssemblyData.vmDomainAssembly),
- VmPtrToCookie(pEvent->vmAppDomain)));
-
- _ASSERTE (pAppDomain != NULL);
-
- // Determine if this Assembly is cached.
- CordbAssembly * pAssembly = pAppDomain->LookupOrCreateAssembly(pEvent->AssemblyData.vmDomainAssembly);
- _ASSERTE(pAssembly != NULL); // throws on error
-
- // If created, or have, an Assembly, notify callback.
- {
- PUBLIC_CALLBACK_IN_THIS_SCOPE(this, pLockHolder, pEvent);
- hr = pCallback1->LoadAssembly(pAppDomain, pAssembly);
- }
- }
-
- break;
-
case DB_IPCE_UNLOAD_ASSEMBLY:
{
LOG((LF_CORDB, LL_INFO100, "RCET::DRCE: unload assembly on thread %#x Asm:0x%x AD:0x%x\n",
@@ -13281,9 +13275,9 @@ void CordbProcess::HandleDebugEventForInteropDebugging(const DEBUG_EVENT * pEven
LOG((LF_CORDB, LL_INFO100000, "W32ET::W32EL: hijack complete will restore context...\n"));
DT_CONTEXT tempContext = { 0 };
#if defined(DT_CONTEXT_EXTENDED_REGISTERS)
- tempContext.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_EXTENDED_REGISTERS;
+ tempContext.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS;
#else
- tempContext.ContextFlags = DT_CONTEXT_FULL;
+ tempContext.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT;
#endif
HRESULT hr = pUnmanagedThread->GetThreadContext(&tempContext);
_ASSERTE(SUCCEEDED(hr));
diff --git a/src/runtime/src/coreclr/debug/di/rsthread.cpp b/src/runtime/src/coreclr/debug/di/rsthread.cpp
index 8b9ec41240e..07e591d15fb 100644
--- a/src/runtime/src/coreclr/debug/di/rsthread.cpp
+++ b/src/runtime/src/coreclr/debug/di/rsthread.cpp
@@ -3706,9 +3706,9 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync()
// to avoid getting incomplete information and corrupt the thread context
DT_CONTEXT context;
#if defined(DT_CONTEXT_EXTENDED_REGISTERS)
- context.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_EXTENDED_REGISTERS;
+ context.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS;
#else
- context.ContextFlags = DT_CONTEXT_FULL;
+ context.ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT;
#endif
BOOL succ = DbiGetThreadContext(m_handle, &context);
_ASSERTE(succ);
@@ -3719,9 +3719,9 @@ HRESULT CordbUnmanagedThread::SetupFirstChanceHijackForSync()
LOG((LF_CORDB, LL_ERROR, "CUT::SFCHFS: DbiGetThreadContext error=0x%x\n", error));
}
#if defined(DT_CONTEXT_EXTENDED_REGISTERS)
- GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_EXTENDED_REGISTERS;
+ GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_EXTENDED_REGISTERS;
#else
- GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL;
+ GetHijackCtx()->ContextFlags = DT_CONTEXT_FULL | DT_CONTEXT_FLOATING_POINT;
#endif
CORDbgCopyThreadContext(GetHijackCtx(), &context);
LOG((LF_CORDB, LL_INFO10000, "CUT::SFCHFS: thread=0x%x Hijacking for sync. Original context is:\n", this));
diff --git a/src/runtime/src/coreclr/debug/ee/controller.cpp b/src/runtime/src/coreclr/debug/ee/controller.cpp
index a7bed1a1001..f7dfde2ae67 100644
--- a/src/runtime/src/coreclr/debug/ee/controller.cpp
+++ b/src/runtime/src/coreclr/debug/ee/controller.cpp
@@ -67,9 +67,79 @@ bool DebuggerControllerPatch::IsSafeForStackTrace()
}
+#ifndef DACCESS_COMPILE
#ifndef FEATURE_EMULATE_SINGLESTEP
-// returns a pointer to the shared buffer. each call will AddRef() the object
-// before returning it so callers only need to Release() when they're finished with it.
+
+//
+// We have to have a whole separate function for this because you
+// can't use __try in a function that requires object unwinding...
+//
+
+LONG FilterAccessViolation2(LPEXCEPTION_POINTERS ep, PVOID pv)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return (ep->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+}
+
+// This helper is required because the AVInRuntimeImplOkayHolder can not
+// be directly placed inside the scope of a PAL_TRY
+void _CopyInstructionBlockHelper(BYTE* to, const BYTE* from)
+{
+ AVInRuntimeImplOkayHolder AVOkay;
+
+ // This function only copies the portion of the instruction that follows the
+ // breakpoint opcode, not the breakpoint itself
+ to += CORDbg_BREAK_INSTRUCTION_SIZE;
+ from += CORDbg_BREAK_INSTRUCTION_SIZE;
+
+ // If an AV occurs because we walked off a valid page then we need
+ // to be certain that all bytes on the previous page were copied.
+ // We are certain that we copied enough bytes to contain the instruction
+ // because it must have fit within the valid page.
+ for (int i = 0; i < MAX_INSTRUCTION_LENGTH - CORDbg_BREAK_INSTRUCTION_SIZE; i++)
+ {
+ *to++ = *from++;
+ }
+
+}
+
+// WARNING: this function skips copying the first CORDbg_BREAK_INSTRUCTION_SIZE bytes by design
+// See the comment at the callsite in DebuggerPatchSkip::DebuggerPatchSkip for more details on
+// this
+void DebuggerControllerPatch::CopyInstructionBlock(BYTE *to, const BYTE* from)
+{
+ // We wrap the memcpy in an exception handler to handle the
+ // extremely rare case where we're copying an instruction off the
+ // end of a method that is also at the end of a page, and the next
+ // page is unmapped.
+ struct Param
+ {
+ BYTE *to;
+ const BYTE* from;
+ } param;
+ param.to = to;
+ param.from = from;
+ PAL_TRY(Param *, pParam, ¶m)
+ {
+ _CopyInstructionBlockHelper(pParam->to, pParam->from);
+ }
+ PAL_EXCEPT_FILTER(FilterAccessViolation2)
+ {
+ // The whole point is that if we copy up the AV, then
+ // that's enough to execute, otherwise we would not have been
+ // able to execute the code anyway. So we just ignore the
+ // exception.
+ LOG((LF_CORDB, LL_INFO10000,
+ "DCP::CIP: AV copying instruction block ignored.\n"));
+ }
+ PAL_ENDTRY
+}
+
+
+// Creates a new shared patch bypass buffer
+// AddRef() before returning it so callers need to Release() when they're finished with it.
SharedPatchBypassBuffer* DebuggerControllerPatch::GetOrCreateSharedPatchBypassBuffer()
{
CONTRACTL
@@ -79,27 +149,110 @@ SharedPatchBypassBuffer* DebuggerControllerPatch::GetOrCreateSharedPatchBypassBu
}
CONTRACTL_END;
- if (m_pSharedPatchBypassBuffer == NULL)
+ if (m_pSharedPatchBypassBuffer != NULL)
{
- void *pSharedPatchBypassBufferRX = g_pDebugger->GetInteropSafeExecutableHeap()->Alloc(sizeof(SharedPatchBypassBuffer));
+ m_pSharedPatchBypassBuffer->AddRef();
+ return m_pSharedPatchBypassBuffer;
+ }
+
+ // NOTE: in order to correctly single-step RIP-relative writes on multiple threads we need to set up
+ // a shared buffer with the instruction and a buffer for the RIP-relative value so that all threads
+ // are working on the same copy. as the single-steps complete the modified data in the buffer is
+ // copied back to the real address to ensure proper execution of the program.
+
+ SharedPatchBypassBuffer *pSharedPatchBypassBufferRX = (SharedPatchBypassBuffer*)g_pDebugger->GetInteropSafeExecutableHeap()->Alloc(sizeof(SharedPatchBypassBuffer));
#if defined(HOST_OSX) && defined(HOST_ARM64)
- ExecutableWriterHolder sharedPatchBypassBufferWriterHolder((SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX, sizeof(SharedPatchBypassBuffer));
- void *pSharedPatchBypassBufferRW = sharedPatchBypassBufferWriterHolder.GetRW();
+ ExecutableWriterHolder sharedPatchBypassBufferWriterHolder((SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX, sizeof(SharedPatchBypassBuffer));
+ SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = sharedPatchBypassBufferWriterHolder.GetRW();
#else // HOST_OSX && HOST_ARM64
- void *pSharedPatchBypassBufferRW = pSharedPatchBypassBufferRX;
+ SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = pSharedPatchBypassBufferRX;
#endif // HOST_OSX && HOST_ARM64
- new (pSharedPatchBypassBufferRW) SharedPatchBypassBuffer();
- m_pSharedPatchBypassBuffer = (SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX;
-
- _ASSERTE(m_pSharedPatchBypassBuffer);
- TRACE_ALLOC(m_pSharedPatchBypassBuffer);
- }
+ new (pSharedPatchBypassBufferRW) SharedPatchBypassBuffer();
+ m_pSharedPatchBypassBuffer = (SharedPatchBypassBuffer*)pSharedPatchBypassBufferRX;
+ _ASSERTE(m_pSharedPatchBypassBuffer);
+ TRACE_ALLOC(m_pSharedPatchBypassBuffer);
m_pSharedPatchBypassBuffer->AddRef();
+ BYTE* patchBypassRW = pSharedPatchBypassBufferRW->PatchBypass;
+ BYTE* patchBypassRX = m_pSharedPatchBypassBuffer->PatchBypass;
+
+ LOG((LF_CORDB, LL_INFO10000, "DCP::CSPBB: Patch skip for opcode 0x%.4x at address %p buffer allocated at 0x%.8x\n", this->opcode, this->address, m_pSharedPatchBypassBuffer));
+
+ // CopyInstructionBlock copies all the code bytes except the breakpoint byte(s).
+ _ASSERTE( this->IsBound() );
+ CopyInstructionBlock(patchBypassRW, (const BYTE *)this->address);
+
+ // Technically, we could create a patch skipper for an inactive patch, but we rely on the opcode being
+ // set here.
+ _ASSERTE( this->IsActivated() );
+ CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypassRW, this->opcode);
+
+ LOG((LF_CORDB, LL_EVERYTHING, "DCP::CSPBB: SetInstruction was called\n"));
+
+ //
+ // Look at instruction to get some attributes
+ //
+ InstructionAttribute instrAttrib = { 0 };
+ NativeWalker::DecodeInstructionForPatchSkip(patchBypassRX, &instrAttrib);
+
+#if defined(TARGET_AMD64)
+ // The code below handles RIP-relative addressing on AMD64. The original implementation made the assumption that
+ // we are only using RIP-relative addressing to access read-only data (see VSW 246145 for more information). This
+ // has since been expanded to handle RIP-relative writes as well.
+ if (instrAttrib.m_dwOffsetToDisp != 0)
+ {
+ _ASSERTE(pSharedPatchBypassBufferRW != NULL);
+ _ASSERTE(instrAttrib.m_cbInstr != 0);
+
+ //
+ // Populate the RIP-relative buffer with the current value if needed
+ //
+
+ BYTE* bufferBypassRW = pSharedPatchBypassBufferRW->BypassBuffer;
+
+ // Overwrite the *signed* displacement.
+ int dwOldDisp = *(int*)(&patchBypassRX[instrAttrib.m_dwOffsetToDisp]);
+ int dwNewDisp = offsetof(SharedPatchBypassBuffer, BypassBuffer) -
+ (offsetof(SharedPatchBypassBuffer, PatchBypass) + instrAttrib.m_cbInstr);
+ *(int*)(&patchBypassRW[instrAttrib.m_dwOffsetToDisp]) = dwNewDisp;
+
+ // This could be an LEA, which we'll just have to change into a MOV and copy the original address.
+ if (((patchBypassRX[0] == 0x4C) || (patchBypassRX[0] == 0x48)) && (patchBypassRX[1] == 0x8d))
+ {
+ patchBypassRW[1] = 0x8b; // MOV reg, mem
+ _ASSERTE((int)sizeof(void*) <= SharedPatchBypassBuffer::cbBufferBypass);
+ *(void**)bufferBypassRW = (void*)(this->address + instrAttrib.m_cbInstr + dwOldDisp);
+ }
+ else
+ {
+ _ASSERTE(instrAttrib.m_cOperandSize <= SharedPatchBypassBuffer::cbBufferBypass);
+ // Copy the data into our buffer.
+ memcpy(bufferBypassRW, this->address + instrAttrib.m_cbInstr + dwOldDisp, instrAttrib.m_cOperandSize);
+
+ if (instrAttrib.m_fIsWrite)
+ {
+ // save the actual destination address and size so when we TriggerSingleStep() we can update the value
+ pSharedPatchBypassBufferRW->RipTargetFixup = (UINT_PTR)(this->address + instrAttrib.m_cbInstr + dwOldDisp);
+ pSharedPatchBypassBufferRW->RipTargetFixupSize = instrAttrib.m_cOperandSize;
+ }
+ }
+ }
+
+ #endif // TARGET_AMD64
+
+ m_pSharedPatchBypassBuffer->SetInstructionAttrib(instrAttrib);
+
+ // Since we just created a new buffer of code, but the CPU caches code and may
+ // not be aware of our changes. This should force the CPU to dump any cached
+ // instructions it has in this region and load the new ones from memory
+ FlushInstructionCache(GetCurrentProcess(), patchBypassRW + CORDbg_BREAK_INSTRUCTION_SIZE,
+ MAX_INSTRUCTION_LENGTH - CORDbg_BREAK_INSTRUCTION_SIZE);
+
return m_pSharedPatchBypassBuffer;
}
#endif // !FEATURE_EMULATE_SINGLESTEP
+#endif // !DACCESS_COMPILE
// @todo - remove all this splicing trash
// This Sort/Splice stuff just reorders the patches within a particular chain such
@@ -4509,53 +4662,9 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
// the single-step emulation itself.
#ifndef FEATURE_EMULATE_SINGLESTEP
- // NOTE: in order to correctly single-step RIP-relative writes on multiple threads we need to set up
- // a shared buffer with the instruction and a buffer for the RIP-relative value so that all threads
- // are working on the same copy. as the single-steps complete the modified data in the buffer is
- // copied back to the real address to ensure proper execution of the program.
-
- //
- // Create the shared instruction block. this will also create the shared RIP-relative buffer
- //
-
+ _ASSERTE(DebuggerController::HasLock());
m_pSharedPatchBypassBuffer = patch->GetOrCreateSharedPatchBypassBuffer();
-#if defined(HOST_OSX) && defined(HOST_ARM64)
- ExecutableWriterHolder sharedPatchBypassBufferWriterHolder((SharedPatchBypassBuffer*)m_pSharedPatchBypassBuffer, sizeof(SharedPatchBypassBuffer));
- SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = sharedPatchBypassBufferWriterHolder.GetRW();
-#else // HOST_OSX && HOST_ARM64
- SharedPatchBypassBuffer *pSharedPatchBypassBufferRW = m_pSharedPatchBypassBuffer;
-#endif // HOST_OSX && HOST_ARM64
-
- BYTE* patchBypassRX = m_pSharedPatchBypassBuffer->PatchBypass;
- BYTE* patchBypassRW = pSharedPatchBypassBufferRW->PatchBypass;
- LOG((LF_CORDB, LL_INFO10000, "DPS::DPS: Patch skip for opcode 0x%.4x at address %p buffer allocated at 0x%.8x\n", patch->opcode, patch->address, m_pSharedPatchBypassBuffer));
-
- // Copy the instruction block over to the patch skip
- // WARNING: there used to be an issue here because CopyInstructionBlock copied the breakpoint from the
- // jitted code stream into the patch buffer. Further below CORDbgSetInstruction would correct the
- // first instruction. This buffer is shared by all threads so if another thread executed the buffer
- // between this thread's execution of CopyInstructionBlock and CORDbgSetInstruction the wrong
- // code would be executed. The bug has been fixed by changing CopyInstructionBlock to only copy
- // the code bytes after the breakpoint.
- // You might be tempted to stop copying the code at all, however that wouldn't work well with rejit.
- // If we skip a breakpoint that is sitting at the beginning of a method, then the profiler rejits that
- // method causing a jump-stamp to be placed, then we skip the breakpoint again, we need to make sure
- // the 2nd skip executes the new jump-stamp code and not the original method prologue code. Copying
- // the code every time ensures that we have the most up-to-date version of the code in the buffer.
- _ASSERTE( patch->IsBound() );
- CopyInstructionBlock(patchBypassRW, (const BYTE *)patch->address);
-
- // Technically, we could create a patch skipper for an inactive patch, but we rely on the opcode being
- // set here.
- _ASSERTE( patch->IsActivated() );
- CORDbgSetInstruction((CORDB_ADDRESS_TYPE *)patchBypassRW, patch->opcode);
-
- LOG((LF_CORDB, LL_EVERYTHING, "SetInstruction was called\n"));
- //
- // Look at instruction to get some attributes
- //
-
- NativeWalker::DecodeInstructionForPatchSkip(patchBypassRX, &(m_instrAttrib));
+ m_instrAttrib = m_pSharedPatchBypassBuffer->GetInstructionAttrib();
#ifdef OUT_OF_PROCESS_SETTHREADCONTEXT
if (g_pDebugInterface->IsOutOfProcessSetContextEnabled() && m_instrAttrib.m_fIsCall)
@@ -4564,51 +4673,6 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
}
#endif
-#if defined(TARGET_AMD64)
-
- // The code below handles RIP-relative addressing on AMD64. The original implementation made the assumption that
- // we are only using RIP-relative addressing to access read-only data (see VSW 246145 for more information). This
- // has since been expanded to handle RIP-relative writes as well.
- if (m_instrAttrib.m_dwOffsetToDisp != 0 && !IsInPlaceSingleStep())
- {
- _ASSERTE(m_instrAttrib.m_cbInstr != 0);
-
- //
- // Populate the RIP-relative buffer with the current value if needed
- //
-
- BYTE* bufferBypassRW = pSharedPatchBypassBufferRW->BypassBuffer;
-
- // Overwrite the *signed* displacement.
- int dwOldDisp = *(int*)(&patchBypassRX[m_instrAttrib.m_dwOffsetToDisp]);
- int dwNewDisp = offsetof(SharedPatchBypassBuffer, BypassBuffer) -
- (offsetof(SharedPatchBypassBuffer, PatchBypass) + m_instrAttrib.m_cbInstr);
- *(int*)(&patchBypassRW[m_instrAttrib.m_dwOffsetToDisp]) = dwNewDisp;
-
- // This could be an LEA, which we'll just have to change into a MOV and copy the original address.
- if (((patchBypassRX[0] == 0x4C) || (patchBypassRX[0] == 0x48)) && (patchBypassRX[1] == 0x8d))
- {
- patchBypassRW[1] = 0x8b; // MOV reg, mem
- _ASSERTE((int)sizeof(void*) <= SharedPatchBypassBuffer::cbBufferBypass);
- *(void**)bufferBypassRW = (void*)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
- }
- else
- {
- _ASSERTE(m_instrAttrib.m_cOperandSize <= SharedPatchBypassBuffer::cbBufferBypass);
- // Copy the data into our buffer.
- memcpy(bufferBypassRW, patch->address + m_instrAttrib.m_cbInstr + dwOldDisp, m_instrAttrib.m_cOperandSize);
-
- if (m_instrAttrib.m_fIsWrite)
- {
- // save the actual destination address and size so when we TriggerSingleStep() we can update the value
- pSharedPatchBypassBufferRW->RipTargetFixup = (UINT_PTR)(patch->address + m_instrAttrib.m_cbInstr + dwOldDisp);
- pSharedPatchBypassBufferRW->RipTargetFixupSize = m_instrAttrib.m_cOperandSize;
- }
- }
- }
-
-#endif // TARGET_AMD64
-
#endif // !FEATURE_EMULATE_SINGLESTEP
// Signals our thread that the debugger will be manipulating the context
@@ -4672,7 +4736,9 @@ DebuggerPatchSkip::DebuggerPatchSkip(Thread *thread,
#else // FEATURE_EMULATE_SINGLESTEP
#ifdef TARGET_ARM64
- patchBypassRX = NativeWalker::SetupOrSimulateInstructionForPatchSkip(context, m_pSharedPatchBypassBuffer, (const BYTE *)patch->address, patch->opcode);
+ BYTE* patchBypassRX = NativeWalker::SetupOrSimulateInstructionForPatchSkip(context, m_pSharedPatchBypassBuffer, (const BYTE *)patch->address, patch->opcode);
+#else
+ BYTE* patchBypassRX = m_pSharedPatchBypassBuffer->PatchBypass;
#endif //TARGET_ARM64
if (!IsInPlaceSingleStep())
@@ -4742,80 +4808,6 @@ void DebuggerPatchSkip::DebuggerDetachClean()
#endif // !FEATURE_EMULATE_SINGLESTEP
}
-
-//
-// We have to have a whole separate function for this because you
-// can't use __try in a function that requires object unwinding...
-//
-
-LONG FilterAccessViolation2(LPEXCEPTION_POINTERS ep, PVOID pv)
-{
- LIMITED_METHOD_CONTRACT;
-
- return (ep->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
- ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
-}
-
-// This helper is required because the AVInRuntimeImplOkayHolder can not
-// be directly placed inside the scope of a PAL_TRY
-void _CopyInstructionBlockHelper(BYTE* to, const BYTE* from)
-{
- AVInRuntimeImplOkayHolder AVOkay;
-
- // This function only copies the portion of the instruction that follows the
- // breakpoint opcode, not the breakpoint itself
- to += CORDbg_BREAK_INSTRUCTION_SIZE;
- from += CORDbg_BREAK_INSTRUCTION_SIZE;
-
- // If an AV occurs because we walked off a valid page then we need
- // to be certain that all bytes on the previous page were copied.
- // We are certain that we copied enough bytes to contain the instruction
- // because it must have fit within the valid page.
- for (int i = 0; i < MAX_INSTRUCTION_LENGTH - CORDbg_BREAK_INSTRUCTION_SIZE; i++)
- {
- *to++ = *from++;
- }
-
-}
-
-// WARNING: this function skips copying the first CORDbg_BREAK_INSTRUCTION_SIZE bytes by design
-// See the comment at the callsite in DebuggerPatchSkip::DebuggerPatchSkip for more details on
-// this
-void DebuggerPatchSkip::CopyInstructionBlock(BYTE *to, const BYTE* from)
-{
- // We wrap the memcpy in an exception handler to handle the
- // extremely rare case where we're copying an instruction off the
- // end of a method that is also at the end of a page, and the next
- // page is unmapped.
- struct Param
- {
- BYTE *to;
- const BYTE* from;
- } param;
- param.to = to;
- param.from = from;
- PAL_TRY(Param *, pParam, ¶m)
- {
- _CopyInstructionBlockHelper(pParam->to, pParam->from);
- }
- PAL_EXCEPT_FILTER(FilterAccessViolation2)
- {
- // The whole point is that if we copy up the AV, then
- // that's enough to execute, otherwise we would not have been
- // able to execute the code anyway. So we just ignore the
- // exception.
- LOG((LF_CORDB, LL_INFO10000,
- "DPS::DPS: AV copying instruction block ignored.\n"));
- }
- PAL_ENDTRY
-
- // We just created a new buffer of code, but the CPU caches code and may
- // not be aware of our changes. This should force the CPU to dump any cached
- // instructions it has in this region and load the new ones from memory
- FlushInstructionCache(GetCurrentProcess(), to + CORDbg_BREAK_INSTRUCTION_SIZE,
- MAX_INSTRUCTION_LENGTH - CORDbg_BREAK_INSTRUCTION_SIZE);
-}
-
TP_RESULT DebuggerPatchSkip::TriggerPatch(DebuggerControllerPatch *patch,
Thread *thread,
TRIGGER_WHY tyWhy)
diff --git a/src/runtime/src/coreclr/debug/ee/controller.h b/src/runtime/src/coreclr/debug/ee/controller.h
index b02cd2802d9..32138edc36a 100644
--- a/src/runtime/src/coreclr/debug/ee/controller.h
+++ b/src/runtime/src/coreclr/debug/ee/controller.h
@@ -312,7 +312,11 @@ class SharedPatchBypassBuffer
UINT_PTR RipTargetFixup;
#endif
+ const InstructionAttribute& GetInstructionAttrib() { return m_instrAttrib; }
+ void SetInstructionAttrib(const InstructionAttribute& instrAttrib) { m_instrAttrib = instrAttrib; }
+
private:
+ InstructionAttribute m_instrAttrib; // info about the instruction being skipped over
const static DWORD SentinelValue = 0xffffffff;
LONG m_refCount;
};
@@ -550,10 +554,13 @@ struct DebuggerControllerPatch
// Is this patch at a position at which it's safe to take a stack?
bool IsSafeForStackTrace();
+#ifndef DACCESS_COMPILE
#ifndef FEATURE_EMULATE_SINGLESTEP
// gets a pointer to the shared buffer
SharedPatchBypassBuffer* GetOrCreateSharedPatchBypassBuffer();
+ void CopyInstructionBlock(BYTE *to, const BYTE* from);
+
// entry point for general initialization when the controller is being created
void Initialize()
{
@@ -567,6 +574,7 @@ struct DebuggerControllerPatch
m_pSharedPatchBypassBuffer->Release();
}
#endif // !FEATURE_EMULATE_SINGLESTEP
+#endif // !DACCESS_COMPILE
void LogInstance()
{
@@ -1515,8 +1523,6 @@ class DebuggerPatchSkip : public DebuggerController
virtual DEBUGGER_CONTROLLER_TYPE GetDCType(void)
{ return DEBUGGER_CONTROLLER_PATCH_SKIP; }
- void CopyInstructionBlock(BYTE *to, const BYTE* from);
-
void DecodeInstruction(CORDB_ADDRESS_TYPE *code);
void DebuggerDetachClean();
diff --git a/src/runtime/src/coreclr/debug/ee/debugger.cpp b/src/runtime/src/coreclr/debug/ee/debugger.cpp
index 9a935112a09..7d7c4e9b96b 100644
--- a/src/runtime/src/coreclr/debug/ee/debugger.cpp
+++ b/src/runtime/src/coreclr/debug/ee/debugger.cpp
@@ -9250,62 +9250,6 @@ void Debugger::SendCreateAppDomainEvent(AppDomain * pRuntimeAppDomain)
}
-
-//
-// LoadAssembly is called when a new Assembly gets loaded.
-//
-void Debugger::LoadAssembly(DomainAssembly * pDomainAssembly)
-{
- CONTRACTL
- {
- MAY_DO_HELPER_THREAD_DUTY_THROWS_CONTRACT;
- MAY_DO_HELPER_THREAD_DUTY_GC_TRIGGERS_CONTRACT;
- }
- CONTRACTL_END;
-
- if (CORDBUnrecoverableError(this))
- return;
-
- LOG((LF_CORDB, LL_INFO100, "D::LA: Load Assembly Asy:0x%p AD:0x%p which:%s\n",
- pDomainAssembly, AppDomain::GetCurrentDomain(), pDomainAssembly->GetAssembly()->GetDebugName() ));
-
- if (!CORDebuggerAttached())
- {
- return;
- }
-
- Thread *pThread = g_pEEInterface->GetThread();
- SENDIPCEVENT_BEGIN(this, pThread)
-
-
- if (CORDebuggerAttached())
- {
- // Send a load assembly event to the Right Side.
- DebuggerIPCEvent* ipce = m_pRCThread->GetIPCEventSendBuffer();
- InitIPCEvent(ipce,
- DB_IPCE_LOAD_ASSEMBLY,
- pThread);
-
- ipce->AssemblyData.vmDomainAssembly.SetRawPtr(pDomainAssembly);
-
- m_pRCThread->SendIPCEvent();
- }
- else
- {
- LOG((LF_CORDB,LL_INFO1000, "D::LA: Skipping SendIPCEvent because RS detached."));
- }
-
- // Stop all Runtime threads
- if (CORDebuggerAttached())
- {
- TrapAllRuntimeThreads();
- }
-
- SENDIPCEVENT_END;
-}
-
-
-
//
// UnloadAssembly is called when a Runtime thread unloads an assembly.
//
diff --git a/src/runtime/src/coreclr/debug/ee/debugger.h b/src/runtime/src/coreclr/debug/ee/debugger.h
index 15915b00d72..79ba57770b2 100644
--- a/src/runtime/src/coreclr/debug/ee/debugger.h
+++ b/src/runtime/src/coreclr/debug/ee/debugger.h
@@ -2623,9 +2623,6 @@ class Debugger : public DebugInterface
void SendCreateAppDomainEvent(AppDomain * pAppDomain);
- // Notify the debugger that an assembly has been loaded
- void LoadAssembly(DomainAssembly * pDomainAssembly);
-
// Notify the debugger that an assembly has been unloaded
void UnloadAssembly(DomainAssembly * pDomainAssembly);
diff --git a/src/runtime/src/coreclr/debug/ee/walker.h b/src/runtime/src/coreclr/debug/ee/walker.h
index 63bd4cfa2fd..4dcae6d75ed 100644
--- a/src/runtime/src/coreclr/debug/ee/walker.h
+++ b/src/runtime/src/coreclr/debug/ee/walker.h
@@ -62,6 +62,8 @@ struct InstructionAttribute
}
};
+#ifndef DACCESS_COMPILE
+
/* ------------------------------------------------------------------------- *
* Classes
* ------------------------------------------------------------------------- */
@@ -280,4 +282,6 @@ class NativeWalker : public Walker
};
#endif
+#endif // DACCESS_COMPILE
+
#endif // WALKER_H_
diff --git a/src/runtime/src/coreclr/debug/inc/dbgtargetcontext.h b/src/runtime/src/coreclr/debug/inc/dbgtargetcontext.h
index ea374cf8b6d..606e4954b35 100644
--- a/src/runtime/src/coreclr/debug/inc/dbgtargetcontext.h
+++ b/src/runtime/src/coreclr/debug/inc/dbgtargetcontext.h
@@ -474,7 +474,7 @@ typedef DECLSPEC_ALIGN(16) struct {
#if !defined(CROSS_COMPILE) && !defined(TARGET_WINDOWS)
-static_assert(sizeof(DT_CONTEXT) == offsetof(T_CONTEXT, XStateFeaturesMask), "DT_CONTEXT must not include the SVE registers on AMD64");
+static_assert(sizeof(DT_CONTEXT) == offsetof(T_CONTEXT, XStateFeaturesMask), "DT_CONTEXT must not include the SVE registers on ARM64");
#else
static_assert(sizeof(DT_CONTEXT) == sizeof(T_CONTEXT), "DT_CONTEXT size must equal the T_CONTEXT size on ARM64");
#endif
diff --git a/src/runtime/src/coreclr/inc/corinfo.h b/src/runtime/src/coreclr/inc/corinfo.h
index 313d67a11ec..ff0420c7995 100644
--- a/src/runtime/src/coreclr/inc/corinfo.h
+++ b/src/runtime/src/coreclr/inc/corinfo.h
@@ -3139,12 +3139,6 @@ class ICorDynamicInfo : public ICorStaticInfo
CORINFO_CONST_LOOKUP * pResult
) = 0;
- // get the synchronization handle that is passed to monXstatic function
- virtual void* getMethodSync(
- CORINFO_METHOD_HANDLE ftn,
- void** ppIndirection = NULL
- ) = 0;
-
// get slow lazy string literal helper to use (CORINFO_HELP_STRCNS*).
// Returns CORINFO_HELP_UNDEF if lazy string literal helper cannot be used.
virtual CorInfoHelpFunc getLazyStringLiteralHelper(
diff --git a/src/runtime/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/runtime/src/coreclr/inc/icorjitinfoimpl_generated.h
index ee74e9c984f..472ada1cdd6 100644
--- a/src/runtime/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/runtime/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -550,10 +550,6 @@ void getFunctionFixedEntryPoint(
bool isUnsafeFunctionPointer,
CORINFO_CONST_LOOKUP* pResult) override;
-void* getMethodSync(
- CORINFO_METHOD_HANDLE ftn,
- void** ppIndirection) override;
-
CorInfoHelpFunc getLazyStringLiteralHelper(
CORINFO_MODULE_HANDLE handle) override;
diff --git a/src/runtime/src/coreclr/inc/jiteeversionguid.h b/src/runtime/src/coreclr/inc/jiteeversionguid.h
index 79b7eda125f..7043a7fa2f5 100644
--- a/src/runtime/src/coreclr/inc/jiteeversionguid.h
+++ b/src/runtime/src/coreclr/inc/jiteeversionguid.h
@@ -37,11 +37,11 @@
#include
-constexpr GUID JITEEVersionIdentifier = { /* 952f0344-7651-46af-8ef3-a34539af5c4a */
- 0x952f0344,
- 0x7651,
- 0x46af,
- {0x8e, 0xf3, 0xa3, 0x45, 0x39, 0xaf, 0x5c, 0x4a}
+constexpr GUID JITEEVersionIdentifier = { /* d24a67e0-9e57-4c9e-ad31-5785df2526f2 */
+ 0xd24a67e0,
+ 0x9e57,
+ 0x4c9e,
+ {0xad, 0x31, 0x57, 0x85, 0xdf, 0x25, 0x26, 0xf2}
};
#endif // JIT_EE_VERSIONING_GUID_H
diff --git a/src/runtime/src/coreclr/interpreter/compiler.cpp b/src/runtime/src/coreclr/interpreter/compiler.cpp
index cb585f78268..51dce8717e4 100644
--- a/src/runtime/src/coreclr/interpreter/compiler.cpp
+++ b/src/runtime/src/coreclr/interpreter/compiler.cpp
@@ -2157,32 +2157,34 @@ int32_t InterpCompiler::GetMethodDataItemIndex(CORINFO_METHOD_HANDLE mHandle)
return GetDataItemIndex((void*)mHandle);
}
-int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn)
+int32_t InterpCompiler::GetDataForHelperFtn(CorInfoHelpFunc ftn)
{
// Interpreter-TODO: Find an existing data item index for this helper if possible and reuse it
CORINFO_CONST_LOOKUP ftnLookup;
m_compHnd->getHelperFtn(ftn, &ftnLookup);
- void* addr = ftnLookup.addr;
- if (ftnLookup.accessType == IAT_VALUE)
- {
- // We can't use the 1 bit to mark indirect addresses because it is used for real code on arm32 (the thumb bit)
- // So instead, we mark direct addresses with a 1 and then on the other end we will clear the 1 and re-set it as needed for thumb
- addr = (void*)((size_t)addr | INTERP_DIRECT_HELPER_TAG);
- }
- else if (ftnLookup.accessType == IAT_PPVALUE)
- NO_WAY("IAT_PPVALUE helpers not implemented in interpreter");
#ifdef DEBUG
- if (!PointerInNameMap(addr))
+ if (!PointerInNameMap(ftnLookup.addr))
{
const char* name = CorInfoHelperToName(ftn);
if (name)
- AddPointerToNameMap(addr, name);
+ AddPointerToNameMap(ftnLookup.addr, name);
}
#endif
- assert(ftnLookup.accessType == IAT_VALUE || ftnLookup.accessType == IAT_PVALUE);
- return GetDataItemIndex(addr);
+ static_assert(sizeof(InterpHelperData) == sizeof(int32_t), "InterpHelperData must be the same size as an int32_t");
+
+ InterpHelperData result;
+ result.accessType = ftnLookup.accessType;
+ int32_t dataItemIndex = GetDataItemIndex(ftnLookup.addr);
+ result.addressDataItemIndex = dataItemIndex;
+
+ if (((int32_t)result.addressDataItemIndex != dataItemIndex) || ((InfoAccessType)result.accessType != ftnLookup.accessType))
+ NO_WAY("Over/underflow in GetDataForHelperFtn");
+
+ int32_t packed;
+ memcpy(&packed, &result, sizeof(result));
+ return packed;
}
static int32_t GetLdindForType(InterpType interpType)
@@ -2373,49 +2375,6 @@ bool InterpCompiler::EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HAN
}
}
-bool InterpCompiler::EmitCallIntrinsics(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig)
-{
- const char *className = NULL;
- const char *namespaceName = NULL;
- const char *methodName = m_compHnd->getMethodNameFromMetadata(method, &className, &namespaceName, NULL, 0);
-
- if (namespaceName && !strcmp(namespaceName, "System"))
- {
- if (className && !strcmp(className, "Environment"))
- {
- if (methodName && !strcmp(methodName, "FailFast"))
- {
- AddIns(INTOP_FAILFAST); // to be removed, not really an intrisic
- m_pStackPointer--;
- return true;
- }
- }
- else if (className && !strcmp(className, "Object"))
- {
- // This is needed at this moment because we don't have support for interop
- // with compiled code, but it might make sense in the future for this to remain
- // in order to avoid redundant interp to jit transition.
- if (methodName && !strcmp(methodName, ".ctor"))
- {
- AddIns(INTOP_NOP);
- m_pStackPointer--;
- return true;
- }
- }
- else if (className && !strcmp(className, "GC"))
- {
- if (methodName && !strcmp(methodName, "Collect"))
- {
- AddIns(INTOP_GC_COLLECT);
- // Not reducing the stack pointer because we expect the version with no arguments
- return true;
- }
- }
- }
-
- return false;
-}
-
void InterpCompiler::ResolveToken(uint32_t token, CorInfoTokenKind tokenKind, CORINFO_RESOLVED_TOKEN *pResolvedToken)
{
pResolvedToken->tokenScope = m_compScopeHnd;
@@ -2520,7 +2479,7 @@ void InterpCompiler::EmitPushHelperCall_2(const CorInfoHelpFunc ftn, const CORIN
if (handleData.argType == HelperArgType::GenericResolution)
{
AddIns(INTOP_CALL_HELPER_P_GS);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVars2(handleData.genericVar, arg2);
@@ -2529,7 +2488,7 @@ void InterpCompiler::EmitPushHelperCall_2(const CorInfoHelpFunc ftn, const CORIN
else
{
AddIns(INTOP_CALL_HELPER_P_PS);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVar(arg2);
@@ -2547,7 +2506,7 @@ void InterpCompiler::EmitPushUnboxAny(const CORINFO_GENERICHANDLE_RESULT& arg1,
if (handleData.argType == HelperArgType::GenericResolution)
{
AddIns(INTOP_UNBOX_ANY_GENERIC);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_UNBOX);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_UNBOX);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVars2(handleData.genericVar, arg2);
@@ -2556,7 +2515,7 @@ void InterpCompiler::EmitPushUnboxAny(const CORINFO_GENERICHANDLE_RESULT& arg1,
else
{
AddIns(INTOP_UNBOX_ANY);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_UNBOX);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_UNBOX);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVar(arg2);
@@ -2574,7 +2533,7 @@ void InterpCompiler::EmitPushUnboxAnyNullable(const CORINFO_GENERICHANDLE_RESULT
if (handleData.argType == HelperArgType::GenericResolution)
{
AddIns(INTOP_CALL_HELPER_V_AGS);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_UNBOX_NULLABLE);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_UNBOX_NULLABLE);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVars2(handleData.genericVar, arg2);
@@ -2583,7 +2542,7 @@ void InterpCompiler::EmitPushUnboxAnyNullable(const CORINFO_GENERICHANDLE_RESULT
else
{
AddIns(INTOP_CALL_HELPER_V_APS);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_UNBOX_NULLABLE);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_UNBOX_NULLABLE);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVar(arg2);
@@ -2601,7 +2560,7 @@ void InterpCompiler::EmitPushHelperCall_Addr2(const CorInfoHelpFunc ftn, const C
if (handleData.argType == HelperArgType::GenericResolution)
{
AddIns(INTOP_CALL_HELPER_P_GA);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVars2(handleData.genericVar, arg2);
@@ -2610,7 +2569,7 @@ void InterpCompiler::EmitPushHelperCall_Addr2(const CorInfoHelpFunc ftn, const C
else
{
AddIns(INTOP_CALL_HELPER_P_PA);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVar(arg2);
@@ -2628,7 +2587,7 @@ void InterpCompiler::EmitPushHelperCall(const CorInfoHelpFunc ftn, const CORINFO
if (handleData.argType == HelperArgType::GenericResolution)
{
AddIns(INTOP_CALL_HELPER_P_G);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVar(handleData.genericVar);
@@ -2637,7 +2596,7 @@ void InterpCompiler::EmitPushHelperCall(const CorInfoHelpFunc ftn, const CORINFO
else
{
AddIns(INTOP_CALL_HELPER_P_P);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(ftn);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(ftn);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetDVar(resultVar);
@@ -2789,12 +2748,6 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
}
}
- if (EmitCallIntrinsics(callInfo.hMethod, callInfo.sig))
- {
- m_ip += 5;
- return;
- }
-
if (callInfo.thisTransform != CORINFO_NO_THIS_TRANSFORM)
{
assert(pConstrainedToken != NULL);
@@ -3027,6 +2980,10 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
}
}
m_pLastNewIns->data[0] = GetDataItemIndex(callInfo.hMethod);
+
+ // Ensure that the dvar does not overlap with the svars; it is incorrect for it to overlap because
+ // the process of initializing the result may trample the args.
+ m_pVars[dVar].noCallArgs = true;
}
else if ((callInfo.classFlags & CORINFO_FLG_ARRAY) && newObj)
{
@@ -3326,7 +3283,7 @@ void InterpCompiler::EmitStaticFieldAddress(CORINFO_FIELD_INFO *pFieldInfo, CORI
}
// Call helper to obtain thread static base address
AddIns(INTOP_CALL_HELPER_P_P);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(pFieldInfo->helper);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(pFieldInfo->helper);
m_pLastNewIns->data[1] = GetDataItemIndex(helperArg);
PushInterpType(InterpTypeByRef, NULL);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
@@ -3521,7 +3478,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
if (!kind.needsRuntimeLookup)
{
AddIns(INTOP_CALL_HELPER_P_P);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_INITCLASS);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_INITCLASS);
m_pLastNewIns->data[1] = GetDataItemIndex(m_classHnd);
PushInterpType(InterpTypeI, NULL);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
@@ -3533,7 +3490,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
{
case CORINFO_LOOKUP_CLASSPARAM:
AddIns(INTOP_CALL_HELPER_P_S);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_INITCLASS);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_INITCLASS);
m_pLastNewIns->SetSVar(getParamArgIndex());
PushInterpType(InterpTypeI, NULL);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
@@ -3550,7 +3507,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
m_pStackPointer--;
AddIns(INTOP_CALL_HELPER_P_SP);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_INITINSTCLASS);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_INITINSTCLASS);
m_pLastNewIns->data[1] = GetDataItemIndex(m_methodHnd);
m_pLastNewIns->SetSVar(thisObjMethodTablePtrVar);
PushInterpType(InterpTypeI, NULL);
@@ -3561,7 +3518,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
case CORINFO_LOOKUP_METHODPARAM:
{
AddIns(INTOP_CALL_HELPER_P_PS);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(CORINFO_HELP_INITINSTCLASS);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(CORINFO_HELP_INITINSTCLASS);
m_pLastNewIns->data[1] = GetDataItemIndex(0);
m_pLastNewIns->SetSVar(getParamArgIndex());
PushInterpType(InterpTypeI, NULL);
@@ -5628,7 +5585,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
AddIns(INTOP_NEWARR_GENERIC);
- m_pLastNewIns->data[0] = GetDataItemIndexForHelperFtn(helpFunc);
+ m_pLastNewIns->data[0] = GetDataForHelperFtn(helpFunc);
m_pLastNewIns->data[1] = handleData.dataItemIndex;
m_pLastNewIns->SetSVars2(handleData.genericVar, newArrLenVar);
@@ -5638,7 +5595,7 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo)
{
AddIns(INTOP_NEWARR);
m_pLastNewIns->data[0] = GetDataItemIndex(arrayClsHnd);
- m_pLastNewIns->data[1] = GetDataItemIndexForHelperFtn(helpFunc);
+ m_pLastNewIns->data[1] = GetDataForHelperFtn(helpFunc);
m_pLastNewIns->SetSVar(newArrLenVar);
m_pLastNewIns->SetDVar(m_pStackPointer[-1].var);
@@ -6308,21 +6265,28 @@ void InterpCompiler::PrintPointer(void* pointer)
#endif
}
-void InterpCompiler::PrintHelperFtn(void* helperDirectOrIndirect)
+void InterpCompiler::PrintHelperFtn(int32_t _data)
{
- void* helperAddr = helperDirectOrIndirect;
-
- if (((size_t)helperDirectOrIndirect) & INTERP_DIRECT_HELPER_TAG)
- {
- helperAddr = (void*)(((size_t)helperDirectOrIndirect) & ~INTERP_DIRECT_HELPER_TAG);
- printf(" (direct)");
- }
- else
- {
- printf(" (indirect)");
- }
+ InterpHelperData data;
+ memcpy(&data, &_data, sizeof(int32_t));
+ void *helperAddr = GetDataItemAtIndex(data.addressDataItemIndex);
PrintPointer(helperAddr);
+
+ switch (data.accessType) {
+ case IAT_PVALUE:
+ printf("(indirect) ");
+ break;
+ case IAT_PPVALUE:
+ printf("(double-indirect) ");
+ break;
+ case IAT_VALUE:
+ printf("(direct) ");
+ break;
+ default:
+ printf("(corrupted) ");
+ break;
+ }
}
void InterpCompiler::PrintInsData(InterpInst *ins, int32_t insOffset, const int32_t *pData, int32_t opcode)
@@ -6369,7 +6333,7 @@ void InterpCompiler::PrintInsData(InterpInst *ins, int32_t insOffset, const int3
}
case InterpOpGenericHelperFtn:
{
- PrintHelperFtn((void*)GetDataItemAtIndex(pData[0]));
+ PrintHelperFtn(pData[0]);
InterpGenericLookup *pGenericLookup = (InterpGenericLookup*)GetAddrOfDataItemAtIndex(pData[1]);
PrintInterpGenericLookup(pGenericLookup);
break;
@@ -6413,21 +6377,23 @@ void InterpCompiler::PrintInsData(InterpInst *ins, int32_t insOffset, const int3
}
case InterpOpHelperFtnNoArgs:
{
- PrintHelperFtn((void*)GetDataItemAtIndex(pData[0]));
+ PrintHelperFtn(pData[0]);
break;
}
case InterpOpHelperFtn:
{
- PrintHelperFtn((void*)GetDataItemAtIndex(pData[0]));
- printf(", ");
- PrintPointer((void*)GetDataItemAtIndex(pData[1]));
+ PrintHelperFtn(pData[0]);
+ if (GetDataLen(opcode) > 1) {
+ printf(", ");
+ PrintPointer((void*)GetDataItemAtIndex(pData[1]));
+ }
break;
}
case InterpOpPointerHelperFtn:
{
PrintPointer((void*)GetDataItemAtIndex(pData[0]));
printf(", ");
- PrintHelperFtn((void*)GetDataItemAtIndex(pData[1]));
+ PrintHelperFtn(pData[1]);
break;
}
case InterpOpPointerInt:
diff --git a/src/runtime/src/coreclr/interpreter/compiler.h b/src/runtime/src/coreclr/interpreter/compiler.h
index 1ea75c8db43..15d0050d074 100644
--- a/src/runtime/src/coreclr/interpreter/compiler.h
+++ b/src/runtime/src/coreclr/interpreter/compiler.h
@@ -527,7 +527,7 @@ class InterpCompiler
void* GetDataItemAtIndex(int32_t index);
void* GetAddrOfDataItemAtIndex(int32_t index);
int32_t GetMethodDataItemIndex(CORINFO_METHOD_HANDLE mHandle);
- int32_t GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn);
+ int32_t GetDataForHelperFtn(CorInfoHelpFunc ftn);
void GenerateCode(CORINFO_METHOD_INFO* methodInfo);
InterpBasicBlock* GenerateCodeForFinallyCallIslands(InterpBasicBlock *pNewBB, InterpBasicBlock *pPrevBB);
@@ -697,7 +697,6 @@ class InterpCompiler
void EmitCompareOp(int32_t opBase);
void EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool readonly, bool tailcall, bool newObj, bool isCalli);
bool EmitNamedIntrinsicCall(NamedIntrinsic ni, CORINFO_CLASS_HANDLE clsHnd, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig);
- bool EmitCallIntrinsics(CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO sig);
void EmitLdind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset);
void EmitStind(InterpType type, CORINFO_CLASS_HANDLE clsHnd, int32_t offset, bool reverseSVarOrder);
void EmitLdelem(int32_t opcode, InterpType type);
@@ -745,7 +744,7 @@ class InterpCompiler
void PrintBBCode(InterpBasicBlock *pBB);
void PrintIns(InterpInst *ins);
void PrintPointer(void* pointer);
- void PrintHelperFtn(void* helperAddr);
+ void PrintHelperFtn(int32_t _data);
void PrintInsData(InterpInst *ins, int32_t offset, const int32_t *pData, int32_t opcode);
void PrintCompiledCode();
void PrintCompiledIns(const int32_t *ip, const int32_t *start);
diff --git a/src/runtime/src/coreclr/interpreter/interpretershared.h b/src/runtime/src/coreclr/interpreter/interpretershared.h
index 210bc1c1ad3..b4bb490237e 100644
--- a/src/runtime/src/coreclr/interpreter/interpretershared.h
+++ b/src/runtime/src/coreclr/interpreter/interpretershared.h
@@ -17,7 +17,10 @@
#define INTERP_STACK_SLOT_SIZE 8 // Alignment of each var offset on the interpreter stack
#define INTERP_STACK_ALIGNMENT 16 // Alignment of interpreter stack at the start of a frame
-#define INTERP_DIRECT_HELPER_TAG 1 // When a helper ftn's address is direct we tag it with this tag bit
+struct InterpHelperData {
+ uint32_t addressDataItemIndex : 29;
+ uint32_t accessType : 3;
+};
struct CallStubHeader;
diff --git a/src/runtime/src/coreclr/interpreter/intops.def b/src/runtime/src/coreclr/interpreter/intops.def
index 8de811f7b52..0e1d73769a4 100644
--- a/src/runtime/src/coreclr/interpreter/intops.def
+++ b/src/runtime/src/coreclr/interpreter/intops.def
@@ -400,8 +400,6 @@ OPDEF(INTOP_LEAVE_CATCH, "leavecatch", 2, 0, 0, InterpOpBranch)
OPDEF(INTOP_LOAD_EXCEPTION, "load.exception", 2, 1, 0, InterpOpNoArgs)
OPDEF(INTOP_THROW_PNSE, "throw.pnse", 1, 0, 0, InterpOpNoArgs)
-OPDEF(INTOP_FAILFAST, "failfast", 1, 0, 0, InterpOpNoArgs)
-OPDEF(INTOP_GC_COLLECT, "gc.collect", 1, 0, 0, InterpOpNoArgs)
OPDEF(INTOP_LOAD_FRAMEVAR, "load.framevar", 2, 1, 0, InterpOpNoArgs)
diff --git a/src/runtime/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/runtime/src/coreclr/jit/ICorJitInfo_names_generated.h
index e8e089f0b1d..34972535019 100644
--- a/src/runtime/src/coreclr/jit/ICorJitInfo_names_generated.h
+++ b/src/runtime/src/coreclr/jit/ICorJitInfo_names_generated.h
@@ -136,7 +136,6 @@ DEF_CLR_API(getAddrOfCaptureThreadGlobal)
DEF_CLR_API(getHelperFtn)
DEF_CLR_API(getFunctionEntryPoint)
DEF_CLR_API(getFunctionFixedEntryPoint)
-DEF_CLR_API(getMethodSync)
DEF_CLR_API(getLazyStringLiteralHelper)
DEF_CLR_API(embedModuleHandle)
DEF_CLR_API(embedClassHandle)
diff --git a/src/runtime/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/runtime/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
index c2a8418e302..7ee76ced3f8 100644
--- a/src/runtime/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
+++ b/src/runtime/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
@@ -1299,16 +1299,6 @@ void WrapICorJitInfo::getFunctionFixedEntryPoint(
API_LEAVE(getFunctionFixedEntryPoint);
}
-void* WrapICorJitInfo::getMethodSync(
- CORINFO_METHOD_HANDLE ftn,
- void** ppIndirection)
-{
- API_ENTER(getMethodSync);
- void* temp = wrapHnd->getMethodSync(ftn, ppIndirection);
- API_LEAVE(getMethodSync);
- return temp;
-}
-
CorInfoHelpFunc WrapICorJitInfo::getLazyStringLiteralHelper(
CORINFO_MODULE_HANDLE handle)
{
diff --git a/src/runtime/src/coreclr/jit/assertionprop.cpp b/src/runtime/src/coreclr/jit/assertionprop.cpp
index 787897de5e1..ae68b1def58 100644
--- a/src/runtime/src/coreclr/jit/assertionprop.cpp
+++ b/src/runtime/src/coreclr/jit/assertionprop.cpp
@@ -5633,8 +5633,8 @@ bool Compiler::optCreateJumpTableImpliedAssertions(BasicBlock* switchBb)
GenTree* switchTree = switchBb->lastStmt()->GetRootNode()->gtEffectiveVal();
assert(switchTree->OperIs(GT_SWITCH));
- // bbsCount is uint32_t, but it's unlikely to be more than INT32_MAX.
- noway_assert(switchBb->GetSwitchTargets()->bbsCount <= INT32_MAX);
+ // Case count is uint32_t, but it's unlikely to be more than INT32_MAX.
+ noway_assert(switchBb->GetSwitchTargets()->GetCaseCount() <= INT32_MAX);
ValueNum opVN = optConservativeNormalVN(switchTree->gtGetOp1());
if (opVN == ValueNumStore::NoVN)
@@ -5652,9 +5652,9 @@ bool Compiler::optCreateJumpTableImpliedAssertions(BasicBlock* switchBb)
int offset = 0;
vnStore->PeelOffsetsI32(&opVN, &offset);
- int jumpCount = static_cast(switchBb->GetSwitchTargets()->bbsCount);
- FlowEdge** jumpTable = switchBb->GetSwitchTargets()->bbsDstTab;
- bool hasDefault = switchBb->GetSwitchTargets()->bbsHasDefault;
+ int jumpCount = static_cast(switchBb->GetSwitchTargets()->GetCaseCount());
+ FlowEdge** jumpTable = switchBb->GetSwitchTargets()->GetCases();
+ bool hasDefault = switchBb->GetSwitchTargets()->HasDefaultCase();
for (int jmpTargetIdx = 0; jmpTargetIdx < jumpCount; jmpTargetIdx++)
{
@@ -5666,14 +5666,15 @@ bool Compiler::optCreateJumpTableImpliedAssertions(BasicBlock* switchBb)
int value = jmpTargetIdx - offset;
// We can only make "X == caseValue" assertions for blocks with a single edge from the switch.
- BasicBlock* target = jumpTable[jmpTargetIdx]->getDestinationBlock();
+ FlowEdge* const edge = jumpTable[jmpTargetIdx];
+ BasicBlock* const target = edge->getDestinationBlock();
if (target->GetUniquePred(this) != switchBb)
{
// Target block is potentially reachable from multiple blocks (outside the switch).
continue;
}
- if (fgGetPredForBlock(target, switchBb)->getDupCount() > 1)
+ if (edge->getDupCount() > 1)
{
// We have just one predecessor (BBJ_SWITCH), but there may be multiple edges (cases) per target.
continue;
diff --git a/src/runtime/src/coreclr/jit/async.cpp b/src/runtime/src/coreclr/jit/async.cpp
index 7a26ab4b004..6dc06714054 100644
--- a/src/runtime/src/coreclr/jit/async.cpp
+++ b/src/runtime/src/coreclr/jit/async.cpp
@@ -290,12 +290,11 @@ BasicBlock* Compiler::InsertTryFinallyForContextRestore(BasicBlock* block, State
block->SetTargetEdge(fgAddRefPred(callFinally, block));
callFinally->SetTargetEdge(fgAddRefPred(finallyRet, callFinally));
- BBehfDesc* ehfDesc = new (this, CMK_BasicBlock) BBehfDesc;
- ehfDesc->bbeCount = 1;
- ehfDesc->bbeSuccs = new (this, CMK_BasicBlock) FlowEdge* [1] {
+ FlowEdge** succs = new (this, CMK_BasicBlock) FlowEdge* [1] {
fgAddRefPred(callFinallyRet, finallyRet)
};
- ehfDesc->bbeSuccs[0]->setLikelihood(1.0);
+ succs[0]->setLikelihood(1.0);
+ BBJumpTable* ehfDesc = new (this, CMK_BasicBlock) BBJumpTable(succs, 1);
finallyRet->SetEhfTargets(ehfDesc);
callFinallyRet->SetTargetEdge(fgAddRefPred(goToTailBlock, callFinallyRet));
@@ -2288,18 +2287,26 @@ void AsyncTransformation::CreateResumptionSwitch()
// Default case. TODO-CQ: Support bbsHasDefault = false before lowering.
m_resumptionBBs.push_back(m_resumptionBBs[0]);
- BBswtDesc* swtDesc = new (m_comp, CMK_BasicBlock) BBswtDesc;
- swtDesc->bbsCount = (unsigned)m_resumptionBBs.size();
- swtDesc->bbsHasDefault = true;
- swtDesc->bbsDstTab = new (m_comp, CMK_Async) FlowEdge*[m_resumptionBBs.size()];
+ const size_t numCases = m_resumptionBBs.size();
+ FlowEdge** const cases = new (m_comp, CMK_FlowEdge) FlowEdge*[numCases * 2];
+ FlowEdge** const succs = cases + numCases;
+ unsigned numUniqueSuccs = 0;
- weight_t stateLikelihood = 1.0 / m_resumptionBBs.size();
- for (size_t i = 0; i < m_resumptionBBs.size(); i++)
+ const weight_t stateLikelihood = 1.0 / m_resumptionBBs.size();
+ for (size_t i = 0; i < numCases; i++)
{
- swtDesc->bbsDstTab[i] = m_comp->fgAddRefPred(m_resumptionBBs[i], switchBB);
- swtDesc->bbsDstTab[i]->setLikelihood(stateLikelihood);
+ FlowEdge* const edge = m_comp->fgAddRefPred(m_resumptionBBs[i], switchBB);
+ edge->setLikelihood(stateLikelihood);
+ cases[i] = edge;
+
+ if (edge->getDupCount() == 1)
+ {
+ succs[numUniqueSuccs++] = edge;
+ }
}
+ BBswtDesc* const swtDesc =
+ new (m_comp, CMK_BasicBlock) BBswtDesc(cases, (unsigned)numCases, succs, numUniqueSuccs, true);
switchBB->SetSwitch(swtDesc);
}
diff --git a/src/runtime/src/coreclr/jit/block.cpp b/src/runtime/src/coreclr/jit/block.cpp
index 52f860ff736..a363e56c629 100644
--- a/src/runtime/src/coreclr/jit/block.cpp
+++ b/src/runtime/src/coreclr/jit/block.cpp
@@ -586,39 +586,10 @@ unsigned BasicBlock::dspPreds() const
void BasicBlock::dspSuccs(Compiler* compiler)
{
bool first = true;
-
- // If this is a switch, we don't want to call `Succs(Compiler*)` because it will eventually call
- // `GetSwitchDescMap()`, and that will have the side-effect of allocating the unique switch descriptor map
- // and/or compute this switch block's unique succ set if it is not present. Debug output functions should
- // never have an effect on codegen. We also don't want to assume the unique succ set is accurate, so we
- // compute it ourselves here.
- if (bbKind == BBJ_SWITCH)
- {
- // Create a set with all the successors.
- unsigned bbNumMax = compiler->fgBBNumMax;
- BitVecTraits bitVecTraits(bbNumMax + 1, compiler);
- BitVec uniqueSuccBlocks(BitVecOps::MakeEmpty(&bitVecTraits));
- for (BasicBlock* const bTarget : SwitchTargets())
- {
- BitVecOps::AddElemD(&bitVecTraits, uniqueSuccBlocks, bTarget->bbNum);
- }
- BitVecOps::Iter iter(&bitVecTraits, uniqueSuccBlocks);
- unsigned bbNum = 0;
- while (iter.NextElem(&bbNum))
- {
- // Note that we will output switch successors in increasing numerical bbNum order, which is
- // not related to their order in the bbSwtTargets->bbsDstTab table.
- printf("%s" FMT_BB, first ? "" : ",", bbNum);
- first = false;
- }
- }
- else
+ for (const BasicBlock* const succ : Succs(compiler))
{
- for (const BasicBlock* const succ : Succs(compiler))
- {
- printf("%s" FMT_BB, first ? "" : ",", succ->bbNum);
- first = false;
- }
+ printf("%s" FMT_BB, first ? "" : ",", succ->bbNum);
+ first = false;
}
}
@@ -672,12 +643,9 @@ void BasicBlock::dspKind() const
}
else
{
- const unsigned jumpCnt = bbEhfTargets->bbeCount;
- FlowEdge** const jumpTab = bbEhfTargets->bbeSuccs;
-
- for (unsigned i = 0; i < jumpCnt; i++)
+ for (unsigned i = 0; i < bbEhfTargets->GetSuccCount(); i++)
{
- printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]));
+ printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(bbEhfTargets->GetSucc(i)));
}
}
@@ -736,20 +704,20 @@ void BasicBlock::dspKind() const
{
printf(" ->");
- const unsigned jumpCnt = bbSwtTargets->bbsCount;
- FlowEdge** const jumpTab = bbSwtTargets->bbsDstTab;
+ const unsigned jumpCnt = bbSwtTargets->GetCaseCount();
+ FlowEdge** const jumpTab = bbSwtTargets->GetCases();
for (unsigned i = 0; i < jumpCnt; i++)
{
printf("%c%s", (i == 0) ? ' ' : ',', dspBlockNum(jumpTab[i]));
- const bool isDefault = bbSwtTargets->bbsHasDefault && (i == jumpCnt - 1);
+ const bool isDefault = bbSwtTargets->HasDefaultCase() && (i == jumpCnt - 1);
if (isDefault)
{
printf("[def]");
}
- const bool isDominant = bbSwtTargets->bbsHasDominantCase && (i == bbSwtTargets->bbsDominantCase);
+ const bool isDominant = bbSwtTargets->HasDominantCase() && (i == bbSwtTargets->GetDominantCase());
if (isDominant)
{
printf("[dom]");
@@ -1184,10 +1152,10 @@ unsigned BasicBlock::NumSucc() const
return 0;
}
- return bbEhfTargets->bbeCount;
+ return bbEhfTargets->GetSuccCount();
case BBJ_SWITCH:
- return bbSwtTargets->bbsCount;
+ return bbSwtTargets->GetCaseCount();
default:
unreached();
@@ -1229,10 +1197,10 @@ FlowEdge* BasicBlock::GetSuccEdge(unsigned i) const
}
case BBJ_EHFINALLYRET:
- return bbEhfTargets->bbeSuccs[i];
+ return bbEhfTargets->GetSucc(i);
case BBJ_SWITCH:
- return bbSwtTargets->bbsDstTab[i];
+ return bbSwtTargets->GetCase(i);
default:
unreached();
@@ -1288,7 +1256,7 @@ unsigned BasicBlock::NumSucc(Compiler* comp)
return 0;
}
- return bbEhfTargets->bbeCount;
+ return bbEhfTargets->GetSuccCount();
case BBJ_CALLFINALLY:
case BBJ_CALLFINALLYRET:
@@ -1309,10 +1277,7 @@ unsigned BasicBlock::NumSucc(Compiler* comp)
}
case BBJ_SWITCH:
- {
- Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
- return sd.numDistinctSuccs;
- }
+ return bbSwtTargets->GetSuccCount();
default:
unreached();
@@ -1343,8 +1308,7 @@ FlowEdge* BasicBlock::GetSuccEdge(unsigned i, Compiler* comp)
case BBJ_EHFINALLYRET:
assert(bbEhfTargets != nullptr);
- assert(i < bbEhfTargets->bbeCount);
- return bbEhfTargets->bbeSuccs[i];
+ return bbEhfTargets->GetSucc(i);
case BBJ_CALLFINALLY:
case BBJ_CALLFINALLYRET:
@@ -1366,11 +1330,7 @@ FlowEdge* BasicBlock::GetSuccEdge(unsigned i, Compiler* comp)
}
case BBJ_SWITCH:
- {
- Compiler::SwitchUniqueSuccSet sd = comp->GetDescriptorForSwitch(this);
- assert(i < sd.numDistinctSuccs); // Range check.
- return sd.nonDuplicates[i];
- }
+ return bbSwtTargets->GetSucc(i);
default:
unreached();
@@ -1636,7 +1596,7 @@ BasicBlock* BasicBlock::New(Compiler* compiler, BBKinds kind)
return block;
}
-BasicBlock* BasicBlock::New(Compiler* compiler, BBehfDesc* ehfTargets)
+BasicBlock* BasicBlock::New(Compiler* compiler, BBJumpTable* ehfTargets)
{
BasicBlock* block = BasicBlock::New(compiler);
block->SetEhf(ehfTargets);
@@ -1758,21 +1718,6 @@ bool BasicBlock::hasEHBoundaryOut() const
return KindIs(BBJ_EHFILTERRET, BBJ_EHFINALLYRET, BBJ_EHFAULTRET, BBJ_EHCATCHRET);
}
-//------------------------------------------------------------------------
-// BBswtDesc copy ctor: copy a switch descriptor, but don't set up the jump table
-//
-// Arguments:
-// other - existing switch descriptor to copy (except for its jump table)
-//
-BBswtDesc::BBswtDesc(const BBswtDesc* other)
- : bbsDstTab(nullptr)
- , bbsCount(other->bbsCount)
- , bbsDominantCase(other->bbsDominantCase)
- , bbsHasDefault(other->bbsHasDefault)
- , bbsHasDominantCase(other->bbsHasDominantCase)
-{
-}
-
//------------------------------------------------------------------------
// BBswtDesc copy ctor: copy a switch descriptor
//
@@ -1781,38 +1726,33 @@ BBswtDesc::BBswtDesc(const BBswtDesc* other)
// other - existing switch descriptor to copy
//
BBswtDesc::BBswtDesc(Compiler* comp, const BBswtDesc* other)
- : bbsDstTab(nullptr)
- , bbsCount(other->bbsCount)
+ : BBJumpTable(new(comp, CMK_FlowEdge) FlowEdge*[other->succCount + other->caseCount], other -> succCount)
+ , caseCount(other->caseCount)
+ , cases(succs + succCount)
, bbsDominantCase(other->bbsDominantCase)
, bbsHasDefault(other->bbsHasDefault)
, bbsHasDominantCase(other->bbsHasDominantCase)
{
- // Allocate and fill in a new dst tab
+ // Fill in the new tables
//
- bbsDstTab = new (comp, CMK_FlowEdge) FlowEdge*[bbsCount];
- for (unsigned i = 0; i < bbsCount; i++)
- {
- bbsDstTab[i] = other->bbsDstTab[i];
- }
+ memcpy(succs, other->succs, sizeof(FlowEdge*) * succCount);
+ memcpy(cases, other->cases, sizeof(FlowEdge*) * caseCount);
}
//------------------------------------------------------------------------
-// BBehfDesc copy ctor: copy a EHFINALLYRET descriptor
+// BBJumpTable copy ctor: copy a N-successor block descriptor
//
// Arguments:
// comp - compiler instance
// other - existing descriptor to copy
//
-BBehfDesc::BBehfDesc(Compiler* comp, const BBehfDesc* other)
- : bbeCount(other->bbeCount)
+BBJumpTable::BBJumpTable(Compiler* comp, const BBJumpTable* other)
+ : succs(new(comp, CMK_FlowEdge) FlowEdge*[other->succCount])
+ , succCount(other->succCount)
{
- // Allocate and fill in a new dst tab
+ // Fill in the new jump table
//
- bbeSuccs = new (comp, CMK_FlowEdge) FlowEdge*[bbeCount];
- for (unsigned i = 0; i < bbeCount; i++)
- {
- bbeSuccs[i] = other->bbeSuccs[i];
- }
+ memcpy(succs, other->succs, sizeof(FlowEdge*) * succCount);
}
//------------------------------------------------------------------------
diff --git a/src/runtime/src/coreclr/jit/block.h b/src/runtime/src/coreclr/jit/block.h
index c541fa5309c..e1ffa46cff0 100644
--- a/src/runtime/src/coreclr/jit/block.h
+++ b/src/runtime/src/coreclr/jit/block.h
@@ -107,7 +107,7 @@ struct BasicBlockList;
struct FlowEdge;
struct EHblkDsc;
struct BBswtDesc;
-struct BBehfDesc;
+struct BBJumpTable;
struct StackEntry
{
@@ -346,7 +346,7 @@ class BBArrayIterator
}
};
-// FlowEdgeArrayIterator: forward iterator for an array of FlowEdge*, such as the BBswtDesc->bbsDstTab.
+// FlowEdgeArrayIterator: forward iterator for an array of FlowEdge*, such as BBJumpTable::succs.
// It is an error (with assert) to yield a nullptr FlowEdge* in this array.
// `m_edgeEntry` can be nullptr, but it only makes sense if both the begin and end of an iteration range are nullptr
// (meaning, no actual iteration will happen).
@@ -382,30 +382,16 @@ class FlowEdgeArrayIterator
}
};
-// BBSwitchTargetList: adapter class for forward iteration of switch targets, using range-based `for`,
-// normally used via BasicBlock::SwitchTargets(), e.g.:
-// for (BasicBlock* const target : block->SwitchTargets()) ...
-//
-class BBSwitchTargetList
-{
- BBswtDesc* m_bbsDesc;
-
-public:
- BBSwitchTargetList(BBswtDesc* bbsDesc);
- BBArrayIterator begin() const;
- BBArrayIterator end() const;
-};
-
-// BBEhfSuccList: adapter class for forward iteration of BBJ_EHFINALLYRET blocks, using range-based `for`,
-// normally used via BasicBlock::EHFinallyRetSuccs(), e.g.:
+// BBJumpTableList: adapter class for forward iteration of blocks with N successors, using range-based `for`,
+// normally used via BasicBlock::EHFinallyRetSuccs() or BasicBlock::SwitchSuccs(), e.g.:
// for (BasicBlock* const succ : block->EHFinallyRetSuccs()) ...
//
-class BBEhfSuccList
+class BBJumpTableList
{
- BBehfDesc* m_bbeDesc;
+ BBJumpTable* m_bbJumpTable;
public:
- BBEhfSuccList(BBehfDesc* bbeDesc);
+ BBJumpTableList(BBJumpTable* bbJumpTable);
BBArrayIterator begin() const;
BBArrayIterator end() const;
};
@@ -740,11 +726,11 @@ struct BasicBlock : private LIR::Range
/* The following union describes the jump target(s) of this block */
union
{
- unsigned bbTargetOffs; // PC offset (temporary only)
- FlowEdge* bbTargetEdge; // successor edge for block kinds with only one successor (BBJ_ALWAYS, etc)
- FlowEdge* bbTrueEdge; // BBJ_COND successor edge when its condition is true (alias for bbTargetEdge)
- BBswtDesc* bbSwtTargets; // switch descriptor
- BBehfDesc* bbEhfTargets; // BBJ_EHFINALLYRET descriptor
+ unsigned bbTargetOffs; // PC offset (temporary only)
+ FlowEdge* bbTargetEdge; // successor edge for block kinds with only one successor (BBJ_ALWAYS, etc)
+ FlowEdge* bbTrueEdge; // BBJ_COND successor edge when its condition is true (alias for bbTargetEdge)
+ BBswtDesc* bbSwtTargets; // switch descriptor
+ BBJumpTable* bbEhfTargets; // BBJ_EHFINALLYRET descriptor
};
// Successor edge of a BBJ_COND block if bbTrueEdge is not taken
@@ -753,7 +739,7 @@ struct BasicBlock : private LIR::Range
public:
static BasicBlock* New(Compiler* compiler);
static BasicBlock* New(Compiler* compiler, BBKinds kind);
- static BasicBlock* New(Compiler* compiler, BBehfDesc* ehfTargets);
+ static BasicBlock* New(Compiler* compiler, BBJumpTable* ehfTargets);
static BasicBlock* New(Compiler* compiler, BBswtDesc* swtTargets);
static BasicBlock* New(Compiler* compiler, BBKinds kind, unsigned targetOffs);
@@ -1029,19 +1015,19 @@ struct BasicBlock : private LIR::Range
bbSwtTargets = swtTarget;
}
- BBehfDesc* GetEhfTargets() const
+ BBJumpTable* GetEhfTargets() const
{
assert(KindIs(BBJ_EHFINALLYRET));
return bbEhfTargets;
}
- void SetEhfTargets(BBehfDesc* ehfTarget)
+ void SetEhfTargets(BBJumpTable* ehfTarget)
{
assert(KindIs(BBJ_EHFINALLYRET));
bbEhfTargets = ehfTarget;
}
- void SetEhf(BBehfDesc* ehfTarget)
+ void SetEhf(BBJumpTable* ehfTarget)
{
assert(ehfTarget != nullptr);
bbKind = BBJ_EHFINALLYRET;
@@ -1405,23 +1391,24 @@ struct BasicBlock : private LIR::Range
BasicBlock* GetSucc(unsigned i) const;
BasicBlock* GetSucc(unsigned i, Compiler* comp);
- // SwitchTargets: convenience method for enabling range-based `for` iteration over a switch block's targets, e.g.:
- // for (BasicBlock* const bTarget : block->SwitchTargets()) ...
+ // SwitchSuccs: convenience method for enabling range-based `for` iteration over a switch block's unique successors,
+ // e.g.:
+ // for (BasicBlock* const bTarget : block->SwitchSuccs()) ...
//
- BBSwitchTargetList SwitchTargets() const
+ BBJumpTableList SwitchSuccs() const
{
assert(bbKind == BBJ_SWITCH);
- return BBSwitchTargetList(bbSwtTargets);
+ return BBJumpTableList((BBJumpTable*)bbSwtTargets);
}
// EHFinallyRetSuccs: convenience method for enabling range-based `for` iteration over BBJ_EHFINALLYRET block
// successors, e.g.:
// for (BasicBlock* const succ : block->EHFinallyRetSuccs()) ...
//
- BBEhfSuccList EHFinallyRetSuccs() const
+ BBJumpTableList EHFinallyRetSuccs() const
{
assert(bbKind == BBJ_EHFINALLYRET);
- return BBEhfSuccList(bbEhfTargets);
+ return BBJumpTableList(bbEhfTargets);
}
BasicBlock* GetUniquePred(Compiler* comp) const;
@@ -2280,6 +2267,70 @@ class BasicBlockRangeList
bool ComplexityExceeds(Compiler* comp, unsigned limit, unsigned* count = nullptr);
};
+// BBJumpTable -- descriptor blocks with N successors
+//
+struct BBJumpTable
+{
+protected:
+ FlowEdge** succs; // array of unique `FlowEdge*` pointing to the block's successors
+ unsigned succCount; // Number of unique successors
+
+public:
+ BBJumpTable()
+ : succs(nullptr)
+ , succCount(0)
+ {
+ }
+
+ BBJumpTable(FlowEdge** succs, unsigned succCount)
+ : succs(succs)
+ , succCount(succCount)
+ {
+ }
+
+ BBJumpTable(Compiler* comp, const BBJumpTable* other);
+
+ FlowEdge** GetSuccs() const
+ {
+ return succs;
+ }
+
+ FlowEdge* GetSucc(unsigned index) const
+ {
+ assert(index < succCount);
+ assert(succs != nullptr);
+ return succs[index];
+ }
+
+ unsigned GetSuccCount() const
+ {
+ return succCount;
+ }
+
+ void SetSuccs(FlowEdge** newSuccs, unsigned newSuccCount)
+ {
+ assert((newSuccs != nullptr) || (newSuccCount == 0));
+
+ succs = newSuccs;
+ succCount = newSuccCount;
+ }
+
+ void RemoveSucc(unsigned index)
+ {
+ assert(index < succCount);
+ assert(succs != nullptr);
+
+ // If succEdge is not the last entry, move everything after in the table down one slot.
+ if ((index + 1) < succCount)
+ {
+ memmove_s(succs + index, (succCount - index) * sizeof(FlowEdge*), succs + index + 1,
+ (succCount - index - 1) * sizeof(FlowEdge*));
+ }
+
+ succCount--;
+ }
+};
+
// BBswtDesc -- descriptor for a switch block
//
// Things to know:
@@ -2289,11 +2340,20 @@ class BasicBlockRangeList
// allows for a degenerate switch with zero cases. Normally, the optimizer will optimize degenerate
// switches with just a default case to a BBJ_ALWAYS branch, and a switch with just two cases to a BBJ_COND.
// However, in debuggable code, we might not do that, so bbsCount might be 1.
+// 3. BBswtDesc makes no promises about the relative positions of the 'succs' and 'cases' arrays.
+// Callers are responsible for allocating these arrays during BBswtDesc creation.
+// A potential optimization is to allocate one array large enough for the two;
+// this is safe, because BBswtDesc does not support adding new cases/successors.
//
-struct BBswtDesc
+struct BBswtDesc : public BBJumpTable
{
- FlowEdge** bbsDstTab; // case label table address
- unsigned bbsCount; // count of cases (includes 'default' if bbsHasDefault)
+private:
+ // Inherited from BBJumpTable:
+ // FlowEdge** succs; // array of unique `FlowEdge*` pointing to the block's successors
+ // unsigned succCount; // Number of unique successors
+
+ unsigned caseCount; // count of cases (includes 'default' if bbsHasDefault)
+ FlowEdge** cases; // array of non-unique FlowEdge* pointing to the switch cases
// Case number of most likely case
// (only known with PGO, only valid if bbsHasDominantCase is true)
@@ -2302,86 +2362,114 @@ struct BBswtDesc
bool bbsHasDefault; // true if last switch case is a default case
bool bbsHasDominantCase; // true if switch has a dominant case
- BBswtDesc()
- : bbsHasDefault(true)
+public:
+ BBswtDesc(FlowEdge** succs, unsigned succCount, FlowEdge** cases, unsigned caseCount, bool hasDefault)
+ : BBJumpTable(succs, succCount)
+ , caseCount(caseCount)
+ , cases(cases)
+ , bbsDominantCase(0)
+ , bbsHasDefault(hasDefault)
, bbsHasDominantCase(false)
{
}
- BBswtDesc(const BBswtDesc* other);
+ BBswtDesc(FlowEdge** succs,
+ unsigned succCount,
+ FlowEdge** cases,
+ unsigned caseCount,
+ bool hasDefault,
+ unsigned dominantCase)
+ : BBJumpTable(succs, succCount)
+ , caseCount(caseCount)
+ , cases(cases)
+ , bbsDominantCase(dominantCase)
+ , bbsHasDefault(hasDefault)
+ , bbsHasDominantCase(true)
+ {
+ }
BBswtDesc(Compiler* comp, const BBswtDesc* other);
- void removeDefault()
+ FlowEdge** GetCases() const
{
- assert(bbsHasDefault);
- assert(bbsCount > 0);
- bbsHasDefault = false;
- bbsCount--;
+ assert((cases != nullptr) || (caseCount == 0));
+ return cases;
}
- FlowEdge* getDefault()
+ FlowEdge* GetCase(unsigned index) const
{
- assert(bbsHasDefault);
- assert(bbsCount > 0);
- return bbsDstTab[bbsCount - 1];
+ assert(index < caseCount);
+ return cases[index];
}
-};
-// BBSwitchTargetList out-of-class-declaration implementations (here due to C++ ordering requirements).
-//
+ unsigned GetCaseCount() const
+ {
+ return caseCount;
+ }
-inline BBSwitchTargetList::BBSwitchTargetList(BBswtDesc* bbsDesc)
- : m_bbsDesc(bbsDesc)
-{
- assert(m_bbsDesc != nullptr);
- assert(m_bbsDesc->bbsDstTab != nullptr);
-}
+ void RemoveDefaultCase()
+ {
+ assert(bbsHasDefault);
+ assert(caseCount > 0);
+ bbsHasDefault = false;
+ caseCount--;
+ }
-inline BBArrayIterator BBSwitchTargetList::begin() const
-{
- return BBArrayIterator(m_bbsDesc->bbsDstTab);
-}
+ bool HasDefaultCase() const
+ {
+ return bbsHasDefault;
+ }
-inline BBArrayIterator BBSwitchTargetList::end() const
-{
- return BBArrayIterator(m_bbsDesc->bbsDstTab + m_bbsDesc->bbsCount);
-}
+ FlowEdge* GetDefaultCase() const
+ {
+ assert(bbsHasDefault);
+ assert(caseCount > 0);
+ return cases[caseCount - 1];
+ }
-// BBehfDesc -- descriptor for a BBJ_EHFINALLYRET block
-//
-struct BBehfDesc
-{
- FlowEdge** bbeSuccs; // array of `FlowEdge*` pointing to BBJ_EHFINALLYRET block successors
- unsigned bbeCount; // size of `bbeSuccs` array
+ void SetDominantCase(unsigned dominantCase)
+ {
+ assert(!bbsHasDominantCase);
+ bbsDominantCase = dominantCase;
+ bbsHasDominantCase = true;
+ }
- BBehfDesc()
- : bbeSuccs(nullptr)
- , bbeCount(0)
+ void RemoveDominantCase()
{
+ assert(bbsHasDominantCase);
+ bbsHasDominantCase = false;
}
- BBehfDesc(Compiler* comp, const BBehfDesc* other);
+ bool HasDominantCase() const
+ {
+ return bbsHasDominantCase;
+ }
+
+ unsigned GetDominantCase() const
+ {
+ assert(bbsHasDominantCase);
+ return bbsDominantCase;
+ }
};
-// BBEhfSuccList out-of-class-declaration implementations (here due to C++ ordering requirements).
+// BBJumpTableList out-of-class-declaration implementations (here due to C++ ordering requirements).
//
-inline BBEhfSuccList::BBEhfSuccList(BBehfDesc* bbeDesc)
- : m_bbeDesc(bbeDesc)
+inline BBJumpTableList::BBJumpTableList(BBJumpTable* bbJumpTable)
+ : m_bbJumpTable(bbJumpTable)
{
- assert(m_bbeDesc != nullptr);
- assert((m_bbeDesc->bbeSuccs != nullptr) || (m_bbeDesc->bbeCount == 0));
+ assert(m_bbJumpTable != nullptr);
+ assert((m_bbJumpTable->GetSuccs() != nullptr) || (m_bbJumpTable->GetSuccCount() == 0));
}
-inline BBArrayIterator BBEhfSuccList::begin() const
+inline BBArrayIterator BBJumpTableList::begin() const
{
- return BBArrayIterator(m_bbeDesc->bbeSuccs);
+ return BBArrayIterator(m_bbJumpTable->GetSuccs());
}
-inline BBArrayIterator BBEhfSuccList::end() const
+inline BBArrayIterator BBJumpTableList::end() const
{
- return BBArrayIterator(m_bbeDesc->bbeSuccs + m_bbeDesc->bbeCount);
+ return BBArrayIterator(m_bbJumpTable->GetSuccs() + m_bbJumpTable->GetSuccCount());
}
// SuccList out-of-class-declaration implementations
@@ -2439,17 +2527,17 @@ inline BasicBlock::SuccList::SuccList(const BasicBlock* block)
}
else
{
- m_begin = block->GetEhfTargets()->bbeSuccs;
- m_end = block->GetEhfTargets()->bbeSuccs + block->GetEhfTargets()->bbeCount;
+ m_begin = block->GetEhfTargets()->GetSuccs();
+ m_end = block->GetEhfTargets()->GetSuccs() + block->GetEhfTargets()->GetSuccCount();
}
break;
case BBJ_SWITCH:
// We don't use the m_succs in-line data for switches; use the existing jump table in the block.
assert(block->bbSwtTargets != nullptr);
- assert(block->bbSwtTargets->bbsDstTab != nullptr);
- m_begin = block->bbSwtTargets->bbsDstTab;
- m_end = block->bbSwtTargets->bbsDstTab + block->bbSwtTargets->bbsCount;
+ assert(block->bbSwtTargets->GetCases() != nullptr);
+ m_begin = block->bbSwtTargets->GetCases();
+ m_end = block->bbSwtTargets->GetCases() + block->bbSwtTargets->GetCaseCount();
break;
default:
diff --git a/src/runtime/src/coreclr/jit/clrjit.natvis b/src/runtime/src/coreclr/jit/clrjit.natvis
index 424bd4e3f2d..b38738ea9ed 100644
--- a/src/runtime/src/coreclr/jit/clrjit.natvis
+++ b/src/runtime/src/coreclr/jit/clrjit.natvis
@@ -22,8 +22,8 @@ Documentation for VS debugger format specifiers: https://learn.microsoft.com/vis
BB{bbNum,d}->BB{bbTargetEdge->m_destBlock->bbNum,d}; {bbKind,en}
BB{bbNum,d}-> (BB{bbTrueEdge->m_destBlock->bbNum,d}(T),BB{bbFalseEdge->m_destBlock->bbNum,d}(F)) ; {bbKind,en}
- BB{bbNum,d}; {bbKind,en}; {bbSwtTargets->bbsCount} cases
- BB{bbNum,d}; {bbKind,en}; {bbEhfTargets->bbeCount} succs
+ BB{bbNum,d}; {bbKind,en}; {bbSwtTargets->caseCount} cases
+ BB{bbNum,d}; {bbKind,en}; {bbEhfTargets->succCount} succs
BB{bbNum,d}; {bbKind,en}
diff --git a/src/runtime/src/coreclr/jit/codegenarm64test.cpp b/src/runtime/src/coreclr/jit/codegenarm64test.cpp
index a66e626a6e2..aefe56ea0f0 100644
--- a/src/runtime/src/coreclr/jit/codegenarm64test.cpp
+++ b/src/runtime/src/coreclr/jit/codegenarm64test.cpp
@@ -7036,95 +7036,95 @@ void CodeGen::genArm64EmitterUnitTestsSve()
// IF_SVE_FE_3A
theEmitter->emitIns_R_R_R_I(INS_sve_smullb, EA_SCALABLE, REG_V0, REG_V1, REG_V0, 0,
- INS_OPTS_SCALABLE_H); // SMULLB .S, .H, .H[]
+ INS_OPTS_SCALABLE_S); // SMULLB .S, .H, .H[]
theEmitter->emitIns_R_R_R_I(INS_sve_smullb, EA_SCALABLE, REG_V2, REG_V3, REG_V1, 1,
- INS_OPTS_SCALABLE_H); // SMULLB .S, .H, .H[]
+ INS_OPTS_SCALABLE_S); // SMULLB .S, .H, .H[]
theEmitter->emitIns_R_R_R_I(INS_sve_smullt, EA_SCALABLE, REG_V4, REG_V5, REG_V2, 2,
- INS_OPTS_SCALABLE_H); // SMULLT .S, .H, .H[]
+ INS_OPTS_SCALABLE_S); // SMULLT .S, .H, .H[]
theEmitter->emitIns_R_R_R_I(INS_sve_smullt, EA_SCALABLE, REG_V6, REG_V7, REG_V3, 3,
- INS_OPTS_SCALABLE_H); // SMULLT .S, .H, .H[]
+ INS_OPTS_SCALABLE_S); // SMULLT .S,