Skip to content

Commit 414bc29

Browse files
author
Julien Couvreur
authored
Extensions: allow extern and disallow in nameof (#79021)
1 parent 00dcd81 commit 414bc29

29 files changed

+1284
-186
lines changed

src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,21 +2306,29 @@ private BoundExpression BindNameofOperatorInternal(InvocationExpressionSyntax no
23062306
var boundArgument = BindExpression(argument, diagnostics);
23072307

23082308
bool syntaxIsOk = CheckSyntaxForNameofArgument(argument, out string name, boundArgument.HasAnyErrors ? BindingDiagnosticBag.Discarded : diagnostics);
2309-
if (!boundArgument.HasAnyErrors && syntaxIsOk && boundArgument.Kind == BoundKind.MethodGroup)
2309+
if (boundArgument is BoundMethodGroup methodGroup)
23102310
{
2311-
var methodGroup = (BoundMethodGroup)boundArgument;
2312-
if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty)
2311+
if (!boundArgument.HasAnyErrors && syntaxIsOk)
23132312
{
2314-
// method group with type parameters not allowed
2315-
diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location);
2313+
if (!methodGroup.TypeArgumentsOpt.IsDefaultOrEmpty)
2314+
{
2315+
// method group with type parameters not allowed
2316+
diagnostics.Add(ErrorCode.ERR_NameofMethodGroupWithTypeParameters, argument.Location);
2317+
}
2318+
else
2319+
{
2320+
EnsureNameofExpressionSymbols(methodGroup, diagnostics);
2321+
}
23162322
}
2317-
else
2323+
}
2324+
else if (boundArgument is BoundPropertyAccess propertyAccess)
2325+
{
2326+
if (propertyAccess.PropertySymbol.GetIsNewExtensionMember())
23182327
{
2319-
EnsureNameofExpressionSymbols(methodGroup, diagnostics);
2328+
diagnostics.Add(ErrorCode.ERR_NameofExtensionMember, boundArgument.Syntax);
23202329
}
23212330
}
2322-
2323-
if (boundArgument is BoundNamespaceExpression nsExpr)
2331+
else if (boundArgument is BoundNamespaceExpression nsExpr)
23242332
{
23252333
diagnostics.AddAssembliesUsedByNamespaceReference(nsExpr.NamespaceSymbol);
23262334
}

src/Compilers/CSharp/Portable/CSharpResources.resx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1806,7 +1806,7 @@ If such a class is used as a base class and if the deriving class defines a dest
18061806
<value>Invalid value for named attribute argument '{0}'</value>
18071807
</data>
18081808
<data name="ERR_DllImportOnInvalidMethod" xml:space="preserve">
1809-
<value>The DllImport attribute must be specified on a method marked 'static' and 'extern'</value>
1809+
<value>The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member</value>
18101810
</data>
18111811
<data name="ERR_EncUpdateFailedMissingSymbol" xml:space="preserve">
18121812
<value>Cannot emit update; {0} '{1}' is missing.</value>
@@ -8188,4 +8188,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
81888188
<data name="ERR_MisplacedExtension" xml:space="preserve">
81898189
<value>An extension member syntax is disallowed in nested position within an extension member syntax</value>
81908190
</data>
8191+
<data name="ERR_NameofExtensionMember" xml:space="preserve">
8192+
<value>Extension members are not allowed as an argument to 'nameof'.</value>
8193+
</data>
81918194
</root>

src/Compilers/CSharp/Portable/Emitter/Model/MethodSymbolAdapter.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ bool Cci.IMethodDefinition.IsExternal
395395
{
396396
CheckDefinitionInvariant();
397397

398-
return AdaptedMethodSymbol.IsExternal;
398+
return !AdaptedMethodSymbol.ContainingType.IsExtension && AdaptedMethodSymbol.IsExternal;
399399
}
400400
}
401401

@@ -422,7 +422,7 @@ bool Cci.IMethodDefinition.IsPlatformInvoke
422422
get
423423
{
424424
CheckDefinitionInvariant();
425-
return AdaptedMethodSymbol.GetDllImportData() != null;
425+
return !AdaptedMethodSymbol.ContainingType.IsExtension && AdaptedMethodSymbol.GetDllImportData() != null;
426426
}
427427
}
428428
#nullable disable
@@ -431,14 +431,14 @@ Cci.IPlatformInvokeInformation Cci.IMethodDefinition.PlatformInvokeData
431431
get
432432
{
433433
CheckDefinitionInvariant();
434-
return AdaptedMethodSymbol.GetDllImportData();
434+
return AdaptedMethodSymbol.ContainingType.IsExtension ? null : AdaptedMethodSymbol.GetDllImportData();
435435
}
436436
}
437437

