From 2af9d3270bdc7f1ee3404b8ff6154b7a43ede67e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 14:48:18 -0800 Subject: [PATCH 01/21] Share ISyntaxFacts with CodeStyle layer. --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 9 +++++++++ .../SyntaxFactsService/ISyntaxFactsService.cs | 3 +-- .../ISyntaxFactsService_LanguageService.cs | 12 ++++++++++++ .../SyntaxFactsService/ISyntaxKindsService.cs | 4 +--- .../ISyntaxKindsService_LanguageService.cs | 16 ++++++++++++++++ 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService_LanguageService.cs create mode 100644 src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService_LanguageService.cs diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index d0c3372e2c499..50c585dd075e2 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -127,6 +127,12 @@ + + + + + + @@ -198,5 +204,8 @@ + + + \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs index 55623bd40a6e0..34e2ec1923312 100644 --- a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService.cs @@ -7,12 +7,11 @@ using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.LanguageServices { - internal interface ISyntaxFactsService : ILanguageService + internal partial interface ISyntaxFactsService { bool IsCaseSensitive { get; } StringComparer StringComparer { get; } diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService_LanguageService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService_LanguageService.cs new file mode 100644 index 0000000000000..21a65f0b0c225 --- /dev/null +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxFactsService_LanguageService.cs @@ -0,0 +1,12 @@ +// 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 Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.LanguageServices +{ + internal partial interface ISyntaxFactsService : ILanguageService + { + } +} diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService.cs index c3317019e0775..024f961076c25 100644 --- a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService.cs +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService.cs @@ -2,15 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.CodeAnalysis.Host; - namespace Microsoft.CodeAnalysis.LanguageServices { /// /// Provides a uniform view of SyntaxKinds over C# and VB for constructs they have /// in common. /// - internal interface ISyntaxKindsService : ILanguageService + internal partial interface ISyntaxKindsService { int DotToken { get; } int QuestionToken { get; } diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService_LanguageService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService_LanguageService.cs new file mode 100644 index 0000000000000..e9ff40fe842e0 --- /dev/null +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/ISyntaxKindsService_LanguageService.cs @@ -0,0 +1,16 @@ +// 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 Microsoft.CodeAnalysis.Host; + +namespace Microsoft.CodeAnalysis.LanguageServices +{ + /// + /// Provides a uniform view of SyntaxKinds over C# and VB for constructs they have + /// in common. + /// + internal partial interface ISyntaxKindsService : ILanguageService + { + } +} From f2ab78f949db5101d10f74dd9e88fa6077b1c21c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 14:55:56 -0800 Subject: [PATCH 02/21] Share more. --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 8 ++ ...bstractDeclaredSymbolInfoFactoryService.cs | 104 ++++++++++++++++++ .../AbstractSyntaxFactsService.cs | 92 ---------------- 3 files changed, 112 insertions(+), 92 deletions(-) create mode 100644 src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractDeclaredSymbolInfoFactoryService.cs diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 50c585dd075e2..c7e4273018efd 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -127,7 +127,9 @@ + + @@ -175,6 +177,12 @@ + + + + + + diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractDeclaredSymbolInfoFactoryService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractDeclaredSymbolInfoFactoryService.cs new file mode 100644 index 0000000000000..291699ea90195 --- /dev/null +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractDeclaredSymbolInfoFactoryService.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Globalization; +using System.Text; +using Microsoft.CodeAnalysis.FindSymbols; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.LanguageServices +{ + internal abstract class AbstractDeclaredSymbolInfoFactoryService : IDeclaredSymbolInfoFactoryService + { + private const string GenericTypeNameManglingString = "`"; + private static readonly string[] s_aritySuffixesOneToNine = { "`1", "`2", "`3", "`4", "`5", "`6", "`7", "`8", "`9" }; + + private readonly static ObjectPool>> s_aliasMapListPool + = SharedPools.Default>>(); + + // Note: these names are stored case insensitively. That way the alias mapping works + // properly for VB. It will mean that our inheritance maps may store more links in them + // for C#. However, that's ok. It will be rare in practice, and all it means is that + // we'll end up examining slightly more types (likely 0) when doing operations like + // Find all references. + private readonly static ObjectPool> s_aliasMapPool + = SharedPools.StringIgnoreCaseDictionary(); + + protected static List> AllocateAliasMapList() + => s_aliasMapListPool.Allocate(); + + protected static void FreeAliasMapList(List> list) + { + if (list != null) + { + foreach (var aliasMap in list) + { + FreeAliasMap(aliasMap); + } + + s_aliasMapListPool.ClearAndFree(list); + } + } + + protected static void FreeAliasMap(Dictionary aliasMap) + { + if (aliasMap != null) + { + s_aliasMapPool.ClearAndFree(aliasMap); + } + } + + protected static Dictionary AllocateAliasMap() + => s_aliasMapPool.Allocate(); + + protected static void AppendTokens(SyntaxNode node, StringBuilder builder) + { + foreach (var child in node.ChildNodesAndTokens()) + { + if (child.IsToken) + { + builder.Append(child.AsToken().Text); + } + else + { + AppendTokens(child.AsNode(), builder); + } + } + } + + protected static void Intern(StringTable stringTable, ArrayBuilder builder) + { + for (int i = 0, n = builder.Count; i < n; i++) + { + builder[i] = stringTable.Add(builder[i]); + } + } + + public static string GetMetadataAritySuffix(int arity) + { + Debug.Assert(arity > 0); + return (arity <= s_aritySuffixesOneToNine.Length) + ? s_aritySuffixesOneToNine[arity - 1] + : string.Concat(GenericTypeNameManglingString, arity.ToString(CultureInfo.InvariantCulture)); + } + + public abstract bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNode node, string rootNamespace, out DeclaredSymbolInfo declaredSymbolInfo); + + /// + /// Get the name of the target type of specified extension method declaration. + /// The node provided must be an extension method declaration, i.e. calling `TryGetDeclaredSymbolInfo()` + /// on `node` should return a `DeclaredSymbolInfo` of kind `ExtensionMethod`. + /// If the return value is null, then it means this is a "complex" method (as described at ). + /// + public abstract string GetTargetTypeName(SyntaxNode node); + + public abstract bool TryGetAliasesFromUsingDirective(SyntaxNode node, out ImmutableArray<(string aliasName, string name)> aliases); + + public abstract string GetRootNamespace(CompilationOptions compilationOptions); + } +} diff --git a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs index d7d6dfa889499..63a221d7666b4 100644 --- a/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs +++ b/src/Workspaces/Core/Portable/LanguageServices/SyntaxFactsService/AbstractSyntaxFactsService.cs @@ -7,11 +7,8 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Globalization; using System.Linq; -using System.Text; using System.Threading; -using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; @@ -20,95 +17,6 @@ namespace Microsoft.CodeAnalysis.LanguageServices { - internal abstract class AbstractDeclaredSymbolInfoFactoryService : IDeclaredSymbolInfoFactoryService - { - private const string GenericTypeNameManglingString = "`"; - private static readonly string[] s_aritySuffixesOneToNine = { "`1", "`2", "`3", "`4", "`5", "`6", "`7", "`8", "`9" }; - - private readonly static ObjectPool>> s_aliasMapListPool - = SharedPools.Default>>(); - - // Note: these names are stored case insensitively. That way the alias mapping works - // properly for VB. It will mean that our inheritance maps may store more links in them - // for C#. However, that's ok. It will be rare in practice, and all it means is that - // we'll end up examining slightly more types (likely 0) when doing operations like - // Find all references. - private readonly static ObjectPool> s_aliasMapPool - = SharedPools.StringIgnoreCaseDictionary(); - - protected static List> AllocateAliasMapList() - => s_aliasMapListPool.Allocate(); - - protected static void FreeAliasMapList(List> list) - { - if (list != null) - { - foreach (var aliasMap in list) - { - FreeAliasMap(aliasMap); - } - - s_aliasMapListPool.ClearAndFree(list); - } - } - - protected static void FreeAliasMap(Dictionary aliasMap) - { - if (aliasMap != null) - { - s_aliasMapPool.ClearAndFree(aliasMap); - } - } - - protected static Dictionary AllocateAliasMap() - => s_aliasMapPool.Allocate(); - - protected static void AppendTokens(SyntaxNode node, StringBuilder builder) - { - foreach (var child in node.ChildNodesAndTokens()) - { - if (child.IsToken) - { - builder.Append(child.AsToken().Text); - } - else - { - AppendTokens(child.AsNode(), builder); - } - } - } - - protected static void Intern(StringTable stringTable, ArrayBuilder builder) - { - for (int i = 0, n = builder.Count; i < n; i++) - { - builder[i] = stringTable.Add(builder[i]); - } - } - - public static string GetMetadataAritySuffix(int arity) - { - Debug.Assert(arity > 0); - return (arity <= s_aritySuffixesOneToNine.Length) - ? s_aritySuffixesOneToNine[arity - 1] - : string.Concat(GenericTypeNameManglingString, arity.ToString(CultureInfo.InvariantCulture)); - } - - public abstract bool TryGetDeclaredSymbolInfo(StringTable stringTable, SyntaxNode node, string rootNamespace, out DeclaredSymbolInfo declaredSymbolInfo); - - /// - /// Get the name of the target type of specified extension method declaration. - /// The node provided must be an extension method declaration, i.e. calling `TryGetDeclaredSymbolInfo()` - /// on `node` should return a `DeclaredSymbolInfo` of kind `ExtensionMethod`. - /// If the return value is null, then it means this is a "complex" method (as described at ). - /// - public abstract string GetTargetTypeName(SyntaxNode node); - - public abstract bool TryGetAliasesFromUsingDirective(SyntaxNode node, out ImmutableArray<(string aliasName, string name)> aliases); - - public abstract string GetRootNamespace(CompilationOptions compilationOptions); - } - internal abstract class AbstractSyntaxFactsService { private readonly static ObjectPool> s_stackPool From 645f4132ae2918aac946e397a204fb0f681108bd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 14:58:32 -0800 Subject: [PATCH 03/21] Add Kinds service. --- .../Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj | 4 ++++ .../Portable/LanguageServices/CSharpSyntaxFactsService.cs | 4 ++-- .../Portable/LanguageServices/CSharpSyntaxKindsService.cs | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj index 05df67c2a7b94..0521245bc0ed8 100644 --- a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj +++ b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj @@ -56,6 +56,7 @@ + @@ -76,4 +77,7 @@ + + + \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs index c0c23843afff6..390302bd34983 100644 --- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs +++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs @@ -10,10 +10,10 @@ using System.Linq; using System.Text; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.CodeGeneration; +//using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -using Microsoft.CodeAnalysis.CSharp.LanguageServices; +//using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxKindsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxKindsService.cs index 4b07bac0730fd..657cfbe21e252 100644 --- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxKindsService.cs +++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxKindsService.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.Composition; using Microsoft.CodeAnalysis.LanguageServices; namespace Microsoft.CodeAnalysis.CSharp.LanguageServices From fe84de2fc27d09ea5baa5234273138573a210e31 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 14:59:58 -0800 Subject: [PATCH 04/21] Revert --- .../Portable/LanguageServices/CSharpSyntaxFactsService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs index 390302bd34983..c0c23843afff6 100644 --- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs +++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs @@ -10,10 +10,10 @@ using System.Linq; using System.Text; using System.Threading; -//using Microsoft.CodeAnalysis.CSharp.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; -//using Microsoft.CodeAnalysis.CSharp.LanguageServices; +using Microsoft.CodeAnalysis.CSharp.LanguageServices; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.LanguageServices; From 2dcaa98c8d2fb511255c5c352110cc7aad95c3f1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 15:26:00 -0800 Subject: [PATCH 05/21] Moving more down --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 18 ++++++ .../Core/Portable/Editing/SyntaxGenerator.cs | 27 +-------- .../SyntaxGenerator_LanguageService.cs | 58 +++++++++++++++++++ .../Extensions/INamedTypeSymbolExtensions.cs | 17 ------ .../INamedTypeSymbolExtensions_Shared.cs | 31 ++++++++++ .../Shared/Extensions/ISymbolExtensions.cs | 10 ---- .../Extensions/ISymbolExtensions_Shared.cs | 23 ++++++++ .../Extensions/ITypeSymbolExtensions.cs | 5 -- .../ITypeSymbolExtensions_Shared.cs | 18 ++++++ .../DoNotAddImportsAnnotation.cs | 8 +-- .../Portable/Simplification/Simplifier.cs | 6 -- .../Simplification/Simplifier_Annotation.cs | 15 +++++ 12 files changed, 167 insertions(+), 69 deletions(-) create mode 100644 src/Workspaces/Core/Portable/Editing/SyntaxGenerator_LanguageService.cs create mode 100644 src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs create mode 100644 src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs create mode 100644 src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs create mode 100644 src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index c7e4273018efd..ba54f77caac39 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -50,6 +50,7 @@ + @@ -58,6 +59,11 @@ + + + + + @@ -163,6 +169,10 @@ + + + + @@ -183,11 +193,15 @@ + + + + @@ -214,6 +228,10 @@ + + + + \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index ca68d7a6e2267..0f942f06eb0da 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -29,7 +28,7 @@ namespace Microsoft.CodeAnalysis.Editing /// preference if any /// overload is called. /// - public abstract class SyntaxGenerator : ILanguageService + public abstract partial class SyntaxGenerator { public static SyntaxRemoveOptions DefaultRemoveOptions = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker; @@ -41,30 +40,6 @@ public abstract class SyntaxGenerator : ILanguageService internal abstract SyntaxTrivia EndOfLine(string text); internal abstract SyntaxTrivia Whitespace(string text); - /// - /// Gets the for the specified language. - /// - public static SyntaxGenerator GetGenerator(Workspace workspace, string language) - { - return workspace.Services.GetLanguageServices(language).GetService(); - } - - /// - /// Gets the for the language corresponding to the document. - /// - public static SyntaxGenerator GetGenerator(Document document) - { - return GetGenerator(document.Project); - } - - /// - /// Gets the for the language corresponding to the project. - /// - public static SyntaxGenerator GetGenerator(Project project) - { - return project.LanguageServices.GetService(); - } - #region Declarations /// diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator_LanguageService.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator_LanguageService.cs new file mode 100644 index 0000000000000..5d01d808e8c38 --- /dev/null +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator_LanguageService.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Editing +{ + /// + /// A language agnostic factory for creating syntax nodes. + /// + /// This API can be used to create language specific syntax nodes that are semantically + /// similar between languages. + /// + /// The trees generated by this API will try to respect user preferences when + /// possible. For example, generating + /// will be done in a way such that "this." or "Me." will be simplified according to user + /// preference if any + /// overload is called. + /// + public abstract partial class SyntaxGenerator : ILanguageService + { + /// + /// Gets the for the specified language. + /// + public static SyntaxGenerator GetGenerator(Workspace workspace, string language) + { + return workspace.Services.GetLanguageServices(language).GetService(); + } + + /// + /// Gets the for the language corresponding to the document. + /// + public static SyntaxGenerator GetGenerator(Document document) + { + return GetGenerator(document.Project); + } + + /// + /// Gets the for the language corresponding to the project. + /// + public static SyntaxGenerator GetGenerator(Project project) + { + return project.LanguageServices.GetService(); + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs index a8cf72653abb5..bba08aadb5818 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs @@ -34,23 +34,6 @@ public static IEnumerable GetAllTypeParameters(this INamed return stack.SelectMany(n => n.TypeParameters); } - public static IEnumerable GetAllTypeArguments(this INamedTypeSymbol? symbol) - { - var stack = GetContainmentStack(symbol); - return stack.SelectMany(n => n.TypeArguments); - } - - private static Stack GetContainmentStack(INamedTypeSymbol? symbol) - { - var stack = new Stack(); - for (var current = symbol; current != null; current = current.ContainingType) - { - stack.Push(current); - } - - return stack; - } - public static bool IsContainedWithin([NotNullWhen(returnValue: true)] this INamedTypeSymbol? symbol, INamedTypeSymbol outer) { // TODO(cyrusn): Should we be using OriginalSymbol here? diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs new file mode 100644 index 0000000000000..3b3e8e60dbb70 --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs @@ -0,0 +1,31 @@ +// 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.Collections.Generic; +using System.Linq; + +namespace Microsoft.CodeAnalysis.Shared.Extensions +{ + internal static partial class INamedTypeSymbolExtensions + { + public static IEnumerable GetAllTypeArguments(this INamedTypeSymbol? symbol) + { + var stack = GetContainmentStack(symbol); + return stack.SelectMany(n => n.TypeArguments); + } + + private static Stack GetContainmentStack(INamedTypeSymbol? symbol) + { + var stack = new Stack(); + for (var current = symbol; current != null; current = current.ContainingType) + { + stack.Push(current); + } + + return stack; + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index d472e93ce80eb..fece28406b025 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -509,16 +509,6 @@ public static bool IsAttribute([NotNullWhen(returnValue: true)] this ISymbol? sy return (symbol as ITypeSymbol)?.IsAttribute() == true; } - /// - /// Returns true if this symbol contains anything unsafe within it. for example - /// List<int*[]> is unsafe, as it "int* Goo { get; }" - /// - public static bool IsUnsafe([NotNullWhen(returnValue: true)] this ISymbol? member) - { - // TODO(cyrusn): Defer to compiler code to handle this once it can. - return member?.Accept(new IsUnsafeVisitor()) == true; - } - public static ITypeSymbol ConvertToType( this ISymbol? symbol, Compilation compilation, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs new file mode 100644 index 0000000000000..535247f19586c --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs @@ -0,0 +1,23 @@ +// 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 +{ + internal static partial class ISymbolExtensions + { + /// + /// Returns true if this symbol contains anything unsafe within it. for example + /// List<int*[]> is unsafe, as it "int* Goo { get; }" + /// + public static bool IsUnsafe([NotNullWhen(returnValue: true)] this ISymbol? member) + { + // TODO(cyrusn): Defer to compiler code to handle this once it can. + return member?.Accept(new IsUnsafeVisitor()) == true; + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs index a284b7f877af8..2680234f7f098 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs @@ -49,11 +49,6 @@ public static bool IsAbstractClass([NotNullWhen(returnValue: true)] this ITypeSy return symbol?.TypeKind == TypeKind.Class && symbol.IsAbstract; } - public static bool IsSystemVoid([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) - { - return symbol?.SpecialType == SpecialType.System_Void; - } - public static bool IsNullable([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) => symbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs new file mode 100644 index 0000000000000..ed95e9650b8eb --- /dev/null +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs @@ -0,0 +1,18 @@ +// 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 +{ + internal static partial class ITypeSymbolExtensions + { + public static bool IsSystemVoid([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) + { + return symbol?.SpecialType == SpecialType.System_Void; + } + } +} diff --git a/src/Workspaces/Core/Portable/Simplification/DoNotAddImportsAnnotation.cs b/src/Workspaces/Core/Portable/Simplification/DoNotAddImportsAnnotation.cs index e8227b0f7189c..1ae43f12ebf51 100644 --- a/src/Workspaces/Core/Portable/Simplification/DoNotAddImportsAnnotation.cs +++ b/src/Workspaces/Core/Portable/Simplification/DoNotAddImportsAnnotation.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// 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.Simplification { diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs index a69bb4aff53b4..bf3ae044690e9 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs +++ b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs @@ -37,12 +37,6 @@ namespace Microsoft.CodeAnalysis.Simplification /// public static partial class Simplifier { - /// - /// The annotation the reducer uses to identify sub trees to be reduced. - /// The Expand operations add this annotation to nodes so that the Reduce operations later find them. - /// - public static SyntaxAnnotation Annotation { get; } = new SyntaxAnnotation(); - /// /// This is the annotation used by the simplifier and expander to identify Predefined type and preserving /// them from over simplification diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs b/src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs new file mode 100644 index 0000000000000..a56b41a1365fb --- /dev/null +++ b/src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs @@ -0,0 +1,15 @@ +// 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.Simplification +{ + public static partial class Simplifier + { + /// + /// The annotation the reducer uses to identify sub trees to be reduced. + /// The Expand operations add this annotation to nodes so that the Reduce operations later find them. + /// + public static SyntaxAnnotation Annotation { get; } = new SyntaxAnnotation(); + } +} From bb9b719fd08bbc4a47965bd857a3f2ccd16066d3 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 15:36:29 -0800 Subject: [PATCH 06/21] Move more down --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 1 + .../Core/Portable/Editing/SyntaxGenerator.cs | 12 ------------ 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index ba54f77caac39..fe9eefdfb9c51 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -133,6 +133,7 @@ + diff --git a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs index 0f942f06eb0da..5eb6fc31d0282 100644 --- a/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs +++ b/src/Workspaces/Core/Portable/Editing/SyntaxGenerator.cs @@ -16,18 +16,6 @@ namespace Microsoft.CodeAnalysis.Editing { - /// - /// A language agnostic factory for creating syntax nodes. - /// - /// This API can be used to create language specific syntax nodes that are semantically - /// similar between languages. - /// - /// The trees generated by this API will try to respect user preferences when - /// possible. For example, generating - /// will be done in a way such that "this." or "Me." will be simplified according to user - /// preference if any - /// overload is called. - /// public abstract partial class SyntaxGenerator { public static SyntaxRemoveOptions DefaultRemoveOptions = SyntaxRemoveOptions.KeepUnbalancedDirectives | SyntaxRemoveOptions.AddElasticMarker; From 56084e82c2864b800094d019ab99cf8fa966f973 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 16:00:33 -0800 Subject: [PATCH 07/21] Share more --- ...osoft.CodeAnalysis.CSharp.CodeStyle.csproj | 8 + .../CodeGeneration/CSharpSyntaxGenerator.cs | 10 +- .../CSharpSyntaxGenerator_Mef.cs | 19 + .../ContextQuery/SyntaxTreeExtensions.cs | 27 -- .../Extensions/ExpressionSyntaxExtensions.cs | 17 - .../ExpressionSyntaxExtensions_Shared.cs | 36 ++ .../Portable/Extensions/StringExtensions.cs | 3 - .../Extensions/SyntaxTokenExtensions.cs | 17 - ...ntaxTokenExtensions_SharedWithCodeStyle.cs | 14 + .../Extensions/SyntaxTreeExtensions.cs | 334 --------------- .../Extensions/SyntaxTreeExtensions_Shared.cs | 383 ++++++++++++++++++ .../Extensions/SyntaxTokenExtensions.cs | 5 + .../Shared/Extensions/SyntaxTreeExtensions.cs | 84 ---- ...yntaxTreeExtensions_SharedWithCodeStyle.cs | 85 ++++ 14 files changed, 551 insertions(+), 491 deletions(-) create mode 100644 src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator_Mef.cs create mode 100644 src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs create mode 100644 src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs diff --git a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj index 0521245bc0ed8..5a3edf544471f 100644 --- a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj +++ b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj @@ -19,10 +19,14 @@ + + + + @@ -56,6 +60,8 @@ + + @@ -79,5 +85,7 @@ + + \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index c23bcf1737d97..4b13c604a706c 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -5,14 +5,12 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Composition; using System.Linq; using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; -using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -20,14 +18,8 @@ namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration { - [ExportLanguageService(typeof(SyntaxGenerator), LanguageNames.CSharp), Shared] - internal class CSharpSyntaxGenerator : SyntaxGenerator + internal partial class CSharpSyntaxGenerator : SyntaxGenerator { - [ImportingConstructor] - public CSharpSyntaxGenerator() - { - } - internal override SyntaxTrivia ElasticCarriageReturnLineFeed => SyntaxFactory.ElasticCarriageReturnLineFeed; internal override SyntaxTrivia CarriageReturnLineFeed => SyntaxFactory.CarriageReturnLineFeed; diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator_Mef.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator_Mef.cs new file mode 100644 index 0000000000000..c1c79cbad0bcb --- /dev/null +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator_Mef.cs @@ -0,0 +1,19 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration +{ + [ExportLanguageService(typeof(SyntaxGenerator), LanguageNames.CSharp), Shared] + internal partial class CSharpSyntaxGenerator : SyntaxGenerator + { + [ImportingConstructor] + public CSharpSyntaxGenerator() + { + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 983302c7e152c..2372fe052ebf6 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -1723,33 +1723,6 @@ public static bool IsPreProcessorDirectiveContext(this SyntaxTree syntaxTree, in return syntaxTree.IsPreProcessorDirectiveContext(position, leftToken, cancellationToken); } - public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - return IsPreProcessorKeywordContext( - syntaxTree, position, - syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives: true)); - } - - public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, SyntaxToken preProcessorTokenOnLeftOfPosition) - { - // cases: - // #| - // #d| - // # | - // # d| - - // note: comments are not allowed between the # and item. - var token = preProcessorTokenOnLeftOfPosition; - token = token.GetPreviousTokenIfTouchingWord(position); - - if (token.IsKind(SyntaxKind.HashToken)) - { - return true; - } - - return false; - } - public static bool IsStatementContext(this SyntaxTree syntaxTree, int position, SyntaxToken tokenOnLeftOfPosition, CancellationToken cancellationToken) { #if false diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs index 465b52bf00c72..16337523aa981 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs @@ -139,12 +139,6 @@ public static bool IsQualifiedCrefName(this ExpressionSyntax expression) return expression.IsParentKind(SyntaxKind.NameMemberCref) && expression.Parent.IsParentKind(SyntaxKind.QualifiedCref); } - public static bool IsMemberAccessExpressionName(this ExpressionSyntax expression) - { - return (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && ((MemberAccessExpressionSyntax)expression.Parent).Name == expression) || - IsMemberBindingExpressionName(expression); - } - public static bool IsAnyMemberAccessExpressionName(this ExpressionSyntax expression) { if (expression == null) @@ -156,17 +150,6 @@ public static bool IsAnyMemberAccessExpressionName(this ExpressionSyntax express expression.IsMemberBindingExpressionName(); } - private static bool IsMemberBindingExpressionName(this ExpressionSyntax expression) - { - return expression.IsParentKind(SyntaxKind.MemberBindingExpression) && - ((MemberBindingExpressionSyntax)expression.Parent).Name == expression; - } - - public static bool IsRightSideOfQualifiedName(this ExpressionSyntax expression) - { - return expression.IsParentKind(SyntaxKind.QualifiedName) && ((QualifiedNameSyntax)expression.Parent).Right == expression; - } - public static bool IsRightSideOfColonColon(this ExpressionSyntax expression) { return expression.IsParentKind(SyntaxKind.AliasQualifiedName) && ((AliasQualifiedNameSyntax)expression.Parent).Name == expression; diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs new file mode 100644 index 0000000000000..165187d515ab2 --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Utilities; +using Microsoft.CodeAnalysis.Simplification; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Extensions +{ + internal static partial class ExpressionSyntaxExtensions + { + public static bool IsRightSideOfQualifiedName(this ExpressionSyntax expression) + { + return expression.IsParentKind(SyntaxKind.QualifiedName) && ((QualifiedNameSyntax)expression.Parent).Right == expression; + } + + public static bool IsMemberAccessExpressionName(this ExpressionSyntax expression) + { + return (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) && ((MemberAccessExpressionSyntax)expression.Parent).Name == expression) || + IsMemberBindingExpressionName(expression); + } + + private static bool IsMemberBindingExpressionName(this ExpressionSyntax expression) + { + return expression.IsParentKind(SyntaxKind.MemberBindingExpression) && + ((MemberBindingExpressionSyntax)expression.Parent).Name == expression; + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Extensions/StringExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/StringExtensions.cs index 95c2d5fe0d850..0e65b26e5af51 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/StringExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/StringExtensions.cs @@ -3,11 +3,8 @@ // See the LICENSE file in the project root for more information. using System; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Simplification; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Extensions { diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions.cs index 8e4bf2b911b65..56c9e48a1e2e1 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions.cs @@ -34,23 +34,6 @@ public static bool IsLiteral(this SyntaxToken token) } } - public static bool IntersectsWith(this SyntaxToken token, int position) - { - return token.Span.IntersectsWith(position); - } - - public static SyntaxToken GetPreviousTokenIfTouchingWord(this SyntaxToken token, int position) - { - return token.IntersectsWith(position) && IsWord(token) - ? token.GetPreviousToken(includeSkipped: true) - : token; - } - - private static bool IsWord(SyntaxToken token) - { - return CSharpSyntaxFactsService.Instance.IsWord(token); - } - public static SyntaxToken GetNextNonZeroWidthTokenOrEndOfFile(this SyntaxToken token) { return token.GetNextTokenOrEndOfFile(); diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.cs index 258241585db83..2f2b212f80e61 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Linq; +using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Extensions { @@ -63,5 +65,17 @@ public static bool IsOpenBraceOfAccessorList(this SyntaxToken token) { return token.IsKind(SyntaxKind.OpenBraceToken) && token.Parent.IsKind(SyntaxKind.AccessorList); } + + public static SyntaxToken GetPreviousTokenIfTouchingWord(this SyntaxToken token, int position) + { + return token.IntersectsWith(position) && IsWord(token) + ? token.GetPreviousToken(includeSkipped: true) + : token; + } + + private static bool IsWord(SyntaxToken token) + { + return CSharpSyntaxFactsService.Instance.IsWord(token); + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs index c11c2bc3e90a1..ada41c622c485 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs @@ -174,27 +174,6 @@ public static bool IsAfterKeyword(this SyntaxTree syntaxTree, int position, Synt return token.Kind() == kind; } - public static bool IsInNonUserCode(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - return - syntaxTree.IsEntirelyWithinNonUserCodeComment(position, cancellationToken) || - syntaxTree.IsEntirelyWithinConflictMarker(position, cancellationToken) || - syntaxTree.IsEntirelyWithinStringOrCharLiteral(position, cancellationToken) || - syntaxTree.IsInInactiveRegion(position, cancellationToken); - } - - public static bool IsEntirelyWithinNonUserCodeComment(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var inNonUserSingleLineDocComment = - syntaxTree.IsEntirelyWithinSingleLineDocComment(position, cancellationToken) && !syntaxTree.IsEntirelyWithinCrefSyntax(position, cancellationToken); - return - syntaxTree.IsEntirelyWithinTopLevelSingleLineComment(position, cancellationToken) || - syntaxTree.IsEntirelyWithinPreProcessorSingleLineComment(position, cancellationToken) || - syntaxTree.IsEntirelyWithinMultiLineComment(position, cancellationToken) || - syntaxTree.IsEntirelyWithinMultiLineDocComment(position, cancellationToken) || - inNonUserSingleLineDocComment; - } - public static bool IsEntirelyWithinComment(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { return @@ -205,319 +184,6 @@ public static bool IsEntirelyWithinComment(this SyntaxTree syntaxTree, int posit syntaxTree.IsEntirelyWithinSingleLineDocComment(position, cancellationToken); } - public static bool IsCrefContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true); - token = token.GetPreviousTokenIfTouchingWord(position); - - if (token.Parent is XmlCrefAttributeSyntax attribute) - { - return token == attribute.StartQuoteToken; - } - - return false; - } - - public static bool IsEntirelyWithinCrefSyntax(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - if (syntaxTree.IsCrefContext(position, cancellationToken)) - { - return true; - } - - var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true); - return token.GetAncestor() != null; - } - - public static bool IsEntirelyWithinSingleLineDocComment( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var root = syntaxTree.GetRoot(cancellationToken) as CompilationUnitSyntax; - var trivia = root.FindTrivia(position); - - // If we ask right at the end of the file, we'll get back nothing. - // So move back in that case and ask again. - var eofPosition = root.FullWidth(); - if (position == eofPosition) - { - var eof = root.EndOfFileToken; - if (eof.HasLeadingTrivia) - { - trivia = eof.LeadingTrivia.Last(); - } - } - - if (trivia.IsSingleLineDocComment()) - { - var span = trivia.Span; - var fullSpan = trivia.FullSpan; - var endsWithNewLine = trivia.GetStructure().GetLastToken(includeSkipped: true).Kind() == SyntaxKind.XmlTextLiteralNewLineToken; - - if (endsWithNewLine) - { - if (position > fullSpan.Start && position < fullSpan.End) - { - return true; - } - } - else - { - if (position > fullSpan.Start && position <= fullSpan.End) - { - return true; - } - } - } - - return false; - } - - public static bool IsEntirelyWithinMultiLineDocComment( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var trivia = syntaxTree.GetRoot(cancellationToken).FindTrivia(position); - - if (trivia.IsMultiLineDocComment()) - { - var span = trivia.FullSpan; - - if (position > span.Start && position < span.End) - { - return true; - } - } - - return false; - } - - public static bool IsEntirelyWithinMultiLineComment( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); - - if (trivia.IsMultiLineComment()) - { - var span = trivia.FullSpan; - - return trivia.IsCompleteMultiLineComment() - ? position > span.Start && position < span.End - : position > span.Start && position <= span.End; - } - - return false; - } - - public static bool IsEntirelyWithinConflictMarker( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); - - if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) - { - // Check if we're on the newline right at the end of a comment - trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken); - } - - return trivia.Kind() == SyntaxKind.ConflictMarkerTrivia; - } - - public static bool IsEntirelyWithinTopLevelSingleLineComment( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); - - if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) - { - // Check if we're on the newline right at the end of a comment - trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken); - } - - if (trivia.IsSingleLineComment() || trivia.IsShebangDirective()) - { - var span = trivia.FullSpan; - - if (position > span.Start && position <= span.End) - { - return true; - } - } - - return false; - } - - public static bool IsEntirelyWithinPreProcessorSingleLineComment( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - // Search inside trivia for directives to ensure that we recognize - // single-line comments at the end of preprocessor directives. - var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken, findInsideTrivia: true); - - if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) - { - // Check if we're on the newline right at the end of a comment - trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken, findInsideTrivia: true); - } - - if (trivia.IsSingleLineComment()) - { - var span = trivia.FullSpan; - - if (position > span.Start && position <= span.End) - { - return true; - } - } - - return false; - } - - private static bool AtEndOfIncompleteStringOrCharLiteral(SyntaxToken token, int position, char lastChar) - { - if (!token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.CharacterLiteralToken)) - { - throw new ArgumentException(CSharpWorkspaceResources.Expected_string_or_char_literal, nameof(token)); - } - - var startLength = 1; - if (token.IsVerbatimStringLiteral()) - { - startLength = 2; - } - - return position == token.Span.End && - (token.Span.Length == startLength || (token.Span.Length > startLength && token.ToString().Cast().LastOrDefault() != lastChar)); - } - - public static bool IsEntirelyWithinStringOrCharLiteral( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - return - syntaxTree.IsEntirelyWithinStringLiteral(position, cancellationToken) || - syntaxTree.IsEntirelyWithinCharLiteral(position, cancellationToken); - } - - public static bool IsEntirelyWithinStringLiteral( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var token = syntaxTree.GetRoot(cancellationToken).FindToken(position, findInsideTrivia: true); - - // If we ask right at the end of the file, we'll get back nothing. We handle that case - // specially for now, though SyntaxTree.FindToken should work at the end of a file. - if (token.IsKind(SyntaxKind.EndOfDirectiveToken, SyntaxKind.EndOfFileToken)) - { - token = token.GetPreviousToken(includeSkipped: true, includeDirectives: true); - } - - if (token.IsKind(SyntaxKind.StringLiteralToken)) - { - var span = token.Span; - - // cases: - // "|" - // "| (e.g. incomplete string literal) - return (position > span.Start && position < span.End) - || AtEndOfIncompleteStringOrCharLiteral(token, position, '"'); - } - - if (token.IsKind(SyntaxKind.InterpolatedStringStartToken, SyntaxKind.InterpolatedStringTextToken, SyntaxKind.InterpolatedStringEndToken)) - { - return token.SpanStart < position && token.Span.End > position; - } - - return false; - } - - public static bool IsEntirelyWithinCharLiteral( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - var root = syntaxTree.GetRoot(cancellationToken) as CompilationUnitSyntax; - var token = root.FindToken(position, findInsideTrivia: true); - - // If we ask right at the end of the file, we'll get back nothing. - // We handle that case specially for now, though SyntaxTree.FindToken should - // work at the end of a file. - if (position == root.FullWidth()) - { - token = root.EndOfFileToken.GetPreviousToken(includeSkipped: true, includeDirectives: true); - } - - if (token.Kind() == SyntaxKind.CharacterLiteralToken) - { - var span = token.Span; - - // cases: - // '|' - // '| (e.g. incomplete char literal) - return (position > span.Start && position < span.End) - || AtEndOfIncompleteStringOrCharLiteral(token, position, '\''); - } - - return false; - } - - public static bool IsInInactiveRegion( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - Contract.ThrowIfNull(syntaxTree); - - // cases: - // $ is EOF - - // #if false - // | - - // #if false - // |$ - - // #if false - // | - - // #if false - // |$ - - if (syntaxTree.IsPreProcessorKeywordContext(position, cancellationToken)) - { - return false; - } - - // The latter two are the hard cases we don't actually have an - // DisabledTextTrivia yet. - var trivia = syntaxTree.GetRoot(cancellationToken).FindTrivia(position, findInsideTrivia: false); - if (trivia.Kind() == SyntaxKind.DisabledTextTrivia) - { - return true; - } - - var token = syntaxTree.FindTokenOrEndToken(position, cancellationToken); - if (token.Kind() == SyntaxKind.EndOfFileToken) - { - var triviaList = token.LeadingTrivia; - foreach (var triviaTok in triviaList.Reverse()) - { - if (triviaTok.Span.Contains(position)) - { - return false; - } - - if (triviaTok.Span.End < position) - { - if (!triviaTok.HasStructure) - { - return false; - } - - var structure = triviaTok.GetStructure(); - if (structure is BranchingDirectiveTriviaSyntax branch) - { - return !branch.IsActive || !branch.BranchTaken; - } - } - } - } - - return false; - } - public static ImmutableArray GetFieldsAndPropertiesInSpan( this SyntaxNode root, TextSpan textSpan, bool allowPartialSelection) { diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs new file mode 100644 index 0000000000000..580722785bb7a --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs @@ -0,0 +1,383 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Extensions +{ + internal static partial class SyntaxTreeExtensions + { + public static bool IsInNonUserCode(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + return + syntaxTree.IsEntirelyWithinNonUserCodeComment(position, cancellationToken) || + syntaxTree.IsEntirelyWithinConflictMarker(position, cancellationToken) || + syntaxTree.IsEntirelyWithinStringOrCharLiteral(position, cancellationToken) || + syntaxTree.IsInInactiveRegion(position, cancellationToken); + } + + public static bool IsEntirelyWithinNonUserCodeComment(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var inNonUserSingleLineDocComment = + syntaxTree.IsEntirelyWithinSingleLineDocComment(position, cancellationToken) && !syntaxTree.IsEntirelyWithinCrefSyntax(position, cancellationToken); + return + syntaxTree.IsEntirelyWithinTopLevelSingleLineComment(position, cancellationToken) || + syntaxTree.IsEntirelyWithinPreProcessorSingleLineComment(position, cancellationToken) || + syntaxTree.IsEntirelyWithinMultiLineComment(position, cancellationToken) || + syntaxTree.IsEntirelyWithinMultiLineDocComment(position, cancellationToken) || + inNonUserSingleLineDocComment; + } + + public static bool IsEntirelyWithinTopLevelSingleLineComment( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); + + if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) + { + // Check if we're on the newline right at the end of a comment + trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken); + } + + if (trivia.IsSingleLineComment() || trivia.IsShebangDirective()) + { + var span = trivia.FullSpan; + + if (position > span.Start && position <= span.End) + { + return true; + } + } + + return false; + } + + public static bool IsEntirelyWithinPreProcessorSingleLineComment( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + // Search inside trivia for directives to ensure that we recognize + // single-line comments at the end of preprocessor directives. + var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken, findInsideTrivia: true); + + if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) + { + // Check if we're on the newline right at the end of a comment + trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken, findInsideTrivia: true); + } + + if (trivia.IsSingleLineComment()) + { + var span = trivia.FullSpan; + + if (position > span.Start && position <= span.End) + { + return true; + } + } + + return false; + } + + public static bool IsEntirelyWithinSingleLineDocComment( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var root = syntaxTree.GetRoot(cancellationToken) as CompilationUnitSyntax; + var trivia = root.FindTrivia(position); + + // If we ask right at the end of the file, we'll get back nothing. + // So move back in that case and ask again. + var eofPosition = root.FullWidth(); + if (position == eofPosition) + { + var eof = root.EndOfFileToken; + if (eof.HasLeadingTrivia) + { + trivia = eof.LeadingTrivia.Last(); + } + } + + if (trivia.IsSingleLineDocComment()) + { + var span = trivia.Span; + var fullSpan = trivia.FullSpan; + var endsWithNewLine = trivia.GetStructure().GetLastToken(includeSkipped: true).Kind() == SyntaxKind.XmlTextLiteralNewLineToken; + + if (endsWithNewLine) + { + if (position > fullSpan.Start && position < fullSpan.End) + { + return true; + } + } + else + { + if (position > fullSpan.Start && position <= fullSpan.End) + { + return true; + } + } + } + + return false; + } + + public static bool IsEntirelyWithinMultiLineDocComment( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var trivia = syntaxTree.GetRoot(cancellationToken).FindTrivia(position); + + if (trivia.IsMultiLineDocComment()) + { + var span = trivia.FullSpan; + + if (position > span.Start && position < span.End) + { + return true; + } + } + + return false; + } + + public static bool IsEntirelyWithinMultiLineComment( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); + + if (trivia.IsMultiLineComment()) + { + var span = trivia.FullSpan; + + return trivia.IsCompleteMultiLineComment() + ? position > span.Start && position < span.End + : position > span.Start && position <= span.End; + } + + return false; + } + + public static bool IsEntirelyWithinConflictMarker( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var trivia = syntaxTree.FindTriviaAndAdjustForEndOfFile(position, cancellationToken); + + if (trivia.Kind() == SyntaxKind.EndOfLineTrivia) + { + // Check if we're on the newline right at the end of a comment + trivia = trivia.GetPreviousTrivia(syntaxTree, cancellationToken); + } + + return trivia.Kind() == SyntaxKind.ConflictMarkerTrivia; + } + + public static bool IsEntirelyWithinStringOrCharLiteral( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + return + syntaxTree.IsEntirelyWithinStringLiteral(position, cancellationToken) || + syntaxTree.IsEntirelyWithinCharLiteral(position, cancellationToken); + } + + public static bool IsEntirelyWithinStringLiteral( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var token = syntaxTree.GetRoot(cancellationToken).FindToken(position, findInsideTrivia: true); + + // If we ask right at the end of the file, we'll get back nothing. We handle that case + // specially for now, though SyntaxTree.FindToken should work at the end of a file. + if (token.IsKind(SyntaxKind.EndOfDirectiveToken, SyntaxKind.EndOfFileToken)) + { + token = token.GetPreviousToken(includeSkipped: true, includeDirectives: true); + } + + if (token.IsKind(SyntaxKind.StringLiteralToken)) + { + var span = token.Span; + + // cases: + // "|" + // "| (e.g. incomplete string literal) + return (position > span.Start && position < span.End) + || AtEndOfIncompleteStringOrCharLiteral(token, position, '"'); + } + + if (token.IsKind(SyntaxKind.InterpolatedStringStartToken, SyntaxKind.InterpolatedStringTextToken, SyntaxKind.InterpolatedStringEndToken)) + { + return token.SpanStart < position && token.Span.End > position; + } + + return false; + } + + private static bool AtEndOfIncompleteStringOrCharLiteral(SyntaxToken token, int position, char lastChar) + { + if (!token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.CharacterLiteralToken)) + { + throw new ArgumentException("Expected string or char literal", nameof(token)); + } + + var startLength = 1; + if (token.IsVerbatimStringLiteral()) + { + startLength = 2; + } + + return position == token.Span.End && + (token.Span.Length == startLength || (token.Span.Length > startLength && token.ToString().Cast().LastOrDefault() != lastChar)); + } + + public static bool IsEntirelyWithinCharLiteral( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var root = syntaxTree.GetRoot(cancellationToken) as CompilationUnitSyntax; + var token = root.FindToken(position, findInsideTrivia: true); + + // If we ask right at the end of the file, we'll get back nothing. + // We handle that case specially for now, though SyntaxTree.FindToken should + // work at the end of a file. + if (position == root.FullWidth()) + { + token = root.EndOfFileToken.GetPreviousToken(includeSkipped: true, includeDirectives: true); + } + + if (token.Kind() == SyntaxKind.CharacterLiteralToken) + { + var span = token.Span; + + // cases: + // '|' + // '| (e.g. incomplete char literal) + return (position > span.Start && position < span.End) + || AtEndOfIncompleteStringOrCharLiteral(token, position, '\''); + } + + return false; + } + + public static bool IsInInactiveRegion( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + Contract.ThrowIfNull(syntaxTree); + + // cases: + // $ is EOF + + // #if false + // | + + // #if false + // |$ + + // #if false + // | + + // #if false + // |$ + + if (syntaxTree.IsPreProcessorKeywordContext(position, cancellationToken)) + { + return false; + } + + // The latter two are the hard cases we don't actually have an + // DisabledTextTrivia yet. + var trivia = syntaxTree.GetRoot(cancellationToken).FindTrivia(position, findInsideTrivia: false); + if (trivia.Kind() == SyntaxKind.DisabledTextTrivia) + { + return true; + } + + var token = syntaxTree.FindTokenOrEndToken(position, cancellationToken); + if (token.Kind() == SyntaxKind.EndOfFileToken) + { + var triviaList = token.LeadingTrivia; + foreach (var triviaTok in triviaList.Reverse()) + { + if (triviaTok.Span.Contains(position)) + { + return false; + } + + if (triviaTok.Span.End < position) + { + if (!triviaTok.HasStructure) + { + return false; + } + + var structure = triviaTok.GetStructure(); + if (structure is BranchingDirectiveTriviaSyntax branch) + { + return !branch.IsActive || !branch.BranchTaken; + } + } + } + } + + return false; + } + + public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + return IsPreProcessorKeywordContext( + syntaxTree, position, + syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives: true)); + } + + public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, SyntaxToken preProcessorTokenOnLeftOfPosition) + { + // cases: + // #| + // #d| + // # | + // # d| + + // note: comments are not allowed between the # and item. + var token = preProcessorTokenOnLeftOfPosition; + token = token.GetPreviousTokenIfTouchingWord(position); + + if (token.IsKind(SyntaxKind.HashToken)) + { + return true; + } + + return false; + } + + public static bool IsEntirelyWithinCrefSyntax(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + if (syntaxTree.IsCrefContext(position, cancellationToken)) + { + return true; + } + + var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true); + return token.GetAncestor() != null; + } + + public static bool IsCrefContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + var token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDocumentationComments: true); + token = token.GetPreviousTokenIfTouchingWord(position); + + if (token.Parent is XmlCrefAttributeSyntax attribute) + { + return token == attribute.StartQuoteToken; + } + + return false; + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTokenExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTokenExtensions.cs index 08d85e653ec4f..89f1eec01ad60 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTokenExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTokenExtensions.cs @@ -172,5 +172,10 @@ public static SyntaxToken WithAppendedTrailingTrivia( public static SyntaxTrivia[] GetTrivia(this IEnumerable tokens) => tokens.SelectMany(token => SyntaxNodeOrTokenExtensions.GetTrivia(token)).ToArray(); + + public static bool IntersectsWith(this SyntaxToken token, int position) + { + return token.Span.IntersectsWith(position); + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions.cs index c25c12db24d36..3e5eb97220083 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions.cs @@ -110,75 +110,6 @@ public static async Task IsBeforeFirstTokenAsync( return position <= firstToken.SpanStart; } - public static SyntaxToken FindTokenOrEndToken( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - Contract.ThrowIfNull(syntaxTree); - - var root = syntaxTree.GetRoot(cancellationToken); - var result = root.FindToken(position, findInsideTrivia: true); - if (result.RawKind != 0) - { - return result; - } - - // Special cases. See if we're actually at the end of a: - // a) doc comment - // b) pp directive - // c) file - - var compilationUnit = (ICompilationUnitSyntax)root; - var triviaList = compilationUnit.EndOfFileToken.LeadingTrivia; - foreach (var trivia in triviaList.Reverse()) - { - if (trivia.HasStructure) - { - var token = trivia.GetStructure().GetLastToken(includeZeroWidth: true); - if (token.Span.End == position) - { - return token; - } - } - } - - if (position == root.FullSpan.End) - { - return compilationUnit.EndOfFileToken; - } - - return default; - } - - internal static SyntaxTrivia FindTriviaAndAdjustForEndOfFile( - this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, bool findInsideTrivia = false) - { - var root = syntaxTree.GetRoot(cancellationToken); - var trivia = root.FindTrivia(position, findInsideTrivia); - - // If we ask right at the end of the file, we'll get back nothing. - // We handle that case specially for now, though SyntaxTree.FindTrivia should - // work at the end of a file. - if (position == root.FullWidth()) - { - var compilationUnit = (ICompilationUnitSyntax)root; - var endOfFileToken = compilationUnit.EndOfFileToken; - if (endOfFileToken.HasLeadingTrivia) - { - trivia = endOfFileToken.LeadingTrivia.Last(); - } - else - { - var token = endOfFileToken.GetPreviousToken(includeSkipped: true); - if (token.HasTrailingTrivia) - { - trivia = token.TrailingTrivia.Last(); - } - } - } - - return trivia; - } - /// /// If the position is inside of token, return that token; otherwise, return the token to the right. /// @@ -193,20 +124,5 @@ public static SyntaxToken FindTokenOnRightOfPosition( return syntaxTree.GetRoot(cancellationToken).FindTokenOnRightOfPosition( position, includeSkipped, includeDirectives, includeDocumentationComments); } - - /// - /// If the position is inside of token, return that token; otherwise, return the token to the left. - /// - public static SyntaxToken FindTokenOnLeftOfPosition( - this SyntaxTree syntaxTree, - int position, - CancellationToken cancellationToken, - bool includeSkipped = true, - bool includeDirectives = false, - bool includeDocumentationComments = false) - { - return syntaxTree.GetRoot(cancellationToken).FindTokenOnLeftOfPosition( - position, includeSkipped, includeDirectives, includeDocumentationComments); - } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.cs index 082e29e641c09..f32b2f1f07f48 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.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; using System.Threading; using Microsoft.CodeAnalysis.Text; @@ -26,5 +27,89 @@ public static bool OverlapsHiddenPosition(this SyntaxTree tree, TextSpan span, C }, cancellationToken); } + + internal static SyntaxTrivia FindTriviaAndAdjustForEndOfFile( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken, bool findInsideTrivia = false) + { + var root = syntaxTree.GetRoot(cancellationToken); + var trivia = root.FindTrivia(position, findInsideTrivia); + + // If we ask right at the end of the file, we'll get back nothing. + // We handle that case specially for now, though SyntaxTree.FindTrivia should + // work at the end of a file. + if (position == root.FullWidth()) + { + var compilationUnit = (ICompilationUnitSyntax)root; + var endOfFileToken = compilationUnit.EndOfFileToken; + if (endOfFileToken.HasLeadingTrivia) + { + trivia = endOfFileToken.LeadingTrivia.Last(); + } + else + { + var token = endOfFileToken.GetPreviousToken(includeSkipped: true); + if (token.HasTrailingTrivia) + { + trivia = token.TrailingTrivia.Last(); + } + } + } + + return trivia; + } + + public static SyntaxToken FindTokenOrEndToken( + this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + Debug.Assert(syntaxTree != null); + + var root = syntaxTree.GetRoot(cancellationToken); + var result = root.FindToken(position, findInsideTrivia: true); + if (result.RawKind != 0) + { + return result; + } + + // Special cases. See if we're actually at the end of a: + // a) doc comment + // b) pp directive + // c) file + + var compilationUnit = (ICompilationUnitSyntax)root; + var triviaList = compilationUnit.EndOfFileToken.LeadingTrivia; + foreach (var trivia in triviaList.Reverse()) + { + if (trivia.HasStructure) + { + var token = trivia.GetStructure().GetLastToken(includeZeroWidth: true); + if (token.Span.End == position) + { + return token; + } + } + } + + if (position == root.FullSpan.End) + { + return compilationUnit.EndOfFileToken; + } + + return default; + } + + /// + /// If the position is inside of token, return that token; otherwise, return the token to the left. + /// + public static SyntaxToken FindTokenOnLeftOfPosition( + this SyntaxTree syntaxTree, + int position, + CancellationToken cancellationToken, + bool includeSkipped = true, + bool includeDirectives = false, + bool includeDocumentationComments = false) + { + return syntaxTree.GetRoot(cancellationToken).FindTokenOnLeftOfPosition( + position, includeSkipped, includeDirectives, includeDocumentationComments); + } } } From a4b41312de4f2a0dc4615a19686a090e6096adb7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 16:20:31 -0800 Subject: [PATCH 08/21] Share more --- ...osoft.CodeAnalysis.CSharp.CodeStyle.csproj | 12 ++- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 2 + .../Classification/ClassificationHelpers.cs | 4 +- .../Extensions/ArgumentSyntaxExtensions.cs | 2 - .../Extensions/ExpressionSyntaxExtensions.cs | 71 ------------ .../ExpressionSyntaxExtensions_Shared.cs | 71 ++++++++++++ ...olExtensions.TypeSyntaxGeneratorVisitor.cs | 7 +- .../Extensions/ITypeSymbolExtensions.cs | 36 ------- .../ITypeSymbolExtensions_Shared.cs | 49 +++++++++ .../Extensions/SyntaxListExtensions.cs | 4 - .../Extensions/SyntaxNodeExtensions.cs | 102 ------------------ ...yntaxNodeExtensions_SharedWithCodeStyle.cs | 102 ++++++++++++++++++ .../Shared/Extensions/ISymbolExtensions.cs | 10 -- .../Extensions/ISymbolExtensions_Shared.cs | 11 ++ .../Extensions/ITypeSymbolExtensions.cs | 14 --- .../ITypeSymbolExtensions_Shared.cs | 14 +++ 16 files changed, 266 insertions(+), 245 deletions(-) create mode 100644 src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions_Shared.cs diff --git a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj index 5a3edf544471f..63c1d1e6d636a 100644 --- a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj +++ b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj @@ -20,12 +20,18 @@ + + - + + + - - + + + + diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index fe9eefdfb9c51..3ad76a18fdfd5 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -195,7 +195,9 @@ + + diff --git a/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs b/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs index 7672dbdb3a1ab..01337b5238e6d 100644 --- a/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs +++ b/src/Workspaces/CSharp/Portable/Classification/ClassificationHelpers.cs @@ -333,13 +333,13 @@ public static bool IsStaticallyDeclared(SyntaxToken token) parentNode = parentNode!.Parent!.Parent; // Check if this is a field constant declaration - if (parentNode.GetModifiers().Any(SyntaxKind.ConstKeyword)) + if (parentNode!.GetModifiers().Any(SyntaxKind.ConstKeyword)) { return true; } } - return parentNode.GetModifiers().Any(SyntaxKind.StaticKeyword); + return parentNode!.GetModifiers().Any(SyntaxKind.StaticKeyword); } private static bool IsExtensionMethod(MethodDeclarationSyntax methodDeclaration) diff --git a/src/Workspaces/CSharp/Portable/Extensions/ArgumentSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ArgumentSyntaxExtensions.cs index 6b50313d09995..42acaa2cbbc28 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ArgumentSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ArgumentSyntaxExtensions.cs @@ -5,11 +5,9 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Extensions { diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs index 16337523aa981..45641219435e0 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs @@ -36,43 +36,6 @@ public static ExpressionSyntax WalkDownParentheses(this ExpressionSyntax express return expression; } - public static ExpressionSyntax Parenthesize( - this ExpressionSyntax expression, bool includeElasticTrivia = true, bool addSimplifierAnnotation = true) - { - // a 'ref' expression should never be parenthesized. It fundamentally breaks the code. - // This is because, from the language's perspective there is no such thing as a ref - // expression. instead, there are constructs like ```return ref expr``` or - // ```x ? ref expr1 : ref expr2```, or ```ref int a = ref expr``` in these cases, the - // ref's do not belong to the exprs, but instead belong to the parent construct. i.e. - // ```return ref``` or ``` ? ref ... : ref ... ``` or ``` ... = ref ...```. For - // parsing convenience, and to prevent having to update all these constructs, we settled - // on a ref-expression node. But this node isn't a true expression that be operated - // on like with everything else. - if (expression.IsKind(SyntaxKind.RefExpression)) - { - return expression; - } - - var result = ParenthesizeWorker(expression, includeElasticTrivia); - return addSimplifierAnnotation - ? result.WithAdditionalAnnotations(Simplifier.Annotation) - : result; - } - - private static ExpressionSyntax ParenthesizeWorker( - this ExpressionSyntax expression, bool includeElasticTrivia) - { - var withoutTrivia = expression.WithoutTrivia(); - var parenthesized = includeElasticTrivia - ? SyntaxFactory.ParenthesizedExpression(withoutTrivia) - : SyntaxFactory.ParenthesizedExpression( - SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.OpenParenToken, SyntaxTriviaList.Empty), - withoutTrivia, - SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, SyntaxTriviaList.Empty)); - - return parenthesized.WithTriviaFrom(expression); - } - public static CastExpressionSyntax Cast( this ExpressionSyntax expression, ITypeSymbol targetType) @@ -276,34 +239,6 @@ public static bool IsAnyLiteralExpression(this ExpressionSyntax expression) expression.IsKind(SyntaxKind.TrueLiteralExpression); } - public static bool IsInConstantContext(this ExpressionSyntax expression) - { - if (expression.GetAncestor() != null) - { - return true; - } - - var attributeArgument = expression.GetAncestor(); - if (attributeArgument != null) - { - if (attributeArgument.NameEquals == null || - expression != attributeArgument.NameEquals.Name) - { - return true; - } - } - - if (expression.IsParentKind(SyntaxKind.ConstantPattern)) - { - return true; - } - - // note: the above list is not intended to be exhaustive. If more cases - // are discovered that should be considered 'constant' contexts in the - // language, then this should be updated accordingly. - return false; - } - public static bool IsInOutContext(this ExpressionSyntax expression) { return @@ -445,12 +380,6 @@ public static bool IsWrittenTo(this ExpressionSyntax expression) return false; } - public static bool IsAttributeNamedArgumentIdentifier(this ExpressionSyntax expression) - { - var nameEquals = expression?.Parent as NameEqualsSyntax; - return nameEquals.IsParentKind(SyntaxKind.AttributeArgument); - } - public static bool IsOperandOfIncrementOrDecrementExpression(this ExpressionSyntax expression) { if (expression != null) diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs index 165187d515ab2..8ad744fa6b3a5 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs @@ -32,5 +32,76 @@ private static bool IsMemberBindingExpressionName(this ExpressionSyntax expressi return expression.IsParentKind(SyntaxKind.MemberBindingExpression) && ((MemberBindingExpressionSyntax)expression.Parent).Name == expression; } + + public static bool IsInConstantContext(this ExpressionSyntax expression) + { + if (expression.GetAncestor() != null) + { + return true; + } + + var attributeArgument = expression.GetAncestor(); + if (attributeArgument != null) + { + if (attributeArgument.NameEquals == null || + expression != attributeArgument.NameEquals.Name) + { + return true; + } + } + + if (expression.IsParentKind(SyntaxKind.ConstantPattern)) + { + return true; + } + + // note: the above list is not intended to be exhaustive. If more cases + // are discovered that should be considered 'constant' contexts in the + // language, then this should be updated accordingly. + return false; + } + + public static bool IsAttributeNamedArgumentIdentifier(this ExpressionSyntax expression) + { + var nameEquals = expression?.Parent as NameEqualsSyntax; + return nameEquals.IsParentKind(SyntaxKind.AttributeArgument); + } + + public static ExpressionSyntax Parenthesize( + this ExpressionSyntax expression, bool includeElasticTrivia = true, bool addSimplifierAnnotation = true) + { + // a 'ref' expression should never be parenthesized. It fundamentally breaks the code. + // This is because, from the language's perspective there is no such thing as a ref + // expression. instead, there are constructs like ```return ref expr``` or + // ```x ? ref expr1 : ref expr2```, or ```ref int a = ref expr``` in these cases, the + // ref's do not belong to the exprs, but instead belong to the parent construct. i.e. + // ```return ref``` or ``` ? ref ... : ref ... ``` or ``` ... = ref ...```. For + // parsing convenience, and to prevent having to update all these constructs, we settled + // on a ref-expression node. But this node isn't a true expression that be operated + // on like with everything else. + if (expression.IsKind(SyntaxKind.RefExpression)) + { + return expression; + } + + var result = ParenthesizeWorker(expression, includeElasticTrivia); + return addSimplifierAnnotation + ? result.WithAdditionalAnnotations(Simplifier.Annotation) + : result; + } + + private static ExpressionSyntax ParenthesizeWorker( + this ExpressionSyntax expression, bool includeElasticTrivia) + { + var withoutTrivia = expression.WithoutTrivia(); + var parenthesized = includeElasticTrivia + ? SyntaxFactory.ParenthesizedExpression(withoutTrivia) + : SyntaxFactory.ParenthesizedExpression( + SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.OpenParenToken, SyntaxTriviaList.Empty), + withoutTrivia, + SyntaxFactory.Token(SyntaxTriviaList.Empty, SyntaxKind.CloseParenToken, SyntaxTriviaList.Empty)); + + return parenthesized.WithTriviaFrom(expression); + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index e4ea4d2b78d5e..2bad36415e737 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.FindSymbols.Finders; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; @@ -70,6 +69,7 @@ public override TypeSyntax VisitArrayType(IArrayTypeSymbol symbol) { underlyingType = innerArray.ElementType; +#if !CODE_STYLE if (underlyingType.NullableAnnotation == NullableAnnotation.Annotated) { // If the inner array we just moved to is also nullable, then @@ -88,6 +88,7 @@ public override TypeSyntax VisitArrayType(IArrayTypeSymbol symbol) break; } +#endif } var elementTypeSyntax = underlyingType.GenerateTypeSyntax(); @@ -104,10 +105,12 @@ public override TypeSyntax VisitArrayType(IArrayTypeSymbol symbol) TypeSyntax arrayTypeSyntax = SyntaxFactory.ArrayType(elementTypeSyntax, ranks.ToSyntaxList()); +#if !CODE_STYLE if (symbol.NullableAnnotation == NullableAnnotation.Annotated) { arrayTypeSyntax = SyntaxFactory.NullableType(arrayTypeSyntax); } +#endif return AddInformationTo(arrayTypeSyntax, symbol); } @@ -255,10 +258,12 @@ public override TypeSyntax VisitNamedType(INamedTypeSymbol symbol) } } +#if !CODE_STYLE if (symbol.NullableAnnotation == NullableAnnotation.Annotated) { typeSyntax = AddInformationTo(SyntaxFactory.NullableType(typeSyntax), symbol); } +#endif return typeSyntax; } diff --git a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.cs index 0243cc0268b00..c3376e829e797 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.cs @@ -10,11 +10,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; using Roslyn.Utilities; @@ -29,39 +26,6 @@ public static ExpressionSyntax GenerateExpressionSyntax( return typeSymbol.Accept(ExpressionSyntaxGeneratorVisitor.Instance).WithAdditionalAnnotations(Simplifier.Annotation); } - public static NameSyntax GenerateNameSyntax( - this INamespaceOrTypeSymbol symbol, bool allowVar = true) - { - return (NameSyntax)GenerateTypeSyntax(symbol, nameSyntax: true, allowVar: allowVar); - } - - public static TypeSyntax GenerateTypeSyntax( - this INamespaceOrTypeSymbol symbol, bool allowVar = true) - { - return GenerateTypeSyntax(symbol, nameSyntax: false, allowVar: allowVar); - } - - private static TypeSyntax GenerateTypeSyntax( - INamespaceOrTypeSymbol symbol, bool nameSyntax, bool allowVar = true) - { - if (symbol is ITypeSymbol type && type.ContainsAnonymousType()) - { - // something with an anonymous type can only be represented with 'var', regardless - // of what the user's preferences might be. - return SyntaxFactory.IdentifierName("var"); - } - - var syntax = symbol.Accept(TypeSyntaxGeneratorVisitor.Create(nameSyntax)) - .WithAdditionalAnnotations(Simplifier.Annotation); - - if (!allowVar) - { - syntax = syntax.WithAdditionalAnnotations(DoNotAllowVarAnnotation.Annotation); - } - - return syntax; - } - public static TypeSyntax GenerateRefTypeSyntax( this INamespaceOrTypeSymbol symbol) { diff --git a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions_Shared.cs new file mode 100644 index 0000000000000..1f426267d811c --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions_Shared.cs @@ -0,0 +1,49 @@ +// 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 Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Simplification; + +namespace Microsoft.CodeAnalysis.CSharp.Extensions +{ + internal static partial class ITypeSymbolExtensions + { + public static NameSyntax GenerateNameSyntax( + this INamespaceOrTypeSymbol symbol, bool allowVar = true) + { + return (NameSyntax)GenerateTypeSyntax(symbol, nameSyntax: true, allowVar: allowVar); + } + + public static TypeSyntax GenerateTypeSyntax( + this INamespaceOrTypeSymbol symbol, bool allowVar = true) + { + return GenerateTypeSyntax(symbol, nameSyntax: false, allowVar: allowVar); + } + + private static TypeSyntax GenerateTypeSyntax( + INamespaceOrTypeSymbol symbol, bool nameSyntax, bool allowVar = true) + { + if (symbol is ITypeSymbol type && type.ContainsAnonymousType()) + { + // something with an anonymous type can only be represented with 'var', regardless + // of what the user's preferences might be. + return SyntaxFactory.IdentifierName("var"); + } + + var syntax = symbol.Accept(TypeSyntaxGeneratorVisitor.Create(nameSyntax)) + .WithAdditionalAnnotations(Simplifier.Annotation); + + if (!allowVar) + { + syntax = syntax.WithAdditionalAnnotations(DoNotAllowVarAnnotation.Annotation); + } + + return syntax; + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxListExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxListExtensions.cs index 7a7a4712d374f..e868d65a967fd 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxListExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxListExtensions.cs @@ -4,10 +4,6 @@ using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs index 3b5bca300225e..c01e0a9c894a3 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs @@ -39,62 +39,6 @@ public static IEnumerable GetEnclosingExternAliasDir .SelectMany(n => n.Externs)); } - public static bool IsUnsafeContext(this SyntaxNode node) - { - if (node.GetAncestor() != null) - { - return true; - } - - return node.GetAncestors().Any( - m => m.GetModifiers().Any(SyntaxKind.UnsafeKeyword)); - } - - public static bool IsInStaticContext(this SyntaxNode node) - { - // this/base calls are always static. - if (node.FirstAncestorOrSelf() != null) - { - return true; - } - - var memberDeclaration = node.FirstAncestorOrSelf(); - if (memberDeclaration == null) - { - return false; - } - - switch (memberDeclaration.Kind()) - { - case SyntaxKind.MethodDeclaration: - case SyntaxKind.ConstructorDeclaration: - case SyntaxKind.EventDeclaration: - case SyntaxKind.IndexerDeclaration: - return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword); - - case SyntaxKind.PropertyDeclaration: - return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword) || - node.IsFoundUnder((PropertyDeclarationSyntax p) => p.Initializer); - - case SyntaxKind.FieldDeclaration: - case SyntaxKind.EventFieldDeclaration: - // Inside a field one can only access static members of a type (unless it's top-level). - return !memberDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit); - - case SyntaxKind.DestructorDeclaration: - return false; - } - - // Global statements are not a static context. - if (node.FirstAncestorOrSelf() != null) - { - return false; - } - - // any other location is considered static - return true; - } - public static NamespaceDeclarationSyntax GetInnermostNamespaceDeclarationWithUsings(this SyntaxNode contextNode) { var usingDirectiveAncestor = contextNode.GetAncestor(); @@ -175,18 +119,6 @@ public static bool IsReturnableConstruct(this SyntaxNode node) public static bool SpansPreprocessorDirective(this IEnumerable list) where TSyntaxNode : SyntaxNode => CSharpSyntaxFactsService.Instance.SpansPreprocessorDirective(list); - public static TNode ConvertToSingleLine(this TNode node, bool useElasticTrivia = false) - where TNode : SyntaxNode - { - if (node == null) - { - return node; - } - - var rewriter = new SingleLineRewriter(useElasticTrivia); - return (TNode)rewriter.Visit(node); - } - public static bool IsAsyncSupportingFunctionSyntax(this SyntaxNode node) { return node.IsKind(SyntaxKind.MethodDeclaration) @@ -437,12 +369,6 @@ public static bool IsCompoundAssignExpression(this SyntaxNode node) return false; } - public static bool IsLeftSideOfAssignExpression(this SyntaxNode node) - { - return node.IsParentKind(SyntaxKind.SimpleAssignmentExpression) && - ((AssignmentExpressionSyntax)node.Parent).Left == node; - } - public static bool IsLeftSideOfAnyAssignExpression(this SyntaxNode node) { return node != null && @@ -575,17 +501,6 @@ public static (SyntaxToken openBrace, SyntaxToken closeBrace) GetBrackets(this S } } - public static SyntaxTokenList GetModifiers(this SyntaxNode member) - { - switch (member) - { - case MemberDeclarationSyntax memberDecl: return memberDecl.Modifiers; - case AccessorDeclarationSyntax accessor: return accessor.Modifiers; - } - - return default; - } - public static SyntaxNode WithModifiers(this SyntaxNode member, SyntaxTokenList modifiers) { switch (member) @@ -676,23 +591,6 @@ public static IEnumerable GetMembers(this SyntaxNode no return SpecializedCollections.EmptyEnumerable(); } - public static ConditionalAccessExpressionSyntax GetParentConditionalAccessExpression(this SyntaxNode node) - { - var current = node; - while (current?.Parent != null) - { - if (current.IsParentKind(SyntaxKind.ConditionalAccessExpression) && - ((ConditionalAccessExpressionSyntax)current.Parent).WhenNotNull == current) - { - return (ConditionalAccessExpressionSyntax)current.Parent; - } - - current = current.Parent; - } - - return null; - } - public static ConditionalAccessExpressionSyntax GetInnerMostConditionalAccessExpression(this SyntaxNode node) { if (!(node is ConditionalAccessExpressionSyntax)) diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs index e58178ecf69d3..4aaf4689edec5 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs @@ -219,5 +219,107 @@ node is UsingStatementSyntax || WhileStatementSyntax n => n.Statement, _ => null, }; + + public static ConditionalAccessExpressionSyntax? GetParentConditionalAccessExpression(this SyntaxNode node) + { + var current = node; + while (current?.Parent != null) + { + if (current.IsParentKind(SyntaxKind.ConditionalAccessExpression) && + ((ConditionalAccessExpressionSyntax)current.Parent).WhenNotNull == current) + { + return (ConditionalAccessExpressionSyntax)current.Parent; + } + + current = current.Parent; + } + + return null; + } + + public static bool IsInStaticContext(this SyntaxNode node) + { + // this/base calls are always static. + if (node.FirstAncestorOrSelf() != null) + { + return true; + } + + var memberDeclaration = node.FirstAncestorOrSelf(); + if (memberDeclaration == null) + { + return false; + } + + switch (memberDeclaration.Kind()) + { + case SyntaxKind.MethodDeclaration: + case SyntaxKind.ConstructorDeclaration: + case SyntaxKind.EventDeclaration: + case SyntaxKind.IndexerDeclaration: + return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword); + + case SyntaxKind.PropertyDeclaration: + return memberDeclaration.GetModifiers().Any(SyntaxKind.StaticKeyword) || + node.IsFoundUnder((PropertyDeclarationSyntax p) => p.Initializer!); + + case SyntaxKind.FieldDeclaration: + case SyntaxKind.EventFieldDeclaration: + // Inside a field one can only access static members of a type (unless it's top-level). + return !memberDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit); + + case SyntaxKind.DestructorDeclaration: + return false; + } + + // Global statements are not a static context. + if (node.FirstAncestorOrSelf() != null) + { + return false; + } + + // any other location is considered static + return true; + } + + public static bool IsUnsafeContext(this SyntaxNode node) + { + if (node.GetAncestor() != null) + { + return true; + } + + return node.GetAncestors().Any( + m => m.GetModifiers().Any(SyntaxKind.UnsafeKeyword)); + } + + public static bool IsLeftSideOfAssignExpression(this SyntaxNode node) + { + return node.IsParentKind(SyntaxKind.SimpleAssignmentExpression) && + ((AssignmentExpressionSyntax)node.Parent!).Left == node; + } + + public static TNode ConvertToSingleLine(this TNode node, bool useElasticTrivia = false) + where TNode : SyntaxNode + { + if (node == null) + { + return node!; + } + + var rewriter = new SingleLineRewriter(useElasticTrivia); + return (TNode)rewriter.Visit(node); + } + + public static SyntaxTokenList GetModifiers(this SyntaxNode member) + { + switch (member) + { + case MemberDeclarationSyntax memberDecl: return memberDecl.Modifiers; + case AccessorDeclarationSyntax accessor: return accessor.Modifiers; + } + + return default; + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index fece28406b025..e0400f5fce346 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -446,16 +446,6 @@ public static bool IsParams([NotNullWhen(returnValue: true)] this ISymbol? symbo return parameters.Length > 0 && parameters[parameters.Length - 1].IsParams; } - public static ImmutableArray GetParameters(this ISymbol? symbol) - { - switch (symbol) - { - case IMethodSymbol m: return m.Parameters; - case IPropertySymbol nt: return nt.Parameters; - default: return ImmutableArray.Empty; - } - } - public static ImmutableArray GetTypeParameters(this ISymbol? symbol) { switch (symbol) diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs index 535247f19586c..634ebaa63251d 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs @@ -4,6 +4,7 @@ #nullable enable +using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; namespace Microsoft.CodeAnalysis.Shared.Extensions @@ -19,5 +20,15 @@ public static bool IsUnsafe([NotNullWhen(returnValue: true)] this ISymbol? membe // TODO(cyrusn): Defer to compiler code to handle this once it can. return member?.Accept(new IsUnsafeVisitor()) == true; } + + public static ImmutableArray GetParameters(this ISymbol? symbol) + { + switch (symbol) + { + case IMethodSymbol m: return m.Parameters; + case IPropertySymbol nt: return nt.Parameters; + default: return ImmutableArray.Empty; + } + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs index 2680234f7f098..85ff61f6053a7 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions.cs @@ -49,9 +49,6 @@ public static bool IsAbstractClass([NotNullWhen(returnValue: true)] this ITypeSy return symbol?.TypeKind == TypeKind.Class && symbol.IsAbstract; } - public static bool IsNullable([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) - => symbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; - public static bool IsNullable( [NotNullWhen(true)] this ITypeSymbol? symbol, [NotNullWhen(true)] out ITypeSymbol? underlyingType) @@ -586,17 +583,6 @@ public static Accessibility DetermineMinimalAccessibility(this ITypeSymbol typeS return typeSymbol.Accept(MinimalAccessibilityVisitor.Instance); } - public static bool ContainsAnonymousType([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) - { - switch (symbol) - { - case IArrayTypeSymbol a: return ContainsAnonymousType(a.ElementType); - case IPointerTypeSymbol p: return ContainsAnonymousType(p.PointedAtType); - case INamedTypeSymbol n: return ContainsAnonymousType(n); - default: return false; - } - } - private static bool ContainsAnonymousType(INamedTypeSymbol type) { if (type.IsAnonymousType) diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs index ed95e9650b8eb..3d5a61b66af50 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ITypeSymbolExtensions_Shared.cs @@ -14,5 +14,19 @@ public static bool IsSystemVoid([NotNullWhen(returnValue: true)] this ITypeSymbo { return symbol?.SpecialType == SpecialType.System_Void; } + + public static bool ContainsAnonymousType([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) + { + switch (symbol) + { + case IArrayTypeSymbol a: return ContainsAnonymousType(a.ElementType); + case IPointerTypeSymbol p: return ContainsAnonymousType(p.PointedAtType); + case INamedTypeSymbol n: return ContainsAnonymousType(n); + default: return false; + } + } + + public static bool IsNullable([NotNullWhen(returnValue: true)] this ITypeSymbol? symbol) + => symbol?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T; } } From e037e13d02767df32bcf06603f83d15cf649fa5f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 16:48:43 -0800 Subject: [PATCH 09/21] Share more --- ...osoft.CodeAnalysis.CSharp.CodeStyle.csproj | 12 +- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 9 + .../ContextQuery/SyntaxTreeExtensions.cs | 101 +----------- .../SyntaxTreeExtensions_Shared.cs | 112 +++++++++++++ .../Extensions/DirectiveSyntaxExtensions.cs | 3 - .../Extensions/ExpressionSyntaxExtensions.cs | 35 ---- .../ExpressionSyntaxExtensions_Shared.cs | 41 ++++- .../MemberDeclarationSyntaxExtensions.cs | 139 ---------------- ...emberDeclarationSyntaxExtensions_Shared.cs | 156 ++++++++++++++++++ .../Extensions/SyntaxNodeExtensions.cs | 140 ---------------- ...yntaxNodeExtensions_SharedWithCodeStyle.cs | 140 ++++++++++++++++ .../Extensions/SyntaxTreeExtensions.cs | 81 --------- .../Extensions/SyntaxTreeExtensions_Shared.cs | 81 +++++++++ .../Extensions/SyntaxTriviaListExtensions.cs | 1 - .../CodeGeneration/CodeGenerationHelpers.cs | 7 +- .../CodeGenerationHelpers_Shared.cs | 23 +++ .../Shared/Extensions/ISymbolExtensions.cs | 5 - .../Extensions/ISymbolExtensions_Shared.cs | 5 + 18 files changed, 574 insertions(+), 517 deletions(-) create mode 100644 src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs create mode 100644 src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions_Shared.cs create mode 100644 src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers_Shared.cs diff --git a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj index 63c1d1e6d636a..333f737788489 100644 --- a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj +++ b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj @@ -19,14 +19,23 @@ + + + + + + + + + @@ -34,6 +43,7 @@ + @@ -90,8 +100,8 @@ + - \ No newline at end of file diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 3ad76a18fdfd5..56c64f9a1792b 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -26,11 +26,14 @@ + + + @@ -54,6 +57,9 @@ + + + @@ -197,6 +203,7 @@ + @@ -232,6 +239,8 @@ + + diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs index 2372fe052ebf6..890aac5dd3023 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.cs @@ -2,20 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery { - internal static class SyntaxTreeExtensions + internal static partial class SyntaxTreeExtensions { public static bool IsAttributeNameContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { @@ -1203,66 +1200,6 @@ public static bool IsPossibleLambdaOrAnonymousMethodParameterTypeContext( return false; } - /// - /// Are you possibly typing a tuple type or expression? - /// This is used to suppress colon as a completion trigger (so that you can type element names). - /// This is also used to recommend some keywords (like var). - /// - public static bool IsPossibleTupleContext(this SyntaxTree syntaxTree, SyntaxToken leftToken, int position) - { - leftToken = leftToken.GetPreviousTokenIfTouchingWord(position); - - // ($$ - // (a, $$ - if (IsPossibleTupleOpenParenOrComma(leftToken)) - { - return true; - } - - // ((a, b) $$ - // (..., (a, b) $$ - if (leftToken.IsKind(SyntaxKind.CloseParenToken)) - { - if (leftToken.Parent.IsKind( - SyntaxKind.ParenthesizedExpression, - SyntaxKind.TupleExpression, - SyntaxKind.TupleType)) - { - var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent); - if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) - { - return true; - } - } - } - - // (a $$ - // (..., b $$ - if (leftToken.IsKind(SyntaxKind.IdentifierToken)) - { - var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent); - if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) - { - return true; - } - } - - // (a.b $$ - // (..., a.b $$ - if (leftToken.IsKind(SyntaxKind.IdentifierToken) && - leftToken.Parent.IsKind(SyntaxKind.IdentifierName) && - leftToken.Parent.IsParentKind(SyntaxKind.QualifiedName, SyntaxKind.SimpleMemberAccessExpression)) - { - var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent.Parent); - if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) - { - return true; - } - } - - return false; - } - public static bool IsPatternContext(this SyntaxTree syntaxTree, SyntaxToken leftToken, int position) { leftToken = leftToken.GetPreviousTokenIfTouchingWord(position); @@ -1299,42 +1236,6 @@ public static bool IsPatternContext(this SyntaxTree syntaxTree, SyntaxToken left return false; } - private static SyntaxToken FindTokenOnLeftOfNode(SyntaxNode node) - { - return node.FindTokenOnLeftOfPosition(node.SpanStart); - } - - - public static bool IsPossibleTupleOpenParenOrComma(this SyntaxToken possibleCommaOrParen) - { - if (!possibleCommaOrParen.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken)) - { - return false; - } - - if (possibleCommaOrParen.Parent.IsKind( - SyntaxKind.ParenthesizedExpression, - SyntaxKind.TupleExpression, - SyntaxKind.TupleType, - SyntaxKind.CastExpression)) - { - return true; - } - - // in script - if (possibleCommaOrParen.Parent.IsKind(SyntaxKind.ParameterList) && - possibleCommaOrParen.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression)) - { - var parenthesizedLambda = (ParenthesizedLambdaExpressionSyntax)possibleCommaOrParen.Parent.Parent; - if (parenthesizedLambda.ArrowToken.IsMissing) - { - return true; - } - } - - return false; - } - /// /// Are you possibly in the designation part of a deconstruction? /// This is used to enter suggestion mode (suggestions become soft-selected). diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs new file mode 100644 index 0000000000000..998fe172f717b --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs @@ -0,0 +1,112 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery +{ + internal static partial class SyntaxTreeExtensions + { + /// + /// Are you possibly typing a tuple type or expression? + /// This is used to suppress colon as a completion trigger (so that you can type element names). + /// This is also used to recommend some keywords (like var). + /// + public static bool IsPossibleTupleContext(this SyntaxTree syntaxTree, SyntaxToken leftToken, int position) + { + leftToken = leftToken.GetPreviousTokenIfTouchingWord(position); + + // ($$ + // (a, $$ + if (IsPossibleTupleOpenParenOrComma(leftToken)) + { + return true; + } + + // ((a, b) $$ + // (..., (a, b) $$ + if (leftToken.IsKind(SyntaxKind.CloseParenToken)) + { + if (leftToken.Parent.IsKind( + SyntaxKind.ParenthesizedExpression, + SyntaxKind.TupleExpression, + SyntaxKind.TupleType)) + { + var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent); + if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) + { + return true; + } + } + } + + // (a $$ + // (..., b $$ + if (leftToken.IsKind(SyntaxKind.IdentifierToken)) + { + var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent); + if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) + { + return true; + } + } + + // (a.b $$ + // (..., a.b $$ + if (leftToken.IsKind(SyntaxKind.IdentifierToken) && + leftToken.Parent.IsKind(SyntaxKind.IdentifierName) && + leftToken.Parent.IsParentKind(SyntaxKind.QualifiedName, SyntaxKind.SimpleMemberAccessExpression)) + { + var possibleCommaOrParen = FindTokenOnLeftOfNode(leftToken.Parent.Parent); + if (IsPossibleTupleOpenParenOrComma(possibleCommaOrParen)) + { + return true; + } + } + + return false; + } + + public static bool IsPossibleTupleOpenParenOrComma(this SyntaxToken possibleCommaOrParen) + { + if (!possibleCommaOrParen.IsKind(SyntaxKind.OpenParenToken, SyntaxKind.CommaToken)) + { + return false; + } + + if (possibleCommaOrParen.Parent.IsKind( + SyntaxKind.ParenthesizedExpression, + SyntaxKind.TupleExpression, + SyntaxKind.TupleType, + SyntaxKind.CastExpression)) + { + return true; + } + + // in script + if (possibleCommaOrParen.Parent.IsKind(SyntaxKind.ParameterList) && + possibleCommaOrParen.Parent.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression)) + { + var parenthesizedLambda = (ParenthesizedLambdaExpressionSyntax)possibleCommaOrParen.Parent.Parent; + if (parenthesizedLambda.ArrowToken.IsMissing) + { + return true; + } + } + + return false; + } + + private static SyntaxToken FindTokenOnLeftOfNode(SyntaxNode node) + { + return node.FindTokenOnLeftOfPosition(node.SpanStart); + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Extensions/DirectiveSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/DirectiveSyntaxExtensions.cs index 876010833d72e..29b3b72a1ec3a 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/DirectiveSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/DirectiveSyntaxExtensions.cs @@ -6,10 +6,7 @@ using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Extensions { diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs index 45641219435e0..6e279ab7f5929 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions.cs @@ -26,16 +26,6 @@ public static ExpressionSyntax WalkUpParentheses(this ExpressionSyntax expressio return expression; } - public static ExpressionSyntax WalkDownParentheses(this ExpressionSyntax expression) - { - while (expression.IsKind(SyntaxKind.ParenthesizedExpression)) - { - expression = ((ParenthesizedExpressionSyntax)expression).Expression; - } - - return expression; - } - public static CastExpressionSyntax Cast( this ExpressionSyntax expression, ITypeSymbol targetType) @@ -145,31 +135,6 @@ public static bool IsRightOfCloseParen(this ExpressionSyntax expression) && firstToken.GetPreviousToken().Kind() == SyntaxKind.CloseParenToken; } - public static bool IsLeftSideOfDot(this ExpressionSyntax expression) - { - if (expression == null) - { - return false; - } - - return IsLeftSideOfQualifiedName(expression) || - IsLeftSideOfSimpleMemberAccessExpression(expression); - } - - public static bool IsLeftSideOfSimpleMemberAccessExpression(this ExpressionSyntax expression) - => (expression?.Parent).IsKind(SyntaxKind.SimpleMemberAccessExpression, out MemberAccessExpressionSyntax memberAccess) && - memberAccess.Expression == expression; - - public static bool IsLeftSideOfDotOrArrow(this ExpressionSyntax expression) - => IsLeftSideOfQualifiedName(expression) || - (expression.Parent is MemberAccessExpressionSyntax memberAccess && memberAccess.Expression == expression); - - public static bool IsLeftSideOfQualifiedName(this ExpressionSyntax expression) - => (expression?.Parent).IsKind(SyntaxKind.QualifiedName, out QualifiedNameSyntax qualifiedName) && qualifiedName.Left == expression; - - public static bool IsLeftSideOfExplicitInterfaceSpecifier(this NameSyntax name) - => name.IsParentKind(SyntaxKind.ExplicitInterfaceSpecifier); - public static bool IsExpressionOfInvocation(this ExpressionSyntax expression) => (expression?.Parent).IsKind(SyntaxKind.InvocationExpression, out InvocationExpressionSyntax invocation) && invocation.Expression == expression; diff --git a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs index 8ad744fa6b3a5..b65db4645ccfc 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ExpressionSyntaxExtensions_Shared.cs @@ -2,15 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Linq; -using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.Simplification; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions { @@ -103,5 +97,40 @@ private static ExpressionSyntax ParenthesizeWorker( return parenthesized.WithTriviaFrom(expression); } + + public static bool IsLeftSideOfDot(this ExpressionSyntax expression) + { + if (expression == null) + { + return false; + } + + return IsLeftSideOfQualifiedName(expression) || + IsLeftSideOfSimpleMemberAccessExpression(expression); + } + + public static bool IsLeftSideOfSimpleMemberAccessExpression(this ExpressionSyntax expression) + => (expression?.Parent).IsKind(SyntaxKind.SimpleMemberAccessExpression, out MemberAccessExpressionSyntax memberAccess) && + memberAccess.Expression == expression; + + public static bool IsLeftSideOfExplicitInterfaceSpecifier(this NameSyntax name) + => name.IsParentKind(SyntaxKind.ExplicitInterfaceSpecifier); + + public static bool IsLeftSideOfQualifiedName(this ExpressionSyntax expression) + => (expression?.Parent).IsKind(SyntaxKind.QualifiedName, out QualifiedNameSyntax qualifiedName) && qualifiedName.Left == expression; + + public static bool IsLeftSideOfDotOrArrow(this ExpressionSyntax expression) + => IsLeftSideOfQualifiedName(expression) || + (expression.Parent is MemberAccessExpressionSyntax memberAccess && memberAccess.Expression == expression); + + public static ExpressionSyntax WalkDownParentheses(this ExpressionSyntax expression) + { + while (expression.IsKind(SyntaxKind.ParenthesizedExpression)) + { + expression = ((ParenthesizedExpressionSyntax)expression).Expression; + } + + return expression; + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions.cs index bd8a112cb364a..5658e1a3a1711 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions.cs @@ -29,45 +29,6 @@ private static Dictionary> CreateLocalDeclar return dictionary.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.AsImmutable()); } - public static SyntaxToken GetNameToken(this MemberDeclarationSyntax member) - { - if (member != null) - { - switch (member.Kind()) - { - case SyntaxKind.EnumDeclaration: - return ((EnumDeclarationSyntax)member).Identifier; - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.StructDeclaration: - return ((TypeDeclarationSyntax)member).Identifier; - case SyntaxKind.DelegateDeclaration: - return ((DelegateDeclarationSyntax)member).Identifier; - case SyntaxKind.FieldDeclaration: - return ((FieldDeclarationSyntax)member).Declaration.Variables.First().Identifier; - case SyntaxKind.EventFieldDeclaration: - return ((EventFieldDeclarationSyntax)member).Declaration.Variables.First().Identifier; - case SyntaxKind.PropertyDeclaration: - return ((PropertyDeclarationSyntax)member).Identifier; - case SyntaxKind.EventDeclaration: - return ((EventDeclarationSyntax)member).Identifier; - case SyntaxKind.MethodDeclaration: - return ((MethodDeclarationSyntax)member).Identifier; - case SyntaxKind.ConstructorDeclaration: - return ((ConstructorDeclarationSyntax)member).Identifier; - case SyntaxKind.DestructorDeclaration: - return ((DestructorDeclarationSyntax)member).Identifier; - case SyntaxKind.IndexerDeclaration: - return ((IndexerDeclarationSyntax)member).ThisKeyword; - case SyntaxKind.OperatorDeclaration: - return ((OperatorDeclarationSyntax)member).OperatorToken; - } - } - - // Conversion operators don't have names. - return default; - } - public static int GetArity(this MemberDeclarationSyntax member) { if (member != null) @@ -88,78 +49,6 @@ public static int GetArity(this MemberDeclarationSyntax member) return 0; } - public static TypeParameterListSyntax GetTypeParameterList(this MemberDeclarationSyntax member) - { - if (member != null) - { - switch (member.Kind()) - { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.StructDeclaration: - return ((TypeDeclarationSyntax)member).TypeParameterList; - case SyntaxKind.DelegateDeclaration: - return ((DelegateDeclarationSyntax)member).TypeParameterList; - case SyntaxKind.MethodDeclaration: - return ((MethodDeclarationSyntax)member).TypeParameterList; - } - } - - return null; - } - - public static BaseParameterListSyntax GetParameterList(this MemberDeclarationSyntax member) - { - if (member != null) - { - switch (member.Kind()) - { - case SyntaxKind.DelegateDeclaration: - return ((DelegateDeclarationSyntax)member).ParameterList; - case SyntaxKind.MethodDeclaration: - return ((MethodDeclarationSyntax)member).ParameterList; - case SyntaxKind.ConstructorDeclaration: - return ((ConstructorDeclarationSyntax)member).ParameterList; - case SyntaxKind.DestructorDeclaration: - return ((DestructorDeclarationSyntax)member).ParameterList; - case SyntaxKind.IndexerDeclaration: - return ((IndexerDeclarationSyntax)member).ParameterList; - case SyntaxKind.OperatorDeclaration: - return ((OperatorDeclarationSyntax)member).ParameterList; - case SyntaxKind.ConversionOperatorDeclaration: - return ((ConversionOperatorDeclarationSyntax)member).ParameterList; - } - } - - return null; - } - - public static MemberDeclarationSyntax WithParameterList( - this MemberDeclarationSyntax member, - BaseParameterListSyntax parameterList) - { - if (member != null) - { - switch (member.Kind()) - { - case SyntaxKind.DelegateDeclaration: - return ((DelegateDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); - case SyntaxKind.MethodDeclaration: - return ((MethodDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); - case SyntaxKind.ConstructorDeclaration: - return ((ConstructorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); - case SyntaxKind.IndexerDeclaration: - return ((IndexerDeclarationSyntax)member).WithParameterList((BracketedParameterListSyntax)parameterList); - case SyntaxKind.OperatorDeclaration: - return ((OperatorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); - case SyntaxKind.ConversionOperatorDeclaration: - return ((ConversionOperatorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); - } - } - - return null; - } - public static MemberDeclarationSyntax AddAttributeLists( this MemberDeclarationSyntax member, params AttributeListSyntax[] attributeLists) @@ -213,34 +102,6 @@ public static MemberDeclarationSyntax WithAttributeLists( return null; } - public static TypeSyntax GetMemberType(this MemberDeclarationSyntax member) - { - if (member != null) - { - switch (member.Kind()) - { - case SyntaxKind.DelegateDeclaration: - return ((DelegateDeclarationSyntax)member).ReturnType; - case SyntaxKind.MethodDeclaration: - return ((MethodDeclarationSyntax)member).ReturnType; - case SyntaxKind.OperatorDeclaration: - return ((OperatorDeclarationSyntax)member).ReturnType; - case SyntaxKind.PropertyDeclaration: - return ((PropertyDeclarationSyntax)member).Type; - case SyntaxKind.IndexerDeclaration: - return ((IndexerDeclarationSyntax)member).Type; - case SyntaxKind.EventDeclaration: - return ((EventDeclarationSyntax)member).Type; - case SyntaxKind.EventFieldDeclaration: - return ((EventFieldDeclarationSyntax)member).Declaration.Type; - case SyntaxKind.FieldDeclaration: - return ((FieldDeclarationSyntax)member).Declaration.Type; - } - } - - return null; - } - public static bool HasMethodShape(this MemberDeclarationSyntax memberDeclaration) { if (memberDeclaration != null) diff --git a/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions_Shared.cs new file mode 100644 index 0000000000000..71a2c4a06289e --- /dev/null +++ b/src/Workspaces/CSharp/Portable/Extensions/MemberDeclarationSyntaxExtensions_Shared.cs @@ -0,0 +1,156 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp.Extensions +{ + internal static partial class MemberDeclarationSyntaxExtensions + { + + public static TypeSyntax GetMemberType(this MemberDeclarationSyntax member) + { + if (member != null) + { + switch (member.Kind()) + { + case SyntaxKind.DelegateDeclaration: + return ((DelegateDeclarationSyntax)member).ReturnType; + case SyntaxKind.MethodDeclaration: + return ((MethodDeclarationSyntax)member).ReturnType; + case SyntaxKind.OperatorDeclaration: + return ((OperatorDeclarationSyntax)member).ReturnType; + case SyntaxKind.PropertyDeclaration: + return ((PropertyDeclarationSyntax)member).Type; + case SyntaxKind.IndexerDeclaration: + return ((IndexerDeclarationSyntax)member).Type; + case SyntaxKind.EventDeclaration: + return ((EventDeclarationSyntax)member).Type; + case SyntaxKind.EventFieldDeclaration: + return ((EventFieldDeclarationSyntax)member).Declaration.Type; + case SyntaxKind.FieldDeclaration: + return ((FieldDeclarationSyntax)member).Declaration.Type; + } + } + + return null; + } + + public static BaseParameterListSyntax GetParameterList(this MemberDeclarationSyntax member) + { + if (member != null) + { + switch (member.Kind()) + { + case SyntaxKind.DelegateDeclaration: + return ((DelegateDeclarationSyntax)member).ParameterList; + case SyntaxKind.MethodDeclaration: + return ((MethodDeclarationSyntax)member).ParameterList; + case SyntaxKind.ConstructorDeclaration: + return ((ConstructorDeclarationSyntax)member).ParameterList; + case SyntaxKind.DestructorDeclaration: + return ((DestructorDeclarationSyntax)member).ParameterList; + case SyntaxKind.IndexerDeclaration: + return ((IndexerDeclarationSyntax)member).ParameterList; + case SyntaxKind.OperatorDeclaration: + return ((OperatorDeclarationSyntax)member).ParameterList; + case SyntaxKind.ConversionOperatorDeclaration: + return ((ConversionOperatorDeclarationSyntax)member).ParameterList; + } + } + + return null; + } + + public static SyntaxToken GetNameToken(this MemberDeclarationSyntax member) + { + if (member != null) + { + switch (member.Kind()) + { + case SyntaxKind.EnumDeclaration: + return ((EnumDeclarationSyntax)member).Identifier; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.StructDeclaration: + return ((TypeDeclarationSyntax)member).Identifier; + case SyntaxKind.DelegateDeclaration: + return ((DelegateDeclarationSyntax)member).Identifier; + case SyntaxKind.FieldDeclaration: + return ((FieldDeclarationSyntax)member).Declaration.Variables.First().Identifier; + case SyntaxKind.EventFieldDeclaration: + return ((EventFieldDeclarationSyntax)member).Declaration.Variables.First().Identifier; + case SyntaxKind.PropertyDeclaration: + return ((PropertyDeclarationSyntax)member).Identifier; + case SyntaxKind.EventDeclaration: + return ((EventDeclarationSyntax)member).Identifier; + case SyntaxKind.MethodDeclaration: + return ((MethodDeclarationSyntax)member).Identifier; + case SyntaxKind.ConstructorDeclaration: + return ((ConstructorDeclarationSyntax)member).Identifier; + case SyntaxKind.DestructorDeclaration: + return ((DestructorDeclarationSyntax)member).Identifier; + case SyntaxKind.IndexerDeclaration: + return ((IndexerDeclarationSyntax)member).ThisKeyword; + case SyntaxKind.OperatorDeclaration: + return ((OperatorDeclarationSyntax)member).OperatorToken; + } + } + + // Conversion operators don't have names. + return default; + } + + public static TypeParameterListSyntax GetTypeParameterList(this MemberDeclarationSyntax member) + { + if (member != null) + { + switch (member.Kind()) + { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.StructDeclaration: + return ((TypeDeclarationSyntax)member).TypeParameterList; + case SyntaxKind.DelegateDeclaration: + return ((DelegateDeclarationSyntax)member).TypeParameterList; + case SyntaxKind.MethodDeclaration: + return ((MethodDeclarationSyntax)member).TypeParameterList; + } + } + + return null; + } + + public static MemberDeclarationSyntax WithParameterList( + this MemberDeclarationSyntax member, + BaseParameterListSyntax parameterList) + { + if (member != null) + { + switch (member.Kind()) + { + case SyntaxKind.DelegateDeclaration: + return ((DelegateDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); + case SyntaxKind.MethodDeclaration: + return ((MethodDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); + case SyntaxKind.ConstructorDeclaration: + return ((ConstructorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); + case SyntaxKind.IndexerDeclaration: + return ((IndexerDeclarationSyntax)member).WithParameterList((BracketedParameterListSyntax)parameterList); + case SyntaxKind.OperatorDeclaration: + return ((OperatorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); + case SyntaxKind.ConversionOperatorDeclaration: + return ((ConversionOperatorDeclarationSyntax)member).WithParameterList((ParameterListSyntax)parameterList); + } + } + + return null; + } + } +} diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs index c01e0a9c894a3..b0133bed1533a 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions.cs @@ -183,80 +183,6 @@ public static bool ContainsInterleavedDirective(this SyntaxNode syntaxNode, Canc public static bool ContainsInterleavedDirective(this SyntaxNode syntaxNode, TextSpan span, CancellationToken cancellationToken) => CSharpSyntaxFactsService.Instance.ContainsInterleavedDirective(span, syntaxNode, cancellationToken); - public static bool ContainsInterleavedDirective( - this SyntaxToken token, - TextSpan textSpan, - CancellationToken cancellationToken) - { - return - ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) || - ContainsInterleavedDirective(textSpan, token.TrailingTrivia, cancellationToken); - } - - private static bool ContainsInterleavedDirective( - TextSpan textSpan, - SyntaxTriviaList list, - CancellationToken cancellationToken) - { - foreach (var trivia in list) - { - if (textSpan.Contains(trivia.Span)) - { - if (ContainsInterleavedDirective(textSpan, trivia, cancellationToken)) - { - return true; - } - } - } - - return false; - } - - private static bool ContainsInterleavedDirective( - TextSpan textSpan, - SyntaxTrivia trivia, - CancellationToken cancellationToken) - { - if (trivia.HasStructure) - { - var structure = trivia.GetStructure(); - var parentSpan = structure.Span; - if (trivia.GetStructure().IsKind(SyntaxKind.RegionDirectiveTrivia, - SyntaxKind.EndRegionDirectiveTrivia, - SyntaxKind.IfDirectiveTrivia, - SyntaxKind.EndIfDirectiveTrivia)) - { - var match = ((DirectiveTriviaSyntax)structure).GetMatchingDirective(cancellationToken); - if (match != null) - { - var matchSpan = match.Span; - if (!textSpan.Contains(matchSpan.Start)) - { - // The match for this pp directive is outside - // this node. - return true; - } - } - } - else if (trivia.GetStructure().IsKind(SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia)) - { - var directives = ((DirectiveTriviaSyntax)structure).GetMatchingConditionalDirectives(cancellationToken); - if (directives != null && directives.Count > 0) - { - if (!textSpan.Contains(directives[0].SpanStart) || - !textSpan.Contains(directives[directives.Count - 1].SpanStart)) - { - // This else/elif belongs to a pp span that isn't - // entirely within this node. - return true; - } - } - } - } - - return false; - } - /// /// Breaks up the list of provided nodes, based on how they are interspersed with pp /// directives, into groups. Within these groups nodes can be moved around safely, without @@ -345,50 +271,12 @@ public static TSyntaxNode GetNodeWithoutLeadingBannerAndPreprocessorDirectives(this TSyntaxNode node, out ImmutableArray strippedTrivia) where TSyntaxNode : SyntaxNode => CSharpSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, out strippedTrivia); - public static bool IsAnyAssignExpression(this SyntaxNode node) - => SyntaxFacts.IsAssignmentExpression(node.Kind()); - - public static bool IsCompoundAssignExpression(this SyntaxNode node) - { - switch (node.Kind()) - { - case SyntaxKind.CoalesceAssignmentExpression: - case SyntaxKind.AddAssignmentExpression: - case SyntaxKind.SubtractAssignmentExpression: - case SyntaxKind.MultiplyAssignmentExpression: - case SyntaxKind.DivideAssignmentExpression: - case SyntaxKind.ModuloAssignmentExpression: - case SyntaxKind.AndAssignmentExpression: - case SyntaxKind.ExclusiveOrAssignmentExpression: - case SyntaxKind.OrAssignmentExpression: - case SyntaxKind.LeftShiftAssignmentExpression: - case SyntaxKind.RightShiftAssignmentExpression: - return true; - } - - return false; - } - - public static bool IsLeftSideOfAnyAssignExpression(this SyntaxNode node) - { - return node != null && - node.Parent.IsAnyAssignExpression() && - ((AssignmentExpressionSyntax)node.Parent).Left == node; - } - public static bool IsRightSideOfAnyAssignExpression(this SyntaxNode node) { return node.Parent.IsAnyAssignExpression() && ((AssignmentExpressionSyntax)node.Parent).Right == node; } - public static bool IsLeftSideOfCompoundAssignExpression(this SyntaxNode node) - { - return node != null && - node.Parent.IsCompoundAssignExpression() && - ((AssignmentExpressionSyntax)node.Parent).Left == node; - } - public static bool IsVariableDeclaratorValue(this SyntaxNode node) { return @@ -501,17 +389,6 @@ public static (SyntaxToken openBrace, SyntaxToken closeBrace) GetBrackets(this S } } - public static SyntaxNode WithModifiers(this SyntaxNode member, SyntaxTokenList modifiers) - { - switch (member) - { - case MemberDeclarationSyntax memberDecl: return memberDecl.WithModifiers(modifiers); - case AccessorDeclarationSyntax accessor: return accessor.WithModifiers(modifiers); - } - - return null; - } - public static bool CheckTopLevel(this SyntaxNode node, TextSpan span) { switch (node) @@ -574,23 +451,6 @@ public static bool ContainsInExpressionBodiedMemberBody(this ArrowExpressionClau return expressionBodiedMemberBody.Contains(textSpan); } - public static IEnumerable GetMembers(this SyntaxNode node) - { - switch (node) - { - case CompilationUnitSyntax compilation: - return compilation.Members; - case NamespaceDeclarationSyntax @namespace: - return @namespace.Members; - case TypeDeclarationSyntax type: - return type.Members; - case EnumDeclarationSyntax @enum: - return @enum.Members; - } - - return SpecializedCollections.EmptyEnumerable(); - } - public static ConditionalAccessExpressionSyntax GetInnerMostConditionalAccessExpression(this SyntaxNode node) { if (!(node is ConditionalAccessExpressionSyntax)) diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs index 4aaf4689edec5..b45c0656cf725 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Threading; using Microsoft.CodeAnalysis.CSharp.Formatting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -321,5 +322,144 @@ public static SyntaxTokenList GetModifiers(this SyntaxNode member) return default; } + + public static IEnumerable GetMembers(this SyntaxNode node) + { + switch (node) + { + case CompilationUnitSyntax compilation: + return compilation.Members; + case NamespaceDeclarationSyntax @namespace: + return @namespace.Members; + case TypeDeclarationSyntax type: + return type.Members; + case EnumDeclarationSyntax @enum: + return @enum.Members; + } + + return SpecializedCollections.EmptyEnumerable(); + } + + public static bool IsLeftSideOfAnyAssignExpression(this SyntaxNode node) + { + return node != null && + node.Parent!.IsAnyAssignExpression() && + ((AssignmentExpressionSyntax)node.Parent!).Left == node; + } + + public static bool IsLeftSideOfCompoundAssignExpression(this SyntaxNode node) + { + return node != null && + node.Parent!.IsCompoundAssignExpression() && + ((AssignmentExpressionSyntax)node.Parent!).Left == node; + } + + public static bool IsAnyAssignExpression(this SyntaxNode node) + => SyntaxFacts.IsAssignmentExpression(node.Kind()); + + public static bool IsCompoundAssignExpression(this SyntaxNode node) + { + switch (node.Kind()) + { + case SyntaxKind.CoalesceAssignmentExpression: + case SyntaxKind.AddAssignmentExpression: + case SyntaxKind.SubtractAssignmentExpression: + case SyntaxKind.MultiplyAssignmentExpression: + case SyntaxKind.DivideAssignmentExpression: + case SyntaxKind.ModuloAssignmentExpression: + case SyntaxKind.AndAssignmentExpression: + case SyntaxKind.ExclusiveOrAssignmentExpression: + case SyntaxKind.OrAssignmentExpression: + case SyntaxKind.LeftShiftAssignmentExpression: + case SyntaxKind.RightShiftAssignmentExpression: + return true; + } + + return false; + } + public static bool ContainsInterleavedDirective( + this SyntaxToken token, + TextSpan textSpan, + CancellationToken cancellationToken) + { + return + ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) || + ContainsInterleavedDirective(textSpan, token.TrailingTrivia, cancellationToken); + } + + private static bool ContainsInterleavedDirective( + TextSpan textSpan, + SyntaxTriviaList list, + CancellationToken cancellationToken) + { + foreach (var trivia in list) + { + if (textSpan.Contains(trivia.Span)) + { + if (ContainsInterleavedDirective(textSpan, trivia, cancellationToken)) + { + return true; + } + } + } + + return false; + } + + private static bool ContainsInterleavedDirective( + TextSpan textSpan, + SyntaxTrivia trivia, + CancellationToken cancellationToken) + { + if (trivia.HasStructure) + { + var structure = trivia.GetStructure(); + var parentSpan = structure.Span; + if (trivia.GetStructure().IsKind(SyntaxKind.RegionDirectiveTrivia, + SyntaxKind.EndRegionDirectiveTrivia, + SyntaxKind.IfDirectiveTrivia, + SyntaxKind.EndIfDirectiveTrivia)) + { + var match = ((DirectiveTriviaSyntax)structure).GetMatchingDirective(cancellationToken); + if (match != null) + { + var matchSpan = match.Span; + if (!textSpan.Contains(matchSpan.Start)) + { + // The match for this pp directive is outside + // this node. + return true; + } + } + } + else if (trivia.GetStructure().IsKind(SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElifDirectiveTrivia)) + { + var directives = ((DirectiveTriviaSyntax)structure).GetMatchingConditionalDirectives(cancellationToken); + if (directives != null && directives.Count > 0) + { + if (!textSpan.Contains(directives[0].SpanStart) || + !textSpan.Contains(directives[directives.Count - 1].SpanStart)) + { + // This else/elif belongs to a pp span that isn't + // entirely within this node. + return true; + } + } + } + } + + return false; + } + + public static SyntaxNode? WithModifiers(this SyntaxNode member, SyntaxTokenList modifiers) + { + switch (member) + { + case MemberDeclarationSyntax memberDecl: return memberDecl.WithModifiers(modifiers); + case AccessorDeclarationSyntax accessor: return accessor.WithModifiers(modifiers); + } + + return null; + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs index ada41c622c485..43c69100b41ac 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions.cs @@ -184,87 +184,6 @@ public static bool IsEntirelyWithinComment(this SyntaxTree syntaxTree, int posit syntaxTree.IsEntirelyWithinSingleLineDocComment(position, cancellationToken); } - public static ImmutableArray GetFieldsAndPropertiesInSpan( - this SyntaxNode root, TextSpan textSpan, bool allowPartialSelection) - { - var token = root.FindTokenOnRightOfPosition(textSpan.Start); - var firstMember = token.GetAncestors().FirstOrDefault(); - if (firstMember != null) - { - if (firstMember.Parent is TypeDeclarationSyntax containingType) - { - return GetFieldsAndPropertiesInSpan(textSpan, containingType, firstMember, allowPartialSelection); - } - } - - return ImmutableArray.Empty; - } - - private static ImmutableArray GetFieldsAndPropertiesInSpan( - TextSpan textSpan, - TypeDeclarationSyntax containingType, - MemberDeclarationSyntax firstMember, - bool allowPartialSelection) - { - var members = containingType.Members; - var fieldIndex = members.IndexOf(firstMember); - if (fieldIndex < 0) - { - return ImmutableArray.Empty; - } - - var selectedMembers = ArrayBuilder.GetInstance(); - for (var i = fieldIndex; i < members.Count; i++) - { - var member = members[i]; - if (IsSelectedFieldOrProperty(textSpan, member, allowPartialSelection)) - { - selectedMembers.Add(member); - } - } - - return selectedMembers.ToImmutableAndFree(); - - // local functions - static bool IsSelectedFieldOrProperty(TextSpan textSpan, MemberDeclarationSyntax member, bool allowPartialSelection) - { - if (!member.IsKind(SyntaxKind.FieldDeclaration, SyntaxKind.PropertyDeclaration)) - { - return false; - } - - // first, check if entire member is selected - if (textSpan.Contains(member.Span)) - { - return true; - } - - if (!allowPartialSelection) - { - return false; - } - - // next, check if identifier is at least partially selected - switch (member) - { - case FieldDeclarationSyntax field: - var variables = field.Declaration.Variables; - foreach (var variable in variables) - { - if (textSpan.OverlapsWith(variable.Identifier.Span)) - { - return true; - } - } - return false; - case PropertyDeclarationSyntax property: - return textSpan.OverlapsWith(property.Identifier.Span); - default: - return false; - } - } - } - public static bool IsInPartiallyWrittenGeneric( this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs index 580722785bb7a..78f9aa3ee8094 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs @@ -379,5 +379,86 @@ public static bool IsCrefContext(this SyntaxTree syntaxTree, int position, Cance return false; } + + public static ImmutableArray GetFieldsAndPropertiesInSpan( + this SyntaxNode root, TextSpan textSpan, bool allowPartialSelection) + { + var token = root.FindTokenOnRightOfPosition(textSpan.Start); + var firstMember = token.GetAncestors().FirstOrDefault(); + if (firstMember != null) + { + if (firstMember.Parent is TypeDeclarationSyntax containingType) + { + return GetFieldsAndPropertiesInSpan(textSpan, containingType, firstMember, allowPartialSelection); + } + } + + return ImmutableArray.Empty; + } + + private static ImmutableArray GetFieldsAndPropertiesInSpan( + TextSpan textSpan, + TypeDeclarationSyntax containingType, + MemberDeclarationSyntax firstMember, + bool allowPartialSelection) + { + var members = containingType.Members; + var fieldIndex = members.IndexOf(firstMember); + if (fieldIndex < 0) + { + return ImmutableArray.Empty; + } + + var selectedMembers = ArrayBuilder.GetInstance(); + for (var i = fieldIndex; i < members.Count; i++) + { + var member = members[i]; + if (IsSelectedFieldOrProperty(textSpan, member, allowPartialSelection)) + { + selectedMembers.Add(member); + } + } + + return selectedMembers.ToImmutableAndFree(); + + // local functions + static bool IsSelectedFieldOrProperty(TextSpan textSpan, MemberDeclarationSyntax member, bool allowPartialSelection) + { + if (!member.IsKind(SyntaxKind.FieldDeclaration, SyntaxKind.PropertyDeclaration)) + { + return false; + } + + // first, check if entire member is selected + if (textSpan.Contains(member.Span)) + { + return true; + } + + if (!allowPartialSelection) + { + return false; + } + + // next, check if identifier is at least partially selected + switch (member) + { + case FieldDeclarationSyntax field: + var variables = field.Declaration.Variables; + foreach (var variable in variables) + { + if (textSpan.OverlapsWith(variable.Identifier.Span)) + { + return true; + } + } + return false; + case PropertyDeclarationSyntax property: + return textSpan.OverlapsWith(property.Identifier.Span); + default: + return false; + } + } + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTriviaListExtensions.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTriviaListExtensions.cs index c7e54a02161e9..fce3009bfa04c 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTriviaListExtensions.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTriviaListExtensions.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; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers.cs index 78ec5af9dec53..91b692ade41f9 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CodeGeneration { - internal static class CodeGenerationHelpers + internal static partial class CodeGenerationHelpers { public static SyntaxNode GenerateThrowStatement( SyntaxGenerator factory, @@ -99,11 +99,6 @@ members[0] is INamespaceSymbol && } } - public static bool IsSpecialType(ITypeSymbol type, SpecialType specialType) - { - return type != null && type.SpecialType == specialType; - } - public static int GetPreferredIndex(int index, IList availableIndices, bool forward) { if (availableIndices == null) diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers_Shared.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers_Shared.cs new file mode 100644 index 0000000000000..6594fe8237f85 --- /dev/null +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationHelpers_Shared.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.Editing; +using Microsoft.CodeAnalysis.Formatting; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CodeGeneration +{ + internal static partial class CodeGenerationHelpers + { + public static bool IsSpecialType(ITypeSymbol type, SpecialType specialType) + { + return type != null && type.SpecialType == specialType; + } + } +} diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index e0400f5fce346..c9dd61853d5cf 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -176,11 +176,6 @@ public static bool IsImplementableMember([NotNullWhen(returnValue: true)] this I return symbol.ContainingType; } - public static bool IsPointerType([NotNullWhen(returnValue: true)] this ISymbol? symbol) - { - return symbol is IPointerTypeSymbol; - } - public static bool IsErrorType([NotNullWhen(returnValue: true)] this ISymbol? symbol) => (symbol as ITypeSymbol)?.TypeKind == TypeKind.Error; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs index 634ebaa63251d..392719866a2f1 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs @@ -30,5 +30,10 @@ public static ImmutableArray GetParameters(this ISymbol? symbo default: return ImmutableArray.Empty; } } + + public static bool IsPointerType([NotNullWhen(returnValue: true)] this ISymbol? symbol) + { + return symbol is IPointerTypeSymbol; + } } } From 9e537c788a9eafec53f7ac4048ed422bb397812b Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 16:54:13 -0800 Subject: [PATCH 10/21] Fix --- src/CodeStyle/Core/Analyzers/Formatting/Formatter.cs | 5 +++++ .../Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj | 2 -- .../Core/Analyzers/Simplification/Simplifier.cs} | 6 +----- .../ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs | 6 +++--- src/Workspaces/Core/Portable/Simplification/Simplifier.cs | 6 ++++++ 5 files changed, 15 insertions(+), 10 deletions(-) rename src/{Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs => CodeStyle/Core/Analyzers/Simplification/Simplifier.cs} (56%) diff --git a/src/CodeStyle/Core/Analyzers/Formatting/Formatter.cs b/src/CodeStyle/Core/Analyzers/Formatting/Formatter.cs index bc62a7993cda9..d2bdc7a7db219 100644 --- a/src/CodeStyle/Core/Analyzers/Formatting/Formatter.cs +++ b/src/CodeStyle/Core/Analyzers/Formatting/Formatter.cs @@ -18,6 +18,11 @@ namespace Microsoft.CodeAnalysis.Formatting /// internal static class Formatter { + /// + /// The annotation used to mark portions of a syntax tree to be formatted. + /// + public static SyntaxAnnotation Annotation { get; } = new SyntaxAnnotation(); + /// /// Gets the formatting rules that would be applied if left unspecified. /// diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 56c64f9a1792b..38a1d8874c778 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -202,7 +202,6 @@ - @@ -243,7 +242,6 @@ - \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs b/src/CodeStyle/Core/Analyzers/Simplification/Simplifier.cs similarity index 56% rename from src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs rename to src/CodeStyle/Core/Analyzers/Simplification/Simplifier.cs index a56b41a1365fb..ed42f697723a0 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifier_Annotation.cs +++ b/src/CodeStyle/Core/Analyzers/Simplification/Simplifier.cs @@ -4,12 +4,8 @@ namespace Microsoft.CodeAnalysis.Simplification { - public static partial class Simplifier + internal class Simplifier { - /// - /// The annotation the reducer uses to identify sub trees to be reduced. - /// The Expand operations add this annotation to nodes so that the Reduce operations later find them. - /// public static SyntaxAnnotation Annotation { get; } = new SyntaxAnnotation(); } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs index 2bad36415e737..eed1260565ba3 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ITypeSymbolExtensions.TypeSyntaxGeneratorVisitor.cs @@ -290,9 +290,9 @@ public override TypeSyntax VisitNamespace(INamespaceSymbol symbol) } /// - /// We always unilaterally add "global::" to all named types/namespaces. This - /// will then be trimmed off if possible by calls to - /// + /// We always unilaterally add "global::" to all named types/namespaces. This will then + /// be trimmed off if possible by calls to the Simplifier. Note: this will only + /// simplify in the Workspace and above layers. /// private TypeSyntax AddGlobalAlias(INamespaceOrTypeSymbol symbol, SimpleNameSyntax syntax) { diff --git a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs index bf3ae044690e9..a69bb4aff53b4 100644 --- a/src/Workspaces/Core/Portable/Simplification/Simplifier.cs +++ b/src/Workspaces/Core/Portable/Simplification/Simplifier.cs @@ -37,6 +37,12 @@ namespace Microsoft.CodeAnalysis.Simplification /// public static partial class Simplifier { + /// + /// The annotation the reducer uses to identify sub trees to be reduced. + /// The Expand operations add this annotation to nodes so that the Reduce operations later find them. + /// + public static SyntaxAnnotation Annotation { get; } = new SyntaxAnnotation(); + /// /// This is the annotation used by the simplifier and expander to identify Predefined type and preserving /// them from over simplification From 4870d4723c34e86a726f9b3b0ff1abaa31099650 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 17:02:05 -0800 Subject: [PATCH 11/21] Fixes --- .../Completion/KeywordRecommenders/GroupKeywordRecommender.cs | 2 +- .../Completion/KeywordRecommenders/LetKeywordRecommender.cs | 2 +- .../Completion/KeywordRecommenders/OrderByKeywordRecommender.cs | 2 +- .../Completion/KeywordRecommenders/SelectKeywordRecommender.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs index 41a40e20001de..b50979cf1da38 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/GroupKeywordRecommender.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs index fb34d1e93ed83..517de9cd5a2ba 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/LetKeywordRecommender.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs index 1fc2366ce0383..9512988347779 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/OrderByKeywordRecommender.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs index 5f0fd2cbb721c..c44800071121f 100644 --- a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/SelectKeywordRecommender.cs @@ -3,8 +3,8 @@ // See the LICENSE file in the project root for more information. using System.Threading; -using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.Shared.Extensions; namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders { From 64bb7a7be4482e0f888ac96bdf2269139410e9f1 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 17:04:37 -0800 Subject: [PATCH 12/21] Fix --- .../VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb index 273fb6491eefd..11be949cb1841 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb @@ -212,11 +212,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return VisualBasicSyntaxFactsService.Instance.IsWord(token) End Function - - Public Function IntersectsWith(token As SyntaxToken, position As Integer) As Boolean - Return token.Span.IntersectsWith(position) - End Function - Public Function GetNextNonZeroWidthTokenOrEndOfFile(token As SyntaxToken) As SyntaxToken Dim nextToken = token.GetNextToken() From d506fb13ef34fcf3406149cb72ed25a9ad4571fd Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 17:08:54 -0800 Subject: [PATCH 13/21] Move back --- .../CSharpReplCommandCompletionProvider.cs | 1 - .../SyntaxTreeExtensions_Shared.cs | 31 ++++++++++++++++--- .../Extensions/SyntaxTreeExtensions_Shared.cs | 30 ------------------ 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/src/EditorFeatures/CSharp.Wpf/Completion/CompletionProviders/CSharpReplCommandCompletionProvider.cs b/src/EditorFeatures/CSharp.Wpf/Completion/CompletionProviders/CSharpReplCommandCompletionProvider.cs index b3cbc6b3c746a..1df5bba16ff2d 100644 --- a/src/EditorFeatures/CSharp.Wpf/Completion/CompletionProviders/CSharpReplCommandCompletionProvider.cs +++ b/src/EditorFeatures/CSharp.Wpf/Completion/CompletionProviders/CSharpReplCommandCompletionProvider.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; using System.ComponentModel.Composition; using System.Text.RegularExpressions; using System.Threading; diff --git a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs index 998fe172f717b..538f020b50a76 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.cs @@ -2,13 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Collections.Generic; -using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Shared.Extensions; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery { @@ -108,5 +104,32 @@ private static SyntaxToken FindTokenOnLeftOfNode(SyntaxNode node) { return node.FindTokenOnLeftOfPosition(node.SpanStart); } + + public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) + { + return IsPreProcessorKeywordContext( + syntaxTree, position, + syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives: true)); + } + + public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, SyntaxToken preProcessorTokenOnLeftOfPosition) + { + // cases: + // #| + // #d| + // # | + // # d| + + // note: comments are not allowed between the # and item. + var token = preProcessorTokenOnLeftOfPosition; + token = token.GetPreviousTokenIfTouchingWord(position); + + if (token.IsKind(SyntaxKind.HashToken)) + { + return true; + } + + return false; + } } } diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs index 78f9aa3ee8094..d4e7206ce6c46 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs @@ -3,12 +3,9 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -329,33 +326,6 @@ public static bool IsInInactiveRegion( return false; } - public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) - { - return IsPreProcessorKeywordContext( - syntaxTree, position, - syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives: true)); - } - - public static bool IsPreProcessorKeywordContext(this SyntaxTree syntaxTree, int position, SyntaxToken preProcessorTokenOnLeftOfPosition) - { - // cases: - // #| - // #d| - // # | - // # d| - - // note: comments are not allowed between the # and item. - var token = preProcessorTokenOnLeftOfPosition; - token = token.GetPreviousTokenIfTouchingWord(position); - - if (token.IsKind(SyntaxKind.HashToken)) - { - return true; - } - - return false; - } - public static bool IsEntirelyWithinCrefSyntax(this SyntaxTree syntaxTree, int position, CancellationToken cancellationToken) { if (syntaxTree.IsCrefContext(position, cancellationToken)) From 87cc476f9c7a9b850a7395116393a0d9a28b87e2 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 17:09:43 -0800 Subject: [PATCH 14/21] Move back --- .../CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs index d4e7206ce6c46..38032126986c0 100644 --- a/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs +++ b/src/Workspaces/CSharp/Portable/Extensions/SyntaxTreeExtensions_Shared.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Linq; using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; From 6d1ddd628950eab04ee48b16e1d68e9a0d29dd65 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 18:16:04 -0800 Subject: [PATCH 15/21] Share VB code. --- .../Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj | 4 ++++ .../LanguageServices/VisualBasicSyntaxKindsService.vb | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj index 59d8fe57142b9..03198e0f46b33 100644 --- a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj +++ b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj @@ -35,6 +35,7 @@ + @@ -71,4 +72,7 @@ + + + \ No newline at end of file diff --git a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxKindsService.vb b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxKindsService.vb index d0f7454fd4a51..3e6970114fe3b 100644 --- a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxKindsService.vb +++ b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxKindsService.vb @@ -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. -Imports System.Composition Imports Microsoft.CodeAnalysis.LanguageServices Namespace Microsoft.CodeAnalysis.VisualBasic.LanguageServices From 115863a8e50fe9d6fdb219c2c5d7fd41230c88bc Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 18:57:46 -0800 Subject: [PATCH 16/21] Share VB code. --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 2 + ....CodeAnalysis.VisualBasic.CodeStyle.vbproj | 15 + .../Extensions/INamedTypeSymbolExtensions.cs | 5 - .../INamedTypeSymbolExtensions_Shared.cs | 5 + .../Shared/Extensions/ISymbolExtensions.cs | 84 ++-- .../Extensions/ISymbolExtensions_Shared.cs | 3 + .../Extensions/ArgumentSyntaxExtensions.vb | 67 +-- .../ArgumentSyntaxExtensions_Shared.vb | 73 +++ .../ContextQuery/SyntaxTreeExtensions.vb | 19 - .../SyntaxTreeExtensions_Shared.vb | 29 ++ .../VisualBasicSyntaxContextExtensions.vb | 2 - .../Extensions/DirectiveSyntaxExtensions.vb | 5 - .../Extensions/ExpressionSyntaxExtensions.vb | 108 ++--- .../ExpressionSyntaxExtensions_Shared.vb | 72 +++ .../MemberAccessExpressionSyntaxExtensions.vb | 118 ----- ...AccessExpressionSyntaxExtensions_Shared.vb | 123 +++++ .../Extensions/StatementSyntaxExtensions.vb | 362 --------------- .../StatementSyntaxExtensions_Shared.vb | 365 +++++++++++++++ .../Extensions/SyntaxNodeExtensions.vb | 424 +---------------- .../Extensions/SyntaxNodeExtensions_Shared.vb | 436 ++++++++++++++++++ .../Extensions/SyntaxTokenExtensions.vb | 17 - ...ntaxTokenExtensions_SharedWithCodeStyle.vb | 18 + .../Extensions/SyntaxTreeExtensions.vb | 216 --------- ...yntaxTreeExtensions_SharedWithCodeStyle.vb | 218 +++++++++ 24 files changed, 1429 insertions(+), 1357 deletions(-) create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions_Shared.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions_Shared.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions_Shared.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 38a1d8874c778..79b970637eeec 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -181,9 +181,11 @@ + + diff --git a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj index 03198e0f46b33..0192f4f2c4776 100644 --- a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj +++ b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj @@ -9,6 +9,15 @@ Microsoft.CodeAnalysis.VisualBasic.CodeStyle.NewNameSinceWeReferenceTheAnalyzersAndNuGetCannotFigureItOut + + + + + + + + + @@ -35,7 +44,11 @@ + + + + @@ -73,6 +86,8 @@ + + \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs index bba08aadb5818..89b4b18a9c75a 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions.cs @@ -583,10 +583,5 @@ private static void RemoveOverriddenMembers( } } } - - public static INamedTypeSymbol TryConstruct(this INamedTypeSymbol type, ITypeSymbol[] typeArguments) - { - return typeArguments.Length > 0 ? type.Construct(typeArguments) : type; - } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs index 3b3e8e60dbb70..91144e9d5696a 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/INamedTypeSymbolExtensions_Shared.cs @@ -27,5 +27,10 @@ private static Stack GetContainmentStack(INamedTypeSymbol? sym return stack; } + + public static INamedTypeSymbol TryConstruct(this INamedTypeSymbol type, ITypeSymbol[] typeArguments) + { + return typeArguments.Length > 0 ? type.Construct(typeArguments) : type; + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index c9dd61853d5cf..43f833d283504 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -494,48 +494,6 @@ public static bool IsAttribute([NotNullWhen(returnValue: true)] this ISymbol? sy return (symbol as ITypeSymbol)?.IsAttribute() == true; } - public static ITypeSymbol ConvertToType( - this ISymbol? symbol, - Compilation compilation, - bool extensionUsedAsInstance = false) - { - if (symbol is ITypeSymbol type) - { - return type; - } - - if (symbol is IMethodSymbol method && method.Parameters.All(p => p.RefKind == RefKind.None)) - { - var count = extensionUsedAsInstance ? Math.Max(0, method.Parameters.Length - 1) : method.Parameters.Length; - var skip = extensionUsedAsInstance ? 1 : 0; - - string WithArity(string typeName, int arity) => arity > 0 ? typeName + '`' + arity : typeName; - - // Convert the symbol to Func<...> or Action<...> - var delegateType = compilation.GetTypeByMetadataName(method.ReturnsVoid - ? WithArity("System.Action", count) - : WithArity("System.Func", count + 1)); - - if (delegateType != null) - { - var types = method.Parameters - .Skip(skip) - .Select(p => (p.Type ?? compilation.GetSpecialType(SpecialType.System_Object)).WithNullableAnnotation(p.NullableAnnotation)); - - if (!method.ReturnsVoid) - { - // +1 for the return type. - types = types.Concat((method.ReturnType ?? compilation.GetSpecialType(SpecialType.System_Object)).WithNullableAnnotation(method.ReturnNullableAnnotation)); - } - - return delegateType.TryConstruct(types.ToArray()); - } - } - - // Otherwise, just default to object. - return compilation.ObjectType; - } - public static bool IsStaticType([NotNullWhen(returnValue: true)] this ISymbol? symbol) { return symbol != null && symbol.Kind == SymbolKind.NamedType && symbol.IsStatic; @@ -1393,5 +1351,47 @@ public static ImmutableArray FilterToVisibleAndBrowsableSymbolsAndNotUnsafeSy return symbols.FilterToVisibleAndBrowsableSymbols(hideAdvancedMembers, compilation) .WhereAsArray(s => !s.IsUnsafe()); } + + public static ITypeSymbol ConvertToType( + this ISymbol? symbol, + Compilation compilation, + bool extensionUsedAsInstance = false) + { + if (symbol is ITypeSymbol type) + { + return type; + } + + if (symbol is IMethodSymbol method && method.Parameters.All(p => p.RefKind == RefKind.None)) + { + var count = extensionUsedAsInstance ? Math.Max(0, method.Parameters.Length - 1) : method.Parameters.Length; + var skip = extensionUsedAsInstance ? 1 : 0; + + string WithArity(string typeName, int arity) => arity > 0 ? typeName + '`' + arity : typeName; + + // Convert the symbol to Func<...> or Action<...> + var delegateType = compilation.GetTypeByMetadataName(method.ReturnsVoid + ? WithArity("System.Action", count) + : WithArity("System.Func", count + 1)); + + if (delegateType != null) + { + var types = method.Parameters + .Skip(skip) + .Select(p => (p.Type ?? compilation.GetSpecialType(SpecialType.System_Object)).WithNullableAnnotation(p.NullableAnnotation)); + + if (!method.ReturnsVoid) + { + // +1 for the return type. + types = types.Concat((method.ReturnType ?? compilation.GetSpecialType(SpecialType.System_Object)).WithNullableAnnotation(method.ReturnNullableAnnotation)); + } + + return delegateType.TryConstruct(types.ToArray()); + } + } + + // Otherwise, just default to object. + return compilation.ObjectType; + } } } diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs index 392719866a2f1..0b583c2e4b751 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions_Shared.cs @@ -4,8 +4,11 @@ #nullable enable +using System; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Shared.Extensions { diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions.vb index 29cd23e910ca9..e409ad2d587b4 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions.vb @@ -5,14 +5,10 @@ Imports System.Runtime.CompilerServices Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions - - Friend Module ArgumentSyntaxExtensions + Partial Friend Module ArgumentSyntaxExtensions Public Function DetermineType(argument As ArgumentSyntax, semanticModel As SemanticModel, @@ -20,66 +16,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions ' If a parameter appears to have a void return type, then just use 'object' instead. Return argument.GetArgumentExpression().DetermineType(semanticModel, cancellationToken) End Function - - - Public Function DetermineParameter( - argument As ArgumentSyntax, - semanticModel As SemanticModel, - Optional allowParamArray As Boolean = False, - Optional cancellationToken As CancellationToken = Nothing - ) As IParameterSymbol - - Dim argumentList = TryCast(argument.Parent, ArgumentListSyntax) - If argumentList Is Nothing Then - Return Nothing - End If - - Dim invocableExpression = TryCast(argumentList.Parent, ExpressionSyntax) - If invocableExpression Is Nothing Then - Return Nothing - End If - - Dim symbol = semanticModel.GetSymbolInfo(invocableExpression, cancellationToken).Symbol - If symbol Is Nothing Then - Return Nothing - End If - - Dim parameters = symbol.GetParameters() - - ' Handle named argument - If argument.IsNamed Then - Dim namedArgument = DirectCast(argument, SimpleArgumentSyntax) - Dim name = namedArgument.NameColonEquals.Name.Identifier.ValueText - Return parameters.FirstOrDefault(Function(p) p.Name = name) - End If - - ' Handle positional argument - Dim index = argumentList.Arguments.IndexOf(argument) - If index < 0 Then - Return Nothing - End If - - If index < parameters.Length Then - Return parameters(index) - End If - - If allowParamArray Then - Dim lastParameter = parameters.LastOrDefault() - If lastParameter Is Nothing Then - Return Nothing - End If - - If lastParameter.IsParams Then - Return lastParameter - End If - End If - - Return Nothing - End Function - - - Public Function GetArgumentExpression(argument As ArgumentSyntax) As ExpressionSyntax - Return argument.GetExpression() - End Function End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions_Shared.vb new file mode 100644 index 0000000000000..ee0565990cba6 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ArgumentSyntaxExtensions_Shared.vb @@ -0,0 +1,73 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports System.Threading +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Friend Module ArgumentSyntaxExtensions + + Public Function DetermineParameter( + argument As ArgumentSyntax, + semanticModel As SemanticModel, + Optional allowParamArray As Boolean = False, + Optional cancellationToken As CancellationToken = Nothing + ) As IParameterSymbol + + Dim argumentList = TryCast(argument.Parent, ArgumentListSyntax) + If argumentList Is Nothing Then + Return Nothing + End If + + Dim invocableExpression = TryCast(argumentList.Parent, ExpressionSyntax) + If invocableExpression Is Nothing Then + Return Nothing + End If + + Dim symbol = semanticModel.GetSymbolInfo(invocableExpression, cancellationToken).Symbol + If symbol Is Nothing Then + Return Nothing + End If + + Dim parameters = symbol.GetParameters() + + ' Handle named argument + If argument.IsNamed Then + Dim namedArgument = DirectCast(argument, SimpleArgumentSyntax) + Dim name = namedArgument.NameColonEquals.Name.Identifier.ValueText + Return parameters.FirstOrDefault(Function(p) p.Name = name) + End If + + ' Handle positional argument + Dim index = argumentList.Arguments.IndexOf(argument) + If index < 0 Then + Return Nothing + End If + + If index < parameters.Length Then + Return parameters(index) + End If + + If allowParamArray Then + Dim lastParameter = parameters.LastOrDefault() + If lastParameter Is Nothing Then + Return Nothing + End If + + If lastParameter.IsParams Then + Return lastParameter + End If + End If + + Return Nothing + End Function + + + Public Function GetArgumentExpression(argument As ArgumentSyntax) As ExpressionSyntax + Return argument.GetExpression() + End Function + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb index 9fca6fdf8c18d..96c4d38dec609 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions.vb @@ -1054,24 +1054,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Return Nothing End If End Function - - ' Tuple literals aren't recognized by the parser until there is a comma - ' So a parenthesized expression is a possible tuple context too - - Friend Function IsPossibleTupleContext(syntaxTree As SyntaxTree, - tokenOnLeftOfPosition As SyntaxToken, - position As Integer) As Boolean - - tokenOnLeftOfPosition = tokenOnLeftOfPosition.GetPreviousTokenIfTouchingWord(position) - - If tokenOnLeftOfPosition.IsKind(SyntaxKind.OpenParenToken) Then - Return tokenOnLeftOfPosition.Parent.IsKind(SyntaxKind.ParenthesizedExpression, - SyntaxKind.TupleExpression, SyntaxKind.TupleType) - End If - - Return tokenOnLeftOfPosition.IsKind(SyntaxKind.CommaToken) AndAlso - tokenOnLeftOfPosition.Parent.IsKind(SyntaxKind.TupleExpression, SyntaxKind.TupleType) - End Function - End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.vb new file mode 100644 index 0000000000000..5e952fa70df36 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/SyntaxTreeExtensions_Shared.vb @@ -0,0 +1,29 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports System.Threading + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery + Partial Friend Module SyntaxTreeExtensions + ' Tuple literals aren't recognized by the parser until there is a comma + ' So a parenthesized expression is a possible tuple context too + + Friend Function IsPossibleTupleContext(syntaxTree As SyntaxTree, + tokenOnLeftOfPosition As SyntaxToken, + position As Integer) As Boolean + + tokenOnLeftOfPosition = tokenOnLeftOfPosition.GetPreviousTokenIfTouchingWord(position) + + If tokenOnLeftOfPosition.IsKind(SyntaxKind.OpenParenToken) Then + Return tokenOnLeftOfPosition.Parent.IsKind(SyntaxKind.ParenthesizedExpression, + SyntaxKind.TupleExpression, SyntaxKind.TupleType) + End If + + Return tokenOnLeftOfPosition.IsKind(SyntaxKind.CommaToken) AndAlso + tokenOnLeftOfPosition.Parent.IsKind(SyntaxKind.TupleExpression, SyntaxKind.TupleType) + End Function + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContextExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContextExtensions.vb index 3e576edb0837e..fd3e5e0dc90de 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContextExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ContextQuery/VisualBasicSyntaxContextExtensions.vb @@ -4,8 +4,6 @@ Imports System.Runtime.CompilerServices Imports System.Threading -Imports Microsoft.CodeAnalysis.Shared.Extensions -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/DirectiveSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/DirectiveSyntaxExtensions.vb index e103f1388821d..64c1818e94101 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/DirectiveSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/DirectiveSyntaxExtensions.vb @@ -3,12 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Runtime.CompilerServices -Imports System.Runtime.InteropServices Imports System.Threading -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb index ace041bdc6f1b..31a49d00d56fd 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb @@ -30,39 +30,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions miscellaneousOptions:=SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers, typeQualificationStyle:=SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces) - - Public Function WalkUpParentheses(expression As ExpressionSyntax) As ExpressionSyntax - While expression.IsParentKind(SyntaxKind.ParenthesizedExpression) - expression = DirectCast(expression.Parent, ExpressionSyntax) - End While - - Return expression - End Function - - - Public Function WalkDownParentheses(expression As ExpressionSyntax) As ExpressionSyntax - While expression.IsKind(SyntaxKind.ParenthesizedExpression) - expression = DirectCast(expression, ParenthesizedExpressionSyntax).Expression - End While - - Return expression - End Function - - - Public Function Parenthesize(expression As ExpressionSyntax, Optional addSimplifierAnnotation As Boolean = True) As ParenthesizedExpressionSyntax - Dim result = SyntaxFactory.ParenthesizedExpression(expression.WithoutTrivia()) _ - .WithTriviaFrom(expression) - Return If(addSimplifierAnnotation, - result.WithAdditionalAnnotations(Simplifier.Annotation), - result) - End Function - - - Public Function IsMemberAccessExpressionName(expression As ExpressionSyntax) As Boolean - Return expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso - DirectCast(expression.Parent, MemberAccessExpressionSyntax).Name Is expression - End Function - Public Function IsAnyMemberAccessExpressionName(expression As ExpressionSyntax) As Boolean Return expression IsNot Nothing AndAlso @@ -80,18 +47,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return expression.IsMemberAccessExpressionName() OrElse expression.IsRightSideOfQualifiedName() End Function - - Public Function IsRightSideOfQualifiedName(expression As ExpressionSyntax) As Boolean - Return expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso - DirectCast(expression.Parent, QualifiedNameSyntax).Right Is expression - End Function - - - Public Function IsLeftSideOfQualifiedName(expression As ExpressionSyntax) As Boolean - Return expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso - DirectCast(expression.Parent, QualifiedNameSyntax).Left Is expression - End Function - Public Function IsAnyLiteralExpression(expression As ExpressionSyntax) As Boolean Return expression.IsKind(SyntaxKind.CharacterLiteralExpression) OrElse @@ -184,17 +139,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return True End Function - - Public Function IsLeftSideOfDot(expression As ExpressionSyntax) As Boolean - If expression Is Nothing Then - Return False - End If - - Return _ - (expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso DirectCast(expression.Parent, QualifiedNameSyntax).Left Is expression) OrElse - (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso DirectCast(expression.Parent, MemberAccessExpressionSyntax).Expression Is expression) - End Function - Public Function Cast( expression As ExpressionSyntax, @@ -725,32 +669,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions End Select End Function - - Public Function DetermineType(expression As ExpressionSyntax, - semanticModel As SemanticModel, - cancellationToken As CancellationToken) As ITypeSymbol - ' If a parameter appears to have a void return type, then just use 'object' instead. - If expression IsNot Nothing Then - Dim typeInfo = semanticModel.GetTypeInfo(expression, cancellationToken) - Dim symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken) - If typeInfo.Type IsNot Nothing AndAlso typeInfo.Type.SpecialType = SpecialType.System_Void Then - Return semanticModel.Compilation.ObjectType - End If - - Dim symbol = If(typeInfo.Type, symbolInfo.GetAnySymbol()) - If symbol IsNot Nothing Then - Return symbol.ConvertToType(semanticModel.Compilation) - End If - - If TypeOf expression Is CollectionInitializerSyntax Then - Dim collectionInitializer = DirectCast(expression, CollectionInitializerSyntax) - Return DetermineType(collectionInitializer, semanticModel, cancellationToken) - End If - End If - - Return semanticModel.Compilation.ObjectType - End Function - Private Function DetermineType(collectionInitializer As CollectionInitializerSyntax, semanticModel As SemanticModel, @@ -832,5 +750,31 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return False End Function + + + Public Function DetermineType(expression As ExpressionSyntax, + semanticModel As SemanticModel, + cancellationToken As CancellationToken) As ITypeSymbol + ' If a parameter appears to have a void return type, then just use 'object' instead. + If expression IsNot Nothing Then + Dim typeInfo = semanticModel.GetTypeInfo(expression, cancellationToken) + Dim symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken) + If typeInfo.Type IsNot Nothing AndAlso typeInfo.Type.SpecialType = SpecialType.System_Void Then + Return semanticModel.Compilation.ObjectType + End If + + Dim symbol = If(typeInfo.Type, symbolInfo.GetAnySymbol()) + If symbol IsNot Nothing Then + Return symbol.ConvertToType(semanticModel.Compilation) + End If + + If TypeOf expression Is CollectionInitializerSyntax Then + Dim collectionInitializer = DirectCast(expression, CollectionInitializerSyntax) + Return DetermineType(collectionInitializer, semanticModel, cancellationToken) + End If + End If + + Return semanticModel.Compilation.ObjectType + End Function End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb new file mode 100644 index 0000000000000..0c77ed5fb103d --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb @@ -0,0 +1,72 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports System.Runtime.InteropServices +Imports System.Threading +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Partial Friend Module ExpressionSyntaxExtensions + + Public Function IsRightSideOfQualifiedName(expression As ExpressionSyntax) As Boolean + Return expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso + DirectCast(expression.Parent, QualifiedNameSyntax).Right Is expression + End Function + + + Public Function IsLeftSideOfQualifiedName(expression As ExpressionSyntax) As Boolean + Return expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso + DirectCast(expression.Parent, QualifiedNameSyntax).Left Is expression + End Function + + + Public Function IsMemberAccessExpressionName(expression As ExpressionSyntax) As Boolean + Return expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso + DirectCast(expression.Parent, MemberAccessExpressionSyntax).Name Is expression + End Function + + + Public Function WalkUpParentheses(expression As ExpressionSyntax) As ExpressionSyntax + While expression.IsParentKind(SyntaxKind.ParenthesizedExpression) + expression = DirectCast(expression.Parent, ExpressionSyntax) + End While + + Return expression + End Function + + + Public Function WalkDownParentheses(expression As ExpressionSyntax) As ExpressionSyntax + While expression.IsKind(SyntaxKind.ParenthesizedExpression) + expression = DirectCast(expression, ParenthesizedExpressionSyntax).Expression + End While + + Return expression + End Function + + + Public Function Parenthesize(expression As ExpressionSyntax, Optional addSimplifierAnnotation As Boolean = True) As ParenthesizedExpressionSyntax + Dim result = SyntaxFactory.ParenthesizedExpression(expression.WithoutTrivia()) _ + .WithTriviaFrom(expression) + Return If(addSimplifierAnnotation, + result.WithAdditionalAnnotations(Simplifier.Annotation), + result) + End Function + + + Public Function IsLeftSideOfDot(expression As ExpressionSyntax) As Boolean + If expression Is Nothing Then + Return False + End If + + Return _ + (expression.IsParentKind(SyntaxKind.QualifiedName) AndAlso DirectCast(expression.Parent, QualifiedNameSyntax).Left Is expression) OrElse + (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso DirectCast(expression.Parent, MemberAccessExpressionSyntax).Expression Is expression) + End Function + + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions.vb index 2b351653f27cc..9360f33793598 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions.vb @@ -2,131 +2,13 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System -Imports System.Collections.Generic -Imports System.Linq Imports System.Runtime.CompilerServices -Imports System.Text Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Simplification -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Friend Module MemberAccessExpressionSyntaxExtensions - - Public Function IsConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean - Return memberAccess.IsThisConstructorInitializer() OrElse memberAccess.IsBaseConstructorInitializer() - End Function - - - Public Function IsThisConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean - If memberAccess IsNot Nothing Then - If IsFirstStatementInConstructor(memberAccess) Then - If memberAccess.Expression.IsKind(SyntaxKind.MeExpression) OrElse - memberAccess.Expression.IsKind(SyntaxKind.MyClassExpression) Then - If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then - Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword) - End If - End If - End If - End If - - Return False - End Function - - - Public Function IsBaseConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean - If memberAccess IsNot Nothing Then - If IsFirstStatementInConstructor(memberAccess) Then - If memberAccess.Expression.IsKind(SyntaxKind.MyBaseExpression) Then - If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then - Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword) - End If - End If - End If - End If - - Return False - End Function - - Private Function IsFirstStatementInConstructor(memberAccess As MemberAccessExpressionSyntax) As Boolean - Dim isCall As Boolean - Dim statement As SyntaxNode - If TypeOf memberAccess.Parent Is InvocationExpressionSyntax Then - statement = memberAccess.Parent.Parent - isCall = statement IsNot Nothing AndAlso (statement.Kind = SyntaxKind.CallStatement OrElse statement.Kind = SyntaxKind.ExpressionStatement) - Else - statement = memberAccess.Parent - isCall = statement.IsKind(SyntaxKind.CallStatement) - End If - - If isCall Then - Return statement.IsParentKind(SyntaxKind.ConstructorBlock) AndAlso - DirectCast(statement.Parent, ConstructorBlockSyntax).Statements.First() Is statement - End If - - Return False - End Function - - - Public Function GetExpressionOfMemberAccessExpression( - memberAccessExpression As MemberAccessExpressionSyntax, - Optional allowImplicitTarget As Boolean = False) As ExpressionSyntax - If memberAccessExpression Is Nothing Then - Return Nothing - End If - - If memberAccessExpression.Expression IsNot Nothing Then - Return memberAccessExpression.Expression - End If - - ' we have a member access expression with a null expression, this may be one of the - ' following forms: - ' - ' 1) new With { .a = 1, .b = .a <-- .a refers to the anonymous type - ' 2) With obj : .m <-- .m refers to the obj type - ' 3) new T() With { .a = 1, .b = .a <-- 'a refers to the T type - - If allowImplicitTarget Then - Dim conditional = memberAccessExpression.GetCorrespondingConditionalAccessExpression() - If conditional IsNot Nothing Then - If conditional.Expression Is Nothing Then - - ' No expression, maybe we're in a with block - Dim withBlock = conditional.GetAncestor(Of WithBlockSyntax)() - If withBlock IsNot Nothing Then - Return withBlock.WithStatement.Expression - End If - End If - - Return conditional.Expression - End If - - Dim current As SyntaxNode = memberAccessExpression - - While current IsNot Nothing - If TypeOf current Is AnonymousObjectCreationExpressionSyntax Then - Return DirectCast(current, ExpressionSyntax) - ElseIf TypeOf current Is WithBlockSyntax Then - Dim withBlock = DirectCast(current, WithBlockSyntax) - If memberAccessExpression IsNot withBlock.WithStatement.Expression Then - Return withBlock.WithStatement.Expression - End If - ElseIf TypeOf current Is ObjectMemberInitializerSyntax AndAlso - TypeOf current.Parent Is ObjectCreationExpressionSyntax Then - Return DirectCast(current.Parent, ExpressionSyntax) - End If - - current = current.Parent - End While - End If - - Return Nothing - End Function - Public Function GetNameWithTriviaMoved(memberAccess As MemberAccessExpressionSyntax, semanticModel As SemanticModel) As SimpleNameSyntax diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions_Shared.vb new file mode 100644 index 0000000000000..9f791d858a4a0 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/MemberAccessExpressionSyntaxExtensions_Shared.vb @@ -0,0 +1,123 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Partial Friend Module MemberAccessExpressionSyntaxExtensions + + Public Function IsConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean + Return memberAccess.IsThisConstructorInitializer() OrElse memberAccess.IsBaseConstructorInitializer() + End Function + + + Public Function IsThisConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean + If memberAccess IsNot Nothing Then + If IsFirstStatementInConstructor(memberAccess) Then + If memberAccess.Expression.IsKind(SyntaxKind.MeExpression) OrElse + memberAccess.Expression.IsKind(SyntaxKind.MyClassExpression) Then + If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then + Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword) + End If + End If + End If + End If + + Return False + End Function + + + Public Function IsBaseConstructorInitializer(memberAccess As MemberAccessExpressionSyntax) As Boolean + If memberAccess IsNot Nothing Then + If IsFirstStatementInConstructor(memberAccess) Then + If memberAccess.Expression.IsKind(SyntaxKind.MyBaseExpression) Then + If memberAccess.Name.IsKind(SyntaxKind.IdentifierName) Then + Return memberAccess.Name.Identifier.HasMatchingText(SyntaxKind.NewKeyword) + End If + End If + End If + End If + + Return False + End Function + + + Public Function GetExpressionOfMemberAccessExpression( + memberAccessExpression As MemberAccessExpressionSyntax, + Optional allowImplicitTarget As Boolean = False) As ExpressionSyntax + If memberAccessExpression Is Nothing Then + Return Nothing + End If + + If memberAccessExpression.Expression IsNot Nothing Then + Return memberAccessExpression.Expression + End If + + ' we have a member access expression with a null expression, this may be one of the + ' following forms: + ' + ' 1) new With { .a = 1, .b = .a <-- .a refers to the anonymous type + ' 2) With obj : .m <-- .m refers to the obj type + ' 3) new T() With { .a = 1, .b = .a <-- 'a refers to the T type + + If allowImplicitTarget Then + Dim conditional = memberAccessExpression.GetCorrespondingConditionalAccessExpression() + If conditional IsNot Nothing Then + If conditional.Expression Is Nothing Then + + ' No expression, maybe we're in a with block + Dim withBlock = conditional.GetAncestor(Of WithBlockSyntax)() + If withBlock IsNot Nothing Then + Return withBlock.WithStatement.Expression + End If + End If + + Return conditional.Expression + End If + + Dim current As SyntaxNode = memberAccessExpression + + While current IsNot Nothing + If TypeOf current Is AnonymousObjectCreationExpressionSyntax Then + Return DirectCast(current, ExpressionSyntax) + ElseIf TypeOf current Is WithBlockSyntax Then + Dim withBlock = DirectCast(current, WithBlockSyntax) + If memberAccessExpression IsNot withBlock.WithStatement.Expression Then + Return withBlock.WithStatement.Expression + End If + ElseIf TypeOf current Is ObjectMemberInitializerSyntax AndAlso + TypeOf current.Parent Is ObjectCreationExpressionSyntax Then + Return DirectCast(current.Parent, ExpressionSyntax) + End If + + current = current.Parent + End While + End If + + Return Nothing + End Function + + Private Function IsFirstStatementInConstructor(memberAccess As MemberAccessExpressionSyntax) As Boolean + Dim isCall As Boolean + Dim statement As SyntaxNode + If TypeOf memberAccess.Parent Is InvocationExpressionSyntax Then + statement = memberAccess.Parent.Parent + isCall = statement IsNot Nothing AndAlso (statement.Kind = SyntaxKind.CallStatement OrElse statement.Kind = SyntaxKind.ExpressionStatement) + Else + statement = memberAccess.Parent + isCall = statement.IsKind(SyntaxKind.CallStatement) + End If + + If isCall Then + Return statement.IsParentKind(SyntaxKind.ConstructorBlock) AndAlso + DirectCast(statement.Parent, ConstructorBlockSyntax).Statements.First() Is statement + End If + + Return False + End Function + + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions.vb index 91f90f88e8859..d36b8b07cc74b 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions.vb @@ -3,17 +3,10 @@ ' See the LICENSE file in the project root for more information. Imports System.Runtime.CompilerServices -Imports System.Threading -Imports Microsoft.CodeAnalysis.Simplification -Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic -Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions - Friend Module StatementSyntaxExtensions - Public Function GetAttributes(member As StatementSyntax) As SyntaxList(Of AttributeListSyntax) If member IsNot Nothing Then @@ -159,351 +152,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return member.WithAttributeLists(member.GetAttributes().AddRange(attributeLists)) End Function - - Public Function GetModifiers(member As SyntaxNode) As SyntaxTokenList - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.ClassBlock, - SyntaxKind.InterfaceBlock, - SyntaxKind.ModuleBlock, - SyntaxKind.StructureBlock - Return DirectCast(member, TypeBlockSyntax).BlockStatement.Modifiers - Case SyntaxKind.EnumBlock - Return DirectCast(member, EnumBlockSyntax).EnumStatement.Modifiers - Case SyntaxKind.ClassStatement, - SyntaxKind.InterfaceStatement, - SyntaxKind.ModuleStatement, - SyntaxKind.StructureStatement - Return DirectCast(member, TypeStatementSyntax).Modifiers - Case SyntaxKind.EnumStatement - Return DirectCast(member, EnumStatementSyntax).Modifiers - Case SyntaxKind.FieldDeclaration - Return DirectCast(member, FieldDeclarationSyntax).Modifiers - Case SyntaxKind.EventBlock - Return DirectCast(member, EventBlockSyntax).EventStatement.Modifiers - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).Modifiers - Case SyntaxKind.PropertyBlock - Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.Modifiers - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).Modifiers - Case SyntaxKind.FunctionBlock, - SyntaxKind.SubBlock, - SyntaxKind.ConstructorBlock, - SyntaxKind.OperatorBlock, - SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock - Return DirectCast(member, MethodBlockBaseSyntax).BlockStatement.Modifiers - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement, - SyntaxKind.SubNewStatement, - SyntaxKind.OperatorStatement, - SyntaxKind.GetAccessorStatement, - SyntaxKind.SetAccessorStatement, - SyntaxKind.AddHandlerAccessorStatement, - SyntaxKind.RemoveHandlerAccessorStatement, - SyntaxKind.RaiseEventAccessorStatement, - SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement, - SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, MethodBaseSyntax).Modifiers - End Select - End If - - Return Nothing - End Function - - - Public Function WithModifiers(Of TNode As SyntaxNode)(member As TNode, modifiers As SyntaxTokenList) As TNode - Return DirectCast(WithModifiersHelper(member, modifiers), TNode) - End Function - - Private Function WithModifiersHelper(member As SyntaxNode, modifiers As SyntaxTokenList) As SyntaxNode - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.ClassBlock - Dim classBlock = DirectCast(member, ClassBlockSyntax) - Return classBlock.WithClassStatement(classBlock.ClassStatement.WithModifiers(modifiers)) - Case SyntaxKind.InterfaceBlock - Dim interfaceBlock = DirectCast(member, InterfaceBlockSyntax) - Return interfaceBlock.WithInterfaceStatement(interfaceBlock.InterfaceStatement.WithModifiers(modifiers)) - Case SyntaxKind.ModuleBlock - Dim moduleBlock = DirectCast(member, ModuleBlockSyntax) - Return moduleBlock.WithModuleStatement(moduleBlock.ModuleStatement.WithModifiers(modifiers)) - Case SyntaxKind.StructureBlock - Dim structureBlock = DirectCast(member, StructureBlockSyntax) - Return structureBlock.WithStructureStatement(structureBlock.StructureStatement.WithModifiers(modifiers)) - Case SyntaxKind.EnumBlock - Dim enumBlock = DirectCast(member, EnumBlockSyntax) - Return enumBlock.WithEnumStatement(enumBlock.EnumStatement.WithModifiers(modifiers)) - Case SyntaxKind.ClassStatement - Return DirectCast(member, ClassStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.InterfaceStatement - Return DirectCast(member, InterfaceStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.ModuleStatement - Return DirectCast(member, ModuleStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.StructureStatement - Return DirectCast(member, StructureStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.EnumStatement - Return DirectCast(member, EnumStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.FieldDeclaration - Return DirectCast(member, FieldDeclarationSyntax).WithModifiers(modifiers) - Case SyntaxKind.EventBlock - Dim eventBlock = DirectCast(member, EventBlockSyntax) - Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithModifiers(modifiers)) - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.PropertyBlock - Dim propertyBlock = DirectCast(member, PropertyBlockSyntax) - Return propertyBlock.WithPropertyStatement(propertyBlock.PropertyStatement.WithModifiers(modifiers)) - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.FunctionBlock, - SyntaxKind.SubBlock - Dim methodBlock = DirectCast(member, MethodBlockSyntax) - Return methodBlock.WithSubOrFunctionStatement(DirectCast(methodBlock.SubOrFunctionStatement.WithModifiers(modifiers), MethodStatementSyntax)) - Case SyntaxKind.ConstructorBlock - Dim methodBlock = DirectCast(member, ConstructorBlockSyntax) - Return methodBlock.WithSubNewStatement(DirectCast(methodBlock.SubNewStatement.WithModifiers(modifiers), SubNewStatementSyntax)) - Case SyntaxKind.OperatorBlock - Dim methodBlock = DirectCast(member, OperatorBlockSyntax) - Return methodBlock.WithOperatorStatement(DirectCast(methodBlock.OperatorStatement.WithModifiers(modifiers), OperatorStatementSyntax)) - Case SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock - Dim methodBlock = DirectCast(member, AccessorBlockSyntax) - Return methodBlock.WithAccessorStatement(DirectCast(methodBlock.AccessorStatement.WithModifiers(modifiers), AccessorStatementSyntax)) - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - Return DirectCast(member, MethodStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.SubNewStatement - Return DirectCast(member, SubNewStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.OperatorStatement - Return DirectCast(member, OperatorStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.GetAccessorStatement, - SyntaxKind.SetAccessorStatement, - SyntaxKind.AddHandlerAccessorStatement, - SyntaxKind.RemoveHandlerAccessorStatement, - SyntaxKind.RaiseEventAccessorStatement - Return DirectCast(member, AccessorStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement - Return DirectCast(member, DeclareStatementSyntax).WithModifiers(modifiers) - Case SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, DelegateStatementSyntax).WithModifiers(modifiers) - End Select - End If - - Return Nothing - End Function - - - Public Function GetNameToken(member As StatementSyntax) As SyntaxToken - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.ClassBlock, - SyntaxKind.InterfaceBlock, - SyntaxKind.ModuleBlock, - SyntaxKind.StructureBlock - Return DirectCast(member, TypeBlockSyntax).BlockStatement.Identifier - Case SyntaxKind.EnumBlock - Return DirectCast(member, EnumBlockSyntax).EnumStatement.Identifier - Case SyntaxKind.ClassStatement, - SyntaxKind.InterfaceStatement, - SyntaxKind.ModuleStatement, - SyntaxKind.StructureStatement - Return DirectCast(member, TypeStatementSyntax).Identifier - Case SyntaxKind.EnumStatement - Return DirectCast(member, EnumStatementSyntax).Identifier - Case SyntaxKind.FieldDeclaration - Return DirectCast(member, FieldDeclarationSyntax).Declarators.First().Names.First().Identifier - Case SyntaxKind.EventBlock - Return DirectCast(member, EventBlockSyntax).EventStatement.Identifier - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).Identifier - Case SyntaxKind.PropertyBlock - Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.Identifier - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).Identifier - Case SyntaxKind.FunctionBlock, - SyntaxKind.SubBlock - Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).Identifier - Case SyntaxKind.ConstructorBlock - Return DirectCast(DirectCast(member, ConstructorBlockSyntax).BlockStatement, SubNewStatementSyntax).NewKeyword - Case SyntaxKind.OperatorBlock - Return DirectCast(DirectCast(member, OperatorBlockSyntax).BlockStatement, OperatorStatementSyntax).OperatorToken - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - Return DirectCast(member, MethodStatementSyntax).Identifier - Case SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement - Return DirectCast(member, DeclareStatementSyntax).Identifier - Case SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, DelegateStatementSyntax).Identifier - End Select - End If - - Return Nothing - End Function - - - Public Function GetMemberKeywordToken(member As DeclarationStatementSyntax) As SyntaxToken - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.ConstructorBlock - Return DirectCast(DirectCast(member, ConstructorBlockSyntax).BlockStatement, SubNewStatementSyntax).SubKeyword - Case SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement - Return DirectCast(member, DeclareStatementSyntax).DeclarationKeyword - Case SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, DelegateStatementSyntax).DeclarationKeyword - Case SyntaxKind.EventBlock - Return DirectCast(member, EventBlockSyntax).EventStatement.EventKeyword - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).EventKeyword - Case SyntaxKind.FunctionBlock, - SyntaxKind.SubBlock - Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).DeclarationKeyword - Case SyntaxKind.FunctionStatement, - SyntaxKind.SubStatement - Return DirectCast(member, MethodStatementSyntax).DeclarationKeyword - Case SyntaxKind.OperatorBlock - Return DirectCast(DirectCast(member, OperatorBlockSyntax).BlockStatement, OperatorStatementSyntax).OperatorKeyword - Case SyntaxKind.PropertyBlock - Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.PropertyKeyword - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).PropertyKeyword - End Select - End If - - Return Nothing - End Function - Public Function GetArity(member As StatementSyntax) As Integer Dim list = GetTypeParameterList(member) Return If(list Is Nothing, 0, list.Parameters.Count) End Function - - Public Function GetTypeParameterList(member As StatementSyntax) As TypeParameterListSyntax - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.ClassBlock, - SyntaxKind.InterfaceBlock, - SyntaxKind.StructureBlock - Return DirectCast(member, TypeBlockSyntax).BlockStatement.TypeParameterList - Case SyntaxKind.ClassStatement, - SyntaxKind.InterfaceStatement, - SyntaxKind.StructureStatement - Return DirectCast(member, TypeStatementSyntax).TypeParameterList - Case SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, DelegateStatementSyntax).TypeParameterList - Case SyntaxKind.SubBlock, - SyntaxKind.FunctionBlock - Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).TypeParameterList - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - Return DirectCast(member, MethodStatementSyntax).TypeParameterList - End Select - End If - - Return Nothing - End Function - - - Public Function GetParameterList(member As StatementSyntax) As ParameterListSyntax - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.SubBlock, - SyntaxKind.FunctionBlock, - SyntaxKind.ConstructorBlock, - SyntaxKind.OperatorBlock, - SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock - Return DirectCast(member, MethodBlockBaseSyntax).BlockStatement.ParameterList - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement, - SyntaxKind.SubNewStatement, - SyntaxKind.OperatorStatement, - SyntaxKind.GetAccessorStatement, - SyntaxKind.SetAccessorStatement, - SyntaxKind.AddHandlerAccessorStatement, - SyntaxKind.RemoveHandlerAccessorStatement, - SyntaxKind.RaiseEventAccessorStatement, - SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement, - SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, MethodBaseSyntax).ParameterList - Case SyntaxKind.PropertyBlock - Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.ParameterList - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).ParameterList - Case SyntaxKind.EventBlock - Return DirectCast(member, EventBlockSyntax).EventStatement.ParameterList - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).ParameterList - End Select - End If - - Return Nothing - End Function - - - Public Function GetAsClause(member As StatementSyntax) As AsClauseSyntax - If member IsNot Nothing Then - Select Case member.Kind - Case SyntaxKind.FunctionBlock - Return DirectCast(member, MethodBlockSyntax).SubOrFunctionStatement.AsClause - Case SyntaxKind.OperatorBlock - Return DirectCast(member, OperatorBlockSyntax).OperatorStatement.AsClause - Case SyntaxKind.FunctionStatement - Return DirectCast(member, MethodStatementSyntax).AsClause - Case SyntaxKind.OperatorStatement - Return DirectCast(member, OperatorStatementSyntax).AsClause - Case SyntaxKind.DeclareFunctionStatement - Return DirectCast(member, DeclareStatementSyntax).AsClause - Case SyntaxKind.DelegateFunctionStatement - Return DirectCast(member, DelegateStatementSyntax).AsClause - Case SyntaxKind.PropertyBlock - Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.AsClause - Case SyntaxKind.PropertyStatement - Return DirectCast(member, PropertyStatementSyntax).AsClause - Case SyntaxKind.EventBlock - Return DirectCast(member, EventBlockSyntax).EventStatement.AsClause - Case SyntaxKind.EventStatement - Return DirectCast(member, EventStatementSyntax).AsClause - End Select - End If - - Return Nothing - End Function - - - Public Function GetReturnType(member As StatementSyntax) As TypeSyntax - Dim asClause = member.GetAsClause() - Return If(asClause IsNot Nothing, asClause.Type, Nothing) - End Function - - - Public Function HasReturnType(member As StatementSyntax) As Boolean - Return member.GetReturnType() IsNot Nothing - End Function - Public Function IsTopLevelDeclaration(statement As StatementSyntax) As Boolean If statement Is Nothing Then @@ -708,21 +362,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return Nothing End Function - - Public Function GetNextStatement(statement As StatementSyntax) As StatementSyntax - If statement IsNot Nothing Then - ' In VB a statement can be followed by another statement in one of two ways. It can - ' follow on the same line (in which case there will be a statement terminator - ' token), or it can be on the same line with a colon between the two of them. - Dim nextToken = statement.GetLastToken().GetNextToken() - - Dim outerStatement = statement.GetAncestors(Of StatementSyntax)().Where(Function(s) s.SpanStart <> statement.SpanStart).FirstOrDefault() - Return nextToken.GetAncestors(Of StatementSyntax)().FirstOrDefault(Function(s) s.GetAncestors(Of StatementSyntax)().Contains(outerStatement)) - End If - - Return Nothing - End Function - Public Function GetNextNonEmptyStatement(statement As StatementSyntax) As StatementSyntax If statement IsNot Nothing Then @@ -770,6 +409,5 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return False End Function - End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions_Shared.vb new file mode 100644 index 0000000000000..1f543be523002 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/StatementSyntaxExtensions_Shared.vb @@ -0,0 +1,365 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Partial Friend Module StatementSyntaxExtensions + + Public Function GetMemberKeywordToken(member As DeclarationStatementSyntax) As SyntaxToken + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.ConstructorBlock + Return DirectCast(DirectCast(member, ConstructorBlockSyntax).BlockStatement, SubNewStatementSyntax).SubKeyword + Case SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement + Return DirectCast(member, DeclareStatementSyntax).DeclarationKeyword + Case SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, DelegateStatementSyntax).DeclarationKeyword + Case SyntaxKind.EventBlock + Return DirectCast(member, EventBlockSyntax).EventStatement.EventKeyword + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).EventKeyword + Case SyntaxKind.FunctionBlock, + SyntaxKind.SubBlock + Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).DeclarationKeyword + Case SyntaxKind.FunctionStatement, + SyntaxKind.SubStatement + Return DirectCast(member, MethodStatementSyntax).DeclarationKeyword + Case SyntaxKind.OperatorBlock + Return DirectCast(DirectCast(member, OperatorBlockSyntax).BlockStatement, OperatorStatementSyntax).OperatorKeyword + Case SyntaxKind.PropertyBlock + Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.PropertyKeyword + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).PropertyKeyword + End Select + End If + + Return Nothing + End Function + + + Public Function GetParameterList(member As StatementSyntax) As ParameterListSyntax + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.SubBlock, + SyntaxKind.FunctionBlock, + SyntaxKind.ConstructorBlock, + SyntaxKind.OperatorBlock, + SyntaxKind.GetAccessorBlock, + SyntaxKind.SetAccessorBlock, + SyntaxKind.AddHandlerAccessorBlock, + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxKind.RaiseEventAccessorBlock + Return DirectCast(member, MethodBlockBaseSyntax).BlockStatement.ParameterList + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement, + SyntaxKind.SubNewStatement, + SyntaxKind.OperatorStatement, + SyntaxKind.GetAccessorStatement, + SyntaxKind.SetAccessorStatement, + SyntaxKind.AddHandlerAccessorStatement, + SyntaxKind.RemoveHandlerAccessorStatement, + SyntaxKind.RaiseEventAccessorStatement, + SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement, + SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, MethodBaseSyntax).ParameterList + Case SyntaxKind.PropertyBlock + Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.ParameterList + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).ParameterList + Case SyntaxKind.EventBlock + Return DirectCast(member, EventBlockSyntax).EventStatement.ParameterList + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).ParameterList + End Select + End If + + Return Nothing + End Function + + + Public Function GetAsClause(member As StatementSyntax) As AsClauseSyntax + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.FunctionBlock + Return DirectCast(member, MethodBlockSyntax).SubOrFunctionStatement.AsClause + Case SyntaxKind.OperatorBlock + Return DirectCast(member, OperatorBlockSyntax).OperatorStatement.AsClause + Case SyntaxKind.FunctionStatement + Return DirectCast(member, MethodStatementSyntax).AsClause + Case SyntaxKind.OperatorStatement + Return DirectCast(member, OperatorStatementSyntax).AsClause + Case SyntaxKind.DeclareFunctionStatement + Return DirectCast(member, DeclareStatementSyntax).AsClause + Case SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, DelegateStatementSyntax).AsClause + Case SyntaxKind.PropertyBlock + Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.AsClause + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).AsClause + Case SyntaxKind.EventBlock + Return DirectCast(member, EventBlockSyntax).EventStatement.AsClause + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).AsClause + End Select + End If + + Return Nothing + End Function + + + Public Function GetNameToken(member As StatementSyntax) As SyntaxToken + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.ClassBlock, + SyntaxKind.InterfaceBlock, + SyntaxKind.ModuleBlock, + SyntaxKind.StructureBlock + Return DirectCast(member, TypeBlockSyntax).BlockStatement.Identifier + Case SyntaxKind.EnumBlock + Return DirectCast(member, EnumBlockSyntax).EnumStatement.Identifier + Case SyntaxKind.ClassStatement, + SyntaxKind.InterfaceStatement, + SyntaxKind.ModuleStatement, + SyntaxKind.StructureStatement + Return DirectCast(member, TypeStatementSyntax).Identifier + Case SyntaxKind.EnumStatement + Return DirectCast(member, EnumStatementSyntax).Identifier + Case SyntaxKind.FieldDeclaration + Return DirectCast(member, FieldDeclarationSyntax).Declarators.First().Names.First().Identifier + Case SyntaxKind.EventBlock + Return DirectCast(member, EventBlockSyntax).EventStatement.Identifier + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).Identifier + Case SyntaxKind.PropertyBlock + Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.Identifier + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).Identifier + Case SyntaxKind.FunctionBlock, + SyntaxKind.SubBlock + Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).Identifier + Case SyntaxKind.ConstructorBlock + Return DirectCast(DirectCast(member, ConstructorBlockSyntax).BlockStatement, SubNewStatementSyntax).NewKeyword + Case SyntaxKind.OperatorBlock + Return DirectCast(DirectCast(member, OperatorBlockSyntax).BlockStatement, OperatorStatementSyntax).OperatorToken + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement + Return DirectCast(member, MethodStatementSyntax).Identifier + Case SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement + Return DirectCast(member, DeclareStatementSyntax).Identifier + Case SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, DelegateStatementSyntax).Identifier + End Select + End If + + Return Nothing + End Function + + + Public Function GetTypeParameterList(member As StatementSyntax) As TypeParameterListSyntax + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.ClassBlock, + SyntaxKind.InterfaceBlock, + SyntaxKind.StructureBlock + Return DirectCast(member, TypeBlockSyntax).BlockStatement.TypeParameterList + Case SyntaxKind.ClassStatement, + SyntaxKind.InterfaceStatement, + SyntaxKind.StructureStatement + Return DirectCast(member, TypeStatementSyntax).TypeParameterList + Case SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, DelegateStatementSyntax).TypeParameterList + Case SyntaxKind.SubBlock, + SyntaxKind.FunctionBlock + Return DirectCast(DirectCast(member, MethodBlockSyntax).BlockStatement, MethodStatementSyntax).TypeParameterList + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement + Return DirectCast(member, MethodStatementSyntax).TypeParameterList + End Select + End If + + Return Nothing + End Function + + + Public Function GetNextStatement(statement As StatementSyntax) As StatementSyntax + If statement IsNot Nothing Then + ' In VB a statement can be followed by another statement in one of two ways. It can + ' follow on the same line (in which case there will be a statement terminator + ' token), or it can be on the same line with a colon between the two of them. + Dim nextToken = statement.GetLastToken().GetNextToken() + + Dim outerStatement = statement.GetAncestors(Of StatementSyntax)().Where(Function(s) s.SpanStart <> statement.SpanStart).FirstOrDefault() + Return nextToken.GetAncestors(Of StatementSyntax)().FirstOrDefault(Function(s) s.GetAncestors(Of StatementSyntax)().Contains(outerStatement)) + End If + + Return Nothing + End Function + + + Public Function GetReturnType(member As StatementSyntax) As TypeSyntax + Dim asClause = member.GetAsClause() + Return If(asClause IsNot Nothing, asClause.Type, Nothing) + End Function + + + Public Function HasReturnType(member As StatementSyntax) As Boolean + Return member.GetReturnType() IsNot Nothing + End Function + + + Public Function GetModifiers(member As SyntaxNode) As SyntaxTokenList + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.ClassBlock, + SyntaxKind.InterfaceBlock, + SyntaxKind.ModuleBlock, + SyntaxKind.StructureBlock + Return DirectCast(member, TypeBlockSyntax).BlockStatement.Modifiers + Case SyntaxKind.EnumBlock + Return DirectCast(member, EnumBlockSyntax).EnumStatement.Modifiers + Case SyntaxKind.ClassStatement, + SyntaxKind.InterfaceStatement, + SyntaxKind.ModuleStatement, + SyntaxKind.StructureStatement + Return DirectCast(member, TypeStatementSyntax).Modifiers + Case SyntaxKind.EnumStatement + Return DirectCast(member, EnumStatementSyntax).Modifiers + Case SyntaxKind.FieldDeclaration + Return DirectCast(member, FieldDeclarationSyntax).Modifiers + Case SyntaxKind.EventBlock + Return DirectCast(member, EventBlockSyntax).EventStatement.Modifiers + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).Modifiers + Case SyntaxKind.PropertyBlock + Return DirectCast(member, PropertyBlockSyntax).PropertyStatement.Modifiers + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).Modifiers + Case SyntaxKind.FunctionBlock, + SyntaxKind.SubBlock, + SyntaxKind.ConstructorBlock, + SyntaxKind.OperatorBlock, + SyntaxKind.GetAccessorBlock, + SyntaxKind.SetAccessorBlock, + SyntaxKind.AddHandlerAccessorBlock, + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxKind.RaiseEventAccessorBlock + Return DirectCast(member, MethodBlockBaseSyntax).BlockStatement.Modifiers + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement, + SyntaxKind.SubNewStatement, + SyntaxKind.OperatorStatement, + SyntaxKind.GetAccessorStatement, + SyntaxKind.SetAccessorStatement, + SyntaxKind.AddHandlerAccessorStatement, + SyntaxKind.RemoveHandlerAccessorStatement, + SyntaxKind.RaiseEventAccessorStatement, + SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement, + SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, MethodBaseSyntax).Modifiers + End Select + End If + + Return Nothing + End Function + + + Public Function WithModifiers(Of TNode As SyntaxNode)(member As TNode, modifiers As SyntaxTokenList) As TNode + Return DirectCast(WithModifiersHelper(member, modifiers), TNode) + End Function + + Private Function WithModifiersHelper(member As SyntaxNode, modifiers As SyntaxTokenList) As SyntaxNode + If member IsNot Nothing Then + Select Case member.Kind + Case SyntaxKind.ClassBlock + Dim classBlock = DirectCast(member, ClassBlockSyntax) + Return classBlock.WithClassStatement(classBlock.ClassStatement.WithModifiers(modifiers)) + Case SyntaxKind.InterfaceBlock + Dim interfaceBlock = DirectCast(member, InterfaceBlockSyntax) + Return interfaceBlock.WithInterfaceStatement(interfaceBlock.InterfaceStatement.WithModifiers(modifiers)) + Case SyntaxKind.ModuleBlock + Dim moduleBlock = DirectCast(member, ModuleBlockSyntax) + Return moduleBlock.WithModuleStatement(moduleBlock.ModuleStatement.WithModifiers(modifiers)) + Case SyntaxKind.StructureBlock + Dim structureBlock = DirectCast(member, StructureBlockSyntax) + Return structureBlock.WithStructureStatement(structureBlock.StructureStatement.WithModifiers(modifiers)) + Case SyntaxKind.EnumBlock + Dim enumBlock = DirectCast(member, EnumBlockSyntax) + Return enumBlock.WithEnumStatement(enumBlock.EnumStatement.WithModifiers(modifiers)) + Case SyntaxKind.ClassStatement + Return DirectCast(member, ClassStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.InterfaceStatement + Return DirectCast(member, InterfaceStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.ModuleStatement + Return DirectCast(member, ModuleStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.StructureStatement + Return DirectCast(member, StructureStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.EnumStatement + Return DirectCast(member, EnumStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.FieldDeclaration + Return DirectCast(member, FieldDeclarationSyntax).WithModifiers(modifiers) + Case SyntaxKind.EventBlock + Dim eventBlock = DirectCast(member, EventBlockSyntax) + Return eventBlock.WithEventStatement(eventBlock.EventStatement.WithModifiers(modifiers)) + Case SyntaxKind.EventStatement + Return DirectCast(member, EventStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.PropertyBlock + Dim propertyBlock = DirectCast(member, PropertyBlockSyntax) + Return propertyBlock.WithPropertyStatement(propertyBlock.PropertyStatement.WithModifiers(modifiers)) + Case SyntaxKind.PropertyStatement + Return DirectCast(member, PropertyStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.FunctionBlock, + SyntaxKind.SubBlock + Dim methodBlock = DirectCast(member, MethodBlockSyntax) + Return methodBlock.WithSubOrFunctionStatement(DirectCast(methodBlock.SubOrFunctionStatement.WithModifiers(modifiers), MethodStatementSyntax)) + Case SyntaxKind.ConstructorBlock + Dim methodBlock = DirectCast(member, ConstructorBlockSyntax) + Return methodBlock.WithSubNewStatement(DirectCast(methodBlock.SubNewStatement.WithModifiers(modifiers), SubNewStatementSyntax)) + Case SyntaxKind.OperatorBlock + Dim methodBlock = DirectCast(member, OperatorBlockSyntax) + Return methodBlock.WithOperatorStatement(DirectCast(methodBlock.OperatorStatement.WithModifiers(modifiers), OperatorStatementSyntax)) + Case SyntaxKind.GetAccessorBlock, + SyntaxKind.SetAccessorBlock, + SyntaxKind.AddHandlerAccessorBlock, + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxKind.RaiseEventAccessorBlock + Dim methodBlock = DirectCast(member, AccessorBlockSyntax) + Return methodBlock.WithAccessorStatement(DirectCast(methodBlock.AccessorStatement.WithModifiers(modifiers), AccessorStatementSyntax)) + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement + Return DirectCast(member, MethodStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.SubNewStatement + Return DirectCast(member, SubNewStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.OperatorStatement + Return DirectCast(member, OperatorStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.GetAccessorStatement, + SyntaxKind.SetAccessorStatement, + SyntaxKind.AddHandlerAccessorStatement, + SyntaxKind.RemoveHandlerAccessorStatement, + SyntaxKind.RaiseEventAccessorStatement + Return DirectCast(member, AccessorStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement + Return DirectCast(member, DeclareStatementSyntax).WithModifiers(modifiers) + Case SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(member, DelegateStatementSyntax).WithModifiers(modifiers) + End Select + End If + + Return Nothing + End Function + + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions.vb index b5c489f734060..79a0a3310c2ff 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions.vb @@ -10,77 +10,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions - Friend Module SyntaxNodeExtensions - - Public Function IsParentKind(node As SyntaxNode, kind As SyntaxKind) As Boolean - Return node IsNot Nothing AndAlso - node.Parent.IsKind(kind) - End Function - - - Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean - Return node IsNot Nothing AndAlso - IsKind(node.Parent, kind1, kind2) - End Function - - - Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean - Return node IsNot Nothing AndAlso - IsKind(node.Parent, kind1, kind2, kind3) - End Function - - - Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean - If node Is Nothing Then - Return False - End If - - Return node.Kind = kind1 OrElse - node.Kind = kind2 - End Function - - - Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean - If node Is Nothing Then - Return False - End If - - Return node.Kind = kind1 OrElse - node.Kind = kind2 OrElse - node.Kind = kind3 - End Function - - - Public Function IsKind(node As SyntaxNode, ParamArray kinds As SyntaxKind()) As Boolean - If node Is Nothing Then - Return False - End If - - Return kinds.Contains(node.Kind()) - End Function - - - Public Function IsInConstantContext(expression As SyntaxNode) As Boolean - If expression.GetAncestor(Of ParameterSyntax)() IsNot Nothing Then - Return True - End If - - ' TODO(cyrusn): Add more cases - Return False - End Function - - - Public Function IsInStaticContext(node As SyntaxNode) As Boolean - Dim containingType = node.GetAncestorOrThis(Of TypeBlockSyntax)() - If containingType.IsKind(SyntaxKind.ModuleBlock) Then - Return True - End If - - Return node.GetAncestorsOrThis(Of StatementSyntax)(). - SelectMany(Function(s) s.GetModifiers()). - Any(Function(t) t.Kind = SyntaxKind.SharedKeyword) - End Function - + Partial Friend Module SyntaxNodeExtensions Public Function IsStatementContainerNode(node As SyntaxNode) As Boolean If node.IsExecutableBlock() Then @@ -240,16 +170,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return VisualBasicSyntaxFactsService.Instance.SpansPreprocessorDirective(list) End Function - - Public Function ConvertToSingleLine(Of TNode As SyntaxNode)(node As TNode, Optional useElasticTrivia As Boolean = False) As TNode - If node Is Nothing Then - Return node - End If - - Dim rewriter = New SingleLineRewriter(useElasticTrivia) - Return DirectCast(rewriter.Visit(node), TNode) - End Function - ''' ''' Breaks up the list of provided nodes, based on how they are ''' interspersed with pp directives, into groups. Within these groups @@ -315,110 +235,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return result End Function - ''' - ''' Returns true if the passed in node contains an interleaved pp - ''' directive. - ''' - ''' i.e. The following returns false: - ''' - ''' void Goo() { - ''' #if true - ''' #endif - ''' } - ''' - ''' #if true - ''' void Goo() { - ''' } - ''' #endif - ''' - ''' but these return true: - ''' - ''' #if true - ''' void Goo() { - ''' #endif - ''' } - ''' - ''' void Goo() { - ''' #if true - ''' } - ''' #endif - ''' - ''' #if true - ''' void Goo() { - ''' #else - ''' } - ''' #endif - ''' - ''' i.e. the method returns true if it contains a PP directive that - ''' belongs to a grouping constructs (like #if/#endif or - ''' #region/#endregion), but the grouping construct isn't entirely c - ''' contained within the span of the node. - ''' - - Public Function ContainsInterleavedDirective(node As SyntaxNode, cancellationToken As CancellationToken) As Boolean - Return VisualBasicSyntaxFactsService.Instance.ContainsInterleavedDirective(node, cancellationToken) - End Function - - - Public Function ContainsInterleavedDirective( - token As SyntaxToken, - textSpan As TextSpan, - cancellationToken As CancellationToken) As Boolean - - Return ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) OrElse - ContainsInterleavedDirective(textSpan, token.TrailingTrivia, cancellationToken) - End Function - - Private Function ContainsInterleavedDirective( - textSpan As TextSpan, - list As SyntaxTriviaList, - cancellationToken As CancellationToken) As Boolean - - For Each trivia In list - If textSpan.Contains(trivia.Span) Then - If ContainsInterleavedDirective(textSpan, trivia, cancellationToken) Then - Return True - End If - End If - Next trivia - - Return False - End Function - - Private Function ContainsInterleavedDirective( - textSpan As TextSpan, - trivia As SyntaxTrivia, - cancellationToken As CancellationToken) As Boolean - - If trivia.HasStructure AndAlso TypeOf trivia.GetStructure() Is DirectiveTriviaSyntax Then - Dim parentSpan = trivia.GetStructure().Span - Dim directiveSyntax = DirectCast(trivia.GetStructure(), DirectiveTriviaSyntax) - If directiveSyntax.IsKind(SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia, SyntaxKind.IfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia) Then - Dim match = directiveSyntax.GetMatchingStartOrEndDirective(cancellationToken) - If match IsNot Nothing Then - Dim matchSpan = match.Span - If Not textSpan.Contains(matchSpan.Start) Then - ' The match for this pp directive is outside - ' this node. - Return True - End If - End If - ElseIf directiveSyntax.IsKind(SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElseIfDirectiveTrivia) Then - Dim directives = directiveSyntax.GetMatchingConditionalDirectives(cancellationToken) - If directives IsNot Nothing AndAlso directives.Count > 0 Then - If Not textSpan.Contains(directives(0).SpanStart) OrElse - Not textSpan.Contains(directives(directives.Count - 1).SpanStart) Then - ' This else/elif belongs to a pp span that isn't - ' entirely within this node. - Return True - End If - End If - End If - End If - - Return False - End Function - Public Function GetLeadingBlankLines(Of TSyntaxNode As SyntaxNode)(node As TSyntaxNode) As ImmutableArray(Of SyntaxTrivia) Return VisualBasicSyntaxFactsService.Instance.GetLeadingBlankLines(node) @@ -449,50 +265,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return VisualBasicSyntaxFactsService.Instance.GetNodeWithoutLeadingBannerAndPreprocessorDirectives(node, strippedTrivia) End Function - ''' - ''' Returns true if this is a block that can contain multiple executable statements. i.e. - ''' this node is the VB equivalent of a BlockSyntax in C#. - ''' - - Public Function IsExecutableBlock(node As SyntaxNode) As Boolean - If node IsNot Nothing Then - If TypeOf node Is MethodBlockBaseSyntax OrElse - TypeOf node Is DoLoopBlockSyntax OrElse - TypeOf node Is ForOrForEachBlockSyntax OrElse - TypeOf node Is MultiLineLambdaExpressionSyntax Then - Return True - End If - - Select Case node.Kind - Case SyntaxKind.WhileBlock, - SyntaxKind.UsingBlock, - SyntaxKind.SyncLockBlock, - SyntaxKind.WithBlock, - SyntaxKind.SingleLineIfStatement, - SyntaxKind.SingleLineElseClause, - SyntaxKind.SingleLineSubLambdaExpression, - SyntaxKind.MultiLineIfBlock, - SyntaxKind.ElseIfBlock, - SyntaxKind.ElseBlock, - SyntaxKind.TryBlock, - SyntaxKind.CatchBlock, - SyntaxKind.FinallyBlock, - SyntaxKind.CaseBlock, - SyntaxKind.CaseElseBlock - Return True - End Select - End If - - Return False - End Function - - - Public Function GetContainingExecutableBlocks(node As SyntaxNode) As IEnumerable(Of SyntaxNode) - Return node.GetAncestorsOrThis(Of StatementSyntax). - Where(Function(s) s.Parent.IsExecutableBlock() AndAlso s.Parent.GetExecutableBlockStatements().Contains(s)). - Select(Function(s) s.Parent) - End Function - Public Function GetContainingMultiLineExecutableBlocks(node As SyntaxNode) As IEnumerable(Of SyntaxNode) Return node.GetAncestorsOrThis(Of StatementSyntax). @@ -500,66 +272,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Select(Function(s) s.Parent) End Function - - Public Function FindInnermostCommonExecutableBlock(nodes As IEnumerable(Of SyntaxNode)) As SyntaxNode - Dim blocks As IEnumerable(Of SyntaxNode) = Nothing - For Each node In nodes - blocks = If(blocks Is Nothing, - node.GetContainingExecutableBlocks(), - blocks.Intersect(node.GetContainingExecutableBlocks())) - Next - - Return If(blocks Is Nothing, Nothing, blocks.FirstOrDefault()) - End Function - - - Public Function GetExecutableBlockStatements(node As SyntaxNode) As SyntaxList(Of StatementSyntax) - If node IsNot Nothing Then - If TypeOf node Is MethodBlockBaseSyntax Then - Return DirectCast(node, MethodBlockBaseSyntax).Statements - ElseIf TypeOf node Is DoLoopBlockSyntax Then - Return DirectCast(node, DoLoopBlockSyntax).Statements - ElseIf TypeOf node Is ForOrForEachBlockSyntax Then - Return DirectCast(node, ForOrForEachBlockSyntax).Statements - ElseIf TypeOf node Is MultiLineLambdaExpressionSyntax Then - Return DirectCast(node, MultiLineLambdaExpressionSyntax).Statements - End If - - Select Case node.Kind - Case SyntaxKind.WhileBlock - Return DirectCast(node, WhileBlockSyntax).Statements - Case SyntaxKind.UsingBlock - Return DirectCast(node, UsingBlockSyntax).Statements - Case SyntaxKind.SyncLockBlock - Return DirectCast(node, SyncLockBlockSyntax).Statements - Case SyntaxKind.WithBlock - Return DirectCast(node, WithBlockSyntax).Statements - Case SyntaxKind.SingleLineIfStatement - Return DirectCast(node, SingleLineIfStatementSyntax).Statements - Case SyntaxKind.SingleLineElseClause - Return DirectCast(node, SingleLineElseClauseSyntax).Statements - Case SyntaxKind.SingleLineSubLambdaExpression - Return SyntaxFactory.SingletonList(DirectCast(DirectCast(node, SingleLineLambdaExpressionSyntax).Body, StatementSyntax)) - Case SyntaxKind.MultiLineIfBlock - Return DirectCast(node, MultiLineIfBlockSyntax).Statements - Case SyntaxKind.ElseIfBlock - Return DirectCast(node, ElseIfBlockSyntax).Statements - Case SyntaxKind.ElseBlock - Return DirectCast(node, ElseBlockSyntax).Statements - Case SyntaxKind.TryBlock - Return DirectCast(node, TryBlockSyntax).Statements - Case SyntaxKind.CatchBlock - Return DirectCast(node, CatchBlockSyntax).Statements - Case SyntaxKind.FinallyBlock - Return DirectCast(node, FinallyBlockSyntax).Statements - Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock - Return DirectCast(node, CaseBlockSyntax).Statements - End Select - End If - - Return Nothing - End Function - ''' ''' Returns child node or token that contains given position. ''' @@ -766,15 +478,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return tree.GetRoot().ReplaceNode(oldBlock, newBlock) End Function - - Public Function GetBraces(node As SyntaxNode) As (openBrace As SyntaxToken, closeBrace As SyntaxToken) - Return node.TypeSwitch( - Function(n As TypeParameterMultipleConstraintClauseSyntax) (n.OpenBraceToken, n.CloseBraceToken), - Function(n As ObjectMemberInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), - Function(n As CollectionInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), - Function(n As SyntaxNode) CType(Nothing, (SyntaxToken, SyntaxToken))) - End Function - Public Function GetParentheses(node As SyntaxNode) As ValueTuple(Of SyntaxToken, SyntaxToken) Return node.TypeSwitch( @@ -798,52 +501,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Function(n As SyntaxNode) CType(Nothing, (SyntaxToken, SyntaxToken))) End Function - - Public Function IsLeftSideOfSimpleAssignmentStatement(node As SyntaxNode) As Boolean - Return node.IsParentKind(SyntaxKind.SimpleAssignmentStatement) AndAlso - DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node - End Function - - - Public Function IsLeftSideOfAnyAssignmentStatement(node As SyntaxNode) As Boolean - Return node IsNot Nothing AndAlso - node.Parent.IsAnyAssignmentStatement() AndAlso - DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node - End Function - - - Public Function IsAnyAssignmentStatement(node As SyntaxNode) As Boolean - Return node IsNot Nothing AndAlso - SyntaxFacts.IsAssignmentStatement(node.Kind) - End Function - - - Public Function IsLeftSideOfCompoundAssignmentStatement(node As SyntaxNode) As Boolean - Return node IsNot Nothing AndAlso - node.Parent.IsCompoundAssignmentStatement() AndAlso - DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node - End Function - - - Public Function IsCompoundAssignmentStatement(node As SyntaxNode) As Boolean - If node IsNot Nothing Then - Select Case node.Kind - Case SyntaxKind.AddAssignmentStatement, - SyntaxKind.SubtractAssignmentStatement, - SyntaxKind.MultiplyAssignmentStatement, - SyntaxKind.DivideAssignmentStatement, - SyntaxKind.IntegerDivideAssignmentStatement, - SyntaxKind.ExponentiateAssignmentStatement, - SyntaxKind.LeftShiftAssignmentStatement, - SyntaxKind.RightShiftAssignmentStatement, - SyntaxKind.ConcatenateAssignmentStatement - Return True - End Select - End If - - Return False - End Function - Public Function ParentingNodeContainsDiagnostics(node As SyntaxNode) As Boolean Dim topMostStatement = node _ @@ -902,31 +559,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return blockSpan.Contains(textSpan) End Function - - Public Function GetMembers(node As SyntaxNode) As SyntaxList(Of StatementSyntax) - Dim compilation = TryCast(node, CompilationUnitSyntax) - If compilation IsNot Nothing Then - Return compilation.Members - End If - - Dim [namespace] = TryCast(node, NamespaceBlockSyntax) - If [namespace] IsNot Nothing Then - Return [namespace].Members - End If - - Dim type = TryCast(node, TypeBlockSyntax) - If type IsNot Nothing Then - Return type.Members - End If - - Dim [enum] = TryCast(node, EnumBlockSyntax) - If [enum] IsNot Nothing Then - Return [enum].Members - End If - - Return Nothing - End Function - Public Function GetBodies(node As SyntaxNode) As IEnumerable(Of SyntaxNode) Dim method = TryCast(node, MethodBlockBaseSyntax) @@ -986,60 +618,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Next End Function - ''' - ''' Given an expression within a tree of s, - ''' finds the that it is part of. - ''' - ''' - ''' - - Friend Function GetCorrespondingConditionalAccessExpression(node As ExpressionSyntax) As ConditionalAccessExpressionSyntax - Dim access As SyntaxNode = node - Dim parent As SyntaxNode = access.Parent - - While parent IsNot Nothing - Select Case parent.Kind - Case SyntaxKind.DictionaryAccessExpression, - SyntaxKind.SimpleMemberAccessExpression - - If DirectCast(parent, MemberAccessExpressionSyntax).Expression IsNot access Then - Return Nothing - End If - - Case SyntaxKind.XmlElementAccessExpression, - SyntaxKind.XmlDescendantAccessExpression, - SyntaxKind.XmlAttributeAccessExpression - - If DirectCast(parent, XmlMemberAccessExpressionSyntax).Base IsNot access Then - Return Nothing - End If - - Case SyntaxKind.InvocationExpression - - If DirectCast(parent, InvocationExpressionSyntax).Expression IsNot access Then - Return Nothing - End If - - Case SyntaxKind.ConditionalAccessExpression - - Dim conditional = DirectCast(parent, ConditionalAccessExpressionSyntax) - If conditional.WhenNotNull Is access Then - Return conditional - ElseIf conditional.Expression IsNot access Then - Return Nothing - End If - - Case Else - Return Nothing - End Select - - access = parent - parent = access.Parent - End While - - Return Nothing - End Function - Public Function IsInExpressionTree(node As SyntaxNode, semanticModel As SemanticModel, diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb new file mode 100644 index 0000000000000..00fc8fc7acf37 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb @@ -0,0 +1,436 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Collections.Immutable +Imports System.Runtime.CompilerServices +Imports System.Threading +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Text +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Partial Friend Module SyntaxNodeExtensions + + Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean + Return node IsNot Nothing AndAlso + IsKind(node.Parent, kind1, kind2) + End Function + + + Public Function IsParentKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean + Return node IsNot Nothing AndAlso + IsKind(node.Parent, kind1, kind2, kind3) + End Function + + + Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind) As Boolean + If node Is Nothing Then + Return False + End If + + Return node.Kind = kind1 OrElse + node.Kind = kind2 + End Function + + + Public Function IsKind(node As SyntaxNode, kind1 As SyntaxKind, kind2 As SyntaxKind, kind3 As SyntaxKind) As Boolean + If node Is Nothing Then + Return False + End If + + Return node.Kind = kind1 OrElse + node.Kind = kind2 OrElse + node.Kind = kind3 + End Function + + + Public Function IsKind(node As SyntaxNode, ParamArray kinds As SyntaxKind()) As Boolean + If node Is Nothing Then + Return False + End If + + Return kinds.Contains(node.Kind()) + End Function + + + Public Function IsParentKind(node As SyntaxNode, kind As SyntaxKind) As Boolean + Return node IsNot Nothing AndAlso + node.Parent.IsKind(kind) + End Function + + + Public Function GetBraces(node As SyntaxNode) As (openBrace As SyntaxToken, closeBrace As SyntaxToken) + Return node.TypeSwitch( + Function(n As TypeParameterMultipleConstraintClauseSyntax) (n.OpenBraceToken, n.CloseBraceToken), + Function(n As ObjectMemberInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), + Function(n As CollectionInitializerSyntax) (n.OpenBraceToken, n.CloseBraceToken), + Function(n As SyntaxNode) CType(Nothing, (SyntaxToken, SyntaxToken))) + End Function + + + Public Function IsInStaticContext(node As SyntaxNode) As Boolean + Dim containingType = node.GetAncestorOrThis(Of TypeBlockSyntax)() + If containingType.IsKind(SyntaxKind.ModuleBlock) Then + Return True + End If + + Return node.GetAncestorsOrThis(Of StatementSyntax)(). + SelectMany(Function(s) s.GetModifiers()). + Any(Function(t) t.Kind = SyntaxKind.SharedKeyword) + End Function + + Public Function IsInConstantContext(expression As SyntaxNode) As Boolean + If expression.GetAncestor(Of ParameterSyntax)() IsNot Nothing Then + Return True + End If + + ' TODO(cyrusn): Add more cases + Return False + End Function + + + Public Function GetMembers(node As SyntaxNode) As SyntaxList(Of StatementSyntax) + Dim compilation = TryCast(node, CompilationUnitSyntax) + If compilation IsNot Nothing Then + Return compilation.Members + End If + + Dim [namespace] = TryCast(node, NamespaceBlockSyntax) + If [namespace] IsNot Nothing Then + Return [namespace].Members + End If + + Dim type = TryCast(node, TypeBlockSyntax) + If type IsNot Nothing Then + Return type.Members + End If + + Dim [enum] = TryCast(node, EnumBlockSyntax) + If [enum] IsNot Nothing Then + Return [enum].Members + End If + + Return Nothing + End Function + + + Public Function IsLeftSideOfSimpleAssignmentStatement(node As SyntaxNode) As Boolean + Return node.IsParentKind(SyntaxKind.SimpleAssignmentStatement) AndAlso + DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node + End Function + + + Public Function IsLeftSideOfAnyAssignmentStatement(node As SyntaxNode) As Boolean + Return node IsNot Nothing AndAlso + node.Parent.IsAnyAssignmentStatement() AndAlso + DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node + End Function + + + Public Function IsAnyAssignmentStatement(node As SyntaxNode) As Boolean + Return node IsNot Nothing AndAlso + SyntaxFacts.IsAssignmentStatement(node.Kind) + End Function + + + Public Function IsLeftSideOfCompoundAssignmentStatement(node As SyntaxNode) As Boolean + Return node IsNot Nothing AndAlso + node.Parent.IsCompoundAssignmentStatement() AndAlso + DirectCast(node.Parent, AssignmentStatementSyntax).Left Is node + End Function + + + Public Function IsCompoundAssignmentStatement(node As SyntaxNode) As Boolean + If node IsNot Nothing Then + Select Case node.Kind + Case SyntaxKind.AddAssignmentStatement, + SyntaxKind.SubtractAssignmentStatement, + SyntaxKind.MultiplyAssignmentStatement, + SyntaxKind.DivideAssignmentStatement, + SyntaxKind.IntegerDivideAssignmentStatement, + SyntaxKind.ExponentiateAssignmentStatement, + SyntaxKind.LeftShiftAssignmentStatement, + SyntaxKind.RightShiftAssignmentStatement, + SyntaxKind.ConcatenateAssignmentStatement + Return True + End Select + End If + + Return False + End Function + + + Public Function ConvertToSingleLine(Of TNode As SyntaxNode)(node As TNode, Optional useElasticTrivia As Boolean = False) As TNode + If node Is Nothing Then + Return node + End If + + Dim rewriter = New SingleLineRewriter(useElasticTrivia) + Return DirectCast(rewriter.Visit(node), TNode) + End Function + + ''' + ''' Returns true if the passed in node contains an interleaved pp + ''' directive. + ''' + ''' i.e. The following returns false: + ''' + ''' void Goo() { + ''' #if true + ''' #endif + ''' } + ''' + ''' #if true + ''' void Goo() { + ''' } + ''' #endif + ''' + ''' but these return true: + ''' + ''' #if true + ''' void Goo() { + ''' #endif + ''' } + ''' + ''' void Goo() { + ''' #if true + ''' } + ''' #endif + ''' + ''' #if true + ''' void Goo() { + ''' #else + ''' } + ''' #endif + ''' + ''' i.e. the method returns true if it contains a PP directive that + ''' belongs to a grouping constructs (like #if/#endif or + ''' #region/#endregion), but the grouping construct isn't entirely c + ''' contained within the span of the node. + ''' + + Public Function ContainsInterleavedDirective(node As SyntaxNode, cancellationToken As CancellationToken) As Boolean + Return VisualBasicSyntaxFactsService.Instance.ContainsInterleavedDirective(node, cancellationToken) + End Function + + + Public Function ContainsInterleavedDirective( + token As SyntaxToken, + textSpan As TextSpan, + cancellationToken As CancellationToken) As Boolean + + Return ContainsInterleavedDirective(textSpan, token.LeadingTrivia, cancellationToken) OrElse + ContainsInterleavedDirective(textSpan, token.TrailingTrivia, cancellationToken) + End Function + + Private Function ContainsInterleavedDirective( + textSpan As TextSpan, + list As SyntaxTriviaList, + cancellationToken As CancellationToken) As Boolean + + For Each trivia In list + If textSpan.Contains(trivia.Span) Then + If ContainsInterleavedDirective(textSpan, trivia, cancellationToken) Then + Return True + End If + End If + Next trivia + + Return False + End Function + + Private Function ContainsInterleavedDirective( + textSpan As TextSpan, + trivia As SyntaxTrivia, + cancellationToken As CancellationToken) As Boolean + + If trivia.HasStructure AndAlso TypeOf trivia.GetStructure() Is DirectiveTriviaSyntax Then + Dim parentSpan = trivia.GetStructure().Span + Dim directiveSyntax = DirectCast(trivia.GetStructure(), DirectiveTriviaSyntax) + If directiveSyntax.IsKind(SyntaxKind.RegionDirectiveTrivia, SyntaxKind.EndRegionDirectiveTrivia, SyntaxKind.IfDirectiveTrivia, SyntaxKind.EndIfDirectiveTrivia) Then + Dim match = directiveSyntax.GetMatchingStartOrEndDirective(cancellationToken) + If match IsNot Nothing Then + Dim matchSpan = match.Span + If Not textSpan.Contains(matchSpan.Start) Then + ' The match for this pp directive is outside + ' this node. + Return True + End If + End If + ElseIf directiveSyntax.IsKind(SyntaxKind.ElseDirectiveTrivia, SyntaxKind.ElseIfDirectiveTrivia) Then + Dim directives = directiveSyntax.GetMatchingConditionalDirectives(cancellationToken) + If directives IsNot Nothing AndAlso directives.Count > 0 Then + If Not textSpan.Contains(directives(0).SpanStart) OrElse + Not textSpan.Contains(directives(directives.Count - 1).SpanStart) Then + ' This else/elif belongs to a pp span that isn't + ' entirely within this node. + Return True + End If + End If + End If + End If + + Return False + End Function + + ''' + ''' Returns true if this is a block that can contain multiple executable statements. i.e. + ''' this node is the VB equivalent of a BlockSyntax in C#. + ''' + + Public Function IsExecutableBlock(node As SyntaxNode) As Boolean + If node IsNot Nothing Then + If TypeOf node Is MethodBlockBaseSyntax OrElse + TypeOf node Is DoLoopBlockSyntax OrElse + TypeOf node Is ForOrForEachBlockSyntax OrElse + TypeOf node Is MultiLineLambdaExpressionSyntax Then + Return True + End If + + Select Case node.Kind + Case SyntaxKind.WhileBlock, + SyntaxKind.UsingBlock, + SyntaxKind.SyncLockBlock, + SyntaxKind.WithBlock, + SyntaxKind.SingleLineIfStatement, + SyntaxKind.SingleLineElseClause, + SyntaxKind.SingleLineSubLambdaExpression, + SyntaxKind.MultiLineIfBlock, + SyntaxKind.ElseIfBlock, + SyntaxKind.ElseBlock, + SyntaxKind.TryBlock, + SyntaxKind.CatchBlock, + SyntaxKind.FinallyBlock, + SyntaxKind.CaseBlock, + SyntaxKind.CaseElseBlock + Return True + End Select + End If + + Return False + End Function + + + Public Function FindInnermostCommonExecutableBlock(nodes As IEnumerable(Of SyntaxNode)) As SyntaxNode + Dim blocks As IEnumerable(Of SyntaxNode) = Nothing + For Each node In nodes + blocks = If(blocks Is Nothing, + node.GetContainingExecutableBlocks(), + blocks.Intersect(node.GetContainingExecutableBlocks())) + Next + + Return If(blocks Is Nothing, Nothing, blocks.FirstOrDefault()) + End Function + + + Public Function GetExecutableBlockStatements(node As SyntaxNode) As SyntaxList(Of StatementSyntax) + If node IsNot Nothing Then + If TypeOf node Is MethodBlockBaseSyntax Then + Return DirectCast(node, MethodBlockBaseSyntax).Statements + ElseIf TypeOf node Is DoLoopBlockSyntax Then + Return DirectCast(node, DoLoopBlockSyntax).Statements + ElseIf TypeOf node Is ForOrForEachBlockSyntax Then + Return DirectCast(node, ForOrForEachBlockSyntax).Statements + ElseIf TypeOf node Is MultiLineLambdaExpressionSyntax Then + Return DirectCast(node, MultiLineLambdaExpressionSyntax).Statements + End If + + Select Case node.Kind + Case SyntaxKind.WhileBlock + Return DirectCast(node, WhileBlockSyntax).Statements + Case SyntaxKind.UsingBlock + Return DirectCast(node, UsingBlockSyntax).Statements + Case SyntaxKind.SyncLockBlock + Return DirectCast(node, SyncLockBlockSyntax).Statements + Case SyntaxKind.WithBlock + Return DirectCast(node, WithBlockSyntax).Statements + Case SyntaxKind.SingleLineIfStatement + Return DirectCast(node, SingleLineIfStatementSyntax).Statements + Case SyntaxKind.SingleLineElseClause + Return DirectCast(node, SingleLineElseClauseSyntax).Statements + Case SyntaxKind.SingleLineSubLambdaExpression + Return SyntaxFactory.SingletonList(DirectCast(DirectCast(node, SingleLineLambdaExpressionSyntax).Body, StatementSyntax)) + Case SyntaxKind.MultiLineIfBlock + Return DirectCast(node, MultiLineIfBlockSyntax).Statements + Case SyntaxKind.ElseIfBlock + Return DirectCast(node, ElseIfBlockSyntax).Statements + Case SyntaxKind.ElseBlock + Return DirectCast(node, ElseBlockSyntax).Statements + Case SyntaxKind.TryBlock + Return DirectCast(node, TryBlockSyntax).Statements + Case SyntaxKind.CatchBlock + Return DirectCast(node, CatchBlockSyntax).Statements + Case SyntaxKind.FinallyBlock + Return DirectCast(node, FinallyBlockSyntax).Statements + Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock + Return DirectCast(node, CaseBlockSyntax).Statements + End Select + End If + + Return Nothing + End Function + + ''' + ''' Given an expression within a tree of s, + ''' finds the that it is part of. + ''' + ''' + ''' + + Friend Function GetCorrespondingConditionalAccessExpression(node As ExpressionSyntax) As ConditionalAccessExpressionSyntax + Dim access As SyntaxNode = node + Dim parent As SyntaxNode = access.Parent + + While parent IsNot Nothing + Select Case parent.Kind + Case SyntaxKind.DictionaryAccessExpression, + SyntaxKind.SimpleMemberAccessExpression + + If DirectCast(parent, MemberAccessExpressionSyntax).Expression IsNot access Then + Return Nothing + End If + + Case SyntaxKind.XmlElementAccessExpression, + SyntaxKind.XmlDescendantAccessExpression, + SyntaxKind.XmlAttributeAccessExpression + + If DirectCast(parent, XmlMemberAccessExpressionSyntax).Base IsNot access Then + Return Nothing + End If + + Case SyntaxKind.InvocationExpression + + If DirectCast(parent, InvocationExpressionSyntax).Expression IsNot access Then + Return Nothing + End If + + Case SyntaxKind.ConditionalAccessExpression + + Dim conditional = DirectCast(parent, ConditionalAccessExpressionSyntax) + If conditional.WhenNotNull Is access Then + Return conditional + ElseIf conditional.Expression IsNot access Then + Return Nothing + End If + + Case Else + Return Nothing + End Select + + access = parent + parent = access.Parent + End While + + Return Nothing + End Function + + + Public Function GetContainingExecutableBlocks(node As SyntaxNode) As IEnumerable(Of SyntaxNode) + Return node.GetAncestorsOrThis(Of StatementSyntax). + Where(Function(s) s.Parent.IsExecutableBlock() AndAlso s.Parent.GetExecutableBlockStatements().Contains(s)). + Select(Function(s) s.Parent) + End Function + + End Module +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb index 11be949cb1841..d2083b08c6f81 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions.vb @@ -16,11 +16,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions token.HasMatchingText(kind) End Function - - Public Function HasMatchingText(token As SyntaxToken, kind As SyntaxKind) As Boolean - Return String.Equals(token.ToString(), SyntaxFacts.GetText(kind), StringComparison.OrdinalIgnoreCase) - End Function - Public Function IsCharacterLiteral(token As SyntaxToken) As Boolean Return token.Kind = SyntaxKind.CharacterLiteralToken @@ -200,18 +195,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return VisualBasicSyntaxFactsService.Instance.SpansPreprocessorDirective(tokens) End Function - - Public Function GetPreviousTokenIfTouchingWord(token As SyntaxToken, position As Integer) As SyntaxToken - Return If(token.IntersectsWith(position) AndAlso IsWord(token), - token.GetPreviousToken(includeSkipped:=True), - token) - End Function - - - Public Function IsWord(token As SyntaxToken) As Boolean - Return VisualBasicSyntaxFactsService.Instance.IsWord(token) - End Function - Public Function GetNextNonZeroWidthTokenOrEndOfFile(token As SyntaxToken) As SyntaxToken Dim nextToken = token.GetNextToken() diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.vb index 7e8ca71a51066..b845e63891e68 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTokenExtensions_SharedWithCodeStyle.vb @@ -3,6 +3,7 @@ ' See the LICENSE file in the project root for more information. Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis.LanguageServices Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Partial Friend Module SyntaxTokenExtensions @@ -16,5 +17,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Public Function IsKind(token As SyntaxToken, ParamArray kinds As SyntaxKind()) As Boolean Return kinds.Contains(token.Kind) End Function + + + Public Function HasMatchingText(token As SyntaxToken, kind As SyntaxKind) As Boolean + Return String.Equals(token.ToString(), SyntaxFacts.GetText(kind), StringComparison.OrdinalIgnoreCase) + End Function + + + Public Function GetPreviousTokenIfTouchingWord(token As SyntaxToken, position As Integer) As SyntaxToken + Return If(token.IntersectsWith(position) AndAlso IsWord(token), + token.GetPreviousToken(includeSkipped:=True), + token) + End Function + + + Public Function IsWord(token As SyntaxToken) As Boolean + Return VisualBasicSyntaxFactsService.Instance.IsWord(token) + End Function End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions.vb index 59317040cc55d..2a3fb07cba69a 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions.vb @@ -2,87 +2,13 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. -Imports System.Collections.Immutable Imports System.Runtime.CompilerServices Imports System.Threading Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.PooledObjects -Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Partial Friend Module SyntaxTreeExtensions - ''' - ''' Finds the token being touched by this position. Unlike the normal FindTrivia helper, this helper will prefer - ''' trivia to the left rather than the right if the position is on the border. - ''' - ''' The syntaxTree to search. - ''' The position to find trivia. - - Public Function FindTriviaToLeft(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As SyntaxTrivia - Return FindTriviaToLeft(syntaxTree.GetRoot(cancellationToken), position) - End Function - - Private Function FindTriviaToLeft(nodeOrToken As SyntaxNodeOrToken, position As Integer) As SyntaxTrivia -recurse: - For Each child In nodeOrToken.ChildNodesAndTokens().Reverse() - If (child.FullSpan.Start < position) AndAlso (position <= child.FullSpan.End) Then - If child.IsNode Then - nodeOrToken = child - GoTo recurse - Else - For Each trivia In child.GetTrailingTrivia.Reverse - If (trivia.SpanStart < position) AndAlso (position <= child.FullSpan.End) Then - Return trivia - End If - Next - For Each trivia In child.GetLeadingTrivia.Reverse - If (trivia.SpanStart < position) AndAlso (position <= child.FullSpan.End) Then - Return trivia - End If - Next - End If - End If - Next - Return Nothing - End Function - - - Public Function IsInNonUserCode(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean - Return _ - syntaxTree.IsEntirelyWithinComment(position, cancellationToken) OrElse - syntaxTree.IsEntirelyWithinStringOrCharOrNumericLiteral(position, cancellationToken) OrElse - syntaxTree.IsInInactiveRegion(position, cancellationToken) OrElse - syntaxTree.IsWithinPartialMethodDeclaration(position, cancellationToken) - End Function - - - Public Function IsWithinPartialMethodDeclaration(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean - Dim token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken) - Dim declaration = token.GetAncestor(Of MethodStatementSyntax) - If declaration IsNot Nothing AndAlso declaration.Modifiers.Any(SyntaxKind.PartialKeyword) Then - Return True - End If - - Dim block = token.GetAncestor(Of MethodBlockSyntax) - If block IsNot Nothing AndAlso block.BlockStatement.Modifiers.Any(SyntaxKind.PartialKeyword) Then - Return True - End If - - Return False - End Function - - - Public Function IsEntirelyWithinComment(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean - Dim trivia = syntaxTree.FindTriviaToLeft(position, cancellationToken) - - If trivia.IsKind(SyntaxKind.CommentTrivia, SyntaxKind.DocumentationCommentTrivia) AndAlso trivia.SpanStart <> position Then - Return True - End If - - Return False - End Function - Public Function IsEntirelyWithinStringLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Dim token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives:=True, includeDocumentationComments:=True) @@ -94,72 +20,6 @@ recurse: Return False End Function - - Public Function IsEntirelyWithinStringOrCharOrNumericLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean - Dim token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives:=True, includeDocumentationComments:=True) - - If Not token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.CharacterLiteralToken, SyntaxKind.DecimalLiteralToken, SyntaxKind.IntegerLiteralToken, - SyntaxKind.DateLiteralToken, SyntaxKind.FloatingLiteralToken) Then - Return False - End If - - ' Check if it's within a completed token. - If token.SpanStart < position AndAlso position < token.Span.End Then - Return True - End If - - ' If it is a numeric literal, all checks are done and we're okay. - If token.IsKind(SyntaxKind.IntegerLiteralToken, SyntaxKind.DecimalLiteralToken, - SyntaxKind.DateLiteralToken, SyntaxKind.FloatingLiteralToken) Then - Return False - End If - - ' For char or string literals, check if we're at the end of an incomplete literal. - Dim lastChar = If(token.IsKind(SyntaxKind.CharacterLiteralToken), "'", """") - - Return AtEndOfIncompleteStringOrCharLiteral(token, position, lastChar) - End Function - - Private Function AtEndOfIncompleteStringOrCharLiteral(token As SyntaxToken, position As Integer, lastChar As String) As Boolean - ' Check if it's a token that was started, but not ended - Dim startLength = 1 - If token.IsKind(SyntaxKind.CharacterLiteralToken) Then - startLength = 2 - End If - - Return _ - position = token.Span.End AndAlso - (token.Span.Length = startLength OrElse - (token.Span.Length > startLength AndAlso Not token.ToString().EndsWith(lastChar, StringComparison.Ordinal))) - End Function - - - Public Function IsInInactiveRegion(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean - Contract.ThrowIfNull(syntaxTree) - - ' cases: - ' $ is EOF - - ' #IF false Then - ' | - - ' #IF false Then - ' |$ - - ' #IF false Then - ' | - - ' #IF false Then - ' |$ - - If syntaxTree.FindTriviaToLeft(position, cancellationToken).Kind = SyntaxKind.DisabledTextTrivia Then - Return True - End If - - ' TODO : insert point at the same line as preprocessor? - Return False - End Function - Public Function IsInSkippedText(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Dim trivia = syntaxTree.FindTriviaToLeft(position, cancellationToken) @@ -244,82 +104,6 @@ recurse: directive.FullSpan.End = syntaxTree.GetRoot(cancellationToken).FullSpan.End End Function - - Public Function GetSelectedFieldsAndPropertiesInSpan(root As SyntaxNode, - textSpan As TextSpan, allowPartialSelection As Boolean) As ImmutableArray(Of StatementSyntax) - - Dim token = root.FindTokenOnRightOfPosition(textSpan.Start) - Dim firstMember = token.GetAncestors(Of StatementSyntax). - Where(Function(s) TypeOf s.Parent Is TypeBlockSyntax). - FirstOrDefault() - If firstMember IsNot Nothing Then - Dim containingType = DirectCast(firstMember.Parent, TypeBlockSyntax) - If containingType IsNot Nothing AndAlso - firstMember IsNot containingType.BlockStatement AndAlso - firstMember IsNot containingType.EndBlockStatement Then - Return GetFieldsAndPropertiesInSpan(textSpan, containingType, firstMember, allowPartialSelection) - End If - End If - - Return ImmutableArray(Of StatementSyntax).Empty - End Function - - Private Function GetFieldsAndPropertiesInSpan( - textSpan As TextSpan, - containingType As TypeBlockSyntax, - firstMember As StatementSyntax, - allowPartialSelection As Boolean) As ImmutableArray(Of StatementSyntax) - Dim selectedMembers = ArrayBuilder(Of StatementSyntax).GetInstance() - - Try - Dim members = containingType.Members - Dim fieldIndex = members.IndexOf(firstMember) - If fieldIndex < 0 Then - Return ImmutableArray(Of StatementSyntax).Empty - End If - - For i = fieldIndex To members.Count - 1 - Dim member = members(i) - If IsSelectedFieldOrProperty(textSpan, member, allowPartialSelection) Then - selectedMembers.Add(member) - End If - Next - - Return selectedMembers.ToImmutable() - Finally - selectedMembers.Free() - End Try - End Function - - Private Function IsSelectedFieldOrProperty(textSpan As TextSpan, member As StatementSyntax, allowPartialSelection As Boolean) As Boolean - If Not member.IsKind(SyntaxKind.FieldDeclaration, SyntaxKind.PropertyStatement) Then - Return False - End If - - ' first, check if entire member is selected - If textSpan.Contains(member.Span) Then - Return True - End If - - If Not allowPartialSelection Then - Return False - End If - - ' next, check if identifier is at lease partially selected - If member.IsKind(SyntaxKind.FieldDeclaration) Then - Dim fieldDeclaration = DirectCast(member, FieldDeclarationSyntax) - For Each declarator In fieldDeclaration.Declarators - If textSpan.Contains(member.Span) Or (allowPartialSelection And textSpan.OverlapsWith(declarator.Names.Span)) Then - Return True - End If - Next - ElseIf member.IsKind(SyntaxKind.PropertyStatement) Then - Return textSpan.OverlapsWith((DirectCast(member, PropertyStatementSyntax)).Identifier.Span) - End If - - Return False - End Function - Public Function GetFirstStatementOnLine(syntaxTree As SyntaxTree, lineNumber As Integer, cancellationToken As CancellationToken) As StatementSyntax Dim line = syntaxTree.GetText(cancellationToken).Lines(lineNumber) diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.vb index f378700b86a5f..9cf4f5b29f2b5 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxTreeExtensions_SharedWithCodeStyle.vb @@ -2,8 +2,12 @@ ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. +Imports System.Collections.Immutable Imports System.Runtime.CompilerServices +Imports System.Threading Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.PooledObjects +Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -105,5 +109,219 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return False End Function + + + Public Function IsInInactiveRegion(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean + Contract.ThrowIfNull(syntaxTree) + + ' cases: + ' $ is EOF + + ' #IF false Then + ' | + + ' #IF false Then + ' |$ + + ' #IF false Then + ' | + + ' #IF false Then + ' |$ + + If syntaxTree.FindTriviaToLeft(position, cancellationToken).Kind = SyntaxKind.DisabledTextTrivia Then + Return True + End If + + ' TODO : insert point at the same line as preprocessor? + Return False + End Function + + + Public Function IsInNonUserCode(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean + Return _ + syntaxTree.IsEntirelyWithinComment(position, cancellationToken) OrElse + syntaxTree.IsEntirelyWithinStringOrCharOrNumericLiteral(position, cancellationToken) OrElse + syntaxTree.IsInInactiveRegion(position, cancellationToken) OrElse + syntaxTree.IsWithinPartialMethodDeclaration(position, cancellationToken) + End Function + + + Public Function IsEntirelyWithinStringOrCharOrNumericLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean + Dim token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken, includeDirectives:=True, includeDocumentationComments:=True) + + If Not token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.CharacterLiteralToken, SyntaxKind.DecimalLiteralToken, SyntaxKind.IntegerLiteralToken, + SyntaxKind.DateLiteralToken, SyntaxKind.FloatingLiteralToken) Then + Return False + End If + + ' Check if it's within a completed token. + If token.SpanStart < position AndAlso position < token.Span.End Then + Return True + End If + + ' If it is a numeric literal, all checks are done and we're okay. + If token.IsKind(SyntaxKind.IntegerLiteralToken, SyntaxKind.DecimalLiteralToken, + SyntaxKind.DateLiteralToken, SyntaxKind.FloatingLiteralToken) Then + Return False + End If + + ' For char or string literals, check if we're at the end of an incomplete literal. + Dim lastChar = If(token.IsKind(SyntaxKind.CharacterLiteralToken), "'", """") + + Return AtEndOfIncompleteStringOrCharLiteral(token, position, lastChar) + End Function + + ''' + ''' Finds the token being touched by this position. Unlike the normal FindTrivia helper, this helper will prefer + ''' trivia to the left rather than the right if the position is on the border. + ''' + ''' The syntaxTree to search. + ''' The position to find trivia. + + Public Function FindTriviaToLeft(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As SyntaxTrivia + Return FindTriviaToLeft(syntaxTree.GetRoot(cancellationToken), position) + End Function + + Private Function FindTriviaToLeft(nodeOrToken As SyntaxNodeOrToken, position As Integer) As SyntaxTrivia +recurse: + For Each child In nodeOrToken.ChildNodesAndTokens().Reverse() + If (child.FullSpan.Start < position) AndAlso (position <= child.FullSpan.End) Then + If child.IsNode Then + nodeOrToken = child + GoTo recurse + Else + For Each trivia In child.GetTrailingTrivia.Reverse + If (trivia.SpanStart < position) AndAlso (position <= child.FullSpan.End) Then + Return trivia + End If + Next + For Each trivia In child.GetLeadingTrivia.Reverse + If (trivia.SpanStart < position) AndAlso (position <= child.FullSpan.End) Then + Return trivia + End If + Next + End If + End If + Next + Return Nothing + End Function + + + Public Function GetSelectedFieldsAndPropertiesInSpan(root As SyntaxNode, + textSpan As TextSpan, allowPartialSelection As Boolean) As ImmutableArray(Of StatementSyntax) + + Dim token = root.FindTokenOnRightOfPosition(textSpan.Start) + Dim firstMember = token.GetAncestors(Of StatementSyntax). + Where(Function(s) TypeOf s.Parent Is TypeBlockSyntax). + FirstOrDefault() + If firstMember IsNot Nothing Then + Dim containingType = DirectCast(firstMember.Parent, TypeBlockSyntax) + If containingType IsNot Nothing AndAlso + firstMember IsNot containingType.BlockStatement AndAlso + firstMember IsNot containingType.EndBlockStatement Then + Return GetFieldsAndPropertiesInSpan(textSpan, containingType, firstMember, allowPartialSelection) + End If + End If + + Return ImmutableArray(Of StatementSyntax).Empty + End Function + + Private Function GetFieldsAndPropertiesInSpan( + textSpan As TextSpan, + containingType As TypeBlockSyntax, + firstMember As StatementSyntax, + allowPartialSelection As Boolean) As ImmutableArray(Of StatementSyntax) + Dim selectedMembers = ArrayBuilder(Of StatementSyntax).GetInstance() + + Try + Dim members = containingType.Members + Dim fieldIndex = members.IndexOf(firstMember) + If fieldIndex < 0 Then + Return ImmutableArray(Of StatementSyntax).Empty + End If + + For i = fieldIndex To members.Count - 1 + Dim member = members(i) + If IsSelectedFieldOrProperty(textSpan, member, allowPartialSelection) Then + selectedMembers.Add(member) + End If + Next + + Return selectedMembers.ToImmutable() + Finally + selectedMembers.Free() + End Try + End Function + + Private Function IsSelectedFieldOrProperty(textSpan As TextSpan, member As StatementSyntax, allowPartialSelection As Boolean) As Boolean + If Not member.IsKind(SyntaxKind.FieldDeclaration, SyntaxKind.PropertyStatement) Then + Return False + End If + + ' first, check if entire member is selected + If textSpan.Contains(member.Span) Then + Return True + End If + + If Not allowPartialSelection Then + Return False + End If + + ' next, check if identifier is at lease partially selected + If member.IsKind(SyntaxKind.FieldDeclaration) Then + Dim fieldDeclaration = DirectCast(member, FieldDeclarationSyntax) + For Each declarator In fieldDeclaration.Declarators + If textSpan.Contains(member.Span) Or (allowPartialSelection And textSpan.OverlapsWith(declarator.Names.Span)) Then + Return True + End If + Next + ElseIf member.IsKind(SyntaxKind.PropertyStatement) Then + Return textSpan.OverlapsWith((DirectCast(member, PropertyStatementSyntax)).Identifier.Span) + End If + + Return False + End Function + + + Public Function IsEntirelyWithinComment(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean + Dim trivia = syntaxTree.FindTriviaToLeft(position, cancellationToken) + + If trivia.IsKind(SyntaxKind.CommentTrivia, SyntaxKind.DocumentationCommentTrivia) AndAlso trivia.SpanStart <> position Then + Return True + End If + + Return False + End Function + + + Public Function IsWithinPartialMethodDeclaration(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean + Dim token = syntaxTree.FindTokenOnLeftOfPosition(position, cancellationToken) + Dim declaration = token.GetAncestor(Of MethodStatementSyntax) + If declaration IsNot Nothing AndAlso declaration.Modifiers.Any(SyntaxKind.PartialKeyword) Then + Return True + End If + + Dim block = token.GetAncestor(Of MethodBlockSyntax) + If block IsNot Nothing AndAlso block.BlockStatement.Modifiers.Any(SyntaxKind.PartialKeyword) Then + Return True + End If + + Return False + End Function + + Private Function AtEndOfIncompleteStringOrCharLiteral(token As SyntaxToken, position As Integer, lastChar As String) As Boolean + ' Check if it's a token that was started, but not ended + Dim startLength = 1 + If token.IsKind(SyntaxKind.CharacterLiteralToken) Then + startLength = 2 + End If + + Return _ + position = token.Span.End AndAlso + (token.Span.Length = startLength OrElse + (token.Span.Length > startLength AndAlso Not token.ToString().EndsWith(lastChar, StringComparison.Ordinal))) + End Function + End Module End Namespace From d46d186843c86cbc31984d7c3a3461009513320f Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 19:05:56 -0800 Subject: [PATCH 17/21] More VB sharing --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 1 + ....CodeAnalysis.VisualBasic.CodeStyle.vbproj | 8 ++ .../VisualBasicSyntaxGenerator.vb | 85 +++++++++---------- .../VisualBasicSyntaxGenerator_Mef.vb | 18 ++++ .../Extensions/ExpressionSyntaxExtensions.vb | 11 --- .../ExpressionSyntaxExtensions_Shared.vb | 11 +++ .../INamespaceOrTypeSymbolExtensions.vb | 7 -- ...INamespaceOrTypeSymbolExtensions_Shared.vb | 17 ++++ 8 files changed, 94 insertions(+), 64 deletions(-) create mode 100644 src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator_Mef.vb create mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions_Shared.vb diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index 79b970637eeec..a9284670dce57 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -196,6 +196,7 @@ + diff --git a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj index 0192f4f2c4776..d63d5bbe844a5 100644 --- a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj +++ b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj @@ -9,10 +9,16 @@ Microsoft.CodeAnalysis.VisualBasic.CodeStyle.NewNameSinceWeReferenceTheAnalyzersAndNuGetCannotFigureItOut + + + + + + @@ -21,6 +27,7 @@ + @@ -88,6 +95,7 @@ + \ No newline at end of file diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index 954e7ba9e9be1..0937e2363f9c9 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -3,26 +3,19 @@ ' See the LICENSE file in the project root for more information. Imports System.Collections.Immutable -Imports System.Composition Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Editing -Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration - Friend Class VisualBasicSyntaxGenerator Inherits SyntaxGenerator Public Shared ReadOnly Instance As SyntaxGenerator = New VisualBasicSyntaxGenerator() - - Public Sub New() - End Sub - Friend Overrides ReadOnly Property ElasticCarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.ElasticCarriageReturnLineFeed Friend Overrides ReadOnly Property CarriageReturnLineFeed As SyntaxTrivia = SyntaxFactory.CarriageReturnLineFeed @@ -400,37 +393,37 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Public Overrides Function TypeExpression(specialType As SpecialType) As SyntaxNode Select Case specialType - Case specialType.System_Boolean + Case SpecialType.System_Boolean Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.BooleanKeyword)) - Case specialType.System_Byte + Case SpecialType.System_Byte Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ByteKeyword)) - Case specialType.System_Char + Case SpecialType.System_Char Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.CharKeyword)) - Case specialType.System_Decimal + Case SpecialType.System_Decimal Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DecimalKeyword)) - Case specialType.System_Double + Case SpecialType.System_Double Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword)) - Case specialType.System_Int16 + Case SpecialType.System_Int16 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ShortKeyword)) - Case specialType.System_Int32 + Case SpecialType.System_Int32 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.IntegerKeyword)) - Case specialType.System_Int64 + Case SpecialType.System_Int64 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.LongKeyword)) - Case specialType.System_Object + Case SpecialType.System_Object Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ObjectKeyword)) - Case specialType.System_SByte + Case SpecialType.System_SByte Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.SByteKeyword)) - Case specialType.System_Single + Case SpecialType.System_Single Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.SingleKeyword)) - Case specialType.System_String + Case SpecialType.System_String Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.StringKeyword)) - Case specialType.System_UInt16 + Case SpecialType.System_UInt16 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UShortKeyword)) - Case specialType.System_UInt32 + Case SpecialType.System_UInt32 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UIntegerKeyword)) - Case specialType.System_UInt64 + Case SpecialType.System_UInt64 Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.ULongKeyword)) - Case specialType.System_DateTime + Case SpecialType.System_DateTime Return SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DateKeyword)) Case Else Throw New NotSupportedException("Unsupported SpecialType") @@ -929,7 +922,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration If initializer IsNot Nothing Then tokens = tokens.Add(SyntaxFactory.Token(SyntaxKind.OptionalKeyword)) End If - If refKind <> refKind.None Then + If refKind <> RefKind.None Then tokens = tokens.Add(SyntaxFactory.Token(SyntaxKind.ByRefKeyword)) End If Return tokens @@ -2756,7 +2749,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Public Overrides Function WithAccessibility(declaration As SyntaxNode, accessibility As Accessibility) As SyntaxNode If Not CanHaveAccessibility(declaration) AndAlso - accessibility <> accessibility.NotApplicable Then + accessibility <> Accessibility.NotApplicable Then Return declaration End If @@ -2781,7 +2774,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Dim newTokens = GetModifierList(accessibility, mods, GetDeclarationKind(declaration), isDefault) 'GetDeclarationKind returns None for Field if the count is > 1 'To handle multiple declarations on a field if the Accessibility is NotApplicable, we need to add the Dim - If declaration.Kind = SyntaxKind.FieldDeclaration AndAlso accessibility = accessibility.NotApplicable AndAlso newTokens.Count = 0 Then + If declaration.Kind = SyntaxKind.FieldDeclaration AndAlso accessibility = Accessibility.NotApplicable AndAlso newTokens.Count = 0 Then ' Add the Dim newTokens = newTokens.Add(SyntaxFactory.Token(SyntaxKind.DimKeyword)) End If @@ -2860,19 +2853,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End If Select Case (accessibility) - Case accessibility.Internal + Case Accessibility.Internal _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)) - Case accessibility.Public + Case Accessibility.Public _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) - Case accessibility.Private + Case Accessibility.Private _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) - Case accessibility.Protected + Case Accessibility.Protected _list = _list.Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case accessibility.ProtectedOrInternal + Case Accessibility.ProtectedOrInternal _list = _list.Add(SyntaxFactory.Token(SyntaxKind.FriendKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case accessibility.ProtectedAndInternal + Case Accessibility.ProtectedAndInternal _list = _list.Add(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)).Add(SyntaxFactory.Token(SyntaxKind.ProtectedKeyword)) - Case accessibility.NotApplicable + Case Accessibility.NotApplicable Case Else Throw New NotSupportedException(String.Format("Accessibility '{0}' not supported.", accessibility)) End Select @@ -2942,7 +2935,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Private Sub GetAccessibilityAndModifiers(modifierTokens As SyntaxTokenList, ByRef accessibility As Accessibility, ByRef modifiers As DeclarationModifiers, ByRef isDefault As Boolean) - accessibility = accessibility.NotApplicable + accessibility = Accessibility.NotApplicable modifiers = DeclarationModifiers.None isDefault = False @@ -2951,26 +2944,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Case SyntaxKind.DefaultKeyword isDefault = True Case SyntaxKind.PublicKeyword - accessibility = accessibility.Public + accessibility = Accessibility.Public Case SyntaxKind.PrivateKeyword - If accessibility = accessibility.Protected Then - accessibility = accessibility.ProtectedAndFriend + If accessibility = Accessibility.Protected Then + accessibility = Accessibility.ProtectedAndFriend Else - accessibility = accessibility.Private + accessibility = Accessibility.Private End If Case SyntaxKind.FriendKeyword - If accessibility = accessibility.Protected Then - accessibility = accessibility.ProtectedOrFriend + If accessibility = Accessibility.Protected Then + accessibility = Accessibility.ProtectedOrFriend Else - accessibility = accessibility.Friend + accessibility = Accessibility.Friend End If Case SyntaxKind.ProtectedKeyword - If accessibility = accessibility.Friend Then - accessibility = accessibility.ProtectedOrFriend - ElseIf accessibility = accessibility.Private Then - accessibility = accessibility.ProtectedAndFriend + If accessibility = Accessibility.Friend Then + accessibility = Accessibility.ProtectedOrFriend + ElseIf accessibility = Accessibility.Private Then + accessibility = Accessibility.ProtectedAndFriend Else - accessibility = accessibility.Protected + accessibility = Accessibility.Protected End If Case SyntaxKind.MustInheritKeyword, SyntaxKind.MustOverrideKeyword modifiers = modifiers Or DeclarationModifiers.Abstract diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator_Mef.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator_Mef.vb new file mode 100644 index 0000000000000..3b43cd1f1874f --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator_Mef.vb @@ -0,0 +1,18 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Composition +Imports Microsoft.CodeAnalysis.Editing +Imports Microsoft.CodeAnalysis.Host.Mef + +Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration + + Partial Friend Class VisualBasicSyntaxGenerator + Inherits SyntaxGenerator + + + Public Sub New() + End Sub + End Class +End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb index 31a49d00d56fd..aa4eb08068412 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions.vb @@ -368,17 +368,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return False End Function - - Public Function IsMeMyBaseOrMyClass(expression As ExpressionSyntax) As Boolean - If expression Is Nothing Then - Return False - End If - - Return expression.Kind = SyntaxKind.MeExpression OrElse - expression.Kind = SyntaxKind.MyBaseExpression OrElse - expression.Kind = SyntaxKind.MyClassExpression - End Function - Public Function IsFirstStatementInCtor(expression As ExpressionSyntax) As Boolean Dim statement = expression.FirstAncestorOrSelf(Of StatementSyntax)() diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb index 0c77ed5fb103d..c6a2b6dd875ba 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/ExpressionSyntaxExtensions_Shared.vb @@ -68,5 +68,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions (expression.IsParentKind(SyntaxKind.SimpleMemberAccessExpression) AndAlso DirectCast(expression.Parent, MemberAccessExpressionSyntax).Expression Is expression) End Function + + Public Function IsMeMyBaseOrMyClass(expression As ExpressionSyntax) As Boolean + If expression Is Nothing Then + Return False + End If + + Return expression.Kind = SyntaxKind.MeExpression OrElse + expression.Kind = SyntaxKind.MyBaseExpression OrElse + expression.Kind = SyntaxKind.MyClassExpression + End Function + End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions.vb b/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions.vb index 5b8d46ae78f48..e7df96065ce94 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions.vb @@ -8,13 +8,7 @@ Imports Microsoft.CodeAnalysis.Simplification Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions - Friend Module INamespaceOrTypeSymbolExtensions - - Public Function GenerateTypeSyntax(symbol As INamespaceOrTypeSymbol, Optional addGlobal As Boolean = True) As TypeSyntax - Return symbol.Accept(TypeSyntaxGeneratorVisitor.Create(addGlobal)).WithAdditionalAnnotations(Simplifier.Annotation) - End Function - Public Function GetAliasForSymbol(symbol As INamespaceOrTypeSymbol, node As SyntaxNode, semanticModel As SemanticModel) As IAliasSymbol ' NOTE(cyrusn): If we're in an imports clause, we can't use aliases. @@ -40,5 +34,4 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Return aliasSymbol End Function End Module - End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions_Shared.vb new file mode 100644 index 0000000000000..420cb67da57d6 --- /dev/null +++ b/src/Workspaces/VisualBasic/Portable/Extensions/INamespaceOrTypeSymbolExtensions_Shared.vb @@ -0,0 +1,17 @@ +' Licensed to the .NET Foundation under one or more agreements. +' The .NET Foundation licenses this file to you under the MIT license. +' See the LICENSE file in the project root for more information. + +Imports System.Runtime.CompilerServices +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.VisualBasic.Syntax + +Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions + Partial Friend Module INamespaceOrTypeSymbolExtensions + + Public Function GenerateTypeSyntax(symbol As INamespaceOrTypeSymbol, Optional addGlobal As Boolean = True) As TypeSyntax + Return symbol.Accept(TypeSyntaxGeneratorVisitor.Create(addGlobal)).WithAdditionalAnnotations(Simplifier.Annotation) + End Function + End Module +End Namespace From bd2640d2524a774d029b6a473137861359b76da7 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 19:14:53 -0800 Subject: [PATCH 18/21] Move files --- .../Microsoft.CodeAnalysis.CodeStyle.csproj | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index a9284670dce57..ad9ac12e58602 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -27,16 +27,16 @@ - - + + - - - + + + @@ -54,24 +54,24 @@ - - - + + + - - - - - + + + + + - - + + @@ -148,14 +148,14 @@ - - - - - - - - + + + + + + + + @@ -169,34 +169,34 @@ - - - - - - + + + + + + - + - - + + - - - - - - - - - - - + + + + + + + + + + + @@ -207,18 +207,18 @@ - - - + + + - - + + - - - - - + + + + + From 07ded019de7c2a92765ff47af4a628166cdcbc0a Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 3 Feb 2020 19:16:31 -0800 Subject: [PATCH 19/21] Move files --- .../Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj | 6 +++--- .../Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj index 333f737788489..22fe0140d7405 100644 --- a/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj +++ b/src/CodeStyle/CSharp/Analyzers/Microsoft.CodeAnalysis.CSharp.CodeStyle.csproj @@ -24,7 +24,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -79,7 +79,7 @@ - + diff --git a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj index d63d5bbe844a5..f4c1cf2d4a28e 100644 --- a/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj +++ b/src/CodeStyle/VisualBasic/Analyzers/Microsoft.CodeAnalysis.VisualBasic.CodeStyle.vbproj @@ -24,11 +24,11 @@ - - - + + + - + From 5e9a6adedeb3deb4e118769a47319f89db40f344 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 10 Feb 2020 13:45:41 -0800 Subject: [PATCH 20/21] Fix --- .../Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj index e4dd00fbcd045..d5cd8e4cc2b93 100644 --- a/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj +++ b/src/CodeStyle/Core/Analyzers/Microsoft.CodeAnalysis.CodeStyle.csproj @@ -36,7 +36,6 @@ - From aa3ca17ef11171acb4e2b5261e92f7f2c274e6f0 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 10 Feb 2020 14:04:23 -0800 Subject: [PATCH 21/21] Merge --- .../CSharpSyntaxFactsService.cs | 1 - .../VisualBasicSyntaxGenerator.vb | 2 +- .../Extensions/SyntaxNodeExtensions_Shared.vb | 110 ++++++++++++++++ ...yntaxNodeExtensions_SharedWithCodeStyle.vb | 120 ------------------ .../VisualBasicSyntaxFactsService.vb | 1 - 5 files changed, 111 insertions(+), 123 deletions(-) delete mode 100644 src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.vb diff --git a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs index 050ea2e9edcd3..988e4f7548a03 100644 --- a/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs +++ b/src/Workspaces/CSharp/Portable/LanguageServices/CSharpSyntaxFactsService.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Text; using System.Threading; -using Microsoft.CodeAnalysis.CSharp.CodeGeneration; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; using Microsoft.CodeAnalysis.CSharp.LanguageServices; diff --git a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb index f397ceeff1e2f..47f47d49024f5 100644 --- a/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb +++ b/src/Workspaces/VisualBasic/Portable/CodeGeneration/VisualBasicSyntaxGenerator.vb @@ -1649,7 +1649,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration End Function Public Overrides Function GetAttributes(declaration As SyntaxNode) As IReadOnlyList(Of SyntaxNode) - Return Me.Flatten(GetAttributeLists(declaration)) + Return Me.Flatten(declaration.GetAttributeLists()) End Function Public Overrides Function InsertAttributes(declaration As SyntaxNode, index As Integer, attributes As IEnumerable(Of SyntaxNode)) As SyntaxNode diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb index 00fc8fc7acf37..a891113c19579 100644 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb +++ b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_Shared.vb @@ -432,5 +432,115 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions Select(Function(s) s.Parent) End Function + + + Public Function GetAttributeLists(node As SyntaxNode) As SyntaxList(Of AttributeListSyntax) + Select Case node.Kind + Case SyntaxKind.CompilationUnit + Return SyntaxFactory.List(DirectCast(node, CompilationUnitSyntax).Attributes.SelectMany(Function(s) s.AttributeLists)) + Case SyntaxKind.ClassBlock + Return DirectCast(node, ClassBlockSyntax).BlockStatement.AttributeLists + Case SyntaxKind.ClassStatement + Return DirectCast(node, ClassStatementSyntax).AttributeLists + Case SyntaxKind.StructureBlock + Return DirectCast(node, StructureBlockSyntax).BlockStatement.AttributeLists + Case SyntaxKind.StructureStatement + Return DirectCast(node, StructureStatementSyntax).AttributeLists + Case SyntaxKind.InterfaceBlock + Return DirectCast(node, InterfaceBlockSyntax).BlockStatement.AttributeLists + Case SyntaxKind.InterfaceStatement + Return DirectCast(node, InterfaceStatementSyntax).AttributeLists + Case SyntaxKind.EnumBlock + Return DirectCast(node, EnumBlockSyntax).EnumStatement.AttributeLists + Case SyntaxKind.EnumStatement + Return DirectCast(node, EnumStatementSyntax).AttributeLists + Case SyntaxKind.EnumMemberDeclaration + Return DirectCast(node, EnumMemberDeclarationSyntax).AttributeLists + Case SyntaxKind.DelegateFunctionStatement, + SyntaxKind.DelegateSubStatement + Return DirectCast(node, DelegateStatementSyntax).AttributeLists + Case SyntaxKind.FieldDeclaration + Return DirectCast(node, FieldDeclarationSyntax).AttributeLists + Case SyntaxKind.FunctionBlock, + SyntaxKind.SubBlock, + SyntaxKind.ConstructorBlock + Return DirectCast(node, MethodBlockBaseSyntax).BlockStatement.AttributeLists + Case SyntaxKind.FunctionStatement, + SyntaxKind.SubStatement + Return DirectCast(node, MethodStatementSyntax).AttributeLists + Case SyntaxKind.SubNewStatement + Return DirectCast(node, SubNewStatementSyntax).AttributeLists + Case SyntaxKind.Parameter + Return DirectCast(node, ParameterSyntax).AttributeLists + Case SyntaxKind.PropertyBlock + Return DirectCast(node, PropertyBlockSyntax).PropertyStatement.AttributeLists + Case SyntaxKind.PropertyStatement + Return DirectCast(node, PropertyStatementSyntax).AttributeLists + Case SyntaxKind.OperatorBlock + Return DirectCast(node, OperatorBlockSyntax).BlockStatement.AttributeLists + Case SyntaxKind.OperatorStatement + Return DirectCast(node, OperatorStatementSyntax).AttributeLists + Case SyntaxKind.EventBlock + Return DirectCast(node, EventBlockSyntax).EventStatement.AttributeLists + Case SyntaxKind.EventStatement + Return DirectCast(node, EventStatementSyntax).AttributeLists + Case SyntaxKind.GetAccessorBlock, + SyntaxKind.SetAccessorBlock, + SyntaxKind.AddHandlerAccessorBlock, + SyntaxKind.RemoveHandlerAccessorBlock, + SyntaxKind.RaiseEventAccessorBlock + Return DirectCast(node, AccessorBlockSyntax).AccessorStatement.AttributeLists + Case SyntaxKind.GetAccessorStatement, + SyntaxKind.SetAccessorStatement, + SyntaxKind.AddHandlerAccessorStatement, + SyntaxKind.RemoveHandlerAccessorStatement, + SyntaxKind.RaiseEventAccessorStatement + Return DirectCast(node, AccessorStatementSyntax).AttributeLists + Case Else + Return Nothing + End Select + End Function + + + Public Function GetParameterList(declaration As SyntaxNode) As ParameterListSyntax + Select Case declaration.Kind + Case SyntaxKind.SubBlock, + SyntaxKind.FunctionBlock + Return DirectCast(declaration, MethodBlockSyntax).BlockStatement.ParameterList + Case SyntaxKind.ConstructorBlock + Return DirectCast(declaration, ConstructorBlockSyntax).BlockStatement.ParameterList + Case SyntaxKind.OperatorBlock + Return DirectCast(declaration, OperatorBlockSyntax).BlockStatement.ParameterList + Case SyntaxKind.SubStatement, + SyntaxKind.FunctionStatement + Return DirectCast(declaration, MethodStatementSyntax).ParameterList + Case SyntaxKind.SubNewStatement + Return DirectCast(declaration, SubNewStatementSyntax).ParameterList + Case SyntaxKind.OperatorStatement + Return DirectCast(declaration, OperatorStatementSyntax).ParameterList + Case SyntaxKind.DeclareSubStatement, + SyntaxKind.DeclareFunctionStatement + Return DirectCast(declaration, DeclareStatementSyntax).ParameterList + Case SyntaxKind.DelegateSubStatement, + SyntaxKind.DelegateFunctionStatement + Return DirectCast(declaration, DelegateStatementSyntax).ParameterList + Case SyntaxKind.PropertyBlock + Return DirectCast(declaration, PropertyBlockSyntax).PropertyStatement.ParameterList + Case SyntaxKind.PropertyStatement + Return DirectCast(declaration, PropertyStatementSyntax).ParameterList + Case SyntaxKind.EventBlock + Return DirectCast(declaration, EventBlockSyntax).EventStatement.ParameterList + Case SyntaxKind.EventStatement + Return DirectCast(declaration, EventStatementSyntax).ParameterList + Case SyntaxKind.MultiLineFunctionLambdaExpression, + SyntaxKind.MultiLineSubLambdaExpression + Return DirectCast(declaration, MultiLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList + Case SyntaxKind.SingleLineFunctionLambdaExpression, + SyntaxKind.SingleLineSubLambdaExpression + Return DirectCast(declaration, SingleLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList + Case Else + Return Nothing + End Select + End Function End Module End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.vb b/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.vb deleted file mode 100644 index 0f35fbcca9a2b..0000000000000 --- a/src/Workspaces/VisualBasic/Portable/Extensions/SyntaxNodeExtensions_SharedWithCodeStyle.vb +++ /dev/null @@ -1,120 +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. - -Imports System.Runtime.CompilerServices -Imports Microsoft.CodeAnalysis.VisualBasic.Syntax - -Namespace Microsoft.CodeAnalysis.VisualBasic.Extensions - Partial Friend Module SyntaxNodeExtensions - - Public Function GetAttributeLists(node As SyntaxNode) As SyntaxList(Of AttributeListSyntax) - Select Case node.Kind - Case SyntaxKind.CompilationUnit - Return SyntaxFactory.List(DirectCast(node, CompilationUnitSyntax).Attributes.SelectMany(Function(s) s.AttributeLists)) - Case SyntaxKind.ClassBlock - Return DirectCast(node, ClassBlockSyntax).BlockStatement.AttributeLists - Case SyntaxKind.ClassStatement - Return DirectCast(node, ClassStatementSyntax).AttributeLists - Case SyntaxKind.StructureBlock - Return DirectCast(node, StructureBlockSyntax).BlockStatement.AttributeLists - Case SyntaxKind.StructureStatement - Return DirectCast(node, StructureStatementSyntax).AttributeLists - Case SyntaxKind.InterfaceBlock - Return DirectCast(node, InterfaceBlockSyntax).BlockStatement.AttributeLists - Case SyntaxKind.InterfaceStatement - Return DirectCast(node, InterfaceStatementSyntax).AttributeLists - Case SyntaxKind.EnumBlock - Return DirectCast(node, EnumBlockSyntax).EnumStatement.AttributeLists - Case SyntaxKind.EnumStatement - Return DirectCast(node, EnumStatementSyntax).AttributeLists - Case SyntaxKind.EnumMemberDeclaration - Return DirectCast(node, EnumMemberDeclarationSyntax).AttributeLists - Case SyntaxKind.DelegateFunctionStatement, - SyntaxKind.DelegateSubStatement - Return DirectCast(node, DelegateStatementSyntax).AttributeLists - Case SyntaxKind.FieldDeclaration - Return DirectCast(node, FieldDeclarationSyntax).AttributeLists - Case SyntaxKind.FunctionBlock, - SyntaxKind.SubBlock, - SyntaxKind.ConstructorBlock - Return DirectCast(node, MethodBlockBaseSyntax).BlockStatement.AttributeLists - Case SyntaxKind.FunctionStatement, - SyntaxKind.SubStatement - Return DirectCast(node, MethodStatementSyntax).AttributeLists - Case SyntaxKind.SubNewStatement - Return DirectCast(node, SubNewStatementSyntax).AttributeLists - Case SyntaxKind.Parameter - Return DirectCast(node, ParameterSyntax).AttributeLists - Case SyntaxKind.PropertyBlock - Return DirectCast(node, PropertyBlockSyntax).PropertyStatement.AttributeLists - Case SyntaxKind.PropertyStatement - Return DirectCast(node, PropertyStatementSyntax).AttributeLists - Case SyntaxKind.OperatorBlock - Return DirectCast(node, OperatorBlockSyntax).BlockStatement.AttributeLists - Case SyntaxKind.OperatorStatement - Return DirectCast(node, OperatorStatementSyntax).AttributeLists - Case SyntaxKind.EventBlock - Return DirectCast(node, EventBlockSyntax).EventStatement.AttributeLists - Case SyntaxKind.EventStatement - Return DirectCast(node, EventStatementSyntax).AttributeLists - Case SyntaxKind.GetAccessorBlock, - SyntaxKind.SetAccessorBlock, - SyntaxKind.AddHandlerAccessorBlock, - SyntaxKind.RemoveHandlerAccessorBlock, - SyntaxKind.RaiseEventAccessorBlock - Return DirectCast(node, AccessorBlockSyntax).AccessorStatement.AttributeLists - Case SyntaxKind.GetAccessorStatement, - SyntaxKind.SetAccessorStatement, - SyntaxKind.AddHandlerAccessorStatement, - SyntaxKind.RemoveHandlerAccessorStatement, - SyntaxKind.RaiseEventAccessorStatement - Return DirectCast(node, AccessorStatementSyntax).AttributeLists - Case Else - Return Nothing - End Select - End Function - - - Public Function GetParameterList(declaration As SyntaxNode) As ParameterListSyntax - Select Case declaration.Kind - Case SyntaxKind.SubBlock, - SyntaxKind.FunctionBlock - Return DirectCast(declaration, MethodBlockSyntax).BlockStatement.ParameterList - Case SyntaxKind.ConstructorBlock - Return DirectCast(declaration, ConstructorBlockSyntax).BlockStatement.ParameterList - Case SyntaxKind.OperatorBlock - Return DirectCast(declaration, OperatorBlockSyntax).BlockStatement.ParameterList - Case SyntaxKind.SubStatement, - SyntaxKind.FunctionStatement - Return DirectCast(declaration, MethodStatementSyntax).ParameterList - Case SyntaxKind.SubNewStatement - Return DirectCast(declaration, SubNewStatementSyntax).ParameterList - Case SyntaxKind.OperatorStatement - Return DirectCast(declaration, OperatorStatementSyntax).ParameterList - Case SyntaxKind.DeclareSubStatement, - SyntaxKind.DeclareFunctionStatement - Return DirectCast(declaration, DeclareStatementSyntax).ParameterList - Case SyntaxKind.DelegateSubStatement, - SyntaxKind.DelegateFunctionStatement - Return DirectCast(declaration, DelegateStatementSyntax).ParameterList - Case SyntaxKind.PropertyBlock - Return DirectCast(declaration, PropertyBlockSyntax).PropertyStatement.ParameterList - Case SyntaxKind.PropertyStatement - Return DirectCast(declaration, PropertyStatementSyntax).ParameterList - Case SyntaxKind.EventBlock - Return DirectCast(declaration, EventBlockSyntax).EventStatement.ParameterList - Case SyntaxKind.EventStatement - Return DirectCast(declaration, EventStatementSyntax).ParameterList - Case SyntaxKind.MultiLineFunctionLambdaExpression, - SyntaxKind.MultiLineSubLambdaExpression - Return DirectCast(declaration, MultiLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList - Case SyntaxKind.SingleLineFunctionLambdaExpression, - SyntaxKind.SingleLineSubLambdaExpression - Return DirectCast(declaration, SingleLineLambdaExpressionSyntax).SubOrFunctionHeader.ParameterList - Case Else - Return Nothing - End Select - End Function - End Module -End Namespace diff --git a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb index ea2b68c8c485d..0578fa5f4a9a5 100644 --- a/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb +++ b/src/Workspaces/VisualBasic/Portable/LanguageServices/VisualBasicSyntaxFactsService.vb @@ -9,7 +9,6 @@ Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text -Imports Microsoft.CodeAnalysis.VisualBasic.CodeGeneration Imports Microsoft.CodeAnalysis.VisualBasic.Extensions.ContextQuery Imports Microsoft.CodeAnalysis.VisualBasic.LanguageServices Imports Microsoft.CodeAnalysis.VisualBasic.Syntax