Skip to content

Commit

Permalink
F# Shim - Round 2 (#35591)
Browse files Browse the repository at this point in the history
* Added fsharp shims over document diagnostic analyzers

* Added shims for completion and sig help. Also added tests.

* Moved around internal files. Added shim over InlineRenameService.

* Starting shim over document highlights service. Added a better way to handle diagnostics

* Added shim for document highlights service

* Added IFSharpDocumentNavigationService

* Added IFSharpGoToDefinitionService

* Added IFSharpNavigationBarItemService

* Added IFSharpNavigateToSearchService

* Added extra glyph case

* Added FSharpGlyphTags

* Added FSharpCommentSelectionService

* Some cleanup. Added FSharpBlockStructureService

* Added some simple statics

* Finishing the last of shims

* Getting analyzers to work

* Remove folder

* Changes due to feedback

* Fixing build

* Still trying to fix build

* Fixed guid

* Fixing build again
  • Loading branch information
TIHan authored Jun 11, 2019
1 parent 9948e3d commit 0d44ad1
Show file tree
Hide file tree
Showing 105 changed files with 6,354 additions and 650 deletions.
7 changes: 7 additions & 0 deletions Roslyn.sln
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Exte
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.VisualStudio.Setup.ServiceHub", "src\Setup\DevDivVsix\ServiceHubConfig\Roslyn.VisualStudio.Setup.ServiceHub.csproj", "{3D33BBFD-EC63-4E8C-A714-0A48A3809A87}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests", "src\Tools\ExternalAccess\FSharpTest\Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests.csproj", "{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.Apex", "src\Tools\ExternalAccess\Apex\Microsoft.CodeAnalysis.ExternalAccess.Apex.csproj", "{FC32EF16-31B1-47B3-B625-A80933CB3F29}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.ExternalAccess.CodeLens", "src\Tools\ExternalAccess\CodeLens\Microsoft.CodeAnalysis.ExternalAccess.CodeLens.csproj", "{D5B1328C-A9EF-4E55-93D7-B8455855709A}"
Expand Down Expand Up @@ -1081,6 +1083,10 @@ Global
{3D33BBFD-EC63-4E8C-A714-0A48A3809A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D33BBFD-EC63-4E8C-A714-0A48A3809A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D33BBFD-EC63-4E8C-A714-0A48A3809A87}.Release|Any CPU.Build.0 = Release|Any CPU
{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5}.Release|Any CPU.Build.0 = Release|Any CPU
{FC32EF16-31B1-47B3-B625-A80933CB3F29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC32EF16-31B1-47B3-B625-A80933CB3F29}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC32EF16-31B1-47B3-B625-A80933CB3F29}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -1294,6 +1300,7 @@ Global
{FA51A3CB-5174-4D99-B76E-DC31C5361DF3} = {8977A560-45C2-4EC2-A849-97335B382C74}
{DE53934B-7FC1-48A0-85AB-C519FBBD02CF} = {8977A560-45C2-4EC2-A849-97335B382C74}
{3D33BBFD-EC63-4E8C-A714-0A48A3809A87} = {BE25E872-1667-4649-9D19-96B83E75A44E}
{BFFB5CAE-33B5-447E-9218-BDEBFDA96CB5} = {8977A560-45C2-4EC2-A849-97335B382C74}
{FC32EF16-31B1-47B3-B625-A80933CB3F29} = {8977A560-45C2-4EC2-A849-97335B382C74}
{D5B1328C-A9EF-4E55-93D7-B8455855709A} = {8977A560-45C2-4EC2-A849-97335B382C74}
{BDB3414C-35F8-4E2D-8603-DE9CF259540F} = {8977A560-45C2-4EC2-A849-97335B382C74}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.VisualBasic" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Remote.ServiceHub" />
<InternalsVisibleTo Include="FSharp.Editor" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.IntegrationTest.Utilities" />
<InternalsVisibleTo Include="Roslyn.Services.Test.Utilities" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.EditorFeatures.UnitTests" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
<InternalsVisibleTo Include="Roslyn.VisualStudio.DiagnosticsWindow" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Remote.ServiceHub" />
<InternalsVisibleTo Include="Roslyn.Hosting.Diagnostics" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<!-- BEGIN MONODEVELOP
These MonoDevelop dependencies don't ship with Visual Studio, so can't break our
binary insertions and are exempted from the ExternalAccess adapter assembly policies.
Expand Down Expand Up @@ -83,6 +82,7 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.IntegrationTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Test.Utilities2" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
<!-- Eventually a bunch of these unit tests should move into Roslyn.Services.Implementation.UnitTests
and this should be removed. -->
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.TypeScript.EditorFeatures" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
Expand All @@ -99,7 +99,6 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.15.8" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.0" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.1" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="FSharp.Editor" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="$(MoqPublicKey)" LoadsWithinVisualStudio="false" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.ExternalDependencyServices" WorkItem="https://github.com/dotnet/roslyn/issues/35085" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.TypeScript.EditorFeatures" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Implementation" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.TypeScript" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
Expand All @@ -50,8 +51,6 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.0" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.1" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Xaml" />
<InternalsVisibleTo Include="FSharp.Editor" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="FSharp.LanguageService" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<!-- BEGIN MONODEVELOP
These MonoDevelop dependencies don't ship with Visual Studio, so can't break our
binary insertions and are exempted from the ExternalAccess adapter assembly policies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Test.Utilities2" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.TypeScript.EditorFeatures" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.TypeScript" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
<InternalsVisibleTo Include="Roslyn.Services.Editor.TypeScript.UnitTests" Key="$(TypeScriptKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35077" />
Expand All @@ -88,7 +89,6 @@
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.15.8" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.0" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.Remote.CSharp.16.1" Key="$(RemoteLanguageServiceKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35074" />
<InternalsVisibleTo Include="FSharp.Editor" Key="$(FSharpKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35076" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="$(MoqPublicKey)" LoadsWithinVisualStudio="false" />
<InternalsVisibleTo Include="Microsoft.Test.Apex.VisualStudio" Key="$(VisualStudioKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35081" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.Alm.Shared.CodeAnalysisClient" Key="$(VisualStudioKey)" WorkItem="https://github.com/dotnet/roslyn/issues/35086" />
Expand Down
1 change: 1 addition & 0 deletions src/Test/Utilities/Portable/Roslyn.Test.Utilities.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Workspaces.UnitTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.ExternalAccess.FSharp.UnitTests" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Compilers\Shared\CoreClrAnalyzerAssemblyLoader.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion
{
internal static class FSharpCommonCompletionItem
{
public static CompletionItem Create(
string displayText,
string displayTextSuffix,
CompletionItemRules rules,
FSharpGlyph? glyph = null,
ImmutableArray<SymbolDisplayPart> description = default,
string sortText = null,
string filterText = null,
bool showsWarningIcon = false,
ImmutableDictionary<string, string> properties = null,
ImmutableArray<string> tags = default,
string inlineDescription = null)
{
var roslynGlyph = glyph.HasValue ? FSharpGlyphHelpers.ConvertTo(glyph.Value) : (Glyph?)null;
return CommonCompletionItem.Create(
displayText, displayTextSuffix, rules, roslynGlyph, description, sortText, filterText, showsWarningIcon, properties, tags, inlineDescription);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal.Completion;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion
{
internal static class FSharpCommonCompletionProvider
{
public static CompletionProvider Create(IFSharpCommonCompletionProvider fsharpCommonCompletionProvider)
{
return new FSharpInternalCommonCompletionProvider(fsharpCommonCompletionProvider);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion
{
internal static class FSharpCommonCompletionUtilities
{
public static bool IsStartingNewWord(SourceText text, int characterPosition, Func<char, bool> isWordStartCharacter, Func<char, bool> isWordCharacter)
{
return CommonCompletionUtilities.IsStartingNewWord(text, characterPosition, isWordStartCharacter, isWordCharacter);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.ExternalAccess.FSharp.Internal;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion
{
internal class FSharpFileSystemCompletionHelper
{
private readonly FileSystemCompletionHelper _fileSystemCompletionHelper;

public FSharpFileSystemCompletionHelper(
FSharpGlyph folderGlyph,
FSharpGlyph fileGlyph,
ImmutableArray<string> searchPaths,
string baseDirectoryOpt,
ImmutableArray<string> allowableExtensions,
CompletionItemRules itemRules)
{
_fileSystemCompletionHelper =
new FileSystemCompletionHelper(
FSharpGlyphHelpers.ConvertTo(folderGlyph),
FSharpGlyphHelpers.ConvertTo(fileGlyph),
searchPaths,
baseDirectoryOpt,
allowableExtensions,
itemRules);
}

public Task<ImmutableArray<CompletionItem>> GetItemsAsync(string directoryPath, CancellationToken cancellationToken)
{
return _fileSystemCompletionHelper.GetItemsAsync(directoryPath, cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Completion
{
internal interface IFSharpCommonCompletionProvider
{
Task ProvideCompletionsAsync(CompletionContext context);

bool IsInsertionTrigger(SourceText text, int insertedCharacterPosition, OptionSet options);

Task<TextChange?> GetTextChangeAsync(
Func<CompletionItem, char?, CancellationToken, Task<TextChange?>> baseGetTextChangeAsync,
CompletionItem selectedItem,
char? ch,
CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal static class FSharpDiagnosticCustomTags
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.CodeAnalysis.Diagnostics;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal static class FSharpIDEDiagnosticIds
{
public static string SimplifyNamesDiagnosticId => IDEDiagnosticIds.SimplifyNamesDiagnosticId;
public static string RemoveUnnecessaryImportsDiagnosticId => IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal interface IFSharpDocumentDiagnosticAnalyzer
{
Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(Document document, CancellationToken cancellationToken);

Task<ImmutableArray<Diagnostic>> AnalyzeSyntaxAsync(Document document, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal interface IFSharpProjectDiagnosticAnalyzer
{
Task<ImmutableArray<Diagnostic>> AnalyzeProjectAsync(Project project, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal interface IFSharpSimplifyNameDiagnosticAnalyzer
{
Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(DiagnosticDescriptor descriptor, Document document, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal interface IFSharpUnusedDeclarationsDiagnosticAnalyzer
{
Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(DiagnosticDescriptor descriptor, Document document, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.CodeAnalysis.ExternalAccess.FSharp.Diagnostics
{
internal interface IFSharpUnusedOpensDiagnosticAnalyzer
{
Task<ImmutableArray<Diagnostic>> AnalyzeSemanticsAsync(DiagnosticDescriptor descriptor, Document document, CancellationToken cancellationToken);
}
}
Loading

0 comments on commit 0d44ad1

Please sign in to comment.