438438
System.Reflection.MethodImplAttributes Cci.IMethodDefinition.GetImplementationAttributes(EmitContext context)
439439
{
440440
CheckDefinitionInvariant();
441-
return AdaptedMethodSymbol.ImplementationAttributes;
441+
return AdaptedMethodSymbol.ContainingType.IsExtension ? default : AdaptedMethodSymbol.ImplementationAttributes;
442442
}
443443

444444
bool Cci.IMethodDefinition.IsRuntimeSpecial

src/Compilers/CSharp/Portable/Errors/ErrorCode.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,6 +2409,7 @@ internal enum ErrorCode
24092409
ERR_PPShebangInProjectBasedProgram = 9314,
24102410

24112411
ERR_TooManyUserStrings_RestartRequired = 9315,
2412+
ERR_NameofExtensionMember = 9316,
24122413

24132414
// Note: you will need to do the following after adding errors:
24142415
// 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs)

src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,6 +2522,7 @@ or ErrorCode.ERR_CloseUnimplementedInterfaceMemberOperatorMismatch
25222522
or ErrorCode.ERR_OperatorMismatchOnOverride
25232523
or ErrorCode.ERR_BadCompoundAssignmentOpArgs
25242524
or ErrorCode.ERR_PPShebangInProjectBasedProgram
2525+
or ErrorCode.ERR_NameofExtensionMember
25252526
=> false,
25262527
};
25272528
#pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.

src/Compilers/CSharp/Portable/Symbols/Extensions/SourceExtensionImplementationMethodSymbol.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ public SourceExtensionImplementationMethodSymbol(MethodSymbol sourceMethod)
2222
{
2323
Debug.Assert(sourceMethod.GetIsNewExtensionMember());
2424
Debug.Assert(sourceMethod.IsStatic || sourceMethod.ContainingType.ExtensionParameter is not null);
25-
Debug.Assert(!sourceMethod.IsExtern);
26-
Debug.Assert(!sourceMethod.IsExternal);
2725

2826
// Tracked by https://github.com/dotnet/roslyn/issues/78963 : Are we creating type parameters with the right emit behavior? Attributes, etc.
2927
// Also, they should be IsImplicitlyDeclared
@@ -59,9 +57,9 @@ internal override int ParameterCount
5957

6058
internal sealed override bool IsAccessCheckedOnOverride => false;
6159

62-
public sealed override bool IsExtern => false;
63-
public sealed override DllImportData? GetDllImportData() => null;
64-
internal sealed override bool IsExternal => false;
60+
public sealed override bool IsExtern => _originalMethod.IsExtern;
61+
public sealed override DllImportData? GetDllImportData() => _originalMethod.GetDllImportData();
62+
internal sealed override bool IsExternal => _originalMethod.IsExternal;
6563

6664
internal sealed override bool IsDeclaredReadOnly => false;
6765

src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ private void DecodeDllImportAttribute(ref DecodeWellKnownAttributeArguments<Attr
825825
bool hasErrors = false;
826826

827827
var implementationPart = this.PartialImplementationPart ?? this;
828-
if (!implementationPart.IsExtern || !implementationPart.IsStatic)
828+
if (!implementationPart.IsExtern || (!implementationPart.IsStatic && !implementationPart.GetIsNewExtensionMember()))
829829
{
830830
diagnostics.Add(ErrorCode.ERR_DllImportOnInvalidMethod, arguments.AttributeSyntaxOpt.Name.Location);
831831
hasErrors = true;

src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -754,12 +754,7 @@ private static (DeclarationModifiers mods, bool hasExplicitAccessMod) MakeModifi
754754
allowedModifiers |= DeclarationModifiers.Static;
755755
}
756756

757-
allowedModifiers |= DeclarationModifiers.Async;
758-
759-
if (!isExtension)
760-
{
761-
allowedModifiers |= DeclarationModifiers.Extern;
762-
}
757+
allowedModifiers |= DeclarationModifiers.Async | DeclarationModifiers.Extern;
763758

764759
if (containingType.IsStructType())
765760
{

src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -449,10 +449,7 @@ private static (DeclarationModifiers modifiers, bool hasExplicitAccessMod) MakeM
449449
allowedModifiers |= DeclarationModifiers.ReadOnly;
450450
}
451451

452-
if (!isExtension)
453-
{
454-
allowedModifiers |= DeclarationModifiers.Extern;
455-
}
452+
allowedModifiers |= DeclarationModifiers.Extern;
456453

457454
bool hasExplicitAccessMod;
458455
var mods = ModifierUtils.MakeAndCheckNonTypeMemberModifiers(isOrdinaryMethod: false, isForInterfaceMember: isInterface,

src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)