From d1971b8b749f53679ebec35b1547e35e3d955f15 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Tue, 26 May 2020 11:05:29 -0700 Subject: [PATCH 01/15] Basic handling of function pointer types in the IDE: * Offer `delegate` keyword when function pointer types are permissible. * Completion inside function pointer type argument lists (including valid ref modifiers) * SymbolKey support. * Basic formatting support. * Support in add/remove parameter. --- .../CSharp/Portable/PublicAPI.Unshipped.txt | 3 ++ .../CSharp/Portable/Syntax/SyntaxFactory.cs | 18 +++++++- .../Portable/PublicAPI.Unshipped.txt | 4 +- .../Portable/Syntax/SyntaxNodeFactories.vb | 18 +++++++- .../LessAndGreaterThanCompletionSession.cs | 1 + .../BoolKeywordRecommender.cs | 1 + .../ByteKeywordRecommender.cs | 1 + .../CharKeywordRecommender.cs | 1 + .../DecimalKeywordRecommender.cs | 1 + .../DelegateKeywordRecommender.cs | 17 +------- .../DoubleKeywordRecommender.cs | 1 + .../DynamicKeywordRecommender.cs | 1 + .../FloatKeywordRecommender.cs | 1 + .../IntKeywordRecommender.cs | 1 + .../LongKeywordRecommender.cs | 1 + .../ObjectKeywordRecommender.cs | 1 + .../ReadOnlyKeywordRecommender.cs | 3 +- .../SByteKeywordRecommender.cs | 1 + .../ShortKeywordRecommender.cs | 1 + .../StringKeywordRecommender.cs | 1 + .../UIntKeywordRecommender.cs | 1 + .../ULongKeywordRecommender.cs | 1 + .../UShortKeywordRecommender.cs | 1 + .../VoidKeywordRecommender.cs | 1 + .../MethodExtractor.TypeParameterCollector.cs | 9 ++++ .../Shared/Extensions/ISymbolExtensions_2.cs | 3 ++ ...pChangeSignatureViewModelFactoryService.cs | 4 +- .../AddParameterDialogViewModel.cs | 3 +- .../ChangeSignatureViewModelFactoryService.cs | 2 +- ...IChangeSignatureViewModelFactoryService.cs | 2 +- ...cChangeSignatureViewModelFactoryService.vb | 4 +- .../SymbolKey.FunctionPointerTypeSymbolKey.cs | 43 +++++++++++++++++++ .../SymbolKey/SymbolKey.SymbolKeyReader.cs | 8 +++- .../SymbolKey/SymbolKey.SymbolKeyWriter.cs | 12 +++++- .../Formatting/Rules/SpacingFormattingRule.cs | 23 ++++++++++ .../ISymbolExtensions_Accessibility.cs | 20 +++++++++ .../ContextQuery/CSharpSyntaxContext.cs | 4 ++ .../ContextQuery/SyntaxNodeExtensions.cs | 2 + .../ContextQuery/SyntaxTreeExtensions.cs | 40 +++++++++++++++++ .../CSharp/Extensions/SyntaxTreeExtensions.cs | 28 +++++++++++- 40 files changed, 259 insertions(+), 29 deletions(-) create mode 100644 src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index bb399a899a306..0d1fcfc4f6db2 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -108,6 +108,8 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.BinaryPattern(Microsoft.CodeA static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression(Microsoft.CodeAnalysis.SyntaxToken newKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset = 0, Microsoft.CodeAnalysis.ParseOptions options = null, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset, bool consumeFullText) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> TResult static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedPattern(Microsoft.CodeAnalysis.CSharp.Syntax.PatternSyntax pattern) -> Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax @@ -122,6 +124,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.UnaryPattern(Microsoft.CodeAn *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.ArgumentList.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.Initializer.get -> Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax *REMOVED*Microsoft.CodeAnalysis.CSharp.Syntax.ObjectCreationExpressionSyntax.NewKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken +*REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset = 0, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitBinaryPattern(Microsoft.CodeAnalysis.CSharp.Syntax.BinaryPatternSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitParenthesizedPattern(Microsoft.CodeAnalysis.CSharp.Syntax.ParenthesizedPatternSyntax node) -> void diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index b0db58c46bfaa..b0c10bb016fd2 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1693,7 +1693,9 @@ public static NameSyntax ParseName(string text, int offset = 0, bool consumeFull /// /// Parse a TypeNameSyntax node using the grammar rule for type names. /// - public static TypeSyntax ParseTypeName(string text, int offset = 0, bool consumeFullText = true) + // Backcompat overload, do not remove + [EditorBrowsable(EditorBrowsableState.Never)] + public static TypeSyntax ParseTypeName(string text, int offset, bool consumeFullText) { using (var lexer = MakeLexer(text, offset)) using (var parser = MakeParser(lexer)) @@ -1704,6 +1706,20 @@ public static TypeSyntax ParseTypeName(string text, int offset = 0, bool consume } } + /// + /// Parse a TypeNameSyntax node using the grammar rule for type names. + /// + public static TypeSyntax ParseTypeName(string text, int offset = 0, ParseOptions? options = null, bool consumeFullText = true) + { + using (var lexer = MakeLexer(text, offset, (CSharpParseOptions?)options)) + using (var parser = MakeParser(lexer)) + { + var node = parser.ParseTypeName(); + if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); + return (TypeSyntax)node.CreateRed(); + } + } + /// /// Parse an ExpressionSyntax node using the lowest precedence grammar rule for expressions. /// diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..9fef8141e9b9e 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1 +1,3 @@ - +Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer = 0, options As Microsoft.CodeAnalysis.ParseOptions = Nothing, consumeFullText As Boolean = True) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax +Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer, consumeFullText As Boolean) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax +*REMOVED*Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer = 0, consumeFullText As Boolean = True) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb index 4a064d6849090..1c9d8071900b4 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb @@ -15,6 +15,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts Imports InternalSyntax = Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Imports Microsoft.CodeAnalysis.Syntax Imports System.Collections.Immutable +Imports System.ComponentModel Namespace Microsoft.CodeAnalysis.VisualBasic @@ -191,7 +192,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' The input string ''' The starting offset in the string - Public Shared Function ParseTypeName(text As String, Optional offset As Integer = 0, Optional consumeFullText As Boolean = True) As TypeSyntax + Public Shared Function ParseTypeName(text As String, Optional offset As Integer = 0, Optional options As ParseOptions = Nothing, Optional consumeFullText As Boolean = True) As TypeSyntax + Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(DirectCast(options, VisualBasicParseOptions), VisualBasicParseOptions.Default)) + p.GetNextToken() + Dim node = p.ParseGeneralType() + Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), TypeSyntax) + End Using + End Function + + '' Backcompat overload, do not touch + ''' + ''' Parse a type name. + ''' + ''' The input string + ''' The starting offset in the string + + Public Shared Function ParseTypeName(text As String, offset As Integer, consumeFullText As Boolean) As TypeSyntax Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) p.GetNextToken() Dim node = p.ParseGeneralType() diff --git a/src/EditorFeatures/CSharp/AutomaticCompletion/Sessions/LessAndGreaterThanCompletionSession.cs b/src/EditorFeatures/CSharp/AutomaticCompletion/Sessions/LessAndGreaterThanCompletionSession.cs index 0fec74e8a9c4c..efe914d0f9f85 100644 --- a/src/EditorFeatures/CSharp/AutomaticCompletion/Sessions/LessAndGreaterThanCompletionSession.cs +++ b/src/EditorFeatures/CSharp/AutomaticCompletion/Sessions/LessAndGreaterThanCompletionSession.cs @@ -35,6 +35,7 @@ public override bool CheckOpeningPoint(IBraceCompletionSession session, Cancella // type argument or parameter list if (!token.CheckParent(n => n.LessThanToken == token) && !token.CheckParent(n => n.LessThanToken == token) && + !token.CheckParent(n => n.LessThanToken == token) && !PossibleTypeArgument(snapshot, token, cancellationToken)) { return false; diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs index 476cb82667266..27beccec5ae6e 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/BoolKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsFixedVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs index 8dbf7de3c6521..b5081139e73cf 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ByteKeywordRecommender.cs @@ -29,6 +29,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs index db432b9629afa..f39a27021420c 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/CharKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsFixedVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs index b8b32d1cb216f..df9ea614df9a3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DecimalKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsFixedVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs index b886fdc317d11..f3a78c5ccb608 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DelegateKeywordRecommender.cs @@ -2,25 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -using Microsoft.CodeAnalysis.CSharp.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { internal class DelegateKeywordRecommender : AbstractSyntacticSingleKeywordRecommender { - private static readonly ISet s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) - { - SyntaxKind.InternalKeyword, - SyntaxKind.PublicKeyword, - SyntaxKind.PrivateKeyword, - SyntaxKind.ProtectedKeyword, - SyntaxKind.UnsafeKeyword - }; - public DelegateKeywordRecommender() : base(SyntaxKind.DelegateKeyword) { @@ -32,11 +21,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || (context.IsNonAttributeExpressionContext && !context.IsConstantExpressionContext) || IsAfterAsyncKeywordInExpressionContext(context, cancellationToken) || - context.IsTypeDeclarationContext( - validModifiers: s_validModifiers, - validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructTypeDeclarations, - canBePartial: false, - cancellationToken: cancellationToken); + context.IsTypeContext; } private static bool IsAfterAsyncKeywordInExpressionContext(CSharpSyntaxContext context, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs index 231cb1cdabb6c..c3a3bc1b062af 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DoubleKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsFixedVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs index 62e20da2ca7a2..6d20d03968bf9 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/DynamicKeywordRecommender.cs @@ -53,6 +53,7 @@ protected static bool IsDynamicTypeContext( syntaxTree.IsPossibleCastTypeContext(position, context.LeftToken, cancellationToken) || context.IsObjectCreationTypeContext || context.IsGenericTypeArgumentContext || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || syntaxTree.IsDefaultExpressionContext(position, context.LeftToken) || syntaxTree.IsAfterKeyword(position, SyntaxKind.ConstKeyword, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs index f48d39680e2c2..fd53561cc484e 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/FloatKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsFixedVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs index 57e0242b0b096..c5339a86c4ef1 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/IntKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs index 2ff8ac4878d6f..92d34e3becdba 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LongKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs index 4479016e01d4f..d469abd5acbb3 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ObjectKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsParameterTypeContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs index c9399497b6609..56ca9f17bd512 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ReadOnlyKeywordRecommender.cs @@ -42,7 +42,8 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context private static bool IsRefReadOnlyContext(CSharpSyntaxContext context) => context.TargetToken.IsKind(SyntaxKind.RefKeyword) && - context.TargetToken.Parent.IsKind(SyntaxKind.RefType); + (context.TargetToken.Parent.IsKind(SyntaxKind.RefType) || + (context.TargetToken.Parent.IsKind(SyntaxKind.Parameter) && context.IsFunctionPointerTypeArgumentContext)); private static bool IsValidContextForType(CSharpSyntaxContext context, CancellationToken cancellationToken) { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs index dcc3a37da2b21..a9b60e470b6ef 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SByteKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs index c7d29756fc646..99583e36c6920 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ShortKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs index 1f9f1a9492010..426356918afd9 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/StringKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || context.IsParameterTypeContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs index 2ce88ad7a9cfd..b2c9399b27e2a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UIntKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs index cd604bffd5304..46d37b1f13c3e 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/ULongKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs index 9f544c325f9ff..40d5c34ab1c5f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/UShortKeywordRecommender.cs @@ -28,6 +28,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsGlobalStatementContext || context.IsObjectCreationTypeContext || (context.IsGenericTypeArgumentContext && !context.TargetToken.Parent.HasAncestor()) || + context.IsFunctionPointerTypeArgumentContext || context.IsEnumBaseListContext || context.IsIsOrAsTypeContext || context.IsLocalVariableDeclarationContext || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs index b71d225e8c693..669b793586557 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs @@ -43,6 +43,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsTypeOfExpressionContext || syntaxTree.IsSizeOfExpressionContext(position, context.LeftToken) || context.IsDelegateReturnTypeContext || + context.IsFunctionPointerTypeArgumentContext || IsUnsafeLocalVariableDeclarationContext(context) || IsUnsafeParameterTypeContext(context) || IsUnsafeCastTypeContext(context) || diff --git a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs index bf7c8639091f3..0cbdef5ec3ed0 100644 --- a/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs +++ b/src/Features/Core/Portable/ExtractMethod/MethodExtractor.TypeParameterCollector.cs @@ -29,6 +29,15 @@ public override void VisitDynamicType(IDynamicTypeSymbol dynamicTypeSymbol) { } + public override void VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) + { + symbol.Signature.ReturnType.Accept(this); + foreach (var param in symbol.Signature.Parameters) + { + param.Type.Accept(this); + } + } + public override void VisitArrayType(IArrayTypeSymbol arrayTypeSymbol) => arrayTypeSymbol.ElementType.Accept(this); diff --git a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs index c9957ea9c5baf..071b9cee1ef01 100644 --- a/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs +++ b/src/Features/Core/Portable/Shared/Extensions/ISymbolExtensions_2.cs @@ -129,6 +129,9 @@ public static Glyph GetGlyph(this ISymbol symbol) case SymbolKind.PointerType: return ((IPointerTypeSymbol)symbol).PointedAtType.GetGlyph(); + case SymbolKind.FunctionPointer: + return Glyph.Intrinsic; + case SymbolKind.Property: { var propertySymbol = (IPropertySymbol)symbol; diff --git a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs index b6bdedfb1bb1d..00b3e537c789a 100644 --- a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs @@ -44,7 +44,9 @@ public override SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterVi return parts.ToArray(); } - public override bool IsTypeNameValid(string typeName) => !SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics; +#nullable enable + public override bool IsTypeNameValid(string typeName, ParseOptions? parseOptions) => !SyntaxFactory.ParseTypeName(typeName, options: parseOptions).ContainsDiagnostics; +#nullable restore public override SyntaxNode GetTypeNode(string typeName) => SyntaxFactory.ParseTypeName(typeName); } diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs index c4925c630b689..089a68072eae4 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs @@ -226,7 +226,8 @@ private void SetCurrentTypeTextAndUpdateBindingStatus(string typeName) private bool IsParameterTypeSyntacticallyValid(string typeName) { var languageService = Document.GetRequiredLanguageService(); - return languageService.IsTypeNameValid(typeName); + _ = Document.TryGetSyntaxTree(out var syntaxTree); + return languageService.IsTypeNameValid(typeName, syntaxTree?.Options); } private bool DoesTypeFullyBind(ITypeSymbol? type) diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs index bd1c150834783..2cbc8d604a742 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs @@ -17,7 +17,7 @@ public ChangeSignatureViewModelFactoryService() public abstract SymbolDisplayPart[] GeneratePreviewDisplayParts( ChangeSignatureDialogViewModel.AddedParameterViewModel addedParameterViewModel); - public abstract bool IsTypeNameValid(string typeName); + public abstract bool IsTypeNameValid(string typeName, ParseOptions? options); public abstract SyntaxNode GetTypeNode(string typeName); } diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs index 1b7b1c55937d2..8a2f43aad57c9 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs @@ -14,7 +14,7 @@ internal interface IChangeSignatureViewModelFactoryService : ILanguageService { SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel); - bool IsTypeNameValid(string typeName); + bool IsTypeNameValid(string typeName, ParseOptions? options); SyntaxNode GetTypeNode(string typeName); } diff --git a/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb b/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb index a232641052967..dc8e5cb069c52 100644 --- a/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb +++ b/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb @@ -40,8 +40,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ChangeSignature Return parts.ToArray() End Function - Public Overrides Function IsTypeNameValid(typeName As String) As Boolean - Return Not SyntaxFactory.ParseTypeName(typeName).ContainsDiagnostics + Public Overrides Function IsTypeNameValid(typeName As String, options As ParseOptions) As Boolean + Return Not SyntaxFactory.ParseTypeName(typeName, options:=options).ContainsDiagnostics End Function Public Overrides Function GetTypeNode(typeName As String) As SyntaxNode diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs new file mode 100644 index 0000000000000..04659c7e4dcb8 --- /dev/null +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis +{ + internal partial struct SymbolKey + { + private static class FunctionPointerTypeSymbolKey + { + public static void Create(IFunctionPointerTypeSymbol symbol, SymbolKeyWriter visitor) + { + visitor.WriteRefKind(symbol.Signature.RefKind); + visitor.WriteSymbolKey(symbol.Signature.ReturnType); + visitor.WriteRefKindArray(symbol.Signature.Parameters); + visitor.WriteParameterTypesArray(symbol.Signature.Parameters); + } + + public static SymbolKeyResolution Resolve(SymbolKeyReader reader) + { + var returnRefKind = reader.ReadRefKind(); + var returnType = reader.ReadSymbolKey(); + using var paramRefKinds = reader.ReadRefKindArray(); + var paramTypes = reader.ReadSymbolKeyArray(); + + if (paramTypes.IsDefault) + { + return default; + } + + using var _ = paramTypes; + + if (!(returnType.GetAnySymbol() is ITypeSymbol returnTypeSymbol)) + { + return default; + } + + return new SymbolKeyResolution(reader.Compilation.CreateFunctionPointerTypeSymbol( + returnTypeSymbol, returnRefKind, paramTypes.ToImmutable(), paramRefKinds.ToImmutable())); + } + } + } +} diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs index cbf4cdc0388b0..0249a8db8a077 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyReader.cs @@ -38,7 +38,7 @@ public Reader() { _readString = ReadString; _readBoolean = ReadBoolean; - _readRefKind = () => (RefKind)ReadInteger(); + _readRefKind = ReadRefKind; } protected virtual void Initialize(string data, CancellationToken cancellationToken) @@ -192,6 +192,11 @@ public PooledArrayBuilder ReadArray(Func readFunction) EatCloseParen(); return builder; } + + public RefKind ReadRefKind() + { + return (RefKind)ReadInteger(); + } } private class RemoveAssemblySymbolKeysReader : Reader @@ -418,6 +423,7 @@ private SymbolKeyResolution ReadWorker(SymbolKeyType type) SymbolKeyType.NamedType => NamedTypeSymbolKey.Resolve(this), SymbolKeyType.ErrorType => ErrorTypeSymbolKey.Resolve(this), SymbolKeyType.Field => FieldSymbolKey.Resolve(this), + SymbolKeyType.FunctionPointer => FunctionPointerTypeSymbolKey.Resolve(this), SymbolKeyType.DynamicType => DynamicTypeSymbolKey.Resolve(this), SymbolKeyType.Method => MethodSymbolKey.Resolve(this), SymbolKeyType.Namespace => NamespaceSymbolKey.Resolve(this), diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyWriter.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyWriter.cs index d644ddf0c0714..c8d40ca3387dc 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyWriter.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.SymbolKeyWriter.cs @@ -25,6 +25,7 @@ private enum SymbolKeyType NamedType = 'D', ErrorType = 'E', Field = 'F', + FunctionPointer = 'G', DynamicType = 'I', Method = 'M', Namespace = 'N', @@ -76,7 +77,7 @@ public SymbolKeyWriter() _writeLocation = WriteLocation; _writeBoolean = WriteBoolean; _writeParameterType = p => WriteSymbolKey(p.Type); - _writeRefKind = p => WriteInteger((int)p.RefKind); + _writeRefKind = p => WriteRefKind(p.RefKind); } public void Dispose() @@ -298,6 +299,8 @@ private void WriteArray(ImmutableArray array, Action writeValue) EndKey(); } + internal void WriteRefKind(RefKind refKind) => WriteInteger((int)refKind); + public override object VisitAlias(IAliasSymbol aliasSymbol) { WriteType(SymbolKeyType.Alias); @@ -455,6 +458,13 @@ public override object VisitPointerType(IPointerTypeSymbol pointerTypeSymbol) return null; } + public override object VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) + { + WriteType(SymbolKeyType.FunctionPointer); + FunctionPointerTypeSymbolKey.Create(symbol, this); + return null; + } + public override object VisitProperty(IPropertySymbol propertySymbol) { WriteType(SymbolKeyType.Property); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs index f9f13a6eb6957..10968a1df885b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs @@ -320,6 +320,29 @@ previousToken.Parent is AssignmentExpressionSyntax || } } + // Function pointer type adjustments + if (previousParentKind == SyntaxKind.FunctionPointerType && currentParentKind == SyntaxKind.FunctionPointerType) + { + if (currentKind == SyntaxKind.LessThanToken) + { + switch (previousKind) + { + // No spacing between the * and < tokens if there is no calling convention + case SyntaxKind.AsteriskToken: + // No spacing between the calling convention and opening angle bracket of function pointer types: + // delegate* cdecl< + case SyntaxKind.IdentifierToken: + return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); + } + } + + // Force a space between * and the calling convention + if (currentKind == SyntaxKind.IdentifierToken && previousKind == SyntaxKind.AsteriskToken) + { + return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); + } + } + // For spacing after the 'not' pattern operator if (previousToken.Parent.IsKind(SyntaxKindEx.NotPattern)) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs index 24a578c5a220e..8d62a9daddc2d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs @@ -103,6 +103,23 @@ private static bool IsSymbolAccessibleCore( case SymbolKind.PointerType: return IsSymbolAccessibleCore(((IPointerTypeSymbol)symbol).PointedAtType, within, null, out failedThroughTypeCheck); + case SymbolKind.FunctionPointer: + var funcPtrSign = ((IFunctionPointerTypeSymbol)symbol).Signature; + if (!IsSymbolAccessibleCore(funcPtrSign.ReturnType, within, null, out failedThroughTypeCheck)) + { + return false; + } + + foreach (var param in funcPtrSign.Parameters) + { + if (!IsSymbolAccessibleCore(param.Type, within, null, out failedThroughTypeCheck)) + { + return false; + } + } + + return true; + case SymbolKind.NamedType: return IsNamedTypeAccessible((INamedTypeSymbol)symbol, within); @@ -143,6 +160,9 @@ private static bool IsSymbolAccessibleCore( } // If it's a synthesized operator on a pointer, use the pointer's PointedAtType. + // Note: there are currently no synthesized operators on function pointer types. If that + // ever changes, updated the below assert and fix the code + Debug.Assert(!(symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.FunctionPointer))); if (symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.PointerType)) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs index f8e9e67c8bec9..00bcccb795677 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/CSharpSyntaxContext.cs @@ -51,6 +51,7 @@ internal sealed class CSharpSyntaxContext : SyntaxContext public readonly bool IsCatchFilterContext; public readonly bool IsDestructorTypeContext; public readonly bool IsLeftSideOfImportAliasDirective; + public readonly bool IsFunctionPointerTypeArgumentContext; private CSharpSyntaxContext( Workspace workspace, @@ -106,6 +107,7 @@ private CSharpSyntaxContext( bool isAfterPatternContext, bool isRightSideOfNumericType, bool isInArgumentList, + bool isFunctionPointerTypeArgumentContext, CancellationToken cancellationToken) : base(workspace, semanticModel, position, leftToken, targetToken, isTypeContext, isNamespaceContext, isNamespaceDeclarationNameContext, @@ -147,6 +149,7 @@ private CSharpSyntaxContext( this.IsCatchFilterContext = isCatchFilterContext; this.IsDestructorTypeContext = isDestructorTypeContext; this.IsLeftSideOfImportAliasDirective = isLeftSideOfImportAliasDirective; + this.IsFunctionPointerTypeArgumentContext = isFunctionPointerTypeArgumentContext; } public static CSharpSyntaxContext CreateContext(Workspace workspace, SemanticModel semanticModel, int position, CancellationToken cancellationToken) @@ -265,6 +268,7 @@ private static CSharpSyntaxContext CreateContextWorker(Workspace workspace, Sema isAfterPatternContext: syntaxTree.IsAtEndOfPattern(leftToken, position), isRightSideOfNumericType: isRightSideOfNumericType, isInArgumentList: isArgumentListToken, + isFunctionPointerTypeArgumentContext: syntaxTree.IsFunctionPointerTypeArgumentContext(position, leftToken, cancellationToken), cancellationToken: cancellationToken); } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs index eef3e1bc80e6e..42daf5dadb8e4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs @@ -30,5 +30,7 @@ public static bool IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParam return false; } + + public static bool IsInFunctionPointer(this SyntaxToken node) => node.Parent.IsKind(SyntaxKind.FunctionPointerType); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index b985e82672c65..cf8d771307357 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -719,6 +719,7 @@ public static bool IsTypeContext( syntaxTree.IsExpressionContext(position, tokenOnLeftOfPosition, attributes: true, cancellationToken: cancellationToken, semanticModelOpt: semanticModelOpt) || syntaxTree.IsPrimaryFunctionExpressionContext(position, tokenOnLeftOfPosition) || syntaxTree.IsGenericTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken, semanticModelOpt) || + syntaxTree.IsFunctionPointerTypeArgumentContext(position, tokenOnLeftOfPosition, cancellationToken) || syntaxTree.IsFixedVariableDeclarationContext(position, tokenOnLeftOfPosition) || syntaxTree.IsImplicitOrExplicitOperatorTypeContext(position, tokenOnLeftOfPosition) || syntaxTree.IsIsOrAsTypeContext(position, tokenOnLeftOfPosition) || @@ -902,6 +903,30 @@ public static bool IsSizeOfExpressionContext( return false; } + public static bool IsFunctionPointerTypeArgumentContext( + this SyntaxTree syntaxTree, + int position, + SyntaxToken tokenOnLeftOfPosition, + CancellationToken cancellationToken) + { + var token = tokenOnLeftOfPosition; + token = token.GetPreviousTokenIfTouchingWord(position); + + switch (token.Kind()) + { + case SyntaxKind.LessThanToken: + case SyntaxKind.CommaToken: + return token.Parent is FunctionPointerTypeSyntax; + } + + if (token.GetAncestor() == null) + { + return false; + } + + return syntaxTree.IsInPartiallyWrittenFunctionPointer(position, cancellationToken); + } + public static bool IsGenericTypeArgumentContext( this SyntaxTree syntaxTree, int position, @@ -1000,6 +1025,12 @@ public static bool IsParameterModifierContext( return true; } + if (token.IsKind(SyntaxKind.LessThanToken) && token.IsInFunctionPointer()) + { + parameterIndex = 0; + return true; + } + if (token.IsKind(SyntaxKind.CommaToken) && token.Parent.IsKind(SyntaxKind.ParameterList, out ParameterListSyntax parameterList) && parameterList.IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParameterList(includeOperators)) @@ -1010,6 +1041,15 @@ public static bool IsParameterModifierContext( return true; } + if (token.IsKind(SyntaxKind.CommaToken) && + token.Parent.IsKind(SyntaxKind.FunctionPointerType, out FunctionPointerTypeSyntax funcPtrType)) + { + var commaIndex = funcPtrType.Parameters.GetWithSeparators().IndexOf(token); + + parameterIndex = commaIndex / 2 + 1; + return true; + } + if (token.IsKind(SyntaxKind.CloseBracketToken) && token.Parent.IsKind(SyntaxKind.AttributeList) && token.Parent.IsParentKind(SyntaxKind.Parameter, out ParameterSyntax parameter) && diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs index 535f3f93d8284..56d86e0e9a6e9 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -92,6 +92,11 @@ public static bool IsInInactiveRegion( return false; } + public static bool IsInPartiallyWrittenFunctionPointer(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + return syntaxTree.IsInPartiallyWrittenGenericOrFunctionPointer(position, lookForFunctionPointer: true, cancellationToken, out _, out _); + } + public static bool IsInPartiallyWrittenGeneric( this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { @@ -113,6 +118,18 @@ public static bool IsInPartiallyWrittenGeneric( CancellationToken cancellationToken, out SyntaxToken genericIdentifier, out SyntaxToken lessThanToken) + { + return IsInPartiallyWrittenGenericOrFunctionPointer(syntaxTree, position, lookForFunctionPointer: false, cancellationToken, out genericIdentifier, out lessThanToken); + } + + + private static bool IsInPartiallyWrittenGenericOrFunctionPointer( + this SyntaxTree syntaxTree, + int position, + bool lookForFunctionPointer, + CancellationToken cancellationToken, + out SyntaxToken genericIdentifier, + out SyntaxToken lessThanToken) { genericIdentifier = default; lessThanToken = default; @@ -153,7 +170,7 @@ public static bool IsInPartiallyWrittenGeneric( // but we need to know the simple name that precedes the < // it could be // ~~~~~~goo Date: Thu, 28 May 2020 12:31:08 -0700 Subject: [PATCH 02/15] PR Feedback and Tests * Added tests for all the new code paths. * Fixed up the formatter. * Fixed up extract method's understanding of rvalues for function pointers. --- .../CSharp/Portable/Syntax/SyntaxFactory.cs | 8 +-- .../Portable/Syntax/SyntaxNodeFactories.vb | 6 +- .../ExtractMethod/ExtractMethodTests.cs | 55 +++++++++++++++---- .../BoolKeywordRecommenderTests.cs | 9 +++ .../ByteKeywordRecommenderTests.cs | 9 +++ .../CharKeywordRecommenderTests.cs | 9 +++ .../DecimalKeywordRecommenderTests.cs | 9 +++ .../DelegateKeywordRecommenderTests.cs | 54 +++++++++++------- .../DoubleKeywordRecommenderTests.cs | 9 +++ .../DynamicKeywordRecommenderTests.cs | 9 +++ .../FloatKeywordRecommenderTests.cs | 9 +++ .../GlobalKeywordRecommenderTests.cs | 9 +++ .../InKeywordRecommenderTests.cs | 22 ++++++++ .../IntKeywordRecommenderTests.cs | 9 +++ .../LongKeywordRecommenderTests.cs | 9 +++ .../NativeIntegerKeywordRecommenderTests.cs | 9 +++ .../ObjectKeywordRecommenderTests.cs | 9 +++ .../OutKeywordRecommenderTests.cs | 22 ++++++++ .../ReadOnlyKeywordRecommenderTests.cs | 22 ++++++++ .../RefKeywordRecommenderTests.cs | 22 ++++++++ .../SByteKeywordRecommenderTests.cs | 9 +++ .../ShortKeywordRecommenderTests.cs | 9 +++ .../StringKeywordRecommenderTests.cs | 9 +++ .../UIntKeywordRecommenderTests.cs | 9 +++ .../ULongKeywordRecommenderTests.cs | 9 +++ .../UShortKeywordRecommenderTests.cs | 9 +++ .../VoidKeywordRecommenderTests.cs | 55 +++++++++++++++++++ .../DelegateKeywordRecommender.cs | 19 ++++++- .../GlobalKeywordRecommender.cs | 1 + .../VoidKeywordRecommender.cs | 19 ++++++- ...pChangeSignatureViewModelFactoryService.cs | 4 +- .../CodeGeneration/CSharpSyntaxGenerator.cs | 7 ++- .../FormattingTests_FunctionPointers.cs | 19 +++++++ .../SymbolKey.FunctionPointerTypeSymbolKey.cs | 11 +--- src/Workspaces/CoreTest/SymbolKeyTests.cs | 16 ++++++ .../Extensions/ExpressionSyntaxExtensions.cs | 1 + .../CSharp/Extensions/SyntaxTreeExtensions.cs | 2 + .../Core/CompilerExtensions.projitems | 1 + .../ISymbolExtensions_Accessibility.cs | 14 +++-- .../Compiler/Core/Extensions/SymbolKindEx.cs | 25 +++++++++ .../ContextQuery/SyntaxNodeExtensions.cs | 2 - .../ContextQuery/SyntaxTreeExtensions.cs | 19 ++++--- ...olExtensions.TypeSyntaxGeneratorVisitor.cs | 9 ++- .../CSharp/Extensions/SyntaxTreeExtensions.cs | 28 +--------- 44 files changed, 520 insertions(+), 105 deletions(-) create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolKindEx.cs diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index b0c10bb016fd2..c725cddb2c3eb 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1697,13 +1697,7 @@ public static NameSyntax ParseName(string text, int offset = 0, bool consumeFull [EditorBrowsable(EditorBrowsableState.Never)] public static TypeSyntax ParseTypeName(string text, int offset, bool consumeFullText) { - using (var lexer = MakeLexer(text, offset)) - using (var parser = MakeParser(lexer)) - { - var node = parser.ParseTypeName(); - if (consumeFullText) node = parser.ConsumeUnexpectedTokens(node); - return (TypeSyntax)node.CreateRed(); - } + return ParseTypeName(text, offset, options: null, consumeFullText); } /// diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb index 1c9d8071900b4..a272b57adabbc 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb @@ -208,11 +208,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' The starting offset in the string Public Shared Function ParseTypeName(text As String, offset As Integer, consumeFullText As Boolean) As TypeSyntax - Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), VisualBasicParseOptions.Default) - p.GetNextToken() - Dim node = p.ParseGeneralType() - Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), TypeSyntax) - End Using + Return ParseTypeName(text, offset, options:=Nothing, consumeFullText) End Function ''' diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index b3abe0fe98fe4..5add73111034d 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -11109,17 +11109,17 @@ public async Task ExtractMethodInInterface() var code = @" interface Program { - void Foo(); + void Goo(); void Test() { - [|Foo();|] + [|Goo();|] } }"; var expected = @" interface Program { - void Foo(); + void Goo(); void Test() { @@ -11128,7 +11128,7 @@ void Test() void NewMethod() { - Foo(); + Goo(); } }"; await TestExtractMethodAsync(code, expected); @@ -11139,18 +11139,18 @@ void NewMethod() public async Task ExtractMethodInExpressionBodiedConstructors() { var code = @" -class Foo +class Goo { private readonly string _bar; - private Foo(string bar) => _bar = [|bar|]; + private Goo(string bar) => _bar = [|bar|]; }"; var expected = @" -class Foo +class Goo { private readonly string _bar; - private Foo(string bar) => _bar = GetBar(bar); + private Goo(string bar) => _bar = GetBar(bar); private static string GetBar(string bar) { @@ -11165,18 +11165,18 @@ private static string GetBar(string bar) public async Task ExtractMethodInExpressionBodiedFinalizers() { var code = @" -class Foo +class Goo { bool finalized; - ~Foo() => finalized = [|true|]; + ~Goo() => finalized = [|true|]; }"; var expected = @" -class Foo +class Goo { bool finalized; - ~Foo() => finalized = NewMethod(); + ~Goo() => finalized = NewMethod(); private static bool NewMethod() { @@ -11185,5 +11185,36 @@ private static bool NewMethod() }"; await TestExtractMethodAsync(code, expected); } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractMethodInvolvingFunctionPointer() + { + var code = @" +class C +{ + void M(delegate*> ptr1) + { + string s = null; + _ = [|ptr1()|](ref s); + } +}"; + + var expected = @" +class C +{ + void M(delegate*> ptr1) + { + string s = null; + _ = NewMethod(ptr1)(ref s); + } + + private static delegate* NewMethod(delegate*> ptr1) + { + return ptr1(); + } +}"; + + await TestExtractMethodAsync(code, expected); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs index bf7bf2133a5df..52d4a7e9698a4 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs @@ -716,5 +716,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs index 94a88324cba32..06a70e3fc37a9 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ByteKeywordRecommenderTests.cs @@ -716,6 +716,15 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs index 8cca8b9a7aa48..f070dd37fd72b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/CharKeywordRecommenderTests.cs @@ -767,5 +767,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs index abfd46dbe82f7..7595cb8080044 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DecimalKeywordRecommenderTests.cs @@ -732,5 +732,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index 6ededeaf32ce1..9bd35d15ee65f 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.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.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -43,16 +44,16 @@ await VerifyKeywordAsync(SourceCodeKind.Script, } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotInUsingAlias() + public async Task TestInUsingAlias() { - await VerifyAbsenceAsync( + await VerifyKeywordAsync( @"using Goo = $$"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotInEmptyStatement() + public async Task TestInEmptyStatement() { - await VerifyAbsenceAsync(AddInsideMethod( + await VerifyKeywordAsync(AddInsideMethod( @"$$")); } @@ -235,16 +236,22 @@ public async Task TestNotAfterSealed() => await VerifyAbsenceAsync(@"sealed $$"); [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotAfterStatic() - => await VerifyAbsenceAsync(@"static $$"); + public async Task TestAfterStatic() + { + await VerifyAbsenceAsync(SourceCodeKind.Regular, @"static $$"); + await VerifyKeywordAsync(SourceCodeKind.Script, @"static $$"); + } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotAfterStaticPublic() - => await VerifyAbsenceAsync(@"static public $$"); + public async Task TestAfterStaticPublic() + { + await VerifyAbsenceAsync(SourceCodeKind.Regular, @"static public $$"); + await VerifyKeywordAsync(SourceCodeKind.Script, @"static public $$"); + } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotAfterDelegate() - => await VerifyAbsenceAsync(@"delegate $$"); + public async Task TestAfterDelegate() + => await VerifyKeywordAsync(@"delegate $$"); [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestDelegateAsArgument() @@ -297,25 +304,25 @@ await VerifyKeywordAsync( [WorkItem(538804, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538804")] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotInTypeOf() + public async Task TestInTypeOf() { - await VerifyAbsenceAsync(AddInsideMethod( + await VerifyKeywordAsync(AddInsideMethod( @"typeof($$")); } [WorkItem(538804, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538804")] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotInDefault() + public async Task TestInDefault() { - await VerifyAbsenceAsync(AddInsideMethod( + await VerifyKeywordAsync(AddInsideMethod( @"default($$")); } [WorkItem(538804, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538804")] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotInSizeOf() + public async Task TestInSizeOf() { - await VerifyAbsenceAsync(AddInsideMethod( + await VerifyKeywordAsync(AddInsideMethod( @"sizeof($$")); } @@ -345,15 +352,24 @@ void M() Action a = async $$"); } - [WorkItem(607197, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/607197")] [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestNotAfterAsyncInMemberDeclaration() + public async Task TestAfterAsyncInMemberDeclaration() { - await VerifyAbsenceAsync(@" + await VerifyKeywordAsync(@" using System; class C { async $$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeList() + { + await VerifyKeywordAsync(@" +using System; +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs index 8980c66c24379..31819d479c12a 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DoubleKeywordRecommenderTests.cs @@ -716,5 +716,14 @@ void Method() } }"); } + + [Fact] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class Program +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs index df089225ee788..915530f02a81b 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs @@ -633,5 +633,14 @@ public async Task TestAfterAsync() [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestNotAfterAsyncAsType() => await VerifyAbsenceAsync(@"class c { async async $$ }"); + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs index 2b1fc9ea0d98d..05b47a0adff33 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/FloatKeywordRecommenderTests.cs @@ -689,5 +689,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs index f64b93a98d6d6..f6184a4849416 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/GlobalKeywordRecommenderTests.cs @@ -132,5 +132,14 @@ public async Task TestAfterRefExpression() await VerifyKeywordAsync(AddInsideMethod( @"ref int x = ref $$")); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs index 25293ebbc692c..0ef778c0d021e 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/InKeywordRecommenderTests.cs @@ -697,5 +697,27 @@ await VerifyAbsenceAsync( @"static class Extensions { void Extension(this int i, this $$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeNoExistingModifiers() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } + + [Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + [InlineData("in")] + [InlineData("out")] + [InlineData("ref")] + [InlineData("ref readonly")] + public async Task TestNotInFunctionPointerTypeExistingModifiers(string modifier) + { + await VerifyAbsenceAsync($@" +class C +{{ + delegate*<{modifier} $$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs index fb08196582cea..2cd8b9236b0f0 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/IntKeywordRecommenderTests.cs @@ -789,5 +789,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs index 5097e0296b6c8..34b194f37d415 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/LongKeywordRecommenderTests.cs @@ -716,5 +716,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs index ff4e91320ad8b..8bbe464f834de 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/NativeIntegerKeywordRecommenderTests.cs @@ -246,5 +246,14 @@ await VerifyKeywordAsync(AddInsideMethod( case $$ }")); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs index 8c6f7864679ab..56108b6379aba 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ObjectKeywordRecommenderTests.cs @@ -723,5 +723,14 @@ void Method() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerType() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs index be34e5f576caf..27746612ae791 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/OutKeywordRecommenderTests.cs @@ -448,5 +448,27 @@ await VerifyAbsenceAsync( @"static class Extensions { static void Extension(this int i, this $$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeNoExistingModifiers() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } + + [Theory, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + [InlineData("in")] + [InlineData("out")] + [InlineData("ref")] + [InlineData("ref readonly")] + public async Task TestNotInFunctionPointerTypeExistingModifiers(string modifier) + { + await VerifyAbsenceAsync($@" +class C +{{ + delegate*<{modifier} $$"); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs index 9f414c84c68a4..61e0971813800 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs @@ -588,5 +588,27 @@ void M() } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeAfterRef() + { + await VerifyKeywordAsync(@" +class C +{ + delegate* a) } }"); } + + [Fact] + [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointer01() + { + await VerifyKeywordAsync(@" +class C +{ + delegate*<$$"); + } + + [Fact] + [Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointer02() + { + await VerifyKeywordAsync(@" +class C +{ + C s_validModifiers = new HashSet(SyntaxFacts.EqualityComparer) + { + SyntaxKind.InternalKeyword, + SyntaxKind.PublicKeyword, + SyntaxKind.PrivateKeyword, + SyntaxKind.ProtectedKeyword, + SyntaxKind.UnsafeKeyword + }; + public DelegateKeywordRecommender() : base(SyntaxKind.DelegateKeyword) { @@ -19,9 +30,13 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context { return context.IsGlobalStatementContext || - (context.IsNonAttributeExpressionContext && !context.IsConstantExpressionContext) || + ((context.IsNonAttributeExpressionContext || context.IsTypeContext) && !context.IsConstantExpressionContext) || IsAfterAsyncKeywordInExpressionContext(context, cancellationToken) || - context.IsTypeContext; + context.IsTypeDeclarationContext( + validModifiers: s_validModifiers, + validTypeDeclarations: SyntaxKindSet.ClassInterfaceStructTypeDeclarations, + canBePartial: false, + cancellationToken: cancellationToken); } private static bool IsAfterAsyncKeywordInExpressionContext(CSharpSyntaxContext context, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs index 928b3bb852378..c34583e01b4f0 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GlobalKeywordRecommender.cs @@ -37,6 +37,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsAnyExpressionContext || context.IsObjectCreationTypeContext || context.IsIsOrAsTypeContext || + context.IsFunctionPointerTypeArgumentContext || syntaxTree.IsAfterKeyword(position, SyntaxKind.ConstKeyword, cancellationToken) || syntaxTree.IsAfterKeyword(position, SyntaxKind.RefKeyword, cancellationToken) || syntaxTree.IsAfterKeyword(position, SyntaxKind.ReadOnlyKeyword, cancellationToken) || diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs index 669b793586557..88e2a666eef0a 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Utilities; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { @@ -43,7 +44,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsTypeOfExpressionContext || syntaxTree.IsSizeOfExpressionContext(position, context.LeftToken) || context.IsDelegateReturnTypeContext || - context.IsFunctionPointerTypeArgumentContext || + IsFunctionPointerNonRefType(context) || IsUnsafeLocalVariableDeclarationContext(context) || IsUnsafeParameterTypeContext(context) || IsUnsafeCastTypeContext(context) || @@ -52,6 +53,22 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.SyntaxTree.IsLocalFunctionDeclarationContext(position, SyntaxKindSet.AllLocalFunctionModifiers, cancellationToken); } + private bool IsFunctionPointerNonRefType(CSharpSyntaxContext context) + => context.IsFunctionPointerTypeArgumentContext + && !context.PrecedingModifiers.Contains(kind => + { + switch (kind) + { + case SyntaxKind.RefKeyword: + case SyntaxKind.ReadOnlyKeyword: + case SyntaxKind.OutKeyword: + case SyntaxKind.InKeyword: + return true; + default: + return false; + } + }); + private bool IsUnsafeDefaultExpressionContext(CSharpSyntaxContext context) { return diff --git a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs index 00b3e537c789a..84f94e878b3df 100644 --- a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs @@ -44,9 +44,7 @@ public override SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterVi return parts.ToArray(); } -#nullable enable - public override bool IsTypeNameValid(string typeName, ParseOptions? parseOptions) => !SyntaxFactory.ParseTypeName(typeName, options: parseOptions).ContainsDiagnostics; -#nullable restore + public override bool IsTypeNameValid(string typeName, ParseOptions parseOptions) => !SyntaxFactory.ParseTypeName(typeName, options: parseOptions).ContainsDiagnostics; public override SyntaxNode GetTypeNode(string typeName) => SyntaxFactory.ParseTypeName(typeName); } diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 151186d7377e7..7869f48b0db14 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -200,13 +200,14 @@ public override SyntaxNode ParameterDeclaration(string name, SyntaxNode type, Sy initializer != null ? SyntaxFactory.EqualsValueClause((ExpressionSyntax)initializer) : null); } - internal static SyntaxTokenList GetParameterModifiers(RefKind refKind) + internal static SyntaxTokenList GetParameterModifiers(RefKind refKind, bool forFunctionPointerReturnParameter = false) => refKind switch { RefKind.None => new SyntaxTokenList(), - RefKind.Out => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.OutKeyword)), + RefKind.Out when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.OutKeyword)), RefKind.Ref => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword)), - RefKind.In => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InKeyword)), + RefKind.In when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InKeyword)), + RefKind.RefReadOnly when forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), _ => throw ExceptionUtilities.UnexpectedValue(refKind), }; diff --git a/src/Workspaces/CSharpTest/Formatting/FormattingTests_FunctionPointers.cs b/src/Workspaces/CSharpTest/Formatting/FormattingTests_FunctionPointers.cs index 8f0d8f4ea71a4..7f9bc9ed9bab1 100644 --- a/src/Workspaces/CSharpTest/Formatting/FormattingTests_FunctionPointers.cs +++ b/src/Workspaces/CSharpTest/Formatting/FormattingTests_FunctionPointers.cs @@ -29,5 +29,24 @@ unsafe class C await AssertFormatAsync(expected, content); } + + [Fact] + public async Task FormatFunctionPointerWithCallingConvention() + { + // TODO(https://github.com/dotnet/roslyn/issues/44312): add a space after the "int"s in the baseline and make this test still pass + var content = @" +unsafe class C +{ + delegate *cdecl < int, int> functionPointer; +}"; + + var expected = @" +unsafe class C +{ + delegate* cdecl functionPointer; +}"; + + await AssertFormatAsync(expected, content); + } } } diff --git a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs index 04659c7e4dcb8..31e9b64f12fc3 100644 --- a/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolKey/SymbolKey.FunctionPointerTypeSymbolKey.cs @@ -21,16 +21,9 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader) var returnRefKind = reader.ReadRefKind(); var returnType = reader.ReadSymbolKey(); using var paramRefKinds = reader.ReadRefKindArray(); - var paramTypes = reader.ReadSymbolKeyArray(); + using var paramTypes = reader.ReadSymbolKeyArray(); - if (paramTypes.IsDefault) - { - return default; - } - - using var _ = paramTypes; - - if (!(returnType.GetAnySymbol() is ITypeSymbol returnTypeSymbol)) + if (paramTypes.IsDefault || !(returnType.GetAnySymbol() is ITypeSymbol returnTypeSymbol)) { return default; } diff --git a/src/Workspaces/CoreTest/SymbolKeyTests.cs b/src/Workspaces/CoreTest/SymbolKeyTests.cs index b9419cef5e785..c8df9a6ab88da 100644 --- a/src/Workspaces/CoreTest/SymbolKeyTests.cs +++ b/src/Workspaces/CoreTest/SymbolKeyTests.cs @@ -48,6 +48,7 @@ public class B { }; public B this[B b] { get { return b; } } public event D E; public event D E2 { add; remove; } + public delegate* Ptr; } "; var compilation = GetCompilation(source, LanguageNames.CSharp); @@ -783,6 +784,21 @@ void Method((C a, int b) t) Assert.True(method.Parameters[0].Type.IsTupleType); } + [Fact] + public void TestFunctionPointerTypeSymbols() + { + var source = @" +class C +{ + public delegate* ptr1; + public delegate* ptr1; +}"; + + var comp = GetCompilation(source, LanguageNames.CSharp); + var fields = GetDeclaredSymbols(comp).OfType().Select(f => f.Type); + TestRoundTrip(fields, comp); + } + private void TestRoundTrip(IEnumerable symbols, Compilation compilation, Func fnId = null) { foreach (var symbol in symbols) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs index 6e38b9ac5a9e4..d22af9db817e3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/ExpressionSyntaxExtensions.cs @@ -381,6 +381,7 @@ private static bool CanReplace(ISymbol symbol) case SymbolKind.Parameter: case SymbolKind.Property: case SymbolKind.RangeVariable: + case SymbolKindEx.FunctionPointer: return true; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs index 39f1a18d7ea38..e49297856326d 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -51,6 +51,8 @@ public static ISet GetPrecedingModifiers( case SyntaxKind.UnsafeKeyword: case SyntaxKind.AsyncKeyword: case SyntaxKind.RefKeyword: + case SyntaxKind.OutKeyword: + case SyntaxKind.InKeyword: result.Add(token.Kind()); token = token.GetPreviousToken(includeSkipped: true); continue; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 930bb9ff5e7ec..9314ce9496e78 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -191,6 +191,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs index 8d62a9daddc2d..69bb90e8bcc85 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions_Accessibility.cs @@ -103,14 +103,15 @@ private static bool IsSymbolAccessibleCore( case SymbolKind.PointerType: return IsSymbolAccessibleCore(((IPointerTypeSymbol)symbol).PointedAtType, within, null, out failedThroughTypeCheck); - case SymbolKind.FunctionPointer: - var funcPtrSign = ((IFunctionPointerTypeSymbol)symbol).Signature; - if (!IsSymbolAccessibleCore(funcPtrSign.ReturnType, within, null, out failedThroughTypeCheck)) + case SymbolKindEx.FunctionPointer: +#if !CODE_STYLE + var funcPtrSignature = ((IFunctionPointerTypeSymbol)symbol).Signature; + if (!IsSymbolAccessibleCore(funcPtrSignature.ReturnType, within, null, out failedThroughTypeCheck)) { return false; } - foreach (var param in funcPtrSign.Parameters) + foreach (var param in funcPtrSignature.Parameters) { if (!IsSymbolAccessibleCore(param.Type, within, null, out failedThroughTypeCheck)) { @@ -119,6 +120,9 @@ private static bool IsSymbolAccessibleCore( } return true; +#else + return false; +#endif case SymbolKind.NamedType: return IsNamedTypeAccessible((INamedTypeSymbol)symbol, within); @@ -162,7 +166,9 @@ private static bool IsSymbolAccessibleCore( // If it's a synthesized operator on a pointer, use the pointer's PointedAtType. // Note: there are currently no synthesized operators on function pointer types. If that // ever changes, updated the below assert and fix the code +#if !CODE_STYLE Debug.Assert(!(symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.FunctionPointer))); +#endif if (symbol.IsKind(SymbolKind.Method) && ((IMethodSymbol)symbol).MethodKind == MethodKind.BuiltinOperator && symbol.ContainingSymbol.IsKind(SymbolKind.PointerType)) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolKindEx.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolKindEx.cs new file mode 100644 index 0000000000000..d3261cb809d4c --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/SymbolKindEx.cs @@ -0,0 +1,25 @@ +// 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. + +#nullable enable + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + /// + /// This class allows the Code Style layer to light up support for new language features when available at runtime + /// while compiling against an older version of the Roslyn assemblies. + /// + [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Private constants are used for static assertions.")] + internal static class SymbolKindEx + { + public const SymbolKind FunctionPointer = (SymbolKind)20; + +#if !CODE_STYLE + // This will overflow if the kinds don't match up. + private const uint FunctionPointerValueAssertion = -(FunctionPointer - SymbolKind.FunctionPointer); +#endif + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs index 42daf5dadb8e4..eef3e1bc80e6e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxNodeExtensions.cs @@ -30,7 +30,5 @@ public static bool IsDelegateOrConstructorOrLocalFunctionOrMethodOrOperatorParam return false; } - - public static bool IsInFunctionPointer(this SyntaxToken node) => node.Parent.IsKind(SyntaxKind.FunctionPointerType); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs index cf8d771307357..a04d84b02e539 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -909,9 +910,11 @@ public static bool IsFunctionPointerTypeArgumentContext( SyntaxToken tokenOnLeftOfPosition, CancellationToken cancellationToken) { +#if !CODE_STYLE var token = tokenOnLeftOfPosition; token = token.GetPreviousTokenIfTouchingWord(position); + // https://github.com/dotnet/roslyn/issues/39865: When the syntax rewrite is done, the parents here will need to change. switch (token.Kind()) { case SyntaxKind.LessThanToken: @@ -919,12 +922,10 @@ public static bool IsFunctionPointerTypeArgumentContext( return token.Parent is FunctionPointerTypeSyntax; } - if (token.GetAncestor() == null) - { - return false; - } - - return syntaxTree.IsInPartiallyWrittenFunctionPointer(position, cancellationToken); + return token.Parent is ParameterSyntax { Parent: FunctionPointerTypeSyntax _ }; +#else + return false; +#endif } public static bool IsGenericTypeArgumentContext( @@ -1025,7 +1026,7 @@ public static bool IsParameterModifierContext( return true; } - if (token.IsKind(SyntaxKind.LessThanToken) && token.IsInFunctionPointer()) + if (token.IsKind(SyntaxKind.LessThanToken) && token.Parent.IsKind(SyntaxKindEx.FunctionPointerType)) { parameterIndex = 0; return true; @@ -1041,14 +1042,16 @@ public static bool IsParameterModifierContext( return true; } +#if !CODE_STYLE if (token.IsKind(SyntaxKind.CommaToken) && - token.Parent.IsKind(SyntaxKind.FunctionPointerType, out FunctionPointerTypeSyntax funcPtrType)) + token.Parent.IsKind(SyntaxKindEx.FunctionPointerType, out FunctionPointerTypeSyntax funcPtrType)) { var commaIndex = funcPtrType.Parameters.GetWithSeparators().IndexOf(token); parameterIndex = commaIndex / 2 + 1; return true; } +#endif if (token.IsKind(SyntaxKind.CloseBracketToken) && token.Parent.IsKind(SyntaxKind.AttributeList) && diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index 7e22b9beec5d0..e86d96c6b9c8f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -115,9 +116,11 @@ public override TypeSyntax VisitDynamicType(IDynamicTypeSymbol symbol) public override TypeSyntax VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) { // TODO(https://github.com/dotnet/roslyn/issues/39865): generate the calling convention once exposed through the API - var parameters = symbol.Signature.Parameters.Select(p => p.Type) - .Concat(SpecializedCollections.SingletonEnumerable(symbol.Signature.ReturnType)) - .SelectAsArray(t => SyntaxFactory.Parameter(SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken)).WithType(t.GenerateTypeSyntax())); + var parameters = symbol.Signature.Parameters.Select(p => (p.Type, RefKindModifiers: CSharpSyntaxGenerator.GetParameterModifiers(p.RefKind))) + .Concat(SpecializedCollections.SingletonEnumerable(( + Type: symbol.Signature.ReturnType, + RefKindModifiers: CSharpSyntaxGenerator.GetParameterModifiers(symbol.Signature.RefKind, forFunctionPointerReturnParameter: true)))) + .SelectAsArray(t => SyntaxFactory.Parameter(SyntaxFactory.MissingToken(SyntaxKind.IdentifierToken)).WithModifiers(t.RefKindModifiers).WithType(t.Type.GenerateTypeSyntax())); return AddInformationTo( SyntaxFactory.FunctionPointerType(SyntaxFactory.SeparatedList(parameters)), symbol); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs index 56d86e0e9a6e9..535f3f93d8284 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/SyntaxTreeExtensions.cs @@ -92,11 +92,6 @@ public static bool IsInInactiveRegion( return false; } - public static bool IsInPartiallyWrittenFunctionPointer(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - return syntaxTree.IsInPartiallyWrittenGenericOrFunctionPointer(position, lookForFunctionPointer: true, cancellationToken, out _, out _); - } - public static bool IsInPartiallyWrittenGeneric( this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { @@ -118,18 +113,6 @@ public static bool IsInPartiallyWrittenGeneric( CancellationToken cancellationToken, out SyntaxToken genericIdentifier, out SyntaxToken lessThanToken) - { - return IsInPartiallyWrittenGenericOrFunctionPointer(syntaxTree, position, lookForFunctionPointer: false, cancellationToken, out genericIdentifier, out lessThanToken); - } - - - private static bool IsInPartiallyWrittenGenericOrFunctionPointer( - this SyntaxTree syntaxTree, - int position, - bool lookForFunctionPointer, - CancellationToken cancellationToken, - out SyntaxToken genericIdentifier, - out SyntaxToken lessThanToken) { genericIdentifier = default; lessThanToken = default; @@ -170,7 +153,7 @@ private static bool IsInPartiallyWrittenGenericOrFunctionPointer( // but we need to know the simple name that precedes the < // it could be // ~~~~~~goo Date: Thu, 28 May 2020 15:01:15 -0700 Subject: [PATCH 03/15] PR Feedback: * Add additional testing. * Implement symbol equivalence for function pointer types. * Simplify the change signature dialog type resolution. --- .../ExtractMethod/ExtractMethodTests.cs | 29 ++++++++++++++++ .../BoolKeywordRecommenderTests.cs | 27 +++++++++++++++ .../ByteKeywordRecommenderTests.cs | 27 +++++++++++++++ .../CharKeywordRecommenderTests.cs | 27 +++++++++++++++ .../DecimalKeywordRecommenderTests.cs | 27 +++++++++++++++ .../DoubleKeywordRecommenderTests.cs | 27 +++++++++++++++ .../FloatKeywordRecommenderTests.cs | 27 +++++++++++++++ .../GlobalKeywordRecommenderTests.cs | 27 +++++++++++++++ .../IntKeywordRecommenderTests.cs | 27 +++++++++++++++ .../LongKeywordRecommenderTests.cs | 27 +++++++++++++++ .../NativeIntegerKeywordRecommenderTests.cs | 27 +++++++++++++++ .../ObjectKeywordRecommenderTests.cs | 27 +++++++++++++++ .../SByteKeywordRecommenderTests.cs | 27 +++++++++++++++ .../ShortKeywordRecommenderTests.cs | 27 +++++++++++++++ .../StringKeywordRecommenderTests.cs | 27 +++++++++++++++ .../UIntKeywordRecommenderTests.cs | 27 +++++++++++++++ .../ULongKeywordRecommenderTests.cs | 27 +++++++++++++++ .../UShortKeywordRecommenderTests.cs | 27 +++++++++++++++ .../VoidKeywordRecommenderTests.cs | 34 +++++++++++++------ .../DelegateKeywordRecommender.cs | 4 ++- .../VoidKeywordRecommender.cs | 18 +--------- ...pChangeSignatureViewModelFactoryService.cs | 6 +++- .../AddParameterDialogViewModel.cs | 3 +- .../ChangeSignatureViewModelFactoryService.cs | 2 +- ...IChangeSignatureViewModelFactoryService.cs | 2 +- ...cChangeSignatureViewModelFactoryService.vb | 5 +-- .../CodeGeneration/CSharpSyntaxGenerator.cs | 1 + .../Core/CompilerExtensions.projitems | 1 + .../Compiler/Core/Extensions/MethodKindEx.cs | 21 ++++++++++++ ...lEquivalenceComparer.EquivalenceVisitor.cs | 18 +++++++++- .../Utilities/SymbolEquivalenceComparer.cs | 4 +++ 31 files changed, 570 insertions(+), 37 deletions(-) create mode 100644 src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 5add73111034d..bcdc962400e3f 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -11216,5 +11216,34 @@ void M(delegate*> ptr1) await TestExtractMethodAsync(code, expected); } + + [Fact, Trait(Traits.Feature, Traits.Features.ExtractMethod)] + public async Task ExtractMethodInvolvingFunctionPointerWithTypeParameter() + { + var code = @" +class C +{ + void M(delegate* ptr1) + { + _ = [|ptr1|](); + } +}"; + + var expected = @" +class C +{ + void M(delegate* ptr1) + { + _ = GetPtr1(ptr1)(); + } + + private static delegate* GetPtr1(delegate* ptr1) + { + return ptr1; + } +}"; + + await TestExtractMethodAsync(code, expected); + } } } diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs index 52d4a7e9698a4..91b826f74bf10 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/BoolKeywordRecommenderTests.cs @@ -725,5 +725,32 @@ class C { delegate*<$$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeAfterComma() + { + await VerifyKeywordAsync(@" +class C +{ + delegate* context.IsNonAttributeExpressionContext || context.IsTypeContext; } private static bool IsAfterAsyncKeywordInExpressionContext(CSharpSyntaxContext context, CancellationToken cancellationToken) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs index 88e2a666eef0a..d753b104b3798 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs @@ -44,7 +44,7 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.IsTypeOfExpressionContext || syntaxTree.IsSizeOfExpressionContext(position, context.LeftToken) || context.IsDelegateReturnTypeContext || - IsFunctionPointerNonRefType(context) || + context.IsFunctionPointerTypeArgumentContext || IsUnsafeLocalVariableDeclarationContext(context) || IsUnsafeParameterTypeContext(context) || IsUnsafeCastTypeContext(context) || @@ -53,22 +53,6 @@ protected override bool IsValidContext(int position, CSharpSyntaxContext context context.SyntaxTree.IsLocalFunctionDeclarationContext(position, SyntaxKindSet.AllLocalFunctionModifiers, cancellationToken); } - private bool IsFunctionPointerNonRefType(CSharpSyntaxContext context) - => context.IsFunctionPointerTypeArgumentContext - && !context.PrecedingModifiers.Contains(kind => - { - switch (kind) - { - case SyntaxKind.RefKeyword: - case SyntaxKind.ReadOnlyKeyword: - case SyntaxKind.OutKeyword: - case SyntaxKind.InKeyword: - return true; - default: - return false; - } - }); - private bool IsUnsafeDefaultExpressionContext(CSharpSyntaxContext context) { return diff --git a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs index 84f94e878b3df..cc8873e430c61 100644 --- a/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/CSharp/Impl/ChangeSignature/CSharpChangeSignatureViewModelFactoryService.cs @@ -16,6 +16,8 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.ChangeSignature [ExportLanguageService(typeof(IChangeSignatureViewModelFactoryService), LanguageNames.CSharp), Shared] internal class CSharpChangeSignatureViewModelFactoryService : ChangeSignatureViewModelFactoryService { + private static readonly CSharpParseOptions s_langVersionLatestParseOptions = new CSharpParseOptions(LanguageVersion.Preview); + [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] public CSharpChangeSignatureViewModelFactoryService() @@ -44,7 +46,9 @@ public override SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterVi return parts.ToArray(); } - public override bool IsTypeNameValid(string typeName, ParseOptions parseOptions) => !SyntaxFactory.ParseTypeName(typeName, options: parseOptions).ContainsDiagnostics; + // Use LangVersion Preview to ensure that all types parse correctly. If the user types in a type only available + // in a preview version, they'll get a diagnostic after everything is generated + public override bool IsTypeNameValid(string typeName) => !SyntaxFactory.ParseTypeName(typeName, options: s_langVersionLatestParseOptions).ContainsDiagnostics; public override SyntaxNode GetTypeNode(string typeName) => SyntaxFactory.ParseTypeName(typeName); } diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs index 089a68072eae4..c4925c630b689 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/AddParameterDialogViewModel.cs @@ -226,8 +226,7 @@ private void SetCurrentTypeTextAndUpdateBindingStatus(string typeName) private bool IsParameterTypeSyntacticallyValid(string typeName) { var languageService = Document.GetRequiredLanguageService(); - _ = Document.TryGetSyntaxTree(out var syntaxTree); - return languageService.IsTypeNameValid(typeName, syntaxTree?.Options); + return languageService.IsTypeNameValid(typeName); } private bool DoesTypeFullyBind(ITypeSymbol? type) diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs index 2cbc8d604a742..bd1c150834783 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/ChangeSignatureViewModelFactoryService.cs @@ -17,7 +17,7 @@ public ChangeSignatureViewModelFactoryService() public abstract SymbolDisplayPart[] GeneratePreviewDisplayParts( ChangeSignatureDialogViewModel.AddedParameterViewModel addedParameterViewModel); - public abstract bool IsTypeNameValid(string typeName, ParseOptions? options); + public abstract bool IsTypeNameValid(string typeName); public abstract SyntaxNode GetTypeNode(string typeName); } diff --git a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs index 8a2f43aad57c9..1b7b1c55937d2 100644 --- a/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs +++ b/src/VisualStudio/Core/Def/Implementation/ChangeSignature/IChangeSignatureViewModelFactoryService.cs @@ -14,7 +14,7 @@ internal interface IChangeSignatureViewModelFactoryService : ILanguageService { SymbolDisplayPart[] GeneratePreviewDisplayParts(AddedParameterViewModel addedParameterViewModel); - bool IsTypeNameValid(string typeName, ParseOptions? options); + bool IsTypeNameValid(string typeName); SyntaxNode GetTypeNode(string typeName); } diff --git a/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb b/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb index dc8e5cb069c52..52b2a5fb64948 100644 --- a/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb +++ b/src/VisualStudio/VisualBasic/Impl/ChangeSignature/VisualBasicChangeSignatureViewModelFactoryService.vb @@ -40,8 +40,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.ChangeSignature Return parts.ToArray() End Function - Public Overrides Function IsTypeNameValid(typeName As String, options As ParseOptions) As Boolean - Return Not SyntaxFactory.ParseTypeName(typeName, options:=options).ContainsDiagnostics + Public Overrides Function IsTypeNameValid(typeName As String) As Boolean + Static visualBasicParseOptions As New VisualBasicParseOptions(LanguageVersion.Latest) + Return Not SyntaxFactory.ParseTypeName(typeName, options:=visualBasicParseOptions).ContainsDiagnostics End Function Public Overrides Function GetTypeNode(typeName As String) As SyntaxNode diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 7869f48b0db14..c9781587f14d4 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -206,6 +206,7 @@ internal static SyntaxTokenList GetParameterModifiers(RefKind refKind, bool forF RefKind.None => new SyntaxTokenList(), RefKind.Out when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.OutKeyword)), RefKind.Ref => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword)), + // Note: RefKind.RefReadonly == RefKind.In RefKind.In when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InKeyword)), RefKind.RefReadOnly when forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), _ => throw ExceptionUtilities.UnexpectedValue(refKind), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems index 9314ce9496e78..ad62c07b78fd2 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/CompilerExtensions.projitems @@ -190,6 +190,7 @@ + diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs new file mode 100644 index 0000000000000..001501d1d665d --- /dev/null +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs @@ -0,0 +1,21 @@ +#nullable enable + +using System.Diagnostics.CodeAnalysis; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + /// + /// This class allows the Code Style layer to light up support for new language features when available at runtime + /// while compiling against an older version of the Roslyn assemblies. + /// + [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Private constants are used for static assertions.")] + internal static class MethodKindEx + { + public const MethodKind FunctionPointerSignature = (MethodKind)18; + +#if !CODE_STYLE + // This will overflow if the kinds don't match up. + private const uint FunctionPointerValueAssertion = -(FunctionPointerSignature - MethodKind.FunctionPointerSignature); +#endif + } +} diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs index 5a2e9d5892c1e..fa37c52aa349b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.EquivalenceVisitor.cs @@ -141,6 +141,12 @@ private bool AreEquivalentWorker(ISymbol x, ISymbol y, SymbolKind k, Dictionary< SymbolKind.RangeVariable => RangeVariablesAreEquivalent((IRangeVariableSymbol)x, (IRangeVariableSymbol)y), SymbolKind.TypeParameter => TypeParametersAreEquivalent((ITypeParameterSymbol)x, (ITypeParameterSymbol)y, equivalentTypesWithDifferingAssemblies), SymbolKind.Preprocessing => PreprocessingSymbolsAreEquivalent((IPreprocessingSymbol)x, (IPreprocessingSymbol)y), + SymbolKindEx.FunctionPointer => +#if !CODE_STYLE + FunctionPointerTypesAreEquivalent((IFunctionPointerTypeSymbol)x, (IFunctionPointerTypeSymbol)y, equivalentTypesWithDifferingAssemblies), +#else + false, +#endif _ => false, }; } @@ -174,7 +180,7 @@ private bool LabelsAreEquivalent(ILabelSymbol x, ILabelSymbol y) private bool LocalsAreEquivalent(ILocalSymbol x, ILocalSymbol y) => HaveSameLocation(x, y); - private bool MethodsAreEquivalent(IMethodSymbol x, IMethodSymbol y, Dictionary equivalentTypesWithDifferingAssemblies) + private bool MethodsAreEquivalent(IMethodSymbol x, IMethodSymbol y, Dictionary equivalentTypesWithDifferingAssemblies, bool considerReturnRefKinds = false) { if (!AreCompatibleMethodKinds(x.MethodKind, y.MethodKind)) { @@ -237,6 +243,11 @@ private bool MethodsAreEquivalent(IMethodSymbol x, IMethodSymbol y, Dictionary equivalentTypesWithDifferingAssemblies) + => MethodsAreEquivalent(x.Signature, y.Signature, equivalentTypesWithDifferingAssemblies); +#endif + private bool PropertiesAreEquivalent(IPropertySymbol x, IPropertySymbol y, Dictionary equivalentTypesWithDifferingAssemblies) { if (x.ContainingType.IsAnonymousType && y.ContainingType.IsAnonymousType) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs index 31440aec6b0f9..1e49922e566c4 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs @@ -184,6 +184,10 @@ private static bool CheckContainingType(IMethodSymbol x) { return false; } + else if (x.MethodKind == MethodKindEx.FunctionPointerSignature) + { + return false; + } return true; } From 9052e853d065f76f7c2b9da83ccc2cd2b34620c8 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 28 May 2020 15:35:05 -0700 Subject: [PATCH 04/15] Remove redundant formatting rules. Apply PR feedback. --- .../ReadOnlyKeywordRecommenderTests.cs | 12 ++++++++++-- .../Portable/CodeGeneration/CSharpSyntaxGenerator.cs | 5 +++-- .../CSharp/Formatting/Rules/SpacingFormattingRule.cs | 4 ++-- .../Formatting/Rules/TokenBasedFormattingRule.cs | 7 ------- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs index 61e0971813800..0c03de509e2c0 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/ReadOnlyKeywordRecommenderTests.cs @@ -598,12 +598,20 @@ class C delegate* refKind switch { RefKind.None => new SyntaxTokenList(), - RefKind.Out when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.OutKeyword)), + RefKind.Out => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.OutKeyword)), RefKind.Ref => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword)), - // Note: RefKind.RefReadonly == RefKind.In + // Note: RefKind.RefReadonly == RefKind.In. Function Pointers must use the correct + // ref kind syntax when generating for the return parameter vs other parameters. RefKind.In when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InKeyword)), RefKind.RefReadOnly when forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), _ => throw ExceptionUtilities.UnexpectedValue(refKind), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs index 10968a1df885b..af930bc368055 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs @@ -321,7 +321,7 @@ previousToken.Parent is AssignmentExpressionSyntax || } // Function pointer type adjustments - if (previousParentKind == SyntaxKind.FunctionPointerType && currentParentKind == SyntaxKind.FunctionPointerType) + if (previousParentKind == SyntaxKindEx.FunctionPointerType && currentParentKind == SyntaxKindEx.FunctionPointerType) { if (currentKind == SyntaxKind.LessThanToken) { @@ -332,7 +332,7 @@ previousToken.Parent is AssignmentExpressionSyntax || // No spacing between the calling convention and opening angle bracket of function pointer types: // delegate* cdecl< case SyntaxKind.IdentifierToken: - return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpaces); + return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs index f3445d8632fb9..d0a8d6aa8bc2f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/TokenBasedFormattingRule.cs @@ -516,13 +516,6 @@ private static SyntaxList GetUsings(SyntaxNode node) return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); } - // no spaces around the * in a function pointer - if ((currentToken.IsKind(SyntaxKind.AsteriskToken) && currentToken.Parent.IsKind(SyntaxKindEx.FunctionPointerType)) || - (previousToken.IsKind(SyntaxKind.AsteriskToken) && previousToken.Parent.IsKind(SyntaxKindEx.FunctionPointerType))) - { - return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); - } - // ~ * case if (previousToken.Kind() == SyntaxKind.TildeToken && (previousToken.Parent is PrefixUnaryExpressionSyntax || previousToken.Parent is DestructorDeclarationSyntax)) { From 3ca29da639754d546b14b2f6f639bb710584b28e Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 28 May 2020 16:29:43 -0700 Subject: [PATCH 05/15] Address naming feedback from other PR. --- src/Compilers/CSharp/Portable/CSharpResources.resx | 2 +- src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf | 4 ++-- .../CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs | 4 ++-- 15 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 737db36bc298b..115e9b7dc40a3 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6161,7 +6161,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 'RefKind.Out' is not a valid ref kind for a return type. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. Cannot convert & method group '{0}' to non-function pointer type '{1}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index a1924c6ebf5a1..10e27daa55c51 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index d9a530e84eb07..bf76520ce1bc6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 632b32d3d72a5..a09f3c7f123c0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 9cd5d7f83c014..e8d3f71bf823a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index b21f9bcb5040d..f5331a9c36d1e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 20c77c2f6ab39..89c7c68de2eda 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 2d014f4cf7182..2ba892d855306 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 8ba6cb43d24f7..03a91fcab42aa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 99fb70350029a..ba156a3f517df 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 912a29e99895f..62a1ecf231695 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 621451fb9231a..bcf48335885fe 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index e359cb495481e..1e5a778f9e42f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 2f2b8ba804289..dc04b99a8d653 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -123,8 +123,8 @@ - Cannot convert a & method group '{0}' to delegate type '{0}'. - Cannot convert a & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert & method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index cce15a5950a60..be3253730cc6a 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -3722,10 +3722,10 @@ unsafe void M() // (8,24): error CS0119: 'Action' is a type, which is not valid in the given context // Action ptr1 = (Action)&M; Diagnostic(ErrorCode.ERR_BadSKunknown, "Action").WithArguments("System.Action", "type").WithLocation(8, 24), - // (9,23): error CS8800: Cannot convert a & method group 'M' to delegate type 'M'. + // (9,23): error CS8800: Cannot convert & method group 'M' to delegate type 'M'. // Action ptr2 = (Action)(&M); Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "(Action)(&M)").WithArguments("M", "System.Action").WithLocation(9, 23), - // (10,23): error CS8800: Cannot convert a & method group 'M' to delegate type 'M'. + // (10,23): error CS8800: Cannot convert & method group 'M' to delegate type 'M'. // Action ptr3 = &M; Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "&M").WithArguments("M", "System.Action").WithLocation(10, 23) ); From deeb91243a095cfd59d11b45d7ce03dec10935e6 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 28 May 2020 16:39:57 -0700 Subject: [PATCH 06/15] PR feedback: * More tests. * Make the delegate keyword recommender a bit stricter. --- ...omaticLessAndGreaterThanCompletionTests.cs | 13 +++++++++ .../DelegateKeywordRecommenderTests.cs | 12 +++++++-- .../DynamicKeywordRecommenderTests.cs | 27 +++++++++++++++++++ .../DelegateKeywordRecommender.cs | 7 +++-- .../CodeGeneration/CSharpSyntaxGenerator.cs | 1 + .../CSharp/Extensions/SyntaxNodeExtensions.cs | 8 ++++++ .../Compiler/Core/Extensions/MethodKindEx.cs | 5 +++- .../Utilities/SymbolEquivalenceComparer.cs | 2 ++ 8 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLessAndGreaterThanCompletionTests.cs b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLessAndGreaterThanCompletionTests.cs index da55d50df7de0..7eb9a06a509dd 100644 --- a/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLessAndGreaterThanCompletionTests.cs +++ b/src/EditorFeatures/CSharpTest/AutomaticCompletion/AutomaticLessAndGreaterThanCompletionTests.cs @@ -392,6 +392,19 @@ public void Method() { } CheckStart(session.Session); } + [WpfFact, Trait(Traits.Feature, Traits.Features.AutomaticCompletion)] + public void FunctionPointerStartSession() + { + var code = @" +class C +{ + delegate*$$"; + + using var session = CreateSession(code); + Assert.NotNull(session); + CheckStart(session.Session); + } + internal Holder CreateSession(string code) { return CreateSession( diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index 9bd35d15ee65f..267e08c766ed2 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs @@ -2,7 +2,6 @@ // 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.Diagnostics.Tracing; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -46,8 +45,17 @@ await VerifyKeywordAsync(SourceCodeKind.Script, [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestInUsingAlias() { - await VerifyKeywordAsync( + await VerifyAbsenceAsync( @"using Goo = $$"); + await VerifyAbsenceAsync( +@"using Goo = d$$"); + } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInUsingAliasTypeParameter() + { + await VerifyKeywordAsync( +@"using Goo = T<$$"); } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs index 915530f02a81b..7059ef311370f 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DynamicKeywordRecommenderTests.cs @@ -642,5 +642,32 @@ class C { delegate*<$$"); } + + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] + public async Task TestInFunctionPointerTypeAfterComma() + { + await VerifyKeywordAsync(@" +class C +{ + delegate* context.IsNonAttributeExpressionContext || context.IsTypeContext; + static bool ValidTypeContext(CSharpSyntaxContext context) + => (context.IsNonAttributeExpressionContext || context.IsTypeContext) + && !context.IsConstantExpressionContext + && !context.LeftToken.IsTopLevelOfUsingAliasDirective(); } private static bool IsAfterAsyncKeywordInExpressionContext(CSharpSyntaxContext context, CancellationToken cancellationToken) diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index a48c7ce12eb8a..bbf110a00e076 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -208,6 +208,7 @@ internal static SyntaxTokenList GetParameterModifiers(RefKind refKind, bool forF RefKind.Ref => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword)), // Note: RefKind.RefReadonly == RefKind.In. Function Pointers must use the correct // ref kind syntax when generating for the return parameter vs other parameters. + // The return parameter must use ref readonly, like regular methods. RefKind.In when !forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.InKeyword)), RefKind.RefReadOnly when forFunctionPointerReturnParameter => SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.RefKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)), _ => throw ExceptionUtilities.UnexpectedValue(refKind), diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index 56761202f745e..7f8c9f893db62 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -1031,6 +1031,14 @@ public static bool IsInDeconstructionLeft( return false; } + public static bool IsTopLevelOfUsingAliasDirective(this SyntaxToken node) + => node switch + { + { Parent: NameEqualsSyntax { Parent: UsingDirectiveSyntax _ } } => true, + { Parent: IdentifierNameSyntax { Parent: UsingDirectiveSyntax _ } } => true, + _ => false + }; + public static T WithCommentsFrom(this T node, SyntaxToken leadingToken, SyntaxToken trailingToken) where T : SyntaxNode => node.WithCommentsFrom( diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs index 001501d1d665d..803762cf6aa78 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/MethodKindEx.cs @@ -1,4 +1,7 @@ -#nullable enable +// 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. +#nullable enable using System.Diagnostics.CodeAnalysis; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs index 1e49922e566c4..c113e1cf5e345 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Utilities/SymbolEquivalenceComparer.cs @@ -186,6 +186,8 @@ private static bool CheckContainingType(IMethodSymbol x) } else if (x.MethodKind == MethodKindEx.FunctionPointerSignature) { + // We use the signature of a function pointer type to determine equivalence, but + // function pointer types do not have containing types. return false; } From 0150ae27b2e1cfdf2f3a820ad7d28f1cde0fbde5 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Thu, 28 May 2020 18:52:21 -0700 Subject: [PATCH 07/15] Readd spacing rule for delegate*, reorder for clarity. --- .../Formatting/Rules/SpacingFormattingRule.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs index af930bc368055..6ce31e81cb688 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Formatting/Rules/SpacingFormattingRule.cs @@ -323,6 +323,18 @@ previousToken.Parent is AssignmentExpressionSyntax || // Function pointer type adjustments if (previousParentKind == SyntaxKindEx.FunctionPointerType && currentParentKind == SyntaxKindEx.FunctionPointerType) { + // No spacing between delegate and * + if (currentKind == SyntaxKind.AsteriskToken && previousKind == SyntaxKind.DelegateKeyword) + { + return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); + } + + // Force a space between * and the calling convention + if (currentKind == SyntaxKind.IdentifierToken && previousKind == SyntaxKind.AsteriskToken) + { + return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); + } + if (currentKind == SyntaxKind.LessThanToken) { switch (previousKind) @@ -335,12 +347,6 @@ previousToken.Parent is AssignmentExpressionSyntax || return CreateAdjustSpacesOperation(0, AdjustSpacesOption.ForceSpacesIfOnSingleLine); } } - - // Force a space between * and the calling convention - if (currentKind == SyntaxKind.IdentifierToken && previousKind == SyntaxKind.AsteriskToken) - { - return CreateAdjustSpacesOperation(1, AdjustSpacesOption.ForceSpacesIfOnSingleLine); - } } // For spacing after the 'not' pattern operator From ee207099b7e80153321ae36a19786305047e3791 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 09:32:46 -0700 Subject: [PATCH 08/15] Remove unusued using. --- .../Completion/KeywordRecommenders/VoidKeywordRecommender.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs index d753b104b3798..669b793586557 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/VoidKeywordRecommender.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Utilities; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { From d6b45eea40fb03f8c67dafd86fc9116ae33a3321 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 10:10:20 -0700 Subject: [PATCH 09/15] Remove other unused using. --- .../ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index e86d96c6b9c8f..c43dcb4aae46e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; From d57ff242c4a10327b6552779f8d868dadac71399 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 10:30:16 -0700 Subject: [PATCH 10/15] Conditionally add using for non-codestyle. --- .../ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index c43dcb4aae46e..24f59e6843adc 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -6,6 +6,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +#if !CODE_STYLE +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; +#endif using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; From ed7c4ae8af564dc4d0354a0c3ec0e756d48f4cba Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 11:02:24 -0700 Subject: [PATCH 11/15] Update error messages for clarity and rename test. --- src/Compilers/CSharp/Portable/CSharpResources.resx | 4 ++-- .../CSharp/Portable/xlf/CSharpResources.cs.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.de.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.es.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.fr.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.it.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.ja.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.ko.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.pl.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.pt-BR.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.ru.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.tr.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf | 8 ++++---- .../CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf | 8 ++++---- .../Emit/CodeGen/CodeGenFunctionPointersTests.cs | 12 ++++++------ .../CSharp/Test/Semantic/Semantics/UnsafeTests.cs | 2 +- .../DelegateKeywordRecommenderTests.cs | 2 +- 17 files changed, 62 insertions(+), 62 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 115e9b7dc40a3..8b4f2f79ef5a2 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6161,9 +6161,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ 'RefKind.Out' is not a valid ref kind for a return type. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 10e27daa55c51..1a8004fc3f922 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index bf76520ce1bc6..03c3c6663f339 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index a09f3c7f123c0..b9c7f9bf939c1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index e8d3f71bf823a..763f00a2cd940 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index f5331a9c36d1e..63fbd921641ae 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 89c7c68de2eda..a1ed2032dc585 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 2ba892d855306..ca1ef88e8b19a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 03a91fcab42aa..c92dc56d99995 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index ba156a3f517df..94c8ad1e39ddc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 62a1ecf231695..7a89322f9afe5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index bcf48335885fe..c3d8f5337bba6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 1e5a778f9e42f..63a9a0ec7a770 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index dc04b99a8d653..46ed73372fee8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -23,8 +23,8 @@ - Cannot convert & method group '{0}' to non-function pointer type '{1}'. - Cannot convert & method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. + Cannot convert &method group '{0}' to non-function pointer type '{1}'. @@ -123,8 +123,8 @@ - Cannot convert & method group '{0}' to delegate type '{0}'. - Cannot convert & method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. + Cannot convert &method group '{0}' to delegate type '{0}'. diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs index be3253730cc6a..00b9ffd547b0e 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenFunctionPointersTests.cs @@ -3670,10 +3670,10 @@ static void M() }"); comp.VerifyDiagnostics( - // (6,22): error CS8801: Cannot convert & method group 'M' to non-function pointer type 'void*'. + // (6,22): error CS8801: Cannot convert &method group 'M' to non-function pointer type 'void*'. // void* ptr1 = &M; Diagnostic(ErrorCode.ERR_AddressOfToNonFunctionPointer, "&M").WithArguments("M", "void*").WithLocation(6, 22), - // (7,22): error CS8801: Cannot convert & method group 'M' to non-function pointer type 'void*'. + // (7,22): error CS8801: Cannot convert &method group 'M' to non-function pointer type 'void*'. // void* ptr2 = (void*)&M; Diagnostic(ErrorCode.ERR_AddressOfToNonFunctionPointer, "(void*)&M").WithArguments("M", "void*").WithLocation(7, 22) ); @@ -3722,10 +3722,10 @@ unsafe void M() // (8,24): error CS0119: 'Action' is a type, which is not valid in the given context // Action ptr1 = (Action)&M; Diagnostic(ErrorCode.ERR_BadSKunknown, "Action").WithArguments("System.Action", "type").WithLocation(8, 24), - // (9,23): error CS8800: Cannot convert & method group 'M' to delegate type 'M'. + // (9,23): error CS8800: Cannot convert &method group 'M' to delegate type 'M'. // Action ptr2 = (Action)(&M); Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "(Action)(&M)").WithArguments("M", "System.Action").WithLocation(9, 23), - // (10,23): error CS8800: Cannot convert & method group 'M' to delegate type 'M'. + // (10,23): error CS8800: Cannot convert &method group 'M' to delegate type 'M'. // Action ptr3 = &M; Diagnostic(ErrorCode.ERR_CannotConvertAddressOfToDelegate, "&M").WithArguments("M", "System.Action").WithLocation(10, 23) ); @@ -3774,10 +3774,10 @@ unsafe void M() // (7,19): error CS0119: 'C' is a type, which is not valid in the given context // C ptr1 = (C)&M; Diagnostic(ErrorCode.ERR_BadSKunknown, "C").WithArguments("C", "type").WithLocation(7, 19), - // (8,18): error CS8801: Cannot convert & method group 'M' to non-function pointer type 'C'. + // (8,18): error CS8801: Cannot convert &method group 'M' to non-function pointer type 'C'. // C ptr2 = (C)(&M); Diagnostic(ErrorCode.ERR_AddressOfToNonFunctionPointer, "(C)(&M)").WithArguments("M", "C").WithLocation(8, 18), - // (9,18): error CS8801: Cannot convert & method group 'M' to non-function pointer type 'C'. + // (9,18): error CS8801: Cannot convert &method group 'M' to non-function pointer type 'C'. // C ptr3 = &M; Diagnostic(ErrorCode.ERR_AddressOfToNonFunctionPointer, "&M").WithArguments("M", "C").WithLocation(9, 18) ); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs index 92f9545ced62a..d8ad314d4da38 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UnsafeTests.cs @@ -3598,7 +3598,7 @@ enum Color // (40,15): error CS0211: Cannot take the address of the given expression // p = &(() => 1); //CS0211 Diagnostic(ErrorCode.ERR_InvalidAddrOp, "() => 1").WithLocation(40, 15), - // (41,13): error CS8801: Cannot convert & method group 'M' to non-function pointer type 'int*'. + // (41,13): error CS8801: Cannot convert &method group 'M' to non-function pointer type 'int*'. // p = &M; //CS0211 Diagnostic(ErrorCode.ERR_AddressOfToNonFunctionPointer, "&M").WithArguments("M", "int*").WithLocation(41, 13), // (42,15): error CS0211: Cannot take the address of the given expression diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs index 267e08c766ed2..ff05e8fced2b3 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/DelegateKeywordRecommenderTests.cs @@ -43,7 +43,7 @@ await VerifyKeywordAsync(SourceCodeKind.Script, } [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] - public async Task TestInUsingAlias() + public async Task TestNotInUsingAlias() { await VerifyAbsenceAsync( @"using Goo = $$"); From dd47d72a2981a2c1ca805123f98c9a711c5c1e9a Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 12:37:59 -0700 Subject: [PATCH 12/15] Narrow factory types, add tests. --- .../CSharp/Portable/Syntax/SyntaxFactory.cs | 4 ++-- .../Semantic/Semantics/FunctionPointerTests.cs | 7 +++++++ .../Test/Syntax/Syntax/SyntaxFactoryTests.cs | 16 ++++++++++++++++ .../Portable/Syntax/SyntaxNodeFactories.vb | 4 ++-- .../Test/Syntax/Syntax/SyntaxFactoryTests.vb | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs index c725cddb2c3eb..f5cdcce077d8d 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFactory.cs @@ -1703,9 +1703,9 @@ public static TypeSyntax ParseTypeName(string text, int offset, bool consumeFull /// /// Parse a TypeNameSyntax node using the grammar rule for type names. /// - public static TypeSyntax ParseTypeName(string text, int offset = 0, ParseOptions? options = null, bool consumeFullText = true) + public static TypeSyntax ParseTypeName(string text, int offset = 0, CSharpParseOptions? options = null, bool consumeFullText = true) { - using (var lexer = MakeLexer(text, offset, (CSharpParseOptions?)options)) + using (var lexer = MakeLexer(text, offset, options)) using (var parser = MakeParser(lexer)) { var node = parser.ParseTypeName(); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index 6a06bee1c0ffb..47028145a5bab 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs @@ -29,6 +29,13 @@ private CompilationVerifier CompileAndVerifyFunctionPointers(CSharpCompilation c return CompileAndVerify(compilation, verify: Verification.Skipped, expectedOutput: expectedOutput); } + [Fact] + public void UsingTest() + { + CreateCompilationWithFunctionPointers(@" +using s = delegate*;").VerifyDiagnostics(); + } + [Fact] public void ImplicitConversionToVoid() { diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs index bac8d43fd3701..12bf83026ee57 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxFactoryTests.cs @@ -588,5 +588,21 @@ public void TestParenthesizedLambdaNoParameterList_ExpressionBody() body: SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(1))); Assert.Equal(fullySpecified.ToFullString(), lambda.ToFullString()); } + + [Fact] + public void TestParseNameWithOptions() + { + var type = "delegate*"; + + var parsedWith8 = SyntaxFactory.ParseTypeName(type, options: TestOptions.Regular8); + parsedWith8.GetDiagnostics().Verify( + // (1,1): error CS8652: The feature 'function pointers' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // delegate* + Diagnostic(ErrorCode.ERR_FeatureInPreview, "delegate*").WithArguments("function pointers").WithLocation(1, 1) + ); + + var parsedWithPreview = SyntaxFactory.ParseTypeName(type, options: TestOptions.RegularPreview); + parsedWithPreview.GetDiagnostics().Verify(); + } } } diff --git a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb index a272b57adabbc..5b17efc0222db 100644 --- a/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb +++ b/src/Compilers/VisualBasic/Portable/Syntax/SyntaxNodeFactories.vb @@ -192,8 +192,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ''' ''' The input string ''' The starting offset in the string - Public Shared Function ParseTypeName(text As String, Optional offset As Integer = 0, Optional options As ParseOptions = Nothing, Optional consumeFullText As Boolean = True) As TypeSyntax - Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(DirectCast(options, VisualBasicParseOptions), VisualBasicParseOptions.Default)) + Public Shared Function ParseTypeName(text As String, Optional offset As Integer = 0, Optional options As VisualBasicParseOptions = Nothing, Optional consumeFullText As Boolean = True) As TypeSyntax + Using p = New InternalSyntax.Parser(MakeSourceText(text, offset), If(options, VisualBasicParseOptions.Default)) p.GetNextToken() Dim node = p.ParseGeneralType() Return DirectCast(If(consumeFullText, p.ConsumeUnexpectedTokens(node), node).CreateRed(Nothing, 0), TypeSyntax) diff --git a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb index 0eb9346399c19..429e675ddb546 100644 --- a/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb +++ b/src/Compilers/VisualBasic/Test/Syntax/Syntax/SyntaxFactoryTests.vb @@ -109,5 +109,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests Assert.Equal(expected, literalMethod.Invoke(Nothing, {value}).ToString()) End Sub + + + Public Shared Sub TestParseTypeNameOptions() + Dim options As VisualBasicParseOptions = TestOptions.Regular + Dim code = " +#If Variable +String +#Else +Integer +#End If" + + Dim type1 = SyntaxFactory.ParseTypeName(code, options:=options.WithPreprocessorSymbols(New KeyValuePair(Of String, Object)("Variable", "True"))) + Assert.Equal("String", type1.ToString()) + + Dim type2 = SyntaxFactory.ParseTypeName(code, options:=options) + Assert.Equal("Integer", type2.ToString()) + End Sub End Class End Namespace From 6f706da3933ad78b1e38984413308c97abe1fdbd Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 12:54:15 -0700 Subject: [PATCH 13/15] Correct public API files, fix build script. --- eng/build.sh | 2 +- src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt | 2 +- src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/build.sh b/eng/build.sh index 56b795582c062..3dfb1abe19534 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -134,7 +134,7 @@ while [[ $# > 0 ]]; do # Bootstrap requires restore restore=true ;; - --runAnalyzers) + --runanalyzers) run_analyzers=true ;; --preparemachine) diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 0d1fcfc4f6db2..b496637f10230 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -108,7 +108,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.BinaryPattern(Microsoft.CodeA static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression() -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitObjectCreationExpression(Microsoft.CodeAnalysis.SyntaxToken newKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ArgumentListSyntax argumentList, Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax initializer) -> Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax -static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset = 0, Microsoft.CodeAnalysis.ParseOptions options = null, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset = 0, Microsoft.CodeAnalysis.CSharp.CSharpParseOptions options = null, bool consumeFullText = true) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParseTypeName(string text, int offset, bool consumeFullText) -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitFunctionPointerType(Microsoft.CodeAnalysis.CSharp.Syntax.FunctionPointerTypeSyntax node) -> TResult diff --git a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt index 9fef8141e9b9e..3be2c921b772c 100644 --- a/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/VisualBasic/Portable/PublicAPI.Unshipped.txt @@ -1,3 +1,3 @@ -Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer = 0, options As Microsoft.CodeAnalysis.ParseOptions = Nothing, consumeFullText As Boolean = True) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax +Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer = 0, options As Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions = Nothing, consumeFullText As Boolean = True) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer, consumeFullText As Boolean) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax *REMOVED*Shared Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory.ParseTypeName(text As String, offset As Integer = 0, consumeFullText As Boolean = True) -> Microsoft.CodeAnalysis.VisualBasic.Syntax.TypeSyntax From 5d4b41b9ef12af7442d987d7fcdfbcf440f7f098 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 13:39:30 -0700 Subject: [PATCH 14/15] Add missing diagnostics. --- .../Semantics/FunctionPointerTests.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs index 47028145a5bab..9802202ffe8e2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FunctionPointerTests.cs @@ -30,10 +30,25 @@ private CompilationVerifier CompileAndVerifyFunctionPointers(CSharpCompilation c } [Fact] - public void UsingTest() + public void UsingAliasTest() { - CreateCompilationWithFunctionPointers(@" -using s = delegate*;").VerifyDiagnostics(); + var comp = CreateCompilationWithFunctionPointers(@" +using s = delegate*;"); + + comp.VerifyDiagnostics( + // (2,1): hidden CS8019: Unnecessary using directive. + // using s = delegate*; + Diagnostic(ErrorCode.HDN_UnusedUsingDirective, "using s = ").WithLocation(2, 1), + // (2,11): error CS1041: Identifier expected; 'delegate' is a keyword + // using s = delegate*; + Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "delegate").WithArguments("", "delegate").WithLocation(2, 11), + // (2,25): error CS0116: A namespace cannot directly contain members such as fields or methods + // using s = delegate*; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ">").WithLocation(2, 25), + // (2,26): error CS1022: Type or namespace definition, or end-of-file expected + // using s = delegate*; + Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(2, 26) + ); } [Fact] From e8194c5d72461b2c8b9007bed4a63db76460903e Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 29 May 2020 13:47:41 -0700 Subject: [PATCH 15/15] Added parsing test. --- .../Syntax/Parsing/FunctionPointerTests.cs | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs index 382022f27aef5..665c142977acf 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FunctionPointerTests.cs @@ -3106,5 +3106,44 @@ public void FunctionPointerArrayInTypeArgument() } EOF(); } + + [Fact] + public void UsingAlias() + { + UsingNode("using t = delegate*;", options: TestOptions.RegularPreview, + // (1,11): error CS1041: Identifier expected; 'delegate' is a keyword + // using t = delegate*; + Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "delegate").WithArguments("", "delegate").WithLocation(1, 11), + // (1,25): error CS0116: A namespace cannot directly contain members such as fields or methods + // using t = delegate*; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, ">").WithLocation(1, 25), + // (1,26): error CS1022: Type or namespace definition, or end-of-file expected + // using t = delegate*; + Diagnostic(ErrorCode.ERR_EOFExpected, ";").WithLocation(1, 26) + ); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.UsingDirective); + { + N(SyntaxKind.UsingKeyword); + N(SyntaxKind.NameEquals); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "t"); + } + N(SyntaxKind.EqualsToken); + } + M(SyntaxKind.IdentifierName); + { + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } } }