From ab4d3850599de58b86ad780d65d22930e7da7646 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Tue, 25 Jan 2022 21:46:34 +0200 Subject: [PATCH 01/21] Classify function pointer calling convention --- .../Classification/TotalClassifierTests.cs | 31 ++++++++++++++ .../CSharpSyntaxClassificationService.cs | 3 +- ...ctionPointerCallingConventionClassifier.cs | 41 +++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index 19bb5e55fb279..dfcedfe279ad5 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -2189,5 +2189,36 @@ public async Task TestStringEscape(TestHost testHost) Verbatim("\""), Punctuation.Semicolon); } + + [Theory] + [CombinatorialData] + [WorkItem(59052, "https://github.com/dotnet/roslyn/issues/59052")] + public async Task FunctionPointerCallingConventions(TestHost testHost) + { + await TestAsync(@" +public unsafe class C +{ + delegate* unmanaged[Stdcall] f0; +} +", + testHost, + Keyword("public"), + Keyword("unsafe"), + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("delegate"), + Operators.Asterisk, + Keyword("unmanaged"), + Punctuation.OpenBracket, + Class("Stdcall"), + Punctuation.CloseBracket, + Punctuation.OpenAngle, + Keyword("void"), + Punctuation.CloseAngle, + Field("f0"), + Punctuation.Semicolon, + Punctuation.CloseCurly); + } } } diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs index 246b0b8597c71..7cab83616ba52 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs @@ -37,7 +37,8 @@ public CSharpSyntaxClassificationService(HostLanguageServices languageServices) new OperatorOverloadSyntaxClassifier(), new SyntaxTokenClassifier(), new UsingDirectiveSyntaxClassifier(), - new DiscardSyntaxClassifier() + new DiscardSyntaxClassifier(), + new FunctionPointerCallingConventionClassifier(), }); } diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs new file mode 100644 index 0000000000000..77885a77d621a --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Immutable; +using System.Threading; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Classification.Classifiers; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.CSharp.Classification +{ + internal class FunctionPointerCallingConventionClassifier : AbstractSyntaxClassifier + { + public override ImmutableArray SyntaxNodeTypes { get; } = ImmutableArray.Create( + typeof(FunctionPointerUnmanagedCallingConventionSyntax)); + + public override void AddClassifications( + SyntaxNode syntax, + SemanticModel semanticModel, + ClassificationOptions options, + ArrayBuilder result, + CancellationToken cancellationToken) + { + // We may use semanticModel.GetSymbolInfo if https://github.com/dotnet/roslyn/issues/59060 got fixed. + var name = ((FunctionPointerUnmanagedCallingConventionSyntax)syntax).Name; + var type = semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + name.ValueText); + if (type is not null) + { + var span = name.Span; + if (!span.IsEmpty) + { + result.Add(new ClassifiedSpan(span, ClassificationTypeNames.ClassName)); + } + } + } + } +} From 015ba4db023f05512a10e4d3930974562a00a529 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Tue, 25 Jan 2022 22:26:04 +0200 Subject: [PATCH 02/21] Fix GoToDefinition for function pointer calling conventions --- .../CSharpGoToDefinitionTests.vb | 18 ++++++++++++++++++ .../SemanticFacts/CSharpSemanticFacts.cs | 2 ++ 2 files changed, 20 insertions(+) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index 88d4a4bc661e5..2e53cd8584587 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3333,5 +3333,23 @@ $$ Test(workspace, expectedResult:=False) End Sub + + + + Public Sub FunctionPointerCallingConvention() + Dim workspace = + + + f0; +} + ]]> + + + + Test(workspace) + End Sub End Class End Namespace diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index 9c0544538f439..e2741d9f3062e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -267,6 +267,8 @@ public ImmutableArray GetBestOrAllSymbols(SemanticModel semanticModel, { AssignmentExpressionSyntax _ when token.Kind() == SyntaxKind.EqualsToken => GetDeconstructionAssignmentMethods(semanticModel, node).As(), ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => GetDeconstructionForEachMethods(semanticModel, node).As(), + // Delete this line if https://github.com/dotnet/roslyn/issues/59060 got fixed + FunctionPointerUnmanagedCallingConventionSyntax callingConvention => ImmutableArray.Create(semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callingConvention.Name.ValueText)), _ => GetSymbolInfo(semanticModel, node, token, cancellationToken).GetBestOrAllSymbols(), }; } From d059fddd1674e9dd6ed85679f31aa8659a1269a6 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Tue, 25 Jan 2022 22:26:55 +0200 Subject: [PATCH 03/21] Update CSharpGoToDefinitionTests.vb --- .../Test2/GoToDefinition/CSharpGoToDefinitionTests.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index 2e53cd8584587..4c03926f75909 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3334,8 +3334,8 @@ $$ Test(workspace, expectedResult:=False) End Sub - + Public Sub FunctionPointerCallingConvention() Dim workspace = From 5d75a0638bfb41b8dd321ee81dbbcfff88b8f8aa Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 01:03:05 +0200 Subject: [PATCH 04/21] Adjust logic --- .../SemanticFacts/CSharpSemanticFacts.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index e2741d9f3062e..3b6c34135818f 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -267,12 +267,34 @@ public ImmutableArray GetBestOrAllSymbols(SemanticModel semanticModel, { AssignmentExpressionSyntax _ when token.Kind() == SyntaxKind.EqualsToken => GetDeconstructionAssignmentMethods(semanticModel, node).As(), ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => GetDeconstructionForEachMethods(semanticModel, node).As(), - // Delete this line if https://github.com/dotnet/roslyn/issues/59060 got fixed - FunctionPointerUnmanagedCallingConventionSyntax callingConvention => ImmutableArray.Create(semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callingConvention.Name.ValueText)), + FunctionPointerUnmanagedCallingConventionSyntax callingConvention => GetCallingConventionSymbol(semanticModel, callingConvention), _ => GetSymbolInfo(semanticModel, node, token, cancellationToken).GetBestOrAllSymbols(), }; } + private static ImmutableArray GetCallingConventionSymbol(SemanticModel model, FunctionPointerUnmanagedCallingConventionSyntax syntax) + { + if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) + { + return ImmutableArray.Empty; + } + + if (list.CallingConventions.Count == 1 && + syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall") + { + return ImmutableArray.Empty; + } + + var corLibrary = model.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + var type = corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + syntax.Name.ValueText); + if (type is null) + { + return ImmutableArray.Empty; + } + + return ImmutableArray.Create(type); + } + private static SymbolInfo GetSymbolInfo(SemanticModel semanticModel, SyntaxNode node, SyntaxToken token, CancellationToken cancellationToken) { switch (node) From 17729b68cc10563ab40bd9bdaca150d016e7c211 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 01:20:16 +0200 Subject: [PATCH 05/21] Adjust classifier logic --- ...ctionPointerCallingConventionClassifier.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index 77885a77d621a..3050268ee64b0 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -25,16 +25,24 @@ public override void AddClassifications( ArrayBuilder result, CancellationToken cancellationToken) { - // We may use semanticModel.GetSymbolInfo if https://github.com/dotnet/roslyn/issues/59060 got fixed. - var name = ((FunctionPointerUnmanagedCallingConventionSyntax)syntax).Name; - var type = semanticModel.Compilation.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + name.ValueText); + if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) + { + return; + } + + var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; + if (list.CallingConventions.Count == 1 && + callingConventionSyntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall") + { + result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.ClassName)); + return; + } + + var corLibrary = semanticModel.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + var type = corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callingConventionSyntax.Name.ValueText); if (type is not null) { - var span = name.Span; - if (!span.IsEmpty) - { - result.Add(new ClassifiedSpan(span, ClassificationTypeNames.ClassName)); - } + result.Add(new ClassifiedSpan(callingConventionSyntax.Name.Span, ClassificationTypeNames.ClassName)); } } } From 401f294ea4037e98dcf84bd186bc645e877e6ffa Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 01:37:18 +0200 Subject: [PATCH 06/21] Refactor --- .../FunctionPointerCallingConventionClassifier.cs | 14 ++++---------- .../Services/SemanticFacts/CSharpSemanticFacts.cs | 11 ++--------- .../Services/SyntaxFacts/CSharpSyntaxFacts.cs | 11 +++++++++++ .../Core/Extensions/ICompilationExtensions.cs | 6 ++++++ 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index 3050268ee64b0..0ab150eb5a07e 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -7,9 +7,10 @@ using System.Threading; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Classification.Classifiers; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Classification { @@ -25,21 +26,14 @@ public override void AddClassifications( ArrayBuilder result, CancellationToken cancellationToken) { - if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) - { - return; - } - var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; - if (list.CallingConventions.Count == 1 && - callingConventionSyntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall") + if (CSharpSyntaxFacts.Instance.IsSpecialUnmanagedCallingConvention(callingConventionSyntax)) { result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.ClassName)); return; } - var corLibrary = semanticModel.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; - var type = corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callingConventionSyntax.Name.ValueText); + var type = semanticModel.Compilation.UnmanagedCallingConventionType(callingConventionSyntax.Name.ValueText); if (type is not null) { result.Add(new ClassifiedSpan(callingConventionSyntax.Name.Span, ClassificationTypeNames.ClassName)); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index 3b6c34135818f..2ec6f05abc465 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -274,19 +274,12 @@ ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => Ge private static ImmutableArray GetCallingConventionSymbol(SemanticModel model, FunctionPointerUnmanagedCallingConventionSyntax syntax) { - if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) + if (CSharpSyntaxFacts.Instance.IsSpecialUnmanagedCallingConvention(syntax)) { return ImmutableArray.Empty; } - if (list.CallingConventions.Count == 1 && - syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall") - { - return ImmutableArray.Empty; - } - - var corLibrary = model.Compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; - var type = corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + syntax.Name.ValueText); + var type = model.Compilation.UnmanagedCallingConventionType(syntax.Name.ValueText); if (type is null) { return ImmutableArray.Empty; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index e9cc29d9fe2f7..eef48b1d86357 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1554,6 +1554,17 @@ public bool IsVerbatimInterpolatedStringExpression(SyntaxNode node) => node is InterpolatedStringExpressionSyntax interpolatedString && interpolatedString.StringStartToken.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken); + public bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax syntax) + { + if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) + { + return false; + } + + return list.CallingConventions.Count == 1 && + syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"); + } + #region IsXXX members public bool IsAnonymousFunctionExpression([NotNullWhen(true)] SyntaxNode? node) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index 4de3db5e271a4..42fa4939b805b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -211,5 +211,11 @@ public static ImmutableArray GetReferencedAssemblySymbols(this public static INamedTypeSymbol? DisallowNullAttribute(this Compilation compilation) => compilation.GetTypeByMetadataName(typeof(DisallowNullAttribute).FullName!); + + public static INamedTypeSymbol? UnmanagedCallingConventionType(this Compilation compilation, string callConv) + { + var corLibrary = compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; + return corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callConv); + } } } From aa4013421c64771bdf9e6bd04dcb866072de1929 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Wed, 26 Jan 2022 01:54:52 +0200 Subject: [PATCH 07/21] Update CSharpSyntaxFacts.cs --- .../Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index eef48b1d86357..caec2e500f0b8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1562,7 +1562,7 @@ public bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingC } return list.CallingConventions.Count == 1 && - syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"); + syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"; } #region IsXXX members From dc04f240ed9ece9779b32a1a3c69c39d82f95412 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Wed, 26 Jan 2022 11:51:52 +0200 Subject: [PATCH 08/21] Update CSharpGoToDefinitionTests.vb --- .../CSharpGoToDefinitionTests.vb | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index 4c03926f75909..de066f0422a47 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3336,7 +3336,7 @@ $$ - Public Sub FunctionPointerCallingConvention() + Public Sub FunctionPointerCallingConvention_Single_SpecialConv() Dim workspace = @@ -3349,6 +3349,78 @@ public unsafe class C + Test(workspace, expectedResult:=False) + End Sub + + + + Public Sub FunctionPointerCallingConvention_Single_NonSpecialConv() + Dim workspace = + + + f0; +} + ]]> + + + + Test(workspace) + End Sub + + + + Public Sub FunctionPointerCallingConvention_Multiple_SpecialConv() + Dim workspace = + + + f0; +} + ]]> + + + + Test(workspace) + End Sub + + + + Public Sub FunctionPointerCallingConvention_Multiple_NonSpecialConv() + Dim workspace = + + + f0; +} + ]]> + + + + Test(workspace) + End Sub + + + + Public Sub FunctionPointerCallingConvention_Multiple_AllAreSpecialConv() + Dim workspace = + + + f0; +} + ]]> + + + Test(workspace) End Sub End Class From a4c777b1847c0d1f2bb143dd098e7470d5a59cc1 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 11:53:55 +0200 Subject: [PATCH 09/21] Make static --- .../FunctionPointerCallingConventionClassifier.cs | 2 +- .../CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs | 2 +- .../Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index 0ab150eb5a07e..de232db268701 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -27,7 +27,7 @@ public override void AddClassifications( CancellationToken cancellationToken) { var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; - if (CSharpSyntaxFacts.Instance.IsSpecialUnmanagedCallingConvention(callingConventionSyntax)) + if (CSharpSyntaxFacts.IsSpecialUnmanagedCallingConvention(callingConventionSyntax)) { result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.ClassName)); return; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index 2ec6f05abc465..ee3fe7dbd0932 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -274,7 +274,7 @@ ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => Ge private static ImmutableArray GetCallingConventionSymbol(SemanticModel model, FunctionPointerUnmanagedCallingConventionSyntax syntax) { - if (CSharpSyntaxFacts.Instance.IsSpecialUnmanagedCallingConvention(syntax)) + if (CSharpSyntaxFacts.IsSpecialUnmanagedCallingConvention(syntax)) { return ImmutableArray.Empty; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index caec2e500f0b8..6d92d80252515 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1554,7 +1554,7 @@ public bool IsVerbatimInterpolatedStringExpression(SyntaxNode node) => node is InterpolatedStringExpressionSyntax interpolatedString && interpolatedString.StringStartToken.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken); - public bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax syntax) + public static bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax syntax) { if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) { From bbe7a76455265dfc4f402daea57d81cd0daf2a3c Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 15:08:56 +0200 Subject: [PATCH 10/21] Use Net6 in tests --- .../Test2/GoToDefinition/CSharpGoToDefinitionTests.vb | 10 +++++----- .../TestUtilities/Workspaces/TestWorkspace_Create.cs | 1 + .../Workspaces/TestWorkspace_XmlConsumption.cs | 8 ++++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index de066f0422a47..c42a73413cd5f 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3339,7 +3339,7 @@ $$ Public Sub FunctionPointerCallingConvention_Single_SpecialConv() Dim workspace = - + - + - + - + - + CreateCommonReferences(TestWorkspace wor references = TargetFrameworkUtil.NetStandard20References.ToList(); } + var net6 = element.Attribute(CommonReferencesNet6Name); + if (net6 != null && + ((bool?)net6).HasValue && + ((bool?)net6).Value) + { + references = TargetFrameworkUtil.GetReferences(TargetFramework.Net60); + } + return references; } From c81035cc20dfc34fbd04f544aa678e2db804dbea Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 15:12:58 +0200 Subject: [PATCH 11/21] Fix error --- .../TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs index 40923b2de627d..f893d323fc2e7 100644 --- a/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs +++ b/src/EditorFeatures/TestUtilities/Workspaces/TestWorkspace_XmlConsumption.cs @@ -1083,7 +1083,7 @@ private static IList CreateCommonReferences(TestWorkspace wor ((bool?)net6).HasValue && ((bool?)net6).Value) { - references = TargetFrameworkUtil.GetReferences(TargetFramework.Net60); + references = TargetFrameworkUtil.GetReferences(TargetFramework.Net60).ToList(); } return references; From ac49884b65b86cd510c3f0c71384e1483fb8722d Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 15:15:43 +0200 Subject: [PATCH 12/21] Add non-corlib test --- .../CSharpGoToDefinitionTests.vb | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index c42a73413cd5f..df566059126bf 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3423,5 +3423,30 @@ public unsafe class C Test(workspace) End Sub + + + + Public Sub FunctionPointerCallingConvention_NotFromCorLib() + Dim workspace = + + + f0; +} + +namespace System.Runtime.CompilerServices +{ + public class CallConvMemberFunction + { + } +} + ]]> + + + + Test(workspace, expectedResult:=False) + End Sub End Class End Namespace From c82742fd05c51b790bcb318380152524b591f56b Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Wed, 26 Jan 2022 16:33:06 +0200 Subject: [PATCH 13/21] Apply suggestions from code review Co-authored-by: CyrusNajmabadi --- .../CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs | 8 ++------ .../Compiler/Core/Extensions/ICompilationExtensions.cs | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index 6d92d80252515..13c35133721c3 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1556,12 +1556,8 @@ public bool IsVerbatimInterpolatedStringExpression(SyntaxNode node) public static bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax syntax) { - if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) - { - return false; - } - - return list.CallingConventions.Count == 1 && + return syntax.Parent is FunctionPointerUnmanagedCallingConventionListSyntax list && + list.CallingConventions.Count == 1 && syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs index 42fa4939b805b..08b125c3dd96e 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ICompilationExtensions.cs @@ -215,7 +215,7 @@ public static ImmutableArray GetReferencedAssemblySymbols(this public static INamedTypeSymbol? UnmanagedCallingConventionType(this Compilation compilation, string callConv) { var corLibrary = compilation.GetSpecialType(SpecialType.System_Object).ContainingAssembly; - return corLibrary.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callConv); + return corLibrary?.GetTypeByMetadataName("System.Runtime.CompilerServices.CallConv" + callConv); } } } From 473e16aa0a2a5ef506ef444763cc0cb7210ce9cb Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 16:41:21 +0200 Subject: [PATCH 14/21] Make extension method --- .../FunctionPointerCallingConventionClassifier.cs | 3 ++- .../CSharp/Extensions/SyntaxNodeExtensions.cs | 5 +++++ .../Services/SemanticFacts/CSharpSemanticFacts.cs | 2 +- .../CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs | 11 ----------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index de232db268701..8d38258182be5 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -7,6 +7,7 @@ using System.Threading; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Classification.Classifiers; +using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; @@ -27,7 +28,7 @@ public override void AddClassifications( CancellationToken cancellationToken) { var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; - if (CSharpSyntaxFacts.IsSpecialUnmanagedCallingConvention(callingConventionSyntax)) + if (callingConventionSyntax.IsSpecialUnmanagedCallingConvention()) { result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.ClassName)); return; diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index f107931667ad8..5bf2180b19df6 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -1175,5 +1175,10 @@ public static T KeepCommentsAndAddElasticMarkers(this T node) where T : Synta => node .WithTrailingTrivia(node.GetTrailingTrivia().FilterComments(addElasticMarker: true)) .WithLeadingTrivia(node.GetLeadingTrivia().FilterComments(addElasticMarker: true)); + + public static bool IsSpecialUnmanagedCallingConvention(this FunctionPointerUnmanagedCallingConventionSyntax syntax) + => syntax.Parent is FunctionPointerUnmanagedCallingConventionListSyntax list && + list.CallingConventions.Count == 1 && + syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index ee3fe7dbd0932..104eecaae4f29 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -274,7 +274,7 @@ ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => Ge private static ImmutableArray GetCallingConventionSymbol(SemanticModel model, FunctionPointerUnmanagedCallingConventionSyntax syntax) { - if (CSharpSyntaxFacts.IsSpecialUnmanagedCallingConvention(syntax)) + if (syntax.IsSpecialUnmanagedCallingConvention()) { return ImmutableArray.Empty; } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs index 6d92d80252515..e9cc29d9fe2f7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SyntaxFacts/CSharpSyntaxFacts.cs @@ -1554,17 +1554,6 @@ public bool IsVerbatimInterpolatedStringExpression(SyntaxNode node) => node is InterpolatedStringExpressionSyntax interpolatedString && interpolatedString.StringStartToken.IsKind(SyntaxKind.InterpolatedVerbatimStringStartToken); - public static bool IsSpecialUnmanagedCallingConvention(FunctionPointerUnmanagedCallingConventionSyntax syntax) - { - if (syntax.Parent is not FunctionPointerUnmanagedCallingConventionListSyntax list) - { - return false; - } - - return list.CallingConventions.Count == 1 && - syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"; - } - #region IsXXX members public bool IsAnonymousFunctionExpression([NotNullWhen(true)] SyntaxNode? node) From 313b53b847ae388e26ae5a633bc2ad447ed6d27b Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 17:09:08 +0200 Subject: [PATCH 15/21] Classify as keyword --- ...allingConventionCompletionProviderTests.cs | 2 -- ...agedCallingConventionCompletionProvider.cs | 28 +++++++++++-------- ...ctionPointerCallingConventionClassifier.cs | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProviderTests.cs index 899f35ff449b6..3fe7ad9053a01 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProviderTests.cs @@ -2,8 +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. -#nullable disable - using System; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs index 3a7dbf9ea04d4..050f78c9db9d4 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs @@ -74,14 +74,7 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var semanticModel = await document.ReuseExistingSpeculativeModelAsync(callingConventionList, cancellationToken).ConfigureAwait(false); var completionItems = new HashSet(CompletionItemComparer.Instance); - AddTypes(completionItems, contextPosition, semanticModel, cancellationToken); - - // Even if we didn't have types, there are four magic calling conventions recognized regardless. - // We add these after doing the type lookup so if we had types we can show that instead - foreach (var callingConvention in s_predefinedCallingConventions) - { - completionItems.Add(CompletionItem.Create(callingConvention, tags: GlyphTags.GetTags(Glyph.Keyword))); - } + AddTypes(completionItems, contextPosition, semanticModel, callingConventionList.CallingConventions.Count, cancellationToken); context.AddItems(completionItems); } @@ -91,8 +84,17 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) } } - private static void AddTypes(HashSet completionItems, int contextPosition, SemanticModel semanticModel, CancellationToken cancellationToken) + private static void AddTypes(HashSet completionItems, int contextPosition, SemanticModel semanticModel, int callingConventionsCount, CancellationToken cancellationToken) { + if (callingConventionsCount == 1) + { + // There are four magic calling conventions recognized without type lookup. + foreach (var callingConvention in s_predefinedCallingConventions) + { + completionItems.Add(CompletionItem.Create(callingConvention, tags: GlyphTags.GetTags(Glyph.Keyword))); + } + } + // We have to find the set of types that meet the criteria listed in // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/function-pointers.md#mapping-the-calling_convention_specifier-to-a-callkind // We skip the check of an type being in the core assembly since that's not really necessary for our work. @@ -107,16 +109,18 @@ private static void AddTypes(HashSet completionItems, int contex cancellationToken.ThrowIfCancellationRequested(); const string CallConvPrefix = "CallConv"; - if (type.DeclaredAccessibility == Accessibility.Public && type.Name.StartsWith(CallConvPrefix)) { var displayName = type.Name[CallConvPrefix.Length..]; - completionItems.Add( - SymbolCompletionItem.CreateWithSymbolId( + if (callingConventionsCount > 1 || !s_predefinedCallingConventions.Contains(displayName)) + { + completionItems.Add( + SymbolCompletionItem.CreateWithSymbolId( displayName, ImmutableArray.Create(type), rules: CompletionItemRules.Default, contextPosition)); + } } } } diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index 8d38258182be5..90b81e85238bf 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -30,7 +30,7 @@ public override void AddClassifications( var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; if (callingConventionSyntax.IsSpecialUnmanagedCallingConvention()) { - result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.ClassName)); + result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.Keyword)); return; } From d8cce8c31551b38eb63e4131e92a1730b895a03b Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Wed, 26 Jan 2022 17:17:56 +0200 Subject: [PATCH 16/21] Adjust symbol display --- .../SymbolDisplay/SymbolDisplayVisitor.Members.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index 5b806987fc8cc..fe700894b9136 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -559,16 +559,16 @@ void visitFunctionPointerSignature(IMethodSymbol symbol) switch (symbol.CallingConvention) { case SignatureCallingConvention.CDecl: - builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Cdecl")); + builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Cdecl")); break; case SignatureCallingConvention.StdCall: - builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Stdcall")); + builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Stdcall")); break; case SignatureCallingConvention.ThisCall: - builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Thiscall")); + builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Thiscall")); break; case SignatureCallingConvention.FastCall: - builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Fastcall")); + builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Fastcall")); break; case SignatureCallingConvention.Unmanaged: From a7ae4eea28c32f452393722420c85b90cfc7b196 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Wed, 26 Jan 2022 18:25:58 +0200 Subject: [PATCH 17/21] Update TotalClassifierTests.cs --- .../Classification/TotalClassifierTests.cs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index dfcedfe279ad5..cba65346915f1 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -2193,13 +2193,44 @@ public async Task TestStringEscape(TestHost testHost) [Theory] [CombinatorialData] [WorkItem(59052, "https://github.com/dotnet/roslyn/issues/59052")] - public async Task FunctionPointerCallingConventions(TestHost testHost) + public async Task FunctionPointerCallingConventions_Keyword(TestHost testHost) { await TestAsync(@" public unsafe class C { delegate* unmanaged[Stdcall] f0; } +", + testHost, + Keyword("public"), + Keyword("unsafe"), + Keyword("class"), + Class("C"), + Punctuation.OpenCurly, + Keyword("delegate"), + Operators.Asterisk, + Keyword("unmanaged"), + Punctuation.OpenBracket, + Keyword("Stdcall"), + Punctuation.CloseBracket, + Punctuation.OpenAngle, + Keyword("void"), + Punctuation.CloseAngle, + Field("f0"), + Punctuation.Semicolon, + Punctuation.CloseCurly); + } + + [Theory] + [CombinatorialData] + [WorkItem(59052, "https://github.com/dotnet/roslyn/issues/59052")] + public async Task FunctionPointerCallingConventions_Class(TestHost testHost) + { + await TestAsync(@" +public unsafe class C +{ + delegate* unmanaged[Stdcall, Fastcall] f0; +} ", testHost, Keyword("public"), @@ -2212,6 +2243,8 @@ public unsafe class C Keyword("unmanaged"), Punctuation.OpenBracket, Class("Stdcall"), + Punctuation.Comma, + Class("Fastcall"), Punctuation.CloseBracket, Punctuation.OpenAngle, Keyword("void"), From fa85916ed47e507ecf594b31fd3246eace922553 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Fri, 4 Feb 2022 15:06:46 +0200 Subject: [PATCH 18/21] Address feedback --- .../SymbolDisplayVisitor.Members.cs | 8 +++--- .../Classification/TotalClassifierTests.cs | 6 ++-- ...agedCallingConventionCompletionProvider.cs | 28 ++++++++----------- ...ctionPointerCallingConventionClassifier.cs | 13 +-------- .../CSharp/Extensions/SyntaxNodeExtensions.cs | 5 ---- .../SemanticFacts/CSharpSemanticFacts.cs | 5 ---- 6 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index fe700894b9136..5b806987fc8cc 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -559,16 +559,16 @@ void visitFunctionPointerSignature(IMethodSymbol symbol) switch (symbol.CallingConvention) { case SignatureCallingConvention.CDecl: - builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Cdecl")); + builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Cdecl")); break; case SignatureCallingConvention.StdCall: - builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Stdcall")); + builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Stdcall")); break; case SignatureCallingConvention.ThisCall: - builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Thiscall")); + builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Thiscall")); break; case SignatureCallingConvention.FastCall: - builder.Add(CreatePart(SymbolDisplayPartKind.Keyword, symbol, "Fastcall")); + builder.Add(CreatePart(SymbolDisplayPartKind.ClassName, symbol, "Fastcall")); break; case SignatureCallingConvention.Unmanaged: diff --git a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs index cba65346915f1..cee7d646c56d1 100644 --- a/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/TotalClassifierTests.cs @@ -2193,7 +2193,7 @@ public async Task TestStringEscape(TestHost testHost) [Theory] [CombinatorialData] [WorkItem(59052, "https://github.com/dotnet/roslyn/issues/59052")] - public async Task FunctionPointerCallingConventions_Keyword(TestHost testHost) + public async Task FunctionPointerCallingConventions_ClassNotUsedByCompiler(TestHost testHost) { await TestAsync(@" public unsafe class C @@ -2211,7 +2211,7 @@ public unsafe class C Operators.Asterisk, Keyword("unmanaged"), Punctuation.OpenBracket, - Keyword("Stdcall"), + Class("Stdcall"), Punctuation.CloseBracket, Punctuation.OpenAngle, Keyword("void"), @@ -2224,7 +2224,7 @@ public unsafe class C [Theory] [CombinatorialData] [WorkItem(59052, "https://github.com/dotnet/roslyn/issues/59052")] - public async Task FunctionPointerCallingConventions_Class(TestHost testHost) + public async Task FunctionPointerCallingConventions_ClassIsUsedByCompiler(TestHost testHost) { await TestAsync(@" public unsafe class C diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs index 050f78c9db9d4..3a7dbf9ea04d4 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/FunctionPointerUnmanagedCallingConventionCompletionProvider.cs @@ -74,7 +74,14 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) var semanticModel = await document.ReuseExistingSpeculativeModelAsync(callingConventionList, cancellationToken).ConfigureAwait(false); var completionItems = new HashSet(CompletionItemComparer.Instance); - AddTypes(completionItems, contextPosition, semanticModel, callingConventionList.CallingConventions.Count, cancellationToken); + AddTypes(completionItems, contextPosition, semanticModel, cancellationToken); + + // Even if we didn't have types, there are four magic calling conventions recognized regardless. + // We add these after doing the type lookup so if we had types we can show that instead + foreach (var callingConvention in s_predefinedCallingConventions) + { + completionItems.Add(CompletionItem.Create(callingConvention, tags: GlyphTags.GetTags(Glyph.Keyword))); + } context.AddItems(completionItems); } @@ -84,17 +91,8 @@ public override async Task ProvideCompletionsAsync(CompletionContext context) } } - private static void AddTypes(HashSet completionItems, int contextPosition, SemanticModel semanticModel, int callingConventionsCount, CancellationToken cancellationToken) + private static void AddTypes(HashSet completionItems, int contextPosition, SemanticModel semanticModel, CancellationToken cancellationToken) { - if (callingConventionsCount == 1) - { - // There are four magic calling conventions recognized without type lookup. - foreach (var callingConvention in s_predefinedCallingConventions) - { - completionItems.Add(CompletionItem.Create(callingConvention, tags: GlyphTags.GetTags(Glyph.Keyword))); - } - } - // We have to find the set of types that meet the criteria listed in // https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/function-pointers.md#mapping-the-calling_convention_specifier-to-a-callkind // We skip the check of an type being in the core assembly since that's not really necessary for our work. @@ -109,18 +107,16 @@ private static void AddTypes(HashSet completionItems, int contex cancellationToken.ThrowIfCancellationRequested(); const string CallConvPrefix = "CallConv"; + if (type.DeclaredAccessibility == Accessibility.Public && type.Name.StartsWith(CallConvPrefix)) { var displayName = type.Name[CallConvPrefix.Length..]; - if (callingConventionsCount > 1 || !s_predefinedCallingConventions.Contains(displayName)) - { - completionItems.Add( - SymbolCompletionItem.CreateWithSymbolId( + completionItems.Add( + SymbolCompletionItem.CreateWithSymbolId( displayName, ImmutableArray.Create(type), rules: CompletionItemRules.Default, contextPosition)); - } } } } diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs index 90b81e85238bf..470b2247f1f5b 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs @@ -27,18 +27,7 @@ public override void AddClassifications( ArrayBuilder result, CancellationToken cancellationToken) { - var callingConventionSyntax = (FunctionPointerUnmanagedCallingConventionSyntax)syntax; - if (callingConventionSyntax.IsSpecialUnmanagedCallingConvention()) - { - result.Add(new ClassifiedSpan(callingConventionSyntax.Span, ClassificationTypeNames.Keyword)); - return; - } - - var type = semanticModel.Compilation.UnmanagedCallingConventionType(callingConventionSyntax.Name.ValueText); - if (type is not null) - { - result.Add(new ClassifiedSpan(callingConventionSyntax.Name.Span, ClassificationTypeNames.ClassName)); - } + result.Add(new ClassifiedSpan(callingConventionSyntax.Name.Span, ClassificationTypeNames.ClassName)); } } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs index 5bf2180b19df6..f107931667ad8 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Extensions/SyntaxNodeExtensions.cs @@ -1175,10 +1175,5 @@ public static T KeepCommentsAndAddElasticMarkers(this T node) where T : Synta => node .WithTrailingTrivia(node.GetTrailingTrivia().FilterComments(addElasticMarker: true)) .WithLeadingTrivia(node.GetLeadingTrivia().FilterComments(addElasticMarker: true)); - - public static bool IsSpecialUnmanagedCallingConvention(this FunctionPointerUnmanagedCallingConventionSyntax syntax) - => syntax.Parent is FunctionPointerUnmanagedCallingConventionListSyntax list && - list.CallingConventions.Count == 1 && - syntax.Name.ValueText is "Cdecl" or "Stdcall" or "Thiscall" or "Fastcall"; } } diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs index 104eecaae4f29..53bcb9d814f1b 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/Services/SemanticFacts/CSharpSemanticFacts.cs @@ -274,11 +274,6 @@ ForEachVariableStatementSyntax _ when token.Kind() == SyntaxKind.InKeyword => Ge private static ImmutableArray GetCallingConventionSymbol(SemanticModel model, FunctionPointerUnmanagedCallingConventionSyntax syntax) { - if (syntax.IsSpecialUnmanagedCallingConvention()) - { - return ImmutableArray.Empty; - } - var type = model.Compilation.UnmanagedCallingConventionType(syntax.Name.ValueText); if (type is null) { From d0ded00852fab98d8f82bf1114e118dbab7a52ed Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Fri, 4 Feb 2022 15:29:40 +0200 Subject: [PATCH 19/21] Simplify --- .../Classification/ClassificationHelpers.cs | 4 +++ .../CSharpSyntaxClassificationService.cs | 1 - ...ctionPointerCallingConventionClassifier.cs | 33 ------------------- 3 files changed, 4 insertions(+), 34 deletions(-) delete mode 100644 src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs diff --git a/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs b/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs index 7554944b81cbf..ad593323386bc 100644 --- a/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs +++ b/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs @@ -289,6 +289,10 @@ private static bool IsVerbatimStringToken(SyntaxToken token) { return ClassificationTypeNames.LabelName; } + else if (token.Parent.IsKind(SyntaxKind.FunctionPointerUnmanagedCallingConvention)) + { + return ClassificationTypeNames.ClassName; + } else { return ClassificationTypeNames.Identifier; diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs index 7cab83616ba52..8c6c6183dd8b9 100644 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs +++ b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/CSharpSyntaxClassificationService.cs @@ -38,7 +38,6 @@ public CSharpSyntaxClassificationService(HostLanguageServices languageServices) new SyntaxTokenClassifier(), new UsingDirectiveSyntaxClassifier(), new DiscardSyntaxClassifier(), - new FunctionPointerCallingConventionClassifier(), }); } diff --git a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs b/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs deleted file mode 100644 index 470b2247f1f5b..0000000000000 --- a/src/Workspaces/CSharp/Portable/Classification/SyntaxClassification/FunctionPointerCallingConventionClassifier.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Immutable; -using System.Threading; -using Microsoft.CodeAnalysis.Classification; -using Microsoft.CodeAnalysis.Classification.Classifiers; -using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Shared.Extensions; - -namespace Microsoft.CodeAnalysis.CSharp.Classification -{ - internal class FunctionPointerCallingConventionClassifier : AbstractSyntaxClassifier - { - public override ImmutableArray SyntaxNodeTypes { get; } = ImmutableArray.Create( - typeof(FunctionPointerUnmanagedCallingConventionSyntax)); - - public override void AddClassifications( - SyntaxNode syntax, - SemanticModel semanticModel, - ClassificationOptions options, - ArrayBuilder result, - CancellationToken cancellationToken) - { - result.Add(new ClassifiedSpan(callingConventionSyntax.Name.Span, ClassificationTypeNames.ClassName)); - } - } -} From 514665eac832753d69a08660cc29681874b66df9 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Fri, 4 Feb 2022 19:47:06 +0200 Subject: [PATCH 20/21] Update CSharpGoToDefinitionTests.vb --- .../Test2/GoToDefinition/CSharpGoToDefinitionTests.vb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb index df566059126bf..41b35ba861c3e 100644 --- a/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb +++ b/src/EditorFeatures/Test2/GoToDefinition/CSharpGoToDefinitionTests.vb @@ -3349,7 +3349,7 @@ public unsafe class C - Test(workspace, expectedResult:=False) + Test(workspace) End Sub From 0814107d066f7793b07e7c3a746a771a50522bb3 Mon Sep 17 00:00:00 2001 From: Youssef Victor Date: Sat, 5 Feb 2022 11:40:29 +0200 Subject: [PATCH 21/21] Update SyntacticClassifierTests.cs --- .../CSharpTest/Classification/SyntacticClassifierTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index fa671a21b1114..4ff7dea2ced39 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -5564,9 +5564,9 @@ await TestAsync(code, Operators.Asterisk, Keyword("unmanaged"), Punctuation.OpenBracket, - Identifier("Stdcall"), + Class("Stdcall"), Punctuation.Comma, - Identifier("SuppressGCTransition"), + Class("SuppressGCTransition"), Punctuation.CloseBracket, Punctuation.OpenAngle, Keyword("int"),