diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 806cac131a1a5..805b05793cfc6 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -389,3 +389,8 @@ stages:
- script: ./eng/build.sh --solution Roslyn.sln --restore --build --configuration Debug --prepareMachine --ci --binaryLog --runanalyzers --warnaserror /p:RoslynEnforceCodeStyle=true
displayName: Build with analyzers
+
+ - template: eng/pipelines/publish-logs.yml
+ parameters:
+ jobName: Correctness_Analyzers
+ configuration: Debug
diff --git a/docs/Language Feature Status.md b/docs/Language Feature Status.md
index 361f44b3e96c0..fe565913a002f 100644
--- a/docs/Language Feature Status.md
+++ b/docs/Language Feature Status.md
@@ -10,6 +10,7 @@ efforts behind them.
| Feature | Branch | State | Developer | Reviewer | LDM Champ |
| ------- | ------ | ----- | --------- | -------- | --------- |
+| [Inline Arrays](https://github.com/dotnet/csharplang/blob/main/proposals/inline-arrays.md) | [InlineArrays](https://github.com/dotnet/roslyn/tree/features/InlineArrays) | [In Progress](https://github.com/dotnet/roslyn/issues/67826) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | |
| [Using aliases for any type](https://github.com/dotnet/csharplang/issues/4284) | [UsingAliasTypes](https://github.com/dotnet/roslyn/tree/features/UsingAliasTypes) | [Merged into 17.6.P3](https://github.com/dotnet/roslyn/issues/56323) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) | [jcouv](https://github.com/jcouv) [cston](https://github.com/cston) | |
| [Primary Constructors](https://github.com/dotnet/csharplang/issues/2691) | [PrimaryConstructors](https://github.com/dotnet/roslyn/tree/features/PrimaryConstructors) | [Merged into 17.6.P2](https://github.com/dotnet/roslyn/issues/65697) | [AlekseyTs](https://github.com/AlekseyTs) | [cston](https://github.com/cston), [jjonescz](https://github.com/jjonescz) | [MadsTorgersen](https://github.com/MadsTorgersen) |
| [Semi-auto-properties](https://github.com/dotnet/csharplang/issues/140) | [semi-auto-props](https://github.com/dotnet/roslyn/tree/features/semi-auto-props) | [In Progress](https://github.com/dotnet/roslyn/issues/57012) | [Youssef1313](https://github.com/Youssef1313) | [333fred](https://github.com/333fred), [RikkiGibson](https://github.com/RikkiGibson) | [CyrusNajmabadi](https://github.com/CyrusNajmabadi) |
diff --git a/eng/targets/Settings.props b/eng/targets/Settings.props
index 5e9984f3f52e9..f00c32423d9f3 100644
--- a/eng/targets/Settings.props
+++ b/eng/targets/Settings.props
@@ -53,14 +53,63 @@
true
-
- net6.0
- net8.0;$(SourceBuildTargetFrameworks)
- net8.0
+
+
+
+
+
+ $(NetPrevious)
+ $(SourceBuildToolsetTargetFramework)
+ $(NetCurrent);$(NetPrevious)
+
+
- $(SourceBuildTargetFrameworks)
- $(SourceBuildTargetFrameworksNetFx);net472
-
+
+
+
+ $(NetCurrent)
+ $(SourceBuildToolsetTargetFramework)
+ $(NetCurrent)
+
+
+
+
+
+
+ net6.0
+ $(NetCurrent);$(NetPrevious);$(SourceBuildToolsetTargetFramework)
+ $(SourceBuildToolsetTargetFrameworks)
+
+
+
+
+
+
+ net6.0
+ $(SourceBuildToolsetTargetFramework);net7.0
+ $(SourceBuildToolsetTargetFrameworks)
+
+
+
-
-
+
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs
index ca2362131ea6c..a47b97af47889 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs
@@ -739,7 +739,7 @@ internal static void ReportDiagnosticsIfObsoleteInternal(BindingDiagnosticBag di
}
}
- internal static void ReportDiagnosticsIfUnmanagedCallersOnly(BindingDiagnosticBag diagnostics, MethodSymbol symbol, Location location, bool isDelegateConversion)
+ internal static void ReportDiagnosticsIfUnmanagedCallersOnly(BindingDiagnosticBag diagnostics, MethodSymbol symbol, SyntaxNodeOrToken syntax, bool isDelegateConversion)
{
var unmanagedCallersOnlyAttributeData = symbol.GetUnmanagedCallersOnlyAttributeData(forceComplete: false);
if (unmanagedCallersOnlyAttributeData != null)
@@ -747,13 +747,14 @@ internal static void ReportDiagnosticsIfUnmanagedCallersOnly(BindingDiagnosticBa
// Either we haven't yet bound the attributes of this method, or there is an UnmanagedCallersOnly present.
// In the former case, we use a lazy diagnostic that may end up being ignored later, to avoid causing a
// binding cycle.
+ Debug.Assert(syntax.GetLocation() != null);
diagnostics.Add(unmanagedCallersOnlyAttributeData == UnmanagedCallersOnlyAttributeData.Uninitialized
- ? (DiagnosticInfo)new LazyUnmanagedCallersOnlyMethodCalledDiagnosticInfo(symbol, isDelegateConversion)
+ ? new LazyUnmanagedCallersOnlyMethodCalledDiagnosticInfo(symbol, isDelegateConversion)
: new CSDiagnosticInfo(isDelegateConversion
? ErrorCode.ERR_UnmanagedCallersOnlyMethodsCannotBeConvertedToDelegate
: ErrorCode.ERR_UnmanagedCallersOnlyMethodsCannotBeCalledDirectly,
symbol),
- location);
+ syntax.GetLocation()!);
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
index 88e343755753b..13e97132b18c4 100644
--- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
@@ -544,7 +544,7 @@ private Symbol GetMemberSymbol(string memberName, TextSpan memberSpan, NamedType
{
Debug.Assert(kind is SymbolKind.Method or SymbolKind.Property or SymbolKind.Event);
- if (container is SourceMemberContainerTypeSymbol { PrimaryConstructor: not null } sourceMemberContainerTypeSymbol)
+ if (container is SourceMemberContainerTypeSymbol { HasPrimaryConstructor: true } sourceMemberContainerTypeSymbol)
{
foreach (Symbol sym in sourceMemberContainerTypeSymbol.GetMembersToMatchAgainstDeclarationSpan())
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
index d8373936fba69..94c4679db30e1 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs
@@ -20,7 +20,7 @@ internal partial class Binder
{
private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureAnonymousTypes.CheckFeatureAvailability(diagnostics, node, node.NewKeyword.GetLocation());
+ MessageID.IDS_FeatureAnonymousTypes.CheckFeatureAvailability(diagnostics, node.NewKeyword);
// prepare
var initializers = node.Initializers;
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
index e90c8e703b2da..ab1233623adf2 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
@@ -57,8 +57,7 @@ internal static void BindAttributeTypes(
// Check the attribute type (unless the attribute type is already an error).
if (boundTypeSymbol.TypeKind != TypeKind.Error)
{
- var location = attributeToBind.Name.GetLocation();
- binder.CheckDisallowedAttributeDependentType(boundType, location, diagnostics);
+ binder.CheckDisallowedAttributeDependentType(boundType, attributeToBind.Name, diagnostics);
}
boundAttributeTypes[i] = boundTypeSymbol;
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
index 9f234db5e7507..bc4ae144fe345 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Await.cs
@@ -18,7 +18,7 @@ internal partial class Binder
{
private BoundExpression BindAwait(AwaitExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureAsync.CheckFeatureAvailability(diagnostics, node, node.AwaitKeyword.GetLocation());
+ MessageID.IDS_FeatureAsync.CheckFeatureAvailability(diagnostics, node.AwaitKeyword);
BoundExpression expression = BindRValueWithoutTargetType(node.Expression, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index 525e00a5d611b..9f4e83b3466f1 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -1477,7 +1477,7 @@ private bool MethodGroupConversionHasErrors(
CheckValidScopedMethodConversion(syntax, selectedMethod, delegateOrFuncPtrType, isExtensionMethod, diagnostics);
if (!isAddressOf)
{
- ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, selectedMethod, location, isDelegateConversion: true);
+ ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, selectedMethod, syntax, isDelegateConversion: true);
}
ReportDiagnosticsIfObsolete(diagnostics, selectedMethod, syntax, hasBaseReceiver: false);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index 4e4f7788ca830..65b67de3ce739 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -835,7 +835,7 @@ private BoundExpression BindScopedType(ExpressionSyntax node, BindingDiagnosticB
private BoundExpression BindThrowExpression(ThrowExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureThrowExpression.CheckFeatureAvailability(diagnostics, node, node.ThrowKeyword.GetLocation());
+ MessageID.IDS_FeatureThrowExpression.CheckFeatureAvailability(diagnostics, node.ThrowKeyword);
bool hasErrors = node.HasErrors;
if (!IsThrowExpressionInProperContext(node))
@@ -1358,29 +1358,29 @@ private BoundExpression BindTypeOf(TypeOfExpressionSyntax node, BindingDiagnosti
}
/// Called when an "attribute-dependent" type such as 'dynamic', 'string?', etc. is not permitted.
- private void CheckDisallowedAttributeDependentType(TypeWithAnnotations typeArgument, Location errorLocation, BindingDiagnosticBag diagnostics)
+ private void CheckDisallowedAttributeDependentType(TypeWithAnnotations typeArgument, NameSyntax attributeName, BindingDiagnosticBag diagnostics)
{
typeArgument.VisitType(type: null, static (typeWithAnnotations, arg, _) =>
{
- var (errorLocation, diagnostics) = arg;
+ var (attributeName, diagnostics) = arg;
var type = typeWithAnnotations.Type;
if (type.IsDynamic()
|| (typeWithAnnotations.NullableAnnotation.IsAnnotated() && !type.IsValueType)
|| type.IsNativeIntegerWrapperType
|| (type.IsTupleType && !type.TupleElementNames.IsDefault))
{
- diagnostics.Add(ErrorCode.ERR_AttrDependentTypeNotAllowed, errorLocation, type);
+ diagnostics.Add(ErrorCode.ERR_AttrDependentTypeNotAllowed, attributeName, type);
return true;
}
if (type.IsUnboundGenericType() || type.Kind == SymbolKind.TypeParameter)
{
- diagnostics.Add(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, errorLocation, type);
+ diagnostics.Add(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, attributeName, type);
return true;
}
return false;
- }, typePredicate: null, arg: (errorLocation, diagnostics));
+ }, typePredicate: null, arg: (attributeName, diagnostics));
}
private BoundExpression BindSizeOf(SizeOfExpressionSyntax node, BindingDiagnosticBag diagnostics)
@@ -1441,7 +1441,7 @@ internal static ConstantValue GetConstantSizeOf(TypeSymbol type)
private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureDefault.CheckFeatureAvailability(diagnostics, node, node.Keyword.GetLocation());
+ MessageID.IDS_FeatureDefault.CheckFeatureAvailability(diagnostics, node.Keyword);
TypeWithAnnotations typeWithAnnotations = this.BindType(node.Type, diagnostics, out AliasSymbol alias);
var typeExpression = new BoundTypeExpression(node.Type, aliasOpt: alias, typeWithAnnotations);
@@ -1776,7 +1776,7 @@ private BoundExpression SynthesizeMethodGroupReceiver(CSharpSyntaxNode syntax, A
private bool IsBadLocalOrParameterCapture(Symbol symbol, TypeSymbol type, RefKind refKind)
{
- if (refKind != RefKind.None || type.IsRefLikeType)
+ if (refKind != RefKind.None || type.IsRestrictedType())
{
var containingMethod = this.ContainingMemberOrLambda as MethodSymbol;
if ((object)containingMethod != null && (object)symbol.ContainingSymbol != (object)containingMethod)
@@ -1899,7 +1899,15 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind
if (IsBadLocalOrParameterCapture(localSymbol, type, localSymbol.RefKind))
{
isError = true;
- Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseLocal, node, localSymbol);
+
+ if (localSymbol.RefKind == RefKind.None && type.IsRestrictedType(ignoreSpanLikeTypes: true))
+ {
+ Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, type);
+ }
+ else
+ {
+ Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseLocal, node, localSymbol);
+ }
}
}
@@ -1931,7 +1939,20 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind
if (IsBadLocalOrParameterCapture(parameter, parameter.Type, parameter.RefKind))
{
isError = true;
- Error(diagnostics, parameter.Type.IsRefLikeType ? ErrorCode.ERR_AnonDelegateCantUseRefLike : ErrorCode.ERR_AnonDelegateCantUse, node, parameter.Name);
+
+ if (parameter.RefKind != RefKind.None)
+ {
+ Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUse, node, parameter.Name);
+ }
+ else if (parameter.Type.IsRestrictedType(ignoreSpanLikeTypes: true))
+ {
+ Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, parameter.Type);
+ }
+ else
+ {
+ Debug.Assert(parameter.Type.IsRefLikeType);
+ Error(diagnostics, ErrorCode.ERR_AnonDelegateCantUseRefLike, node, parameter.Name);
+ }
}
else if (primaryCtor is not null)
{
@@ -1939,10 +1960,22 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind
bool capture = (this.ContainingMember() is MethodSymbol containingMethod && (object)primaryCtor != containingMethod);
if (capture &&
- (parameter.RefKind != RefKind.None || parameter.Type.IsRefLikeType) &&
+ (parameter.RefKind != RefKind.None || parameter.Type.IsRestrictedType()) &&
!IsInsideNameof)
{
- Error(diagnostics, parameter.Type.IsRefLikeType ? ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefLike : ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRef, node, parameter.Name);
+ if (parameter.RefKind != RefKind.None)
+ {
+ Error(diagnostics, ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRef, node, parameter.Name);
+ }
+ else if (parameter.Type.IsRestrictedType(ignoreSpanLikeTypes: true))
+ {
+ Error(diagnostics, ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefAny, node, parameter.Type);
+ }
+ else
+ {
+ Debug.Assert(parameter.Type.IsRefLikeType);
+ Error(diagnostics, ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefLike, node, parameter.Name);
+ }
}
else if (primaryCtor is { ThisParameter.RefKind: not RefKind.None } &&
this.ContainingMemberOrLambda is MethodSymbol { MethodKind: MethodKind.AnonymousFunction or MethodKind.LocalFunction } &&
@@ -2075,19 +2108,18 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi
(currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType))))
{
bool hasErrors = false;
- if (EnclosingNameofArgument != node)
+ if (!IsInsideNameof || (EnclosingNameofArgument != node && !node.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof)))
{
+ DiagnosticInfo diagnosticInfoOpt = null;
if (InFieldInitializer && !currentType.IsScriptClass)
{
//can't access "this" in field initializers
- Error(diagnostics, ErrorCode.ERR_FieldInitRefNonstatic, node, member);
- hasErrors = true;
+ diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_FieldInitRefNonstatic, member);
}
else if (InConstructorInitializer || InAttributeArgument)
{
//can't access "this" in constructor initializers or attribute arguments
- Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member);
- hasErrors = true;
+ diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member);
}
else
{
@@ -2099,12 +2131,24 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi
if (!locationIsInstanceMember)
{
// error CS0120: An object reference is required for the non-static field, method, or property '{0}'
- Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member);
- hasErrors = true;
+ diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member);
}
}
- hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnostics);
+ diagnosticInfoOpt ??= GetDiagnosticIfRefOrOutThisParameterCaptured();
+ hasErrors = diagnosticInfoOpt is not null;
+
+ if (hasErrors)
+ {
+ if (IsInsideNameof)
+ {
+ CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics);
+ }
+ else
+ {
+ Error(diagnostics, diagnosticInfoOpt, node);
+ }
+ }
}
return ThisReference(node, currentType, hasErrors, wasCompilerGenerated: true);
@@ -2276,20 +2320,35 @@ private BoundThisReference ThisReference(SyntaxNode node, NamedTypeSymbol thisTy
return new BoundThisReference(node, thisTypeOpt ?? CreateErrorType(), hasErrors) { WasCompilerGenerated = wasCompilerGenerated };
}
+#nullable enable
private bool IsRefOrOutThisParameterCaptured(SyntaxNodeOrToken thisOrBaseToken, BindingDiagnosticBag diagnostics)
{
- ParameterSymbol thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol();
- // If there is no this parameter, then it is definitely not captured and
- // any diagnostic would be cascading.
- if ((object)thisSymbol != null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None)
+ if (GetDiagnosticIfRefOrOutThisParameterCaptured() is { } diagnosticInfo)
{
- Error(diagnostics, ErrorCode.ERR_ThisStructNotInAnonMeth, thisOrBaseToken);
+ var location = thisOrBaseToken.GetLocation();
+ Debug.Assert(location is not null);
+ Error(diagnostics, diagnosticInfo, location);
return true;
}
return false;
}
+ private DiagnosticInfo? GetDiagnosticIfRefOrOutThisParameterCaptured()
+ {
+ Debug.Assert(this.ContainingMemberOrLambda is not null);
+ ParameterSymbol? thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol();
+ // If there is no this parameter, then it is definitely not captured and
+ // any diagnostic would be cascading.
+ if (thisSymbol is not null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None)
+ {
+ return new CSDiagnosticInfo(ErrorCode.ERR_ThisStructNotInAnonMeth);
+ }
+
+ return null;
+ }
+#nullable disable
+
private BoundBaseReference BindBase(BaseExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
bool hasErrors = false;
@@ -2868,12 +2927,12 @@ private void BindArgumentAndName(
private BoundExpression BindArgumentValue(BindingDiagnosticBag diagnostics, ArgumentSyntax argumentSyntax, bool allowArglist, RefKind refKind)
{
if (argumentSyntax.RefKindKeyword.IsKind(SyntaxKind.InKeyword))
- MessageID.IDS_FeatureReadOnlyReferences.CheckFeatureAvailability(diagnostics, argumentSyntax, argumentSyntax.RefKindKeyword.GetLocation());
+ MessageID.IDS_FeatureReadOnlyReferences.CheckFeatureAvailability(diagnostics, argumentSyntax.RefKindKeyword);
if (argumentSyntax.Expression.Kind() == SyntaxKind.DeclarationExpression)
{
if (argumentSyntax.RefKindKeyword.IsKind(SyntaxKind.OutKeyword))
- MessageID.IDS_FeatureOutVar.CheckFeatureAvailability(diagnostics, argumentSyntax, argumentSyntax.RefKindKeyword.GetLocation());
+ MessageID.IDS_FeatureOutVar.CheckFeatureAvailability(diagnostics, argumentSyntax.RefKindKeyword);
var declarationExpression = (DeclarationExpressionSyntax)argumentSyntax.Expression;
if (declarationExpression.IsOutDeclaration())
@@ -3403,7 +3462,7 @@ private BoundExpression BindArrayDimension(ExpressionSyntax dimension, BindingDi
private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreationExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
// See BindArrayCreationExpression method above for implicitly typed array creation SPEC.
- MessageID.IDS_FeatureImplicitArray.CheckFeatureAvailability(diagnostics, node, node.NewKeyword.GetLocation());
+ MessageID.IDS_FeatureImplicitArray.CheckFeatureAvailability(diagnostics, node.NewKeyword);
InitializerExpressionSyntax initializer = node.Initializer;
int rank = node.Commas.Count + 1;
@@ -3874,7 +3933,7 @@ private bool ReportBadStackAllocPosition(SyntaxNode node, BindingDiagnosticBag d
inLegalPosition = (IsInMethodBody || IsLocalFunctionsScopeBinder) && node.IsLegalCSharp73SpanStackAllocPosition();
if (!inLegalPosition)
{
- MessageID.IDS_FeatureNestedStackalloc.CheckFeatureAvailability(diagnostics, node, node.GetFirstToken().GetLocation());
+ MessageID.IDS_FeatureNestedStackalloc.CheckFeatureAvailability(diagnostics, node.GetFirstToken());
}
}
@@ -3956,7 +4015,7 @@ private BoundExpression BindStackAllocWithInitializer(
{
Debug.Assert(node.IsKind(SyntaxKind.ImplicitStackAllocArrayCreationExpression) || node.IsKind(SyntaxKind.StackAllocArrayCreationExpression));
- MessageID.IDS_FeatureStackAllocInitializer.CheckFeatureAvailability(diagnostics, node, stackAllocKeyword.GetLocation());
+ MessageID.IDS_FeatureStackAllocInitializer.CheckFeatureAvailability(diagnostics, stackAllocKeyword);
if (boundInitExprOpt.IsDefault)
{
@@ -4403,7 +4462,7 @@ constructor is not SynthesizedPrimaryConstructor &&
private BoundExpression BindImplicitObjectCreationExpression(ImplicitObjectCreationExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureImplicitObjectCreation.CheckFeatureAvailability(diagnostics, node, node.NewKeyword.GetLocation());
+ MessageID.IDS_FeatureImplicitObjectCreation.CheckFeatureAvailability(diagnostics, node.NewKeyword);
var arguments = AnalyzedArguments.GetInstance();
BindArgumentsAndNames(node.ArgumentList, diagnostics, arguments, allowArglist: true);
@@ -4826,7 +4885,7 @@ private BoundObjectInitializerExpression BindObjectInitializerExpression(
Debug.Assert((object)initializerType != null);
if (initializerSyntax.Kind() == SyntaxKind.ObjectInitializerExpression)
- MessageID.IDS_FeatureObjectInitializer.CheckFeatureAvailability(diagnostics, initializerSyntax, initializerSyntax.OpenBraceToken.GetLocation());
+ MessageID.IDS_FeatureObjectInitializer.CheckFeatureAvailability(diagnostics, initializerSyntax.OpenBraceToken);
// We use a location specific binder for binding object initializer field/property access to generate object initializer specific diagnostics:
// 1) CS1914 (ERR_StaticMemberInObjectInitializer)
@@ -4972,8 +5031,7 @@ private BoundExpression BindObjectInitializerMember(
{
var implicitIndexing = (ImplicitElementAccessSyntax)leftSyntax;
- MessageID.IDS_FeatureDictionaryInitializer.CheckFeatureAvailability(
- diagnostics, implicitIndexing, implicitIndexing.ArgumentList.OpenBracketToken.GetLocation());
+ MessageID.IDS_FeatureDictionaryInitializer.CheckFeatureAvailability(diagnostics, implicitIndexing.ArgumentList.OpenBracketToken);
boundMember = BindElementAccess(implicitIndexing, implicitReceiver, implicitIndexing.ArgumentList, diagnostics);
@@ -5323,7 +5381,7 @@ private BoundCollectionInitializerExpression BindCollectionInitializerExpression
Debug.Assert(initializerSyntax.Expressions.Any());
Debug.Assert((object)initializerType != null);
- MessageID.IDS_FeatureCollectionInitializer.CheckFeatureAvailability(diagnostics, initializerSyntax, initializerSyntax.OpenBraceToken.GetLocation());
+ MessageID.IDS_FeatureCollectionInitializer.CheckFeatureAvailability(diagnostics, initializerSyntax.OpenBraceToken);
var initializerBuilder = ArrayBuilder.GetInstance();
@@ -6265,7 +6323,7 @@ private BoundLiteral BindLiteralConstant(LiteralExpressionSyntax node, BindingDi
if (node.Token.Kind() is SyntaxKind.SingleLineRawStringLiteralToken or SyntaxKind.MultiLineRawStringLiteralToken)
{
- MessageID.IDS_FeatureRawStringLiterals.CheckFeatureAvailability(diagnostics, node, node.Location);
+ MessageID.IDS_FeatureRawStringLiterals.CheckFeatureAvailability(diagnostics, node);
}
return new BoundLiteral(node, cv, type);
@@ -7715,10 +7773,17 @@ private bool CheckInstanceOrStatic(
{
if (instanceReceiver == true)
{
- ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ?
- ErrorCode.ERR_StaticMemberInObjectInitializer :
- ErrorCode.ERR_ObjectProhibited;
- Error(diagnostics, errorCode, node, symbol);
+ if (!IsInsideNameof)
+ {
+ ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ?
+ ErrorCode.ERR_StaticMemberInObjectInitializer :
+ ErrorCode.ERR_ObjectProhibited;
+ Error(diagnostics, errorCode, node, symbol);
+ }
+ else if (CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics))
+ {
+ return false;
+ }
resultKind = LookupResultKind.StaticInstanceMismatch;
return true;
}
@@ -9335,7 +9400,7 @@ internal static bool ReportDelegateInvokeUseSiteDiagnostic(BindingDiagnosticBag
private BoundConditionalAccess BindConditionalAccessExpression(ConditionalAccessExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureNullPropagatingOperator.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureNullPropagatingOperator.CheckFeatureAvailability(diagnostics, node.OperatorToken);
BoundExpression receiver = BindConditionalAccessReceiver(node, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
index ba818cfaa8f9a..b48887917afb4 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
@@ -1109,7 +1109,7 @@ private BoundCall BindInvocationExpressionContinued(
bool hasBaseReceiver = receiver != null && receiver.Kind == BoundKind.BaseReference;
ReportDiagnosticsIfObsolete(diagnostics, method, node, hasBaseReceiver);
- ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, method, node.Location, isDelegateConversion: false);
+ ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, method, node, isDelegateConversion: false);
// No use site errors, but there could be use site warnings.
// If there are any use site warnings, they have already been reported by overload resolution.
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
index 5f818e6af0cb7..ed1cbf9c8f28f 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lambda.cs
@@ -56,7 +56,7 @@ private UnboundLambda AnalyzeAnonymousFunction(
if (syntax is LambdaExpressionSyntax lambdaSyntax)
{
- MessageID.IDS_FeatureLambda.CheckFeatureAvailability(diagnostics, syntax, lambdaSyntax.ArrowToken.GetLocation());
+ MessageID.IDS_FeatureLambda.CheckFeatureAvailability(diagnostics, lambdaSyntax.ArrowToken);
checkAttributes(syntax, lambdaSyntax.AttributeLists, diagnostics);
}
@@ -86,7 +86,7 @@ private UnboundLambda AnalyzeAnonymousFunction(
// delegate (int x) { }
// delegate { }
var anon = (AnonymousMethodExpressionSyntax)syntax;
- MessageID.IDS_FeatureAnonDelegates.CheckFeatureAvailability(diagnostics, anon, anon.DelegateKeyword.GetLocation());
+ MessageID.IDS_FeatureAnonDelegates.CheckFeatureAvailability(diagnostics, anon.DelegateKeyword);
hasSignature = anon.ParameterList != null;
if (hasSignature)
@@ -105,12 +105,12 @@ private UnboundLambda AnalyzeAnonymousFunction(
{
if (modifier.IsKind(SyntaxKind.AsyncKeyword))
{
- MessageID.IDS_FeatureAsync.CheckFeatureAvailability(diagnostics, syntax, modifier.GetLocation());
+ MessageID.IDS_FeatureAsync.CheckFeatureAvailability(diagnostics, modifier);
isAsync = true;
}
else if (modifier.IsKind(SyntaxKind.StaticKeyword))
{
- MessageID.IDS_FeatureStaticAnonymousFunction.CheckFeatureAvailability(diagnostics, syntax, modifier.GetLocation());
+ MessageID.IDS_FeatureStaticAnonymousFunction.CheckFeatureAvailability(diagnostics, modifier);
isStatic = true;
}
}
@@ -155,7 +155,7 @@ private UnboundLambda AnalyzeAnonymousFunction(
}
else
{
- MessageID.IDS_FeatureLambdaOptionalParameters.CheckFeatureAvailability(diagnostics, syntax, p.Default.EqualsToken.GetLocation());
+ MessageID.IDS_FeatureLambdaOptionalParameters.CheckFeatureAvailability(diagnostics, p.Default.EqualsToken);
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
index 6463199811307..d3cbe2574fbca 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Lookup.cs
@@ -1304,7 +1304,7 @@ internal static ImmutableArray GetCandidateMembers(NamespaceOrTypeSymbol
{
return ImmutableArray.Empty;
}
- else if (nsOrType is SourceMemberContainerTypeSymbol { PrimaryConstructor: not null } sourceMemberContainerTypeSymbol)
+ else if (nsOrType is SourceMemberContainerTypeSymbol { HasPrimaryConstructor: true } sourceMemberContainerTypeSymbol)
{
return sourceMemberContainerTypeSymbol.GetCandidateMembersForLookup(name);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
index 1ac2909d7eec8..0653d993db96e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
@@ -2407,7 +2407,7 @@ private bool CheckConstraintLanguageVersionAndRuntimeSupportForOperator(SyntaxNo
private BoundExpression BindSuppressNullableWarningExpression(PostfixUnaryExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureNullableReferenceTypes.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureNullableReferenceTypes.CheckFeatureAvailability(diagnostics, node.OperatorToken);
var expr = BindExpression(node.Operand, diagnostics);
switch (expr.Kind)
@@ -4089,7 +4089,7 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node,
private BoundExpression BindNullCoalescingAssignmentOperator(AssignmentExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureCoalesceAssignmentExpression.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureCoalesceAssignmentExpression.CheckFeatureAvailability(diagnostics, node.OperatorToken);
BoundExpression leftOperand = BindValue(node.Left, diagnostics, BindValueKind.CompoundAssignment);
ReportSuppressionIfNeeded(leftOperand, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
index 9ffff3ffe995a..2e6332492a73e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
@@ -17,7 +17,7 @@ partial class Binder
{
private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node, node.IsKeyword.GetLocation());
+ MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node.IsKeyword);
BoundExpression expression = BindRValueWithoutTargetType(node.Expression, diagnostics);
bool hasErrors = IsOperandErrors(node, ref expression, diagnostics);
@@ -144,7 +144,7 @@ private BoundExpression BindSwitchExpression(SwitchExpressionSyntax node, Bindin
{
RoslynDebug.Assert(node is not null);
- MessageID.IDS_FeatureRecursivePatterns.CheckFeatureAvailability(diagnostics, node, node.SwitchKeyword.GetLocation());
+ MessageID.IDS_FeatureRecursivePatterns.CheckFeatureAvailability(diagnostics, node.SwitchKeyword);
Binder? switchBinder = this.GetBinder(node);
RoslynDebug.Assert(switchBinder is { });
@@ -194,7 +194,7 @@ private BoundPattern BindParenthesizedPattern(
BindingDiagnosticBag diagnostics,
bool underIsPattern)
{
- MessageID.IDS_FeatureParenthesizedPattern.CheckFeatureAvailability(diagnostics, node, node.OpenParenToken.GetLocation());
+ MessageID.IDS_FeatureParenthesizedPattern.CheckFeatureAvailability(diagnostics, node.OpenParenToken);
return BindPattern(node.Pattern, inputType, permitDesignations, hasErrors, diagnostics, underIsPattern);
}
@@ -1088,7 +1088,7 @@ deconstructMethod is null &&
}
else if (subPattern.ExpressionColon != null)
{
- MessageID.IDS_FeatureExtendedPropertyPatterns.CheckFeatureAvailability(diagnostics, subPattern, subPattern.ExpressionColon.ColonToken.GetLocation());
+ MessageID.IDS_FeatureExtendedPropertyPatterns.CheckFeatureAvailability(diagnostics, subPattern.ExpressionColon.ColonToken);
diagnostics.Add(ErrorCode.ERR_IdentifierExpected, subPattern.ExpressionColon.Expression.Location);
}
@@ -1466,7 +1466,7 @@ private ImmutableArray BindPropertyPatternClause(
foreach (SubpatternSyntax p in node.Subpatterns)
{
if (p.ExpressionColon is ExpressionColonSyntax)
- MessageID.IDS_FeatureExtendedPropertyPatterns.CheckFeatureAvailability(diagnostics, p, p.ExpressionColon.ColonToken.GetLocation());
+ MessageID.IDS_FeatureExtendedPropertyPatterns.CheckFeatureAvailability(diagnostics, p.ExpressionColon.ColonToken);
ExpressionSyntax? expr = p.ExpressionColon?.Expression;
PatternSyntax pattern = p.Pattern;
@@ -1626,7 +1626,7 @@ private BoundPattern BindRelationalPattern(
bool hasErrors,
BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureRelationalPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureRelationalPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken);
BoundExpression value = BindExpressionForPattern(inputType, node.Expression, ref hasErrors, diagnostics, out var constantValueOpt, out _, out Conversion patternConversion);
ExpressionSyntax innerExpression = SkipParensAndNullSuppressions(node.Expression, diagnostics, ref hasErrors);
@@ -1719,7 +1719,7 @@ private BoundPattern BindUnaryPattern(
BindingDiagnosticBag diagnostics,
bool underIsPattern)
{
- MessageID.IDS_FeatureNotPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureNotPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken);
bool permitDesignations = underIsPattern; // prevent designators under 'not' except under an is-pattern
var subPattern = BindPattern(node.Pattern, inputType, permitDesignations, hasErrors, diagnostics, underIsPattern);
@@ -1736,7 +1736,7 @@ private BoundPattern BindBinaryPattern(
bool isDisjunction = node.Kind() == SyntaxKind.OrPattern;
if (isDisjunction)
{
- MessageID.IDS_FeatureOrPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureOrPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken);
permitDesignations = false; // prevent designators under 'or'
var left = BindPattern(node.Left, inputType, permitDesignations, hasErrors, diagnostics);
@@ -1821,7 +1821,7 @@ static void collectCandidates(BoundPattern pat, ArrayBuilder candida
}
else
{
- MessageID.IDS_FeatureAndPattern.CheckFeatureAvailability(diagnostics, node, node.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureAndPattern.CheckFeatureAvailability(diagnostics, node.OperatorToken);
var left = BindPattern(node.Left, inputType, permitDesignations, hasErrors, diagnostics);
var right = BindPattern(node.Right, left.NarrowedType, permitDesignations, hasErrors, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
index be3bac2451952..8cb074eb80fd3 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Query.cs
@@ -23,7 +23,7 @@ internal partial class Binder
internal BoundExpression BindQuery(QueryExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureQueryExpression.CheckFeatureAvailability(diagnostics, node, node.FromClause.FromKeyword.GetLocation());
+ MessageID.IDS_FeatureQueryExpression.CheckFeatureAvailability(diagnostics, node.FromClause.FromKeyword);
var fromClause = node.FromClause;
var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
index 0c8f9d6d6b53f..ddc29ce3202bb 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
@@ -215,7 +215,7 @@ private BoundStatement BindFixedStatementParts(FixedStatementSyntax node, Bindin
private void CheckRequiredLangVersionForIteratorMethods(YieldStatementSyntax statement, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureIterators.CheckFeatureAvailability(diagnostics, statement, statement.YieldKeyword.GetLocation());
+ MessageID.IDS_FeatureIterators.CheckFeatureAvailability(diagnostics, statement.YieldKeyword);
var method = (MethodSymbol)this.ContainingMemberOrLambda;
if (method.IsAsync)
@@ -550,7 +550,7 @@ private BoundStatement BindGoto(GotoStatementSyntax node, BindingDiagnosticBag d
private BoundStatement BindLocalFunctionStatement(LocalFunctionStatementSyntax node, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureLocalFunctions.CheckFeatureAvailability(diagnostics, node, node.Identifier.GetLocation());
+ MessageID.IDS_FeatureLocalFunctions.CheckFeatureAvailability(diagnostics, node.Identifier);
// already defined symbol in containing block
var localSymbol = this.LookupLocalFunction(node.Identifier);
@@ -595,9 +595,9 @@ private BoundStatement BindLocalFunctionStatement(LocalFunctionStatementSyntax n
foreach (var modifier in node.Modifiers)
{
if (modifier.IsKind(SyntaxKind.StaticKeyword))
- MessageID.IDS_FeatureStaticLocalFunctions.CheckFeatureAvailability(diagnostics, node, modifier.GetLocation());
+ MessageID.IDS_FeatureStaticLocalFunctions.CheckFeatureAvailability(diagnostics, modifier);
else if (modifier.IsKind(SyntaxKind.ExternKeyword))
- MessageID.IDS_FeatureExternLocalFunctions.CheckFeatureAvailability(diagnostics, node, modifier.GetLocation());
+ MessageID.IDS_FeatureExternLocalFunctions.CheckFeatureAvailability(diagnostics, modifier);
}
return new BoundLocalFunctionStatement(node, localSymbol, blockBody, expressionBody, hasErrors);
@@ -1426,7 +1426,7 @@ private BoundExpression BindAssignment(AssignmentExpressionSyntax node, BindingD
var lhsKind = isRef ? BindValueKind.RefAssignable : BindValueKind.Assignable;
if (isRef)
- MessageID.IDS_FeatureRefReassignment.CheckFeatureAvailability(diagnostics, node.Right, node.Right.GetFirstToken().GetLocation());
+ MessageID.IDS_FeatureRefReassignment.CheckFeatureAvailability(diagnostics, node.Right.GetFirstToken());
var op1 = BindValue(node.Left, diagnostics, lhsKind);
ReportSuppressionIfNeeded(op1, diagnostics);
@@ -3247,7 +3247,7 @@ private BoundCatchBlock BindCatchBlock(CatchClauseSyntax node, ArrayBuilder throw ExceptionUtilities.UnexpectedValue(expressionBody.Parent.Kind()),
};
- messageId?.CheckFeatureAvailability(diagnostics, expressionBody, expressionBody.ArrowToken.GetLocation());
+ messageId?.CheckFeatureAvailability(diagnostics, expressionBody.ArrowToken);
Binder bodyBinder = this.GetBinder(expressionBody);
Debug.Assert(bodyBinder != null);
@@ -3652,7 +3652,7 @@ private BoundNode BindConstructorBody(ConstructorDeclarationSyntax constructor,
constructor.Body == null ? diagnostics : BindingDiagnosticBag.Discarded));
bool hasPrimaryConstructor() =>
- ContainingType is SourceMemberContainerTypeSymbol { PrimaryConstructor: not null };
+ ContainingType is SourceMemberContainerTypeSymbol { HasPrimaryConstructor: true };
bool isInstanceConstructor(out MethodSymbol constructorSymbol)
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
index fb06a4e052467..8f668fc7684e4 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
@@ -444,7 +444,7 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS
case SyntaxKind.FunctionPointerType:
var functionPointerTypeSyntax = (FunctionPointerTypeSyntax)syntax;
- MessageID.IDS_FeatureFunctionPointers.CheckFeatureAvailability(diagnostics, syntax, functionPointerTypeSyntax.DelegateKeyword.GetLocation());
+ MessageID.IDS_FeatureFunctionPointers.CheckFeatureAvailability(diagnostics, functionPointerTypeSyntax.DelegateKeyword);
if (GetUnsafeDiagnosticInfo(sizeOfTypeOpt: null) is CSDiagnosticInfo info)
{
@@ -535,7 +535,7 @@ void reportNullableReferenceTypesIfNeeded(SyntaxToken questionToken, TypeWithAnn
NamespaceOrTypeOrAliasSymbolWithAnnotations bindNullable()
{
var nullableSyntax = (NullableTypeSyntax)syntax;
- MessageID.IDS_FeatureNullable.CheckFeatureAvailability(diagnostics, nullableSyntax, nullableSyntax.QuestionToken.GetLocation());
+ MessageID.IDS_FeatureNullable.CheckFeatureAvailability(diagnostics, nullableSyntax.QuestionToken);
TypeSyntax typeArgumentSyntax = nullableSyntax.ElementType;
TypeWithAnnotations typeArgument = BindType(typeArgumentSyntax, diagnostics, basesBeingResolved);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_WithExpression.cs b/src/Compilers/CSharp/Portable/Binder/Binder_WithExpression.cs
index 9bb42e8b61beb..1ff2935f76237 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_WithExpression.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_WithExpression.cs
@@ -14,7 +14,7 @@ internal partial class Binder
{
private BoundExpression BindWithExpression(WithExpressionSyntax syntax, BindingDiagnosticBag diagnostics)
{
- MessageID.IDS_FeatureRecords.CheckFeatureAvailability(diagnostics, syntax, syntax.WithKeyword.GetLocation());
+ MessageID.IDS_FeatureRecords.CheckFeatureAvailability(diagnostics, syntax.WithKeyword);
var receiver = BindRValueWithoutTargetType(syntax.Expression, diagnostics);
var receiverType = receiver.Type;
diff --git a/src/Compilers/CSharp/Portable/Binder/BindingDiagnosticBag.cs b/src/Compilers/CSharp/Portable/Binder/BindingDiagnosticBag.cs
index b1aab32456052..d69391916db66 100644
--- a/src/Compilers/CSharp/Portable/Binder/BindingDiagnosticBag.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BindingDiagnosticBag.cs
@@ -160,6 +160,12 @@ internal CSDiagnosticInfo Add(ErrorCode code, Location location)
return info;
}
+ internal CSDiagnosticInfo Add(ErrorCode code, SyntaxNode syntax, params object[] args)
+ => Add(code, syntax.Location, args);
+
+ internal CSDiagnosticInfo Add(ErrorCode code, SyntaxToken syntax, params object[] args)
+ => Add(code, syntax.GetLocation()!, args);
+
internal CSDiagnosticInfo Add(ErrorCode code, Location location, params object[] args)
{
var info = new CSDiagnosticInfo(code, args);
diff --git a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
index 4a7f3b64ae7a4..a3e4566b820a9 100644
--- a/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/DecisionDagBuilder.cs
@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
@@ -38,7 +39,7 @@ namespace Microsoft.CodeAnalysis.CSharp
///
///
/// In order to build this automaton, we start (in
- ///
+ ///
/// by computing a description of the initial state in a , and then
/// for each such state description we decide what the test or evaluation will be at
/// that state, and compute the successor state descriptions.
@@ -132,7 +133,11 @@ private BoundDecisionDag CreateDecisionDagForIsPattern(
LabelSymbol whenTrueLabel)
{
var rootIdentifier = BoundDagTemp.ForOriginalInput(inputExpression);
- return MakeBoundDecisionDag(syntax, ImmutableArray.Create(MakeTestsForPattern(index: 1, pattern.Syntax, rootIdentifier, pattern, whenClause: null, whenTrueLabel)));
+ var builder = ArrayBuilder.GetInstance(1);
+ builder.Add(MakeTestsForPattern(index: 1, pattern.Syntax, rootIdentifier, pattern, whenClause: null, whenTrueLabel));
+ var result = MakeBoundDecisionDag(syntax, builder);
+ builder.Free();
+ return result;
}
private BoundDecisionDag CreateDecisionDagForSwitchStatement(
@@ -154,7 +159,9 @@ private BoundDecisionDag CreateDecisionDagForSwitchStatement(
}
}
- return MakeBoundDecisionDag(syntax, builder.ToImmutableAndFree());
+ var result = MakeBoundDecisionDag(syntax, builder);
+ builder.Free();
+ return result;
}
///
@@ -171,7 +178,9 @@ private BoundDecisionDag CreateDecisionDagForSwitchExpression(
foreach (BoundSwitchExpressionArm arm in switchArms)
builder.Add(MakeTestsForPattern(++i, arm.Syntax, rootIdentifier, arm.Pattern, arm.WhenClause, arm.Label));
- return MakeBoundDecisionDag(syntax, builder.ToImmutableAndFree());
+ var result = MakeBoundDecisionDag(syntax, builder);
+ builder.Free();
+ return result;
}
///
@@ -704,10 +713,15 @@ private TypeSymbol ErrorType(string name = "")
/// decision when no decision appears to match. This implementation is nonrecursive to avoid
/// overflowing the compiler's evaluation stack when compiling a large switch statement.
///
- private BoundDecisionDag MakeBoundDecisionDag(SyntaxNode syntax, ImmutableArray cases)
+ private BoundDecisionDag MakeBoundDecisionDag(SyntaxNode syntax, ArrayBuilder cases)
{
+ // A work list of DagStates whose successors need to be computed
+ var workList = ArrayBuilder.GetInstance();
+
// Build the state machine underlying the decision dag
- DecisionDag decisionDag = MakeDecisionDag(cases);
+ DecisionDag decisionDag = MakeDecisionDag(cases, workList);
+
+ workList.Free();
// Note: It is useful for debugging the dag state table construction to set a breakpoint
// here and view `decisionDag.Dump()`.
@@ -767,11 +781,10 @@ int tempIdentifier(BoundDagEvaluation e)
/// Make a (state machine) starting with the given set of cases in the root node,
/// and return the node for the root.
///
- private DecisionDag MakeDecisionDag(ImmutableArray casesForRootNode)
+ private DecisionDag MakeDecisionDag(
+ ArrayBuilder casesForRootNode,
+ ArrayBuilder workList)
{
- // A work list of DagStates whose successors need to be computed
- var workList = ArrayBuilder.GetInstance();
-
// A mapping used to make each DagState unique (i.e. to de-dup identical states).
var uniqueState = new Dictionary(DagStateEquivalence.Instance);
@@ -781,7 +794,7 @@ private DecisionDag MakeDecisionDag(ImmutableArray casesForRootNod
// so that it is processed only once. This object identity uniqueness will be important later when we
// start mutating the DagState nodes to compute successors and BoundDecisionDagNodes
// for each one. That is why we have to use an equivalence relation in the dictionary `uniqueState`.
- DagState uniqifyState(ImmutableArray cases, ImmutableDictionary remainingValues)
+ DagState uniquifyState(ImmutableArray cases, ImmutableDictionary remainingValues)
{
var state = new DagState(cases, remainingValues);
if (uniqueState.TryGetValue(state, out DagState? existingState))
@@ -821,7 +834,7 @@ DagState uniqifyState(ImmutableArray cases, ImmutableDictionary.GetInstance(casesForRootNode.Length);
+ var rewrittenCases = ArrayBuilder.GetInstance(casesForRootNode.Count);
foreach (var state in casesForRootNode)
{
var rewrittenCase = state.RewriteNestedLengthTests();
@@ -832,7 +845,7 @@ DagState uniqifyState(ImmutableArray cases, ImmutableDictionary.Empty);
+ var initialState = uniquifyState(rewrittenCases.ToImmutableAndFree(), ImmutableDictionary.Empty);
// Go through the worklist of DagState nodes for which we have not yet computed
// successor states.
@@ -867,7 +880,7 @@ DagState uniqifyState(ImmutableArray cases, ImmutableDictionary cases, ImmutableDictionary cases, ImmutableDictionary whenTrueValues,
out ImmutableDictionary whenFalseValues,
ref foundExplicitNullTest);
- state.TrueBranch = uniqifyState(whenTrueDecisions, whenTrueValues);
- state.FalseBranch = uniqifyState(whenFalseDecisions, whenFalseValues);
+ state.TrueBranch = uniquifyState(whenTrueDecisions, whenTrueValues);
+ state.FalseBranch = uniquifyState(whenFalseDecisions, whenFalseValues);
if (foundExplicitNullTest && d is BoundDagNonNullTest { IsExplicitTest: false } t)
{
// Turn an "implicit" non-null test into an explicit one
@@ -914,7 +927,6 @@ DagState uniqifyState(ImmutableArray cases, ImmutableDictionary
/// A successor function used to topologically sort the DagState set.
///
- private static ImmutableArray Successor(DagState state)
+ private static void AddSuccessor(ref TemporaryArray builder, DagState state)
{
- if (state.TrueBranch != null && state.FalseBranch != null)
- {
- return ImmutableArray.Create(state.FalseBranch, state.TrueBranch);
- }
- else if (state.TrueBranch != null)
- {
- return ImmutableArray.Create(state.TrueBranch);
- }
- else if (state.FalseBranch != null)
- {
- return ImmutableArray.Create(state.FalseBranch);
- }
- else
- {
- return ImmutableArray.Empty;
- }
+ builder.AddIfNotNull(state.TrueBranch);
+ builder.AddIfNotNull(state.FalseBranch);
}
///
@@ -1602,7 +1600,7 @@ private static ImmutableArray Successor(DagState state)
/// True if the graph was acyclic.
public bool TryGetTopologicallySortedReachableStates(out ImmutableArray result)
{
- return TopologicalSort.TryIterativeSort(SpecializedCollections.SingletonEnumerable(this.RootNode), Successor, out result);
+ return TopologicalSort.TryIterativeSort(this.RootNode, AddSuccessor, out result);
}
#if DEBUG
@@ -1808,7 +1806,7 @@ public bool Equals(DagState? x, DagState? y)
{
RoslynDebug.Assert(x is { });
RoslynDebug.Assert(y is { });
- return x == y || x.Cases.SequenceEqual(y.Cases, (a, b) => a.Equals(b));
+ return x == y || x.Cases.SequenceEqual(y.Cases, static (a, b) => a.Equals(b));
}
public int GetHashCode(DagState x)
@@ -1821,7 +1819,7 @@ public int GetHashCode(DagState x)
/// As part of the description of a node of the decision automaton, we keep track of what tests
/// remain to be done for each case.
///
- private sealed class StateForCase
+ private readonly struct StateForCase
{
///
/// A number that is distinct for each case and monotonically increasing from earlier to later cases.
@@ -1875,9 +1873,7 @@ public bool Equals(StateForCase other)
{
// We do not include Syntax, Bindings, WhereClause, or CaseLabel
// because once the Index is the same, those must be the same too.
- return this == other ||
- other != null &&
- this.Index == other.Index &&
+ return this.Index == other.Index &&
this.RemainingTests.Equals(other.RemainingTests);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
index ecb5ea0a48ea8..3b02eec015aab 100644
--- a/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ExpressionVariableFinder.cs
@@ -649,7 +649,7 @@ protected override Symbol MakePatternVariable(TypeSyntax type, SingleVariableDes
{
return designation == null ? null : GlobalExpressionVariable.Create(
_containingType, _modifiers, type,
- designation.Identifier.ValueText, designation, designation.GetLocation(),
+ designation.Identifier.ValueText, designation, designation.Span,
_containingFieldOpt, nodeToBind);
}
@@ -657,7 +657,7 @@ protected override Symbol MakeDeclarationExpressionVariable(DeclarationExpressio
{
return GlobalExpressionVariable.Create(
_containingType, _modifiers, node.Type,
- designation.Identifier.ValueText, designation, designation.Identifier.GetLocation(),
+ designation.Identifier.ValueText, designation, designation.Identifier.Span,
_containingFieldOpt, nodeToBind);
}
@@ -672,7 +672,7 @@ protected override Symbol MakeDeconstructionVariable(
typeSyntax: closestTypeSyntax,
name: designation.Identifier.ValueText,
syntax: designation,
- location: designation.Location,
+ locationSpan: designation.Span,
containingFieldOpt: null,
nodeToBind: deconstruction);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
index ef254301c1296..6c22b41537c6f 100644
--- a/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
@@ -432,7 +432,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno
var foreachKeyword = _syntax.ForEachKeyword;
ReportDiagnosticsIfObsolete(diagnostics, getEnumeratorMethod, foreachKeyword, hasBaseReceiver: false);
- ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, getEnumeratorMethod, foreachKeyword.GetLocation(), isDelegateConversion: false);
+ ReportDiagnosticsIfUnmanagedCallersOnly(diagnostics, getEnumeratorMethod, foreachKeyword, isDelegateConversion: false);
// MoveNext is an instance method, so it does not need to have unmanaged callers only diagnostics reported.
// Either a diagnostic was reported at the declaration of the method (for the invalid attribute), or MoveNext
// is marked as not supported and we won't get here in the first place (for metadata import).
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
index 1592f2bac88c3..6f62adbf611d9 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
@@ -25,6 +25,13 @@ namespace Microsoft.CodeAnalysis.CSharp
// in uncommon cases an instance of this class is attached to the conversion.
private class UncommonData
{
+ public static readonly UncommonData NoApplicableOperators = new UncommonData(
+ isExtensionMethod: false,
+ isArrayIndex: false,
+ conversionResult: UserDefinedConversionResult.NoApplicableOperators(ImmutableArray.Empty),
+ conversionMethod: null,
+ nestedConversions: default);
+
public UncommonData(
bool isExtensionMethod,
bool isArrayIndex,
@@ -107,12 +114,14 @@ internal Conversion(UserDefinedConversionResult conversionResult, bool isImplici
? ConversionKind.NoConversion
: isImplicit ? ConversionKind.ImplicitUserDefined : ConversionKind.ExplicitUserDefined;
- _uncommonData = new UncommonData(
- isExtensionMethod: false,
- isArrayIndex: false,
- conversionResult: conversionResult,
- conversionMethod: null,
- nestedConversions: default);
+ _uncommonData = conversionResult.Kind == UserDefinedConversionResultKind.NoApplicableOperators && conversionResult.Results.IsEmpty
+ ? UncommonData.NoApplicableOperators
+ : new UncommonData(
+ isExtensionMethod: false,
+ isArrayIndex: false,
+ conversionResult: conversionResult,
+ conversionMethod: null,
+ nestedConversions: default);
}
// For the method group, lambda and anonymous method conversions
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs
index b8599bddf7e3f..e5aba45435135 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/BinaryOperatorOverloadResolution.cs
@@ -475,9 +475,8 @@ private void GetEnumOperation(BinaryOperatorKind kind, TypeSymbol enumType, Boun
Debug.Assert((object)underlying != null);
Debug.Assert(underlying.SpecialType != SpecialType.None);
- var nullable = Compilation.GetSpecialType(SpecialType.System_Nullable_T);
- var nullableEnum = nullable.Construct(enumType);
- var nullableUnderlying = nullable.Construct(underlying);
+ var nullableEnum = MakeNullable(enumType);
+ var nullableUnderlying = MakeNullable(underlying);
switch (kind)
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/UnaryOperatorOverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/UnaryOperatorOverloadResolution.cs
index f849ec6edd41b..4c6c2656b402f 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/UnaryOperatorOverloadResolution.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Operators/UnaryOperatorOverloadResolution.cs
@@ -17,7 +17,7 @@ internal sealed partial class OverloadResolution
{
private NamedTypeSymbol MakeNullable(TypeSymbol type)
{
- return Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(type);
+ return Compilation.GetOrCreateNullableType(type);
}
public void UnaryOperatorOverloadResolution(UnaryOperatorKind kind, bool isChecked, BoundExpression operand, UnaryOperatorOverloadResolutionResult result, ref CompoundUseSiteInfo useSiteInfo)
diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs
index a70f367e3446b..3dcf824ff86db 100644
--- a/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs
+++ b/src/Compilers/CSharp/Portable/Binder/SwitchBinder_Patterns.cs
@@ -267,7 +267,7 @@ private BoundSwitchLabel BindSwitchSectionLabel(
{
var matchLabelSyntax = (CasePatternSwitchLabelSyntax)node;
- MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node, node.Keyword.GetLocation());
+ MessageID.IDS_FeaturePatternMatching.CheckFeatureAvailability(diagnostics, node.Keyword);
BoundPattern pattern = sectionBinder.BindPattern(
matchLabelSyntax.Pattern, SwitchGoverningType, permitDesignations: true, node.HasErrors, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs
index 463109a589e10..73ff46d298ef9 100644
--- a/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/SwitchExpressionBinder.cs
@@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
@@ -84,7 +85,7 @@ private bool CheckSwitchExpressionExhaustive(
// We only report exhaustive warnings when the default label is reachable through some series of
// tests that do not include a test in which the value is known to be null. Handling paths with
// nulls is the job of the nullable walker.
- bool wasAcyclic = TopologicalSort.TryIterativeSort(SpecializedCollections.SingletonEnumerable(decisionDag.RootNode), nonNullSuccessors, out var nodes);
+ bool wasAcyclic = TopologicalSort.TryIterativeSort(decisionDag.RootNode, addNonNullSuccessors, out var nodes);
// Since decisionDag.RootNode is acyclic by construction, its subset of nodes sorted here cannot be cyclic
Debug.Assert(wasAcyclic);
foreach (var n in nodes)
@@ -107,7 +108,7 @@ private bool CheckSwitchExpressionExhaustive(
return false;
- ImmutableArray nonNullSuccessors(BoundDecisionDagNode n)
+ static void addNonNullSuccessors(ref TemporaryArray builder, BoundDecisionDagNode n)
{
switch (n)
{
@@ -115,14 +116,18 @@ ImmutableArray nonNullSuccessors(BoundDecisionDagNode n)
switch (p.Test)
{
case BoundDagNonNullTest t: // checks that the input is not null
- return ImmutableArray.Create(p.WhenTrue);
+ builder.Add(p.WhenTrue);
+ return;
case BoundDagExplicitNullTest t: // checks that the input is null
- return ImmutableArray.Create(p.WhenFalse);
+ builder.Add(p.WhenFalse);
+ return;
default:
- return BoundDecisionDag.Successors(n);
+ BoundDecisionDag.AddSuccessors(ref builder, n);
+ return;
}
default:
- return BoundDecisionDag.Successors(n);
+ BoundDecisionDag.AddSuccessors(ref builder, n);
+ return;
}
}
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
index eec713ae6fbbc..1deac891fe1d9 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundDecisionDag.cs
@@ -11,6 +11,7 @@
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
@@ -20,18 +21,23 @@ internal partial class BoundDecisionDag
private ImmutableHashSet _reachableLabels;
private ImmutableArray _topologicallySortedNodes;
- internal static ImmutableArray Successors(BoundDecisionDagNode node)
+ internal static void AddSuccessors(ref TemporaryArray builder, BoundDecisionDagNode node)
{
switch (node)
{
case BoundEvaluationDecisionDagNode p:
- return ImmutableArray.Create(p.Next);
+ builder.Add(p.Next);
+ return;
case BoundTestDecisionDagNode p:
- return ImmutableArray.Create(p.WhenFalse, p.WhenTrue);
+ builder.Add(p.WhenFalse);
+ builder.Add(p.WhenTrue);
+ return;
case BoundLeafDecisionDagNode d:
- return ImmutableArray.Empty;
+ return;
case BoundWhenDecisionDagNode w:
- return (w.WhenFalse != null) ? ImmutableArray.Create(w.WhenTrue, w.WhenFalse) : ImmutableArray.Create(w.WhenTrue);
+ builder.Add(w.WhenTrue);
+ builder.AddIfNotNull(w.WhenFalse);
+ return;
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind);
}
@@ -69,7 +75,7 @@ public ImmutableArray TopologicallySortedNodes
if (_topologicallySortedNodes.IsDefault)
{
// We use an iterative topological sort to avoid overflowing the compiler's runtime stack for a large switch statement.
- bool wasAcyclic = TopologicalSort.TryIterativeSort(SpecializedCollections.SingletonEnumerable(this.RootNode), Successors, out _topologicallySortedNodes);
+ bool wasAcyclic = TopologicalSort.TryIterativeSort(this.RootNode, AddSuccessors, out _topologicallySortedNodes);
// Since these nodes were constructed by an isomorphic mapping from a known acyclic graph, it cannot be cyclic
Debug.Assert(wasAcyclic);
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index b36398e1d8b8e..d0db9d09556ab 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -5074,9 +5074,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Cannot return '{0}' by reference because it is a '{1}'
-
- Cannot return fields of '{0}' by reference because it is a '{1}'
-
A readonly field cannot be returned by writable reference
@@ -6817,6 +6814,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Parameter is unread. Did you forget to use it to initialize the property with that name?
+
+ instance member in 'nameof'
+
The primary constructor conflicts with the synthesized copy constructor.
@@ -7508,4 +7508,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
A constant value of type '{0}' is expected
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
\ No newline at end of file
diff --git a/src/Compilers/CSharp/Portable/Compilation/BuiltInOperators.cs b/src/Compilers/CSharp/Portable/Compilation/BuiltInOperators.cs
index 8b4d330e83a70..0cc6a7bffb1f9 100644
--- a/src/Compilers/CSharp/Portable/Compilation/BuiltInOperators.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/BuiltInOperators.cs
@@ -281,7 +281,7 @@ internal UnaryOperatorSignature GetSignature(UnaryOperatorKind kind)
if (kind.IsLifted())
{
- opType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(opType);
+ opType = _compilation.GetOrCreateNullableType(opType);
}
return new UnaryOperatorSignature(kind, opType, opType);
@@ -723,7 +723,7 @@ internal BinaryOperatorSignature GetSignature(BinaryOperatorKind kind)
TypeSymbol rightType = _compilation.GetSpecialType(SpecialType.System_Int32);
if (kind.IsLifted())
{
- rightType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(rightType);
+ rightType = _compilation.GetOrCreateNullableType(rightType);
}
return new BinaryOperatorSignature(kind, left, rightType, left);
@@ -837,23 +837,22 @@ private TypeSymbol LiftedType(BinaryOperatorKind kind)
{
Debug.Assert(kind.IsLifted());
- var nullable = _compilation.GetSpecialType(SpecialType.System_Nullable_T);
-
- switch (kind.OperandTypes())
+ var typeArgument = kind.OperandTypes() switch
{
- case BinaryOperatorKind.Int: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int32));
- case BinaryOperatorKind.UInt: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt32));
- case BinaryOperatorKind.Long: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Int64));
- case BinaryOperatorKind.ULong: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_UInt64));
- case BinaryOperatorKind.NInt: return nullable.Construct(_compilation.CreateNativeIntegerTypeSymbol(signed: true));
- case BinaryOperatorKind.NUInt: return nullable.Construct(_compilation.CreateNativeIntegerTypeSymbol(signed: false));
- case BinaryOperatorKind.Float: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Single));
- case BinaryOperatorKind.Double: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Double));
- case BinaryOperatorKind.Decimal: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Decimal));
- case BinaryOperatorKind.Bool: return nullable.Construct(_compilation.GetSpecialType(SpecialType.System_Boolean));
- }
- Debug.Assert(false, "Bad operator kind in lifted type");
- return null;
+ BinaryOperatorKind.Int => _compilation.GetSpecialType(SpecialType.System_Int32),
+ BinaryOperatorKind.UInt => _compilation.GetSpecialType(SpecialType.System_UInt32),
+ BinaryOperatorKind.Long => _compilation.GetSpecialType(SpecialType.System_Int64),
+ BinaryOperatorKind.ULong => _compilation.GetSpecialType(SpecialType.System_UInt64),
+ BinaryOperatorKind.NInt => _compilation.CreateNativeIntegerTypeSymbol(signed: true),
+ BinaryOperatorKind.NUInt => _compilation.CreateNativeIntegerTypeSymbol(signed: false),
+ BinaryOperatorKind.Float => _compilation.GetSpecialType(SpecialType.System_Single),
+ BinaryOperatorKind.Double => _compilation.GetSpecialType(SpecialType.System_Double),
+ BinaryOperatorKind.Decimal => _compilation.GetSpecialType(SpecialType.System_Decimal),
+ BinaryOperatorKind.Bool => _compilation.GetSpecialType(SpecialType.System_Boolean),
+ var v => throw ExceptionUtilities.UnexpectedValue(v),
+ };
+
+ return _compilation.GetOrCreateNullableType(typeArgument);
}
internal static bool IsValidObjectEquality(Conversions Conversions, TypeSymbol leftType, bool leftIsNull, bool leftIsDefault, TypeSymbol rightType, bool rightIsNull, bool rightIsDefault, ref CompoundUseSiteInfo useSiteInfo)
diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
index 078a52970ea02..d7eeb560d938f 100644
--- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
@@ -16,6 +16,7 @@
using Microsoft.Cci;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGen;
+using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -1565,6 +1566,18 @@ internal AliasSymbol GlobalNamespaceAlias
return result;
}
+ ///
+ /// Cache of T to Nullable<T>.
+ ///
+ private ImmutableSegmentedDictionary _typeToNullableVersion = ImmutableSegmentedDictionary.Empty;
+
+ internal NamedTypeSymbol GetOrCreateNullableType(TypeSymbol typeArgument)
+ => RoslynImmutableInterlocked.GetOrAdd(
+ ref _typeToNullableVersion,
+ typeArgument,
+ static (typeArgument, @this) => @this.GetSpecialType(SpecialType.System_Nullable_T).Construct(typeArgument),
+ this);
+
///
/// Get the symbol for the predefined type member from the COR Library referenced by this compilation.
///
@@ -4744,7 +4757,7 @@ protected override bool ShouldCheckTypeForMembers(MergedTypeDeclaration current)
{
foreach (SingleTypeDeclaration typeDecl in current.Declarations)
{
- if (typeDecl.MemberNames.ContainsKey(_name))
+ if (typeDecl.MemberNames.Contains(_name))
{
return true;
}
diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTable.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTable.cs
index a811203ee22bf..dd991cf527d7d 100644
--- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTable.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTable.cs
@@ -281,7 +281,7 @@ public static bool ContainsName(
mergedRoot,
n => n == name,
filter,
- t => t.MemberNames.ContainsKey(name),
+ t => t.MemberNames.Contains(name),
cancellationToken);
}
@@ -295,7 +295,7 @@ public static bool ContainsName(
mergedRoot, predicate, filter,
t =>
{
- foreach (var (name, _) in t.MemberNames)
+ foreach (var name in t.MemberNames)
{
if (predicate(name))
{
diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
index 083f88688a0f8..dcffaa303c257 100644
--- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
@@ -138,7 +138,7 @@ private ImmutableArray VisitNamespaceChildren(
return childrenBuilder.ToImmutableAndFree();
}
- private static SingleNamespaceOrTypeDeclaration CreateImplicitClass(ImmutableSegmentedDictionary memberNames, SyntaxReference container, SingleTypeDeclaration.TypeDeclarationFlags declFlags)
+ private static SingleNamespaceOrTypeDeclaration CreateImplicitClass(ImmutableSegmentedHashSet memberNames, SyntaxReference container, SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
return new SingleTypeDeclaration(
kind: DeclarationKind.ImplicitClass,
@@ -167,7 +167,7 @@ private static SingleNamespaceOrTypeDeclaration CreateSimpleProgram(GlobalStatem
SingleTypeDeclaration.TypeDeclarationFlags.IsSimpleProgram,
syntaxReference: firstGlobalStatement.SyntaxTree.GetReference(firstGlobalStatement.Parent),
nameLocation: new SourceLocation(firstGlobalStatement.GetFirstToken()),
- memberNames: ImmutableSegmentedDictionary.Empty,
+ memberNames: ImmutableSegmentedHashSet.Empty,
children: ImmutableArray.Empty,
diagnostics: diagnostics,
quickAttributes: QuickAttributes.None);
@@ -236,7 +236,7 @@ private static ImmutableArray GetReferenceDirectives(Compila
private SingleNamespaceOrTypeDeclaration CreateScriptClass(
CompilationUnitSyntax parent,
ImmutableArray children,
- ImmutableSegmentedDictionary memberNames,
+ ImmutableSegmentedHashSet memberNames,
SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
Debug.Assert(parent.Kind() == SyntaxKind.CompilationUnit && _syntaxTree.Options.Kind != SourceCodeKind.Regular);
@@ -613,8 +613,7 @@ private SingleNamespaceOrTypeDeclaration VisitTypeDeclaration(TypeDeclarationSyn
Symbol.ReportErrorIfHasConstraints(node.ConstraintClauses, diagnostics);
}
- // A type with parameters at least has a primary constructor
- var hasPrimaryCtor = node.ParameterList != null;
+ var hasPrimaryCtor = node.ParameterList != null && node is RecordDeclarationSyntax or ClassDeclarationSyntax or StructDeclarationSyntax;
if (hasPrimaryCtor)
{
declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasAnyNontypeMembers;
@@ -729,7 +728,7 @@ public override SingleNamespaceOrTypeDeclaration VisitDelegateDeclaration(Delega
declFlags: declFlags,
syntaxReference: _syntaxTree.GetReference(node),
nameLocation: new SourceLocation(node.Identifier),
- memberNames: ImmutableSegmentedDictionary.Empty,
+ memberNames: ImmutableSegmentedHashSet.Empty,
children: ImmutableArray.Empty,
diagnostics: diagnostics.ToReadOnlyAndFree(),
_nonGlobalAliasedQuickAttributes | quickAttributes);
@@ -748,7 +747,7 @@ public override SingleNamespaceOrTypeDeclaration VisitEnumDeclaration(EnumDeclar
declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasBaseDeclarations;
}
- ImmutableSegmentedDictionary memberNames = GetEnumMemberNames(members, ref declFlags);
+ ImmutableSegmentedHashSet memberNames = GetEnumMemberNames(members, ref declFlags);
var diagnostics = DiagnosticBag.GetInstance();
var modifiers = node.Modifiers.ToDeclarationModifiers(isForTypeDeclaration: true, diagnostics: diagnostics);
@@ -787,10 +786,10 @@ private static QuickAttributes GetQuickAttributes(SyntaxList.Builder> s_memberNameBuilderPool =
- new ObjectPool.Builder>(() => ImmutableSegmentedDictionary.CreateBuilder());
+ private static readonly ObjectPool.Builder> s_memberNameBuilderPool =
+ new ObjectPool.Builder>(() => ImmutableSegmentedHashSet.CreateBuilder());
- private static ImmutableSegmentedDictionary ToImmutableAndFree(ImmutableSegmentedDictionary.Builder builder)
+ private static ImmutableSegmentedHashSet ToImmutableAndFree(ImmutableSegmentedHashSet.Builder builder)
{
var result = builder.ToImmutable();
builder.Clear();
@@ -798,7 +797,7 @@ private static ImmutableSegmentedDictionary ToImmutableAndFr
return result;
}
- private static ImmutableSegmentedDictionary GetEnumMemberNames(SeparatedSyntaxList members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags)
+ private static ImmutableSegmentedHashSet GetEnumMemberNames(SeparatedSyntaxList members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags)
{
var cnt = members.Count;
@@ -811,7 +810,7 @@ private static ImmutableSegmentedDictionary GetEnumMemberNam
bool anyMemberHasAttributes = false;
foreach (var member in members)
{
- memberNamesBuilder.TryAdd(member.Identifier.ValueText);
+ memberNamesBuilder.Add(member.Identifier.ValueText);
if (!anyMemberHasAttributes && member.AttributeLists.Any())
{
anyMemberHasAttributes = true;
@@ -826,7 +825,7 @@ private static ImmutableSegmentedDictionary GetEnumMemberNam
return ToImmutableAndFree(memberNamesBuilder);
}
- private static ImmutableSegmentedDictionary GetNonTypeMemberNames(
+ private static ImmutableSegmentedHashSet GetNonTypeMemberNames(
CoreInternalSyntax.SyntaxList members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags, bool skipGlobalStatements = false, bool hasPrimaryCtor = false)
{
bool anyMethodHadExtensionSyntax = false;
@@ -838,7 +837,7 @@ private static ImmutableSegmentedDictionary GetNonTypeMember
if (hasPrimaryCtor)
{
- memberNameBuilder.TryAdd(WellKnownMemberNames.InstanceConstructorName);
+ memberNameBuilder.Add(WellKnownMemberNames.InstanceConstructorName);
}
foreach (var member in members)
@@ -976,7 +975,7 @@ private static bool CheckMemberForAttributes(Syntax.InternalSyntax.CSharpSyntaxN
}
private static void AddNonTypeMemberNames(
- Syntax.InternalSyntax.CSharpSyntaxNode member, ImmutableSegmentedDictionary.Builder set, ref bool anyNonTypeMembers, bool skipGlobalStatements)
+ Syntax.InternalSyntax.CSharpSyntaxNode member, ImmutableSegmentedHashSet.Builder set, ref bool anyNonTypeMembers, bool skipGlobalStatements)
{
switch (member.Kind)
{
@@ -987,7 +986,7 @@ private static void AddNonTypeMemberNames(
int numFieldDeclarators = fieldDeclarators.Count;
for (int i = 0; i < numFieldDeclarators; i++)
{
- set.TryAdd(fieldDeclarators[i].Identifier.ValueText);
+ set.Add(fieldDeclarators[i].Identifier.ValueText);
}
break;
@@ -998,7 +997,7 @@ private static void AddNonTypeMemberNames(
int numEventDeclarators = eventDeclarators.Count;
for (int i = 0; i < numEventDeclarators; i++)
{
- set.TryAdd(eventDeclarators[i].Identifier.ValueText);
+ set.Add(eventDeclarators[i].Identifier.ValueText);
}
break;
@@ -1011,7 +1010,7 @@ private static void AddNonTypeMemberNames(
var methodDecl = (Syntax.InternalSyntax.MethodDeclarationSyntax)member;
if (methodDecl.ExplicitInterfaceSpecifier == null)
{
- set.TryAdd(methodDecl.Identifier.ValueText);
+ set.Add(methodDecl.Identifier.ValueText);
}
break;
@@ -1021,7 +1020,7 @@ private static void AddNonTypeMemberNames(
var propertyDecl = (Syntax.InternalSyntax.PropertyDeclarationSyntax)member;
if (propertyDecl.ExplicitInterfaceSpecifier == null)
{
- set.TryAdd(propertyDecl.Identifier.ValueText);
+ set.Add(propertyDecl.Identifier.ValueText);
}
break;
@@ -1031,25 +1030,25 @@ private static void AddNonTypeMemberNames(
var eventDecl = (Syntax.InternalSyntax.EventDeclarationSyntax)member;
if (eventDecl.ExplicitInterfaceSpecifier == null)
{
- set.TryAdd(eventDecl.Identifier.ValueText);
+ set.Add(eventDecl.Identifier.ValueText);
}
break;
case SyntaxKind.ConstructorDeclaration:
anyNonTypeMembers = true;
- set.TryAdd(((Syntax.InternalSyntax.ConstructorDeclarationSyntax)member).Modifiers.Any((int)SyntaxKind.StaticKeyword)
+ set.Add(((Syntax.InternalSyntax.ConstructorDeclarationSyntax)member).Modifiers.Any((int)SyntaxKind.StaticKeyword)
? WellKnownMemberNames.StaticConstructorName
: WellKnownMemberNames.InstanceConstructorName);
break;
case SyntaxKind.DestructorDeclaration:
anyNonTypeMembers = true;
- set.TryAdd(WellKnownMemberNames.DestructorName);
+ set.Add(WellKnownMemberNames.DestructorName);
break;
case SyntaxKind.IndexerDeclaration:
anyNonTypeMembers = true;
- set.TryAdd(WellKnownMemberNames.Indexer);
+ set.Add(WellKnownMemberNames.Indexer);
break;
case SyntaxKind.OperatorDeclaration:
@@ -1062,7 +1061,7 @@ private static void AddNonTypeMemberNames(
if (opDecl.ExplicitInterfaceSpecifier == null)
{
var name = OperatorFacts.OperatorNameFromDeclaration(opDecl);
- set.TryAdd(name);
+ set.Add(name);
}
}
break;
@@ -1077,7 +1076,7 @@ private static void AddNonTypeMemberNames(
if (opDecl.ExplicitInterfaceSpecifier == null)
{
var name = OperatorFacts.OperatorNameFromDeclaration(opDecl);
- set.TryAdd(name);
+ set.Add(name);
}
}
break;
diff --git a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs
index 966cbae8d051f..e55a01689cfc3 100644
--- a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs
@@ -243,7 +243,7 @@ public ICollection MemberNames
{
if (_lazyMemberNames == null)
{
- var names = UnionCollection.Create(this.Declarations, d => d.MemberNames.Keys);
+ var names = UnionCollection.Create(this.Declarations, d => d.MemberNames);
Interlocked.CompareExchange(ref _lazyMemberNames, names, null);
}
diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs
index 1110313132338..3e3cb7f5c9ffa 100644
--- a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs
@@ -70,7 +70,7 @@ internal SingleTypeDeclaration(
TypeDeclarationFlags declFlags,
SyntaxReference syntaxReference,
SourceLocation nameLocation,
- ImmutableSegmentedDictionary memberNames,
+ ImmutableSegmentedHashSet memberNames,
ImmutableArray children,
ImmutableArray diagnostics,
QuickAttributes quickAttributes)
@@ -119,7 +119,7 @@ public DeclarationModifiers Modifiers
}
}
- public ImmutableSegmentedDictionary MemberNames { get; }
+ public ImmutableSegmentedHashSet MemberNames { get; }
public bool AnyMemberHasExtensionMethodSyntax
{
@@ -245,7 +245,7 @@ public bool Equals(TypeDeclarationIdentity other)
return false;
}
- if ((object)thisDecl.Location.SourceTree != otherDecl.Location.SourceTree
+ if ((object)thisDecl.SyntaxReference.SyntaxTree != otherDecl.SyntaxReference.SyntaxTree
&& ((thisDecl.Modifiers & DeclarationModifiers.File) != 0
|| (otherDecl.Modifiers & DeclarationModifiers.File) != 0))
{
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 8423565e79902..ca89dd2af9635 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -2190,6 +2190,7 @@ internal enum ErrorCode
ERR_BadCaseInSwitchArm = 9134,
ERR_ConstantValueOfTypeExpected = 9135,
+ ERR_UnsupportedPrimaryConstructorParameterCapturingRefAny = 9136,
#endregion
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index 3052e5e6cf4f6..beaf7cfeab2db 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -2310,6 +2310,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_BadStaticAfterUnsafe:
case ErrorCode.ERR_BadCaseInSwitchArm:
case ErrorCode.ERR_ConstantValueOfTypeExpected:
+ case ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefAny:
return false;
default:
// NOTE: All error codes must be explicitly handled in this switch statement
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index e55e7ad573ffb..92e08d6ae0c10 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -265,6 +265,8 @@ internal enum MessageID
IDS_FeaturePrimaryConstructors = MessageBase + 12833,
IDS_FeatureUsingTypeAlias = MessageBase + 12834,
+
+ IDS_FeatureInstanceMemberInNameof = MessageBase + 12835,
}
// Message IDs may refer to strings that need to be localized.
@@ -314,31 +316,87 @@ public static LocalizableErrorArgument Localize(this MessageID id)
}
}
+ internal static bool CheckFeatureAvailability(
+ this MessageID feature,
+ DiagnosticBag diagnostics,
+ SyntaxNode syntax,
+ Location? location = null)
+ {
+ return CheckFeatureAvailability(
+ feature,
+ diagnostics,
+ syntax.SyntaxTree.Options,
+ static tuple => tuple.location ?? tuple.syntax.Location,
+ (syntax, location));
+ }
+
+ internal static bool CheckFeatureAvailability(
+ this MessageID feature,
+ DiagnosticBag diagnostics,
+ SyntaxToken syntax,
+ Location? location = null)
+ {
+ return CheckFeatureAvailability(
+ feature,
+ diagnostics,
+ syntax.SyntaxTree!.Options,
+ static tuple => tuple.location ?? tuple.syntax.GetLocation(),
+ (syntax, location));
+ }
+
internal static bool CheckFeatureAvailability(
this MessageID feature,
BindingDiagnosticBag diagnostics,
SyntaxNode syntax,
Location? location = null)
{
- var diag = GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpParseOptions)syntax.SyntaxTree.Options);
- if (diag is object)
+ return CheckFeatureAvailability(
+ feature,
+ diagnostics,
+ syntax.SyntaxTree.Options,
+ static tuple => tuple.location ?? tuple.syntax.Location,
+ (syntax, location));
+ }
+
+ internal static bool CheckFeatureAvailability(
+ this MessageID feature,
+ BindingDiagnosticBag diagnostics,
+ SyntaxToken syntax,
+ Location? location = null)
+ {
+ return CheckFeatureAvailability(
+ feature,
+ diagnostics,
+ syntax.SyntaxTree!.Options,
+ static tuple => tuple.location ?? tuple.syntax.GetLocation(),
+ (syntax, location));
+ }
+
+ private static bool CheckFeatureAvailability(
+ this MessageID feature,
+ DiagnosticBag diagnostics,
+ ParseOptions parseOptions,
+ Func getLocation,
+ TData data)
+ {
+ if (GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpParseOptions)parseOptions) is { } diagInfo)
{
- diagnostics.Add(diag, location ?? syntax.GetLocation());
+ diagnostics.Add(diagInfo, getLocation(data));
return false;
}
return true;
}
- internal static bool CheckFeatureAvailability(
+ private static bool CheckFeatureAvailability(
this MessageID feature,
- DiagnosticBag diagnostics,
- SyntaxNode syntax,
- Location? location = null)
+ BindingDiagnosticBag diagnostics,
+ ParseOptions parseOptions,
+ Func getLocation,
+ TData data)
{
- var diag = GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpParseOptions)syntax.SyntaxTree.Options);
- if (diag is object)
+ if (GetFeatureAvailabilityDiagnosticInfo(feature, (CSharpParseOptions)parseOptions) is { } diagInfo)
{
- diagnostics.Add(diag, location ?? syntax.GetLocation());
+ diagnostics.Add(diagInfo, getLocation(data));
return false;
}
return true;
@@ -393,6 +451,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureLambdaParamsArray: // semantic check
case MessageID.IDS_FeaturePrimaryConstructors: // declaration table check
case MessageID.IDS_FeatureUsingTypeAlias: // semantic check
+ case MessageID.IDS_FeatureInstanceMemberInNameof: // semantic check
return LanguageVersion.Preview;
// C# 11.0 features.
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index 228e533fa7271..6139464e617a9 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -7920,7 +7920,7 @@ private TypeWithState VisitConversion(
bool extensionMethodThisArgument = false,
Optional stateForLambda = default,
bool trackMembers = false,
- Location? diagnosticLocationOpt = null,
+ Location? diagnosticLocation = null,
ArrayBuilder? previousArgumentConversionResults = null)
{
Debug.Assert(!trackMembers || !IsConditionalState);
@@ -7957,7 +7957,6 @@ private TypeWithState VisitConversion(
NullableFlowState resultState = NullableFlowState.NotNull;
bool canConvertNestedNullability = true;
bool isSuppressed = false;
- diagnosticLocationOpt ??= (conversionOpt ?? conversionOperand).Syntax.GetLocation();
if (conversionOperand.IsSuppressed == true)
{
@@ -7985,7 +7984,7 @@ private TypeWithState VisitConversion(
}
if (reportRemainingWarnings && invokeSignature != null)
{
- ReportNullabilityMismatchWithTargetDelegate(diagnosticLocationOpt, targetType, invokeSignature, method, conversion.IsExtensionMethod);
+ ReportNullabilityMismatchWithTargetDelegate(getDiagnosticLocation(), targetType, invokeSignature, method, conversion.IsExtensionMethod);
}
}
resultState = NullableFlowState.NotNull;
@@ -8007,7 +8006,7 @@ private TypeWithState VisitConversion(
VisitLambda(lambda, delegateType, stateForLambda);
if (reportRemainingWarnings && delegateType is not null)
{
- ReportNullabilityMismatchWithTargetDelegate(diagnosticLocationOpt, delegateType, lambda);
+ ReportNullabilityMismatchWithTargetDelegate(getDiagnosticLocation(), delegateType, lambda);
}
TrackAnalyzedNullabilityThroughConversionGroup(targetTypeWithNullability.ToTypeWithState(), conversionOpt, conversionOperand);
@@ -8038,7 +8037,7 @@ private TypeWithState VisitConversion(
case ConversionKind.ExplicitUserDefined:
case ConversionKind.ImplicitUserDefined:
- return VisitUserDefinedConversion(conversionOpt, conversionOperand, conversion, targetTypeWithNullability, operandType, useLegacyWarnings, assignmentKind, parameterOpt, reportTopLevelWarnings, reportRemainingWarnings, diagnosticLocationOpt);
+ return VisitUserDefinedConversion(conversionOpt, conversionOperand, conversion, targetTypeWithNullability, operandType, useLegacyWarnings, assignmentKind, parameterOpt, reportTopLevelWarnings, reportRemainingWarnings, getDiagnosticLocation());
case ConversionKind.ExplicitDynamic:
case ConversionKind.ImplicitDynamic:
@@ -8054,7 +8053,7 @@ private TypeWithState VisitConversion(
{
if (!operandType.IsNotNull && reportRemainingWarnings)
{
- ReportDiagnostic(ErrorCode.WRN_UnboxPossibleNull, diagnosticLocationOpt);
+ ReportDiagnostic(ErrorCode.WRN_UnboxPossibleNull, getDiagnosticLocation());
}
LearnFromNonNullTest(conversionOperand, ref State);
@@ -8148,7 +8147,7 @@ private TypeWithState VisitConversion(
// Explicit conversion of Nullable to T is equivalent to Nullable.Value.
if (reportTopLevelWarnings && operandType.MayBeNull)
{
- ReportDiagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, diagnosticLocationOpt);
+ ReportDiagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, getDiagnosticLocation());
}
// Mark the value as not nullable, regardless of whether it was known to be nullable,
@@ -8214,17 +8213,17 @@ private TypeWithState VisitConversion(
// Need to report all warnings that apply since the warnings can be suppressed individually.
if (reportTopLevelWarnings)
{
- ReportNullableAssignmentIfNecessary(conversionOperand, targetTypeWithNullability, resultType, useLegacyWarnings, assignmentKind, parameterOpt, diagnosticLocationOpt);
+ ReportNullableAssignmentIfNecessary(conversionOperand, targetTypeWithNullability, resultType, useLegacyWarnings, assignmentKind, parameterOpt, getDiagnosticLocation());
}
if (reportRemainingWarnings && !canConvertNestedNullability)
{
if (assignmentKind == AssignmentKind.Argument)
{
- ReportNullabilityMismatchInArgument(diagnosticLocationOpt, operandType.Type, parameterOpt, targetType, forOutput: false);
+ ReportNullabilityMismatchInArgument(getDiagnosticLocation(), operandType.Type, parameterOpt, targetType, forOutput: false);
}
else
{
- ReportNullabilityMismatchInAssignment(diagnosticLocationOpt, GetTypeAsDiagnosticArgument(operandType.Type), targetType);
+ ReportNullabilityMismatchInAssignment(getDiagnosticLocation(), GetTypeAsDiagnosticArgument(operandType.Type), targetType);
}
}
}
@@ -8233,6 +8232,13 @@ private TypeWithState VisitConversion(
return resultType;
+ // Avoid realizing the diagnostic location until needed.
+ Location getDiagnosticLocation()
+ {
+ diagnosticLocation ??= (conversionOpt ?? conversionOperand).Syntax.GetLocation();
+ return diagnosticLocation;
+ }
+
#nullable enable
static TypeWithState calculateResultType(TypeWithAnnotations targetTypeWithNullability, bool fromExplicitCast, NullableFlowState resultState, bool isSuppressed, TypeSymbol targetType)
{
@@ -8475,7 +8481,7 @@ private TypeWithState VisitUserDefinedConversion(
parameterOpt,
reportTopLevelWarnings,
reportRemainingWarnings,
- diagnosticLocationOpt: diagnosticLocation);
+ diagnosticLocation: diagnosticLocation);
// Update method based on operandType: see https://github.com/dotnet/roslyn/issues/29605.
// (see NullableReferenceTypesTests.ImplicitConversions_07).
@@ -8688,7 +8694,7 @@ private TypeWithState ClassifyAndVisitConversion(
parameterOpt,
reportTopLevelWarnings: reportWarnings,
reportRemainingWarnings: !fromExplicitCast && reportWarnings,
- diagnosticLocationOpt: diagnosticLocation);
+ diagnosticLocation: diagnosticLocation);
}
public override BoundNode? VisitDelegateCreationExpression(BoundDelegateCreationExpression node)
@@ -10221,7 +10227,7 @@ public override void VisitForEachIterationVariables(BoundForEachStatement node)
AssignmentKind.ForEachIterationVariable,
reportTopLevelWarnings: true,
reportRemainingWarnings: true,
- diagnosticLocationOpt: variableLocation);
+ diagnosticLocation: variableLocation);
}
// In non-error cases we'll only run this loop a single time. In error cases we'll set the nullability of the VariableType multiple times, but at least end up with something
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
index 55e82a0530129..0fd96f0aaf08d 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_BinaryOperator.cs
@@ -1558,9 +1558,8 @@ private BoundExpression CaptureExpressionInTempIfNeeded(
private BoundExpression MakeNewNullableBoolean(SyntaxNode syntax, bool? value)
{
- NamedTypeSymbol nullableType = _compilation.GetSpecialType(SpecialType.System_Nullable_T);
TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
- NamedTypeSymbol nullableBoolType = nullableType.Construct(boolType);
+ NamedTypeSymbol nullableBoolType = _compilation.GetOrCreateNullableType(boolType);
if (value == null)
{
return new BoundDefaultExpression(syntax, nullableBoolType);
diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
index aefd2df3998c4..fb537a77a0ee1 100644
--- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_UnaryOperator.cs
@@ -734,7 +734,7 @@ private BoundExpression MakeBuiltInIncrementOperator(BoundIncrementOperator node
if (binaryOperatorKind.IsLifted())
{
- binaryOperandType = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(binaryOperandType);
+ binaryOperandType = _compilation.GetOrCreateNullableType(binaryOperandType);
MethodSymbol ctor = UnsafeGetNullableMethod(node.Syntax, binaryOperandType, SpecialMember.System_Nullable_T__ctor);
boundOne = new BoundObjectCreationExpression(node.Syntax, ctor, boundOne);
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs
index 487971e6bbae6..f39280f32a662 100644
--- a/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/AliasSymbol.cs
@@ -374,7 +374,7 @@ private NamespaceOrTypeSymbol ResolveAliasTarget(
{
if (usingDirective.UnsafeKeyword != default)
{
- MessageID.IDS_FeatureUsingTypeAlias.CheckFeatureAvailability(diagnostics, usingDirective, usingDirective.UnsafeKeyword.GetLocation());
+ MessageID.IDS_FeatureUsingTypeAlias.CheckFeatureAvailability(diagnostics, usingDirective.UnsafeKeyword);
}
else if (usingDirective.NamespaceOrType is not NameSyntax)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
index 9898f52773941..64b9a72c48268 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/GlobalExpressionVariable.cs
@@ -8,6 +8,7 @@
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
@@ -30,8 +31,8 @@ internal GlobalExpressionVariable(
TypeSyntax typeSyntax,
string name,
SyntaxReference syntax,
- Location location)
- : base(containingType, modifiers, name, syntax, location)
+ TextSpan locationSpan)
+ : base(containingType, modifiers, name, syntax, locationSpan)
{
Debug.Assert(DeclaredAccessibility == Accessibility.Private);
_typeSyntaxOpt = typeSyntax?.GetReference();
@@ -43,7 +44,7 @@ internal static GlobalExpressionVariable Create(
TypeSyntax typeSyntax,
string name,
SyntaxNode syntax,
- Location location,
+ TextSpan locationSpan,
FieldSymbol containingFieldOpt,
SyntaxNode nodeToBind)
{
@@ -51,8 +52,8 @@ internal static GlobalExpressionVariable Create(
var syntaxReference = syntax.GetReference();
return (typeSyntax == null || typeSyntax.SkipScoped(out _).SkipRef().IsVar)
- ? new InferrableGlobalExpressionVariable(containingType, modifiers, typeSyntax, name, syntaxReference, location, containingFieldOpt, nodeToBind)
- : new GlobalExpressionVariable(containingType, modifiers, typeSyntax, name, syntaxReference, location);
+ ? new InferrableGlobalExpressionVariable(containingType, modifiers, typeSyntax, name, syntaxReference, locationSpan, containingFieldOpt, nodeToBind)
+ : new GlobalExpressionVariable(containingType, modifiers, typeSyntax, name, syntaxReference, locationSpan);
}
protected override SyntaxList AttributeDeclarationSyntaxList => default(SyntaxList);
@@ -169,10 +170,10 @@ internal InferrableGlobalExpressionVariable(
TypeSyntax typeSyntax,
string name,
SyntaxReference syntax,
- Location location,
+ TextSpan locationSpan,
FieldSymbol containingFieldOpt,
SyntaxNode nodeToBind)
- : base(containingType, modifiers, typeSyntax, name, syntax, location)
+ : base(containingType, modifiers, typeSyntax, name, syntax, locationSpan)
{
Debug.Assert(nodeToBind.Kind() == SyntaxKind.VariableDeclarator || nodeToBind is ExpressionSyntax);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
index 89a6dbdb8a619..e54c7008482b0 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs
@@ -303,6 +303,8 @@ public override bool IsExtensionMethod
public override ImmutableArray Locations => ImmutableArray.Create(Syntax.Identifier.GetLocation());
+ public override Location? TryGetFirstLocation() => Syntax.Identifier.GetLocation();
+
internal override bool GenerateDebugInfo => true;
public override ImmutableArray RefCustomModifiers => ImmutableArray.Empty;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
index 70a4c7370c399..efbe13b19594e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs
@@ -27,7 +27,7 @@ internal static DeclarationModifiers MakeAndCheckNonTypeMemberModifiers(
var readonlyToken = modifiers.FirstOrDefault(SyntaxKind.ReadOnlyKeyword);
if (readonlyToken.Parent is MethodDeclarationSyntax or AccessorDeclarationSyntax or BasePropertyDeclarationSyntax or EventDeclarationSyntax)
- modifierErrors |= !MessageID.IDS_FeatureReadOnlyMembers.CheckFeatureAvailability(diagnostics, readonlyToken.Parent, readonlyToken.GetLocation());
+ modifierErrors |= !MessageID.IDS_FeatureReadOnlyMembers.CheckFeatureAvailability(diagnostics, readonlyToken);
if ((result & DeclarationModifiers.AccessibilityMask) == 0)
result |= defaultAccess;
@@ -401,7 +401,7 @@ public static DeclarationModifiers ToDeclarationModifiers(
if (one == DeclarationModifiers.Partial)
{
var messageId = isForTypeDeclaration ? MessageID.IDS_FeaturePartialTypes : MessageID.IDS_FeaturePartialMethod;
- messageId.CheckFeatureAvailability(diagnostics, modifier.Parent, modifier.GetLocation());
+ messageId.CheckFeatureAvailability(diagnostics, modifier);
// `partial` must always be the last modifier according to the language. However, there was a bug
// where we allowed `partial async` at the end of modifiers on methods. We keep this behavior for
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs
index 4c90e7e60b40e..613f0c478e7a9 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/ParameterHelpers.cs
@@ -531,7 +531,7 @@ internal static void CheckParameterModifiers(
if (parsingLambdaParams)
{
- MessageID.IDS_FeatureLambdaParamsArray.CheckFeatureAvailability(diagnostics, parameter, modifier.GetLocation());
+ MessageID.IDS_FeatureLambdaParamsArray.CheckFeatureAvailability(diagnostics, modifier);
}
break;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
index 4544f4714dc9f..e8f76dd887aea 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs
@@ -367,7 +367,7 @@ private ConstantValue MakeDefaultExpression(BindingDiagnosticBag diagnostics, ou
return ConstantValue.NotAvailable;
}
- MessageID.IDS_FeatureOptionalParameter.CheckFeatureAvailability(diagnostics, defaultSyntax, defaultSyntax.EqualsToken.GetLocation());
+ MessageID.IDS_FeatureOptionalParameter.CheckFeatureAvailability(diagnostics, defaultSyntax.EqualsToken);
binder = GetDefaultParameterValueBinder(defaultSyntax);
Binder binderForDefault = binder.CreateBinderForParameterDefaultValue(this, defaultSyntax);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
index 520b9aa43f75c..ff7adaaeafb06 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs
@@ -175,14 +175,6 @@ internal sealed override OneOrMany> GetReturnTyp
return OneOrMany.Create(default(SyntaxList));
}
- protected sealed override IAttributeTargetSymbol AttributeOwner
- {
- get
- {
- return base.AttributeOwner;
- }
- }
-
internal sealed override bool GenerateDebugInfo
{
get { return true; }
@@ -252,7 +244,7 @@ internal sealed override int CalculateLocalSyntaxOffset(int position, SyntaxTree
protected sealed override bool HasSetsRequiredMembersImpl
=> GetEarlyDecodedWellKnownAttributeData()?.HasSetsRequiredMembersAttribute == true;
- internal sealed override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments)
+ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments)
{
if (arguments.SymbolPart == AttributeLocation.None)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
index 45500e7957e5a..81b6d58b15362 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEnumConstantSymbol.cs
@@ -46,7 +46,7 @@ public static SourceEnumConstantSymbol CreateImplicitValuedConstant(
}
protected SourceEnumConstantSymbol(SourceMemberContainerTypeSymbol containingEnum, EnumMemberDeclarationSyntax syntax, BindingDiagnosticBag diagnostics)
- : base(containingEnum, syntax.Identifier.ValueText, syntax.GetReference(), syntax.Identifier.GetLocation())
+ : base(containingEnum, syntax.Identifier.ValueText, syntax.GetReference(), syntax.Identifier.Span)
{
if (this.Name == WellKnownMemberNames.EnumBackingFieldName)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs
index e97a17ce96331..04279e41aaf83 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs
@@ -11,6 +11,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
@@ -166,7 +167,7 @@ internal sealed override bool HasRuntimeSpecialName
internal abstract class SourceFieldSymbolWithSyntaxReference : SourceFieldSymbol
{
private readonly string _name;
- private readonly Location _location;
+ private readonly TextSpan _locationSpan;
private readonly SyntaxReference _syntaxReference;
private string _lazyDocComment;
@@ -174,16 +175,15 @@ internal abstract class SourceFieldSymbolWithSyntaxReference : SourceFieldSymbol
private ConstantValue _lazyConstantEarlyDecodingValue = Microsoft.CodeAnalysis.ConstantValue.Unset;
private ConstantValue _lazyConstantValue = Microsoft.CodeAnalysis.ConstantValue.Unset;
- protected SourceFieldSymbolWithSyntaxReference(SourceMemberContainerTypeSymbol containingType, string name, SyntaxReference syntax, Location location)
+ protected SourceFieldSymbolWithSyntaxReference(SourceMemberContainerTypeSymbol containingType, string name, SyntaxReference syntax, TextSpan locationSpan)
: base(containingType)
{
Debug.Assert(name != null);
Debug.Assert(syntax != null);
- Debug.Assert(location != null);
_name = name;
_syntaxReference = syntax;
- _location = location;
+ _locationSpan = locationSpan;
}
public SyntaxTree SyntaxTree
@@ -211,33 +211,22 @@ public sealed override string Name
}
internal override LexicalSortKey GetLexicalSortKey()
- {
- return new LexicalSortKey(_location, this.DeclaringCompilation);
- }
+ => new LexicalSortKey(_syntaxReference, this.DeclaringCompilation);
+
+ public override Location TryGetFirstLocation()
+ => _syntaxReference.SyntaxTree.GetLocation(_locationSpan);
public sealed override ImmutableArray Locations
- {
- get
- {
- return ImmutableArray.Create(_location);
- }
- }
+ => ImmutableArray.Create(GetFirstLocation());
internal sealed override Location ErrorLocation
- {
- get
- {
- return _location;
- }
- }
+ => GetFirstLocation();
public sealed override ImmutableArray DeclaringSyntaxReferences
- {
- get
- {
- return ImmutableArray.Create(_syntaxReference);
- }
- }
+ => ImmutableArray.Create(_syntaxReference);
+
+ public override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedWithinSpan, CancellationToken cancellationToken = default)
+ => IsDefinedInSourceTree(_syntaxReference, tree, definedWithinSpan);
public sealed override string GetDocumentationCommentXml(CultureInfo preferredCulture = null, bool expandIncludes = false, CancellationToken cancellationToken = default(CancellationToken))
{
@@ -341,7 +330,7 @@ private void BindConstantValueIfNecessary(bool earlyDecodingWellKnownAttributes,
var diagnostics = BindingDiagnosticBag.GetInstance();
if (startsCycle)
{
- diagnostics.Add(ErrorCode.ERR_CircConstValue, _location, this);
+ diagnostics.Add(ErrorCode.ERR_CircConstValue, GetFirstLocation(), this);
}
var value = MakeConstantValue(builder, earlyDecodingWellKnownAttributes, diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
index ccbacc8bf13bd..746a884447a8e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
@@ -8,11 +8,14 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
+#if DEBUG
+using System.Runtime.CompilerServices;
+#endif
+
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
///
@@ -28,7 +31,6 @@ internal class SourceLocalSymbol : LocalSymbol
private readonly Symbol _containingSymbol;
private readonly SyntaxToken _identifierToken;
- private readonly ImmutableArray _locations;
private readonly TypeSyntax _typeSyntax;
private readonly RefKind _refKind;
private readonly LocalDeclarationKind _declarationKind;
@@ -69,9 +71,6 @@ private SourceLocalSymbol(
: isScoped ? ScopedKind.ScopedValue : ScopedKind.None;
this._declarationKind = declarationKind;
-
- // create this eagerly as it will always be needed for the EnsureSingleDefinition
- _locations = ImmutableArray.Create(identifierToken.GetLocation());
}
///
@@ -404,18 +403,16 @@ internal void SetTypeWithAnnotations(TypeWithAnnotations newType)
}
}
+ public override Location TryGetFirstLocation()
+ => _identifierToken.GetLocation();
+
///
/// Gets the locations where the local symbol was originally defined in source.
/// There should not be local symbols from metadata, and there should be only one local variable declared.
/// TODO: check if there are multiple same name local variables - error symbol or local symbol?
///
public override ImmutableArray Locations
- {
- get
- {
- return _locations;
- }
- }
+ => ImmutableArray.Create(GetFirstLocation());
internal sealed override SyntaxNode GetDeclaratorSyntax()
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
index cdb108c1d88b5..589b61065b511 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs
@@ -252,6 +252,7 @@ internal SourceMemberContainerTypeSymbol(
: SpecialType.None;
_flags = new Flags(specialType, typeKind, declaration.HasPrimaryConstructor);
+ Debug.Assert(typeKind is TypeKind.Struct or TypeKind.Class || !HasPrimaryConstructor);
var containingType = this.ContainingType;
if (containingType?.IsSealed == true && this.DeclaredAccessibility.HasProtected())
@@ -2654,6 +2655,14 @@ private void CheckSequentialOnPartialType(BindingDiagnosticBag diagnostics)
}
}
}
+
+ if (whereFoundField != null &&
+ PrimaryConstructor is { } primaryConstructor && primaryConstructor.GetCapturedParameters().Any() &&
+ (primaryConstructor.SyntaxRef.SyntaxTree != whereFoundField.SyntaxTree || primaryConstructor.SyntaxRef.Span != whereFoundField.Span))
+ {
+ diagnostics.Add(ErrorCode.WRN_SequentialOnPartialClass, GetFirstLocation(), this);
+ return;
+ }
}
private static bool HasInstanceData(MemberDeclarationSyntax m)
@@ -3200,20 +3209,28 @@ ImmutableArray buildSimpleProgramEntry
}
}
+ internal bool HasPrimaryConstructor => this._flags.HasPrimaryConstructor;
+
internal SynthesizedPrimaryConstructor? PrimaryConstructor
{
get
{
- if (!this._flags.HasPrimaryConstructor)
+ if (!HasPrimaryConstructor)
return null;
var declared = Volatile.Read(ref _lazyDeclaredMembersAndInitializers);
+ SynthesizedPrimaryConstructor? result;
if (declared is not null && declared != DeclaredMembersAndInitializers.UninitializedSentinel)
{
- return declared.PrimaryConstructor;
+ result = declared.PrimaryConstructor;
+ }
+ else
+ {
+ result = GetMembersAndInitializers().PrimaryConstructor;
}
- return GetMembersAndInitializers().PrimaryConstructor;
+ Debug.Assert(result is object);
+ return result;
}
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
index 3c8930fb110f2..c053192dea854 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs
@@ -26,8 +26,8 @@ internal SourceMemberFieldSymbol(
DeclarationModifiers modifiers,
string name,
SyntaxReference syntax,
- Location location)
- : base(containingType, name, syntax, location)
+ TextSpan locationSpan)
+ : base(containingType, name, syntax, locationSpan)
{
_modifiers = modifiers;
}
@@ -196,7 +196,7 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp
foreach (var modifier in modifiers)
{
if (modifier.IsKind(SyntaxKind.FixedKeyword))
- MessageID.IDS_FeatureFixedBuffer.CheckFeatureAvailability(diagnostics, modifier.Parent, modifier.GetLocation());
+ MessageID.IDS_FeatureFixedBuffer.CheckFeatureAvailability(diagnostics, modifier);
}
reportBadMemberFlagIfAny(result, DeclarationModifiers.Static, diagnostics, errorLocation);
@@ -338,7 +338,7 @@ internal SourceMemberFieldSymbolFromDeclarator(
DeclarationModifiers modifiers,
bool modifierErrors,
BindingDiagnosticBag diagnostics)
- : base(containingType, modifiers, declarator.Identifier.ValueText, declarator.GetReference(), declarator.Identifier.GetLocation())
+ : base(containingType, modifiers, declarator.Identifier.ValueText, declarator.GetReference(), declarator.Identifier.Span)
{
_hasInitializer = declarator.Initializer != null;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
index 893d1d7a431d6..79f805093c5a8 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs
@@ -128,6 +128,11 @@ protected virtual IAttributeTargetSymbol AttributeOwner
get { return this; }
}
+ protected virtual AttributeLocation AttributeLocationForLoadAndValidateAttributes
+ {
+ get { return AttributeLocation.None; }
+ }
+
IAttributeTargetSymbol IAttributeTargetSymbol.AttributesOwner
{
get { return this.AttributeOwner; }
@@ -280,7 +285,7 @@ private CustomAttributesBag GetAttributesBag(ref CustomAttr
{
var (declarations, symbolPart) = forReturnType
? (GetReturnTypeAttributeDeclarations(), AttributeLocation.Return)
- : (GetAttributeDeclarations(), AttributeLocation.None);
+ : (GetAttributeDeclarations(), AttributeLocationForLoadAndValidateAttributes);
bagCreatedOnThisThread = LoadAndValidateAttributes(
declarations,
ref lazyCustomAttributesBag,
@@ -476,7 +481,7 @@ internal sealed override ImmutableArray GetAppliedConditionalSymbols()
return data != null ? data.ConditionalSymbols : ImmutableArray.Empty;
}
- protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments)
+ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments)
{
Debug.Assert(!arguments.Attribute.HasErrors);
Debug.Assert(arguments.SymbolPart == AttributeLocation.None || arguments.SymbolPart == AttributeLocation.Return);
@@ -1015,7 +1020,7 @@ static UnmanagedCallersOnlyAttributeData DecodeUnmanagedCallersOnlyAttributeData
}
}
- internal sealed override void PostDecodeWellKnownAttributes(ImmutableArray boundAttributes, ImmutableArray allAttributeSyntaxNodes, BindingDiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
+ internal override void PostDecodeWellKnownAttributes(ImmutableArray boundAttributes, ImmutableArray allAttributeSyntaxNodes, BindingDiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
{
Debug.Assert(!boundAttributes.IsDefault);
Debug.Assert(!allAttributeSyntaxNodes.IsDefault);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
index ce3cf12ddc9e7..01950c5021b6d 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs
@@ -181,7 +181,7 @@ private ImmutableArray MakeTypeParameters(BindingDiagnostic
throw ExceptionUtilities.UnexpectedValue(typeDecl.Kind());
}
- MessageID.IDS_FeatureGenerics.CheckFeatureAvailability(diagnostics, tpl, tpl.LessThanToken.GetLocation());
+ MessageID.IDS_FeatureGenerics.CheckFeatureAvailability(diagnostics, tpl.LessThanToken);
bool isInterfaceOrDelegate = typeKind == SyntaxKind.InterfaceDeclaration || typeKind == SyntaxKind.DelegateDeclaration;
var parameterBuilder = new List();
@@ -197,7 +197,7 @@ private ImmutableArray MakeTypeParameters(BindingDiagnostic
}
else
{
- MessageID.IDS_FeatureTypeVariance.CheckFeatureAvailability(diagnostics, tp, tp.VarianceKeyword.GetLocation());
+ MessageID.IDS_FeatureTypeVariance.CheckFeatureAvailability(diagnostics, tp.VarianceKeyword);
}
}
@@ -821,7 +821,7 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations
case TypeKind.Struct:
case TypeKind.Class:
- return AttributeLocation.Type;
+ return AttributeLocation.Type | (HasPrimaryConstructor ? AttributeLocation.Method : 0);
default:
return AttributeLocation.None;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs
index 9236831630301..0ae85749547cc 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodOrUserDefinedOperatorSymbol.cs
@@ -228,11 +228,10 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
{
base.AfterAddingTypeMembersChecks(conversions, diagnostics);
- var location = ReturnTypeLocation;
+ // Defer computing location to avoid unnecessary allocations in most cases.
+ Location? returnTypeLocation = null;
var compilation = DeclaringCompilation;
- Debug.Assert(location != null);
-
// Check constraints on return type and parameters. Note: Dev10 uses the
// method name location for any such errors. We'll do the same for return
// type errors but for parameter errors, we'll use the parameter location.
@@ -249,14 +248,14 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
if (RefKind == RefKind.RefReadOnly)
{
- compilation.EnsureIsReadOnlyAttributeExists(diagnostics, location, modifyCompilation: true);
+ compilation.EnsureIsReadOnlyAttributeExists(diagnostics, getReturnTypeLocation(), modifyCompilation: true);
}
ParameterHelpers.EnsureIsReadOnlyAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
if (compilation.ShouldEmitNativeIntegerAttributes(ReturnType))
{
- compilation.EnsureNativeIntegerAttributeExists(diagnostics, location, modifyCompilation: true);
+ compilation.EnsureNativeIntegerAttributeExists(diagnostics, getReturnTypeLocation(), modifyCompilation: true);
}
ParameterHelpers.EnsureNativeIntegerAttributeExists(compilation, Parameters, diagnostics, modifyCompilation: true);
@@ -265,10 +264,16 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions,
if (compilation.ShouldEmitNullableAttributes(this) && ReturnTypeWithAnnotations.NeedsNullableAttribute())
{
- compilation.EnsureNullableAttributeExists(diagnostics, location, modifyCompilation: true);
+ compilation.EnsureNullableAttributeExists(diagnostics, getReturnTypeLocation(), modifyCompilation: true);
}
ParameterHelpers.EnsureNullableAttributeExists(compilation, this, Parameters, diagnostics, modifyCompilation: true);
+
+ Location getReturnTypeLocation()
+ {
+ returnTypeLocation ??= this.ReturnTypeLocation;
+ return returnTypeLocation;
+ }
}
protected abstract void CheckConstraintsForExplicitInterfaceType(ConversionsBase conversions, BindingDiagnosticBag diagnostics);
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
index aadde6cc87875..49ea558801938 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
@@ -533,7 +533,7 @@ private ImmutableArray MakeTypeParameters(MethodDeclaration
{
Debug.Assert(syntax.TypeParameterList != null);
- MessageID.IDS_FeatureGenerics.CheckFeatureAvailability(diagnostics, syntax.TypeParameterList, syntax.TypeParameterList.LessThanToken.GetLocation());
+ MessageID.IDS_FeatureGenerics.CheckFeatureAvailability(diagnostics, syntax.TypeParameterList.LessThanToken);
OverriddenMethodTypeParameterMapBase typeMap = null;
if (this.IsOverride)
@@ -620,8 +620,9 @@ public override bool IsDefinedInSourceTree(
{
// Since only the declaring (and not the implementing) part of a partial method appears in the member
// list, we need to ensure we complete the implementation part when needed.
+ Debug.Assert(this.DeclaringSyntaxReferences.Length == 1);
return
- base.IsDefinedInSourceTree(tree, definedWithinSpan, cancellationToken) ||
+ IsDefinedInSourceTree(this.SyntaxRef, tree, definedWithinSpan) ||
this.SourcePartialImplementation?.IsDefinedInSourceTree(tree, definedWithinSpan, cancellationToken) == true;
}
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
index 9bf97d566b7ad..322b183327a77 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
@@ -235,7 +235,7 @@ protected SourcePropertyAccessorSymbol(
}
if (modifiers.Count > 0)
- MessageID.IDS_FeaturePropertyAccessorMods.CheckFeatureAvailability(diagnostics, syntax, modifiers[0].GetLocation());
+ MessageID.IDS_FeaturePropertyAccessorMods.CheckFeatureAvailability(diagnostics, modifiers[0]);
}
#nullable disable
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
index a2247924b101e..af93d12c934ff 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
@@ -133,7 +133,7 @@ private SourcePropertySymbol(
diagnostics);
if (syntax is PropertyDeclarationSyntax { Initializer: { } initializer })
- MessageID.IDS_FeatureAutoPropertyInitializer.CheckFeatureAvailability(diagnostics, syntax, initializer.EqualsToken.GetLocation());
+ MessageID.IDS_FeatureAutoPropertyInitializer.CheckFeatureAvailability(diagnostics, initializer.EqualsToken);
}
private TypeSyntax GetTypeSyntax(SyntaxNode syntax) => ((BasePropertyDeclarationSyntax)syntax).Type;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedConversionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedConversionSymbol.cs
index 136872cc5bb72..0e9bac249c720 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedConversionSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedConversionSymbol.cs
@@ -27,7 +27,7 @@ public static SourceUserDefinedConversionSymbol CreateUserDefinedConversionSymbo
if (name == WellKnownMemberNames.CheckedExplicitConversionName)
{
- MessageID.IDS_FeatureCheckedUserDefinedOperators.CheckFeatureAvailability(diagnostics, syntax, syntax.CheckedKeyword.GetLocation());
+ MessageID.IDS_FeatureCheckedUserDefinedOperators.CheckFeatureAvailability(diagnostics, syntax.CheckedKeyword);
}
else if (syntax.CheckedKeyword.IsKind(SyntaxKind.CheckedKeyword))
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs
index b150708e7de10..4a9c89330c33f 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbol.cs
@@ -27,7 +27,7 @@ public static SourceUserDefinedOperatorSymbol CreateUserDefinedOperatorSymbol(
if (SyntaxFacts.IsCheckedOperator(name))
{
- MessageID.IDS_FeatureCheckedUserDefinedOperators.CheckFeatureAvailability(diagnostics, syntax, syntax.CheckedKeyword.GetLocation());
+ MessageID.IDS_FeatureCheckedUserDefinedOperators.CheckFeatureAvailability(diagnostics, syntax.CheckedKeyword);
}
else if (!syntax.OperatorToken.IsMissing && syntax.CheckedKeyword.IsKind(SyntaxKind.CheckedKeyword))
{
@@ -36,7 +36,7 @@ public static SourceUserDefinedOperatorSymbol CreateUserDefinedOperatorSymbol(
if (name == WellKnownMemberNames.UnsignedRightShiftOperatorName)
{
- MessageID.IDS_FeatureUnsignedRightShift.CheckFeatureAvailability(diagnostics, syntax, syntax.OperatorToken.GetLocation());
+ MessageID.IDS_FeatureUnsignedRightShift.CheckFeatureAvailability(diagnostics, syntax.OperatorToken);
}
var interfaceSpecifier = syntax.ExplicitInterfaceSpecifier;
diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
index 734dba9e066e3..8f2c451aa7a85 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs
@@ -829,8 +829,7 @@ internal bool Dangerous_IsFromSomeCompilation
{
cancellationToken.ThrowIfCancellationRequested();
- if (syntaxRef.SyntaxTree == tree &&
- (!definedWithinSpan.HasValue || syntaxRef.Span.IntersectsWith(definedWithinSpan.Value)))
+ if (IsDefinedInSourceTree(syntaxRef, tree, definedWithinSpan))
{
return true;
}
@@ -839,6 +838,10 @@ internal bool Dangerous_IsFromSomeCompilation
return false;
}
+ protected static bool IsDefinedInSourceTree(SyntaxReference syntaxRef, SyntaxTree tree, TextSpan? definedWithinSpan)
+ => syntaxRef.SyntaxTree == tree &&
+ (!definedWithinSpan.HasValue || syntaxRef.Span.IntersectsWith(definedWithinSpan.Value));
+
internal static void ForceCompleteMemberByLocation(SourceLocation locationOpt, Symbol member, CancellationToken cancellationToken)
{
if (locationOpt == null || member.IsDefinedInSourceTree(locationOpt.SourceTree, locationOpt.SourceSpan, cancellationToken))
diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
index 9b50cfc1d6b7f..f8f464d31506e 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs
@@ -590,7 +590,8 @@ private ImmutableArray GetAttributesToBind(
foreach (var attributeDeclarationSyntax in attributeDeclarationSyntaxList)
{
// We bind the attribute only if it has a matching target for the given ownerSymbol and attributeLocation.
- if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics))
+ if (MatchAttributeTarget(attributeTarget, symbolPart, attributeDeclarationSyntax.Target, diagnostics) &&
+ ShouldBindAttributes(attributeDeclarationSyntax, diagnostics))
{
if (syntaxBuilder == null)
{
@@ -644,6 +645,11 @@ private ImmutableArray GetAttributesToBind(
}
}
+ protected virtual bool ShouldBindAttributes(AttributeListSyntax attributeDeclarationSyntax, BindingDiagnosticBag diagnostics)
+ {
+ return true;
+ }
+
#nullable enable
private Binder GetAttributeBinder(SyntaxList attributeDeclarationSyntaxList, CSharpCompilation compilation, Binder? rootBinder = null)
{
diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructor.cs
index f737464c83c8c..2703847c97b27 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructor.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedPrimaryConstructor.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -21,6 +22,9 @@ public SynthesizedPrimaryConstructor(
base(containingType, syntax.Identifier.GetLocation(), syntax, isIterator: false)
{
Debug.Assert(syntax.Kind() is SyntaxKind.RecordDeclaration or SyntaxKind.RecordStructDeclaration or SyntaxKind.ClassDeclaration or SyntaxKind.StructDeclaration);
+ Debug.Assert(containingType.HasPrimaryConstructor);
+ Debug.Assert(containingType is SourceNamedTypeSymbol);
+ Debug.Assert(containingType is IAttributeTargetSymbol);
this.MakeFlags(
MethodKind.Constructor,
@@ -36,6 +40,21 @@ internal TypeDeclarationSyntax GetSyntax()
return (TypeDeclarationSyntax)syntaxReferenceOpt.GetSyntax();
}
+ protected override IAttributeTargetSymbol AttributeOwner
+ {
+ get { return (IAttributeTargetSymbol)ContainingType; }
+ }
+
+ protected override AttributeLocation AttributeLocationForLoadAndValidateAttributes
+ {
+ get { return AttributeLocation.Method; }
+ }
+
+ internal override OneOrMany> GetAttributeDeclarations()
+ {
+ return new OneOrMany>(((SourceNamedTypeSymbol)ContainingType).GetAttributeDeclarations());
+ }
+
protected override ParameterListSyntax GetParameterList()
{
return GetSyntax().ParameterList!;
@@ -99,5 +118,55 @@ public IReadOnlyDictionary GetCapturedParameters()
Interlocked.CompareExchange(ref _capturedParameters, Binder.CapturedParametersFinder.GetCapturedParameters(this), null);
return _capturedParameters;
}
+
+ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments)
+ {
+ Debug.Assert(arguments.SymbolPart == AttributeLocation.Method);
+ arguments.SymbolPart = AttributeLocation.None;
+ var result = base.EarlyDecodeWellKnownAttribute(ref arguments);
+ arguments.SymbolPart = AttributeLocation.Method;
+ return result;
+ }
+
+ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments)
+ {
+ Debug.Assert(arguments.SymbolPart == AttributeLocation.Method);
+ arguments.SymbolPart = AttributeLocation.None;
+ base.DecodeWellKnownAttributeImpl(ref arguments);
+ arguments.SymbolPart = AttributeLocation.Method;
+ }
+
+ internal override void PostDecodeWellKnownAttributes(ImmutableArray boundAttributes, ImmutableArray allAttributeSyntaxNodes, BindingDiagnosticBag diagnostics, AttributeLocation symbolPart, WellKnownAttributeData decodedData)
+ {
+ Debug.Assert(symbolPart is AttributeLocation.Method or AttributeLocation.Return);
+ base.PostDecodeWellKnownAttributes(boundAttributes, allAttributeSyntaxNodes, diagnostics, symbolPart is AttributeLocation.Method ? AttributeLocation.None : symbolPart, decodedData);
+ }
+
+ protected override bool ShouldBindAttributes(AttributeListSyntax attributeDeclarationSyntax, BindingDiagnosticBag diagnostics)
+ {
+ Debug.Assert(attributeDeclarationSyntax.Target is object);
+
+ if (!base.ShouldBindAttributes(attributeDeclarationSyntax, diagnostics))
+ {
+ return false;
+ }
+
+ if (attributeDeclarationSyntax.SyntaxTree == SyntaxRef.SyntaxTree &&
+ GetSyntax().AttributeLists.Contains(attributeDeclarationSyntax))
+ {
+ if (ContainingType is { IsRecord: true } or { IsRecordStruct: true })
+ {
+ MessageID.IDS_FeaturePrimaryConstructors.CheckFeatureAvailability(diagnostics, attributeDeclarationSyntax, attributeDeclarationSyntax.Target.Identifier.GetLocation());
+ }
+
+ return true;
+ }
+
+ SyntaxToken target = attributeDeclarationSyntax.Target.Identifier;
+ diagnostics.Add(ErrorCode.WRN_AttributeLocationOnBadDeclaration,
+ target.GetLocation(), target.ToString(), (AttributeOwner.AllowedAttributeLocations & ~AttributeLocation.Method).ToDisplayString());
+
+ return false;
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
index c181404184893..f315f0a24792a 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxNodeExtensions.cs
@@ -271,10 +271,10 @@ private static TypeSyntax SkipRefWorker(TypeSyntax syntax, BindingDiagnosticBag?
(current.Parent is VariableDeclarationSyntax { Parent: LocalDeclarationStatementSyntax } variableDeclaration && variableDeclaration.Type == current));
#endif
- MessageID.IDS_FeatureRefLocalsReturns.CheckFeatureAvailability(diagnostics, refType, refType.RefKeyword.GetLocation());
+ MessageID.IDS_FeatureRefLocalsReturns.CheckFeatureAvailability(diagnostics, refType.RefKeyword);
if (refType.ReadOnlyKeyword != default)
- MessageID.IDS_FeatureReadOnlyReferences.CheckFeatureAvailability(diagnostics, refType, refType.ReadOnlyKeyword.GetLocation());
+ MessageID.IDS_FeatureReadOnlyReferences.CheckFeatureAvailability(diagnostics, refType.ReadOnlyKeyword);
}
return refType.Type;
@@ -325,8 +325,7 @@ internal static SyntaxNode ModifyingScopedOrRefTypeOrSelf(this SyntaxNode syntax
return syntax;
}
- MessageID.IDS_FeatureRefLocalsReturns.CheckFeatureAvailability(
- diagnostics, refExpression, refExpression.RefKeyword.GetLocation());
+ MessageID.IDS_FeatureRefLocalsReturns.CheckFeatureAvailability(diagnostics, refExpression.RefKeyword);
refKind = RefKind.Ref;
expression.CheckDeconstructionCompatibleArgument(diagnostics);
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 08b608bf72086..cf2d5091ce7e3 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -1777,6 +1777,11 @@
Uvnitř členu instance nejde použít parametr primárního konstruktoru {0} typu odkaz, výstup nebo vstup.
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Nejde použít parametr primárního konstruktoru {0}, který má uvnitř členu instance typ podobný odkazu.
@@ -1902,6 +1907,11 @@
odvozený typ delegáta
+
+
+ instance member in 'nameof'
+
+
atributy lambda
@@ -11672,11 +11682,6 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference
{0} nejde vrátit pomocí odkazu, protože je to {1}.
-
-
- Pole elementu {0} nejde vrátit pomocí odkazu, protože je to {1}.
-
-
Pole jen pro čtení nejde vrátit zapisovatelným odkazem.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 1d6e11204d64a..d1aa50feea941 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -1777,6 +1777,11 @@
Der ref-, out- oder in-primäre Konstruktorparameter „{0}“ kann nicht innerhalb eines Instanzmembers verwendet werden.
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Der primäre Konstruktorparameter „{0}“, der einen ref-ähnlichen Typ innerhalb eines Instanzmembers aufweist, kann nicht verwendet werden.
@@ -1902,6 +1907,11 @@
abgeleiteter Delegattyp
+
+
+ instance member in 'nameof'
+
+
Lambdaattribute
@@ -11672,11 +11682,6 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett
"{0}" kann nicht als Verweis zurückgegeben werden, weil es sich um ein {1}-Element handelt.
-
-
- Felder von "{0}" können nicht als Verweis zurückgegeben werden, weil es sich um ein {1}-Element handelt.
-
-
Ein schreibgeschütztes Feld kann nicht als schreibbarer Verweis zurückgegeben werden.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index 4f8f403b1ec52..1d7eae3b86136 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -1777,6 +1777,11 @@
No se puede usar ref, out o en el parámetro de constructor principal '{0}' dentro de un miembro de instancia
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
No se puede usar el parámetro de constructor principal '{0}' que tiene un tipo ref-like dentro de un miembro de instancia
@@ -1902,6 +1907,11 @@
tipo de delegado inferido
+
+
+ instance member in 'nameof'
+
+
atributos de lambda
@@ -11672,11 +11682,6 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe
'{0}' no se puede devolver por referencia porque es un '{1}'.
-
-
- Los campos de '{0}' no se pueden devolver por referencia porque es un '{1}'.
-
-
No se puede devolver un campo de solo lectura por referencia grabable.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index 67db681971e65..d9515827f9d61 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -1777,6 +1777,11 @@
Impossible d’utiliser le paramètre de constructeur principal '{0}' avec ref, out ou in à l’intérieur d’un membre d’instance.
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Nous n’avons pas pu utiliser le paramètre de constructeur principal '{0}' qui a un type de référence similaire à l’intérieur d’un membre d’instance
@@ -1902,6 +1907,11 @@
type délégué déduit
+
+
+ instance member in 'nameof'
+
+
attributs lambda
@@ -11672,11 +11682,6 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé
Impossible de retourner '{0}' par référence, car il s'agit d'un '{1}'
-
-
- Impossible de retourner les champs de '{0}' par référence, car il s'agit d'un '{1}'
-
-
Impossible de retourner un champ readonly par référence accessible en écriture
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index fb63a0510b8cb..b9599ffc38273 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -1777,6 +1777,11 @@
Non è possibile usare il parametro ref, out o in del costruttore primario '{0}' all'interno di un membro di istanza
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Non è possibile usare il parametro del costruttore primario '{0}' con un tipo simile a ref all'interno di un membro di istanza
@@ -1902,6 +1907,11 @@
tipo di delegato dedotto
+
+
+ instance member in 'nameof'
+
+
attributi lambda
@@ -11672,11 +11682,6 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr
Non è possibile restituire '{0}' per riferimento perché è '{1}'
-
-
- Non è possibile restituire i campi di '{0}' per riferimento perché è '{1}'
-
-
Un campo di sola lettura non può restituito per riferimento scrivibile
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index e8beb6a35d68e..edc79dc35b41a 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -1777,6 +1777,11 @@
インスタンス メンバー内のプライマリ コンストラクター パラメーター '{0}' では ref、out、in を使用できません
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
インスタンス メンバー内に ref に似た型を持つプライマリ コンストラクター パラメーター '{0}' を使用することはできません
@@ -1902,6 +1907,11 @@
推論されたデリゲート型
+
+
+ instance member in 'nameof'
+
+
ラムダ属性
@@ -11672,11 +11682,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
'{1}' であるため、'{0}' を参照渡しで返すことはできません
-
-
- '{1}' であるため、'{0}' のフィールドを参照渡しで返すことはできません
-
-
読み取り専用フィールドを書き込み可能な参照渡しで返すことはできません
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index c480f2f4d0adc..8ba51bf19c702 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -1777,6 +1777,11 @@
인스턴스 멤버 내에서 ref, out 또는 기본 생성자 '{0}' 매개 변수를 사용할 수 없습니다.
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
인스턴스 멤버 내에 ref 유사 형식이 있는 기본 생성자 '{0}' 매개 변수를 사용할 수 없습니다.
@@ -1902,6 +1907,11 @@
유추된 대리자 형식
+
+
+ instance member in 'nameof'
+
+
람다 특성
@@ -11671,11 +11681,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
'{0}'은(는) '{1}'이므로 참조로 반환할 수 없습니다.
-
-
- '{0}'의 필드는 '{1}'이므로 참조로 반환할 수 없습니다.
-
-
읽기 전용 필드는 쓰기 가능 참조로 반환될 수 없습니다.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index 3306e602d4082..d50d0d8303084 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -1777,6 +1777,11 @@
Nie można użyć ref, out lub w podstawowym parametrze konstruktora '{0}' wewnątrz elementu członkowskiego wystąpienia
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Nie można użyć podstawowego parametru konstruktora '{0}', który ma typ przypominający odwołanie wewnątrz składowej wystąpienia
@@ -1902,6 +1907,11 @@
Typ delegowania wywnioskowanego
+
+
+ instance member in 'nameof'
+
+
atrybuty lambda
@@ -11672,11 +11682,6 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w
Nie można zwrócić elementu „{0}” przez referencję, ponieważ to jest element „{1}”
-
-
- Nie można zwrócić pól elementu „{0}” przez referencję, ponieważ to jest element „{1}”
-
-
Nie można zwrócić pola tylko do odczytu przez zapisywalne odwołanie
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index c0e4438db70d8..6b2d4acb4bb83 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -1777,6 +1777,11 @@
Não é possível usar ref, out ou no parâmetro de construtor primário "{0}" dentro de um membro da instância
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Não é possível usar o parâmetro de construtor primário "{0}" que tem o tipo ref-like dentro de um membro de instância
@@ -1902,6 +1907,11 @@
tipo representante inferido
+
+
+ instance member in 'nameof'
+
+
lambda attributes
@@ -11672,11 +11682,6 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl
Não é possível retornar '{0}' por referência, porque ele é um '{1}'
-
-
- Não é possível retornar campos de '{0}' por referência, porque ele é um '{1}'
-
-
Um campo somente leitura não pode ser retornado por referência gravável
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 1ef0d19b1ac13..d1362cd391fc4 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -1777,6 +1777,11 @@
Невозможно использовать параметр основного конструктора "{0}" с модификаторами ref, out или in внутри элемента экземпляра
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Невозможно использовать параметр основного конструктора "{0}" типа ref-like внутри элемента экземпляра
@@ -1902,6 +1907,11 @@
выводимый тип делегата
+
+
+ instance member in 'nameof'
+
+
лямбда-атрибуты
@@ -11672,11 +11682,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Невозможно вернуть "{0}" по ссылке, так как это "{1}"
-
-
- Невозможно вернуть поля "{0}" по ссылке, так как это "{1}"
-
-
Поле, доступное только для чтения, невозможно вернуть по ссылке, доступной для записи
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 23c0e98db66e9..63258ad292658 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -1777,6 +1777,11 @@
Bir örnek üye içinde ref, out veya in '{0}' birincil oluşturucu parametresi kullanılamaz
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
Bir örnek üye içinde ref benzeri türe sahip '{0}' birincil oluşturucu parametresi kullanılamaz
@@ -1902,6 +1907,11 @@
çıkarsanan temsilci türü
+
+
+ instance member in 'nameof'
+
+
lambda öznitelikleri
@@ -11672,11 +11682,6 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T
'{0}' öğesi bir '{1}' olduğundan başvuru ile döndürülemez
-
-
- '{0}' bir '{1}' olduğundan alanları başvuru ile döndürülemez
-
-
Salt okunur bir alan, yazılabilir başvuru ile döndürülemez
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index cefa521ea09ed..80a8f77bb0f6b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -1777,6 +1777,11 @@
无法在实例成员内的主构造函数参数 “{0}” 中使用 ref、out 或
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
无法使用实例成员内具有 ref-like 类型的主构造函数参数 “{0}”
@@ -1902,6 +1907,11 @@
推断的委托类型
+
+
+ instance member in 'nameof'
+
+
Lambda 属性
@@ -11677,11 +11687,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
“{0}”是一个“{1}”,无法通过引用返回
-
-
- “{0}”是一个“{1}”,无法通过引用返回其字段
-
-
只读字段无法通过可写的引用返回
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 3d3bdc4e84ed4..04a3ec570e8e7 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -1777,6 +1777,11 @@
無法在執行個體成員內使用 ref、out 或 in 主要建立建構函式參數 '{0}'
+
+
+ Cannot use primary constructor parameter of type '{0}' inside an instance member
+
+
無法使用執行個體成員內具有類似參考類型的主要建立函式參數 '{0}'
@@ -1902,6 +1907,11 @@
推斷委派類型
+
+
+ instance member in 'nameof'
+
+
Lambda 屬性
@@ -11672,11 +11682,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
無法藉傳址方式傳回 '{0}',因其為 '{1}'
-
-
- 無法藉傳址方式傳回 '{0}' 欄位,因其為 '{1}'
-
-
無法以可寫入傳址方式傳回唯讀欄位
diff --git a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
index 8731f0293ac95..cf28edcd5f19a 100644
--- a/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
+++ b/src/Compilers/CSharp/Test/CommandLine/CommandLineTests.cs
@@ -8635,7 +8635,7 @@ public void FileShareDeleteCompatibility_Windows()
fsDll.Dispose();
fsPdb.Dispose();
- AssertEx.Equal(new[] { "Lib.cs", "Lib.dll", "Lib.pdb" }, Roslyn.Utilities.EnumerableExtensions.Order(Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p))));
+ AssertEx.Equal(new[] { "Lib.cs", "Lib.dll", "Lib.pdb" }, Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p)).Order());
}
///
@@ -8692,7 +8692,7 @@ public void FileShareDeleteCompatibility_Xplat()
peDll.Dispose();
pePdb.Dispose();
- AssertEx.Equal(new[] { "Lib.cs", "Lib.dll", "Lib.pdb" }, Roslyn.Utilities.EnumerableExtensions.Order(Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p))));
+ AssertEx.Equal(new[] { "Lib.cs", "Lib.dll", "Lib.pdb" }, Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p)).Order());
// files can be deleted now:
File.Delete(libSrc.Path);
@@ -8733,7 +8733,7 @@ public void FileShareDeleteCompatibility_ReadOnlyFiles()
fsDll.Dispose();
- AssertEx.Equal(new[] { "Lib.cs", "Lib.dll" }, Roslyn.Utilities.EnumerableExtensions.Order(Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p))));
+ AssertEx.Equal(new[] { "Lib.cs", "Lib.dll" }, Directory.GetFiles(dir.Path).Select(p => Path.GetFileName(p)).Order());
}
[Fact]
diff --git a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs
index b2808db170bf5..9460fa67eaeb2 100644
--- a/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/Diagnostics/DiagnosticSuppressorTests.cs
@@ -563,7 +563,7 @@ public void TestProgrammaticSuppressionInfo_DiagnosticSuppressor()
Assert.Single(diagnostics);
var programmaticSuppression = diagnostics.Select(d => d.ProgrammaticSuppressionInfo).Single();
Assert.Equal(2, programmaticSuppression.Suppressions.Count);
- var orderedSuppressions = Roslyn.Utilities.EnumerableExtensions.Order(programmaticSuppression.Suppressions).ToImmutableArrayOrEmpty();
+ var orderedSuppressions = programmaticSuppression.Suppressions.Order().ToImmutableArrayOrEmpty();
Assert.Equal(suppressionId, orderedSuppressions[0].Id);
Assert.Equal(suppressor.SuppressionDescriptor.Justification, orderedSuppressions[0].Justification);
Assert.Equal(suppressionId2, orderedSuppressions[1].Id);
diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs
index a6474e1d6859e..f718c080bade6 100644
--- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs
+++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs
@@ -5912,5 +5912,31 @@ public static void Main()
";
CreateCompilation(source).VerifyDiagnostics();
}
+
+ [Fact]
+ public void NameOf_Nested()
+ {
+ var source = """
+ System.Console.WriteLine(C.M());
+ public class C
+ {
+ private C c;
+ public static string M() => nameof(c.c.c);
+ }
+ """;
+
+ var expectedDiagnostic =
+ // (4,15): warning CS0649: Field 'C.c' is never assigned to, and will always have its default value null
+ // private C c;
+ Diagnostic(ErrorCode.WRN_UnassignedInternalField, "c").WithArguments("C.c", "null").WithLocation(4, 15);
+
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "c").VerifyDiagnostics(expectedDiagnostic);
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "c").VerifyDiagnostics(expectedDiagnostic);
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ expectedDiagnostic,
+ // (5,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(c.c.c);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "c").WithArguments("instance member in 'nameof'").WithLocation(5, 40));
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs
index 2587442a62a18..4f7975c981bb2 100644
--- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs
+++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs
@@ -223,5 +223,208 @@ void M()
";
VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics);
}
+
+ [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
+ [Fact]
+ public void NameOfFlow_InstanceMemberFromStatic_Flat()
+ {
+ var source = """
+ public class C
+ {
+ public int Property { get; }
+ public int Field;
+ public event System.Action Event;
+
+ public static string StaticMethod()
+ /**/{
+ return nameof(Property) +
+ nameof(Field) +
+ nameof(Event);
+ }/**/
+ }
+ """;
+
+ var expectedFlowGraph = """
+ Block[B0] - Entry
+ Statements (0)
+ Next (Regular) Block[B1]
+ Block[B1] - Block
+ Predecessors: [B0]
+ Statements (0)
+ Next (Return) Block[B2]
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEvent") (Syntax: 'nameof(Prop ... meof(Event)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyField") (Syntax: 'nameof(Prop ... meof(Field)')
+ Left:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Property)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Field)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Event)')
+ Block[B2] - Exit
+ Predecessors: [B1]
+ Statements (0)
+ """;
+
+ VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None);
+ }
+
+ [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
+ [Fact]
+ public void NameOfFlow_InstanceMemberFromStatic_Flat_MethodGroup()
+ {
+ var source = """
+ public class C
+ {
+ public void Method1() { }
+ public void Method1(int i) { }
+ public void Method2() { }
+ public static void Method2(int i) { }
+
+ public static string StaticMethod()
+ /**/{
+ return nameof(Method1) +
+ nameof(Method2);
+ }/**/
+ }
+ """;
+
+ var expectedFlowGraph = """
+ Block[B0] - Entry
+ Statements (0)
+ Next (Regular) Block[B1]
+ Block[B1] - Block
+ Predecessors: [B0]
+ Statements (0)
+ Next (Return) Block[B2]
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "Method1Method2") (Syntax: 'nameof(Meth ... of(Method2)')
+ Left:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method1") (Syntax: 'nameof(Method1)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method2") (Syntax: 'nameof(Method2)')
+ Block[B2] - Exit
+ Predecessors: [B1]
+ Statements (0)
+ """;
+
+ VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None);
+ }
+
+ [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")]
+ public void NameOfFlow_InstanceMemberFromStatic_Nested()
+ {
+ var source = """
+ public class C
+ {
+ public C1 Property { get; }
+ public C1 Field;
+
+ public static string StaticMethod()
+ /**/{
+ return nameof(Property.Property) +
+ nameof(Property.Field) +
+ nameof(Property.Event) +
+ nameof(Field.Property) +
+ nameof(Field.Field) +
+ nameof(Field.Event);
+ }/**/
+ }
+
+ public class C1
+ {
+ public int Property { get; }
+ public int Field;
+ public event System.Action Event;
+ }
+ """;
+
+ var expectedFlowGraph = """
+ Block[B0] - Entry
+ Statements (0)
+ Next (Regular) Block[B1]
+ Block[B1] - Block
+ Predecessors: [B0]
+ Statements (0)
+ Next (Return) Block[B2]
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventPropertyFieldEvent") (Syntax: 'nameof(Prop ... ield.Event)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventPropertyField") (Syntax: 'nameof(Prop ... ield.Field)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventProperty") (Syntax: 'nameof(Prop ... d.Property)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEvent") (Syntax: 'nameof(Prop ... erty.Event)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyField") (Syntax: 'nameof(Prop ... erty.Field)')
+ Left:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Prop ... y.Property)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Property.Field)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Property.Event)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Field.Property)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Field.Field)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Field.Event)')
+ Block[B2] - Exit
+ Predecessors: [B1]
+ Statements (0)
+ """;
+
+ VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None);
+ }
+
+ [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")]
+ public void NameOfFlow_InstanceMemberFromStatic_Nested_MethodGroup()
+ {
+ var source = """
+ public class C
+ {
+ public C1 Property { get; }
+ public C1 Field;
+ public event System.Action Event;
+
+ public static string StaticMethod()
+ /**/{
+ return nameof(Property.Method) +
+ nameof(Field.Method) +
+ nameof(Event.Invoke);
+ }/**/
+ }
+
+ public class C1
+ {
+ public void Method() { }
+ public void Method(int i) { }
+ }
+ """;
+
+ var expectedFlowGraph = """
+ Block[B0] - Entry
+ Statements (0)
+ Next (Regular) Block[B1]
+ Block[B1] - Block
+ Predecessors: [B0]
+ Statements (0)
+ Next (Return) Block[B2]
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "MethodMethodInvoke") (Syntax: 'nameof(Prop ... ent.Invoke)')
+ Left:
+ IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "MethodMethod") (Syntax: 'nameof(Prop ... eld.Method)')
+ Left:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method") (Syntax: 'nameof(Property.Method)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method") (Syntax: 'nameof(Field.Method)')
+ Right:
+ ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Invoke") (Syntax: 'nameof(Event.Invoke)')
+ Block[B2] - Exit
+ Predecessors: [B1]
+ Statements (0)
+ """;
+
+ VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None);
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs
index 4699165bab2b7..98a9d1f8137a9 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs
@@ -4,13 +4,15 @@
#nullable disable
-using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
-using System.Threading;
-using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
@@ -954,6 +956,315 @@ private static void Use(object o) {}
Assert.Equal(0, symbolInfo.CandidateSymbols.Length);
}
+ [Fact]
+ public void SymbolInfo_InstanceMemberFromStatic_Flat()
+ {
+ var source = """
+ public class C
+ {
+ public int Property { get; }
+ public int Field;
+ public event System.Action Event;
+
+ public static string StaticField =
+ nameof(Property) +
+ nameof(Field) +
+ nameof(Event);
+ }
+ """;
+ var comp = CreateCompilation(source).VerifyDiagnostics();
+
+ var cProperty = comp.GetMember("C.Property");
+ var cField = comp.GetMember("C.Field");
+ var cEvent = comp.GetMember("C.Event");
+
+ var tree = comp.SyntaxTrees.Single();
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source + " ");
+
+ var initializer = tree2.GetRoot().DescendantNodes().OfType().Single();
+
+ var nameofCalls = getNameOfCalls(tree);
+ Assert.Equal(3, nameofCalls.Length);
+ var nameofCalls2 = getNameOfCalls(tree2);
+ Assert.Equal(3, nameofCalls2.Length);
+
+ var model = comp.GetSemanticModel(tree);
+
+ verify(0, "Property", cProperty);
+ verify(1, "Field", cField);
+ verify(2, "Event", cEvent);
+
+ void verify(int index, string expression, Symbol symbol)
+ {
+ var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument.ToString());
+
+ verifySymbolInfo(model.GetSymbolInfo(argument));
+
+ var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument2.ToString());
+
+ Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2));
+
+ verifySymbolInfo(model2.GetSymbolInfo(argument2));
+
+ verifySymbolInfo(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression));
+
+ Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty);
+
+ void verifySymbolInfo(SymbolInfo symbolInfo)
+ {
+ Assert.NotNull(symbolInfo.Symbol);
+ Assert.Same(symbol.GetPublicSymbol(), symbolInfo.Symbol);
+ }
+ }
+
+ static ImmutableArray getNameOfCalls(SyntaxTree tree)
+ {
+ return tree.GetRoot().DescendantNodes().OfType()
+ .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" })
+ .ToImmutableArray();
+ }
+ }
+
+ [Fact]
+ public void SymbolInfo_InstanceMemberFromStatic_Flat_MethodGroup()
+ {
+ var source = """
+ public class C
+ {
+ public void Method1() { }
+ public void Method1(int i) { }
+ public void Method2() { }
+ public static void Method2(int i) { }
+
+ public static string StaticField =
+ nameof(Method1) +
+ nameof(Method2);
+ }
+ """;
+ var comp = CreateCompilation(source).VerifyDiagnostics();
+
+ var cMethods1 = comp.GetMembers("C.Method1");
+ Assert.Equal(2, cMethods1.Length);
+ var cMethods2 = comp.GetMembers("C.Method2");
+ Assert.Equal(2, cMethods2.Length);
+
+ var tree = comp.SyntaxTrees.Single();
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source + " ");
+
+ var initializer = tree2.GetRoot().DescendantNodes().OfType().Single();
+
+ var nameofCalls = getNameOfCalls(tree);
+ Assert.Equal(2, nameofCalls.Length);
+ var nameofCalls2 = getNameOfCalls(tree2);
+ Assert.Equal(2, nameofCalls2.Length);
+
+ var model = comp.GetSemanticModel(tree);
+
+ verify(0, "Method1", cMethods1);
+ verify(1, "Method2", cMethods2);
+
+ void verify(int index, string expression, ImmutableArray symbols)
+ {
+ var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument.ToString());
+
+ verifySymbolInfo(CandidateReason.MemberGroup, model.GetSymbolInfo(argument));
+
+ var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument2.ToString());
+
+ Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2));
+
+ verifySymbolInfo(CandidateReason.MemberGroup, model2.GetSymbolInfo(argument2));
+
+ verifySymbolInfo(CandidateReason.OverloadResolutionFailure, model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression));
+
+ Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty);
+
+ void verifySymbolInfo(CandidateReason reason, SymbolInfo symbolInfo)
+ {
+ Assert.Equal(reason, symbolInfo.CandidateReason);
+ AssertEx.SetEqual(
+ symbols.Select(s => s.GetPublicSymbol()),
+ symbolInfo.CandidateSymbols,
+ Roslyn.Utilities.ReferenceEqualityComparer.Instance);
+ }
+ }
+
+ static ImmutableArray getNameOfCalls(SyntaxTree tree)
+ {
+ return tree.GetRoot().DescendantNodes().OfType()
+ .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" })
+ .ToImmutableArray();
+ }
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")]
+ public void SymbolInfo_InstanceMemberFromStatic_Nested()
+ {
+ var source = """
+ public class C
+ {
+ public C1 Property { get; }
+ public C1 Field;
+
+ public static string StaticField =
+ nameof(Property.Property) +
+ nameof(Property.Field) +
+ nameof(Property.Event) +
+ nameof(Field.Property) +
+ nameof(Field.Field) +
+ nameof(Field.Event);
+ }
+
+ public class C1
+ {
+ public int Property { get; }
+ public int Field;
+ public event System.Action Event;
+ }
+ """;
+ var comp = CreateCompilation(source).VerifyDiagnostics();
+
+ var c1Property = comp.GetMember("C1.Property");
+ var c1Field = comp.GetMember("C1.Field");
+ var c1Event = comp.GetMember("C1.Event");
+
+ var tree = comp.SyntaxTrees.Single();
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source + " ");
+
+ var initializer = tree2.GetRoot().DescendantNodes().OfType().Single();
+
+ var nameofCalls = getNameOfCalls(tree);
+ Assert.Equal(6, nameofCalls.Length);
+ var nameofCalls2 = getNameOfCalls(tree2);
+ Assert.Equal(6, nameofCalls2.Length);
+
+ var model = comp.GetSemanticModel(tree);
+
+ verify(0, "Property.Property", c1Property);
+ verify(1, "Property.Field", c1Field);
+ verify(2, "Property.Event", c1Event);
+ verify(3, "Field.Property", c1Property);
+ verify(4, "Field.Field", c1Field);
+ verify(5, "Field.Event", c1Event);
+
+ void verify(int index, string expression, Symbol symbol)
+ {
+ var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument.ToString());
+
+ verifySymbolInfo(model.GetSymbolInfo(argument));
+
+ var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument2.ToString());
+
+ Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2));
+
+ verifySymbolInfo(model2.GetSymbolInfo(argument2));
+
+ verifySymbolInfo(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression));
+
+ Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty);
+
+ void verifySymbolInfo(SymbolInfo symbolInfo)
+ {
+ Assert.NotNull(symbolInfo.Symbol);
+ Assert.Same(symbol.GetPublicSymbol(), symbolInfo.Symbol);
+ }
+ }
+
+ static ImmutableArray getNameOfCalls(SyntaxTree tree)
+ {
+ return tree.GetRoot().DescendantNodes().OfType()
+ .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" })
+ .ToImmutableArray();
+ }
+ }
+
+ [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")]
+ public void SymbolInfo_InstanceMemberFromStatic_Nested_MethodGroup()
+ {
+ var source = """
+ public class C
+ {
+ public C1 Property { get; }
+ public C1 Field;
+ public event System.Action Event;
+
+ public static string StaticField =
+ nameof(Property.Method) +
+ nameof(Field.Method) +
+ nameof(Event.Invoke);
+ }
+
+ public class C1
+ {
+ public void Method() { }
+ public void Method(int i) { }
+ }
+ """;
+ var comp = CreateCompilation(source).VerifyDiagnostics();
+
+ var c1Methods = comp.GetMembers("C1.Method").ToArray();
+ Assert.Equal(2, c1Methods.Length);
+ var c1Event = comp.GetMember("C1.Event");
+ var actionInvoke = comp.GetWellKnownType(WellKnownType.System_Action).GetMember("Invoke");
+
+ var tree = comp.SyntaxTrees.Single();
+ var tree2 = SyntaxFactory.ParseSyntaxTree(source + " ");
+
+ var initializer = tree2.GetRoot().DescendantNodes().OfType().Single();
+
+ var nameofCalls = getNameOfCalls(tree);
+ Assert.Equal(3, nameofCalls.Length);
+ var nameofCalls2 = getNameOfCalls(tree2);
+ Assert.Equal(3, nameofCalls2.Length);
+
+ var model = comp.GetSemanticModel(tree);
+
+ verify(0, "Property.Method", c1Methods);
+ verify(1, "Field.Method", c1Methods);
+ verify(2, "Event.Invoke", actionInvoke);
+
+ void verify(int index, string expression, params Symbol[] symbols)
+ {
+ var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument.ToString());
+
+ verifySymbolInfo(CandidateReason.MemberGroup, model.GetSymbolInfo(argument));
+
+ var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression;
+ Assert.Equal(expression, argument2.ToString());
+
+ Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2));
+
+ verifySymbolInfo(CandidateReason.MemberGroup, model2.GetSymbolInfo(argument2));
+
+ verifySymbolInfo(CandidateReason.OverloadResolutionFailure, model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression));
+
+ Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty);
+
+ void verifySymbolInfo(CandidateReason reason, SymbolInfo symbolInfo)
+ {
+ Assert.Equal(reason, symbolInfo.CandidateReason);
+ AssertEx.SetEqual(
+ symbols.Select(s => s.GetPublicSymbol()),
+ symbolInfo.CandidateSymbols,
+ Roslyn.Utilities.ReferenceEqualityComparer.Instance);
+ }
+ }
+
+ static ImmutableArray getNameOfCalls(SyntaxTree tree)
+ {
+ return tree.GetRoot().DescendantNodes().OfType()
+ .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" })
+ .ToImmutableArray();
+ }
+ }
+
[Fact]
public void ExtensionMethodConstraintFailed()
{
@@ -1487,5 +1798,580 @@ public void nameof(string x)
var option = TestOptions.ReleaseDll;
CreateCompilation(source, options: option).VerifyDiagnostics();
}
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceInstanceMembersFromStaticMemberInNameof_Flat()
+ {
+ var source = @"
+System.Console.Write(C.M());
+public class C
+{
+ public object Property { get; }
+ public object Field;
+ public event System.Action Event;
+ public void M2() { }
+ public static string M() => nameof(Property)
+ + "","" + nameof(Field)
+ + "","" + nameof(Event)
+ + "","" + nameof(M2)
+ ;
+}";
+ var expectedOutput = "Property,Field,Event,M2";
+
+ CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics();
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceInstanceMembersFromStaticMemberInNameof_Nested()
+ {
+ var source = @"
+System.Console.Write(C.M());
+public class C
+{
+ public C1 Property { get; }
+ public C1 Field;
+ public event System.Action Event;
+ public static string M() => nameof(Property.Property)
+ + "","" + nameof(Property.Field)
+ + "","" + nameof(Property.Method)
+ + "","" + nameof(Property.Event)
+ + "","" + nameof(Field.Property)
+ + "","" + nameof(Field.Field)
+ + "","" + nameof(Field.Method)
+ + "","" + nameof(Field.Event)
+ + "","" + nameof(Event.Invoke)
+ ;
+}
+
+public class C1
+{
+ public int Property { get; }
+ public int Field;
+ public void Method(){}
+ public event System.Action Event;
+}";
+ var expectedOutput = "Property,Field,Method,Event,Property,Field,Method,Event,Invoke";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (8,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(Property.Property)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("instance member in 'nameof'").WithLocation(8, 40),
+ // (9,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Property.Field)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("instance member in 'nameof'").WithLocation(9, 24),
+ // (10,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Property.Method)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("instance member in 'nameof'").WithLocation(10, 24),
+ // (11,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Property.Event)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("instance member in 'nameof'").WithLocation(11, 24),
+ // (12,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Field.Property)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("instance member in 'nameof'").WithLocation(12, 24),
+ // (13,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Field.Field)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("instance member in 'nameof'").WithLocation(13, 24),
+ // (14,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Field.Method)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("instance member in 'nameof'").WithLocation(14, 24),
+ // (15,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Field.Event)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("instance member in 'nameof'").WithLocation(15, 24),
+ // (16,24): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // + "," + nameof(Event.Invoke)
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(16, 24));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void InstanceFromStatic_Lambdas()
+ {
+ var source = """
+ using System;
+ Console.Write(C.Names());
+ public class C
+ {
+ public object Property { get; }
+ public object Field;
+ public event Action Event;
+ public void Method() { }
+ public static string Names()
+ {
+ var lambda1 = static () => nameof(Property);
+ var lambda2 = static (string f = nameof(Field)) => f;
+ var lambda3 = static () => nameof(Event.Invoke);
+ var lambda4 = static (string i = nameof(Event.Invoke)) => i;
+ return lambda1() + "," + lambda2() + "," + lambda3() + "," + lambda4();
+ }
+ }
+ """;
+ var expectedOutput = "Property,Field,Invoke,Invoke";
+
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (12,40): error CS8652: The feature 'lambda optional parameters' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // var lambda2 = static (string f = nameof(Field)) => f;
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "=").WithArguments("lambda optional parameters").WithLocation(12, 40),
+ // (13,43): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // var lambda3 = static () => nameof(Event.Invoke);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(13, 43),
+ // (14,40): error CS8652: The feature 'lambda optional parameters' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // var lambda4 = static (string i = nameof(Event.Invoke)) => i;
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "=").WithArguments("lambda optional parameters").WithLocation(14, 40),
+ // (14,49): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // var lambda4 = static (string i = nameof(Event.Invoke)) => i;
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(14, 49));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void InstanceFromStatic_LocalFunctions()
+ {
+ var source = """
+ using System;
+ Console.Write(C.Names());
+ public class C
+ {
+ public object Property { get; }
+ public object Field;
+ public event Action Event;
+ public void Method() { }
+ public static string Names()
+ {
+ static string local1() => nameof(Property);
+ static string local2(string f = nameof(Field)) => f;
+ static string local3() => nameof(Event.Invoke);
+ static string local4(string i = nameof(Event.Invoke)) => i;
+ return local1() + "," + local2() + "," + local3() + "," + local4();
+ }
+ }
+ """;
+ var expectedOutput = "Property,Field,Invoke,Invoke";
+
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (13,42): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // static string local3() => nameof(Event.Invoke);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(13, 42),
+ // (14,48): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // static string local4(string i = nameof(Event.Invoke)) => i;
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(14, 48));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceInstanceMembersFromFieldInitializerInNameof()
+ {
+ var source = @"
+System.Console.Write(new C().S);
+public class C
+{
+ public string S { get; } = nameof(S.Length);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (5,39): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public string S { get; } = nameof(S.Length);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(5, 39));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceInstanceMembersFromAttributeInNameof()
+ {
+ var source = @"
+var p = new C().P; // 1
+public class C
+{
+ [System.Obsolete(nameof(S.Length))]
+ public int P { get; }
+ public string S { get; }
+}";
+ var expectedDiagnostics = new[]
+ {
+ // (2,9): warning CS0618: 'C.P' is obsolete: 'Length'
+ // var p = new C().P; // 1
+ Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "new C().P").WithArguments("C.P", "Length").WithLocation(2, 9)
+ };
+ CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (5,29): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [System.Obsolete(nameof(S.Length))]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(5, 29));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceInstanceMembersFromConstructorInitializersInNameof()
+ {
+ var source = @"
+System.Console.WriteLine(new C().S);
+public class C
+{
+ public C(string s){ S = s; }
+ public C() : this(nameof(S.Length)){}
+ public string S { get; }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (6,30): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public C() : this(nameof(S.Length)){}
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(6, 30));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanAccessStructInstancePropertyInLambdaInNameof()
+ {
+ var source = @"
+using System;
+
+string s = ""str"";
+new S().M(ref s);
+
+public struct S
+{
+ public string P { get; }
+ public void M(ref string x)
+ {
+ Func func = () => nameof(P.Length);
+ Console.WriteLine(func());
+ }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (12,42): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // Func func = () => nameof(P.Length);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("instance member in 'nameof'").WithLocation(12, 42));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameof1()
+ {
+ var source = @"
+System.Console.WriteLine(new C().M());
+public class C
+{
+ public C Prop { get; }
+ public static int StaticProp { get; }
+ public string M() => nameof(Prop.StaticProp);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticProp").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (7,33): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public string M() => nameof(Prop.StaticProp);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("instance member in 'nameof'").WithLocation(7, 33));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameof2()
+ {
+ var source = @"
+System.Console.WriteLine(C.M());
+public class C
+{
+ public C Prop { get; }
+ public static int StaticProp { get; }
+ public static string M() => nameof(Prop.StaticProp);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticProp").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (7,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(Prop.StaticProp);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("instance member in 'nameof'").WithLocation(7, 40),
+ // (7,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(Prop.StaticProp);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("instance member in 'nameof'").WithLocation(7, 40));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameof3()
+ {
+ var source = @"
+System.Console.WriteLine(C.M());
+public class C
+{
+ public C Prop { get; }
+ public static string M() => nameof(Prop.M);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "M").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "M").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (6,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(Prop.M);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("instance member in 'nameof'").WithLocation(6, 40));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameof4()
+ {
+ var source = @"
+System.Console.WriteLine(new C().M());
+public class C
+{
+ public C Prop { get; }
+ public static void StaticMethod(){}
+ public string M() => nameof(Prop.StaticMethod);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics();
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp11()
+ {
+ var source = @"
+public class C
+{
+ public string S { get; }
+ public static string M() => nameof(S.Length);
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (5,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public static string M() => nameof(S.Length);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(5, 40));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotReferenceInstanceMembersFromFieldInitializerInNameofInCSharp11()
+ {
+ var source = @"
+public class C
+{
+ public string S { get; } = nameof(S.Length);
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (4,39): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public string S { get; } = nameof(S.Length);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(4, 39));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotReferenceInstanceMembersFromAttributeInNameofInCSharp11()
+ {
+ var source = @"
+public class C
+{
+ [System.Obsolete(nameof(S.Length))]
+ public int P { get; }
+ public string S { get; }
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (4,29): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [System.Obsolete(nameof(S.Length))]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(4, 29));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotReferenceInstanceMembersFromConstructorInitializersInNameofInCSharp11()
+ {
+ var source = @"
+public class C
+{
+ public C(string s){}
+ public C() : this(nameof(S.Length)){}
+ public string S { get; }
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (5,30): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public C() : this(nameof(S.Length)){}
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("instance member in 'nameof'").WithLocation(5, 30));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotAccessStructInstancePropertyInLambdaInNameofInCSharp11()
+ {
+ var source = @"
+using System;
+
+public struct S
+{
+ public string P { get; }
+ public void M(ref string x)
+ {
+ Func func = () => nameof(P.Length);
+ }
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (9,42): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // Func func = () => nameof(P.Length);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("instance member in 'nameof'").WithLocation(9, 42));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCannotReferenceStaticPropertyFromInstanceMemberInNameofInCSharp11()
+ {
+ var source = @"
+public class C
+{
+ public C Prop { get; }
+ public static int StaticProp { get; }
+ public string M() => nameof(Prop.StaticProp);
+}";
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (6,33): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public string M() => nameof(Prop.StaticProp);
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("instance member in 'nameof'").WithLocation(6, 33));
+ }
+
+ [Fact]
+ public void TestCanReferenceStaticMethodFromInstanceMemberInNameofInCSharp11()
+ {
+ var source = @"
+System.Console.WriteLine(new C().M());
+public class C
+{
+ public C Prop { get; }
+ public static void StaticMethod(){}
+ public string M() => nameof(Prop.StaticMethod);
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ }
+
+ [Fact]
+ public void TestCanAccessRefParameterInLambdaInNameof()
+ {
+ var source = @"
+using System;
+
+string s = ""str"";
+new S().M(ref s);
+
+public struct S
+{
+ public void M(ref string x)
+ {
+ Func func = () => nameof(x.Length);
+ Console.WriteLine(func());
+ }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "Length").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics();
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes1()
+ {
+ var source = @"
+using System;
+using System.Reflection;
+Console.WriteLine(typeof(C).GetProperty(""Prop"").GetCustomAttribute().S);
+class C
+{
+ [Attr(nameof(Prop.StaticMethod))]
+ public C Prop { get; }
+ public static void StaticMethod(){}
+}
+class Attr : Attribute
+{
+ public readonly string S;
+ public Attr(string s) { S = s; }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (7,18): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [Attr(nameof(Prop.StaticMethod))]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("instance member in 'nameof'").WithLocation(7, 18));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes2()
+ {
+ var source = @"
+using System;
+using System.Reflection;
+Console.WriteLine(typeof(C).GetProperty(""Prop"").GetCustomAttribute().S);
+class C
+{
+ [Attr(nameof(Prop.Prop))]
+ public static C Prop { get; }
+}
+class Attr : Attribute
+{
+ public readonly string S;
+ public Attr(string s) { S = s; }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Prop").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (7,18): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [Attr(nameof(Prop.Prop))]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.Prop").WithArguments("instance member in 'nameof'").WithLocation(7, 18));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes3()
+ {
+ var source = @"
+using System;
+using System.Reflection;
+Console.WriteLine(typeof(C).GetCustomAttribute().S);
+[Attr(nameof(C.Prop.Prop))]
+class C
+{
+ public static C Prop { get; }
+}
+class Attr : Attribute
+{
+ public readonly string S;
+ public Attr(string s) { S = s; }
+}";
+ CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Prop").VerifyDiagnostics();
+ CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop").VerifyDiagnostics();
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
+ // (5,14): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [Attr(nameof(C.Prop.Prop))]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "C.Prop.Prop").WithArguments("instance member in 'nameof'").WithLocation(5, 14));
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler1()
+ {
+ var source = @"
+class C
+{
+ [Attr(nameof(Method().Method))]
+ T Method() where T : C => default;
+}
+class Attr : System.Attribute { public Attr(string s) {} }";
+ var expectedDiagnostics = new[]
+ {
+ // (4,18): error CS0411: The type arguments for method 'C.Method()' cannot be inferred from the usage. Try specifying the type arguments explicitly.
+ // [Attr(nameof(Method().Method))]
+ Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Method").WithArguments("C.Method()").WithLocation(4, 18)
+ };
+ CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics);
+ }
+
+ [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")]
+ public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2()
+ {
+ var source = @"
+class C
+{
+ [Attr(nameof(Method().Method))]
+ T Method() where T : C => default;
+}
+class Attr : System.Attribute { public Attr(string s) {} }";
+ var expectedDiagnostics = new[]
+ {
+ // (4,18): error CS8082: Sub-expression cannot be used in an argument to nameof.
+ // [Attr(nameof(Method().Method))]
+ Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "Method()").WithLocation(4, 18)
+ };
+ CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics);
+ CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics);
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs
index 61075f1fb3320..764b90baddebe 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ObjectAndCollectionInitializerTests.cs
@@ -3510,7 +3510,7 @@ where node.IsKind(SyntaxKind.CollectionInitializerExpression)
Assert.Equal(2, symbolInfo.CandidateSymbols.Length);
Assert.Equal(new[] {"void X.Add(System.Collections.Generic.List x)",
"void X.Add(X x)"},
- Roslyn.Utilities.EnumerableExtensions.Order(symbolInfo.CandidateSymbols.Select(s => s.ToTestDisplayString())).ToArray());
+ symbolInfo.CandidateSymbols.Select(s => s.ToTestDisplayString()).Order().ToArray());
}
[WorkItem(529787, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/529787")]
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs
index 28654bc28f2b7..e3905450d2eff 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/PrimaryConstructorTests.cs
@@ -3064,6 +3064,370 @@ public static void Main()
comp.VerifyDiagnostics();
}
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_01([CombinatorialValues("class", "struct", "record", "record class", "record struct")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[method: A]
+" + declaration + @" C
+ ();
+";
+ var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
+ comp.VerifyDiagnostics();
+ verify(comp);
+
+ comp = CreateCompilation(source, parseOptions: TestOptions.RegularNext);
+ comp.VerifyDiagnostics();
+ verify(comp);
+
+ comp = CreateCompilation(source, parseOptions: TestOptions.Regular11);
+
+ if (declaration is "class" or "struct")
+ {
+ comp.VerifyDiagnostics(
+ // (9,5): error CS8652: The feature 'primary constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // ();
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "()").WithArguments("primary constructors").WithLocation(9, 5)
+ );
+ }
+ else
+ {
+ comp.VerifyDiagnostics(
+ // (7,2): error CS8652: The feature 'primary constructors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // [method: A]
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "method").WithArguments("primary constructors").WithLocation(7, 2)
+ );
+ }
+
+ verify(comp);
+
+ static void verify(CSharpCompilation comp)
+ {
+ var c = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C");
+ Assert.Empty(c.GetAttributes());
+ Assert.True(c.HasPrimaryConstructor);
+ Assert.Equal("A", c.PrimaryConstructor.GetAttributes().Single().ToString());
+ Assert.True(c.Constructors.Where(ctor => ctor != c.PrimaryConstructor).All(ctor => ctor.GetAttributes().IsEmpty));
+ }
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_02([CombinatorialValues("class C();", "struct C();", "record C();", "record class C();", "record struct C();")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[return: A]
+" + declaration + @"
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (7,2): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type, method'. All attributes in this block will be ignored.
+ // [return: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "type, method").WithLocation(7, 2)
+ );
+
+ var c = comp.GetTypeByMetadataName("C");
+ Assert.Empty(c.GetAttributes());
+ Assert.True(c.Constructors.All(ctor => ctor.GetAttributes().IsEmpty));
+ Assert.True(c.Constructors.All(ctor => ctor.GetReturnTypeAttributes().IsEmpty));
+ }
+
+ [Fact]
+ public void AttributesOnPrimaryConstructor_03()
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[method: A]
+[return: A]
+interface I();
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (7,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(7, 2),
+ // (8,2): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [return: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "type").WithLocation(8, 2),
+ // (9,12): error CS9122: Unexpected parameter list.
+ // interface I();
+ Diagnostic(ErrorCode.ERR_UnexpectedParameterList, "()").WithLocation(9, 12)
+ );
+
+ var i = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("I");
+ Assert.Empty(i.GetAttributes());
+ Assert.False(i.HasPrimaryConstructor);
+ Assert.Null(i.PrimaryConstructor);
+ Assert.Empty(i.Constructors);
+ }
+
+ [Fact]
+ public void AttributesOnPrimaryConstructor_04()
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[method: A]
+[return: A]
+enum E();
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (7,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(7, 2),
+ // (8,2): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [return: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "type").WithLocation(8, 2),
+ // (9,7): error CS1514: { expected
+ // enum E();
+ Diagnostic(ErrorCode.ERR_LbraceExpected, "(").WithLocation(9, 7),
+ // (9,7): error CS1513: } expected
+ // enum E();
+ Diagnostic(ErrorCode.ERR_RbraceExpected, "(").WithLocation(9, 7),
+ // (9,7): error CS8803: Top-level statements must precede namespace and type declarations.
+ // enum E();
+ Diagnostic(ErrorCode.ERR_TopLevelStatementAfterNamespaceOrType, "();").WithLocation(9, 7),
+ // (9,8): error CS1525: Invalid expression term ')'
+ // enum E();
+ Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(9, 8)
+ );
+
+ var e = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("E");
+ Assert.Empty(e.GetAttributes());
+ Assert.False(e.HasPrimaryConstructor);
+ Assert.Null(e.PrimaryConstructor);
+ Assert.True(e.Constructors.All(ctor => ctor.GetAttributes().IsEmpty));
+ Assert.True(e.Constructors.All(ctor => ctor.GetReturnTypeAttributes().IsEmpty));
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_05([CombinatorialValues("class C;", "struct C;", "record C;", "record class C;", "record struct C;", "interface C;", "enum C;")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[method: A]
+[return: A]
+" + declaration + @"
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (7,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(7, 2),
+ // (8,2): warning CS0657: 'return' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [return: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "return").WithArguments("return", "type").WithLocation(8, 2)
+ );
+
+ var c = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C");
+ Assert.Empty(c.GetAttributes());
+ Assert.False(c.HasPrimaryConstructor);
+ Assert.Null(c.PrimaryConstructor);
+ Assert.True(c.Constructors.All(ctor => ctor.GetAttributes().IsEmpty));
+ Assert.True(c.Constructors.All(ctor => ctor.GetReturnTypeAttributes().IsEmpty));
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_06([CombinatorialValues("class C();", "struct C();", "record C();", "record class C();", "record struct C();")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[type: A]
+" + declaration + @"
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+
+ var c = comp.GetTypeByMetadataName("C");
+ Assert.Equal("A", c.GetAttributes().Single().ToString());
+ Assert.True(c.Constructors.All(ctor => ctor.GetAttributes().IsEmpty));
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_07([CombinatorialValues("class C();", "struct C();", "record C();", "record class C();", "record struct C();")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[A]
+" + declaration + @"
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+
+ var c = comp.GetTypeByMetadataName("C");
+ Assert.Equal("A", c.GetAttributes().Single().ToString());
+ Assert.True(c.Constructors.All(ctor => ctor.GetAttributes().IsEmpty));
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_08([CombinatorialValues("class", "struct", "record", "record class", "record struct")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class B : System.Attribute
+{
+}
+
+[method: A]
+partial " + declaration + @" C1();
+
+[method: B]
+partial " + declaration + @" C1;
+
+[method: B]
+partial " + declaration + @" C2;
+
+[method: A]
+partial " + declaration + @" C2();
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (15,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: B]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(15, 2),
+ // (18,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: B]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(18, 2)
+ );
+
+ var c1 = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C1");
+ Assert.Empty(c1.GetAttributes());
+ Assert.True(c1.HasPrimaryConstructor);
+ Assert.Equal("A", c1.PrimaryConstructor.GetAttributes().Single().ToString());
+ Assert.True(c1.Constructors.Where(ctor => ctor != c1.PrimaryConstructor).All(ctor => ctor.GetAttributes().IsEmpty));
+
+ var c2 = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C2");
+ Assert.Empty(c2.GetAttributes());
+ Assert.True(c2.HasPrimaryConstructor);
+ Assert.Equal("A", c2.PrimaryConstructor.GetAttributes().Single().ToString());
+ Assert.True(c2.Constructors.Where(ctor => ctor != c2.PrimaryConstructor).All(ctor => ctor.GetAttributes().IsEmpty));
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void AttributesOnPrimaryConstructor_09([CombinatorialValues("class", "struct", "record", "record class", "record struct")] string declaration)
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+}
+
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class B : System.Attribute
+{
+}
+
+[method: A]
+partial " + declaration + @" C1();
+
+#line 100
+[method: B]
+partial " + declaration + @" C1
+#line 200
+ ();
+
+[method: B]
+partial " + declaration + @" C2();
+
+#line 300
+[method: A]
+partial " + declaration + @" C2
+#line 400
+ ();
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // (100,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: B]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(100, 2),
+ // (200,5): error CS8863: Only a single partial type declaration may have a parameter list
+ // ();
+ Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "()").WithLocation(200, 5),
+ // (300,2): warning CS0657: 'method' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'type'. All attributes in this block will be ignored.
+ // [method: A]
+ Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "method").WithArguments("method", "type").WithLocation(300, 2),
+ // (400,5): error CS8863: Only a single partial type declaration may have a parameter list
+ // ();
+ Diagnostic(ErrorCode.ERR_MultipleRecordParameterLists, "()").WithLocation(400, 5)
+ );
+
+ var c1 = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C1");
+ Assert.Empty(c1.GetAttributes());
+ Assert.True(c1.HasPrimaryConstructor);
+ Assert.Equal("A", c1.PrimaryConstructor.GetAttributes().Single().ToString());
+ Assert.True(c1.Constructors.Where(ctor => ctor != c1.PrimaryConstructor).All(ctor => ctor.GetAttributes().IsEmpty));
+
+ var c2 = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C2");
+ Assert.Empty(c2.GetAttributes());
+ Assert.True(c2.HasPrimaryConstructor);
+ Assert.Equal("B", c2.PrimaryConstructor.GetAttributes().Single().ToString());
+ Assert.True(c2.Constructors.Where(ctor => ctor != c2.PrimaryConstructor).All(ctor => ctor.GetAttributes().IsEmpty));
+ }
+
+ [Fact]
+ public void AttributesOnPrimaryConstructor_10_NameofParameter()
+ {
+ string source = @"
+[System.AttributeUsage(System.AttributeTargets.All, AllowMultiple = true) ]
+public class A : System.Attribute
+{
+ public A(string x){}
+}
+
+[method: A(nameof(someParam))]
+class C(int someParam)
+{
+ int X = someParam;
+}
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics();
+
+ var c = (SourceNamedTypeSymbol)comp.GetTypeByMetadataName("C");
+ Assert.Equal(@"A(""someParam"")", c.PrimaryConstructor.GetAttributes().Single().ToString());
+ }
+
[Fact]
public void AnalyzerActions_01_Class()
{
@@ -15430,5 +15794,279 @@ public S3(object o) : this()
Diagnostic(ErrorCode.ERR_RecordStructConstructorCallsDefaultConstructor, "this").WithLocation(6, 27)
);
}
+
+ [Fact]
+ public void StructLayout_01()
+ {
+ string source = @"
+using System.Runtime.InteropServices;
+
+[StructLayout(LayoutKind.Explicit)]
+struct S(int x, int y)
+{
+ int X = x;
+ int Y => y;
+
+ [FieldOffset(8)]
+ int Z = 0;
+}
+";
+ var comp = CreateCompilation(source);
+ comp.VerifyDiagnostics(
+ // We might want to adjust the warning depending on what we decide to do for
+ // https://github.com/dotnet/csharplang/blob/main/proposals/primary-constructors.md#field-targeting-attributes-for-captured-primary-constructor-parameters.
+ //
+ // If we decide to support attributes for capture fields, consider testing
+ // ERR_MarshalUnmanagedTypeNotValidForFields
+ // ERR_StructOffsetOnBadStruct
+ // ERR_DoNotUseFixedBufferAttr
+
+ // (5,21): error CS0625: 'S.P': instance field in types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute
+ // struct S(int x, int y)
+ Diagnostic(ErrorCode.ERR_MissingStructOffset, "y").WithArguments("S.P").WithLocation(5, 21),
+ // (7,9): error CS0625: 'S.X': instance field in types marked with StructLayout(LayoutKind.Explicit) must have a FieldOffset attribute
+ // int X = x;
+ Diagnostic(ErrorCode.ERR_MissingStructOffset, "X").WithArguments("S.X").WithLocation(7, 9)
+ );
+ }
+
+ [Fact]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/67162")]
+ public void StructLayout_02()
+ {
+ string source1 = @"
+public partial struct S(int x)
+{
+ int X => x;
+}
+";
+ string source2 = @"
+public partial struct S
+{
+ public int Y;
+}
+";
+ verify1(source1, source2, validate2);
+ verify1(source1 + source2, "", validate2);
+ verify1(source2, source1, validate3);
+ verify1(source2 + source1, "", validate3);
+
+ void verify1(string source1, string source2, Action validator)
+ {
+ var comp = CreateCompilation(new[] { source1, source2 });
+ CompileAndVerify(comp, symbolValidator: validator, sourceSymbolValidator: validator).VerifyDiagnostics(
+ // 0.cs(2,23): warning CS0282: There is no defined ordering between fields in multiple declarations of partial struct 'S'. To specify an ordering, all instance fields must be in the same declaration.
+ // public partial struct S(int x)
+ Diagnostic(ErrorCode.WRN_SequentialOnPartialClass, "S").WithArguments("S").WithLocation(2, 23)
+ );
+ }
+
+ void validate2(ModuleSymbol m)
+ {
+ var fields = m.GlobalNamespace.GetTypeMember("S").GetMembers().OfType().ToArray();
+ Assert.Equal(2, fields.Length);
+ Assert.Equal("P", fields[0].Name);
+ Assert.Equal("Y", fields[1].Name);
+ }
+
+ void validate3(ModuleSymbol m)
+ {
+ var fields = m.GlobalNamespace.GetTypeMember("S").GetMembers().OfType().ToArray();
+ Assert.Equal(2, fields.Length);
+ Assert.Equal("Y", fields[0].Name);
+ Assert.Equal("P", fields[1].Name);
+ }
+ }
+
+ [Fact]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/67162")]
+ public void StructLayout_03()
+ {
+ string source1 = @"
+public partial struct S(int x)
+{
+}
+";
+ string source2 = @"
+public partial struct S
+{
+ int X = x;
+}
+";
+ verify1(source1, source2, validate2);
+ verify1(source1 + source2, "", validate2);
+ verify1(source2, source1, validate2);
+ verify1(source2 + source1, "", validate2);
+
+ void verify1(string source1, string source2, Action validator)
+ {
+ var comp = CreateCompilation(new[] { source1, source2 });
+ CompileAndVerify(comp, symbolValidator: validator, sourceSymbolValidator: validator).VerifyDiagnostics();
+ }
+
+ void validate2(ModuleSymbol m)
+ {
+ Assert.Equal(1, m.GlobalNamespace.GetTypeMember("S").GetMembers().OfType().Count());
+ }
+ }
+
+ [Fact]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/67162")]
+ public void StructLayout_04()
+ {
+ string source1 = @"
+public partial struct S(int x)
+{
+ int X => x;
+ public int Y;
+}
+";
+ string source2 = @"
+public partial struct S
+{
+}
+";
+ verify1(source1, source2, validate2);
+ verify1(source1 + source2, "", validate2);
+ verify1(source2, source1, validate2);
+ verify1(source2 + source1, "", validate2);
+
+ void verify1(string source1, string source2, Action validator)
+ {
+ var comp = CreateCompilation(new[] { source1, source2 });
+ CompileAndVerify(comp, symbolValidator: validator, sourceSymbolValidator: validator).VerifyDiagnostics();
+ }
+
+ void validate2(ModuleSymbol m)
+ {
+ var fields = m.GlobalNamespace.GetTypeMember("S").GetMembers().OfType().ToArray();
+ Assert.Equal(2, fields.Length);
+ Assert.Equal("P", fields[0].Name);
+ Assert.Equal("Y", fields[1].Name);
+ }
+ }
+
+ [Fact]
+ [WorkItem("https://github.com/dotnet/roslyn/issues/67162")]
+ public void StructLayout_05()
+ {
+ string source1 = @"
+public partial struct S(int x)
+{
+ int X => x;
+}
+";
+ string source2 = @"
+public partial struct S
+{
+ public int Y;
+}
+";
+ string source3 = @"
+public partial struct S
+{
+ public int Z;
+}
+";
+ verify1(source1, source2, source3);
+ verify1(source1 + source2, source3, "");
+ verify1(source1 + source2 + source3, "", "");
+
+ verify1(source1, source3, source2);
+ verify1(source1 + source3, source2, "");
+ verify1(source1 + source3 + source2, "", "");
+
+ verify1(source2, source1, source3);
+ verify1(source2 + source1, source3, "");
+ verify1(source2 + source1 + source3, "", "");
+
+ verify1(source2, source3, source1);
+ verify1(source2 + source3, source1, "");
+ verify1(source2 + source3 + source1, "", "");
+
+ verify1(source3, source1, source2);
+ verify1(source3 + source1, source2, "");
+ verify1(source3 + source1 + source2, "", "");
+
+ verify1(source3, source2, source1);
+ verify1(source3 + source2, source1, "");
+ verify1(source3 + source2 + source1, "", "");
+
+ void verify1(string source1, string source2, string source3)
+ {
+ var comp = CreateCompilation(new[] { source1, source2, source3 });
+ comp.VerifyDiagnostics(
+ // 0.cs(2,23): warning CS0282: There is no defined ordering between fields in multiple declarations of partial struct 'S'. To specify an ordering, all instance fields must be in the same declaration.
+ // public partial struct S(int x)
+ Diagnostic(ErrorCode.WRN_SequentialOnPartialClass, "S").WithArguments("S").WithLocation(2, 23)
+ );
+ }
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void RestrictedType_01([CombinatorialValues("class", "struct")] string declaration)
+ {
+ var src1 = @"
+" + declaration + @" C1
+(System.ArgIterator a)
+{
+ void M()
+ {
+ _ = a;
+ }
+}
+
+" + declaration + @" C2
+(System.ArgIterator b)
+{
+ void M()
+ {
+ System.Action d = () => _ = b;
+ }
+}
+
+" + declaration + @" C3
+(System.ArgIterator c)
+{
+ System.Action d = () => _ = c;
+}
+
+#pragma warning disable CS" + UnreadParameterWarning() + @" // Parameter 'z' is unread.
+" + declaration + @" C4(System.ArgIterator z)
+{
+}
+";
+ var comp = CreateCompilation(src1, targetFramework: TargetFramework.DesktopLatestExtended);
+ comp.VerifyDiagnostics(
+ // (7,13): error CS9136: Cannot use primary constructor parameter of type 'ArgIterator' inside an instance member
+ // _ = a;
+ Diagnostic(ErrorCode.ERR_UnsupportedPrimaryConstructorParameterCapturingRefAny, "a").WithArguments("System.ArgIterator").WithLocation(7, 13),
+ // (16,37): error CS4013: Instance of type 'ArgIterator' cannot be used inside a nested function, query expression, iterator block or async method
+ // System.Action d = () => _ = b;
+ Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "b").WithArguments("System.ArgIterator").WithLocation(16, 37),
+ // (23,33): error CS4013: Instance of type 'ArgIterator' cannot be used inside a nested function, query expression, iterator block or async method
+ // System.Action d = () => _ = c;
+ Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "c").WithArguments("System.ArgIterator").WithLocation(23, 33)
+ );
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public void RestrictedType_02([CombinatorialValues("record", "record class", "record struct")] string keyword)
+ {
+ var src1 = @"
+" + keyword + @" C1
+(System.ArgIterator x)
+{
+}
+";
+ var comp = CreateCompilation(src1, targetFramework: TargetFramework.NetCoreApp);
+ comp.VerifyDiagnostics(
+ // (3,2): error CS0610: Field or property cannot be of type 'ArgIterator'
+ // (System.ArgIterator x)
+ Diagnostic(ErrorCode.ERR_FieldCantBeRefAny, "System.ArgIterator").WithArguments("System.ArgIterator").WithLocation(3, 2)
+ );
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs
index f35bd414f7716..fe6c672902c0a 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs
@@ -13102,18 +13102,6 @@ static void MT2() where T : I1
targetFramework: _supportingFramework);
compilation1.VerifyDiagnostics(
- // (14,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(this.P01);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P01").WithArguments("I1.P01").WithLocation(14, 20),
- // (15,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(this.P04);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P04").WithArguments("I1.P04").WithLocation(15, 20),
- // (28,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(x.P01);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P01").WithArguments("I1.P01").WithLocation(28, 20),
- // (30,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(x.P04);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P04").WithArguments("I1.P04").WithLocation(30, 20),
// (35,20): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter
// _ = nameof(T.P03);
Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(35, 20),
@@ -13984,18 +13972,6 @@ static void MT2() where T : I1
targetFramework: _supportingFramework);
compilation1.VerifyDiagnostics(
- // (14,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(this.P01);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P01").WithArguments("I1.P01").WithLocation(14, 20),
- // (15,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(this.P04);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P04").WithArguments("I1.P04").WithLocation(15, 20),
- // (28,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(x.P01);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P01").WithArguments("I1.P01").WithLocation(28, 20),
- // (30,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead
- // _ = nameof(x.P04);
- Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P04").WithArguments("I1.P04").WithLocation(30, 20),
// (35,20): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter
// _ = nameof(T.P03);
Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(35, 20),
diff --git a/src/Compilers/CSharp/csc/AnyCpu/csc.csproj b/src/Compilers/CSharp/csc/AnyCpu/csc.csproj
index f159446c495ec..621378e9e9089 100644
--- a/src/Compilers/CSharp/csc/AnyCpu/csc.csproj
+++ b/src/Compilers/CSharp/csc/AnyCpu/csc.csproj
@@ -3,7 +3,7 @@
Exe
- $(SourceBuildTargetFrameworksNetFx)
+ $(SourceBuildToolsetTargetFrameworks);net472
false
true
diff --git a/src/Compilers/Core/CodeAnalysisTest/Collections/TopologicalSortTests.cs b/src/Compilers/Core/CodeAnalysisTest/Collections/TopologicalSortTests.cs
index 8531686f0d9b0..f17755162b283 100644
--- a/src/Compilers/Core/CodeAnalysisTest/Collections/TopologicalSortTests.cs
+++ b/src/Compilers/Core/CodeAnalysisTest/Collections/TopologicalSortTests.cs
@@ -2,13 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Shared.Collections;
using Roslyn.Test.Utilities;
using Xunit;
@@ -16,6 +15,12 @@ namespace Microsoft.CodeAnalysis.UnitTests.Collections
{
public class TopologicalSortTests
{
+ private TopologicalSortAddSuccessors GetAddSuccessorsFunction(int[][] successors)
+ => GetAddSuccessorsFunction(successors, i => i);
+
+ private static TopologicalSortAddSuccessors GetAddSuccessorsFunction(T[][] successors, Func toInt)
+ => (ref TemporaryArray builder, T value) => builder.AddRange(successors[toInt(value)].ToImmutableArray());
+
[Fact]
public void Test01()
{
@@ -29,8 +34,8 @@ public void Test01()
/* 5 */ new int[] { 0, 2 },
};
- Func> succF = x => successors[x];
- var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 4, 5 }, i => succF(i).ToImmutableArray(), out var sorted);
+ var succF = GetAddSuccessorsFunction(successors);
+ var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 4, 5 }, succF, out var sorted);
Assert.True(wasAcyclic);
AssertTopologicallySorted(sorted, succF, "Test01");
Assert.Equal(6, sorted.Length);
@@ -50,8 +55,8 @@ public void Test01b()
/* 5 */ new string[] { "0", "2" },
};
- Func> succF = x => successors[int.Parse(x)];
- var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { "4", "5" }, i => succF(i).ToImmutableArray(), out var sorted);
+ var succF = GetAddSuccessorsFunction(successors, x => int.Parse(x));
+ var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { "4", "5" }, succF, out var sorted);
Assert.True(wasAcyclic);
AssertTopologicallySorted(sorted, succF, "Test01");
Assert.Equal(6, sorted.Length);
@@ -73,8 +78,8 @@ public void Test02()
/* 7 */ new int[] { }
};
- Func> succF = x => successors[x];
- var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 1, 6 }, i => succF(i).ToImmutableArray(), out var sorted);
+ var succF = GetAddSuccessorsFunction(successors);
+ var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 1, 6 }, succF, out var sorted);
Assert.True(wasAcyclic);
AssertTopologicallySorted(sorted, succF, "Test02");
Assert.Equal(7, sorted.Length);
@@ -97,7 +102,8 @@ public void TestCycle()
};
// 1 -> 4 -> 3 -> 5 -> 1
- var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 1 }, x => successors[x].ToImmutableArray(), out var sorted);
+ var succF = GetAddSuccessorsFunction(successors);
+ var wasAcyclic = TopologicalSort.TryIterativeSort(new[] { 1 }, succF, out var sorted);
Assert.False(wasAcyclic);
}
@@ -140,8 +146,8 @@ public void TestRandom(int seed)
}
// Perform a topological sort and check it.
- Func> succF = x => successors[x];
- var wasAcyclic = TopologicalSort.TryIterativeSort(Enumerable.Range(0, numberOfNodes).ToArray(), i => succF(i).ToImmutableArray(), out var sorted);
+ var succF = GetAddSuccessorsFunction(successors);
+ var wasAcyclic = TopologicalSort.TryIterativeSort(Enumerable.Range(0, numberOfNodes).ToArray(), succF, out var sorted);
Assert.True(wasAcyclic);
Assert.Equal(numberOfNodes, sorted.Length);
AssertTopologicallySorted(sorted, succF, $"TestRandom(seed: {seed})");
@@ -155,7 +161,7 @@ public void TestRandom(int seed)
// time.
successors[possibleSort[0]] = successors[possibleSort[0]].Concat(new int[] { possibleSort[numberOfNodes - 1] }).ToArray();
- wasAcyclic = TopologicalSort.TryIterativeSort(Enumerable.Range(0, numberOfNodes).ToArray(), i => succF(i).ToImmutableArray(), out sorted);
+ wasAcyclic = TopologicalSort.TryIterativeSort(Enumerable.Range(0, numberOfNodes).ToArray(), succF, out sorted);
Assert.False(wasAcyclic);
// where
@@ -203,13 +209,18 @@ public void TestLots()
}
}
- private void AssertTopologicallySorted(ImmutableArray sorted, Func> successors, string message = null)
+ private void AssertTopologicallySorted(ImmutableArray sorted, TopologicalSortAddSuccessors addSuccessors, string? message = null)
{
var seen = new HashSet();
+ using var successors = TemporaryArray.Empty;
for (int i = sorted.Length - 1; i >= 0; i--)
{
var n = sorted[i];
- foreach (var succ in successors(n))
+
+ successors.Clear();
+ addSuccessors(ref successors.AsRef(), n);
+
+ foreach (var succ in successors)
{
Assert.True(seen.Contains(succ), message);
}
diff --git a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
index b25c8696df1f3..76f8c63559e8e 100644
--- a/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
+++ b/src/Compilers/Core/MSBuildTask/Microsoft.Build.Tasks.CodeAnalysis.csproj
@@ -6,7 +6,7 @@
Library
Microsoft.CodeAnalysis.BuildTasks
en-US
- $(SourceBuildTargetFrameworksNetFx)
+ $(SourceBuildToolsetTargetFrameworks);net472
true
- $(SourceBuildTargetFrameworksNetFx)
+ net472;$(SourceBuildToolsetTargetFramework)
true
Microsoft.Net.Compilers.Toolset
@@ -51,10 +51,10 @@
<_File Include="@(DesktopCompilerArtifact)" TargetDir="tasks/net472"/>
<_File Include="@(DesktopCompilerResourceArtifact)" TargetDir="tasks/net472"/>
- <_File Include="@(CoreClrCompilerBuildArtifact)" TargetDir="tasks/$(TargetFramework)"/>
- <_File Include="@(CoreClrCompilerToolsArtifact)" TargetDir="tasks/$(TargetFramework)"/>
- <_File Include="@(CoreClrCompilerBinArtifact)" TargetDir="tasks/$(TargetFramework)/bincore"/>
- <_File Include="@(CoreClrCompilerBinRuntimesArtifact)" TargetDir="tasks/$(TargetFramework)/bincore/runtimes"/>
+ <_File Include="@(CoreClrCompilerBuildArtifact)" TargetDir="tasks/netcore"/>
+ <_File Include="@(CoreClrCompilerToolsArtifact)" TargetDir="tasks/netcore"/>
+ <_File Include="@(CoreClrCompilerBinArtifact)" TargetDir="tasks/netcore/bincore"/>
+ <_File Include="@(CoreClrCompilerBinRuntimesArtifact)" TargetDir="tasks/netcore/bincore/runtimes"/>
diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/build/Microsoft.Net.Compilers.Toolset.props b/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/build/Microsoft.Net.Compilers.Toolset.props
index 4b771afb964cf..8dc5f46a1ecd3 100644
--- a/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/build/Microsoft.Net.Compilers.Toolset.props
+++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/AnyCpu/build/Microsoft.Net.Compilers.Toolset.props
@@ -2,7 +2,7 @@
- <_RoslynTargetDirectoryName Condition="'$(MSBuildRuntimeType)' == 'Core'">net6.0
+ <_RoslynTargetDirectoryName Condition="'$(MSBuildRuntimeType)' == 'Core'">netcore
<_RoslynTargetDirectoryName Condition="'$(MSBuildRuntimeType)' != 'Core'">net472
<_RoslynTasksDirectory>$(MSBuildThisFileDirectory)..\tasks\$(_RoslynTargetDirectoryName)\
$(_RoslynTasksDirectory)Microsoft.Build.Tasks.CodeAnalysis.dll
diff --git a/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/build/Microsoft.Net.Compilers.Toolset.Arm64.props b/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/build/Microsoft.Net.Compilers.Toolset.Arm64.props
index 4b771afb964cf..ea3dd999eb8c4 100644
--- a/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/build/Microsoft.Net.Compilers.Toolset.Arm64.props
+++ b/src/NuGet/Microsoft.Net.Compilers.Toolset/arm64/build/Microsoft.Net.Compilers.Toolset.Arm64.props
@@ -2,9 +2,7 @@
- <_RoslynTargetDirectoryName Condition="'$(MSBuildRuntimeType)' == 'Core'">net6.0
- <_RoslynTargetDirectoryName Condition="'$(MSBuildRuntimeType)' != 'Core'">net472
- <_RoslynTasksDirectory>$(MSBuildThisFileDirectory)..\tasks\$(_RoslynTargetDirectoryName)\
+ <_RoslynTasksDirectory>$(MSBuildThisFileDirectory)..\tasks\net472\
$(_RoslynTasksDirectory)Microsoft.Build.Tasks.CodeAnalysis.dll
true
$(_RoslynTasksDirectory)Microsoft.CSharp.Core.targets
diff --git a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs
index 2c70bfbe51e47..4e2c621a86750 100644
--- a/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs
+++ b/src/Tools/BuildBoss/CompilerNuGetCheckerUtil.cs
@@ -138,16 +138,16 @@ private bool CheckPackages(TextWriter textWriter)
allGood &= VerifyPackageCore(
textWriter,
FindNuGetPackage(Path.Combine(ArtifactsDirectory, "packages", Configuration, "Shipping"), "Microsoft.Net.Compilers.Toolset"),
- excludeFunc: relativeFileName => relativeFileName.StartsWith(@"tasks\net6.0\bincore\Microsoft.DiaSymReader.Native", PathComparison),
+ excludeFunc: relativeFileName => relativeFileName.StartsWith(@"tasks\netcore\bincore\Microsoft.DiaSymReader.Native", PathComparison),
(@"tasks\net472", GetProjectOutputDirectory("csc", "net472")),
(@"tasks\net472", GetProjectOutputDirectory("vbc", "net472")),
(@"tasks\net472", GetProjectOutputDirectory("csi", "net472")),
(@"tasks\net472", GetProjectOutputDirectory("VBCSCompiler", "net472")),
(@"tasks\net472", GetProjectOutputDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net472")),
- (@"tasks\net6.0\bincore", GetProjectPublishDirectory("csc", "net6.0")),
- (@"tasks\net6.0\bincore", GetProjectPublishDirectory("vbc", "net6.0")),
- (@"tasks\net6.0\bincore", GetProjectPublishDirectory("VBCSCompiler", "net6.0")),
- (@"tasks\net6.0", GetProjectPublishDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net6.0")));
+ (@"tasks\netcore\bincore", GetProjectPublishDirectory("csc", "net6.0")),
+ (@"tasks\netcore\bincore", GetProjectPublishDirectory("vbc", "net6.0")),
+ (@"tasks\netcore\bincore", GetProjectPublishDirectory("VBCSCompiler", "net6.0")),
+ (@"tasks\netcore", GetProjectPublishDirectory("Microsoft.Build.Tasks.CodeAnalysis", "net6.0")));
foreach (var arch in new[] { "x86", "x64", "arm64" })
{
diff --git a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef
index bb95c44a768af..8b73440802722 100644
--- a/src/VisualStudio/Core/Def/PackageRegistration.pkgdef
+++ b/src/VisualStudio/Core/Def/PackageRegistration.pkgdef
@@ -31,6 +31,12 @@
"Title"="Run C#/VB code analysis on .Net 6 (requires restart)"
"PreviewPaneChannels"="IntPreview,int.main"
+[$RootKey$\FeatureFlags\Roslyn\OOPServerGC]
+"Description"="Run C#/VB out-of-process code analysis with ServerGC."
+"Value"=dword:00000000
+"Title"="Run C#/VB code analysis with ServerGC (requires restart)"
+"PreviewPaneChannels"="IntPreview,int.main"
+
// Corresponds to WellKnownExperimentNames.LspPullDiagnosticsFeatureFlag
[$RootKey$\FeatureFlags\Lsp\PullDiagnostics]
"Description"="Enables the LSP-powered diagnostics for managed .Net projects"
diff --git a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj
index 1f2b37be84e72..075262492f489 100644
--- a/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj
+++ b/src/Workspaces/Core/MSBuild/Microsoft.CodeAnalysis.Workspaces.MSBuild.csproj
@@ -5,7 +5,7 @@
Library
Microsoft.CodeAnalysis
true
- $(SourceBuildTargetFrameworksNetFx)
+ $(SourceBuildTargetFrameworks);net472
$(DefineConstants);WORKSPACE_MSBUILD
true
diff --git a/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs
index da4f39eec73c7..eb12898fd5f53 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/ContainerPatternMatcher.cs
@@ -2,12 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
using System;
using System.Globalization;
using System.Linq;
-using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Collections;
namespace Microsoft.CodeAnalysis.PatternMatching
@@ -21,9 +18,10 @@ private sealed partial class ContainerPatternMatcher : PatternMatcher
public ContainerPatternMatcher(
string[] patternParts, char[] containerSplitCharacters,
- CultureInfo culture,
+ bool includeMatchedSpans,
+ CultureInfo? culture,
bool allowFuzzyMatching = false)
- : base(false, culture, allowFuzzyMatching)
+ : base(includeMatchedSpans, culture, allowFuzzyMatching)
{
_containerSplitCharacters = containerSplitCharacters;
@@ -44,7 +42,7 @@ public override void Dispose()
}
}
- public override bool AddMatches(string container, ref TemporaryArray matches)
+ public override bool AddMatches(string? container, ref TemporaryArray matches)
{
if (SkipMatch(container))
{
diff --git a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
index 36c33c465e7be..67153d122d0d2 100644
--- a/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
+++ b/src/Workspaces/Core/Portable/PatternMatching/PatternMatcher.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared;
@@ -46,7 +47,7 @@ internal abstract partial class PatternMatcher : IDisposable
/// Whether or not close matches should count as matches.
protected PatternMatcher(
bool includeMatchedSpans,
- CultureInfo culture,
+ CultureInfo? culture,
bool allowFuzzyMatching = false)
{
culture ??= CultureInfo.CurrentCulture;
@@ -74,21 +75,23 @@ public static PatternMatcher CreatePatternMatcher(
public static PatternMatcher CreateContainerPatternMatcher(
string[] patternParts,
char[] containerSplitCharacters,
+ bool includeMatchedSpans = false,
CultureInfo? culture = null,
bool allowFuzzyMatching = false)
{
return new ContainerPatternMatcher(
- patternParts, containerSplitCharacters, culture, allowFuzzyMatching);
+ patternParts, containerSplitCharacters, includeMatchedSpans, culture, allowFuzzyMatching);
}
public static PatternMatcher CreateDotSeparatedContainerMatcher(
string pattern,
+ bool includeMatchedSpans = false,
CultureInfo? culture = null,
bool allowFuzzyMatching = false)
{
return CreateContainerPatternMatcher(
pattern.Split(s_dotCharacterArray, StringSplitOptions.RemoveEmptyEntries),
- s_dotCharacterArray, culture, allowFuzzyMatching);
+ s_dotCharacterArray, includeMatchedSpans, culture, allowFuzzyMatching);
}
internal static (string name, string? containerOpt) GetNameAndContainer(string pattern)
@@ -102,7 +105,7 @@ internal static (string name, string? containerOpt) GetNameAndContainer(string p
public abstract bool AddMatches(string? candidate, ref TemporaryArray matches);
- private bool SkipMatch(string? candidate)
+ private bool SkipMatch([NotNullWhen(false)] string? candidate)
=> _invalidPattern || string.IsNullOrWhiteSpace(candidate);
private static bool ContainsUpperCaseLetter(string pattern)
diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/LoadableTextAndVersionSource.cs b/src/Workspaces/Core/Portable/Workspace/Solution/LoadableTextAndVersionSource.cs
index c0ab70015feb1..9639bc617aa50 100644
--- a/src/Workspaces/Core/Portable/Workspace/Solution/LoadableTextAndVersionSource.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/LoadableTextAndVersionSource.cs
@@ -2,6 +2,7 @@
// 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.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
@@ -16,12 +17,27 @@ internal sealed class LoadableTextAndVersionSource : ITextAndVersionSource
private sealed class LazyValueWithOptions
{
public readonly LoadableTextAndVersionSource Source;
- public readonly AsyncLazy LazyValue;
public readonly LoadTextOptions Options;
+ private readonly SemaphoreSlim _gate = new(initialCount: 1);
+
+ ///
+ /// Strong reference to the loaded text and version. Only held onto once computed if . is . Once held onto, this will be returned from all calls to
+ /// , or . Once non-null will always
+ /// remain non-null.
+ ///
+ private TextAndVersion? _instance;
+
+ ///
+ /// Weak reference to the loaded text and version that we create whenever the value is computed. We will
+ /// attempt to return from this if still alive when clients call back into this. If neither this, nor are available, the value will be reloaded. Once non-null, this will always be non-null.
+ ///
+ private WeakReference? _weakInstance;
+
public LazyValueWithOptions(LoadableTextAndVersionSource source, LoadTextOptions options)
{
- LazyValue = new AsyncLazy(LoadAsync, LoadSynchronously, source.CacheResult);
Source = source;
Options = options;
}
@@ -31,6 +47,67 @@ private Task LoadAsync(CancellationToken cancellationToken)
private TextAndVersion LoadSynchronously(CancellationToken cancellationToken)
=> Source.Loader.LoadTextSynchronously(Options, cancellationToken);
+
+ public bool TryGetValue([MaybeNullWhen(false)] out TextAndVersion value)
+ {
+ value = _instance;
+ if (value != null)
+ return true;
+
+ return _weakInstance?.TryGetTarget(out value) == true && value != null;
+ }
+
+ public TextAndVersion GetValue(CancellationToken cancellationToken)
+ {
+ if (!TryGetValue(out var textAndVersion))
+ {
+ using (_gate.DisposableWait(cancellationToken))
+ {
+ if (!TryGetValue(out textAndVersion))
+ {
+ textAndVersion = LoadSynchronously(cancellationToken);
+ UpdateWeakAndStrongReferences_NoLock(textAndVersion);
+ }
+ }
+ }
+
+ return textAndVersion;
+ }
+
+ public async Task GetValueAsync(CancellationToken cancellationToken)
+ {
+ if (!TryGetValue(out var textAndVersion))
+ {
+ using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
+ {
+ if (!TryGetValue(out textAndVersion))
+ {
+ textAndVersion = await LoadAsync(cancellationToken).ConfigureAwait(false);
+ UpdateWeakAndStrongReferences_NoLock(textAndVersion);
+ }
+ }
+ }
+
+ return textAndVersion;
+ }
+
+ private void UpdateWeakAndStrongReferences_NoLock(TextAndVersion textAndVersion)
+ {
+ Contract.ThrowIfTrue(_gate.CurrentCount != 0);
+
+ if (this.Source.CacheResult)
+ {
+ // if our source wants us to hold onto the value strongly, do so. No need to involve the weak-refs as
+ // this will now hold onto the value forever.
+ _instance = textAndVersion;
+ }
+ else
+ {
+ // Update the weak ref, so we can return the same instance if anything else is holding onto it.
+ _weakInstance ??= new WeakReference(textAndVersion);
+ _weakInstance.SetTarget(textAndVersion);
+ }
+ }
}
public readonly TextLoader Loader;
@@ -47,7 +124,7 @@ public LoadableTextAndVersionSource(TextLoader loader, bool cacheResult)
public bool CanReloadText
=> Loader.CanReloadText;
- private AsyncLazy GetLazyValue(LoadTextOptions options)
+ private LazyValueWithOptions GetLazyValue(LoadTextOptions options)
{
var lazy = _lazyValue;
@@ -57,7 +134,7 @@ private AsyncLazy GetLazyValue(LoadTextOptions options)
_lazyValue = lazy = new LazyValueWithOptions(this, options);
}
- return lazy.LazyValue;
+ return lazy;
}
public TextAndVersion GetValue(LoadTextOptions options, CancellationToken cancellationToken)
diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs
index cf16b22f5fcb4..4593d8b9c5c70 100644
--- a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph.cs
@@ -128,6 +128,17 @@ internal ProjectDependencyGraph WithProjectReferences(ProjectId projectId, IRead
{
Contract.ThrowIfFalse(_projectIds.Contains(projectId));
+ if (!_referencesMap.ContainsKey(projectId))
+ {
+ // This project doesn't have any references currently, so we delegate to WithAdditionalProjectReferences
+ return WithAdditionalProjectReferences(projectId, projectReferences);
+ }
+ else if (projectReferences.Count == 0)
+ {
+ // We are removing all project references; do so directly
+ return WithAllProjectReferencesRemoved(projectId);
+ }
+
// This method we can't optimize very well: changing project references arbitrarily could invalidate pretty much anything.
// The only thing we can reuse is our actual map of project references for all the other projects, so we'll do that.
diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs
new file mode 100644
index 0000000000000..22deeab440b73
--- /dev/null
+++ b/src/Workspaces/Core/Portable/Workspace/Solution/ProjectDependencyGraph_RemoveAllProjectReferences.cs
@@ -0,0 +1,124 @@
+// 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.Collections.Immutable;
+using System.Diagnostics;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis
+{
+ public partial class ProjectDependencyGraph
+ {
+ internal ProjectDependencyGraph WithAllProjectReferencesRemoved(ProjectId projectId)
+ {
+ Contract.ThrowIfFalse(_projectIds.Contains(projectId));
+
+ if (!_referencesMap.TryGetValue(projectId, out var referencedProjectIds))
+ return this;
+
+ // Removing a project reference doesn't change the set of projects
+ var projectIds = _projectIds;
+
+ // Incrementally update the graph
+ var referencesMap = ComputeNewReferencesMapForRemovedAllProjectReferences(_referencesMap, projectId);
+ var reverseReferencesMap = ComputeNewReverseReferencesMapForRemovedAllProjectReferences(_lazyReverseReferencesMap, projectId, referencedProjectIds);
+ var transitiveReferencesMap = ComputeNewTransitiveReferencesMapForRemovedAllProjectReferences(_transitiveReferencesMap, projectId, referencedProjectIds);
+ var reverseTransitiveReferencesMap = ComputeNewReverseTransitiveReferencesMapForRemovedAllProjectReferences(_reverseTransitiveReferencesMap, projectId);
+
+ return new ProjectDependencyGraph(
+ projectIds,
+ referencesMap,
+ reverseReferencesMap,
+ transitiveReferencesMap,
+ reverseTransitiveReferencesMap,
+ topologicallySortedProjects: default,
+ dependencySets: default);
+ }
+
+ private static ImmutableDictionary> ComputeNewReferencesMapForRemovedAllProjectReferences(
+ ImmutableDictionary> existingForwardReferencesMap,
+ ProjectId projectId)
+ {
+ // Projects with no references do not have an entry in the forward references map
+ return existingForwardReferencesMap.Remove(projectId);
+ }
+
+ ///
+ /// Computes a new for the removal of all project references from a
+ /// project.
+ ///
+ /// The prior to the removal,
+ /// or if the reverse references map was not computed for the prior graph.
+ /// The project ID from which a project reference is being removed.
+ /// The targets of the project references which are being removed.
+ /// The updated (complete) reverse references map, or if the reverse references
+ /// map could not be incrementally updated.
+ private static ImmutableDictionary>? ComputeNewReverseReferencesMapForRemovedAllProjectReferences(
+ ImmutableDictionary>? existingReverseReferencesMap,
+ ProjectId projectId,
+ ImmutableHashSet referencedProjectIds)
+ {
+ if (existingReverseReferencesMap is null)
+ {
+ return null;
+ }
+
+ var builder = existingReverseReferencesMap.ToBuilder();
+ foreach (var referencedProjectId in referencedProjectIds)
+ {
+ builder.MultiRemove(referencedProjectId, projectId);
+ }
+
+ return builder.ToImmutable();
+ }
+
+ private static ImmutableDictionary> ComputeNewTransitiveReferencesMapForRemovedAllProjectReferences(
+ ImmutableDictionary> existingTransitiveReferencesMap,
+ ProjectId projectId,
+ ImmutableHashSet referencedProjectIds)
+ {
+ var builder = existingTransitiveReferencesMap.ToBuilder();
+
+ // Invalidate the transitive references from every project referencing the changed project (transitively)
+ foreach (var (project, references) in existingTransitiveReferencesMap)
+ {
+ if (!references.Contains(projectId))
+ {
+ // This is the forward-references-equivalent of the optimization in the update of reverse transitive
+ // references.
+ continue;
+ }
+
+ Debug.Assert(references.IsSupersetOf(referencedProjectIds));
+ builder.Remove(project);
+ }
+
+ // Invalidate the transitive references from the changed project
+ builder.Remove(projectId);
+
+ return builder.ToImmutable();
+ }
+
+ private static ImmutableDictionary> ComputeNewReverseTransitiveReferencesMapForRemovedAllProjectReferences(
+ ImmutableDictionary> existingReverseTransitiveReferencesMap,
+ ProjectId projectId)
+ {
+ var builder = existingReverseTransitiveReferencesMap.ToBuilder();
+
+ // Invalidate the transitive reverse references from every project previously referenced by the original
+ // project (transitively).
+ foreach (var (project, references) in existingReverseTransitiveReferencesMap)
+ {
+ if (!references.Contains(projectId))
+ {
+ continue;
+ }
+
+ builder.Remove(project);
+ }
+
+ return builder.ToImmutable();
+ }
+ }
+}
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs
index b9695d23e8e1a..879b628a01346 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ListExtensions.cs
@@ -78,5 +78,14 @@ public static int IndexOf(this IList list, Func predicate)
return -1;
}
+
+ public static void AddRangeWhere(this List list, List collection, Func predicate)
+ {
+ foreach (var element in collection)
+ {
+ if (predicate(element))
+ list.Add(element);
+ }
+ }
}
}
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.AnalysisData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.AnalysisData.cs
index af6ff0d545911..c0ad85b57b3b1 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.AnalysisData.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.AnalysisData.cs
@@ -185,11 +185,13 @@ public void OnReadReferenceFound(ISymbol symbol)
// Mark all the current reaching writes of symbol as read.
if (SymbolsWriteBuilder.Count != 0)
{
- var currentWrites = CurrentBlockAnalysisData.GetCurrentWrites(symbol);
- foreach (var write in currentWrites)
- {
- SymbolsWriteBuilder[(symbol, write)] = true;
- }
+ CurrentBlockAnalysisData.ForEachCurrentWrite(
+ symbol,
+ static (write, arg) =>
+ {
+ arg.self.SymbolsWriteBuilder[(arg.symbol, write)] = true;
+ },
+ (symbol, self: this));
}
// Mark the current symbol as read.
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs
index 7b0f5f5c7a2d4..45c98a5326b28 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/FlowAnalysis/SymbolUsageAnalysis/SymbolUsageAnalysis.BasicBlockAnalysisData.cs
@@ -73,15 +73,30 @@ public void Clear(ISymbol symbol)
///