提交 d94c8128 编写于 作者: C Cyrus Najmabadi

Merge branch 'master' into typeScriptCodeRefactorings

......@@ -114,15 +114,13 @@ build_roslyn()
BOOTSTRAP_ARG=/p:BootstrapBuildPath=$(pwd)/Binaries/Bootstrap
echo Running the bootstrap build
echo -e "\tCompiling the C# compiler"
run_xbuild $BOOTSTRAP_ARG src/Compilers/CSharp/csc/csc.csproj
if [ "$FULL_RUN" = "true" ]; then
echo -e "\tCompiling the VB compiler"
run_xbuild $BOOTSTRAP_ARG src/Compilers/VisualBasic/vbc/vbc.csproj
run_xbuild $BOOTSTRAP_ARG src/Compilers/CSharp/Test/Syntax/CSharpCompilerSyntaxTest.csproj
run_xbuild $BOOTSTRAP_ARG src/Compilers/CSharp/Test/CommandLine/CSharpCommandLineTest.csproj
run_xbuild $BOOTSTRAP_ARG src/Compilers/VisualBasic/Test/Syntax/BasicCompilerSyntaxTest.vbproj
echo -e "\tCompiling CrossPlatform.sln"
run_xbuild $BOOTSTRAP_ARG src/CrossPlatform.sln
else
echo -e "\tCompiling the C# compiler"
run_xbuild $BOOTSTRAP_ARG src/Compilers/CSharp/csc/csc.csproj
fi
}
......@@ -132,13 +130,22 @@ test_roslyn()
return
fi
XUNIT_RUNNER=packages/xunit.runners.$XUNIT_VERSION/tools/xunit.console.x86.exe
mono $XUNIT_RUNNER Binaries/Debug/Roslyn.Compilers.CSharp.Syntax.UnitTests.dll -noshadow
mono $XUNIT_RUNNER Binaries/Debug/Roslyn.Compilers.CSharp.CommandLine.UnitTests.dll -noshadow
mono $XUNIT_RUNNER Binaries/Debug/Roslyn.Compilers.VisualBasic.Syntax.UnitTests.dll -noshadow
local xunit_runner=packages/xunit.runners.$XUNIT_VERSION/tools/xunit.console.x86.exe
local test_binaries=(
Roslyn.Compilers.CSharp.Syntax.UnitTests
Roslyn.Compilers.CSharp.CommandLine.UnitTests
Roslyn.Compilers.VisualBasic.Syntax.UnitTests)
local any_failed=false
for i in "${test_binaries[@]}"
do
mono $xunit_runner Binaries/Debug/$i.dll -xml Binaries/Debug/$i.TestResults.xml -noshadow
if [ $? -ne 0 ]; then
any_failed=true
fi
done
if [ $? -ne 0 ]; then
echo Unit tests failed
if [ "$any_failed" = "true" ]; then
echo Unit test failed
exit 1
fi
}
......
......@@ -5312,7 +5312,7 @@ private void CheckManifestString(string source, OutputKind outputKind, string ex
}
[WorkItem(544926, "DevDiv")]
[Fact]
[ConditionalFact(typeof(ClrOnly))]
public void ResponseFilesWithNoconfig_01()
{
string source = Temp.CreateFile("a.cs").WriteAllText(@"
......
......@@ -19,11 +19,6 @@
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\..\..\Scripting\Test\ScriptingTest.csproj">
<Project>{2DAE4406-7A89-4B5F-95C3-BC5472CE47CE}</Project>
<Name>ScriptingTest</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Test\Utilities\TestUtilities.csproj">
<Project>{76C6F005-C89D-4348-BB4A-391898DBEB52}</Project>
<Name>TestUtilities</Name>
......@@ -225,4 +220,4 @@
<Import Project="..\..\..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -4,10 +4,19 @@
<ProjectGuid>d0bc9be7-24f6-40ca-8dc6-fcb93bd44b34</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import
Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props')" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props')" />
<PropertyGroup />
<Import Project="AnalyzerDriver.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets')" />
</Project>
......@@ -487,13 +487,6 @@ ICscHostObject cscHostObject
{
param = "Analyzers"; this.CheckHostObjectSupport(param, analyzerHostObject.SetAnalyzers(this.Analyzers));
}
// For host objects which support it, pass the list of analyzer dependencies.
IAnalyzerDependencyHostObject analyzerDependencyHostObject = cscHostObject as IAnalyzerDependencyHostObject;
if (analyzerDependencyHostObject != null)
{
param = "AnalyzerDependencies"; this.CheckHostObjectSupport(param, analyzerDependencyHostObject.SetAnalyzerDependencies(this.AnalyzerDependencies));
}
}
catch (Exception e) when (!Utilities.IsCriticalException(e))
{
......
// 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.Runtime.InteropServices;
using Microsoft.Build.Framework;
namespace Microsoft.CodeAnalysis.BuildTasks
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("13926637-09A6-438A-9418-DE6B9D2BEC6B")]
public interface IAnalyzerDependencyHostObject
{
bool SetAnalyzerDependencies(ITaskItem[] analyzerDependencies);
}
}
......@@ -63,7 +63,6 @@
<DesignTime>True</DesignTime>
<DependentUpon>ErrorString.resx</DependentUpon>
</Compile>
<Compile Include="IAnalyzerDependencyHostObject.cs" />
<Compile Include="ICscHostObject5.cs" />
<Compile Include="IVbcHostObject6.cs" />
<Compile Include="ManagedCompiler.cs" />
......@@ -97,4 +96,4 @@
<Import Project="..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\..\build\VSL.Imports.Closed.targets" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
......@@ -56,12 +56,6 @@ public ITaskItem[] Analyzers
get { return (ITaskItem[])_store["Analyzers"]; }
}
public ITaskItem[] AnalyzerDependencies
{
set { _store["AnalyzerDependencies"] = value; }
get { return (ITaskItem[])_store["AnalyzerDependencies"]; }
}
// We do not support BugReport because it always requires user interaction,
// which will cause a hang.
......@@ -593,9 +587,6 @@ protected internal virtual void AddResponseFileCommands(CommandLineBuilderExtens
// Append the analyzers.
this.AddAnalyzersToCommandLine(commandLine);
// Append the analyzer dependencies.
this.AddAnalyzerDependenciesToCommandLine(commandLine);
// Append additional files.
this.AddAdditionalFilesToCommandLine(commandLine);
......@@ -621,27 +612,6 @@ private void AddAnalyzersToCommandLine(CommandLineBuilderExtension commandLine)
}
}
/// <summary>
/// Adds a "/analyzerdependency:" switch to the command line for each provided analyzer dependency.
///
/// Note that even though MSBuild makes a distinction between analyzers and dependencies, the
/// command-line compilers do not--both are passed in via "/analyzer".
/// </summary>
private void AddAnalyzerDependenciesToCommandLine(CommandLineBuilderExtension commandLine)
{
// If there were no analyzers passed in, don't add any /analyzer: switches
// on the command-line.
if ((this.AnalyzerDependencies == null) || (this.AnalyzerDependencies.Length == 0))
{
return;
}
foreach (ITaskItem dependency in this.AnalyzerDependencies)
{
commandLine.AppendSwitchIfNotNull("/analyzer:", dependency.ItemSpec);
}
}
/// <summary>
/// Adds a "/additionalfile:" switch to the command line for each additional file.
/// </summary>
......
......@@ -70,7 +70,6 @@
AdditionalFiles="@(AdditionalFiles)"
AllowUnsafeBlocks="$(AllowUnsafeBlocks)"
Analyzers="@(Analyzer)"
AnalyzerDependencies="@(AnalyzerDependency)"
ApplicationConfiguration="$(AppConfigForCompiler)"
BaseAddress="$(BaseAddress)"
CheckForOverflowUnderflow="$(CheckForOverflowUnderflow)"
......
......@@ -58,7 +58,6 @@
AddModules="@(AddModules)"
AdditionalFiles="@(AdditionalFiles)"
Analyzers="@(Analyzer)"
AnalyzerDependencies="@(AnalyzerDependency)"
BaseAddress="$(BaseAddress)"
CodeAnalysisRuleSet="$(ResolvedCodeAnalysisRuleSet)"
CodePage="$(CodePage)"
......
......@@ -840,13 +840,6 @@ IVbcHostObject vbcHostObject
param = "AdditionalFiles"; this.CheckHostObjectSupport(param, analyzerHostObject.SetAdditionalFiles(this.AdditionalFiles));
}
// For host objects which support them, set the analyzers' dependencies.
IAnalyzerDependencyHostObject analyzerDependencyHostObject = vbcHostObject as IAnalyzerDependencyHostObject;
if (analyzerDependencyHostObject != null)
{
param = "AnalyzerDependencies"; this.CheckHostObjectSupport(param, analyzerDependencyHostObject.SetAnalyzerDependencies(this.AnalyzerDependencies));
}
param = "BaseAddress"; this.CheckHostObjectSupport(param, vbcHostObject.SetBaseAddress(this.TargetType, this.GetBaseAddressInHex()));
param = "CodePage"; this.CheckHostObjectSupport(param, vbcHostObject.SetCodePage(this.CodePage));
param = "DebugType"; this.CheckHostObjectSupport(param, vbcHostObject.SetDebugType(this.EmitDebugInformation, this.DebugType));
......
......@@ -4,10 +4,18 @@
<ProjectGuid>c1930979-c824-496b-a630-70f5369a636f</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import
Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props"
Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props')" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props')" />
<PropertyGroup />
<Import Project="SharedCollections.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
<Import
Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets"
Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets')" />
</Project>
......@@ -22,7 +22,7 @@ public static MetadataReference CompileToMetadata(string source, string assembly
references = new[] { TestBase.MscorlibRef };
}
var compilation = CreateCompilationWithMscorlib(source, assemblyName, references);
var verifier = s_instance.CompileAndVerify(compilation, emitters: TestEmitters.CCI, verify: verify);
var verifier = Instance.CompileAndVerify(compilation, emitters: TestEmitters.CCI, verify: verify);
return MetadataReference.CreateFromImage(verifier.EmittedAssemblyData);
}
......@@ -37,7 +37,9 @@ private static VisualBasicCompilation CreateCompilationWithMscorlib(string sourc
return VisualBasicCompilation.Create(assemblyName, new[] { tree }, references, options);
}
private static BasicTestBase s_instance = new BasicTestBase();
private static BasicTestBase s_instance;
private static BasicTestBase Instance => s_instance ?? (s_instance = new BasicTestBase());
private sealed class BasicTestBase : CommonTestBase
{
......
......@@ -50,7 +50,7 @@
<Name>BasicCodeAnalysis.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\vbc\vbc.csproj">
<Project>{2AC2755D-9437-4271-BBDE-1A3795A0C320}</Project>
<Project>{E58EE9D7-1239-4961-A0C1-F9EC3952C4C1}</Project>
<Name>vbc</Name>
</ProjectReference>
<ProjectReference Include="..\..\Portable\BasicCodeAnalysis.vbproj">
......
......@@ -289,4 +289,4 @@
<Import Project="..\..\..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -53,11 +53,6 @@
<Project>{2523D0E6-DF32-4A3E-8AE0-A19BFFAE2EF6}</Project>
<Name>BasicCodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Scripting\Test\ScriptingTest.csproj">
<Project>{2DAE4406-7A89-4B5F-95C3-BC5472CE47CE}</Project>
<Name>CommonScriptingTest</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<ItemGroup Label="File References">
<Reference Include="..\..\..\..\..\packages\System.Reflection.Metadata.$(SystemReflectionMetadataVersion)\lib\portable-net45+win8\System.Reflection.Metadata.dll" />
......@@ -209,4 +204,4 @@
<Import Project="..\..\..\..\..\build\Roslyn.Toolsets.Xunit.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
此差异已折叠。
// 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.Linq;
using System.Threading;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Editor.UnitTests.ChangeSignature;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -168,5 +171,91 @@ void B()
TestChangeSignatureViaCommand(LanguageNames.CSharp, markup, updatedSignature: updatedSignature, expectedUpdatedInvocationDocumentCode: updatedCode);
}
[Fact, Trait(Traits.Feature, Traits.Features.ChangeSignature)]
[WorkItem(1102830)]
[WorkItem(784, "https://github.com/dotnet/roslyn/issues/784")]
public void RemoveParameters_ExtensionMethodInAnotherFile()
{
var workspaceXml = @"
<Workspace>
<Project Language=""C#"" AssemblyName=""CSharpAssembly"" CommonReferences=""true"">";
for (int i = 0; i <= 4; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += @"
<Document FilePath = ""C5.cs"">
public class C5
{
}
public static class C5Ext
{
public void $$Ext(this C5 c, int i, string s)
{
}
}
</Document>";
for (int i = 6; i <= 9; i++)
{
workspaceXml += $@"
<Document FilePath = ""C{i}.cs"">
class C{i}
{{
void M()
{{
C5 c = new C5();
c.Ext(1, ""two"");
}}
}}
</Document>";
}
workspaceXml += @"
</Project>
</Workspace>";
// Ext(this F f, int i, string s) --> Ext(this F f, string s)
// If a reference does not bind correctly, it will believe Ext is not an extension
// method and remove the string argument instead of the int argument.
var updatedSignature = new[] { 0, 2 };
using (var testState = new ChangeSignatureTestState(XElement.Parse(workspaceXml)))
{
testState.TestChangeSignatureOptionsService.IsCancelled = false;
testState.TestChangeSignatureOptionsService.UpdatedSignature = updatedSignature;
var result = testState.ChangeSignature();
Assert.True(result.Succeeded);
Assert.Null(testState.ErrorMessage);
foreach (var updatedDocument in testState.Workspace.Documents.Select(d => result.UpdatedSolution.GetDocument(d.Id)))
{
if (updatedDocument.Name == "C5.cs")
{
Assert.Contains("void Ext(this C5 c, string s)", updatedDocument.GetTextAsync(CancellationToken.None).Result.ToString());
}
else
{
Assert.Contains(@"c.Ext(""two"");", updatedDocument.GetTextAsync(CancellationToken.None).Result.ToString());
}
}
}
}
}
}
......@@ -610,6 +610,7 @@
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.RenameTrackingCodeAction.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.RenameTrackingCommitter.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.RenameTrackingSolutionSet.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.StateMachine.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.Tagger.cs" />
<Compile Include="Implementation\RenameTracking\RenameTrackingTaggerProvider.TrackingSession.cs" />
......
......@@ -1600,15 +1600,6 @@ internal class EditorFeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Rename &apos;{0}&apos; to &apos;{1}&apos; with preview....
/// </summary>
internal static string RenameToWithPreview {
get {
return ResourceManager.GetString("RenameToWithPreview", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Renaming anonymous type members is not yet supported..
/// </summary>
......
......@@ -618,9 +618,6 @@
<data name="PreviewCodeChanges" xml:space="preserve">
<value>Preview Code Changes:</value>
</data>
<data name="RenameToWithPreview" xml:space="preserve">
<value>Rename '{0}' to '{1}' with preview...</value>
</data>
<data name="PreviewChanges" xml:space="preserve">
<value>Preview Changes</value>
</data>
......
......@@ -84,7 +84,7 @@
</imaging:CrispImage>
<!-- description text -->
<TextBlock Grid.Column="1" Text="{Binding Path=Description}" FontWeight="Bold" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Stretch">
<TextBlock Grid.Column="1" Text="{Binding Path=Description, Mode=OneTime}" FontWeight="Bold" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Stretch">
<!-- if severity is error, make the description text red -->
<TextBlock.Style>
......
......@@ -15,6 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.InlineRename
{
internal class DashboardViewModel : INotifyPropertyChanged, IDisposable
{
private const int SymbolDescriptionTextLength = 15;
private readonly Visibility _renameOverloadsVisibility;
private DashboardSeverity _severity = DashboardSeverity.None;
......@@ -155,10 +156,17 @@ public string Description
{
get
{
return string.Format(EditorFeaturesResources.Rename1, this.Session.OriginalSymbolName);
return string.Format(EditorFeaturesResources.Rename1, GetTruncatedSymbolName());
}
}
private string GetTruncatedSymbolName()
{
return this.Session.OriginalSymbolName.Length < SymbolDescriptionTextLength
? this.Session.OriginalSymbolName
: this.Session.OriginalSymbolName.Substring(0, SymbolDescriptionTextLength) + "...";
}
public string SearchText
{
get { return _searchText; }
......
......@@ -43,11 +43,8 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
// any fixes.
if (RenameTrackingTaggerProvider.CanInvokeRename(document))
{
var action1 = RenameTrackingTaggerProvider.CreateCodeAction(document, diagnostic, _waitIndicator, _refactorNotifyServices, _undoHistoryRegistry, showPreview: false);
context.RegisterCodeFix(action1, diagnostic);
var action2 = RenameTrackingTaggerProvider.CreateCodeAction(document, diagnostic, _waitIndicator, _refactorNotifyServices, _undoHistoryRegistry, showPreview: true);
context.RegisterCodeFix(action2, diagnostic);
var action = RenameTrackingTaggerProvider.CreateCodeAction(document, diagnostic, _waitIndicator, _refactorNotifyServices, _undoHistoryRegistry);
context.RegisterCodeFix(action, diagnostic);
}
return SpecializedTasks.EmptyTask;
......
......@@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.CodeAnalysis.Notification;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Text;
......@@ -21,62 +22,78 @@ private class RenameTrackingCodeAction : CodeAction
private readonly string _title;
private readonly Document _document;
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;
private readonly bool _showPreview;
private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
private RenameTrackingCommitter _renameTrackingCommitter;
public RenameTrackingCodeAction(Document document, string title, IEnumerable<IRefactorNotifyService> refactorNotifyServices, ITextUndoHistoryRegistry undoHistoryRegistry, bool showPreview)
public RenameTrackingCodeAction(Document document, string title, IEnumerable<IRefactorNotifyService> refactorNotifyServices, ITextUndoHistoryRegistry undoHistoryRegistry)
{
_document = document;
_title = title;
_refactorNotifyServices = refactorNotifyServices;
_undoHistoryRegistry = undoHistoryRegistry;
_showPreview = showPreview;
}
public override string Title { get { return _title; } }
protected override Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
{
// Invoked directly without previewing.
if (_renameTrackingCommitter == null)
{
if (!TryInitializeRenameTrackingCommitter(cancellationToken))
{
return SpecializedTasks.EmptyEnumerable<CodeActionOperation>();
}
}
var committerOperation = new RenameTrackingCommitterOperation(_renameTrackingCommitter);
return Task.FromResult(SpecializedCollections.SingletonEnumerable(committerOperation as CodeActionOperation));
}
protected override async Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken)
{
if (!_document.Project.Solution.Workspace.Options.GetOption(FeatureOnOffOptions.RenameTrackingPreview, _document.Project.Language) ||
!TryInitializeRenameTrackingCommitter(cancellationToken))
{
return await SpecializedTasks.EmptyEnumerable<CodeActionOperation>().ConfigureAwait(false);
}
var solutionSet = await _renameTrackingCommitter.RenameSymbolAsync(cancellationToken).ConfigureAwait(false);
return SpecializedCollections.SingletonEnumerable(
(CodeActionOperation)new ApplyChangesOperation(solutionSet.RenamedSolution));
}
private bool TryInitializeRenameTrackingCommitter(CancellationToken cancellationToken)
{
SourceText text;
StateMachine stateMachine;
ITextBuffer textBuffer;
if (_document.TryGetText(out text))
{
textBuffer = text.Container.TryGetTextBuffer();
if (textBuffer == null)
{
Environment.FailFast(string.Format("document with name {0} is open but textBuffer is null. Textcontainer is of type {1}. SourceText is: {2}",
_document.Name, text.Container.GetType().FullName, text.ToString()));
}
var textBuffer = text.Container.GetTextBuffer();
if (textBuffer.Properties.TryGetProperty(typeof(StateMachine), out stateMachine))
{
TrackingSession trackingSession;
if (stateMachine.CanInvokeRename(out trackingSession, cancellationToken: cancellationToken))
if (!stateMachine.CanInvokeRename(out trackingSession, cancellationToken: cancellationToken))
{
var snapshotSpan = stateMachine.TrackingSession.TrackingSpan.GetSpan(stateMachine.Buffer.CurrentSnapshot);
var str = string.Format(EditorFeaturesResources.RenameTo, stateMachine.TrackingSession.OriginalName, snapshotSpan.GetText());
var committerOperation = new RenameTrackingCommitterOperation(new RenameTrackingCommitter(stateMachine, snapshotSpan, _refactorNotifyServices, _undoHistoryRegistry, str, showPreview: _showPreview));
return Task.FromResult(SpecializedCollections.SingletonEnumerable(committerOperation as CodeActionOperation));
// The rename tracking could be dismissed while a codefix is still cached
// in the lightbulb. If this happens, do not perform the rename requested
// and instead let the user know their fix will not be applied.
_document.Project.Solution.Workspace.Services.GetService<INotificationService>()
?.SendNotification(EditorFeaturesResources.TheRenameTrackingSessionWasCancelledAndIsNoLongerAvailable, severity: NotificationSeverity.Error);
return false;
}
// The rename tracking could be dismissed while a codefix is still cached
// in the lightbulb. If this happens, do not perform the rename requested
// and instead let the user know their fix will not be applied.
_document.Project.Solution.Workspace.Services.GetService<INotificationService>()
?.SendNotification(EditorFeaturesResources.TheRenameTrackingSessionWasCancelledAndIsNoLongerAvailable, severity: NotificationSeverity.Error);
return SpecializedTasks.EmptyEnumerable<CodeActionOperation>();
var snapshotSpan = stateMachine.TrackingSession.TrackingSpan.GetSpan(stateMachine.Buffer.CurrentSnapshot);
var newName = snapshotSpan.GetText();
var displayText = string.Format(EditorFeaturesResources.RenameTo, stateMachine.TrackingSession.OriginalName, newName);
_renameTrackingCommitter = new RenameTrackingCommitter(stateMachine, snapshotSpan, _refactorNotifyServices, _undoHistoryRegistry, displayText);
return true;
}
}
Debug.Assert(false, "RenameTracking codefix invoked on a document for which the text or StateMachine is not available.");
return SpecializedTasks.EmptyEnumerable<CodeActionOperation>();
}
protected override Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyEnumerable<CodeActionOperation>();
return false;
}
private sealed class RenameTrackingCommitterOperation : CodeActionOperation
......
// 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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
......@@ -27,30 +29,28 @@ private class RenameTrackingCommitter : ForegroundThreadAffinitizedObject
private readonly IEnumerable<IRefactorNotifyService> _refactorNotifyServices;
private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
private readonly string _displayText;
private readonly bool _showPreview;
private readonly AsyncLazy<RenameTrackingSolutionSet> _renameSymbolResultGetter;
public RenameTrackingCommitter(
StateMachine stateMachine,
SnapshotSpan snapshotSpan,
IEnumerable<IRefactorNotifyService> refactorNotifyServices,
ITextUndoHistoryRegistry undoHistoryRegistry,
string displayText,
bool showPreview)
string displayText)
{
_stateMachine = stateMachine;
_snapshotSpan = snapshotSpan;
_refactorNotifyServices = refactorNotifyServices;
_undoHistoryRegistry = undoHistoryRegistry;
_displayText = displayText;
_showPreview = showPreview;
_renameSymbolResultGetter = new AsyncLazy<RenameTrackingSolutionSet>(c => RenameSymbolWorkerAsync(c), cacheResult: true);
}
public void Commit(CancellationToken cancellationToken)
{
AssertIsForeground();
bool clearTrackingSession = false;
RenameSymbolAndApplyChanges(cancellationToken, out clearTrackingSession);
bool clearTrackingSession = ApplyChangesToWorkspace(cancellationToken);
// Clear the state machine so that future updates to the same token work,
// and any text changes caused by this update are not interpreted as
......@@ -61,47 +61,30 @@ public void Commit(CancellationToken cancellationToken)
}
}
private void RenameSymbolAndApplyChanges(CancellationToken cancellationToken, out bool clearTrackingSession)
public async Task<RenameTrackingSolutionSet> RenameSymbolAsync(CancellationToken cancellationToken)
{
AssertIsForeground();
return await _renameSymbolResultGetter.GetValueAsync(cancellationToken).ConfigureAwait(false);
}
// Undo must backtrack to the state with the original identifier before the state
// with the user-edited identifier. For example,
//
// 1. Original: void M() { M(); }
// 2. User types: void Method() { M(); }
// 3. Invoke rename: void Method() { Method(); }
//
// The undo process should be as follows
// 1. Back to original name everywhere: void M() { M(); } // No tracking session
// 2. Back to state 2 above: void Method() { M(); } // Resume tracking session
// 3. Finally, start undoing typing: void M() { M(); }
//
// As far as the user can see, undo state 1 never actually existed so we must insert
// a state here to facilitate the undo. Do the work to obtain the intermediate and
// final solution without updating the workspace, and then finally disallow
// cancellation and update the workspace twice.
private async Task<RenameTrackingSolutionSet> RenameSymbolWorkerAsync(CancellationToken cancellationToken)
{
var document = _snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
var newName = _snapshotSpan.GetText();
Document document = _snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
if (document == null)
{
Contract.Fail("Invoked rename tracking smart tag but cannot find the document for the snapshot span.");
}
// Get copy of solution with the original name in the place of the renamed name
var solutionWithOriginalName = CreateSolutionWithOriginalName(document, cancellationToken);
// Get the symbol for the identifier we're renaming (which has now been reverted to
// its original name) and invoke the rename service.
ISymbol symbol;
if (!TryGetSymbol(solutionWithOriginalName, document.Id, cancellationToken, out symbol))
var symbol = await TryGetSymbolAsync(solutionWithOriginalName, document.Id, cancellationToken).ConfigureAwait(false);
if (symbol == null)
{
Contract.Fail("Invoked rename tracking smart tag but cannot find the symbol");
Contract.Fail("Invoked rename tracking smart tag but cannot find the symbol.");
}
var newName = _snapshotSpan.GetText();
var optionSet = document.Project.Solution.Workspace.Options;
if (_stateMachine.TrackingSession.ForceRenameOverloads)
......@@ -109,37 +92,40 @@ private void RenameSymbolAndApplyChanges(CancellationToken cancellationToken, ou
optionSet = optionSet.WithChangedOption(RenameOptions.RenameOverloads, true);
}
var renamedSolution = Renamer.RenameSymbolAsync(solutionWithOriginalName, symbol, newName, optionSet, cancellationToken).WaitAndGetResult(cancellationToken);
var renamedSolution = await Renamer.RenameSymbolAsync(solutionWithOriginalName, symbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
return new RenameTrackingSolutionSet(symbol, solutionWithOriginalName, renamedSolution);
}
private bool ApplyChangesToWorkspace(CancellationToken cancellationToken)
{
AssertIsForeground();
// Now that the necessary work has been done to create the intermediate and final
// solutions, check one more time for cancellation before making all of the
// solutions during PreparePreview, check one more time for cancellation before making all of the
// workspace changes.
cancellationToken.ThrowIfCancellationRequested();
if (_showPreview)
{
var previewService = renamedSolution.Workspace.Services.GetService<IPreviewDialogService>();
renamedSolution = previewService.PreviewChanges(
string.Format(EditorFeaturesResources.PreviewChangesOf, EditorFeaturesResources.Rename),
"vs.csharp.refactoring.rename",
string.Format(
EditorFeaturesResources.RenameToTitle,
_stateMachine.TrackingSession.OriginalName,
newName),
symbol.ToDisplayString(),
symbol.GetGlyph(),
renamedSolution,
solutionWithOriginalName);
if (renamedSolution == null)
{
// User clicked cancel.
clearTrackingSession = false;
return;
}
}
// Undo must backtrack to the state with the original identifier before the state
// with the user-edited identifier. For example,
//
// 1. Original: void M() { M(); }
// 2. User types: void Method() { M(); }
// 3. Invoke rename: void Method() { Method(); }
//
// The undo process should be as follows
// 1. Back to original name everywhere: void M() { M(); } // No tracking session
// 2. Back to state 2 above: void Method() { M(); } // Resume tracking session
// 3. Finally, start undoing typing: void M() { M(); }
//
// As far as the user can see, undo state 1 never actually existed so we must insert
// a state here to facilitate the undo. Do the work to obtain the intermediate and
// final solution without updating the workspace, and then finally disallow
// cancellation and update the workspace twice.
var renameTrackingSolutionSet = RenameSymbolAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var document = _snapshotSpan.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
var newName = _snapshotSpan.GetText();
var workspace = document.Project.Solution.Workspace;
......@@ -147,15 +133,15 @@ private void RenameSymbolAndApplyChanges(CancellationToken cancellationToken, ou
// text changes caused by undo and redo actions as potential renames, so carefully
// update the state machine after undo/redo actions.
var changedDocuments = renamedSolution.GetChangedDocuments(solutionWithOriginalName);
var changedDocuments = renameTrackingSolutionSet.RenamedSolution.GetChangedDocuments(renameTrackingSolutionSet.OriginalSolution);
// When this action is undone (the user has undone twice), restore the state
// machine to so that they can continue their original rename tracking session.
UpdateWorkspaceForResetOfTypedIdentifier(workspace, solutionWithOriginalName);
UpdateWorkspaceForResetOfTypedIdentifier(workspace, renameTrackingSolutionSet.OriginalSolution);
// Now that the solution is back in its original state, notify third parties about
// the coming rename operation.
if (!_refactorNotifyServices.TryOnBeforeGlobalSymbolRenamed(workspace, changedDocuments, symbol, newName, throwOnFailure: false))
if (!_refactorNotifyServices.TryOnBeforeGlobalSymbolRenamed(workspace, changedDocuments, renameTrackingSolutionSet.Symbol, newName, throwOnFailure: false))
{
var notificationService = workspace.Services.GetService<INotificationService>();
notificationService.SendNotification(
......@@ -163,8 +149,7 @@ private void RenameSymbolAndApplyChanges(CancellationToken cancellationToken, ou
EditorFeaturesResources.RenameSymbol,
NotificationSeverity.Error);
clearTrackingSession = true;
return;
return true;
}
// move all changes to final solution based on the workspace's current solution, since the current solution
......@@ -174,15 +159,15 @@ private void RenameSymbolAndApplyChanges(CancellationToken cancellationToken, ou
{
// because changes have already been made to the workspace (UpdateWorkspaceForResetOfTypedIdentifier() above),
// these calls can't be cancelled and must be allowed to complete.
var root = renamedSolution.GetDocument(docId).GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
var root = renameTrackingSolutionSet.RenamedSolution.GetDocument(docId).GetSyntaxRootAsync(CancellationToken.None).WaitAndGetResult(CancellationToken.None);
finalSolution = finalSolution.WithDocumentSyntaxRoot(docId, root);
}
// Undo/redo on this action must always clear the state machine
UpdateWorkspaceForGlobalIdentifierRename(workspace, finalSolution, workspace.CurrentSolution, _displayText, changedDocuments, symbol, newName);
UpdateWorkspaceForGlobalIdentifierRename(workspace, finalSolution, workspace.CurrentSolution, _displayText, changedDocuments, renameTrackingSolutionSet.Symbol, newName);
RenameTrackingDismisser.DismissRenameTracking(workspace, changedDocuments);
clearTrackingSession = true;
return true;
}
private Solution CreateSolutionWithOriginalName(Document document, CancellationToken cancellationToken)
......@@ -209,20 +194,19 @@ private Solution CreateSolutionWithOriginalName(Document document, CancellationT
return solution;
}
private bool TryGetSymbol(Solution solutionWithOriginalName, DocumentId documentId, CancellationToken cancellationToken, out ISymbol symbol)
private async Task<ISymbol> TryGetSymbolAsync(Solution solutionWithOriginalName, DocumentId documentId, CancellationToken cancellationToken)
{
var documentWithOriginalName = solutionWithOriginalName.GetDocument(documentId);
var syntaxTreeWithOriginalName = documentWithOriginalName.GetSyntaxTreeAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var syntaxTreeWithOriginalName = await documentWithOriginalName.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);
var syntaxFacts = documentWithOriginalName.GetLanguageService<ISyntaxFactsService>();
var semanticFacts = documentWithOriginalName.GetLanguageService<ISemanticFactsService>();
var semanticModel = documentWithOriginalName.GetSemanticModelAsync(cancellationToken).WaitAndGetResult(cancellationToken);
var semanticModel = await documentWithOriginalName.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
var token = syntaxTreeWithOriginalName.GetTouchingWord(_snapshotSpan.Start, syntaxFacts, cancellationToken);
var tokenRenameInfo = RenameUtilities.GetTokenRenameInfo(semanticFacts, semanticModel, token, cancellationToken);
symbol = tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;
return symbol != null;
return tokenRenameInfo.HasSymbols ? tokenRenameInfo.Symbols.First() : null;
}
private void UpdateWorkspaceForResetOfTypedIdentifier(Workspace workspace, Solution newSolution)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking
{
internal sealed partial class RenameTrackingTaggerProvider
{
/// <summary>
/// Tracks the solution before and after rename.
/// </summary>
private class RenameTrackingSolutionSet
{
public ISymbol Symbol { get; }
public Solution OriginalSolution { get; }
public Solution RenamedSolution { get; }
public RenameTrackingSolutionSet(
ISymbol symbolToRename,
Solution originalSolution,
Solution renamedSolution)
{
Symbol = symbolToRename;
OriginalSolution = originalSolution;
RenamedSolution = renamedSolution;
}
}
}
}
......@@ -7,6 +7,7 @@
using Microsoft.CodeAnalysis.Editor.Shared.Options;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Adornments;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.Text.Tagging;
......@@ -14,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking
{
internal sealed partial class RenameTrackingTaggerProvider
{
private class Tagger : ITagger<RenameTrackingTag>, IDisposable
private class Tagger : ITagger<RenameTrackingTag>, ITagger<IErrorTag>, IDisposable
{
private readonly StateMachine _stateMachine;
private readonly ITextUndoHistoryRegistry _undoHistoryRegistry;
......@@ -52,6 +53,16 @@ private void StateMachine_TrackingSessionUpdated()
}
public IEnumerable<ITagSpan<RenameTrackingTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
return GetTags(spans, RenameTrackingTag.Instance);
}
IEnumerable<ITagSpan<IErrorTag>> ITagger<IErrorTag>.GetTags(NormalizedSnapshotSpanCollection spans)
{
return GetTags(spans, new ErrorTag(PredefinedErrorTypeNames.Suggestion));
}
private IEnumerable<ITagSpan<T>> GetTags<T>(NormalizedSnapshotSpanCollection spans, T tag) where T : ITag
{
if (!_stateMachine.Buffer.GetOption(InternalFeatureOnOffOptions.RenameTracking))
{
......@@ -68,7 +79,7 @@ public IEnumerable<ITagSpan<RenameTrackingTag>> GetTags(NormalizedSnapshotSpanCo
var snapshotSpan = trackingSession.TrackingSpan.GetSpan(span.Snapshot);
if (span.IntersectsWith(snapshotSpan))
{
yield return new TagSpan<RenameTrackingTag>(snapshotSpan, RenameTrackingTag.Instance);
yield return new TagSpan<T>(snapshotSpan, tag);
}
}
}
......
......@@ -27,6 +27,7 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.RenameTracking
/// </summary>
[Export(typeof(ITaggerProvider))]
[TagType(typeof(RenameTrackingTag))]
[TagType(typeof(IErrorTag))]
[ContentType(ContentTypeNames.RoslynContentType)]
[TextViewRole(PredefinedTextViewRoles.Editable)]
internal sealed partial class RenameTrackingTaggerProvider : ITaggerProvider
......@@ -137,18 +138,16 @@ internal static async Task<IEnumerable<Diagnostic>> GetDiagnosticsAsync(SyntaxTr
Diagnostic diagnostic,
IWaitIndicator waitIndicator,
IEnumerable<IRefactorNotifyService> refactorNotifyServices,
ITextUndoHistoryRegistry undoHistoryRegistry,
bool showPreview)
ITextUndoHistoryRegistry undoHistoryRegistry)
{
// This can run on a background thread.
var renameToResourceString = showPreview ? EditorFeaturesResources.RenameToWithPreview : EditorFeaturesResources.RenameTo;
var message = string.Format(
renameToResourceString,
EditorFeaturesResources.RenameTo,
diagnostic.Properties[RenameTrackingDiagnosticAnalyzer.RenameFromPropertyKey],
diagnostic.Properties[RenameTrackingDiagnosticAnalyzer.RenameToPropertyKey]);
return new RenameTrackingCodeAction(document, message, refactorNotifyServices, undoHistoryRegistry, showPreview);
return new RenameTrackingCodeAction(document, message, refactorNotifyServices, undoHistoryRegistry);
}
internal static bool IsRenamableIdentifier(Task<TriggerIdentifierKind> isRenamableIdentifierTask, bool waitForResult, CancellationToken cancellationToken)
......@@ -199,7 +198,7 @@ internal static bool CanInvokeRename(Document document)
textBuffer = text.Container.TryGetTextBuffer();
return textBuffer != null &&
textBuffer.Properties.TryGetProperty(typeof(StateMachine), out stateMachine) &&
textBuffer.Properties.TryGetProperty(typeof(StateMachine), out stateMachine) &&
stateMachine.CanInvokeRename(out unused);
}
}
......
......@@ -41,6 +41,9 @@ internal static class FeatureOnOffOptions
[ExportOption]
public static readonly PerLanguageOption<bool> AutoFormattingOnSemicolon = new PerLanguageOption<bool>(OptionName, "Auto Formatting On Semicolon", defaultValue: true);
[ExportOption]
public static readonly PerLanguageOption<bool> RenameTrackingPreview = new PerLanguageOption<bool>(OptionName, "Rename Tracking Preview", defaultValue: true);
/// <summary>
/// This option is currently usued by Roslyn, but we might want to implement it in the
/// future. Keeping the option while it's unimplemented allows all upgrade paths to
......
......@@ -835,56 +835,6 @@ Enum E
}
}
[Fact, WorkItem(978099)]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTrackingPreviewChanges()
{
var code = @"
class C$$
{
}";
using (var state = new RenameTrackingTestState(code, LanguageNames.CSharp))
{
var mockPreview = state.Workspace.Services.GetService<IPreviewDialogService>() as MockPreviewDialogService;
mockPreview.Called = false;
mockPreview.ReturnsNull = false;
state.EditorOperations.InsertText("at");
state.AssertTag("C", "Cat", invokeAction: true, actionIndex: 1);
Assert.True(mockPreview.Called);
Assert.Equal(string.Format(EditorFeaturesResources.RenameToTitle, "C", "Cat"), mockPreview.Description);
Assert.Equal(string.Format(EditorFeaturesResources.PreviewChangesOf, EditorFeaturesResources.Rename), mockPreview.Title);
Assert.Equal("C", mockPreview.TopLevelName);
Assert.Equal(Glyph.ClassInternal, mockPreview.TopLevelGlyph);
}
}
[Fact]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTrackingCancelPreviewChanges()
{
var code = @"
class C$$
{
}";
var expected = @"
class Cat
{
}";
using (var state = new RenameTrackingTestState(code, LanguageNames.CSharp))
{
var mockPreview = state.Workspace.Services.GetService<IPreviewDialogService>() as MockPreviewDialogService;
mockPreview.Called = false;
mockPreview.ReturnsNull = true;
state.EditorOperations.InsertText("at");
state.AssertTag("C", "Cat", invokeAction: true, actionIndex: 1);
Assert.True(mockPreview.Called);
Assert.Equal(expected, state.HostDocument.TextBuffer.CurrentSnapshot.GetText());
state.AssertTag("C", "Cat");
}
}
[Fact, WorkItem(1028072)]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public void RenameTrackingDoesNotThrowAggregateException()
......
......@@ -154,7 +154,7 @@ public IList<Diagnostic> GetDocumentDiagnostics(Document document = null)
return DiagnosticProviderTestUtilities.GetDocumentDiagnostics(analyzer, document, document.GetSyntaxRootAsync(CancellationToken.None).Result.FullSpan).ToList();
}
public void AssertTag(string expectedFromName, string expectedToName, bool invokeAction = false, int actionIndex = 0)
public void AssertTag(string expectedFromName, string expectedToName, bool invokeAction = false)
{
WaitForAsyncOperations();
......@@ -176,15 +176,14 @@ public void AssertTag(string expectedFromName, string expectedToName, bool invok
var context = new CodeFixContext(document, diagnostics[0], (a, d) => actions.Add(a), CancellationToken.None);
_codeFixProvider.RegisterCodeFixesAsync(context).Wait();
// There should be two actions
Assert.Equal(2, actions.Count);
// There should only be one code action
Assert.Equal(1, actions.Count);
Assert.Equal(string.Format(EditorFeaturesResources.RenameTo, expectedFromName, expectedToName), actions[0].Title);
Assert.Equal(string.Format(EditorFeaturesResources.RenameToWithPreview, expectedFromName, expectedToName), actions[1].Title);
if (invokeAction)
{
var operations = actions[actionIndex]
var operations = actions[0]
.GetOperationsAsync(CancellationToken.None)
.WaitAndGetResult(CancellationToken.None)
.ToArray();
......
......@@ -40,6 +40,7 @@ internal unsafe static ImmutableArray<MetadataBlock> GetMetadataBlocks(this DkmC
try
{
ptr = module.GetMetaDataBytesPtr(out size);
Debug.Assert(size > 0);
block = GetMetadataBlock(ptr, size);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, module.FullName))
......@@ -66,6 +67,7 @@ internal static ImmutableArray<MetadataBlock> GetMetadataBlocks(GetMetadataBytes
uint size;
IntPtr ptr;
ptr = getMetaDataBytesPtrFunction(missingAssemblyIdentity, out size);
Debug.Assert(size > 0);
block = GetMetadataBlock(ptr, size);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, missingAssemblyIdentity.GetDisplayName()))
......@@ -99,6 +101,7 @@ internal static ImmutableArray<AssemblyReaders> MakeAssemblyReaders(this DkmClrI
uint size;
IntPtr ptr;
ptr = module.GetMetaDataBytesPtr(out size);
Debug.Assert(size > 0);
reader = new MetadataReader((byte*)ptr, (int)size);
}
catch (Exception e) when (MetadataUtilities.IsBadOrMissingMetadataException(e, module.FullName))
......
......@@ -259,6 +259,8 @@ private bool TryCreateUpdatedSolution(ChangeSignatureAnalyzedContext context, Ch
}
}
// Find and annotate all the relevant definitions
if (includeDefinitionLocations)
{
foreach (var def in symbolWithSyntacticParameters.Locations)
......@@ -279,7 +281,7 @@ private bool TryCreateUpdatedSolution(ChangeSignatureAnalyzedContext context, Ch
}
}
// TODO: Find references to containing type for Add methods & collection initializers (for example)
// Find and annotate all the relevant references
foreach (var location in symbol.Locations)
{
......@@ -314,6 +316,9 @@ private bool TryCreateUpdatedSolution(ChangeSignatureAnalyzedContext context, Ch
}
}
// Construct all the relevant syntax trees from the base solution
var updatedRoots = new Dictionary<DocumentId, SyntaxNode>();
foreach (var docId in nodesToUpdate.Keys)
{
var doc = updatedSolution.GetDocument(docId);
......@@ -337,7 +342,14 @@ private bool TryCreateUpdatedSolution(ChangeSignatureAnalyzedContext context, Ch
rules: GetFormattingRules(doc),
cancellationToken: CancellationToken.None);
updatedSolution = updatedSolution.WithDocumentSyntaxRoot(docId, formattedRoot);
updatedRoots[docId] = formattedRoot;
}
// Update the documents using the updated syntax trees
foreach (var docId in nodesToUpdate.Keys)
{
updatedSolution = updatedSolution.WithDocumentSyntaxRoot(docId, updatedRoots[docId]);
}
return true;
......
......@@ -209,18 +209,18 @@ public override string ToString()
public Diagnostic ToDiagnostic(SyntaxTree tree)
{
var location = Location.None;
if (tree == null)
if (tree != null)
{
var span = _textSpan ?? default(TextSpan);
var span = _textSpan.HasValue ? _textSpan.Value : GetTextSpan(tree.GetText());
location = tree.GetLocation(span);
}
else if (OriginalFilePath != null && _textSpan != null)
{
var span = _textSpan.Value;
location = Location.Create(OriginalFilePath, span, new LinePositionSpan(
new LinePosition(OriginalStartLine, OriginalStartColumn),
new LinePosition(OriginalEndLine, OriginalEndColumn)));
}
else
{
var span = _textSpan.HasValue ? _textSpan.Value : GetTextSpan(tree.GetText());
location = tree.GetLocation(span);
}
return Diagnostic.Create(this.Id, this.Category, this.Message, this.Severity, this.DefaultSeverity, this.IsEnabledByDefault, this.WarningLevel, this.Title, this.Description, this.HelpLink, location, customTags: this.CustomTags, properties: this.Properties);
}
......
......@@ -23,7 +23,7 @@ namespace Microsoft.CodeAnalysis.Test.Utilities
/// </summary>
public abstract partial class CommonTestBase : TestBase
{
static CommonTestBase()
private static ImmutableArray<Emitter> LoadEmitters()
{
var configFileName = Path.GetFileName(Assembly.GetExecutingAssembly().Location) + ".config";
var configFilePath = Path.Combine(Directory.GetCurrentDirectory(), configFileName);
......@@ -70,10 +70,12 @@ static CommonTestBase()
throw new Exception("Unable to load any emitter");
}
s_emitters = builder.ToImmutableArray();
return builder.ToImmutableArray();
}
}
}
return ImmutableArray<Emitter>.Empty;
}
internal abstract IEnumerable<IModuleSymbol> ReferencesToModuleSymbols(IEnumerable<MetadataReference> references, MetadataImportOptions importOptions = MetadataImportOptions.Public);
......@@ -100,7 +102,20 @@ static CommonTestBase()
bool collectEmittedAssembly,
bool verify);
private static readonly ImmutableArray<Emitter> s_emitters;
private static ImmutableArray<Emitter> s_emitters;
private static ImmutableArray<Emitter> Emitters
{
get
{
if (s_emitters.IsDefault)
{
s_emitters = LoadEmitters();
}
return s_emitters;
}
}
internal CompilationVerifier CompileAndVerify(
string source,
......@@ -198,7 +213,7 @@ static CommonTestBase()
sourceSymbolValidator(module, emitters);
}
if (s_emitters.IsDefaultOrEmpty)
if (Emitters.IsDefaultOrEmpty)
{
throw new InvalidOperationException(
@"You must specify at least one Emitter.
......@@ -217,7 +232,7 @@ static CommonTestBase()
CompilationVerifier result = null;
foreach (var emit in s_emitters)
foreach (var emit in Emitters)
{
var verifier = emit(this,
compilation,
......@@ -242,7 +257,7 @@ static CommonTestBase()
}
}
// If this fails, it means that more that all emmiters failed to return a validator
// If this fails, it means that more that all emitters failed to return a validator
// (i.e. none thought that they were applicable for the given input parameters).
Assert.NotNull(result);
......
......@@ -546,6 +546,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Show preview for _rename tracking.
/// </summary>
internal static string Option_RenameTrackingPreview {
get {
return ResourceManager.GetString("Option_RenameTrackingPreview", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Selection In Completion List.
/// </summary>
......
......@@ -399,4 +399,7 @@
<data name="Option_SelectionInCompletionList" xml:space="preserve">
<value>Selection In Completion List</value>
</data>
<data name="Option_RenameTrackingPreview" xml:space="preserve">
<value>Show preview for _rename tracking</value>
</data>
</root>
\ No newline at end of file
......@@ -36,6 +36,8 @@
Content="{x:Static local:AdvancedOptionPageStrings.Option_GenerateXmlDocCommentsForTripleSlash}" />
<CheckBox x:Name="ClosedFileDiagnostics"
Content="{x:Static local:AdvancedOptionPageStrings.Option_ClosedFileDiagnostics}" />
<CheckBox x:Name="RenameTrackingPreview"
Content="{x:Static local:AdvancedOptionPageStrings.Option_RenameTrackingPreview}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="OrganizeUsingsGroupBox"
......
......@@ -20,6 +20,7 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic
BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.CSharp);
BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp);
BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp);
BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp);
BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp);
BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptions.DontPutOutOrRefOnStruct, LanguageNames.CSharp);
BindToOption(AllowMovingDeclaration, ExtractMethodOptions.AllowMovingDeclaration, LanguageNames.CSharp);
......
......@@ -14,6 +14,11 @@ public static string Option_ClosedFileDiagnostics
get { return CSharpVSResources.Option_ClosedFileDiagnostics; }
}
public static string Option_RenameTrackingPreview
{
get { return CSharpVSResources.Option_RenameTrackingPreview; }
}
public static string Option_DisplayLineSeparators
{
get { return CSharpVSResources.Option_DisplayLineSeparators; }
......
......@@ -248,6 +248,12 @@ public int RenameSmartTagEnabled
set { SetBooleanOption(FeatureOnOffOptions.RenameTracking, value); }
}
public int RenameTrackingPreview
{
get { return GetBooleanOption(FeatureOnOffOptions.RenameTrackingPreview); }
set { SetBooleanOption(FeatureOnOffOptions.RenameTrackingPreview, value); }
}
public int ShowKeywords
{
get { return GetBooleanOption(CompletionOptions.IncludeKeywords); }
......
......@@ -148,7 +148,8 @@ private bool SupportsOnOffOption(IOption option)
option == FeatureOnOffOptions.FormatOnPaste ||
option == FeatureOnOffOptions.AutoXmlDocCommentGeneration ||
option == FeatureOnOffOptions.RefactoringVerification ||
option == FeatureOnOffOptions.RenameTracking;
option == FeatureOnOffOptions.RenameTracking ||
option == FeatureOnOffOptions.RenameTrackingPreview;
}
public override bool TryFetch(OptionKey optionKey, out object value)
......
......@@ -54,7 +54,22 @@ internal IList<AbstractTreeItem> CreateFindReferencesItems(Solution solution, IE
var definition = referencedSymbol.Definition;
var locations = definition.Locations;
foreach (var definitionLocation in definition.Locations)
// When finding references of a namespace, the data provided by the ReferenceFinder
// will include one definition location for each of its exact namespace
// declarations and each declaration of its children namespaces that mention
// its name (e.g. definitions of A.B will include "namespace A.B.C"). The list of
// reference locations includes both these namespace declarations and their
// references in usings or fully qualified names. Instead of showing many top-level
// declaration nodes (one of which will contain the full list of references
// including declarations, the rest of which will say "0 references" due to
// reference deduplication and there being no meaningful way to partition them),
// we pick a single declaration to use as the top-level definition and nest all of
// the declarations & references underneath.
var definitionLocations = definition.IsKind(SymbolKind.Namespace)
? SpecializedCollections.SingletonEnumerable(definition.Locations.First())
: definition.Locations;
foreach (var definitionLocation in definitionLocations)
{
var definitionItem = ConvertToDefinitionItem(solution, referencedSymbol, definitionLocation, definition.GetGlyph());
if (definitionItem != null)
......
......@@ -28,10 +28,10 @@ protected override bool CanGoToSource(uint index, VSOBJGOTOSRCTYPE srcType)
return true;
case VSOBJGOTOSRCTYPE.GS_DEFINITION:
return item.GlyphIndex != Glyph.Reference.GetGlyphIndex();
return item.CanGoToDefinition();
case VSOBJGOTOSRCTYPE.GS_REFERENCE:
return item.GlyphIndex == Glyph.Reference.GetGlyphIndex();
return item.CanGoToReference();
}
return false;
......
......@@ -20,7 +20,7 @@ public virtual bool UseGrayText
{
get
{
return this.Children == null || this.Children.Count == 0;
return this.Children == null || this.Children.Count == 0;
}
}
......@@ -51,6 +51,16 @@ protected AbstractTreeItem(ushort glyphIndex)
public abstract int GoToSource();
public virtual bool CanGoToReference()
{
return false;
}
public virtual bool CanGoToDefinition()
{
return false;
}
protected void SetDisplayProperties(string filePath, int mappedLineNumber, int mappedOffset, int offset, string lineText, int spanLength, string projectNameDisambiguator)
{
var sourceSnippet = lineText.Replace('\t', ' ').TrimStart(' ');
......
......@@ -56,6 +56,11 @@ private static string GetSourceLine(string filePath, int lineNumber, IServicePro
}
}
public override bool CanGoToDefinition()
{
return true;
}
public override int GoToSource()
{
return (TryOpenFile() && TryNavigateToPosition()) ? VSConstants.S_OK : VSConstants.E_FAIL;
......
......@@ -11,6 +11,7 @@ internal class MetadataDefinitionTreeItem : AbstractTreeItem
private readonly string _assemblyName;
private readonly string _symbolDefinition;
private readonly SymbolKey _symbolKey;
private readonly bool _canGoToDefinition;
private readonly Workspace _workspace;
private readonly ProjectId _referencingProjectId;
......@@ -20,19 +21,26 @@ public MetadataDefinitionTreeItem(Workspace workspace, ISymbol definition, Proje
_workspace = workspace;
_referencingProjectId = referencingProjectId;
_symbolKey = definition.GetSymbolKey();
_assemblyName = definition.ContainingAssembly.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
_assemblyName = definition.ContainingAssembly?.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat);
_symbolDefinition = definition.ToDisplayString(definitionDisplayFormat);
this.DisplayText = $"[{_assemblyName}] {_symbolDefinition}";
_canGoToDefinition = definition.Kind != SymbolKind.Namespace;
this.DisplayText = $"{GetAssemblyNameString()}{_symbolDefinition}";
}
public override bool CanGoToDefinition()
{
return _canGoToDefinition;
}
public override int GoToSource()
{
var resolution = _symbolKey.Resolve(_workspace.CurrentSolution.GetCompilationAsync(_referencingProjectId, CancellationToken.None).Result);
var symbol = ResolveSymbolInCurrentSolution();
var referencingProject = _workspace.CurrentSolution.GetProject(_referencingProjectId);
if (resolution.Symbol != null && referencingProject != null)
if (symbol != null && referencingProject != null)
{
var navigationService = _workspace.Services.GetService<ISymbolNavigationService>();
return navigationService.TryNavigateToSymbol(resolution.Symbol, referencingProject)
return navigationService.TryNavigateToSymbol(symbol, referencingProject)
? VSConstants.S_OK
: VSConstants.E_FAIL;
}
......@@ -40,13 +48,23 @@ public override int GoToSource()
return VSConstants.E_FAIL;
}
private ISymbol ResolveSymbolInCurrentSolution()
{
return _symbolKey.Resolve(_workspace.CurrentSolution.GetCompilationAsync(_referencingProjectId, CancellationToken.None).Result).Symbol;
}
internal override void SetReferenceCount(int referenceCount)
{
var referenceCountDisplay = referenceCount == 1
? ServicesVSResources.ReferenceCountSingular
: string.Format(ServicesVSResources.ReferenceCountPlural, referenceCount);
this.DisplayText = $"[{_assemblyName}] {_symbolDefinition} ({referenceCountDisplay})";
this.DisplayText = $"{GetAssemblyNameString()}{_symbolDefinition} ({referenceCountDisplay})";
}
private string GetAssemblyNameString()
{
return (_assemblyName != null && _canGoToDefinition) ? $"[{_assemblyName}] " : string.Empty;
}
}
}
......@@ -7,14 +7,21 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindRes
{
internal class SourceDefinitionTreeItem : AbstractSourceTreeItem
{
private readonly bool _canGoToDefinition;
private readonly string _symbolDisplay;
public SourceDefinitionTreeItem(Document document, TextSpan sourceSpan, ISymbol symbol, ushort glyphIndex)
: base(document, sourceSpan, glyphIndex)
{
_symbolDisplay = symbol.ToDisplayString(definitionDisplayFormat);
this.DisplayText = $"{GetProjectNameString()}{_symbolDisplay}";
this.DisplayText = $"[{document.Project.Name}] {_symbolDisplay}";
_canGoToDefinition = symbol.Kind != SymbolKind.Namespace;
}
public override bool CanGoToDefinition()
{
return _canGoToDefinition;
}
internal override void SetReferenceCount(int referenceCount)
......@@ -23,7 +30,12 @@ internal override void SetReferenceCount(int referenceCount)
? ServicesVSResources.ReferenceCountSingular
: string.Format(ServicesVSResources.ReferenceCountPlural, referenceCount);
this.DisplayText = $"[{_projectName}] {_symbolDisplay} ({referenceCountDisplay})";
this.DisplayText = $"{GetProjectNameString()}{_symbolDisplay} ({referenceCountDisplay})";
}
private string GetProjectNameString()
{
return (_projectName != null && _canGoToDefinition) ? $"[{_projectName}] " : string.Empty;
}
}
}
......@@ -29,6 +29,11 @@ public SourceReferenceTreeItem(Document document, TextSpan sourceSpan, ushort gl
}
}
public override bool CanGoToReference()
{
return true;
}
public override bool UseGrayText
{
get
......
......@@ -10,7 +10,7 @@
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal partial class AbstractProject : IAnalyzerHost, IAnalyzerDependencyHost
internal partial class AbstractProject : IAnalyzerHost
{
private AnalyzerFileWatcherService _analyzerFileWatcherService = null;
private AnalyzerDependencyCheckingService _dependencyCheckingService = null;
......@@ -111,21 +111,6 @@ public void RemoveAdditionalFile(string additionalFilePath)
RemoveAdditionalDocument(document);
}
public void AddAnalyzerDependency(string analyzerDependencyFullPath)
{
var analyzerLoader = _visualStudioWorkspaceOpt.Services.GetRequiredService<IAnalyzerService>().GetLoader();
analyzerLoader.AddDependencyLocation(analyzerDependencyFullPath);
GetAnalyzerFileWatcherService().AddPath(analyzerDependencyFullPath);
GetAnalyzerFileWatcherService().ErrorIfAnalyzerAlreadyLoaded(_id, analyzerDependencyFullPath);
}
public void RemoveAnalyzerDependency(string analyzerDependencyFullPath)
{
GetAnalyzerFileWatcherService().RemoveAnalyzerAlreadyLoadedDiagnostics(_id, analyzerDependencyFullPath);
}
private void ResetAnalyzerRuleSet(string ruleSetFileFullPath)
{
ClearAnalyzerRuleSet();
......
// 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.Runtime.InteropServices;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop
{
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("91A139C9-8197-42ED-9081-32FB5C75E482")]
internal interface IAnalyzerDependencyHost
{
void AddAnalyzerDependency([MarshalAs(UnmanagedType.LPWStr)] string analyzerDependencyFullPath);
void RemoveAnalyzerDependency([MarshalAs(UnmanagedType.LPWStr)] string analyzerDependencyFullPath);
}
}
......@@ -38,7 +38,6 @@
<Compile Include="Implementation\Preview\ReferenceChange.ProjectReferenceChange.cs" />
<Compile Include="Implementation\Preview\ReferenceChange.cs" />
<Compile Include="Implementation\ProjectSystem\AbstractEncProject.cs" />
<Compile Include="Implementation\ProjectSystem\Interop\IAnalyzerDependencyHost.cs" />
<Compile Include="Implementation\ProjectSystem\IVisualStudioWorkingFolder.cs" />
<Compile Include="Implementation\ProjectSystem\MetadataReferences\VisualStudioAnalyzerAssemblyLoaderService.cs" />
<Compile Include="Implementation\ProjectSystem\RuleSets\RuleSetEventHandler.cs" />
......
......@@ -37,12 +37,12 @@ class $$C
Dim expectedResults = New List(Of AbstractTreeItem) From
{
New TestFindResult($"[CSharpAssembly1] C.C() ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (11, 21) : var a = new C();")),
New TestFindResult($"[CSharpAssembly1] C.C(int) ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (12, 21) : var b = new C(5);")),
New TestFindResult($"[CSharpAssembly1] class C ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("CSharpAssembly1\Test1.cs - (13, 17) : var c = C.z;"))
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C() ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (11, 21) : var a = new C();")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] C.C(int) ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (12, 21) : var b = new C(5);")),
TestFindResult.CreateDefinition($"[CSharpAssembly1] class C ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (13, 17) : var c = C.z;"))
}
Verify(markup, LanguageNames.CSharp, expectedResults)
......@@ -70,17 +70,57 @@ End Class"]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
New TestFindResult($"[VisualBasicAssembly1] Class C ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (14, 17) : Dim d = C.z")),
New TestFindResult($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (12, 21) : Dim a = New C()")),
New TestFindResult($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources.ReferenceCountSingular})",
New TestFindResult("VisualBasicAssembly1\Test1.vb - (13, 21) : Dim b = New C(5)"))
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Class C ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("VisualBasicAssembly1\Test1.vb - (14, 17) : Dim d = C.z")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New() ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("VisualBasicAssembly1\Test1.vb - (12, 21) : Dim a = New C()")),
TestFindResult.CreateDefinition($"[VisualBasicAssembly1] Sub C.New(Integer) ({ServicesVSResources.ReferenceCountSingular})",
TestFindResult.CreateReference("VisualBasicAssembly1\Test1.vb - (13, 21) : Dim b = New C(5)"))
}
Verify(markup, LanguageNames.VisualBasic, expectedResults)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Sub TestSourceNamespace()
Dim markup = <Text><![CDATA[
namespace NS$$
{
}
namespace NS
{
}
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace NS ({String.Format(ServicesVSResources.ReferenceCountPlural, 2)})",
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (2, 11) : namespace NS"),
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (6, 11) : namespace NS"))
}
Verify(markup, LanguageNames.CSharp, expectedResults)
End Sub
<Fact, Trait(Traits.Feature, Traits.Features.FindReferences)>
Public Sub TestMetadataNamespace()
Dim markup = <Text><![CDATA[
using System$$;
using System.Threading;
]]></Text>
Dim expectedResults = New List(Of AbstractTreeItem) From
{
TestFindResult.CreateUnnavigable($"namespace System ({String.Format(ServicesVSResources.ReferenceCountPlural, 2)})",
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (2, 7) : using System;"),
TestFindResult.CreateReference("CSharpAssembly1\Test1.cs - (3, 7) : using System.Threading;"))
}
Verify(markup, LanguageNames.CSharp, expectedResults)
End Sub
Private Shared ReadOnly s_exportProvider As ExportProvider = MinimalTestExportProvider.CreateExportProvider(
TestExportProvider.MinimumCatalogWithCSharpAndVisualBasic.WithParts(
GetType(MockDocumentNavigationServiceProvider),
......@@ -130,6 +170,8 @@ Actual Items:
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
......@@ -142,22 +184,27 @@ Actual Items:
Next
End Sub
Private Function GetResultText(references As IList(Of AbstractTreeItem)) As String
Private Function GetResultText(items As IList(Of AbstractTreeItem)) As String
Dim indentString = String.Empty
Dim stringBuilder = New StringBuilder()
GetResultTextWorker(references, stringBuilder, indentString)
GetResultTextWorker(items, stringBuilder, indentString)
Return stringBuilder.ToString()
End Function
Private Sub GetResultTextWorker(references As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
For Each reference In references
Private Sub GetResultTextWorker(items As IList(Of AbstractTreeItem), stringBuilder As StringBuilder, indentString As String)
For Each item In items
stringBuilder.Append(indentString)
stringBuilder.AppendLine(reference.DisplayText)
If reference.Children IsNot Nothing AndAlso reference.Children.Any() Then
GetResultTextWorker(reference.Children, stringBuilder, 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
......@@ -165,10 +212,39 @@ Actual Items:
Private Class TestFindResult
Inherits AbstractTreeItem
Public Sub New(displayText As String, ParamArray children As TestFindResult())
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.Children = If(children.Length > 0, children, Nothing)
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
......
......@@ -119,6 +119,10 @@ private void OnSolutionExistsAndFullyLoadedContext(object sender, UIContextChang
private void LoadComponents()
{
// we need to load it as early as possible since we can have errors from
// package from each language very early
this.ComponentModel.GetService<VisualStudioTodoListTable>();
this.ComponentModel.GetService<VisualStudioErrorTaskList>();
this.ComponentModel.GetService<VisualStudioTodoTaskList>();
this.ComponentModel.GetService<HACK_ThemeColorFixer>();
......@@ -138,7 +142,6 @@ private void LoadComponentsBackground()
var commandHandlerServiceFactory = this.ComponentModel.GetService<ICommandHandlerServiceFactory>();
commandHandlerServiceFactory.Initialize(ContentTypeNames.RoslynContentType);
this.ComponentModel.GetService<VisualStudioTodoListTable>();
this.ComponentModel.GetService<VisualStudioDiagnosticListTable>();
this.ComponentModel.GetService<MiscellaneousTodoListTable>();
......
......@@ -141,12 +141,12 @@
<ProjectReference Include="..\CSharp\Impl\CSharpVisualStudio.csproj">
<Project>{5defadbd-44eb-47a2-a53e-f1282cc9e4e9}</Project>
<Name>CSharpVisualStudio</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup</IncludeOutputGroupsInVSIX>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup;PkgDefProjectOutputGroup</IncludeOutputGroupsInVSIX>
</ProjectReference>
<ProjectReference Include="..\VisualBasic\Impl\BasicVisualStudio.vbproj">
<Project>{d49439d7-56d2-450f-a4f0-74cb95d620e6}</Project>
<Name>BasicVisualStudio</Name>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup</IncludeOutputGroupsInVSIX>
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup;PkgDefProjectOutputGroup</IncludeOutputGroupsInVSIX>
</ProjectReference>
</ItemGroup>
<ItemGroup>
......
'------------------------------------------------------------------------------
' <auto-generated>
' This code was generated by a tool.
' Runtime Version:4.0.30319.35312
' Runtime Version:4.0.30319.0
'
' Changes to this file may cause incorrect behavior and will be lost if
' the code is regenerated.
......@@ -271,6 +271,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Show preview for _rename tracking.
'''</summary>
Friend Shared ReadOnly Property Option_RenameTrackingPreview() As String
Get
Return ResourceManager.GetString("Option_RenameTrackingPreview", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Prefer intrinsic predefined type keyword when declaring locals, parameters and members.
'''</summary>
......
......@@ -195,4 +195,7 @@
<data name="Option_Performance" xml:space="preserve">
<value>Performance</value>
</data>
<data name="Option_RenameTrackingPreview" xml:space="preserve">
<value>Show preview for _rename tracking</value>
</data>
</root>
\ No newline at end of file
......@@ -42,6 +42,8 @@
Content="{x:Static local:AdvancedOptionPageStrings.Option_GenerateXmlDocCommentsForTripleApostrophes}" />
<CheckBox x:Name="ClosedFileDiagnostics"
Content="{x:Static local:AdvancedOptionPageStrings.Option_ClosedFileDiagnostics}" />
<CheckBox x:Name="RenameTrackingPreview"
Content="{x:Static local:AdvancedOptionPageStrings.Option_RenameTrackingPreview}" />
</StackPanel>
</GroupBox>
<GroupBox x:Uid="ExtractMethodGroupBox"
......
......@@ -19,6 +19,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
BindToOption(DisplayLineSeparators, FeatureOnOffOptions.LineSeparator, LanguageNames.VisualBasic)
BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.VisualBasic)
BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.VisualBasic)
BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.VisualBasic)
BindToOption(GenerateXmlDocCommentsForTripleApostrophes, FeatureOnOffOptions.AutoXmlDocCommentGeneration, LanguageNames.VisualBasic)
BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptions.DontPutOutOrRefOnStruct, LanguageNames.VisualBasic)
BindToOption(AllowMovingDeclaration, ExtractMethodOptions.AllowMovingDeclaration, LanguageNames.VisualBasic)
......
......@@ -21,6 +21,12 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End Get
End Property
Public ReadOnly Property Option_RenameTrackingPreview As String
Get
Return BasicVSResources.Option_RenameTrackingPreview
End Get
End Property
Public ReadOnly Property Option_DisplayLineSeparators As String
Get
Return BasicVSResources.Option_DisplayLineSeparators
......
......@@ -53,6 +53,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
End Set
End Property
Public Property RenameTrackingPreview As Boolean
Get
Return GetBooleanOption(FeatureOnOffOptions.RenameTrackingPreview)
End Get
Set(value As Boolean)
SetBooleanOption(FeatureOnOffOptions.RenameTrackingPreview, value)
End Set
End Property
Public Property DisplayLineSeparators As Boolean
Get
Return GetBooleanOption(FeatureOnOffOptions.LineSeparator)
......
......@@ -43,6 +43,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "Outlining", FeatureOnOffOptions.Outlining),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "EnableHighlightReferences", FeatureOnOffOptions.ReferenceHighlighting),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "EnableHighlightRelatedKeywords", FeatureOnOffOptions.KeywordHighlighting),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "RenameTrackingPreview", FeatureOnOffOptions.RenameTrackingPreview),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "AutoEndInsert", FeatureOnOffOptions.EndConstruct),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "AutoComment", FeatureOnOffOptions.AutoXmlDocCommentGeneration),
New KeyValuePair(Of String, IOption)(SettingStorageRoot + "AutoRequiredMemberInsert", FeatureOnOffOptions.AutomaticInsertionOfAbstractOrInterfaceMembers)})
......@@ -79,6 +80,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
[option].Name = FeatureOnOffOptions.Outlining.Name Or
[option].Name = FeatureOnOffOptions.ReferenceHighlighting.Name Or
[option].Name = FeatureOnOffOptions.KeywordHighlighting.Name Or
[option].Name = FeatureOnOffOptions.RenameTrackingPreview.Name Or
[option].Name = FeatureOnOffOptions.EndConstruct.Name Or
[option].Name = FeatureOnOffOptions.AutoXmlDocCommentGeneration.Name Or
[option].Name = FeatureOnOffOptions.AutomaticInsertionOfAbstractOrInterfaceMembers.Name
......@@ -106,6 +108,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
Return SettingStorageRoot + "EnableHighlightReferences"
Case FeatureOnOffOptions.KeywordHighlighting.Name
Return SettingStorageRoot + "EnableHighlightRelatedKeywords"
Case FeatureOnOffOptions.RenameTrackingPreview.Name
Return SettingStorageRoot + "RenameTrackingPreview"
Case FeatureOnOffOptions.EndConstruct.Name
Return SettingStorageRoot + "AutoEndInsert"
Case FeatureOnOffOptions.AutoXmlDocCommentGeneration.Name
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册