diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index c5d209fb1fda5..5bd1db04eb95e 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -6,16 +6,4 @@ FROM mcr.microsoft.com/vscode/devcontainers/dotnet:0-${VARIANT}
# Set up machine requirements to build the repo
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
- && apt-get -y install --no-install-recommends cmake llvm-9 clang-9 \
- build-essential python curl git lldb-6.0 liblldb-6.0-dev \
- libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev \
- libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja-build
-
-# Install V8 Engine
-SHELL ["/bin/bash", "-c"]
-
-RUN curl -sSL "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/linux/chromium-v8/v8-linux64-rel-8.5.183.zip" -o ./v8.zip \
- && unzip ./v8.zip -d /usr/local/v8 \
- && echo $'#!/usr/bin/env bash\n\
-"/usr/local/v8/d8" --snapshot_blob="/usr/local/v8/snapshot_blob.bin" "$@"\n' > /usr/local/bin/v8 \
- && chmod +x /usr/local/bin/v8
\ No newline at end of file
+ && apt-get -y install --no-install-recommends curl git
diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md
index c152a61951ad2..15ed9a97a5f4f 100644
--- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md
+++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md
@@ -98,3 +98,11 @@ https://github.com/dotnet/roslyn/issues/57750
public S() { Y = 0; } // ok
}
```
+
+7. Before Visual Studio 17.2, the C# compiler would accept incorrect default argument values involving a reference conversion of a string constant, and would emit `null` as the constant value instead of the default value specified in source. In Visual Studio 17.2, this becomes an error. See [roslyn#59806](https://github.com/dotnet/roslyn/pull/59806).
+
+ For instance, the following results in an error in 17.2:
+ ```csharp
+ void M(IEnumerable s = "hello")
+ ```
+
diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md
index 2abe570bdef9c..006716142562f 100644
--- a/docs/contributing/Compiler Test Plan.md
+++ b/docs/contributing/Compiler Test Plan.md
@@ -2,7 +2,8 @@ This document provides guidance for thinking about language interactions and tes
# General concerns:
- Completeness of the specification as a guide for testing (is the spec complete enough to suggest what the compiler should do in each scenario?)
-- Other external documentation
+- *Ping* for new breaking changes and general ping for partner teams (Bill, Kathleen, Mads, IDE, Razor)
+- Help review external documentation
- Backward and forward compatibility (interoperation with previous and future compilers, each in both directions)
- Error handling/recovery (missing libraries, including missing types in mscorlib; errors in parsing, ambiguous lookup, inaccessible lookup, wrong kind of thing found, instance vs static thing found, wrong type for the context, value vs variable)
- BCL (including mono) and other customer impact
diff --git a/eng/Versions.props b/eng/Versions.props
index 8b8b2d3a2ebf7..db28578cd2987 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,7 +8,7 @@
4
2
0
- 2
+ 3
$(MajorVersion).$(MinorVersion).$(PatchVersion)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornment.xaml.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornment.xaml.cs
new file mode 100644
index 0000000000000..9138e5550fa4a
--- /dev/null
+++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornment.xaml.cs
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.Editor.InlineRename.Adornment
+{
+ ///
+ /// Interaction logic for InlineRenameAdornment.xaml
+ ///
+ internal partial class InlineRenameAdornment : UserControl, IDisposable
+ {
+ private readonly InlineRenameAdornmentViewModel _viewModel;
+ private readonly ITextView _textView;
+
+ public InlineRenameAdornment(InlineRenameAdornmentViewModel viewModel, ITextView textView)
+ {
+ DataContext = _viewModel = viewModel;
+ _textView = textView;
+
+ _textView.LayoutChanged += TextView_LayoutChanged;
+ _textView.ViewportHeightChanged += TextView_ViewPortChanged;
+ _textView.ViewportWidthChanged += TextView_ViewPortChanged;
+ _textView.LostAggregateFocus += TextView_LostFocus;
+ _textView.Caret.PositionChanged += TextView_CursorChanged;
+
+ // On initialization focus the first tab target
+ Initialized += (s, e) => MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
+
+ InitializeComponent();
+ PositionAdornment();
+ }
+
+#pragma warning disable CA1822 // Mark members as static - used in xaml
+ public string RenameOverloads => EditorFeaturesResources.Include_overload_s;
+ public string SearchInComments => EditorFeaturesResources.Include_comments;
+ public string SearchInStrings => EditorFeaturesResources.Include_strings;
+ public string ApplyRename => EditorFeaturesResources.Apply1;
+ public string CancelRename => EditorFeaturesResources.Cancel;
+ public string PreviewChanges => EditorFeaturesResources.Preview_changes1;
+ public string SubmitText => EditorFeaturesWpfResources.Enter_to_rename_shift_enter_to_preview;
+#pragma warning restore CA1822 // Mark members as static
+
+ private void TextView_CursorChanged(object sender, CaretPositionChangedEventArgs e)
+ => _viewModel.Cancel();
+
+ private void TextView_LostFocus(object sender, EventArgs e)
+ => _viewModel.Cancel();
+
+ private void TextView_ViewPortChanged(object sender, EventArgs e)
+ => PositionAdornment();
+
+ private void TextView_LayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
+ => PositionAdornment();
+
+ private void PositionAdornment()
+ {
+ var top = _textView.Caret.Bottom + 5;
+ var left = _textView.Caret.Left - 5;
+
+ Canvas.SetTop(this, top);
+ Canvas.SetLeft(this, left);
+ }
+
+ public void Dispose()
+ {
+ _viewModel.Dispose();
+
+ _textView.LayoutChanged -= TextView_LayoutChanged;
+ _textView.ViewportHeightChanged -= TextView_ViewPortChanged;
+ _textView.ViewportWidthChanged -= TextView_ViewPortChanged;
+ _textView.LostAggregateFocus -= TextView_LostFocus;
+ _textView.Caret.PositionChanged -= TextView_CursorChanged;
+ }
+
+ private void Submit_Click(object sender, RoutedEventArgs e)
+ {
+ _viewModel.Submit();
+ }
+
+ private void Adornment_KeyDown(object sender, KeyEventArgs e)
+ {
+ switch (e.Key)
+ {
+ case Key.Enter:
+ e.Handled = true;
+ _viewModel.Submit();
+ break;
+
+ case Key.Escape:
+ e.Handled = true;
+ _viewModel.Cancel();
+ break;
+
+ case Key.Tab:
+ // We don't want tab to lose focus for the adornment, so manually
+ // loop focus back to the first item that is focusable.
+ FrameworkElement lastItem = _viewModel.IsExpanded
+ ? FileRenameCheckbox
+ : IdentifierTextBox;
+
+ if (lastItem.IsFocused)
+ {
+ e.Handled = true;
+ MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
+ }
+
+ break;
+ }
+ }
+
+ private void IdentifierTextBox_GotFocus(object sender, RoutedEventArgs e)
+ {
+ IdentifierTextBox.SelectAll();
+ }
+
+ private void Adornment_ConsumeMouseEvent(object sender, MouseButtonEventArgs e)
+ {
+ e.Handled = true;
+ }
+
+ private void Adornment_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
+ {
+ if (e.OldFocus == this)
+ {
+ return;
+ }
+
+ IdentifierTextBox.Focus();
+ e.Handled = true;
+ }
+
+ private void ToggleExpand(object sender, RoutedEventArgs e)
+ {
+ _viewModel.IsExpanded = !_viewModel.IsExpanded;
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornmentViewModel.cs b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornmentViewModel.cs
new file mode 100644
index 0000000000000..c9932ebf66ef6
--- /dev/null
+++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Adornment/InlineRenameAdornmentViewModel.cs
@@ -0,0 +1,269 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Windows.Interop;
+using Microsoft.CodeAnalysis.Editor.Implementation.InlineRename;
+using Microsoft.CodeAnalysis.InlineRename;
+using Microsoft.CodeAnalysis.Options;
+using Microsoft.CodeAnalysis.Rename;
+using Microsoft.VisualStudio.PlatformUI.OleComponentSupport;
+
+namespace Microsoft.CodeAnalysis.Editor.InlineRename.Adornment
+{
+ internal class InlineRenameAdornmentViewModel : INotifyPropertyChanged, IDisposable
+ {
+ private readonly InlineRenameSession _session;
+ private OleComponent? _oleComponent;
+ private bool _disposedValue;
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ public InlineRenameAdornmentViewModel(InlineRenameSession session)
+ {
+ _session = session;
+ _session.ReplacementTextChanged += OnReplacementTextChanged;
+
+ _previewChangesFlag = _session.PreviewChanges;
+ _renameFileFlag = _session.Options.RenameFile;
+ _renameInStringsFlag = _session.Options.RenameInStrings;
+ _renameInCommentsFlag = _session.Options.RenameInComments;
+ _renameOverloadsFlag = _session.Options.RenameOverloads;
+
+ RegisterOleComponent();
+ }
+
+ public string IdentifierText
+ {
+ get => _session.ReplacementText;
+ set
+ {
+ if (value != _session.ReplacementText)
+ {
+ _session.ApplyReplacementText(value, propagateEditImmediately: false);
+ NotifyPropertyChanged(nameof(IdentifierText));
+ }
+ }
+ }
+
+ public bool AllowFileRename => _session.FileRenameInfo == InlineRenameFileRenameInfo.Allowed;
+ public bool ShowFileRename => _session.FileRenameInfo != InlineRenameFileRenameInfo.NotAllowed;
+
+ public string FileRenameString => _session.FileRenameInfo switch
+ {
+ InlineRenameFileRenameInfo.TypeDoesNotMatchFileName => EditorFeaturesResources.Rename_file_name_doesnt_match,
+ InlineRenameFileRenameInfo.TypeWithMultipleLocations => EditorFeaturesResources.Rename_file_partial_type,
+ _ => EditorFeaturesResources.Rename_symbols_file
+ };
+
+ private bool _renameInCommentsFlag;
+ public bool RenameInCommentsFlag
+ {
+ get => _renameInCommentsFlag;
+ set
+ {
+ if (Set(ref _renameInCommentsFlag, value))
+ {
+ _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInComments), value);
+ _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInComments = value });
+ }
+ }
+ }
+
+ private bool _renameInStringsFlag;
+ public bool RenameInStringsFlag
+ {
+ get => _renameInStringsFlag;
+ set
+ {
+ if (Set(ref _renameInStringsFlag, value))
+ {
+ _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameInStrings), value);
+ _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameInStrings = value });
+ }
+ }
+ }
+
+ private bool _renameFileFlag;
+ public bool RenameFileFlag
+ {
+ get => _renameFileFlag;
+ set
+ {
+ if (Set(ref _renameFileFlag, value))
+ {
+ _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameFile), value);
+ _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameFile = value });
+ }
+ }
+ }
+
+ private bool _previewChangesFlag;
+ public bool PreviewChangesFlag
+ {
+ get => _previewChangesFlag;
+ set
+ {
+ if (Set(ref _previewChangesFlag, value))
+ {
+ _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.PreviewChanges), value);
+ _session.SetPreviewChanges(value);
+ }
+ }
+ }
+
+ private bool _renameOverloadsFlag;
+ public bool RenameOverloadsFlag
+ {
+ get => _renameOverloadsFlag;
+ set
+ {
+ if (Set(ref _renameOverloadsFlag, value))
+ {
+ _session.RenameService.GlobalOptions.SetGlobalOption(new OptionKey(InlineRenameSessionOptionsStorage.RenameOverloads), value);
+ _session.RefreshRenameSessionWithOptionsChanged(_session.Options with { RenameOverloads = value });
+ }
+ }
+ }
+
+ private bool _isCollapsed;
+ public bool IsCollapsed
+ {
+ get => _isCollapsed;
+ set
+ {
+ if (Set(ref _isCollapsed, value))
+ {
+ NotifyPropertyChanged(nameof(IsExpanded));
+ }
+ }
+ }
+
+ public bool IsExpanded
+ {
+ get => !IsCollapsed;
+ set => IsCollapsed = !value;
+ }
+
+ public bool IsRenameOverloadsEditable
+ => !_session.MustRenameOverloads;
+
+ public void Submit()
+ {
+ _session.Commit();
+ }
+
+ public void Cancel()
+ {
+ _session.Cancel();
+ }
+
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Shell routes commands based on focused tool window. Since we're outside of a tool window,
+ /// Editor can end up intercepting commands and TYPECHARs sent to us, even when we're focused,
+ /// so hook in and intercept each message for WPF.
+ ///
+ public void RegisterOleComponent()
+ {
+ Debug.Assert(_oleComponent is null);
+
+ _oleComponent = OleComponent.CreateHostedComponent("Microsoft CodeAnalysis Inline Rename");
+ _oleComponent.PreTranslateMessage += OnPreTranslateMessage;
+ _oleComponent.BeginTracking();
+ }
+
+ private void UnregisterOleComponent()
+ {
+ if (_oleComponent is not null)
+ {
+ _oleComponent.EndTracking();
+ _oleComponent.PreTranslateMessage -= OnPreTranslateMessage;
+ _oleComponent.Dispose();
+ _oleComponent = null;
+ }
+ }
+
+ private void OnPreTranslateMessage(object sender, PreTranslateMessageEventArgs e)
+ {
+ var msg = e.Message;
+ if (ComponentDispatcher.RaiseThreadMessage(ref msg) || IsSuppressedMessage(msg))
+ {
+ e.MessageConsumed = true;
+ }
+
+ // When the adornment is focused, we register an OleComponent to divert window messages
+ // away from the editor and back to WPF to enable proper handling of arrows, backspace,
+ // delete, etc. Unfortunately, anything not handled by WPF is then propagated back to the
+ // shell command system where it is handled by the open editor window.
+ // To avoid unhandled arrow commands from being handled by editor,
+ // we mark them as handled so long as the adornment is focused.
+ static bool IsSuppressedMessage(MSG msg)
+ => msg.message switch
+ {
+ 0x0100 or // WM_KEYDOWN
+ 0x0101 // WM_KEYUP
+ => msg.wParam.ToInt32() switch
+ {
+ >= 0x0025 and <= 0x0028 => true, // VK_LEFT, VK_UP, VK_RIGHT, and VK_DOWN
+
+ 0x0021 or // VK_PRIOR (Page Up)
+ 0x0022 or // VK_NEXT (Page Down)
+ 0x0023 or // VK_END
+ 0x0024 or // VK_HOME
+ 0x0D00 or // VK_RETURN
+ 0x0009 => true, // VK_TAB
+
+ _ => false
+ },
+
+ _ => false
+ };
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing)
+ {
+ _session.ReplacementTextChanged -= OnReplacementTextChanged;
+
+ UnregisterOleComponent();
+ }
+
+ _disposedValue = true;
+ }
+ }
+
+ private void OnReplacementTextChanged(object sender, EventArgs e)
+ {
+ NotifyPropertyChanged(nameof(IdentifierText));
+ }
+
+ private void NotifyPropertyChanged([CallerMemberName] string? name = null)
+ => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
+
+ private bool Set(ref T field, T newValue, [CallerMemberName] string? name = null)
+ {
+ if (EqualityComparer.Default.Equals(field, newValue))
+ {
+ return false;
+ }
+
+ field = newValue;
+ NotifyPropertyChanged(name);
+ return true;
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/Dashboard.xaml b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/Dashboard.xaml
similarity index 96%
rename from src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/Dashboard.xaml
rename to src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/Dashboard.xaml
index 18c0b5beaba69..f0a17489c9676 100644
--- a/src/EditorFeatures/Core.Wpf/InlineRename/Dashboard/Dashboard.xaml
+++ b/src/EditorFeatures/Core.Wpf/InlineRename/UI/Dashboard/Dashboard.xaml
@@ -24,15 +24,15 @@
-
+
-
+