提交 4cdf4fba 编写于 作者: C CyrusNajmabadi

Merge remote-tracking branch 'upstream/master' into convertIfToSwitchOnlyForComplexCases

......@@ -11,14 +11,14 @@
<_CopyReferences>false</_CopyReferences>
<_CopyProjectReferences>false</_CopyProjectReferences>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
<OutDir>$(OutDir)Exes\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Exes\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'UnitTest'">
<PropertyGroup>
<_IsAnyUnitTest>true</_IsAnyUnitTest>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<OutDir>$(OutDir)UnitTests\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)UnitTests\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'UnitTestPortable' OR '$(RoslynProjectType)' == 'UnitTestDesktop'">
......@@ -39,21 +39,21 @@
<_IsAnyUnitTest>true</_IsAnyUnitTest>
<_IsAnyPortableUnitTest>true</_IsAnyPortableUnitTest>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
<OutDir>$(OutDir)Dlls\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Dlls\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'CompilerGeneratorTool'">
<PropertyGroup>
<_CopyReferences>false</_CopyReferences>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
<OutDir>$(OutDir)Exes\</OutDir>
<OutputPath>$(OutputPath)Exes\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'Vsix'">
<PropertyGroup>
<_CopyReferences>false</_CopyReferences>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<OutDir>$(OutDir)Vsix\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Vsix\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'DeploymentTest'">
......@@ -62,8 +62,8 @@
<PropertyGroup>
<AllowedReferenceRelatedFileExtensions>$(AllowedReferenceRelatedFileExtensions);.pdb</AllowedReferenceRelatedFileExtensions>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<OutDir Condition="'$(TargetFrameworkIdentifier)' == '.NETPortable'">$(OutDir)CoreClrTest</OutDir>
<OutDir Condition="'$(TargetFrameworkIdentifier)' != '.NETPortable'">$(OutDir)UnitTests\Portable\</OutDir>
<OutputPath Condition="'$(TargetFrameworkIdentifier)' == '.NETPortable'">$(OutputPath)CoreClrTest</OutputPath>
<OutputPath Condition="'$(TargetFrameworkIdentifier)' != '.NETPortable'">$(OutputPath)UnitTests\Portable\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == 'Custom'">
......@@ -74,19 +74,19 @@
<_CopyReferences>false</_CopyReferences>
<_CopyProjectReferences>false</_CopyProjectReferences>
<CopyNuGetImplementations>false</CopyNuGetImplementations>
<OutDir>$(OutDir)Dlls\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Dlls\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == '' AND '$(OutputType)' == 'Exe'">
<PropertyGroup>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<OutDir>$(OutDir)Exes\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Exes\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
<When Condition="'$(RoslynProjectType)' == '' AND '$(OutputType)' == 'WinExe'">
<PropertyGroup>
<CopyNuGetImplementations>true</CopyNuGetImplementations>
<OutDir>$(OutDir)Exes\$(MSBuildProjectName)\</OutDir>
<OutputPath>$(OutputPath)Exes\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
</When>
</Choose>
......@@ -114,7 +114,6 @@
</PropertyGroup>
<PropertyGroup>
<OutputPath>$(OutDir)</OutputPath>
<RoslynPublicKey>0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9</RoslynPublicKey>
<RoslynInternalKey>002400000480000094000000060200000024000052534131000400000100010055e0217eb635f69281051f9a823e0c7edd90f28063eb6c7a742a19b4f6139778ee0af438f47aed3b6e9f99838aa8dba689c7a71ddb860c96d923830b57bbd5cd6119406ddb9b002cf1c723bf272d6acbb7129e9d6dd5a5309c94e0ff4b2c884d45a55f475cd7dba59198086f61f5a8c8b5e601c0edbf269733f6f578fc8579c2</RoslynInternalKey>
......
......@@ -27,7 +27,7 @@
<SignAssembly>true</SignAssembly>
<UseRoslynAnalyzers Condition="'$(UseRoslynAnalyzers)' == ''">true</UseRoslynAnalyzers>
<BaseOutputPath Condition="'$(BaseOutputPath)' == ''">$(RepoRoot)Binaries\</BaseOutputPath>
<OutDir>$(BaseOutputPath)$(Configuration)\</OutDir>
<OutputPath>$(BaseOutputPath)$(Configuration)\</OutputPath>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)' == ''">$(RepoRoot)Binaries\Obj\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\$(MSBuildProjectName)\</IntermediateOutputPath>
......@@ -47,7 +47,7 @@
<MinimumVisualStudioVersion>$(VisualStudioVersion)</MinimumVisualStudioVersion>
<!-- Disable AppX packaging for the Roslyn source. Not setting this to false has the side effect
that any builds of portable projects end up in a sub folder of $(OutDir). Search for this flag in
that any builds of portable projects end up in a sub folder of $(OutputPath). Search for this flag in
Microsoft.Common.CurrentVersion.targets to see how it is consumed -->
<WindowsAppContainer>false</WindowsAppContainer>
......
......@@ -4,6 +4,7 @@ param (
[switch]$build = $false,
[switch]$restore = $false,
[switch]$test = $false,
[switch]$test64 = $false,
[switch]$clean = $false,
[switch]$clearPackageCache = $false,
[string]$project = "",
......@@ -17,7 +18,8 @@ function Print-Usage() {
Write-Host "Build.ps1"
Write-Host "`t-build Run a build operation (default false)"
Write-Host "`t-restore Run a restore operation (default false)"
Write-Host "`t-test Run tests (default false)"
Write-Host "`t-test Run unit tests (default false)"
Write-Host "`t-test64 Run unit tests in 64 bit mode"
Write-Host "`t-clean Do a clean build / restore (default false)"
Write-Host "`t-clearPackageCache Clear package cache before restoring"
Write-Host "`t-project <path> Project the build or restore should target"
......@@ -38,7 +40,11 @@ function Run-Build() {
function Run-Test() {
$proj = Join-Path $repoDir "BuildAndTest.proj"
Exec-Command $msbuild "/v:m /p:SkipCoreClr=true /t:Test $proj" | Out-Host
$args = "/v:m /p:SkipCoreClr=true /p:ManualTest=true /t:Test $proj"
if ($test64) {
$args += " /p:Test64=true"
}
Exec-Command $msbuild $args | Out-Host
}
try {
......@@ -68,7 +74,7 @@ try {
Run-Build
}
if ($test) {
if ($test -or $test64) {
Run-Test
}
}
......
......@@ -4066,7 +4066,7 @@ public class Test
// TODO...
}
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18800")]
[Fact]
public void CS0306ERR_BadTypeArgument01()
{
var source =
......
......@@ -3820,6 +3820,81 @@ static void G(out object o)
parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)]
[WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")]
public async Task TestMemberOfBuiltInType1()
{
await TestAsync(
@"using System;
class C
{
void Main()
{
[|UInt32|] value = UInt32.MaxValue;
}
}",
@"using System;
class C
{
void Main()
{
uint value = UInt32.MaxValue;
}
}",
parseOptions: CSharpParseOptions.Default,
options: PreferIntrinsicTypeInDeclaration);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)]
[WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")]
public async Task TestMemberOfBuiltInType2()
{
await TestAsync(
@"using System;
class C
{
void Main()
{
UInt32 value = [|UInt32|].MaxValue;
}
}",
@"using System;
class C
{
void Main()
{
UInt32 value = uint.MaxValue;
}
}",
parseOptions: CSharpParseOptions.Default,
options: PreferIntrinsicTypeInMemberAccess);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)]
[WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")]
public async Task TestMemberOfBuiltInType3()
{
await TestAsync(
@"using System;
class C
{
void Main()
{
[|UInt32|].Parse(""foo"");
}
}",
@"using System;
class C
{
void Main()
{
uint.Parse(""foo"");
}
}",
parseOptions: CSharpParseOptions.Default,
options: PreferIntrinsicTypeInMemberAccess);
}
private async Task TestWithPredefinedTypeOptionsAsync(string code, string expected, int index = 0)
{
await TestInRegularAndScriptAsync(code, expected, index: index, options: PreferIntrinsicTypeEverywhere);
......
......@@ -1552,5 +1552,38 @@ public override void M2<T>(T? i = null)
}
}");
}
[WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")]
[WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
public async Task TestAutoProperties()
{
await TestInRegularAndScript1Async(
@"abstract class AbstractClass
{
public abstract int ReadOnlyProp { get; }
public abstract int ReadWriteProp { get; set; }
public abstract int WriteOnlyProp { set; }
}
class [|C|] : AbstractClass
{
}",
@"abstract class AbstractClass
{
public abstract int ReadOnlyProp { get; }
public abstract int ReadWriteProp { get; set; }
public abstract int WriteOnlyProp { set; }
}
class C : AbstractClass
{
public override int ReadOnlyProp { get; }
public override int ReadWriteProp { get; set; }
public override int WriteOnlyProp { set => throw new System.NotImplementedException(); }
}", parameters: new TestParameters(options: Option(
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)));
}
}
}
\ No newline at end of file
......@@ -3,7 +3,6 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.ImplementInterface;
......@@ -6705,5 +6704,40 @@ class C : I
}
}");
}
[WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")]
[WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)]
public async Task TestAutoProperties()
{
await TestInRegularAndScript1Async(
@"interface IInterface
{
int ReadOnlyProp { get; }
int ReadWriteProp { get; set; }
int WriteOnlyProp { set; }
}
class Class : [|IInterface|]
{
}",
@"interface IInterface
{
int ReadOnlyProp { get; }
int ReadWriteProp { get; set; }
int WriteOnlyProp { set; }
}
class Class : IInterface
{
public int ReadOnlyProp { get; }
public int ReadWriteProp { get; set; }
public int WriteOnlyProp { set => throw new System.NotImplementedException(); }
}", parameters: new TestParameters(options: Option(
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)));
}
}
}
\ No newline at end of file
......@@ -105,6 +105,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="FindUsages\AbstractFindUsagesService.cs" />
<Compile Include="FindUsages\AbstractFindUsagesService.DefinitionTrackingContext.cs" />
<Compile Include="FindUsages\FindUsagesHelpers.cs" />
<Compile Include="FindUsages\FindUsagesContext.cs" />
<Compile Include="FindUsages\IDefinitionsAndReferencesFactory.cs" />
......
// 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.Generic;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal abstract partial class AbstractFindUsagesService
{
/// <summary>
/// Forwards <see cref="IFindUsagesContext"/> notifications to an underlying <see cref="IFindUsagesContext"/>
/// while also keeping track of the <see cref="DefinitionItem"/> definitions reported.
///
/// These can then be used by <see cref="GetThirdPartyDefinitions"/> to report the
/// definitions found to third parties in case they want to add any additional definitions
/// to the results we present.
/// </summary>
private class DefinitionTrackingContext : IFindUsagesContext
{
private readonly IFindUsagesContext _underlyingContext;
private readonly object _gate = new object();
private readonly List<DefinitionItem> _definitions = new List<DefinitionItem>();
public DefinitionTrackingContext(IFindUsagesContext underlyingContext)
{
_underlyingContext = underlyingContext;
}
public CancellationToken CancellationToken
=> _underlyingContext.CancellationToken;
public void ReportMessage(string message)
=> _underlyingContext.ReportMessage(message);
public void SetSearchTitle(string title)
=> _underlyingContext.SetSearchTitle(title);
public Task OnReferenceFoundAsync(SourceReferenceItem reference)
=> _underlyingContext.OnReferenceFoundAsync(reference);
public Task ReportProgressAsync(int current, int maximum)
=> _underlyingContext.ReportProgressAsync(current, maximum);
public Task OnDefinitionFoundAsync(DefinitionItem definition)
{
lock (_gate)
{
_definitions.Add(definition);
}
return _underlyingContext.OnDefinitionFoundAsync(definition);
}
public ImmutableArray<DefinitionItem> GetDefinitions()
{
lock (_gate)
{
return _definitions.ToImmutableArray();
}
}
}
}
}
\ No newline at end of file
......@@ -2,7 +2,6 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
......@@ -15,6 +14,10 @@ namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal abstract partial class AbstractFindUsagesService
{
/// <summary>
/// Forwards <see cref="IStreamingFindLiteralReferencesProgress"/> calls to an
/// <see cref="IFindUsagesContext"/> instance.
/// </summary>
private class FindLiteralsProgressAdapter : IStreamingFindLiteralReferencesProgress
{
private readonly IFindUsagesContext _context;
......@@ -73,7 +76,7 @@ public FindReferencesProgressAdapter(Solution solution, IFindUsagesContext conte
public Task OnFindInDocumentCompletedAsync(Document document) => SpecializedTasks.EmptyTask;
// Simple context forwarding functions.
public Task ReportProgressAsync(int current, int maximum) =>
public Task ReportProgressAsync(int current, int maximum) =>
_context.ReportProgressAsync(current, maximum);
// More complicated forwarding functions. These need to map from the symbols
......@@ -106,22 +109,6 @@ public async Task OnReferenceFoundAsync(SymbolAndProjectId definition, Reference
await _context.OnReferenceFoundAsync(referenceItem).ConfigureAwait(false);
}
}
public async Task CallThirdPartyExtensionsAsync(CancellationToken cancellationToken)
{
var factory = _solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
foreach (var definition in _definitionToItem.Keys)
{
var item = factory.GetThirdPartyDefinitionItem(
_solution, definition, cancellationToken);
if (item != null)
{
// ConfigureAwait(true) because we want to come back on the
// same thread after calling into extensions.
await _context.OnDefinitionFoundAsync(item).ConfigureAwait(true);
}
}
}
}
}
}
\ No newline at end of file
// 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
......@@ -44,36 +47,60 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
public async Task FindReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
// NOTE: All ConFigureAwaits in this method need to pass 'true' so that
// we return to the caller's context. that's so the call to
// CallThirdPartyExtensionsAsync will happen on the UI thread. We need
// this to maintain the threading guarantee we had around that method
// from pre-Roslyn days.
var cancellationToken = context.CancellationToken;
cancellationToken.ThrowIfCancellationRequested();
var definitionTrackingContext = new DefinitionTrackingContext(context);
// Need ConfigureAwait(true) here so we get back to the UI thread before calling
// GetThirdPartyDefinitions. We need to call that on the UI thread to match behavior
// of how the language service always worked in the past.
//
// Any async calls before GetThirdPartyDefinitions must be ConfigureAwait(true).
await FindLiteralOrSymbolReferencesAsync(
document, position, definitionTrackingContext).ConfigureAwait(true);
// After the FAR engine is done call into any third party extensions to see
// if they want to add results.
var thirdPartyDefinitions = GetThirdPartyDefinitions(
document.Project.Solution, definitionTrackingContext.GetDefinitions(), context.CancellationToken);
// From this point on we can do ConfigureAwait(false) as we're not calling back
// into third parties anymore.
foreach (var definition in thirdPartyDefinitions)
{
// Don't need ConfigureAwait(true) here
await context.OnDefinitionFoundAsync(definition).ConfigureAwait(false);
}
}
private async Task FindLiteralOrSymbolReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
// First, see if we're on a literal. If so search for literals in the solution with
// the same value.
var found = await TryFindLiteralReferencesAsync(document, position, context).ConfigureAwait(true);
var found = await TryFindLiteralReferencesAsync(
document, position, context).ConfigureAwait(false);
if (found)
{
return;
}
var findReferencesProgress = await FindSymbolReferencesAsync(
document, position, context).ConfigureAwait(true);
if (findReferencesProgress == null)
{
return;
}
// Wasn't a literal. Try again as a symbol.
await FindSymbolReferencesAsync(
document, position, context).ConfigureAwait(false);
}
// After the FAR engine is done call into any third party extensions to see
// if they want to add results.
await findReferencesProgress.CallThirdPartyExtensionsAsync(
context.CancellationToken).ConfigureAwait(true);
private ImmutableArray<DefinitionItem> GetThirdPartyDefinitions(
Solution solution,
ImmutableArray<DefinitionItem> definitions,
CancellationToken cancellationToken)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
return definitions.Select(d => factory.GetThirdPartyDefinitionItem(solution, d, cancellationToken))
.WhereNotNull()
.ToImmutableArray();
}
private async Task<FindReferencesProgressAdapter> FindSymbolReferencesAsync(
private async Task FindSymbolReferencesAsync(
Document document, int position, IFindUsagesContext context)
{
var cancellationToken = context.CancellationToken;
......@@ -84,12 +111,20 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
document, position, cancellationToken).ConfigureAwait(false);
if (symbolAndProject == null)
{
return null;
return;
}
var symbol = symbolAndProject?.symbol;
var project = symbolAndProject?.project;
await FindSymbolReferencesAsync(
context, symbolAndProject?.symbol, symbolAndProject?.project, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Public helper that we use from features like ObjectBrowser which start with a symbol
/// and want to push all the references to it into the Streaming-Find-References window.
/// </summary>
public static async Task FindSymbolReferencesAsync(
IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken)
{
context.SetSearchTitle(string.Format(EditorFeaturesResources._0_references,
FindUsagesHelpers.GetDisplayName(symbol)));
......@@ -105,8 +140,6 @@ public async Task FindImplementationsAsync(Document document, int position, IFin
progressAdapter,
documents: null,
cancellationToken: cancellationToken).ConfigureAwait(false);
return progressAdapter;
}
private async Task<bool> TryFindLiteralReferencesAsync(
......
// 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.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.Completion;
using Microsoft.CodeAnalysis.Features.RQName;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Editor.FindUsages
{
internal interface IDefinitionsAndReferencesFactory : IWorkspaceService
{
DefinitionsAndReferences CreateDefinitionsAndReferences(
Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols,
bool includeHiddenLocations, CancellationToken cancellationToken);
DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken);
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken);
}
[ExportWorkspaceService(typeof(IDefinitionsAndReferencesFactory)), Shared]
internal class DefaultDefinitionsAndReferencesFactory : IDefinitionsAndReferencesFactory
{
public DefinitionsAndReferences CreateDefinitionsAndReferences(
Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols,
bool includeHiddenLocations, CancellationToken cancellationToken)
{
var definitions = ArrayBuilder<DefinitionItem>.GetInstance();
var references = ArrayBuilder<SourceReferenceItem>.GetInstance();
var uniqueLocations = new HashSet<DocumentSpan>();
// Order the symbols by precedence, then create the appropriate
// definition item per symbol and all reference items for its
// reference locations.
foreach (var referencedSymbol in referencedSymbols.OrderBy(GetPrecedence))
{
ProcessReferencedSymbol(
solution, referencedSymbol, definitions, references,
includeHiddenLocations, uniqueLocations,cancellationToken);
}
return new DefinitionsAndReferences(
definitions.ToImmutableAndFree(), references.ToImmutableAndFree());
}
/// <summary>
/// Reference locations are de-duplicated across the entire find references result set
/// Order the definitions so that references to multiple definitions appear under the
/// desired definition (e.g. constructor references should prefer the constructor method
/// over the type definition). Note that this does not change the order in which
/// definitions are displayed in Find Symbol Results, it only changes which definition
/// a given reference should appear under when its location is a reference to multiple
/// definitions.
/// </summary>
private static int GetPrecedence(ReferencedSymbol referencedSymbol)
{
switch (referencedSymbol.Definition.Kind)
{
case SymbolKind.Event:
case SymbolKind.Field:
case SymbolKind.Label:
case SymbolKind.Local:
case SymbolKind.Method:
case SymbolKind.Parameter:
case SymbolKind.Property:
case SymbolKind.RangeVariable:
return 0;
case SymbolKind.ArrayType:
case SymbolKind.DynamicType:
case SymbolKind.ErrorType:
case SymbolKind.NamedType:
case SymbolKind.PointerType:
return 1;
default:
return 2;
}
}
private void ProcessReferencedSymbol(
Solution solution,
ReferencedSymbol referencedSymbol,
ArrayBuilder<DefinitionItem> definitions,
ArrayBuilder<SourceReferenceItem> references,
bool includeHiddenLocations,
HashSet<DocumentSpan> uniqueSpans,
CancellationToken cancellationToken)
{
// See if this is a symbol we even want to present to the user. If not,
// ignore it entirely (including all its reference locations).
if (!referencedSymbol.ShouldShow())
{
return;
}
var definitionItem = referencedSymbol.Definition.ToDefinitionItem(
solution, includeHiddenLocations, uniqueSpans);
definitions.Add(definitionItem);
// Now, create the SourceReferenceItems for all the reference locations
// for this definition.
CreateReferences(
referencedSymbol, references, definitionItem,
includeHiddenLocations, uniqueSpans);
// Finally, see if there are any third parties that want to add their
// own result to our collection.
var thirdPartyItem = GetThirdPartyDefinitionItem(
solution, referencedSymbol.Definition, cancellationToken);
if (thirdPartyItem != null)
{
definitions.Add(thirdPartyItem);
}
}
/// <summary>
/// Provides an extension point that allows for other workspace layers to add additional
/// results to the results found by the FindReferences engine.
/// </summary>
public virtual DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken)
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
{
return null;
}
private static void CreateReferences(
ReferencedSymbol referencedSymbol,
ArrayBuilder<SourceReferenceItem> references,
DefinitionItem definitionItem,
bool includeHiddenLocations,
HashSet<DocumentSpan> uniqueSpans)
{
foreach (var referenceLocation in referencedSymbol.Locations)
{
var sourceReferenceItem = referenceLocation.TryCreateSourceReferenceItem(
definitionItem, includeHiddenLocations);
if (sourceReferenceItem == null)
{
continue;
}
if (uniqueSpans.Add(sourceReferenceItem.SourceSpan))
{
references.Add(sourceReferenceItem);
}
}
}
}
internal static class DefinitionItemExtensions
......@@ -162,8 +39,7 @@ internal static class DefinitionItemExtensions
public static DefinitionItem ToDefinitionItem(
this ISymbol definition,
Solution solution,
bool includeHiddenLocations,
HashSet<DocumentSpan> uniqueSpans = null)
bool includeHiddenLocations)
{
// Ensure we're working with the original definition for the symbol. I.e. When we're
// creating definition items, we want to create them for types like Dictionary<TKey,TValue>
......@@ -181,7 +57,8 @@ internal static class DefinitionItemExtensions
showMetadataSymbolsWithoutReferences: false);
var sourceLocations = ArrayBuilder<DocumentSpan>.GetInstance();
ImmutableDictionary<string, string> properties = null;
var properties = GetProperties(definition);
// If it's a namespace, don't create any normal location. Namespaces
// come from many different sources, but we'll only show a single
......@@ -207,19 +84,7 @@ internal static class DefinitionItemExtensions
var document = solution.GetDocument(location.SourceTree);
if (document != null)
{
var documentLocation = new DocumentSpan(document, location.SourceSpan);
if (sourceLocations.Count == 0)
{
sourceLocations.Add(documentLocation);
}
else
{
if (uniqueSpans == null ||
uniqueSpans.Add(documentLocation))
{
sourceLocations.Add(documentLocation);
}
}
sourceLocations.Add(new DocumentSpan(document, location.SourceSpan));
}
}
}
......@@ -240,6 +105,30 @@ internal static class DefinitionItemExtensions
nameDisplayParts, properties, displayIfNoReferences);
}
private static ImmutableDictionary<string, string> GetProperties(ISymbol definition)
{
var properties = ImmutableDictionary<string, string>.Empty;
var rqName = RQNameInternal.From(definition);
if (rqName != null)
{
properties = properties.Add(DefinitionItem.RQNameKey1, rqName);
}
if (definition?.IsConstructor() == true)
{
// If the symbol being considered is a constructor include the containing type in case
// a third party wants to navigate to that.
rqName = RQNameInternal.From(definition.ContainingType);
if (rqName != null)
{
properties = properties.Add(DefinitionItem.RQNameKey2, rqName);
}
}
return properties;
}
public static SourceReferenceItem TryCreateSourceReferenceItem(
this ReferenceLocation referenceLocation,
DefinitionItem definitionItem,
......
......@@ -53,14 +53,6 @@ internal static class GoToDefinitionHelpers
symbol = definition ?? symbol;
var definitions = ArrayBuilder<DefinitionItem>.GetInstance();
if (thirdPartyNavigationAllowed)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, symbol, cancellationToken);
definitions.AddIfNotNull(thirdPartyItem);
}
// If it is a partial method declaration with no body, choose to go to the implementation
// that has a method body.
if (symbol is IMethodSymbol method)
......@@ -68,16 +60,24 @@ internal static class GoToDefinitionHelpers
symbol = method.PartialImplementationPart ?? symbol;
}
var options = project.Solution.Options;
var definitions = ArrayBuilder<DefinitionItem>.GetInstance();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
if (thirdPartyNavigationAllowed)
{
var factory = solution.Workspace.Services.GetService<IDefinitionsAndReferencesFactory>();
var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
definitions.AddIfNotNull(thirdPartyItem);
}
definitions.Add(symbol.ToDefinitionItem(solution, includeHiddenLocations: true));
definitions.Add(definitionItem);
var presenter = GetFindUsagesPresenter(streamingPresenters);
var title = string.Format(EditorFeaturesResources._0_declarations,
FindUsagesHelpers.GetDisplayName(symbol));
return presenter.TryNavigateToOrPresentItemsAsync(
title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken);
project.Solution.Workspace, title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken);
}
private static IStreamingFindUsagesPresenter GetFindUsagesPresenter(
......
......@@ -136,7 +136,7 @@ public void ExecuteCommand(GoToImplementationCommandArgs args, Action nextHandle
var definitionItems = goToImplContext.GetDefinitions();
streamingPresenter.TryNavigateToOrPresentItemsAsync(
goToImplContext.SearchTitle, definitionItems).Wait(cancellationToken);
document.Project.Solution.Workspace, goToImplContext.SearchTitle, definitionItems).Wait(cancellationToken);
}
private IStreamingFindUsagesPresenter GetStreamingPresenter()
......
......@@ -43,17 +43,17 @@ internal static class IStreamingFindUsagesPresenterExtensions
/// </summary>
public static async Task<bool> TryNavigateToOrPresentItemsAsync(
this IStreamingFindUsagesPresenter presenter,
string title, ImmutableArray<DefinitionItem> items)
Workspace workspace, string title, ImmutableArray<DefinitionItem> items)
{
// Ignore any definitions that we can't navigate to.
var definitions = items.WhereAsArray(d => d.CanNavigateTo());
var definitions = items.WhereAsArray(d => d.CanNavigateTo(workspace));
// See if there's a third party external item we can navigate to. If so, defer
// to that item and finish.
var externalItems = definitions.WhereAsArray(d => d.IsExternal);
foreach (var item in externalItems)
{
if (item.TryNavigateTo())
if (item.TryNavigateTo(workspace, isPreview: true))
{
return true;
}
......@@ -69,7 +69,7 @@ internal static class IStreamingFindUsagesPresenterExtensions
nonExternalItems[0].SourceSpans.Length <= 1)
{
// There was only one location to navigate to. Just directly go to that location.
return nonExternalItems[0].TryNavigateTo();
return nonExternalItems[0].TryNavigateTo(workspace, isPreview: true);
}
if (presenter != null)
......
......@@ -6,6 +6,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Peek;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
......@@ -59,9 +60,10 @@ private PeekableItemFactory(IMetadataAsSourceFileService metadataAsSourceFileSer
}
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
if (symbolNavigationService.WouldNavigateToSymbol(
symbol, solution, cancellationToken,
definitionItem, solution, cancellationToken,
out var filePath, out var lineNumber, out var charOffset))
{
var position = new LinePosition(lineNumber, charOffset);
......
......@@ -182,6 +182,8 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("[|Fog|]Bar", "fog", PatternMatchKind.Prefix, CaseInsensitive)]
[InlineData("[|fog|]BarFoo", "Fog", PatternMatchKind.Prefix, CaseInsensitive)]
[InlineData("[|system.ref|]lection", "system.ref", PatternMatchKind.Prefix, CaseSensitive)]
[InlineData("Fog[|B|]ar", "b", PatternMatchKind.Substring, CaseInsensitive)]
[InlineData("_[|my|]Button", "my", PatternMatchKind.Substring, CaseSensitive)]
......@@ -234,10 +236,10 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("my[|_b|]utton", "_B", PatternMatchKind.CamelCase, CaseInsensitive, PatternMatcher.CamelCaseContiguousBonus)]
[InlineData("[|_|]my_[|b|]utton", "_B", PatternMatchKind.CamelCase, CaseInsensitive, PatternMatcher.CamelCaseMatchesFromStartBonus)]
public void TryMatchSingleWordPattern(
public void TestNonFuzzyMatch(
string candidate, string pattern, int matchKindInt, bool isCaseSensitive, int? camelCaseWeight = null)
{
var match = TryMatchSingleWordPattern(candidate, pattern);
var match = TestNonFuzzyMatch(candidate, pattern);
Assert.NotNull(match);
var matchKind = (PatternMatchKind)matchKindInt;
......@@ -269,9 +271,10 @@ private void VerifyBreakIntoCharacterParts(string original, params string[] part
[InlineData("FogBarBaz", "FZ")]
[InlineData("_mybutton", "myB")]
[InlineData("FogBarChangedEventArgs", "changedeventarrrgh")]
public void TryMatchSingleWordPattern_NoMatch(string candidate, string pattern)
[InlineData("runtime.native.system", "system.reflection")]
public void TestNonFuzzyMatch_NoMatch(string candidate, string pattern)
{
var match = TryMatchSingleWordPattern(candidate, pattern);
var match = TestNonFuzzyMatch(candidate, pattern);
Assert.Null(match);
}
......@@ -470,7 +473,7 @@ public void TryMatchSingleWordPattern_CultureAwareSingleWordPreferCaseSensitiveE
try
{
var match = TryMatchSingleWordPattern("[|ioo|]", "\u0130oo"); // u0130 = Capital I with dot
var match = TestNonFuzzyMatch("[|ioo|]", "\u0130oo"); // u0130 = Capital I with dot
Assert.Equal(PatternMatchKind.Exact, match.Value.Kind);
Assert.False(match.Value.IsCaseSensitive);
......@@ -499,11 +502,15 @@ private static IList<string> BreakIntoCharacterParts(string identifier)
private static IList<string> BreakIntoWordParts(string identifier)
=> PartListToSubstrings(identifier, StringBreaker.BreakIntoWordParts(identifier));
private static PatternMatch? TryMatchSingleWordPattern(string candidate, string pattern)
private static PatternMatch? TestNonFuzzyMatch(string candidate, string pattern)
{
MarkupTestFile.GetSpans(candidate, out candidate, out ImmutableArray<TextSpan> spans);
var match = new PatternMatcher(pattern).MatchSingleWordPattern_ForTestingOnly(candidate);
var match = new PatternMatcher(pattern).GetFirstMatch(candidate, includeMatchSpans: true);
if (match?.Kind == PatternMatchKind.Fuzzy)
{
match = null;
}
if (match == null)
{
......@@ -536,4 +543,4 @@ private static IEnumerable<PatternMatch> TryMatchMultiWordPattern(string candida
}
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports System.Globalization
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Text
Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
' These tests adapted from David Kean's table at
......@@ -10,7 +11,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
Public Class CompletionRulesTests
<Fact>
Public Sub TestMatchLowerCaseEnglishI()
Dim wordsToMatch = {"index", "Index", "işte", şte"}
Dim wordsToMatch = {"[|i|]ndex", "[|I|]ndex", "[|i|]şte", "[|İ|]şte"}
Dim wordsToNotMatch = {"ırak"}
TestMatches("i", wordsToMatch)
......@@ -19,7 +20,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchDottedUpperTurkishI()
Dim wordsToMatch = {"index", "işte", şte"}
Dim wordsToMatch = {"[|i|]ndex", "[|i|]şte", "[|İ|]şte"}
Dim wordsToNotMatch = {"ırak", "Irak", "Index"}
TestMatches("İ", wordsToMatch)
......@@ -28,7 +29,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchNonDottedLowerTurkishI()
Dim wordsToMatch = {"ırak", "Irak"}
Dim wordsToMatch = {"[|ı|]rak", "[|I|]rak"}
Dim wordsToNotMatch = {"index", "işte", "İşte"}
TestMatches("ı", wordsToMatch)
......@@ -37,31 +38,48 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<Fact>
Public Sub TestMatchEnglishUpperI()
Dim wordsToMatch = {"Index", "index", "ırak", "Irak"}
' In turkish-culture "I" will not match "index". However, we want to verify that
' the underlying completion helper will fallback to doing an en-us check if the
' tr-tr check fails, and that it properly also returns the matched spans in this case.
Dim wordsToMatch = {"[|I|]ndex", "[|i|]ndex", "[|ı|]rak", "[|I|]rak"}
Dim wordsToNotMatch = {"İşte"}
TestMatches("I", wordsToMatch)
TestNotMatches("I", wordsToNotMatch)
End Sub
Private Sub TestMatches(v As String, wordsToMatch() As String)
Private Sub TestMatches(pattern As String, wordsToMatch() As String)
Dim culture = New CultureInfo("tr-TR", useUserOverride:=False)
Dim workspace = New TestWorkspace
Dim helper = CompletionHelper.GetHelper(workspace, LanguageNames.CSharp)
For Each word In wordsToMatch
For Each wordMarkup In wordsToMatch
Dim word As String = Nothing
Dim wordMatchSpan As TextSpan = Nothing
MarkupTestFile.GetSpan(wordMarkup, word, wordMatchSpan)
Dim item = CompletionItem.Create(word)
Assert.True(helper.MatchesPattern(item.FilterText, v, culture), $"Expected item {word} does not match {v}")
Assert.True(helper.MatchesPattern(item.FilterText, pattern, culture), $"Expected item {word} does not match {pattern}")
Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture)
Assert.NotEmpty(highlightedSpans)
Assert.Equal(1, highlightedSpans.Length)
Assert.Equal(wordMatchSpan, highlightedSpans(0))
Next
End Sub
Private Sub TestNotMatches(v As String, wordsToNotMatch() As String)
Private Sub TestNotMatches(pattern As String, wordsToNotMatch() As String)
Dim culture = New CultureInfo("tr-TR", useUserOverride:=False)
Dim workspace = New TestWorkspace
Dim helper = CompletionHelper.GetHelper(workspace, LanguageNames.CSharp)
For Each word In wordsToNotMatch
Dim item = CompletionItem.Create(word)
Assert.False(helper.MatchesPattern(item.FilterText, v, culture), $"Unexpected item {word} matches {v}")
Assert.False(helper.MatchesPattern(item.FilterText, pattern, culture), $"Unexpected item {word} matches {pattern}")
Dim highlightedSpans = helper.GetHighlightedSpans(item.FilterText, pattern, culture)
Assert.Empty(highlightedSpans)
Next
End Sub
End Class
......
......@@ -2,6 +2,7 @@
Imports System.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis.FindUsages
Imports Microsoft.CodeAnalysis.Host
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Navigation
......@@ -31,7 +32,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Public TrySymbolNavigationNotifyProvidedSolution As Solution
Public TrySymbolNavigationNotifyReturnValue As Boolean = False
Public WouldNavigateToSymbolProvidedSymbol As ISymbol
Public WouldNavigateToSymbolProvidedDefinitionItem As DefinitionItem
Public WouldNavigateToSymbolProvidedSolution As Solution
Public WouldNavigateToSymbolReturnValue As Boolean = False
Public NavigationFilePathReturnValue As String = String.Empty
......@@ -54,11 +55,11 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Return TrySymbolNavigationNotifyReturnValue
End Function
Public Function WouldNavigateToSymbol(symbol As ISymbol,
Public Function WouldNavigateToSymbol(definitionItem As DefinitionItem,
solution As Solution,
cancellationToken As CancellationToken,
ByRef filePath As String, ByRef lineNumber As Integer, ByRef charOffset As Integer) As Boolean Implements ISymbolNavigationService.WouldNavigateToSymbol
Me.WouldNavigateToSymbolProvidedSymbol = symbol
Me.WouldNavigateToSymbolProvidedDefinitionItem = definitionItem
Me.WouldNavigateToSymbolProvidedSolution = solution
filePath = Me.NavigationFilePathReturnValue
......
......@@ -2430,5 +2430,62 @@ End Class")
diagnosticId:=IDEDiagnosticIds.RemoveQualificationDiagnosticId,
diagnosticSeverity:=DiagnosticSeverity.Error)
End Function
<WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")>
<Fact(), Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)>
Public Async Function TestMemberOfBuiltInType1() As Task
Await TestInRegularAndScriptAsync(
"Imports System
Module Module1
Sub Main()
Dim var As [|UInt32|] = UInt32.MinValue
End Sub
End Module",
"Imports System
Module Module1
Sub Main()
Dim var As UInteger = UInt32.MinValue
End Sub
End Module",
options:=PreferIntrinsicPredefinedTypeInDeclaration())
End Function
<WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")>
<Fact(), Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)>
Public Async Function TestMemberOfBuiltInType2() As Task
Await TestInRegularAndScriptAsync(
"Imports System
Module Module1
Sub Main()
Dim var As UInt32 = [|UInt32|].MinValue
End Sub
End Module",
"Imports System
Module Module1
Sub Main()
Dim var As UInt32 = UInteger.MinValue
End Sub
End Module",
options:=PreferIntrinsicTypeInMemberAccess())
End Function
<WorkItem(15996, "https://github.com/dotnet/roslyn/issues/15996")>
<Fact(), Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)>
Public Async Function TestMemberOfBuiltInType3() As Task
Await TestInRegularAndScriptAsync(
"Imports System
Module Module1
Sub Main()
[|UInt32|].Parse(""Foo"")
End Sub
End Module",
"Imports System
Module Module1
Sub Main()
UInteger.Parse(""Foo"")
End Sub
End Module",
options:=PreferIntrinsicTypeInMemberAccess())
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.ImplementType
Imports Microsoft.CodeAnalysis.VisualBasic.ImplementAbstractClass
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementAbstractClass
......@@ -574,5 +575,42 @@ Class x
End Function
End Class")
End Function
<WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")>
<WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)>
Public Async Function TestAutoProperties() As Task
Await TestInRegularAndScript1Async(
"MustInherit Class AbstractClass
MustOverride ReadOnly Property ReadOnlyProp As Integer
MustOverride Property ReadWriteProp As Integer
MustOverride WriteOnly Property WriteOnlyProp As Integer
End Class
Class [|C|]
Inherits AbstractClass
End Class",
"MustInherit Class AbstractClass
MustOverride ReadOnly Property ReadOnlyProp As Integer
MustOverride Property ReadWriteProp As Integer
MustOverride WriteOnly Property WriteOnlyProp As Integer
End Class
Class C
Inherits AbstractClass
Public Overrides ReadOnly Property ReadOnlyProp As Integer
Public Overrides Property ReadWriteProp As Integer
Public Overrides WriteOnly Property WriteOnlyProp As Integer
Set(value As Integer)
Throw New System.NotImplementedException()
End Set
End Property
End Class", parameters:=New TestParameters(options:=[Option](
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -3,6 +3,7 @@
Imports Microsoft.CodeAnalysis.CodeFixes
Imports Microsoft.CodeAnalysis.Diagnostics
Imports Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics
Imports Microsoft.CodeAnalysis.ImplementType
Imports Microsoft.CodeAnalysis.VisualBasic.ImplementInterface
Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.ImplementInterface
......@@ -4518,5 +4519,41 @@ Namespace System
End Structure
End Namespace")
End Function
<WorkItem(13932, "https://github.com/dotnet/roslyn/issues/13932")>
<WorkItem(5898, "https://github.com/dotnet/roslyn/issues/5898")>
<Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)>
Public Async Function TestAutoProperties() As Task
Await TestInRegularAndScript1Async(
"interface IInterface
readonly property ReadOnlyProp as integer
property ReadWriteProp as integer
writeonly property WriteOnlyProp as integer
end interface
class Class
implements [|IInterface|]
end class",
"interface IInterface
readonly property ReadOnlyProp as integer
property ReadWriteProp as integer
writeonly property WriteOnlyProp as integer
end interface
class Class
implements IInterface
Public ReadOnly Property ReadOnlyProp As Integer Implements IInterface.ReadOnlyProp
Public Property ReadWriteProp As Integer Implements IInterface.ReadWriteProp
Public WriteOnly Property WriteOnlyProp As Integer Implements IInterface.WriteOnlyProp
Set(value As Integer)
Throw New System.NotImplementedException()
End Set
End Property
end class", parameters:=New TestParameters(options:=[Option](
ImplementTypeOptions.PropertyGenerationBehavior,
ImplementTypePropertyGenerationBehavior.PreferAutoProperties)))
End Function
End Class
End Namespace
\ No newline at end of file
......@@ -112,7 +112,7 @@ public bool MatchesPattern(string text, string pattern, CultureInfo culture)
if (!culture.Equals(EnUSCultureInfo))
{
patternMatcher = this.GetPatternMatcher(pattern, EnUSCultureInfo);
match = patternMatcher.GetFirstMatch(completionItemText);
match = patternMatcher.GetFirstMatch(completionItemText, includeMatchSpans);
if (match != null)
{
return match;
......
......@@ -52,13 +52,13 @@ public static bool CanNavigateTo(this DocumentSpan documentSpan)
return service.CanNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan);
}
public static bool TryNavigateTo(this DocumentSpan documentSpan)
public static bool TryNavigateTo(this DocumentSpan documentSpan, bool isPreview)
{
var solution = documentSpan.Document.Project.Solution;
var workspace = solution.Workspace;
var service = workspace.Services.GetService<IDocumentNavigationService>();
return service.TryNavigateToSpan(workspace, documentSpan.Document.Id, documentSpan.SourceSpan,
options: solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true));
options: solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, isPreview));
}
public static async Task<bool> IsHiddenAsync(
......
......@@ -396,8 +396,6 @@
<Compile Include="DocumentSpan.cs" />
<Compile Include="FindUsages\DefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.DocumentLocationDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.NonNavigatingDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionItem.SymbolDefinitionItem.cs" />
<Compile Include="FindUsages\DefinitionsAndReferences.cs" />
<Compile Include="FindUsages\SourceReferenceItem.cs" />
<Compile Include="Diagnostics\EngineV2\DiagnosticAnalyzerExecutor.cs" />
......
// 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.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
......@@ -11,25 +17,111 @@ internal partial class DefinitionItem
/// <see cref="DocumentSpan"/>.
/// </summary>
// internal for testing purposes.
internal sealed class DocumentLocationDefinitionItem : DefinitionItem
internal sealed class DefaultDefinitionItem : DefinitionItem
{
internal override bool IsExternal => false;
public DocumentLocationDefinitionItem(
public DefaultDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableArray<DocumentSpan> sourceSpans,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, nameDisplayParts,
ImmutableArray.Create(new TaggedText(TextTags.Text, sourceSpans[0].Document.Project.Name)),
: base(tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences)
{
}
public override bool CanNavigateTo() => SourceSpans[0].CanNavigateTo();
public override bool TryNavigateTo() => SourceSpans[0].TryNavigateTo();
public override bool CanNavigateTo(Workspace workspace)
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return CanNavigateToMetadataSymbol(workspace, symbolKey);
}
return SourceSpans[0].CanNavigateTo();
}
public override bool TryNavigateTo(Workspace workspace, bool isPreview)
{
if (this.Properties.ContainsKey(NonNavigable))
{
return false;
}
if (this.Properties.TryGetValue(MetadataSymbolKey, out var symbolKey))
{
return TryNavigateToMetadataSymbol(workspace, symbolKey);
}
return SourceSpans[0].TryNavigateTo(isPreview);
}
private bool CanNavigateToMetadataSymbol(Workspace workspace, string symbolKey)
=> TryNavigateToMetadataSymbol(workspace, symbolKey, action: (symbol, project, service) => true);
private bool TryNavigateToMetadataSymbol(Workspace workspace, string symbolKey)
{
return TryNavigateToMetadataSymbol(workspace, symbolKey,
action: (symbol, project, service) =>
{
return service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true));
});
}
private bool TryNavigateToMetadataSymbol(
Workspace workspace, string symbolKey, Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = TryResolveSymbolInCurrentSolution(workspace, symbolKey);
var project = projectAndSymbol.project;
var symbol = projectAndSymbol.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol) TryResolveSymbolInCurrentSolution(
Workspace workspace, string symbolKey)
{
if (!this.Properties.TryGetValue(MetadataAssemblyIdentityDisplayName, out var identityDisplayName) ||
!AssemblyIdentity.TryParseDisplayName(identityDisplayName, out var identity))
{
return (null, null);
}
var project = workspace.CurrentSolution
.ProjectsWithReferenceToAssembly(identity)
.FirstOrDefault();
if (project == null)
{
return (null, null);
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
var symbol = SymbolKey.Resolve(symbolKey, compilation).Symbol;
return (project, symbol);
}
}
}
}
\ No newline at end of file
// 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;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> used for definitions
/// that cannot be navigated to. For example, C# and VB namespaces cannot be
/// navigated to.
/// </summary>
private sealed class NonNavigatingDefinitionItem : DefinitionItem
{
internal override bool IsExternal => false;
public NonNavigatingDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> originationParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences)
: base(tags, displayParts, ImmutableArray<TaggedText>.Empty,
originationParts, ImmutableArray<DocumentSpan>.Empty,
properties, displayIfNoReferences)
{
}
public override bool CanNavigateTo() => false;
public override bool TryNavigateTo() => false;
}
}
}
\ No newline at end of file
// 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.Collections.Immutable;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
internal partial class DefinitionItem
{
/// <summary>
/// Implementation of a <see cref="DefinitionItem"/> that sits on top of an
/// <see cref="ISymbol"/>. In order to not keep anything alive too long, we only
/// hold onto IDs and Keys. When the user tries to navigate to an item we will
/// attempt to find the symbol again in the current solution snapshot and
/// navigate to it there.
/// </summary>
private sealed class MetadataDefinitionItem : DefinitionItem
{
private readonly Workspace _workspace;
private readonly SymbolKey _symbolKey;
private readonly AssemblyIdentity _symbolAssemblyIdentity;
internal override bool IsExternal => false;
public MetadataDefinitionItem(
ImmutableArray<string> tags,
ImmutableArray<TaggedText> displayParts,
ImmutableArray<TaggedText> nameDisplayParts,
ImmutableDictionary<string, string> properties,
bool displayIfNoReferences,
Solution solution, ISymbol definition)
: base(tags, displayParts, nameDisplayParts,
GetOriginationParts(definition),
ImmutableArray<DocumentSpan>.Empty,
properties,
displayIfNoReferences)
{
_workspace = solution.Workspace;
_symbolKey = definition.GetSymbolKey();
_symbolAssemblyIdentity = definition.ContainingAssembly?.Identity;
}
public override bool CanNavigateTo()
=> TryNavigateTo((symbol, project, service) => true);
public override bool TryNavigateTo()
{
return TryNavigateTo((symbol, project, service) =>
service.TryNavigateToSymbol(
symbol, project, project.Solution.Options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true)));
}
private bool TryNavigateTo(Func<ISymbol, Project, ISymbolNavigationService, bool> action)
{
var projectAndSymbol = ResolveSymbolInCurrentSolution();
if (projectAndSymbol == null)
{
return false;
}
var project = projectAndSymbol?.project;
var symbol = projectAndSymbol?.symbol;
if (symbol == null || project == null)
{
return false;
}
if (symbol.Kind == SymbolKind.Namespace)
{
return false;
}
var navigationService = _workspace.Services.GetService<ISymbolNavigationService>();
return action(symbol, project, navigationService);
}
private (Project project, ISymbol symbol)? ResolveSymbolInCurrentSolution()
{
var project = _workspace.CurrentSolution
.ProjectsWithReferenceToAssembly(_symbolAssemblyIdentity)
.FirstOrDefault();
if (project == null)
{
return null;
}
var compilation = project.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
return (project, _symbolKey.Resolve(compilation).Symbol);
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Completion;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindUsages
{
......@@ -18,6 +19,29 @@ namespace Microsoft.CodeAnalysis.FindUsages
/// </summary>
internal abstract partial class DefinitionItem
{
// Existing behavior is to do up to two lookups for 3rd party navigation for FAR. One
// for the symbol itself and one for a 'fallback' symbol. For example, if we're FARing
// on a constructor, then the fallback symbol will be the actual type that the constructor
// is contained within.
internal const string RQNameKey1 = nameof(RQNameKey1);
internal const string RQNameKey2 = nameof(RQNameKey2);
/// <summary>
/// For metadata symbols we encode information in the <see cref="Properties"/> so we can
/// retrieve the symbol later on when navigating. This is needed so that we can go to
/// metadata-as-source for metadata symbols. We need to store the <see cref="SymbolKey"/>
/// for the symbol and the name we get back from <see cref="AssemblyIdentity.GetDisplayName"/>
/// for. With these we can effetively recover the symbol.
/// </summary>
private const string MetadataSymbolKey = nameof(MetadataSymbolKey);
private const string MetadataAssemblyIdentityDisplayName = nameof(MetadataAssemblyIdentityDisplayName);
/// <summary>
/// If this item is something that cannot be navigated to. We store this in our
/// <see cref="Properties"/> to act as an explicit marker that navigation is not possible.
/// </summary>
private const string NonNavigable = nameof(NonNavigable);
/// <summary>
/// Descriptive tags from <see cref="CompletionTags"/>. These tags may influence how the
/// item is displayed.
......@@ -82,12 +106,17 @@ internal abstract partial class DefinitionItem
NameDisplayParts = nameDisplayParts.IsDefaultOrEmpty ? displayParts : nameDisplayParts;
OriginationParts = originationParts.NullToEmpty();
SourceSpans = sourceSpans.NullToEmpty();
Properties = properties;
Properties = properties ?? ImmutableDictionary<string, string>.Empty;
DisplayIfNoReferences = displayIfNoReferences;
if (Properties.ContainsKey(MetadataSymbolKey))
{
Contract.ThrowIfFalse(Properties.ContainsKey(MetadataAssemblyIdentityDisplayName));
}
}
public abstract bool CanNavigateTo();
public abstract bool TryNavigateTo();
public abstract bool CanNavigateTo(Workspace workspace);
public abstract bool TryNavigateTo(Workspace workspace, bool isPreview);
public static DefinitionItem Create(
ImmutableArray<string> tags,
......@@ -127,8 +156,13 @@ internal abstract partial class DefinitionItem
throw new ArgumentException($"{nameof(sourceSpans)} cannot be empty.");
}
return new DocumentLocationDefinitionItem(
tags, displayParts, nameDisplayParts, sourceSpans, properties, displayIfNoReferences);
var firstDocument = sourceSpans[0].Document;
var originationParts = ImmutableArray.Create(
new TaggedText(TextTags.Text, firstDocument.Project.Name));
return new DefaultDefinitionItem(
tags, displayParts, nameDisplayParts, originationParts,
sourceSpans, properties, displayIfNoReferences);
}
internal static DefinitionItem CreateMetadataDefinition(
......@@ -139,9 +173,20 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new MetadataDefinitionItem(
tags, displayParts, nameDisplayParts, properties,
displayIfNoReferences, solution, symbol);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
var symbolKey = symbol.GetSymbolKey().ToString();
var assemblyIdentityDisplayName = symbol.ContainingAssembly?.Identity.GetDisplayName();
properties = properties.Add(MetadataSymbolKey, symbolKey)
.Add(MetadataAssemblyIdentityDisplayName, assemblyIdentityDisplayName);
var originationParts = GetOriginationParts(symbol);
return new DefaultDefinitionItem(
tags, displayParts, nameDisplayParts, originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
// Kept around for binary compat with F#/TypeScript.
......@@ -163,8 +208,17 @@ internal abstract partial class DefinitionItem
ImmutableDictionary<string, string> properties = null,
bool displayIfNoReferences = true)
{
return new NonNavigatingDefinitionItem(
tags, displayParts, originationParts, properties, displayIfNoReferences);
properties = properties ?? ImmutableDictionary<string, string>.Empty;
properties = properties.Add(NonNavigable, "");
return new DefaultDefinitionItem(
tags: tags,
displayParts: displayParts,
nameDisplayParts: ImmutableArray<TaggedText>.Empty,
originationParts: originationParts,
sourceSpans: ImmutableArray<DocumentSpan>.Empty,
properties: properties,
displayIfNoReferences: displayIfNoReferences);
}
internal static ImmutableArray<TaggedText> GetOriginationParts(ISymbol symbol)
......
// 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;
namespace Microsoft.CodeAnalysis.FindReferences
{
internal partial class DefinitionLocation
{
/// <summary>
/// Implementation of a <see cref="DefinitionLocation"/> that sits on top of a
/// <see cref="DocumentLocation"/>.
/// </summary>
// Internal for testing purposes only.
internal sealed class DocumentDefinitionLocation : DefinitionLocation
{
public readonly DocumentLocation Location;
public DocumentDefinitionLocation(DocumentLocation location)
{
Location = location;
}
/// <summary>
/// Show the project that this <see cref="DocumentLocation"/> is contained in as the
/// Origination of this <see cref="DefinitionLocation"/>.
/// </summary>
public override ImmutableArray<TaggedText> OriginationParts =>
ImmutableArray.Create(new TaggedText(TextTags.Text, Location.Document.Project.Name));
public override bool CanNavigateTo() => true;
public override bool TryNavigateTo() => Location.TryNavigateTo();
}
}
}
\ No newline at end of file
// 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.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
......@@ -37,11 +35,12 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
{
var unimplementedMembers = _state.UnimplementedMembers;
var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var propertyGenerationBehavior = options.GetOption(ImplementTypeOptions.PropertyGenerationBehavior);
var memberDefinitions = GenerateMembers(
unimplementedMembers,
cancellationToken);
unimplementedMembers, propertyGenerationBehavior, cancellationToken);
var options = await _document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var insertionBehavior = options.GetOption(ImplementTypeOptions.InsertionBehavior);
var groupMembers = insertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind;
......@@ -51,23 +50,25 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
memberDefinitions,
new CodeGenerationOptions(
_state.Location.GetLocation(),
autoInsertionLocation: groupMembers,
autoInsertionLocation: groupMembers,
sortMembers: groupMembers),
cancellationToken).ConfigureAwait(false);
}
private ImmutableArray<ISymbol> GenerateMembers(
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
return unimplementedMembers.SelectMany(t => t.members)
.Select(m => GenerateMember(m, cancellationToken))
.Select(m => GenerateMember(m, propertyGenerationBehavior, cancellationToken))
.WhereNotNull()
.ToImmutableArray();
}
private ISymbol GenerateMember(
ISymbol member,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
......@@ -76,32 +77,29 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
var syntaxFacts = _document.Project.LanguageServices.GetService<ISyntaxFactsService>();
var addUnsafe = member.IsUnsafe() && !syntaxFacts.IsUnsafeContext(_state.Location);
return GenerateMember(member, addUnsafe, cancellationToken);
return GenerateMember(member, addUnsafe, propertyGenerationBehavior, cancellationToken);
}
private ISymbol GenerateMember(
ISymbol member,
bool addUnsafe,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var modifiers = new DeclarationModifiers(isOverride: true, isUnsafe: addUnsafe);
var accessibility = member.ComputeResultantAccessibility(_state.ClassType);
if (member.Kind == SymbolKind.Method)
{
return GenerateMethod((IMethodSymbol)member, modifiers, accessibility, cancellationToken);
}
else if (member.Kind == SymbolKind.Property)
{
return GenerateProperty((IPropertySymbol)member, modifiers, accessibility, cancellationToken);
}
else if (member.Kind == SymbolKind.Event)
switch (member)
{
var @event = (IEventSymbol)member;
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers);
case IMethodSymbol method:
return GenerateMethod(method, modifiers, accessibility, cancellationToken);
case IPropertySymbol property:
return GenerateProperty(property, modifiers, accessibility, propertyGenerationBehavior, cancellationToken);
case IEventSymbol @event:
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event, accessibility: accessibility, modifiers: modifiers);
}
return null;
......@@ -128,18 +126,27 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
IPropertySymbol property,
DeclarationModifiers modifiers,
Accessibility accessibility,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (property.GetMethod == null)
{
// Can't generate an auto-prop for a setter-only property.
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var syntaxFactory = _document.Project.LanguageServices.GetService<SyntaxGenerator>();
var throwingBody = syntaxFactory.CreateThrowNotImplementedStatementBlock(
_model.Compilation);
var accessorBody = propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: syntaxFactory.CreateThrowNotImplementedStatementBlock(_model.Compilation);
var getMethod = ShouldGenerateAccessor(property.GetMethod)
? CodeGenerationSymbolFactory.CreateAccessorSymbol(
property.GetMethod,
attributes: default(ImmutableArray<AttributeData>),
accessibility: property.GetMethod.ComputeResultantAccessibility(_state.ClassType),
statements: throwingBody)
statements: accessorBody)
: null;
var setMethod = ShouldGenerateAccessor(property.SetMethod)
......@@ -147,7 +154,7 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
property.SetMethod,
attributes: default(ImmutableArray<AttributeData>),
accessibility: property.SetMethod.ComputeResultantAccessibility(_state.ClassType),
statements: throwingBody)
statements: accessorBody)
: null;
return CodeGenerationSymbolFactory.CreatePropertySymbol(
......@@ -158,7 +165,8 @@ public async Task<Document> GetEditAsync(CancellationToken cancellationToken)
setMethod: setMethod);
}
private bool ShouldGenerateAccessor(IMethodSymbol method) => method != null && _state.ClassType.FindImplementationForAbstractMember(method) == null;
private bool ShouldGenerateAccessor(IMethodSymbol method)
=> method != null && _state.ClassType.FindImplementationForAbstractMember(method) == null;
}
}
}
}
\ No newline at end of file
......@@ -176,15 +176,15 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
var compilation = await result.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var isComImport = unimplementedMembers.Any(t => t.Item1.IsComImport);
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var propertyGenerationBehavior = options.GetOption(ImplementTypeOptions.PropertyGenerationBehavior);
var memberDefinitions = GenerateMembers(
compilation,
unimplementedMembers,
cancellationToken);
compilation, unimplementedMembers, propertyGenerationBehavior, cancellationToken);
// Only group the members in the destination if the user wants that *and*
// it's not a ComImport interface. Member ordering in ComImport interfaces
// matters, so we don't want to much with them.
var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
var insertionBehavior = options.GetOption(ImplementTypeOptions.InsertionBehavior);
var groupMembers = !isComImport &&
insertionBehavior == ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind;
......@@ -203,6 +203,7 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
private ImmutableArray<ISymbol> GenerateMembers(
Compilation compilation,
ImmutableArray<(INamedTypeSymbol type, ImmutableArray<ISymbol> members)> unimplementedMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// As we go along generating members we may end up with conflicts. For example, say
......@@ -229,7 +230,9 @@ public Task<Document> GetUpdatedDocumentAsync(CancellationToken cancellationToke
foreach (var unimplementedInterfaceMember in unimplementedInterfaceMembers)
{
var member = GenerateMember(compilation, unimplementedInterfaceMember, implementedVisibleMembers, cancellationToken);
var member = GenerateMember(
compilation, unimplementedInterfaceMember, implementedVisibleMembers,
propertyGenerationBehavior, cancellationToken);
if (member != null)
{
implementedMembers.Add(member);
......@@ -272,6 +275,7 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
Compilation compilation,
ISymbol member,
List<ISymbol> implementedVisibleMembers,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
// First check if we already generate a member that matches the member we want to
......@@ -308,7 +312,9 @@ private string DetermineMemberName(ISymbol member, List<ISymbol> implementedVisi
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var addUnsafe = member.IsUnsafe() && !syntaxFacts.IsUnsafeContext(State.Location);
return GenerateMember(compilation, member, memberName, generateInvisibleMember, generateAbstractly, addNew, addUnsafe, cancellationToken);
return GenerateMember(
compilation, member, memberName, generateInvisibleMember, generateAbstractly,
addNew, addUnsafe, propertyGenerationBehavior, cancellationToken);
}
private bool GenerateInvisibleMember(ISymbol member, string memberName)
......@@ -376,6 +382,7 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
bool generateAbstractly,
bool addNew,
bool addUnsafe,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
......@@ -386,35 +393,28 @@ private static bool IsUnexpressibleTypeParameter(ITypeParameterSymbol typeParame
? Accessibility.Public
: Accessibility.Private;
if (member.Kind == SymbolKind.Method)
{
var method = (IMethodSymbol)member;
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
}
else if (member.Kind == SymbolKind.Property)
{
var property = (IPropertySymbol)member;
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
}
else if (member.Kind == SymbolKind.Event)
switch (member)
{
var @event = (IEventSymbol)member;
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default(ImmutableArray<AttributeData>),
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? @event : null,
name: memberName,
addMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
case IMethodSymbol method:
return GenerateMethod(compilation, method, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, cancellationToken);
case IPropertySymbol property:
return GenerateProperty(compilation, property, accessibility, modifiers, generateAbstractly, useExplicitInterfaceSymbol, memberName, propertyGenerationBehavior, cancellationToken);
case IEventSymbol @event:
var accessor = CodeGenerationSymbolFactory.CreateAccessorSymbol(
attributes: default(ImmutableArray<AttributeData>),
accessibility: Accessibility.NotApplicable,
statements: factory.CreateThrowNotImplementedStatementBlock(compilation));
return CodeGenerationSymbolFactory.CreateEventSymbol(
@event,
accessibility: accessibility,
modifiers: modifiers,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? @event : null,
name: memberName,
addMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.AddEventHandler),
removeMethod: GetAddOrRemoveMethod(generateInvisibly, accessor, memberName, factory.RemoveEventHandler));
}
return null;
......
......@@ -7,6 +7,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.ImplementType;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -25,16 +26,19 @@ internal partial class ImplementInterfaceCodeAction
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
string memberName,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
var factory = this.Document.GetLanguageService<SyntaxGenerator>();
var attributesToRemove = AttributesToRemove(compilation);
var getAccessor = GenerateGetAccessor(compilation, property, accessibility, generateAbstractly,
useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var getAccessor = GenerateGetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(compilation, property, accessibility,
generateAbstractly, useExplicitInterfaceSymbol, attributesToRemove, cancellationToken);
var setAccessor = GenerateSetAccessor(
compilation, property, accessibility, generateAbstractly, useExplicitInterfaceSymbol,
propertyGenerationBehavior, attributesToRemove, cancellationToken);
var syntaxFacts = Document.GetLanguageService<ISyntaxFactsService>();
var parameterNames = NameGenerator.EnsureUniqueness(
......@@ -73,6 +77,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -81,6 +86,12 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return null;
}
if (property.GetMethod == null)
{
// Can't have an auto-prop with just a setter.
propertyGenerationBehavior = ImplementTypePropertyGenerationBehavior.PreferThrowingProperties;
}
var setMethod = property.SetMethod.RemoveInaccessibleAttributesAndAttributesOfTypes(
this.State.ClassOrStructType,
attributesToRemove);
......@@ -90,7 +101,8 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.SetMethod : null,
statements: GetSetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetSetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private IMethodSymbol GenerateGetAccessor(
......@@ -99,6 +111,7 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
Accessibility accessibility,
bool generateAbstractly,
bool useExplicitInterfaceSymbol,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
INamedTypeSymbol[] attributesToRemove,
CancellationToken cancellationToken)
{
......@@ -116,13 +129,15 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
attributes: default(ImmutableArray<AttributeData>),
accessibility: accessibility,
explicitInterfaceSymbol: useExplicitInterfaceSymbol ? property.GetMethod : null,
statements: GetGetAccessorStatements(compilation, property, generateAbstractly, cancellationToken));
statements: GetGetAccessorStatements(
compilation, property, generateAbstractly, propertyGenerationBehavior, cancellationToken));
}
private ImmutableArray<SyntaxNode> GetSetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -157,13 +172,16 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ExpressionStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
private ImmutableArray<SyntaxNode> GetGetAccessorStatements(
Compilation compilation,
IPropertySymbol property,
bool generateAbstractly,
ImplementTypePropertyGenerationBehavior propertyGenerationBehavior,
CancellationToken cancellationToken)
{
if (generateAbstractly)
......@@ -196,8 +214,10 @@ private INamedTypeSymbol[] AttributesToRemove(Compilation compilation)
return ImmutableArray.Create(factory.ReturnStatement(expression));
}
return factory.CreateThrowNotImplementedStatementBlock(compilation);
return propertyGenerationBehavior == ImplementTypePropertyGenerationBehavior.PreferAutoProperties
? default(ImmutableArray<SyntaxNode>)
: factory.CreateThrowNotImplementedStatementBlock(compilation);
}
}
}
}
}
\ No newline at end of file
// 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.Collections.Generic;
using System.Linq;
using System.Threading;
......
......@@ -10,6 +10,12 @@ internal enum ImplementTypeInsertionBehavior
AtTheEnd = 1,
}
internal enum ImplementTypePropertyGenerationBehavior
{
PreferThrowingProperties = 0,
PreferAutoProperties = 1,
}
internal static class ImplementTypeOptions
{
public static readonly PerLanguageOption<ImplementTypeInsertionBehavior> InsertionBehavior =
......@@ -19,5 +25,14 @@ internal static class ImplementTypeOptions
defaultValue: ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(InsertionBehavior)}"));
public static readonly PerLanguageOption<ImplementTypePropertyGenerationBehavior> PropertyGenerationBehavior =
new PerLanguageOption<ImplementTypePropertyGenerationBehavior>(
nameof(ImplementTypeOptions),
nameof(PropertyGenerationBehavior),
defaultValue: ImplementTypePropertyGenerationBehavior.PreferThrowingProperties,
storageLocations: new RoamingProfileStorageLocation(
$"TextEditor.%LANGUAGE%.{nameof(ImplementTypeOptions)}.{nameof(PropertyGenerationBehavior)}"));
}
}
\ No newline at end of file
// 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.Threading;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Navigation
......@@ -8,17 +9,13 @@ namespace Microsoft.CodeAnalysis.Navigation
internal class DefaultSymbolNavigationService : ISymbolNavigationService
{
public bool TryNavigateToSymbol(ISymbol symbol, Project project, OptionSet options = null, CancellationToken cancellationToken = default(CancellationToken))
{
return false;
}
=> false;
public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
return false;
}
=> false;
public bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
filePath = null;
......@@ -28,4 +25,4 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
return false;
}
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis.Host;
using System.Threading;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.FindUsages;
namespace Microsoft.CodeAnalysis.Navigation
{
......@@ -25,7 +26,7 @@ internal interface ISymbolNavigationService : IWorkspaceService
/// <returns>True if the navigation would be handled.</returns>
bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset);
}
}
......@@ -5,19 +5,19 @@
<Target Name="Build">
<!-- NuGetPerBuildPreReleaseVersion -->
<Exec Command="$(OutDir)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutDir) $(NuGetPerBuildPreReleaseVersion) $(OutDir)NuGet\PerBuildPreRelease" Condition="'$(NuGetPerBuildPreReleaseVersion)' != ''" />
<Exec Command="$(OutputPath)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutputPath) $(NuGetPerBuildPreReleaseVersion) $(OutputPath)NuGet\PerBuildPreRelease" Condition="'$(NuGetPerBuildPreReleaseVersion)' != ''" />
<!-- NuGetPreReleaseVersion -->
<Exec Command="$(OutDir)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutDir) $(NuGetPreReleaseVersion) $(OutDir)NuGet\PreRelease" Condition="'$(NuGetPreReleaseVersion)' != ''" />
<Exec Command="$(OutputPath)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutputPath) $(NuGetPreReleaseVersion) $(OutputPath)NuGet\PreRelease" Condition="'$(NuGetPreReleaseVersion)' != ''" />
<!-- NuGetReleaseVersion -->
<Exec Command="$(OutDir)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutDir) $(NuGetReleaseVersion) $(OutDir)NuGet\Release" Condition="'$(NuGetReleaseVersion)' != ''" />
<Exec Command="$(OutputPath)Exes\csi\csi.exe $(MSBuildThisFileDirectory)BuildNuGets.csx $(OutputPath) $(NuGetReleaseVersion) $(OutputPath)NuGet\Release" Condition="'$(NuGetReleaseVersion)' != ''" />
</Target>
<Target Name="Clean">
<RemoveDir Directories="$(OutDir)NuGet" />
<RemoveDir Directories="$(OutputPath)NuGet" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>
</Project>
\ No newline at end of file
</Project>
......@@ -3,16 +3,16 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\..\..\build\Targets\Settings.props" />
<PropertyGroup>
<InsertionFilesDir>$(OutDir)DevDivInsertionFiles</InsertionFilesDir>
<InsertionFilesDir>$(OutputPath)\DevDivInsertionFiles</InsertionFilesDir>
<VsToolsetDir>$(InsertionFilesDir)\VS.Tools.Roslyn</VsToolsetDir>
<PackagesOutDir>$(OutDir)DevDivPackages\Roslyn</PackagesOutDir>
<PackagesOutDir>$(OutputPath)\DevDivPackages\Roslyn</PackagesOutDir>
</PropertyGroup>
<ItemGroup>
<NuSpec Include="$(InsertionFilesDir)\VS.ExternalAPIs.Roslyn.nuspec">
<Version>$(NuGetPerBuildPreReleaseVersion)</Version>
<!-- TFS build number isn't set on CI server -->
<Version Condition="'$(NuGetPerBuildPreReleaseVersion)' == ''">$(NuGetReleaseVersion)-cibuild</Version>
<BaseDir>$(OutDir)</BaseDir>
<BaseDir>$(OutputPath)</BaseDir>
</NuSpec>
<NuSpec Include="$(VsToolsetDir)\VS.Tools.Roslyn.nuspec">
<Version>$(NuGetPerBuildPreReleaseVersion)</Version>
......@@ -30,4 +30,4 @@
<Target Name="Clean">
<RemoveDir Directories="$(PackagesOutDir)" />
</Target>
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,8 @@
<PropertyGroup>
<OutputArchitecture>neutral</OutputArchitecture>
<OutputLocalized>false</OutputLocalized>
<OutputPath>$(OutDir)Insertion</OutputPath>
<RoslynOutputPath>$(OutputPath)</RoslynOutputPath>
<OutputPath>$(OutputPath)\Insertion</OutputPath>
<IsPackage>true</IsPackage>
<OutputType>vsix</OutputType>
</PropertyGroup>
......@@ -14,7 +15,7 @@
<Import Project="$(NuGetPackageRoot)\MicroBuild.Core\$(MicroBuildCoreVersion)\build\MicroBuild.Core.props" />
<PropertyGroup>
<PackagePreprocessorDefinitions>$(PackagePreprocessorDefinitions);Version=$(VsixVersion);OutputPath=$(OutDir)</PackagePreprocessorDefinitions>
<PackagePreprocessorDefinitions>$(PackagePreprocessorDefinitions);Version=$(VsixVersion);OutputPath=$(RoslynOutputPath)</PackagePreprocessorDefinitions>
<IntermediateOutputPath>$(BaseIntermediateOutputPath)$(Configuration)\</IntermediateOutputPath>
</PropertyGroup>
......@@ -23,4 +24,4 @@
</ItemGroup>
<Import Project="$(NuGetPackageRoot)\MicroBuild.Core\$(MicroBuildCoreVersion)\build\MicroBuild.Core.targets" />
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,7 @@
<PropertyGroup>
<FinalizeManifest>true</FinalizeManifest>
<FinalizeSkipLayout>true</FinalizeSkipLayout>
<OutputPath>$(OutDir)Insertion\</OutputPath>
<OutputPath>$(OutputPath)Insertion\</OutputPath>
<IsPackage>true</IsPackage>
<FinalizeValidate>false</FinalizeValidate>
<ValidateManifest>false</ValidateManifest>
......@@ -29,4 +29,4 @@
</ItemGroup>
<Target Name="ValidateManifest" />
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,7 @@
<PropertyGroup>
<FinalizeManifest>true</FinalizeManifest>
<FinalizeSkipLayout>true</FinalizeSkipLayout>
<OutputPath>$(OutDir)Insertion</OutputPath>
<OutputPath>$(OutputPath)\Insertion</OutputPath>
<IsPackage>true</IsPackage>
<FinalizeValidate>false</FinalizeValidate>
<ValidateManifest>false</ValidateManifest>
......@@ -38,4 +38,4 @@
</ItemGroup>
<Target Name="ValidateManifest" />
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,7 @@
<PropertyGroup>
<OutputArchitecture>neutral</OutputArchitecture>
<OutputLocalized>false</OutputLocalized>
<OutputPath>$(OutDir)Insertion</OutputPath>
<OutputPath>$(OutputPath)\Insertion</OutputPath>
<IsPackage>true</IsPackage>
<OutputType>vsix</OutputType>
</PropertyGroup>
......@@ -23,4 +23,4 @@
</ItemGroup>
<Import Project="$(NuGetPackageRoot)\MicroBuild.Core\$(MicroBuildCoreVersion)\build\MicroBuild.Core.targets" />
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,7 @@
<PropertyGroup>
<FinalizeManifest>true</FinalizeManifest>
<FinalizeSkipLayout>true</FinalizeSkipLayout>
<OutputPath>$(OutDir)Insertion\</OutputPath>
<OutputPath>$(OutputPath)\Insertion\</OutputPath>
<IsPackage>true</IsPackage>
<FinalizeValidate>false</FinalizeValidate>
<ValidateManifest>false</ValidateManifest>
......@@ -24,4 +24,4 @@
</ItemGroup>
<Target Name="ValidateManifest" />
</Project>
\ No newline at end of file
</Project>
......@@ -25,7 +25,7 @@
where building multiple projects that produce VSIXes larger than 10MB will race against each other -->
<MSBuild Projects="@(Project)" Targets="Build" BuildInParallel="false" />
<Copy SourceFiles="@(PowerShellScriptsToCopy)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(PowerShellScriptsToCopy)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(PowerShellScriptsToCopy)" DestinationFolder="Templates\CSharp\Diagnostic\Analyzer" />
<Copy SourceFiles="@(PowerShellScriptsToCopy)" DestinationFolder="Templates\VisualBasic\Diagnostic\Analyzer\tools" />
......@@ -40,4 +40,4 @@
<Target Name="Rebuild">
<MSBuild Projects="@(Project)" Targets="Rebuild" BuildInParallel="false" />
</Target>
</Project>
\ No newline at end of file
</Project>
......@@ -8,7 +8,7 @@
<!-- Build CoreXT packages for insertion into DevDiv (order of the following actions matters) -->
<MSBuild Projects="DevDivInsertionFiles\DevDivInsertionFiles.sln" />
<Exec Command="&quot;$(OutDir)\Exes\DevDivInsertionFiles\Roslyn.BuildDevDivInsertionFiles.exe&quot; &quot;$(OutDir)\&quot; &quot;$(MSBuildThisFileDirectory)\&quot; &quot;$(NuGetPackageRoot)&quot; $(AssemblyVersion)" LogStandardErrorAsError="true" />
<Exec Command="&quot;$(OutputPath)\Exes\DevDivInsertionFiles\Roslyn.BuildDevDivInsertionFiles.exe&quot; &quot;$(OutputPath)\&quot; &quot;$(MSBuildThisFileDirectory)\&quot; &quot;$(NuGetPackageRoot)&quot; $(AssemblyVersion)" LogStandardErrorAsError="true" />
<MSBuild Projects="DevDivPackages\Roslyn.proj" />
<MSBuild Projects="DevDivVsix\PortableFacades\PortableFacades.vsmanproj" />
<MSBuild Projects="DevDivVsix\CompilersPackage\Microsoft.CodeAnalysis.Compilers.vsmanproj" />
......@@ -23,4 +23,4 @@
<!-- VSIX Gallery -->
<MSBuild Projects="Vsix\Vsix.proj" />
</Target>
</Project>
\ No newline at end of file
</Project>
......@@ -6,7 +6,7 @@
<VsixUploadConfigs Include="myget_org-extensions.config" />
</ItemGroup>
<Target Name="Build">
<Copy SourceFiles="@(VsixUploadConfigs)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" />
<Copy SourceFiles="@(VsixUploadConfigs)" DestinationFolder="$(OutputPath)" SkipUnchangedFiles="true" />
</Target>
<Target Name="Clean" />
</Project>
\ No newline at end of file
</Project>
......@@ -100,6 +100,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
</StackPanel>
<Label Content="{x:Static local:AdvancedOptionPageStrings.Option_When_generating_properties}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_throwing_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_throwing_properties}"/>
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_auto_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_auto_properties}"/>
</StackPanel>
</StackPanel>
</GroupBox>
</StackPanel>
......
......@@ -48,6 +48,9 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.CSharp);
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.CSharp);
BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.CSharp);
BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.CSharp);
}
}
}
\ No newline at end of file
......@@ -62,6 +62,15 @@ public static string Option_with_other_members_of_the_same_kind
public static string Option_at_the_end
=> ServicesVSResources.at_the_end;
public static string Option_When_generating_properties
=> ServicesVSResources.When_generating_properties;
public static string Option_prefer_auto_properties
=> ServicesVSResources.prefer_auto_properties;
public static string Option_prefer_throwing_properties
=> ServicesVSResources.prefer_throwing_properties;
public static string Option_GenerateXmlDocCommentsForTripleSlash
{
get { return CSharpVSResources.Generate_XML_documentation_comments_for; }
......
......@@ -32,11 +32,11 @@ public VisualStudioDefinitionsAndReferencesFactory(SVsServiceProvider servicePro
}
public override DefinitionItem GetThirdPartyDefinitionItem(
Solution solution, ISymbol definition, CancellationToken cancellationToken)
Solution solution, DefinitionItem definitionItem, CancellationToken cancellationToken)
{
var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
if (!symbolNavigationService.WouldNavigateToSymbol(
definition, solution, cancellationToken,
definitionItem, solution, cancellationToken,
out var filePath, out var lineNumber, out var charOffset))
{
return null;
......@@ -44,7 +44,7 @@ public VisualStudioDefinitionsAndReferencesFactory(SVsServiceProvider servicePro
var displayParts = GetDisplayParts(filePath, lineNumber, charOffset);
return new ExternalDefinitionItem(
GlyphTags.GetTags(definition.GetGlyph()), displayParts,
definitionItem.Tags, displayParts,
_serviceProvider, filePath, lineNumber, charOffset);
}
......@@ -106,9 +106,9 @@ private class ExternalDefinitionItem : DefinitionItem
_charOffset = charOffset;
}
public override bool CanNavigateTo() => true;
public override bool CanNavigateTo(Workspace workspace) => true;
public override bool TryNavigateTo()
public override bool TryNavigateTo(Workspace workspace, bool isPreview)
{
return TryOpenFile() && TryNavigateToPosition();
}
......
......@@ -12,9 +12,12 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
[Guid(Guids.RoslynLibraryIdString)]
internal partial class LibraryManager : AbstractLibraryManager
{
public LibraryManager(IServiceProvider serviceProvider)
private readonly Workspace _workspace;
public LibraryManager(Workspace workspace, IServiceProvider serviceProvider)
: base(Guids.RoslynLibraryId, serviceProvider)
{
_workspace = workspace;
}
public override uint GetLibraryFlags()
......
......@@ -40,7 +40,7 @@ public void PresentDefinitionsAndReferences(DefinitionsAndReferences definitions
var query =
from d in definitionsAndReferences.Definitions
let referenceItems = CreateReferenceItems(d, definitionsAndReferences, commonPathElements)
select new DefinitionTreeItem(d, referenceItems);
select new DefinitionTreeItem(_workspace, d, referenceItems);
return query.ToList<AbstractTreeItem>();
}
......
......@@ -12,13 +12,16 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
{
internal class DefinitionTreeItem : AbstractTreeItem
{
private readonly Workspace _workspace;
private readonly DefinitionItem _definitionItem;
public DefinitionTreeItem(
Workspace workspace,
DefinitionItem definitionItem,
ImmutableArray<SourceReferenceTreeItem> referenceItems)
: base(definitionItem.Tags.GetGlyph().GetGlyphIndex())
{
_workspace = workspace;
_definitionItem = definitionItem;
this.Children.AddRange(referenceItems);
......@@ -49,14 +52,14 @@ private string CreateDisplayText()
public override int GoToSource()
{
return _definitionItem.TryNavigateTo()
return _definitionItem.TryNavigateTo(_workspace, isPreview: true)
? VSConstants.S_OK
: VSConstants.E_FAIL;
}
public override bool CanGoToDefinition()
{
return _definitionItem.CanNavigateTo();
return _definitionItem.CanNavigateTo(_workspace);
}
}
}
\ No newline at end of file
// 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
......@@ -33,7 +38,13 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi
private AbstractListItemFactory _listItemFactory;
private object _classMemberGate = new object();
protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryGuid, __SymbolToolLanguage preferredLanguage, IServiceProvider serviceProvider)
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
protected AbstractObjectBrowserLibraryManager(
string languageName,
Guid libraryGuid,
__SymbolToolLanguage preferredLanguage,
IServiceProvider serviceProvider)
: base(libraryGuid, serviceProvider)
{
_languageName = languageName;
......@@ -43,6 +54,8 @@ protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryG
this.Workspace = componentModel.GetService<VisualStudioWorkspace>();
this.LibraryService = this.Workspace.Services.GetLanguageServices(languageName).GetService<ILibraryService>();
this.Workspace.WorkspaceChanged += OnWorkspaceChanged;
this._streamingPresenters = componentModel.DefaultExportProvider.GetExports<IStreamingFindUsagesPresenter>();
}
internal abstract AbstractDescriptionBuilder CreateDescriptionBuilder(
......@@ -481,24 +494,21 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
switch (commandId)
{
case (uint)VSConstants.VSStd97CmdID.FindReferences:
var streamingPresenter = _streamingPresenters.FirstOrDefault()?.Value;
var symbolListItem = _activeListItem as SymbolListItem;
if (symbolListItem != null)
if (streamingPresenter != null && symbolListItem?.ProjectId != null)
{
var projectId = symbolListItem.ProjectId;
if (projectId != null)
var project = this.Workspace.CurrentSolution.GetProject(symbolListItem.ProjectId);
if (project != null)
{
var project = this.Workspace.CurrentSolution.GetProject(projectId);
if (project != null)
{
var compilation = project
.GetCompilationAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None);
var symbol = symbolListItem.ResolveSymbol(compilation);
this.Workspace.TryFindAllReferences(symbol, project, CancellationToken.None);
return true;
}
// Note: we kick of FindReferencesAsync in a 'fire and forget' manner.
// We don't want to block the UI thread while we compute the references,
// and the references will be asynchronously added to the FindReferences
// window as they are computed. The user also knows something is happening
// as the window, with the progress-banner will pop up immediately.
var task = FindReferencesAsync(streamingPresenter, symbolListItem, project);
return true;
}
}
......@@ -508,5 +518,51 @@ protected override bool TryExec(Guid commandGroup, uint commandId)
return false;
}
private async Task FindReferencesAsync(
IStreamingFindUsagesPresenter presenter, SymbolListItem symbolListItem, Project project)
{
try
{
// Let the presented know we're starting a search. It will give us back
// the context object that the FAR service will push results into.
var context = presenter.StartSearch(
EditorFeaturesResources.Find_References, supportsReferences: true);
var cancellationToken = context.CancellationToken;
// Kick off the work to do the actual finding on a BG thread. That way we don'
// t block the calling (UI) thread too long if we happen to do our work on this
// thread.
await Task.Run(async () =>
{
await FindReferencesAsync(symbolListItem, project, context, cancellationToken).ConfigureAwait(false);
}, cancellationToken).ConfigureAwait(false);
// Note: we don't need to put this in a finally. The only time we might not hit
// this is if cancellation or another error gets thrown. In the former case,
// that means that a new search has started. We don't care about telling the
// context it has completed. In the latter case something wrong has happened
// and we don't want to run any more code in this particular context.
await context.OnCompletedAsync().ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
catch (Exception e) when (FatalError.ReportWithoutCrash(e))
{
}
}
private static async Task FindReferencesAsync(SymbolListItem symbolListItem, Project project, CodeAnalysis.FindUsages.FindUsagesContext context, CancellationToken cancellationToken)
{
var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var symbol = symbolListItem.ResolveSymbol(compilation);
if (symbol != null)
{
await AbstractFindUsagesService.FindSymbolReferencesAsync(
context, symbol, project, cancellationToken).ConfigureAwait(false);
}
}
}
}
}
\ No newline at end of file
......@@ -275,7 +275,11 @@ private static Document OpenDocument(Workspace workspace, DocumentId documentId,
{
if (options.GetOption(NavigationOptions.PreferProvisionalTab))
{
using (NewDocumentStateScope ndss = new NewDocumentStateScope(__VSNEWDOCUMENTSTATE.NDS_Provisional, VSConstants.NewDocumentStateReason.Navigation))
// If we're just opening the provisional tab, then do not "activate" the document
// (i.e. don't give it focus). This way if a user is just arrowing through a set
// of FindAllReferences results, they don't have their cursor placed into the document.
var state = __VSNEWDOCUMENTSTATE.NDS_Provisional | __VSNEWDOCUMENTSTATE.NDS_NoActivate;
using (var scope = new NewDocumentStateScope(state, VSConstants.NewDocumentStateReason.Navigation))
{
workspace.OpenDocument(documentId);
}
......
......@@ -6,8 +6,10 @@
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.Implementation.Structure;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
......@@ -156,9 +158,13 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
ISymbol symbol, Solution solution, CancellationToken cancellationToken)
{
AssertIsForeground();
var definitionItem = symbol.ToDefinitionItem(solution, includeHiddenLocations: true);
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName);
if (!TryGetNavigationAPIRequiredArguments(
symbol, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
definitionItem, rqName, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
......@@ -166,30 +172,21 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
int returnCode = navigationNotify.OnBeforeNavigateToSymbol(
hierarchy,
itemID,
rqname,
rqName,
out var navigationHandled);
if (returnCode == VSConstants.S_OK && navigationHandled == 1)
{
return true;
}
return false;
return returnCode == VSConstants.S_OK && navigationHandled == 1;
}
public bool WouldNavigateToSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
if (WouldNotifyToSpecificSymbol(symbol, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
{
return true;
}
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey1, out var rqName1);
definitionItem.Properties.TryGetValue(DefinitionItem.RQNameKey2, out var rqName2);
// If the symbol being considered is a constructor and no third parties choose to
// navigate to the constructor, then try the constructor's containing type.
if (symbol.IsConstructor() && WouldNotifyToSpecificSymbol(
symbol.ContainingType, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
if (WouldNotifyToSpecificSymbol(definitionItem, rqName1, solution, cancellationToken, out filePath, out lineNumber, out charOffset) ||
WouldNotifyToSpecificSymbol(definitionItem, rqName2, solution, cancellationToken, out filePath, out lineNumber, out charOffset))
{
return true;
}
......@@ -201,7 +198,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
}
public bool WouldNotifyToSpecificSymbol(
ISymbol symbol, Solution solution, CancellationToken cancellationToken,
DefinitionItem definitionItem, string rqName, Solution solution, CancellationToken cancellationToken,
out string filePath, out int lineNumber, out int charOffset)
{
AssertIsForeground();
......@@ -209,9 +206,15 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
filePath = null;
lineNumber = 0;
charOffset = 0;
if (rqName == null)
{
return false;
}
if (!TryGetNavigationAPIRequiredArguments(
symbol, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify, out var rqname))
definitionItem, rqName, solution, cancellationToken,
out var hierarchy, out var itemID, out var navigationNotify))
{
return false;
}
......@@ -221,7 +224,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
int queryNavigateStatusCode = navigationNotify.QueryNavigateToSymbol(
hierarchy,
itemID,
rqname,
rqName,
out var navigateToHierarchy,
out var navigateToItem,
navigateToTextSpan,
......@@ -239,43 +242,38 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
}
private bool TryGetNavigationAPIRequiredArguments(
ISymbol symbol,
DefinitionItem definitionItem,
string rqName,
Solution solution,
CancellationToken cancellationToken,
out IVsHierarchy hierarchy,
out uint itemID,
out IVsSymbolicNavigationNotify navigationNotify,
out string rqname)
out IVsSymbolicNavigationNotify navigationNotify)
{
AssertIsForeground();
hierarchy = null;
navigationNotify = null;
rqname = null;
itemID = (uint)VSConstants.VSITEMID.Nil;
if (!symbol.Locations.Any())
if (rqName == null)
{
return false;
}
var sourceLocations = symbol.Locations.Where(loc => loc.IsInSource);
var sourceLocations = definitionItem.SourceSpans;
if (!sourceLocations.Any())
{
return false;
}
var documents = sourceLocations.Select(loc => solution.GetDocument(loc.SourceTree)).WhereNotNull();
if (!documents.Any())
{
return false;
}
var documents = sourceLocations.SelectAsArray(loc => loc.Document);
// We can only pass one itemid to IVsSymbolicNavigationNotify, so prefer itemids from
// documents we consider to be "generated" to give external language services the best
// chance of participating.
var generatedDocuments = documents.Where(d => d.IsGeneratedCode(cancellationToken));
var generatedDocuments = documents.WhereAsArray(d => d.IsGeneratedCode(cancellationToken));
var documentToUse = generatedDocuments.FirstOrDefault() ?? documents.First();
if (!TryGetVsHierarchyAndItemId(documentToUse, out hierarchy, out itemID))
......@@ -289,8 +287,7 @@ public bool TrySymbolNavigationNotify(ISymbol symbol, Solution solution, Cancell
return false;
}
rqname = LanguageServices.RQName.From(symbol);
return rqname != null;
return true;
}
private bool TryGetVsHierarchyAndItemId(Document document, out IVsHierarchy hierarchy, out uint itemID)
......
......@@ -62,11 +62,11 @@ protected override void Initialize()
var method = compilerFailFast.GetMethod(nameof(FailFast.OnFatalException), BindingFlags.Static | BindingFlags.NonPublic);
property.SetValue(null, Delegate.CreateDelegate(property.PropertyType, method));
RegisterFindResultsLibraryManager();
var componentModel = (IComponentModel)this.GetService(typeof(SComponentModel));
_workspace = componentModel.GetService<VisualStudioWorkspace>();
RegisterFindResultsLibraryManager();
// Ensure the options persisters are loaded since we have to fetch options from the shell
componentModel.GetExtensions<IOptionPersister>();
......@@ -186,7 +186,7 @@ private void RegisterFindResultsLibraryManager()
var objectManager = this.GetService(typeof(SVsObjectManager)) as IVsObjectManager2;
if (objectManager != null)
{
_libraryManager = new LibraryManager(this);
_libraryManager = new LibraryManager(_workspace, this);
if (ErrorHandler.Failed(objectManager.RegisterSimpleLibrary(_libraryManager, out _libraryManagerCookie)))
{
......
......@@ -1457,6 +1457,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer auto properties.
/// </summary>
internal static string prefer_auto_properties {
get {
return ResourceManager.GetString("prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prefer braces.
/// </summary>
......@@ -1547,6 +1556,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer throwing properties.
/// </summary>
internal static string prefer_throwing_properties {
get {
return ResourceManager.GetString("prefer_throwing_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Preference.
/// </summary>
......@@ -2164,7 +2182,7 @@ internal class ServicesVSResources {
internal static string Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio {
get {
return ResourceManager.GetString("Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_er" +
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio", resourceCulture);
"ror_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio", resourceCulture);
}
}
......@@ -2332,6 +2350,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to When generating properties:.
/// </summary>
internal static string When_generating_properties {
get {
return ResourceManager.GetString("When_generating_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to When inserting properties, events and methods, place them:.
/// </summary>
......
......@@ -873,7 +873,7 @@ Additional information: {1}</value>
<data name="Pick_members" xml:space="preserve">
<value>Pick members</value>
</data>
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual Studio" xml:space="preserve">
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio" xml:space="preserve">
<value>Unfortunately, a process used by Visual Studio has encountered an unrecoverable error. We recommend saving your work, and then closing and restarting Visual Studio.</value>
</data>
<data name="Add_a_symbol_specification" xml:space="preserve">
......@@ -900,6 +900,15 @@ Additional information: {1}</value>
<data name="VisualStudioWorkspace_TryApplyChanges_cannot_be_called_from_a_background_thread" xml:space="preserve">
<value>VisualStudioWorkspace.TryApplyChanges cannot be called from a background thread.</value>
</data>
<data name="prefer_auto_properties" xml:space="preserve">
<value>prefer auto properties</value>
</data>
<data name="prefer_throwing_properties" xml:space="preserve">
<value>prefer throwing properties</value>
</data>
<data name="When_generating_properties" xml:space="preserve">
<value>When generating properties:</value>
</data>
<data name="Options" xml:space="preserve">
<value>Options</value>
</data>
......
......@@ -6,23 +6,17 @@
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editor.FindUsages;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Undo;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.GeneratedCodeRecognition;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.VisualStudio.ComponentModelHost;
using Microsoft.VisualStudio.Composition;
using Microsoft.VisualStudio.LanguageServices.Implementation;
using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel;
using Microsoft.VisualStudio.LanguageServices.Implementation.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.Shell;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices
......@@ -32,18 +26,15 @@ namespace Microsoft.VisualStudio.LanguageServices
internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl
{
private readonly IEnumerable<Lazy<IStreamingFindUsagesPresenter>> _streamingPresenters;
private readonly IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> _referencedSymbolsPresenters;
[ImportingConstructor]
private RoslynVisualStudioWorkspace(
ExportProvider exportProvider,
[ImportMany] IEnumerable<Lazy<IStreamingFindUsagesPresenter>> streamingPresenters,
[ImportMany] IEnumerable<Lazy<IDefinitionsAndReferencesPresenter>> referencedSymbolsPresenters,
[ImportMany] IEnumerable<IDocumentOptionsProviderFactory> documentOptionsProviderFactories)
: base(exportProvider.AsExportProvider())
{
_streamingPresenters = streamingPresenters;
_referencedSymbolsPresenters = referencedSymbolsPresenters;
foreach (var providerFactory in documentOptionsProviderFactories)
{
......@@ -203,44 +194,15 @@ private static bool TryResolveSymbol(ISymbol symbol, Project project, Cancellati
public override bool TryFindAllReferences(ISymbol symbol, Project project, CancellationToken cancellationToken)
{
if (!_referencedSymbolsPresenters.Any())
{
return false;
}
if (!TryResolveSymbol(symbol, project, cancellationToken, out var searchSymbol, out var searchProject))
{
return false;
}
var searchSolution = searchProject.Solution;
var result = SymbolFinder
.FindReferencesAsync(searchSymbol, searchSolution, cancellationToken)
.WaitAndGetResult(cancellationToken).ToList();
if (result != null)
{
DisplayReferencedSymbols(searchSolution, result);
return true;
}
// Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an
// object browser item. Now ObjectBrowser goes through the streaming-FindRefs system.
return false;
}
public override void DisplayReferencedSymbols(
Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
public override void DisplayReferencedSymbols(Solution solution, IEnumerable<ReferencedSymbol> referencedSymbols)
{
var service = this.Services.GetService<IDefinitionsAndReferencesFactory>();
var definitionsAndReferences = service.CreateDefinitionsAndReferences(
solution, referencedSymbols,
includeHiddenLocations: false, cancellationToken: CancellationToken.None);
foreach (var presenter in _referencedSymbolsPresenters)
{
presenter.Value.DisplayResult(definitionsAndReferences);
return;
}
// Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an
// object browser item. Now ObjectBrowser goes through the streaming-FindRefs system.
}
internal override object GetBrowseObject(SymbolListItem symbolListItem)
......
......@@ -33,7 +33,7 @@ public override void PreprocessNavigate(ITableEntryHandle entry, TableEntryNavig
var supportsNavigation = entry.Identity as ISupportsNavigation;
if (supportsNavigation != null)
{
if (supportsNavigation.TryNavigateTo())
if (supportsNavigation.TryNavigateTo(e.IsPreview))
{
e.Handled = true;
return;
......
......@@ -4,6 +4,6 @@ namespace Microsoft.VisualStudio.LanguageServices.FindUsages
{
internal interface ISupportsNavigation
{
bool TryNavigateTo();
bool TryNavigateTo(bool isPreview);
}
}
\ No newline at end of file
......@@ -34,10 +34,8 @@ private class RoslynDefinitionBucket : DefinitionBucket, ISupportsNavigation
DefinitionItem = definitionItem;
}
public bool TryNavigateTo()
{
return DefinitionItem.TryNavigateTo();
}
public bool TryNavigateTo(bool isPreview)
=> DefinitionItem.TryNavigateTo(_presenter._workspace, isPreview);
public override bool TryGetValue(string key, out object content)
{
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports System.Text
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Editor.FindUsages
Imports Microsoft.CodeAnalysis.Editor.UnitTests
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.FindSymbols
Imports Microsoft.VisualStudio.Composition
Imports Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ObjectBrowser.Mocks
Imports Roslyn.Test.Utilities
Imports Roslyn.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.FindResults
Public Class FindResultsTests
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1138943")>
Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInCSharp() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
class $$C
{
const int z = 1;
public C() { }
public C(int x) { }
void T()
{
var a = new C();
var b = new C(5);
var c = C.z;
}
}"]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C() ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (11, 21) : var a = new C();")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C(int) ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (12, 21) : var b = new C(5);")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] class C ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.cs - (13, 17) : var c = C.z;"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
<WorkItem(1138943, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1138943")>
Public Async Function ConstructorReferencesShouldNotAppearUnderClassNodeInVisualBasic() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
Class C$$
Const z = 1
Public Sub New()
End Sub
Public Sub New(x As Integer)
End Sub
Sub T()
Dim a = New C()
Dim b = New C(5)
Dim d = C.z
End Sub
End Class"]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Class C ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (14, 17) : Dim d = C.z")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (12, 21) : Dim a = New C()")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources._1_reference})",
TestFindResult.CreateReference("Test1.vb - (13, 21) : Dim b = New C(5)"))
}
Await VerifyAsync(markup, LanguageNames.VisualBasic, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestSourceNamespace() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
namespace NS$$
{
}
namespace NS
{
}
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace NS ({String.Format(ServicesVSResources._0_references, 2)})",
TestFindResult.CreateReference("Test1.cs - (2, 11) : namespace NS"),
TestFindResult.CreateReference("Test1.cs - (6, 11) : namespace NS"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
<WpfFact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Async Function TestMetadataNamespace() As System.Threading.Tasks.Task
Dim markup = <Text><![CDATA[
using System$$;
using System.Threading;
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace System ({String.Format(ServicesVSResources._0_references, 2)})",
TestFindResult.CreateReference("Test1.cs - (2, 7) : using System;"),
TestFindResult.CreateReference("Test1.cs - (3, 7) : using System.Threading;"))
}
Await VerifyAsync(markup, LanguageNames.CSharp, expectedResults)
End Function
Private Shared ReadOnly s_exportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(
TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic.WithParts(
GetType(MockDocumentNavigationServiceProvider),
GetType(MockSymbolNavigationServiceProvider),
GetType(DefaultDefinitionsAndReferencesFactory)))
Private Async Function VerifyAsync(markup As XElement, languageName As String, expectedResults As IList(Of AbstractTreeItem)) As System.Threading.Tasks.Task
Dim workspaceXml =
<Workspace>
<Project Language=<%= languageName %> CommonReferences="true">
<Document><%= markup %></Document>
</Project>
</Workspace>
Using workspace = TestWorkspace.Create(workspaceXml, exportProvider:=s_exportProvider)
Dim doc = workspace.Documents.Single()
Dim workspaceDoc = workspace.CurrentSolution.GetDocument(doc.Id)
If Not doc.CursorPosition.HasValue Then
Assert.True(False, "Missing caret location in document.")
End If
Dim symbol = Await SymbolFinder.FindSymbolAtPositionAsync(workspaceDoc, doc.CursorPosition.Value, CancellationToken.None)
Assert.NotNull(symbol)
Dim result = Await SymbolFinder.FindReferencesAsync(symbol, workspace.CurrentSolution, CancellationToken.None)
WpfTestCase.RequireWpfFact($"The {NameOf(Implementation.Library.FindResults.LibraryManager)} assumes it's on the VS UI thread and thus uses WaitAndGetResult")
Dim libraryManager = New LibraryManager(New MockServiceProvider(New MockComponentModel(workspace.ExportProvider)))
Dim factory = workspace.Services.GetService(Of IDefinitionsAndReferencesFactory)
Dim definitionsAndReferences = factory.CreateDefinitionsAndReferences(
workspace.CurrentSolution, result,
includeHiddenLocations:=False, cancellationToken:=CancellationToken.None)
Dim findReferencesTree = libraryManager.CreateFindReferencesItems(definitionsAndReferences)
' We cannot control the ordering of top-level nodes in the Find Symbol References window, so do not consider ordering of these items here.
expectedResults = expectedResults.OrderBy(Function(n) n.DisplayText).ToList()
findReferencesTree = findReferencesTree.OrderBy(Function(n) n.DisplayText).ToList()
VerifyResultsTree(expectedResults, findReferencesTree)
End Using
End Function
Private Sub VerifyResultsTree(expectedResults As IList(Of AbstractTreeItem), findReferencesTree As IList(Of AbstractTreeItem))
Assert.True(expectedResults.Count = findReferencesTree.Count, $"Unexpected number of results. Expected: {expectedResults.Count} Actual: {findReferencesTree.Count}
Expected Items:
{GetResultText(expectedResults)}
Actual Items:
{GetResultText(findReferencesTree)}
")
For index = 0 To expectedResults.Count - 1
Dim expectedItem = expectedResults(index)
Dim actualItem = findReferencesTree(index)
Assert.Equal(expectedItem.DisplayText, actualItem.DisplayText)
Assert.Equal(expectedItem.CanGoToDefinition, actualItem.CanGoToDefinition)
Assert.Equal(expectedItem.CanGoToReference, actualItem.CanGoToReference)
Dim expectedHasChildren = expectedItem.Children IsNot Nothing AndAlso expectedItem.Children.Count > 0
Dim actualHasChildren = actualItem.Children IsNot Nothing AndAlso actualItem.Children.Count > 0
Assert.Equal(expectedHasChildren, actualHasChildren)
If expectedHasChildren Then
VerifyResultsTree(expectedItem.Children, actualItem.Children)
End If
Next
End Sub
Private Function GetResultText(items As IList(Of AbstractTreeItem)) As String
Dim indentString = String.Empty
Dim stringBuilder = New StringBuilder()
GetResultTextWorker(items, stringBuilder, indentString)
Return stringBuilder.ToString()
End Function
Private Sub GetResultTextWorker(items As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
For Each item In items
stringBuilder.Append(indentString)
stringBuilder.Append(item.DisplayText)
stringBuilder.Append(" [Kind: " &
If(item.CanGoToDefinition, "Def", String.Empty) &
If(item.CanGoToReference, "Ref", String.Empty) &
If(item.CanGoToDefinition OrElse item.CanGoToDefinition, "None", String.Empty) &
"]")
If item.Children IsNot Nothing AndAlso item.Children.Any() Then
GetResultTextWorker(item.Children, stringBuilder, indentString + " ")
End If
Next
End Sub
Private Class TestFindResult
Inherits AbstractTreeItem
Public ReadOnly expectedCanGoToDefinition As Boolean?
Public ReadOnly expectedCanGoToReference As Boolean?
Public Overrides Function CanGoToDefinition() As Boolean
Return If(expectedCanGoToDefinition, True)
End Function
Public Overrides Function CanGoToReference() As Boolean
Return If(expectedCanGoToReference, True)
End Function
Public Shared Function CreateDefinition(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=True, expectedCanGoToReference:=False)
End Function
Public Shared Function CreateReference(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=True)
End Function
Public Shared Function CreateUnnavigable(displayText As String, ParamArray children As TestFindResult()) As TestFindResult
Return New TestFindResult(displayText, children, expectedCanGoToDefinition:=False, expectedCanGoToReference:=False)
End Function
Private Sub New(displayText As String,
children As TestFindResult(),
expectedCanGoToDefinition As Boolean,
expectedCanGoToReference As Boolean)
MyBase.New(0)
Me.DisplayText = displayText
Me.expectedCanGoToDefinition = expectedCanGoToDefinition
Me.expectedCanGoToReference = expectedCanGoToReference
Me.Children = If(children IsNot Nothing AndAlso children.Length > 0, children, Nothing)
End Sub
Public Overrides Function GoToSource() As Integer
Throw New NotImplementedException()
End Function
End Class
End Class
End Namespace
\ No newline at end of file
......@@ -330,7 +330,6 @@
<Compile Include="EditAndContinue\EditAndContinueWorkspaceServiceTests.vb" />
<Compile Include="EditAndContinue\VsReadOnlyDocumentTrackerTests.vb" />
<Compile Include="ExtractInterface\ExtractInterfaceViewModelTests.vb" />
<Compile Include="FindResults\FindResultsTests.vb" />
<Compile Include="GenerateType\GenerateTypeViewModelTests.vb" />
<Compile Include="GoToDefinition\GoToDefinitionApiTests.vb" />
<Compile Include="Help\HelpTests.vb" />
......@@ -411,4 +410,4 @@
<None Include="project.json" />
</ItemGroup>
<Import Project="..\..\..\..\build\Targets\Imports.targets" />
</Project>
</Project>
\ No newline at end of file
......@@ -30,7 +30,7 @@ static void Main(string[] args)
}
}";
[Fact, Trait(Traits.Feature, Traits.Features.EncapsulateField)]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18879"), Trait(Traits.Feature, Traits.Features.EncapsulateField)]
public void EncapsulateThroughCommand()
{
SetUpEditor(TestSource);
......
......@@ -20,7 +20,7 @@ public CSharpNavigateTo(VisualStudioInstanceFactory instanceFactory)
{
}
[Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18870"), Trait(Traits.Feature, Traits.Features.SignatureHelp)]
public void NavigateTo()
{
var project = new ProjectUtils.Project(ProjectName);
......
......@@ -61,7 +61,7 @@ public void VerifySharpLoadCompletionList()
VisualStudio.InteractiveWindow.Verify.CompletionItemsExist("C:");
}
[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18877")]
public void VerifyNoCrashOnEnter()
{
VisualStudio.Workspace.SetUseSuggestionMode(false);
......
......@@ -214,7 +214,7 @@ public void AddAssemblyReferenceAndTypesToInteractive()
VisualStudio.Workspace.WaitForAsyncOperations(FeatureAttribute.SolutionCrawler);
}
[Fact]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18880")]
public void ResetInteractiveFromProjectAndVerify()
{
var assembly = new ProjectUtils.AssemblyReference("System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
......
......@@ -18,7 +18,7 @@ public BasicNavigateTo(VisualStudioInstanceFactory instanceFactory)
{
}
[Fact, Trait(Traits.Feature, Traits.Features.SignatureHelp)]
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/18870"), Trait(Traits.Feature, Traits.Features.SignatureHelp)]
public void NavigateTo()
{
var project = new ProjectUtils.Project(ProjectName);
......
......@@ -110,6 +110,16 @@
x:Name="at_the_end"
Content="{x:Static local:AdvancedOptionPageStrings.Option_at_the_end}"/>
</StackPanel>
<Label Content="{x:Static local:AdvancedOptionPageStrings.Option_When_generating_properties}"/>
<StackPanel Margin="15, 0, 0, 0">
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_throwing_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_throwing_properties}"/>
<RadioButton GroupName="Property_generation_behavior"
x:Name="prefer_auto_properties"
Content="{x:Static local:AdvancedOptionPageStrings.Option_prefer_auto_properties}"/>
</StackPanel>
</StackPanel>
</GroupBox>
......
......@@ -45,6 +45,9 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
BindToOption(with_other_members_of_the_same_kind, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.WithOtherMembersOfTheSameKind, LanguageNames.VisualBasic)
BindToOption(at_the_end, ImplementTypeOptions.InsertionBehavior, ImplementTypeInsertionBehavior.AtTheEnd, LanguageNames.VisualBasic)
BindToOption(prefer_throwing_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferThrowingProperties, LanguageNames.VisualBasic)
BindToOption(prefer_auto_properties, ImplementTypeOptions.PropertyGenerationBehavior, ImplementTypePropertyGenerationBehavior.PreferAutoProperties, LanguageNames.VisualBasic)
End Sub
End Class
End Namespace
\ No newline at end of file
......@@ -84,6 +84,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Public ReadOnly Property Option_with_other_members_of_the_same_kind As String =
ServicesVSResources.with_other_members_of_the_same_kind
Public ReadOnly Property Option_When_generating_properties As String =
ServicesVSResources.When_generating_properties
Public ReadOnly Property Option_prefer_auto_properties As String =
ServicesVSResources.prefer_auto_properties
Public ReadOnly Property Option_prefer_throwing_properties As String =
ServicesVSResources.prefer_throwing_properties
Public ReadOnly Property Option_at_the_end As String =
ServicesVSResources.at_the_end
......
......@@ -246,18 +246,27 @@ public PatternMatches GetMatches(string candidate, string dottedContainer)
/// so, unless you need to know the full set of matches, use this version.
/// </remarks>
/// <param name="candidate">The word being tested.</param>
/// <param name="inludeMatchSpans">Whether or not the matched spans should be included with results</param>
/// <param name="includeMatchSpans">Whether or not the matched spans should be included with results</param>
/// <returns>If this was a match, the first element of the set of match types that occurred while matching the
/// patterns. If it was not a match, it returns null.</returns>
public PatternMatch? GetFirstMatch(string candidate, bool inludeMatchSpans = false)
public PatternMatch? GetFirstMatch(
string candidate, bool includeMatchSpans)
{
if (SkipMatch(candidate))
{
return null;
}
return MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: false) ??
MatchPatternSegment(candidate, inludeMatchSpans, _fullPatternSegment, wantAllMatches: false, allMatches: out _, fuzzyMatch: true);
return GetFirstMatchWorker(candidate, includeMatchSpans, fuzzyMatch: false) ??
GetFirstMatchWorker(candidate, includeMatchSpans, fuzzyMatch: true);
}
private PatternMatch? GetFirstMatchWorker(
string candidate, bool includeMatchSpans, bool fuzzyMatch)
{
return MatchPatternSegment(
candidate, includeMatchSpans, _fullPatternSegment,
wantAllMatches: false, allMatches: out _, fuzzyMatch: fuzzyMatch);
}
private StringBreaks GetWordSpans(string word)
......@@ -268,13 +277,6 @@ private StringBreaks GetWordSpans(string word)
}
}
internal PatternMatch? MatchSingleWordPattern_ForTestingOnly(string candidate)
{
return MatchPatternChunk(candidate, includeMatchSpans: true,
patternChunk: _fullPatternSegment.TotalTextChunk, punctuationStripped: false,
fuzzyMatch: false);
}
private static bool ContainsUpperCaseLetter(string pattern)
{
// Expansion of "foreach(char ch in pattern)" to avoid a CharEnumerator allocation
......@@ -443,12 +445,10 @@ private static bool ContainsSpaceOrAsterisk(string text)
var singleMatch = MatchPatternSegment(candidate, includeMatchSpans, patternSegment,
wantAllMatches: true, fuzzyMatch: fuzzyMatch, allMatches: out var matches);
if (singleMatch.HasValue)
{
return ImmutableArray.Create(singleMatch.Value);
}
return matches;
return singleMatch.HasValue
? ImmutableArray.Create(singleMatch.Value)
: matches;
}
/// <summary>
......@@ -554,17 +554,18 @@ private static bool ContainsSpaceOrAsterisk(string text)
return null;
}
if (!wantAllMatches || subWordTextChunks.Length == 1)
{
// Stop at the first word
return result;
}
matches.Add(result.Value);
}
allMatches = matches.ToImmutable();
return null;
if (wantAllMatches && matches.Count >= 2)
{
allMatches = matches.ToImmutable();
return null;
}
else
{
return matches.FirstOrNullable();
}
}
finally
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册