diff --git a/Roslyn.sln b/Roslyn.sln
index 7a24e77b16147..924423c8aba59 100644
--- a/Roslyn.sln
+++ b/Roslyn.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeAnalysisTest", "src\Compilers\Core\CodeAnalysisTest\CodeAnalysisTest.csproj", "{A4C99B85-765C-4C65-9C2A-BB609AAB09E6}"
EndProject
@@ -363,6 +363,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerformanceTesting", "src\T
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Roslyn", "src\Deployment\Roslyn.csproj", "{600AF682-E097-407B-AD85-EE3CED37E680}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EditorFeatures.Next", "src\EditorFeatures\Next\EditorFeatures.Next.csproj", "{366BBCDC-B05F-4677-9B5B-78BA816A1484}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioSetup.Next", "src\VisualStudio\Setup.Next\VisualStudioSetup.Next.csproj", "{143FE684-6E1C-41DF-9C60-84C7772DC49C}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Test\Utilities\Shared\TestUtilities.projitems*{76c6f005-c89d-4348-bb4a-391898dbeb52}*SharedItemsImports = 4
@@ -395,8 +399,8 @@ Global
src\ExpressionEvaluator\CSharp\Source\ResultProvider\CSharpResultProvider.projitems*{bf9dac1e-3a5e-4dc3-bb44-9a64e0d4e9d3}*SharedItemsImports = 4
src\Compilers\Core\SharedCollections\SharedCollections.projitems*{afde6bea-5038-4a4a-a88e-dbd2e4088eed}*SharedItemsImports = 4
src\ExpressionEvaluator\Core\Source\ResultProvider\ResultProvider.projitems*{fa0e905d-ec46-466d-b7b2-3b5557f9428c}*SharedItemsImports = 4
- src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
src\Compilers\Core\SharedCollections\SharedCollections.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
+ src\Compilers\Core\AnalyzerDriver\AnalyzerDriver.projitems*{1ee8cad3-55f9-4d91-96b2-084641da9a6c}*SharedItemsImports = 4
src\Compilers\Core\MSBuildTask\Shared\MSBuildTask.Shared.projitems*{7ad4fe65-9a30-41a6-8004-aa8f89bcb7f3}*SharedItemsImports = 4
src\Compilers\Core\CommandLine\CommandLine.projitems*{7ad4fe65-9a30-41a6-8004-aa8f89bcb7f3}*SharedItemsImports = 4
src\Compilers\CSharp\CSharpAnalyzerDriver\CSharpAnalyzerDriver.projitems*{3973b09a-4fbf-44a5-8359-3d22ceb71f71}*SharedItemsImports = 4
@@ -3130,6 +3134,46 @@ Global
{600AF682-E097-407B-AD85-EE3CED37E680}.Release|x64.Build.0 = Release|Any CPU
{600AF682-E097-407B-AD85-EE3CED37E680}.Release|x86.ActiveCfg = Release|Any CPU
{600AF682-E097-407B-AD85-EE3CED37E680}.Release|x86.Build.0 = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|ARM.Build.0 = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|x64.Build.0 = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Debug|x86.Build.0 = Debug|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|Any CPU.Build.0 = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|ARM.ActiveCfg = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|ARM.Build.0 = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|x64.ActiveCfg = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|x64.Build.0 = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|x86.ActiveCfg = Release|Any CPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}.Release|x86.Build.0 = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|ARM.Build.0 = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|x64.Build.0 = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Debug|x86.Build.0 = Debug|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|ARM.ActiveCfg = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|ARM.Build.0 = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|x64.ActiveCfg = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|x64.Build.0 = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|x86.ActiveCfg = Release|Any CPU
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3296,5 +3340,7 @@ Global
{A32EAB7F-691C-4D00-98C4-F50C37BB4754} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{A57DDFE5-AB0E-4371-98E5-11B9218DF11C} = {C2D1346B-9665-4150-B644-075CF1636BAA}
{DA0D2A70-A2F9-4654-A99A-3227EDF54FF1} = {CAD2965A-19AB-489F-BE2E-7649957F914A}
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484} = {EE97CB90-33BB-4F3A-9B3D-69375DEC6AC6}
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C} = {8DBA5174-B0AA-4561-82B1-A46607697753}
EndGlobalSection
EndGlobal
diff --git a/build/Targets/VSL.Imports.targets b/build/Targets/VSL.Imports.targets
index 5d1f95b1e087d..cb4ee932e0930 100644
--- a/build/Targets/VSL.Imports.targets
+++ b/build/Targets/VSL.Imports.targets
@@ -82,6 +82,38 @@
+
+
+
+ $(VisualStudioReferenceAssemblyVersion)
+
+
+ $(VisualStudioReferenceAssemblyVersion)
+
+
+ $(VisualStudioReferenceAssemblyVersion)
+
+
+
+ true
+ true
+
+
+
+
+
+
+ true
+
+
+
@@ -94,7 +126,7 @@
-
+
@@ -112,13 +144,13 @@
-
+
-
+
diff --git a/src/Compilers/Core/MSBuildTaskTests/IntegrationTests.cs b/src/Compilers/Core/MSBuildTaskTests/IntegrationTests.cs
index 2e275d810df80..f2d3d02a1a5e8 100644
--- a/src/Compilers/Core/MSBuildTaskTests/IntegrationTests.cs
+++ b/src/Compilers/Core/MSBuildTaskTests/IntegrationTests.cs
@@ -25,18 +25,8 @@ public class IntegrationTests : TestBase
static IntegrationTests()
{
- using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0", writable: false))
- {
- if (key != null)
- {
- var toolsPath = key.GetValue("MSBuildToolsPath");
- if (toolsPath != null)
- {
- s_msbuildDirectory = toolsPath.ToString();
- s_msbuildExecutable = Path.Combine(s_msbuildDirectory, "MSBuild.exe");
- }
- }
- }
+ s_msbuildDirectory = TestHelpers.GetMSBuildDirectory();
+ s_msbuildExecutable = Path.Combine(s_msbuildDirectory, "MSBuild.exe");
}
private readonly TempDirectory _tempDirectory;
diff --git a/src/Compilers/Core/MSBuildTaskTests/MSBuildTaskTests.csproj b/src/Compilers/Core/MSBuildTaskTests/MSBuildTaskTests.csproj
index 6a42a77fbfe82..dab9e06ca6d92 100644
--- a/src/Compilers/Core/MSBuildTaskTests/MSBuildTaskTests.csproj
+++ b/src/Compilers/Core/MSBuildTaskTests/MSBuildTaskTests.csproj
@@ -1,6 +1,6 @@
-
+
@@ -16,6 +16,7 @@
..\..\..\..\
true
v4.6
+
diff --git a/src/Compilers/Core/Portable/Collections/OrderPreservingMultiDictionary.cs b/src/Compilers/Core/Portable/Collections/OrderPreservingMultiDictionary.cs
index a7f32443622e9..40c444b592a8f 100644
--- a/src/Compilers/Core/Portable/Collections/OrderPreservingMultiDictionary.cs
+++ b/src/Compilers/Core/Portable/Collections/OrderPreservingMultiDictionary.cs
@@ -1,5 +1,7 @@
// 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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -8,14 +10,14 @@
namespace Microsoft.CodeAnalysis.Collections
{
///
- /// A MultiDictionary that allows only adding, and
- /// preserves the order of values added to the dictionary.
- /// Thread-safe for reading, but not for adding.
+ /// A MultiDictionary that allows only adding, and preserves the order of values added to the
+ /// dictionary. Thread-safe for reading, but not for adding.
///
///
/// Always uses the default comparer.
///
- internal sealed class OrderPreservingMultiDictionary
+ internal sealed class OrderPreservingMultiDictionary :
+ IEnumerable.ValueSet>>
{
#region Pooling
@@ -30,6 +32,12 @@ public void Free()
{
if (_dictionary != null)
{
+ // Allow our ValueSets to return their underlying ArrayBuilders to the pool.
+ foreach (var kvp in _dictionary)
+ {
+ kvp.Value.Free();
+ }
+
_dictionary.Free();
_dictionary = null;
}
@@ -57,159 +65,231 @@ public void Free()
#endregion Pooling
+ // An empty dictionary we keep around to simplify certain operations (like "Keys")
+ // when we don't have an underlying dictionary of our own.
+ private static readonly Dictionary s_emptyDictionary = new Dictionary();
+
+ // The underlying dictionary we store our data in. null if we are empty.
+ private PooledDictionary _dictionary;
+
public OrderPreservingMultiDictionary()
{
}
- // store either a single V or an ArrayBuilder
- ///
- /// Each value is either a single V or an .
- /// Null when the dictionary is empty.
- /// Don't access the field directly.
- ///
- private PooledDictionary _dictionary;
-
private void EnsureDictionary()
{
- _dictionary = _dictionary ?? PooledDictionary.GetInstance();
+ _dictionary = _dictionary ?? PooledDictionary.GetInstance();
}
- public bool IsEmpty
- {
- get { return _dictionary == null; }
- }
+ public bool IsEmpty => _dictionary == null;
///
/// Add a value to the dictionary.
///
public void Add(K k, V v)
{
- object item;
- if (!this.IsEmpty && _dictionary.TryGetValue(k, out item))
+ ValueSet valueSet;
+ if (!this.IsEmpty && _dictionary.TryGetValue(k, out valueSet))
{
- var arrayBuilder = item as ArrayBuilder;
- if (arrayBuilder == null)
- {
- // Promote from singleton V to ArrayBuilder.
- Debug.Assert(item is V, "Item must be either a V or an ArrayBuilder");
- arrayBuilder = new ArrayBuilder(2);
- arrayBuilder.Add((V)item);
- arrayBuilder.Add(v);
- _dictionary[k] = arrayBuilder;
- }
- else
- {
- arrayBuilder.Add(v);
- }
+ Debug.Assert(valueSet.Count >= 1);
+ // Have to re-store the ValueSet in case we upgraded the existing ValueSet from
+ // holding a single item to holding multiple items.
+ _dictionary[k] = valueSet.WithAddedItem(v);
}
else
{
this.EnsureDictionary();
- _dictionary[k] = v;
+ _dictionary[k] = new ValueSet(v);
}
}
- ///
- /// Add multiple values to the dictionary.
- ///
- public void AddRange(K k, ImmutableArray values)
+ public Dictionary.Enumerator GetEnumerator()
{
- if (values.IsEmpty)
- return;
-
- object item;
- ArrayBuilder arrayBuilder;
+ return IsEmpty ? s_emptyDictionary.GetEnumerator() : _dictionary.GetEnumerator();
+ }
- if (!this.IsEmpty && _dictionary.TryGetValue(k, out item))
- {
- arrayBuilder = item as ArrayBuilder;
- if (arrayBuilder == null)
- {
- // Promote from singleton V to ArrayBuilder.
- Debug.Assert(item is V, "Item must be either a V or an ArrayBuilder");
- arrayBuilder = new ArrayBuilder(1 + values.Length);
- arrayBuilder.Add((V)item);
- arrayBuilder.AddRange(values);
- _dictionary[k] = arrayBuilder;
- }
- else
- {
- arrayBuilder.AddRange(values);
- }
- }
- else
- {
- this.EnsureDictionary();
+ IEnumerator> IEnumerable>.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
- if (values.Length == 1)
- {
- _dictionary[k] = values[0];
- }
- else
- {
- arrayBuilder = new ArrayBuilder(values.Length);
- arrayBuilder.AddRange(values);
- _dictionary[k] = arrayBuilder;
- }
- }
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
}
///
- /// Get the number of values associated with a key.
+ /// Get all values associated with K, in the order they were added.
+ /// Returns empty read-only array if no values were present.
///
- public int GetCountForKey(K k)
+ public ImmutableArray this[K k]
{
- object item;
- if (!this.IsEmpty && _dictionary.TryGetValue(k, out item))
+ get
{
- return (item as ArrayBuilder)?.Count ?? 1;
- }
+ ValueSet valueSet;
+ if (!this.IsEmpty && _dictionary.TryGetValue(k, out valueSet))
+ {
+ Debug.Assert(valueSet.Count >= 1);
+ return valueSet.Items;
+ }
- return 0;
+ return ImmutableArray.Empty;
+ }
}
///
- /// Returns true if one or more items with given key have been added.
+ /// Get a collection of all the keys.
///
- public bool ContainsKey(K k)
+ public Dictionary.KeyCollection Keys
{
- return !this.IsEmpty && _dictionary.ContainsKey(k);
+ get { return this.IsEmpty ? s_emptyDictionary.Keys : _dictionary.Keys; }
}
- ///
- /// Get all values associated with K, in the order they were added.
- /// Returns empty read-only array if no values were present.
- ///
- public ImmutableArray this[K k]
+ public struct ValueSet : IEnumerable
{
- get
+ ///
+ /// Each value is either a single V or an .
+ /// Never null.
+ ///
+ private readonly object _value;
+
+ internal ValueSet(V value)
{
- object item;
- if (!this.IsEmpty && _dictionary.TryGetValue(k, out item))
+ _value = value;
+ }
+
+ internal ValueSet(ArrayBuilder values)
+ {
+ _value = values;
+ }
+
+ internal void Free()
+ {
+ var arrayBuilder = _value as ArrayBuilder;
+ arrayBuilder?.Free();
+ }
+
+ internal V this[int index]
+ {
+ get
{
- var arrayBuilder = item as ArrayBuilder;
+ Debug.Assert(this.Count >= 1);
+
+ var arrayBuilder = _value as ArrayBuilder;
+ if (arrayBuilder == null)
+ {
+ if (index == 0)
+ {
+ return (V)_value;
+ }
+ else
+ {
+ throw new IndexOutOfRangeException();
+ }
+ }
+ else
+ {
+ return arrayBuilder[index];
+ }
+ }
+ }
+
+ internal ImmutableArray Items
+ {
+ get
+ {
+ Debug.Assert(this.Count >= 1);
+
+ var arrayBuilder = _value as ArrayBuilder;
if (arrayBuilder == null)
{
// promote singleton to set
- Debug.Assert(item is V, "Item must be either a V or an ArrayBuilder");
- return ImmutableArray.Create((V)item);
+ Debug.Assert(_value is V, "Item must be a a V");
+ return ImmutableArray.Create((V)_value);
}
else
{
return arrayBuilder.ToImmutable();
}
}
+ }
- return ImmutableArray.Empty;
+ internal int Count => (_value as ArrayBuilder)?.Count ?? 1;
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
}
- }
- ///
- /// Get a collection of all the keys.
- ///
- public ICollection Keys
- {
- get { return this.IsEmpty ? SpecializedCollections.EmptyCollection() : _dictionary.Keys; }
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public Enumerator GetEnumerator()
+ {
+ return new Enumerator(this);
+ }
+
+ internal ValueSet WithAddedItem(V item)
+ {
+ Debug.Assert(this.Count >= 1);
+
+ var arrayBuilder = _value as ArrayBuilder;
+ if (arrayBuilder == null)
+ {
+ // Promote from singleton V to ArrayBuilder.
+ Debug.Assert(_value is V, "_value must be a V");
+
+ // By default we allocate array builders with a size of two. That's to store
+ // the single item already in _value, and to store the item we're adding.
+ // In general, we presume that the amount of values per key will be low, so this
+ // means we have very little overhead when there are multiple keys per value.
+ arrayBuilder = ArrayBuilder.GetInstance(capacity: 2);
+ arrayBuilder.Add((V)_value);
+ arrayBuilder.Add(item);
+ }
+ else
+ {
+ arrayBuilder.Add(item);
+ }
+
+ return new ValueSet(arrayBuilder);
+ }
+
+ public struct Enumerator : IEnumerator
+ {
+ private readonly ValueSet _valueSet;
+ private readonly int _count;
+ private int _index;
+
+ public Enumerator(ValueSet valueSet)
+ {
+ _valueSet = valueSet;
+ _count = _valueSet.Count;
+ Debug.Assert(_count >= 1);
+ _index = -1;
+ }
+
+ public V Current => _valueSet[_index];
+
+ object IEnumerator.Current => Current;
+
+ public bool MoveNext()
+ {
+ _index++;
+ return _index < _count;
+ }
+
+ public void Reset()
+ {
+ _index = -1;
+ }
+
+ public void Dispose()
+ {
+ }
+ }
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Compilers/Core/Portable/Compilation/IExpression.cs b/src/Compilers/Core/Portable/Compilation/IExpression.cs
index 98eb2db52eb24..4cf6988a2218f 100644
--- a/src/Compilers/Core/Portable/Compilation/IExpression.cs
+++ b/src/Compilers/Core/Portable/Compilation/IExpression.cs
@@ -4,6 +4,10 @@
namespace Microsoft.CodeAnalysis.Semantics
{
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IHasArgumentsExpression : IOperation
{
///
@@ -23,6 +27,10 @@ public interface IHasArgumentsExpression : IOperation
///
/// Represents a C# or VB method invocation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IInvocationExpression : IHasArgumentsExpression
{
///
@@ -48,6 +56,10 @@ public interface IInvocationExpression : IHasArgumentsExpression
///
/// Represents an argument in a method invocation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IArgument : IOperation
{
///
@@ -100,6 +112,10 @@ public enum ArgumentKind
///
/// Represents a reference to an array element.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IArrayElementReferenceExpression : IOperation
{
///
@@ -115,6 +131,10 @@ public interface IArrayElementReferenceExpression : IOperation
///
/// Represents a reference through a pointer.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IPointerIndirectionReferenceExpression : IOperation
{
///
@@ -126,6 +146,10 @@ public interface IPointerIndirectionReferenceExpression : IOperation
///
/// Represents a reference to a declared local variable.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILocalReferenceExpression : IOperation
{
///
@@ -137,6 +161,10 @@ public interface ILocalReferenceExpression : IOperation
///
/// Represents a reference to a parameter.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IParameterReferenceExpression : IOperation
{
///
@@ -148,6 +176,10 @@ public interface IParameterReferenceExpression : IOperation
///
/// Represents a reference to a local variable synthesized by language analysis.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISyntheticLocalReferenceExpression : IOperation
{
///
@@ -180,6 +212,10 @@ public enum SyntheticLocalKind
///
/// Represents a C# this or base expression, or a VB Me, MyClass, or MyBase expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IInstanceReferenceExpression : IOperation
{
///
@@ -201,10 +237,14 @@ public enum InstanceReferenceKind
/// Indicates an explicit MyClass expression.
ThisClass = 0x4
}
-
+
///
/// Represents a reference to a member of a class, struct, or interface.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IMemberReferenceExpression : IOperation
{
///
@@ -213,14 +253,18 @@ public interface IMemberReferenceExpression : IOperation
IOperation Instance { get; }
///
- /// Referenced member.
- ///
+ /// Referenced member.
+ ///
ISymbol Member { get; }
}
///
/// Represents a reference to a field.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IFieldReferenceExpression : IMemberReferenceExpression
{
///
@@ -232,6 +276,10 @@ public interface IFieldReferenceExpression : IMemberReferenceExpression
///
/// Represents a reference to a method other than as the target of an invocation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IMethodBindingExpression : IMemberReferenceExpression
{
///
@@ -248,6 +296,10 @@ public interface IMethodBindingExpression : IMemberReferenceExpression
///
/// Represents a reference to a property.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IPropertyReferenceExpression : IMemberReferenceExpression
{
///
@@ -259,6 +311,10 @@ public interface IPropertyReferenceExpression : IMemberReferenceExpression
///
/// Represents a reference to an indexed property.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IIndexedPropertyReferenceExpression : IPropertyReferenceExpression, IHasArgumentsExpression
{
}
@@ -266,6 +322,10 @@ public interface IIndexedPropertyReferenceExpression : IPropertyReferenceExpress
///
/// Represents a reference to an event.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IEventReferenceExpression : IMemberReferenceExpression
{
///
@@ -277,6 +337,10 @@ public interface IEventReferenceExpression : IMemberReferenceExpression
///
/// Represents a binding of an event.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IEventAssignmentExpression : IOperation
{
///
@@ -303,6 +367,10 @@ public interface IEventAssignmentExpression : IOperation
///
/// Represents an expression that includes a ? or ?. conditional access instance expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IConditionalAccessExpression : IOperation
{
///
@@ -318,6 +386,10 @@ public interface IConditionalAccessExpression : IOperation
///
/// Represents the value of a conditionally-accessed expression within an expression containing a conditional access.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IConditionalAccessInstanceExpression : IOperation
{
}
@@ -326,6 +398,10 @@ public interface IConditionalAccessInstanceExpression : IOperation
/// Represents a general placeholder when no more specific kind of placeholder is available.
/// A placeholder is an expression whose meaning is inferred from context.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IPlaceholderExpression : IOperation
{
}
@@ -333,6 +409,10 @@ public interface IPlaceholderExpression : IOperation
///
/// Represents a unary, binary, relational, or conversion operation that can use an operator method.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IHasOperatorMethodExpression : IOperation
{
///
@@ -348,6 +428,10 @@ public interface IHasOperatorMethodExpression : IOperation
///
/// Represents an operation with one operand.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IUnaryOperatorExpression : IHasOperatorMethodExpression
{
///
@@ -473,10 +557,13 @@ public enum UnaryOperationKind
Invalid = UnaryOperandKind.Invalid | SimpleUnaryOperationKind.Invalid
}
-
///
/// Represents an operation with two operands that produces a result with the same type as at least one of the operands.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IBinaryOperatorExpression : IHasOperatorMethodExpression
{
///
@@ -831,6 +918,10 @@ public static BinaryOperandsKind GetBinaryOperandsKind(BinaryOperationKind kind)
///
/// Represents a conversion operation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IConversionExpression : IHasOperatorMethodExpression
{
///
@@ -882,6 +973,10 @@ public enum ConversionKind
///
/// Represents a C# ?: or VB If expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IConditionalChoiceExpression : IOperation
{
///
@@ -901,6 +996,10 @@ public interface IConditionalChoiceExpression : IOperation
///
/// Represents a null-coalescing expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface INullCoalescingExpression : IOperation
{
///
@@ -916,6 +1015,10 @@ public interface INullCoalescingExpression : IOperation
///
/// Represents an expression that tests if a value is of a specific type.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IIsTypeExpression : IOperation
{
///
@@ -931,6 +1034,10 @@ public interface IIsTypeExpression : IOperation
///
/// Represents an expression operating on a type.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ITypeOperationExpression : IOperation
{
///
@@ -942,6 +1049,10 @@ public interface ITypeOperationExpression : IOperation
///
/// Represents a SizeOf expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISizeOfExpression : ITypeOperationExpression
{
}
@@ -949,6 +1060,10 @@ public interface ISizeOfExpression : ITypeOperationExpression
///
/// Represents a TypeOf expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ITypeOfExpression : ITypeOperationExpression
{
}
@@ -956,6 +1071,10 @@ public interface ITypeOfExpression : ITypeOperationExpression
///
/// Represents a lambda expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILambdaExpression : IOperation
{
///
@@ -971,6 +1090,10 @@ public interface ILambdaExpression : IOperation
///
/// Represents a textual literal numeric, string, etc. expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILiteralExpression : IOperation
{
///
@@ -982,6 +1105,10 @@ public interface ILiteralExpression : IOperation
///
/// Represents an await expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IAwaitExpression : IOperation
{
///
@@ -993,6 +1120,10 @@ public interface IAwaitExpression : IOperation
///
/// Represents an expression that creates a pointer value by taking the address of a reference.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IAddressOfExpression : IOperation
{
///
@@ -1004,6 +1135,10 @@ public interface IAddressOfExpression : IOperation
///
/// Represents a new/New expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IObjectCreationExpression : IHasArgumentsExpression
{
///
@@ -1019,6 +1154,10 @@ public interface IObjectCreationExpression : IHasArgumentsExpression
///
/// Represents an initializer for a field, property, or parameter.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISymbolInitializer : IOperation
{
IOperation Value { get; }
@@ -1027,6 +1166,10 @@ public interface ISymbolInitializer : IOperation
///
/// Represents an initialization of a field.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IFieldInitializer : ISymbolInitializer
{
///
@@ -1038,6 +1181,10 @@ public interface IFieldInitializer : ISymbolInitializer
///
/// Represents an initialization of a property.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IPropertyInitializer : ISymbolInitializer
{
///
@@ -1049,6 +1196,10 @@ public interface IPropertyInitializer : ISymbolInitializer
///
/// Represents an initialization of a parameter at the point of declaration.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IParameterInitializer : ISymbolInitializer
{
///
@@ -1060,6 +1211,10 @@ public interface IParameterInitializer : ISymbolInitializer
///
/// Represents the creation of an array instance.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IArrayCreationExpression : IOperation
{
///
@@ -1079,6 +1234,10 @@ public interface IArrayCreationExpression : IOperation
///
/// Represents the initialization of an array instance.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IArrayInitializer : IOperation
{
///
@@ -1090,6 +1249,10 @@ public interface IArrayInitializer : IOperation
///
/// Represents an assignment expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IAssignmentExpression : IOperation
{
///
@@ -1105,6 +1268,10 @@ public interface IAssignmentExpression : IOperation
///
/// Represents an assignment expression that includes a binary operation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ICompoundAssignmentExpression : IAssignmentExpression, IHasOperatorMethodExpression
{
///
@@ -1116,6 +1283,10 @@ public interface ICompoundAssignmentExpression : IAssignmentExpression, IHasOper
///
/// Represents an increment expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IIncrementExpression : ICompoundAssignmentExpression
{
///
@@ -1127,6 +1298,10 @@ public interface IIncrementExpression : ICompoundAssignmentExpression
///
/// Represents a parenthesized expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IParenthesizedExpression : IOperation
{
///
@@ -1138,6 +1313,10 @@ public interface IParenthesizedExpression : IOperation
///
/// Represents a late-bound reference to a member of a class or struct.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILateBoundMemberReferenceExpression : IOperation
{
///
@@ -1153,22 +1332,42 @@ public interface ILateBoundMemberReferenceExpression : IOperation
///
/// Represents an argument value that has been omitted in an invocation.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IOmittedArgumentExpression : IOperation
{
}
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IUnboundLambdaExpression : IOperation
{
}
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IDefaultValueExpression : IOperation
{
}
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ITypeParameterObjectCreationExpression : IOperation
{
}
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IInvalidExpression : IOperation
{
}
diff --git a/src/Compilers/Core/Portable/Compilation/IOperation.cs b/src/Compilers/Core/Portable/Compilation/IOperation.cs
index 805f9e6911d04..d6ad22ab65ef9 100644
--- a/src/Compilers/Core/Portable/Compilation/IOperation.cs
+++ b/src/Compilers/Core/Portable/Compilation/IOperation.cs
@@ -1,5 +1,6 @@
// 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.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Semantics;
namespace Microsoft.CodeAnalysis
@@ -7,6 +8,11 @@ namespace Microsoft.CodeAnalysis
///
/// Root type for representing the abstract semantics of C# and VB statements and expressions.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
+ [InternalImplementationOnly]
public interface IOperation
{
///
diff --git a/src/Compilers/Core/Portable/Compilation/IStatement.cs b/src/Compilers/Core/Portable/Compilation/IStatement.cs
index 22f72ccbc8518..41a2ce90e7326 100644
--- a/src/Compilers/Core/Portable/Compilation/IStatement.cs
+++ b/src/Compilers/Core/Portable/Compilation/IStatement.cs
@@ -7,6 +7,10 @@ namespace Microsoft.CodeAnalysis.Semantics
///
/// Represents a block scope.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IBlockStatement : IOperation
{
///
@@ -22,6 +26,10 @@ public interface IBlockStatement : IOperation
///
/// Represents a local variable declaration statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IVariableDeclarationStatement : IOperation
{
///
@@ -33,6 +41,10 @@ public interface IVariableDeclarationStatement : IOperation
///
/// Represents a local variable declaration.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IVariableDeclaration : IOperation
{
///
@@ -48,6 +60,10 @@ public interface IVariableDeclaration : IOperation
///
/// Represents a C# switch or VB Select Case statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISwitchStatement : IOperation
{
///
@@ -63,6 +79,10 @@ public interface ISwitchStatement : IOperation
///
/// Represents a C# case or VB Case statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISwitchCase : IOperation
{
///
@@ -78,6 +98,10 @@ public interface ISwitchCase : IOperation
///
/// Represents a clause of a C# case or a VB Case.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ICaseClause : IOperation
{
///
@@ -114,6 +138,10 @@ public enum CaseKind
///
/// Represents case x in C# or Case x in VB.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ISingleValueCaseClause : ICaseClause
{
///
@@ -129,6 +157,10 @@ public interface ISingleValueCaseClause : ICaseClause
///
/// Represents Case Is op x in VB.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IRelationalCaseClause : ICaseClause
{
///
@@ -136,7 +168,7 @@ public interface IRelationalCaseClause : ICaseClause
///
IOperation Value { get; }
///
- /// Relational operator used to compare the switch value with the case value.
+ /// Relational operator used to compare the switch value with the case value.
///
BinaryOperationKind Relation { get; }
}
@@ -144,6 +176,10 @@ public interface IRelationalCaseClause : ICaseClause
///
/// Represents Case x To y in VB.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IRangeCaseClause : ICaseClause
{
///
@@ -159,6 +195,10 @@ public interface IRangeCaseClause : ICaseClause
///
/// Represents an if statement in C# or an If statement in VB.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IIfStatement : IOperation
{
///
@@ -178,6 +218,10 @@ public interface IIfStatement : IOperation
///
/// Represents a C# while, for, foreach, or do statement, or a VB While, For, For Each, or Do statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILoopStatement : IOperation
{
///
@@ -214,6 +258,10 @@ public enum LoopKind
///
/// Represents a C# while, for, or do statement, or a VB While, For, or Do statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IForWhileUntilLoopStatement : ILoopStatement
{
///
@@ -225,6 +273,10 @@ public interface IForWhileUntilLoopStatement : ILoopStatement
///
/// Represents a C# while or do statement, or a VB While or Do statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IWhileUntilLoopStatement : IForWhileUntilLoopStatement
{
///
@@ -240,6 +292,10 @@ public interface IWhileUntilLoopStatement : IForWhileUntilLoopStatement
///
/// Represents a C# for statement or a VB For statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IForLoopStatement : IForWhileUntilLoopStatement
{
///
@@ -259,6 +315,10 @@ public interface IForLoopStatement : IForWhileUntilLoopStatement
///
/// Represents a C# foreach statement or a VB For Each staement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IForEachLoopStatement : ILoopStatement
{
///
@@ -274,6 +334,10 @@ public interface IForEachLoopStatement : ILoopStatement
///
/// Represents a C# or VB label statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILabelStatement : IOperation
{
///
@@ -289,6 +353,10 @@ public interface ILabelStatement : IOperation
///
/// Represents a C# goto, break, or continue statement, or a VB GoTo, Exit ***, or Continue *** statement
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IBranchStatement : IOperation
{
///
@@ -312,6 +380,10 @@ public enum BranchKind
///
/// Represents a C# throw or a VB Throw statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IThrowStatement : IOperation
{
///
@@ -323,6 +395,10 @@ public interface IThrowStatement : IOperation
///
/// Represents a C# return or a VB Return statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IReturnStatement : IOperation
{
///
@@ -334,6 +410,10 @@ public interface IReturnStatement : IOperation
///
/// Represents a C# lock or a VB SyncLock statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ILockStatement : IOperation
{
///
@@ -349,6 +429,10 @@ public interface ILockStatement : IOperation
///
/// Represents a C# try or a VB Try statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ITryStatement : IOperation
{
///
@@ -368,6 +452,10 @@ public interface ITryStatement : IOperation
///
/// Represents a C# catch or VB Catch clause.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface ICatchClause : IOperation
{
///
@@ -391,6 +479,10 @@ public interface ICatchClause : IOperation
///
/// Represents a C# using or VB Using statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IUsingStatement : IOperation
{
///
@@ -408,10 +500,14 @@ public interface IUsingStatement : IOperation
///
IOperation Value { get; }
}
-
+
///
/// Represents a C# fixed staement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IFixedStatement : IOperation
{
///
@@ -427,6 +523,10 @@ public interface IFixedStatement : IOperation
///
/// Represents a C# or VB statement that consists solely of an expression.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IExpressionStatement : IOperation
{
///
@@ -438,6 +538,10 @@ public interface IExpressionStatement : IOperation
///
/// Represents a VB With statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IWithStatement : IOperation
{
///
@@ -453,6 +557,10 @@ public interface IWithStatement : IOperation
///
/// Reprsents an empty statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IEmptyStatement : IOperation
{
}
@@ -460,6 +568,10 @@ public interface IEmptyStatement : IOperation
///
/// Represents a VB Stop statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IStopStatement : IOperation
{
}
@@ -467,6 +579,10 @@ public interface IStopStatement : IOperation
///
/// Represents a VB End statemnt.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IEndStatement : IOperation
{
}
@@ -474,6 +590,10 @@ public interface IEndStatement : IOperation
///
/// Represents a syntactically or semantically invalid C# or VB statement.
///
+ ///
+ /// This interface is reserved for implementation by its associated APIs. We reserve the right to
+ /// change it in the future.
+ ///
public interface IInvalidStatement : IOperation
{
}
diff --git a/src/Compilers/Core/Portable/Symbols/ISourceAssemblySymbol.cs b/src/Compilers/Core/Portable/Symbols/ISourceAssemblySymbol.cs
index 6245d1c136fed..d7b2bd79bf137 100644
--- a/src/Compilers/Core/Portable/Symbols/ISourceAssemblySymbol.cs
+++ b/src/Compilers/Core/Portable/Symbols/ISourceAssemblySymbol.cs
@@ -16,7 +16,6 @@ namespace Microsoft.CodeAnalysis
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
///
- [InternalImplementationOnly]
public interface ISourceAssemblySymbol : IAssemblySymbol
{
Compilation Compilation { get; }
diff --git a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs
index 8d63a6627b244..d1c64da2f2b72 100644
--- a/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs
+++ b/src/Compilers/Server/VBCSCompilerTests/CompilerServerTests.cs
@@ -51,7 +51,7 @@ static CompilerServerUnitTests()
// VBCSCompiler is used as a DLL in these tests, need to hook the resolve to the installed location.
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
- basePath = GetMSBuildDirectory();
+ basePath = TestHelpers.GetMSBuildDirectory();
if (basePath == null)
{
return;
@@ -74,23 +74,6 @@ private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs e)
return null;
}
- private static string GetMSBuildDirectory()
- {
- using (var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0", false))
- {
- if (key != null)
- {
- var toolsPath = key.GetValue("MSBuildToolsPath");
- if (toolsPath != null)
- {
- return toolsPath.ToString();
- }
- }
- }
-
- return null;
- }
-
private static readonly KeyValuePair[] s_helloWorldSrcCs =
{
new KeyValuePair("hello.cs",
diff --git a/src/Dependencies/VisualStudio/project.json b/src/Dependencies/VisualStudio/project.json
index efefe50e36041..b2d2398bde01f 100644
--- a/src/Dependencies/VisualStudio/project.json
+++ b/src/Dependencies/VisualStudio/project.json
@@ -2,15 +2,15 @@
"supports": { },
"dependencies": {
"Microsoft.VisualStudio.Designer.Interfaces": "1.1.4322",
- "Microsoft.VisualStudio.Editor": "14.1.24720",
- "Microsoft.VisualStudio.ImageCatalog": "14.1.24720",
+ "Microsoft.VisualStudio.Editor": "14.2.25123",
+ "Microsoft.VisualStudio.ImageCatalog": "14.2.25123",
"Microsoft.VisualStudio.OLE.Interop": "7.10.6070",
- "Microsoft.VisualStudio.Shell.Design": "14.1.24720",
- "Microsoft.VisualStudio.Shell.14.0": "14.1.24720",
+ "Microsoft.VisualStudio.Shell.Design": "14.2.25123",
+ "Microsoft.VisualStudio.Shell.14.0": "14.2.25123",
"Microsoft.VisualStudio.Shell.Interop.10.0": "10.0.30319",
"Microsoft.VisualStudio.Shell.Interop.11.0": "11.0.61030",
"Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime": "12.1.30328",
- "Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime": "14.1.24720",
+ "Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime": "14.2.25123",
"Microsoft.VisualStudio.TextManager.Interop.10.0": "10.0.30319",
"Microsoft.VisualStudio.TextManager.Interop.12.0": "12.0.30110",
"Microsoft.VisualStudio.TextManager.Interop.12.1.DesignTime": "12.1.30328",
diff --git a/src/Dependencies/VisualStudioEditor/project.json b/src/Dependencies/VisualStudioEditor/project.json
index 3935c317cb7d4..7f30373444fcb 100644
--- a/src/Dependencies/VisualStudioEditor/project.json
+++ b/src/Dependencies/VisualStudioEditor/project.json
@@ -1,11 +1,11 @@
{
"supports": { },
"dependencies": {
- "Microsoft.VisualStudio.Imaging": "14.1.24720",
- "Microsoft.VisualStudio.ImageCatalog": "14.1.24720",
- "Microsoft.VisualStudio.Language.Intellisense": "14.1.24720",
- "Microsoft.VisualStudio.Language.StandardClassification": "14.1.24720",
- "Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime": "14.1.24720"
+ "Microsoft.VisualStudio.Imaging": "14.2.25123",
+ "Microsoft.VisualStudio.ImageCatalog": "14.2.25123",
+ "Microsoft.VisualStudio.Language.Intellisense": "14.2.25123",
+ "Microsoft.VisualStudio.Language.StandardClassification": "14.2.25123",
+ "Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime": "14.2.25123"
},
"frameworks": {
".NETFramework,Version=v4.6": { }
diff --git a/src/Dependencies/VisualStudioText/project.json b/src/Dependencies/VisualStudioText/project.json
index 445779fb9eaea..5827594f42b6c 100644
--- a/src/Dependencies/VisualStudioText/project.json
+++ b/src/Dependencies/VisualStudioText/project.json
@@ -1,12 +1,13 @@
{
"supports": { },
"dependencies": {
- "Microsoft.VisualStudio.Text.Data": "14.1.24720",
- "Microsoft.VisualStudio.Text.Logic": "14.1.24720",
- "Microsoft.VisualStudio.Text.UI": "14.1.24720",
- "Microsoft.VisualStudio.Text.UI.Wpf": "14.1.24720"
+ "Microsoft.VisualStudio.Text.Data": "14.2.25123",
+ "Microsoft.VisualStudio.Text.Logic": "14.2.25123",
+ "Microsoft.VisualStudio.Text.UI": "14.2.25123",
+ "Microsoft.VisualStudio.Text.UI.Wpf": "14.2.25123",
+ "RoslynDependencies.Microsoft.VisualStudio.Text.Internal": "14.2.25123"
},
"frameworks": {
".NETFramework,Version=v4.6": { }
}
-}
\ No newline at end of file
+}
diff --git a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
index 99ca30785b2d4..1914820690883 100644
--- a/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
+++ b/src/EditorFeatures/CSharpTest/CSharpEditorServicesTest.csproj
@@ -105,10 +105,6 @@
-
-
-
-
@@ -518,4 +514,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/CSharpTest2/CSharpEditorServicesTest2.csproj b/src/EditorFeatures/CSharpTest2/CSharpEditorServicesTest2.csproj
index 33ea43692fb94..d2eb1d60227a3 100644
--- a/src/EditorFeatures/CSharpTest2/CSharpEditorServicesTest2.csproj
+++ b/src/EditorFeatures/CSharpTest2/CSharpEditorServicesTest2.csproj
@@ -109,10 +109,6 @@
-
-
-
-
@@ -265,4 +261,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/Core/EditorFeatures.csproj b/src/EditorFeatures/Core/EditorFeatures.csproj
index ad4e43550e031..6293269c70a1c 100644
--- a/src/EditorFeatures/Core/EditorFeatures.csproj
+++ b/src/EditorFeatures/Core/EditorFeatures.csproj
@@ -59,11 +59,6 @@
true
-
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Language.CallHierarchy.dll
-
-
-
@@ -80,6 +75,7 @@
+
@@ -109,6 +105,7 @@
+
@@ -227,6 +224,8 @@
+
+
@@ -258,6 +257,7 @@
+
@@ -275,9 +275,10 @@
-
-
-
+
+
+
+
@@ -484,7 +485,6 @@
-
@@ -804,4 +804,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/Core/Extensibility/Composition/VisualStudioVersionMetadata.cs b/src/EditorFeatures/Core/Extensibility/Composition/VisualStudioVersionMetadata.cs
new file mode 100644
index 0000000000000..6fc6fc83ceb6b
--- /dev/null
+++ b/src/EditorFeatures/Core/Extensibility/Composition/VisualStudioVersionMetadata.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Editor.Extensibility.Composition
+{
+ internal sealed class VisualStudioVersionMetadata
+ {
+ public VisualStudioVersion Version { get; }
+
+ public VisualStudioVersionMetadata(IDictionary data)
+ {
+ Version = (VisualStudioVersion)data.GetValueOrDefault("Version");
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core/Extensibility/ExportVersionSpecificAttribute.cs b/src/EditorFeatures/Core/Extensibility/ExportVersionSpecificAttribute.cs
new file mode 100644
index 0000000000000..e17b76e9733f4
--- /dev/null
+++ b/src/EditorFeatures/Core/Extensibility/ExportVersionSpecificAttribute.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.CodeAnalysis.Editor
+{
+ ///
+ /// Note: This need to be in ascending order, since we compare values in
+ /// .
+ ///
+ internal enum VisualStudioVersion
+ {
+ /// VS Version 14, aka 'VS 2015'
+ Dev14 = 14,
+ /// VS Version 15, aka 'VS "15"'
+ Dev15 = 15,
+ }
+
+ [MetadataAttribute]
+ [AttributeUsage(AttributeTargets.Class)]
+ internal sealed class ExportVersionSpecificAttribute : ExportAttribute
+ {
+ public VisualStudioVersion Version { get; }
+ public ExportVersionSpecificAttribute(Type contractType, VisualStudioVersion version)
+ : base(contractType)
+ {
+ this.Version = version;
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core/Extensibility/VersionSelector.cs b/src/EditorFeatures/Core/Extensibility/VersionSelector.cs
new file mode 100644
index 0000000000000..0dc2c7000004d
--- /dev/null
+++ b/src/EditorFeatures/Core/Extensibility/VersionSelector.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Editor.Extensibility.Composition;
+
+namespace Microsoft.CodeAnalysis.Editor
+{
+ internal sealed class VersionSelector
+ {
+ public static T SelectHighest(IEnumerable> items)
+ {
+ return items.OrderByDescending(i => i.Metadata.Version).First().Value;
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenter.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenter.cs
index 010926eff0b20..38156510624e1 100644
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenter.cs
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenter.cs
@@ -1,6 +1,9 @@
// 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.ComponentModel.Composition;
+using Microsoft.CodeAnalysis.Editor.Extensibility.Composition;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
@@ -17,18 +20,24 @@ internal sealed class CompletionPresenter : ForegroundThreadAffinitizedObject, I
{
private readonly ICompletionBroker _completionBroker;
private readonly IGlyphService _glyphService;
+ private readonly ICompletionSetFactory _completionSetFactory;
[ImportingConstructor]
- public CompletionPresenter(ICompletionBroker completionBroker, IGlyphService glyphService)
+ public CompletionPresenter(
+ ICompletionBroker completionBroker,
+ IGlyphService glyphService,
+ [ImportMany] IEnumerable> completionSetFactories)
{
_completionBroker = completionBroker;
_glyphService = glyphService;
+ _completionSetFactory = VersionSelector.SelectHighest(completionSetFactories);
}
ICompletionPresenterSession IIntelliSensePresenter.CreateSession(ITextView textView, ITextBuffer subjectBuffer, ICompletionSession session)
{
AssertIsForeground();
- return new CompletionPresenterSession(_completionBroker, _glyphService, textView, subjectBuffer);
+ return new CompletionPresenterSession(
+ _completionSetFactory, _completionBroker, _glyphService, textView, subjectBuffer);
}
ICompletionSource ICompletionSourceProvider.TryCreateCompletionSource(ITextBuffer textBuffer)
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenterSession.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenterSession.cs
index 8bad59fb68968..e6944660608ab 100644
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenterSession.cs
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionPresenterSession.cs
@@ -28,7 +28,7 @@ internal sealed class CompletionPresenterSession : ForegroundThreadAffinitizedOb
public event EventHandler ItemSelected;
public event EventHandler FilterStateChanged;
- private readonly CompletionSet3 _completionSet;
+ private readonly ICompletionSet _completionSet;
private ICompletionSession _editorSessionOpt;
private bool _ignoreSelectionStatusChangedEvent;
@@ -44,6 +44,7 @@ public ITextBuffer SubjectBuffer
}
public CompletionPresenterSession(
+ ICompletionSetFactory completionSetFactory,
ICompletionBroker completionBroker,
IGlyphService glyphService,
ITextView textView,
@@ -54,7 +55,7 @@ public ITextBuffer SubjectBuffer
_textView = textView;
_subjectBuffer = subjectBuffer;
- _completionSet = new CompletionSet3(this, textView, subjectBuffer);
+ _completionSet = completionSetFactory.CreateCompletionSet(this, textView, subjectBuffer);
_completionSet.SelectionStatusChanged += OnCompletionSetSelectionStatusChanged;
}
@@ -156,15 +157,14 @@ private void OnCompletionSetSelectionStatusChanged(object sender, ValueChangedEv
internal void AugmentCompletionSession(IList completionSets)
{
- Contract.ThrowIfTrue(completionSets.Contains(_completionSet));
- completionSets.Add(_completionSet);
+ Contract.ThrowIfTrue(completionSets.Contains(_completionSet.CompletionSet));
+ completionSets.Add(_completionSet.CompletionSet);
}
- internal void OnIntelliSenseFiltersChanged(IReadOnlyList filters)
+ internal void OnIntelliSenseFiltersChanged(ImmutableDictionary filterStates)
{
this.FilterStateChanged?.Invoke(this,
- new CompletionItemFilterStateChangedEventArgs(
- filters.ToImmutableDictionary(f => f.CompletionItemFilter, f => f.IsChecked)));
+ new CompletionItemFilterStateChangedEventArgs(filterStates));
}
public void Dismiss()
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSet.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSet.cs
new file mode 100644
index 0000000000000..3445ff9f6c750
--- /dev/null
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSet.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis.Completion;
+using Microsoft.VisualStudio.Language.Intellisense;
+using Microsoft.VisualStudio.Text;
+using VSCompletion = Microsoft.VisualStudio.Language.Intellisense.Completion;
+
+namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
+{
+ internal interface ICompletionSet
+ {
+ event EventHandler> SelectionStatusChanged;
+ void SetTrackingSpan(ITrackingSpan trackingSpan);
+
+ CompletionSet CompletionSet { get; }
+
+ void SetCompletionItems(
+ IList completionItems,
+ PresentationItem selectedItem,
+ PresentationItem presetBuilder,
+ bool suggestionMode,
+ bool isSoftSelected,
+ ImmutableArray completionItemFilters,
+ IReadOnlyDictionary completionItemToFilterText);
+ PresentationItem GetPresentationItem(VSCompletion completion);
+ }
+}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSetFactory.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSetFactory.cs
new file mode 100644
index 0000000000000..f2daef0ee25cf
--- /dev/null
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/ICompletionSetFactory.cs
@@ -0,0 +1,18 @@
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
+{
+ ///
+ /// We have two implementations of ICompletionSet that are specific to different VS versions
+ /// because the newer one lights up new functionality from the platform. This let's the
+ /// presenter create the right one.
+ ///
+ internal interface ICompletionSetFactory
+ {
+ ICompletionSet CreateCompletionSet(
+ CompletionPresenterSession completionPresenterSession,
+ ITextView textView,
+ ITextBuffer subjectBuffer);
+ }
+}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionSet3.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/RoslynCompletionSet.cs
similarity index 91%
rename from src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionSet3.cs
rename to src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/RoslynCompletionSet.cs
index 4481b873ade61..3d9fa05b0640a 100644
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/CompletionSet3.cs
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/RoslynCompletionSet.cs
@@ -15,10 +15,10 @@
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
{
-#if NEWCOMPLETION
- internal sealed class CompletionSet3 : CompletionSet2
+#if DEV15
+ internal sealed class FilteredRoslynCompletionSet : CompletionSet2, ICompletionSet
#else
- internal sealed class CompletionSet3 : CompletionSet
+ internal sealed class RoslynCompletionSet : CompletionSet, ICompletionSet
#endif
{
private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject();
@@ -27,11 +27,17 @@ internal sealed class CompletionSet3 : CompletionSet
private readonly CompletionPresenterSession _completionPresenterSession;
private Dictionary _presentationItemMap;
+ private IReadOnlyDictionary _completionItemToFilterText;
+
+#if DEV15
private CompletionHelper _completionHelper;
private IReadOnlyList _filters;
- private IReadOnlyDictionary _completionItemToFilterText;
+ public override IReadOnlyList Filters => _filters;
- public CompletionSet3(
+ public FilteredRoslynCompletionSet(
+#else
+ public RoslynCompletionSet(
+#endif
CompletionPresenterSession completionPresenterSession,
ITextView textView,
ITextBuffer subjectBuffer)
@@ -43,19 +49,15 @@ internal sealed class CompletionSet3 : CompletionSet
this.DisplayName = "All";
}
-#if NEWCOMPLETION
- public override IReadOnlyList Filters => _filters;
-#endif
-
- internal void SetTrackingSpan(ITrackingSpan trackingSpan)
+ void ICompletionSet.SetTrackingSpan(ITrackingSpan trackingSpan)
{
this.ApplicableTo = trackingSpan;
}
- internal void SetCompletionItems(
+ void ICompletionSet.SetCompletionItems(
IList completionItems,
PresentationItem selectedItem,
- PresentationItem suggestionModeItem,
+ PresentationItem presetBuilder,
bool suggestionMode,
bool isSoftSelected,
ImmutableArray completionItemFilters,
@@ -74,12 +76,14 @@ internal void SetTrackingSpan(ITrackingSpan trackingSpan)
this.WritableCompletionBuilders.BeginBulkOperation();
this.WritableCompletionBuilders.Clear();
+#if DEV15
// If more than one filter was provided, then present it to the user.
if (_filters == null && completionItemFilters.Length > 1)
{
_filters = completionItemFilters.Select(f => new IntellisenseFilter2(this, f, GetLanguage()))
.ToArray();
}
+#endif
var applicableToText = this.ApplicableTo.GetText(this.ApplicableTo.TextBuffer.CurrentSnapshot);
@@ -90,8 +94,8 @@ internal void SetTrackingSpan(ITrackingSpan trackingSpan)
selectedItem.CompletionService,
isSuggestionModeItem: true);
- var showBuilder = suggestionMode || suggestionModeItem != null;
- var bestSuggestionModeItem = applicableToText.Length > 0 ? filteredSuggestionModeItem : suggestionModeItem ?? filteredSuggestionModeItem;
+ var showBuilder = suggestionMode || presetBuilder != null;
+ var bestSuggestionModeItem = applicableToText.Length > 0 ? filteredSuggestionModeItem : presetBuilder ?? filteredSuggestionModeItem;
if (showBuilder && bestSuggestionModeItem != null)
{
@@ -148,7 +152,7 @@ private VSCompletion GetVSCompletion(PresentationItem item)
return value;
}
- internal PresentationItem GetPresentationItem(VSCompletion completion)
+ PresentationItem ICompletionSet.GetPresentationItem(VSCompletion completion)
{
// Linear search is ok since this is only called by the user manually selecting
// an item. Creating a reverse mapping uses too much memory and affects GCs.
@@ -191,6 +195,7 @@ private string GetLanguage()
return "";
}
+#if DEV15
private CompletionHelper GetCompletionHelper()
{
_foregroundObject.AssertIsForeground();
@@ -206,11 +211,7 @@ private CompletionHelper GetCompletionHelper()
return _completionHelper;
}
-#if NEWCOMPLETION
public override IReadOnlyList GetHighlightedSpansInDisplayText(string displayText)
-#else
- public IReadOnlyList GetHighlightedSpansInDisplayText(string displayText)
-#endif
{
if (_completionItemToFilterText != null)
{
@@ -239,7 +240,11 @@ public IReadOnlyList GetHighlightedSpansInDisplayText(string displayText)
internal void OnIntelliSenseFiltersChanged()
{
- this._completionPresenterSession.OnIntelliSenseFiltersChanged(_filters);
+ this._completionPresenterSession.OnIntelliSenseFiltersChanged(
+ _filters.ToImmutableDictionary(f => f.CompletionItemFilter, f => f.IsChecked));
}
+#endif
+
+ CompletionSet ICompletionSet.CompletionSet => this;
}
}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/VisualStudio14CompletionSetFactory.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/VisualStudio14CompletionSetFactory.cs
new file mode 100644
index 0000000000000..db6b7562db0d3
--- /dev/null
+++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/VisualStudio14CompletionSetFactory.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel.Composition;
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
+{
+ [ExportVersionSpecific(typeof(ICompletionSetFactory), VisualStudioVersion.Dev14)]
+ internal sealed class VisualStudio14CompletionSetFactory : ICompletionSetFactory
+ {
+ public ICompletionSet CreateCompletionSet(
+ CompletionPresenterSession completionPresenterSession,
+ ITextView textView,
+ ITextBuffer subjectBuffer)
+ {
+ return new RoslynCompletionSet(
+ completionPresenterSession, textView, subjectBuffer);
+ }
+ }
+}
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IIntellisenseFilter.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IIntellisenseFilter.cs
deleted file mode 100644
index 5bf81f1a5aea7..0000000000000
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IIntellisenseFilter.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-#if !NEWCOMPLETION
-// Copyright (c) Microsoft Corporation
-// All rights reserved
-// REMOVE ONCE WE ACTUALLY REFERENCE THE REAL EDITOR DLLS.
-using Microsoft.VisualStudio.Imaging.Interop;
-
-namespace Microsoft.VisualStudio.Language.Intellisense
-{
- ///
- /// Defines a filter used to add a row of filter buttons to the bottom
- ///
- internal interface IIntellisenseFilter
- {
- ///
- /// The icon shown on the filter's button.
- ///
- ImageMoniker Moniker { get; }
- ///
- /// The tooltip shown when the mouse hovers over the button.
- ///
- string ToolTip { get; }
- ///
- /// The key used to toggle the filter's state.
- ///
- string AccessKey { get; }
- ///
- /// String used to represent the button for automation.
- ///
- string AutomationText { get; }
- ///
- /// Has the user turned the filter on?
- ///
- ///
- /// The setter will be called when the user toggles the corresponding filter button.
- ///
- bool IsChecked { get; set; }
- ///
- /// Is the filter enabled?
- ///
- ///
- /// Disabled filters are shown but are grayed out.
- ///
- bool IsEnabled { get; set; }
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IntellisenseFilter.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IntellisenseFilter.cs
deleted file mode 100644
index 4ae35ac1d7364..0000000000000
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Temporary/IntellisenseFilter.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-#if !NEWCOMPLETION
-// Copyright (c) Microsoft Corporation
-// All rights reserved
-// REMOVE ONCE WE ACTUALLY REFERENCE THE REAL EDITOR DLLS.
-using System;
-using Microsoft.VisualStudio.Imaging.Interop;
-
-namespace Microsoft.VisualStudio.Language.Intellisense
-{
- internal class IntellisenseFilter : IIntellisenseFilter
- {
- ///
- /// Create an instance of an IntellisenseFilter with the specified attributes.
- ///
- public IntellisenseFilter(ImageMoniker moniker, string toolTip, string accessKey, string automationText, bool initialIsChecked = false, bool initialIsEnabled = true)
- {
- if (string.IsNullOrEmpty(accessKey))
- {
- throw new ArgumentException("Must not be null or empty", nameof(accessKey));
- }
- this.Moniker = moniker;
- this.ToolTip = toolTip;
- this.AccessKey = accessKey;
- this.AutomationText = automationText;
- this.IsChecked = initialIsChecked;
- this.IsEnabled = initialIsEnabled;
- }
- ///
- /// The icon shown on the filter's button.
- ///
- public ImageMoniker Moniker { get; }
- ///
- /// The tooltip shown when the mouse hovers over the button.
- ///
- public string ToolTip { get; }
- ///
- /// The key used to toggle the filter's state.
- ///
- public string AccessKey { get; }
- ///
- /// String used to represent the button for automation.
- ///
- public string AutomationText { get; }
- ///
- /// Has the user turned the filter on?
- ///
- ///
- /// The setter will be called when the user toggles the corresponding filter button.
- ///
- public virtual bool IsChecked { get; set; }
- ///
- /// Is the filter enabled?
- ///
- ///
- /// Disabled filters are shown but are grayed out.
- /// Intellisense will never call the setter but the owner may and the Intellisense popup will respect the changes.
- ///
- public bool IsEnabled { get; set; }
- }
-}
-#endif
\ No newline at end of file
diff --git a/src/EditorFeatures/Core/project.json b/src/EditorFeatures/Core/project.json
index 718f042f58ddd..398f006138a8e 100644
--- a/src/EditorFeatures/Core/project.json
+++ b/src/EditorFeatures/Core/project.json
@@ -1,5 +1,7 @@
{
"dependencies": {
+ "RoslynDependencies.Microsoft.VisualStudio.Language.CallHierarchy": "14.0.23107",
+ "RoslynDependencies.Microsoft.VisualStudio.Language.NavigateTo.Interfaces": "14.0.23107"
},
"frameworks": {
"net46": {}
diff --git a/src/EditorFeatures/Next/EditorFeatures.Next.csproj b/src/EditorFeatures/Next/EditorFeatures.Next.csproj
new file mode 100644
index 0000000000000..eacb774c7ea8b
--- /dev/null
+++ b/src/EditorFeatures/Next/EditorFeatures.Next.csproj
@@ -0,0 +1,85 @@
+
+
+
+ CSharp
+
+
+
+
+
+ Debug
+ AnyCPU
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}
+ Library
+ Microsoft.CodeAnalysis.Editor
+ Microsoft.CodeAnalysis.EditorFeatures.Next
+ v4.6
+ false
+ DEV15
+
+
+
+ {1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}
+ CodeAnalysis
+
+
+ {DCDA908D-EF5E-494B-ADDC-C26F5FD610CA}
+ Immutable
+
+
+ {ef986d9b-8cfc-4ecb-9729-e260a1f84aff}
+ VisualStudioEditor
+
+
+ {2e87fa96-50bb-4607-8676-46521599f998}
+ Workspaces.Desktop
+
+
+ {5F8D2414-064A-4B3A-9B42-8E2A04246BE5}
+ Workspaces
+
+
+ {EDC68A0E-C68D-4A74-91B7-BF38EC909888}
+ Features
+
+
+ {3cdeeab7-2256-418a-beb2-620b5cb16302}
+ EditorFeatures
+
+
+ {18F5FBB8-7570-4412-8CC7-0A86FF13B7BA}
+ TextEditorFeatures
+
+
+ {01E9BD68-0339-4A13-B42F-A3CA84D164F3}
+ InteractiveWindow
+ InteractiveWindow
+
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IntelliSense\Completion\Presentation\RoslynCompletionSet.cs
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs b/src/EditorFeatures/Next/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs
similarity index 87%
rename from src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs
rename to src/EditorFeatures/Next/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs
index 2a10c22501b70..5187cdb8e5a95 100644
--- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs
+++ b/src/EditorFeatures/Next/IntelliSense/Completion/Presentation/IntellisenseFilter2.cs
@@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.P
{
internal class IntellisenseFilter2 : IntellisenseFilter
{
- private readonly CompletionSet3 _completionSet;
+ private readonly FilteredRoslynCompletionSet _completionSet;
public readonly CompletionItemFilter CompletionItemFilter;
public IntellisenseFilter2(
- CompletionSet3 completionSet, CompletionItemFilter filter, string language)
+ FilteredRoslynCompletionSet completionSet, CompletionItemFilter filter, string language)
: base(ImageMonikers.GetImageMoniker(filter.Tags, language), GetToolTip(filter),
filter.AccessKey.ToString(), automationText: filter.Tags[0])
{
diff --git a/src/EditorFeatures/Next/IntelliSense/Completion/Presentation/VisualStudio15CompletionSetFactory.cs b/src/EditorFeatures/Next/IntelliSense/Completion/Presentation/VisualStudio15CompletionSetFactory.cs
new file mode 100644
index 0000000000000..cc21608cbebe6
--- /dev/null
+++ b/src/EditorFeatures/Next/IntelliSense/Completion/Presentation/VisualStudio15CompletionSetFactory.cs
@@ -0,0 +1,18 @@
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Editor;
+
+namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.Presentation
+{
+ [ExportVersionSpecific(typeof(ICompletionSetFactory), VisualStudioVersion.Dev15)]
+ internal sealed class VisualStudio15CompletionSetFactory : ICompletionSetFactory
+ {
+ public ICompletionSet CreateCompletionSet(
+ CompletionPresenterSession completionPresenterSession,
+ ITextView textView,
+ ITextBuffer subjectBuffer)
+ {
+ return new FilteredRoslynCompletionSet(
+ completionPresenterSession, textView, subjectBuffer);
+ }
+ }
+}
diff --git a/src/EditorFeatures/Next/PublicAPI.Shipped.txt b/src/EditorFeatures/Next/PublicAPI.Shipped.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/EditorFeatures/Next/PublicAPI.Unshipped.txt b/src/EditorFeatures/Next/PublicAPI.Unshipped.txt
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/EditorFeatures/Next/project.json b/src/EditorFeatures/Next/project.json
new file mode 100644
index 0000000000000..3d2e6fbd053de
--- /dev/null
+++ b/src/EditorFeatures/Next/project.json
@@ -0,0 +1,8 @@
+{
+ "dependencies": {
+ "Microsoft.VisualStudio.Language.Intellisense": "15.0.25123-Dev15Preview",
+ },
+ "frameworks": {
+ "net46": {}
+ }
+}
diff --git a/src/EditorFeatures/Test/EditorServicesTest.csproj b/src/EditorFeatures/Test/EditorServicesTest.csproj
index 5c6c2a60deb32..beab9602190e0 100644
--- a/src/EditorFeatures/Test/EditorServicesTest.csproj
+++ b/src/EditorFeatures/Test/EditorServicesTest.csproj
@@ -18,11 +18,6 @@
true
true
-
-
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Platform.VSEditor.Interop.dll
-
-
{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}
@@ -144,10 +139,6 @@
-
-
-
-
@@ -350,4 +341,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/Test/project.json b/src/EditorFeatures/Test/project.json
index 776ced8e60381..335400b75762b 100644
--- a/src/EditorFeatures/Test/project.json
+++ b/src/EditorFeatures/Test/project.json
@@ -2,6 +2,7 @@
"dependencies": {
"BasicUndo": "0.9.3",
"Microsoft.VisualStudio.Composition": "14.0.50715-pre",
+ "RoslynDependencies.Microsoft.VisualStudio.Platform.VSEditor": "14.2.25123"
},
"frameworks": {
"net46": {}
diff --git a/src/EditorFeatures/Test2/EditorServicesTest2.vbproj b/src/EditorFeatures/Test2/EditorServicesTest2.vbproj
index b9ce4afed98db..0c2a70a29207b 100644
--- a/src/EditorFeatures/Test2/EditorServicesTest2.vbproj
+++ b/src/EditorFeatures/Test2/EditorServicesTest2.vbproj
@@ -116,9 +116,6 @@
Roslyn.Services.Editor.UnitTests2.xml
-
-
-
@@ -302,4 +299,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/Text/TextEditorFeatures.csproj b/src/EditorFeatures/Text/TextEditorFeatures.csproj
index e914166049156..7ca636907970e 100644
--- a/src/EditorFeatures/Text/TextEditorFeatures.csproj
+++ b/src/EditorFeatures/Text/TextEditorFeatures.csproj
@@ -32,9 +32,6 @@
-
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Text.Internal.dll
-
@@ -43,6 +40,7 @@
+
@@ -94,4 +92,4 @@
-
\ No newline at end of file
+
diff --git a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj
index 4888c0cd830d5..71c32767c59af 100644
--- a/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj
+++ b/src/EditorFeatures/VisualBasicTest/BasicEditorServicesTest.vbproj
@@ -91,9 +91,6 @@
true
-
-
-
@@ -612,4 +609,4 @@
-
\ No newline at end of file
+
diff --git a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/DebuggerVisualizerAttributeTests.cs b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/DebuggerVisualizerAttributeTests.cs
index 061512d132b04..e7cbf67c7d610 100644
--- a/src/ExpressionEvaluator/CSharp/Test/ResultProvider/DebuggerVisualizerAttributeTests.cs
+++ b/src/ExpressionEvaluator/CSharp/Test/ResultProvider/DebuggerVisualizerAttributeTests.cs
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+using System;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
@@ -44,7 +45,8 @@ class Q
var typeQ = assembly.GetType("Q");
string defaultDebuggeeSideVisualizerTypeName = "Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource";
- string defaultDebuggeeSideVisualizerAssemblyName = "Microsoft.VisualStudio.DebuggerVisualizers, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
+ var vsVersion = Environment.GetEnvironmentVariable("VisualStudioVersion") ?? "14.0";
+ string defaultDebuggeeSideVisualizerAssemblyName = $"Microsoft.VisualStudio.DebuggerVisualizers, Version={vsVersion}.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
DkmCustomUIVisualizerInfo[] customUIVisualizerInfo =
{
diff --git a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs
index 7d63682bd9ce8..4602ff8ac61c7 100644
--- a/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs
+++ b/src/ExpressionEvaluator/Core/Test/ResultProvider/Debugger/Engine/DkmClrType.cs
@@ -299,7 +299,8 @@ private static DkmClrDebuggerVisualizerAttribute[] GetDebuggerVisualizerAttribut
else
{
debuggeeSideVisualizerTypeName = "Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource";
- debuggeeSideVisualizerAssemblyName = "Microsoft.VisualStudio.DebuggerVisualizers, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
+ var vsVersion = System.Environment.GetEnvironmentVariable("VisualStudioVersion") ?? "14.0";
+ debuggeeSideVisualizerAssemblyName = $"Microsoft.VisualStudio.DebuggerVisualizers, Version={vsVersion}.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
}
string visualizerDescription = uiSideVisualizerTypeName;
diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj
index 1094fc0715372..a928bb66783f2 100644
--- a/src/Features/Core/Portable/Features.csproj
+++ b/src/Features/Core/Portable/Features.csproj
@@ -36,6 +36,7 @@
+
@@ -65,6 +66,7 @@
+
diff --git a/src/Interactive/EditorFeatures/Core/Implementation/Completion/Presentation/CompletionPresenter.cs b/src/Interactive/EditorFeatures/Core/Implementation/Completion/Presentation/CompletionPresenter.cs
index e0d9e9051078d..eccbabf03deb7 100644
--- a/src/Interactive/EditorFeatures/Core/Implementation/Completion/Presentation/CompletionPresenter.cs
+++ b/src/Interactive/EditorFeatures/Core/Implementation/Completion/Presentation/CompletionPresenter.cs
@@ -9,6 +9,9 @@
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.InteractiveWindow;
using Microsoft.VisualStudio.InteractiveWindow.Commands;
+using System.Collections.Generic;
+using System;
+using Microsoft.CodeAnalysis.Editor.Extensibility.Composition;
namespace Microsoft.CodeAnalysis.Editor.Implementation.Completion.Presentation
{
@@ -19,18 +22,24 @@ internal partial class CompletionPresenter : ForegroundThreadAffinitizedObject,
{
private readonly ICompletionBroker _completionBroker;
private readonly IGlyphService _glyphService;
+ private readonly ICompletionSetFactory _completionSetFactory;
[ImportingConstructor]
- public CompletionPresenter(ICompletionBroker completionBroker, IGlyphService glyphService)
+ public CompletionPresenter(
+ ICompletionBroker completionBroker,
+ IGlyphService glyphService,
+ [ImportMany] IEnumerable> completionSetFactories)
{
_completionBroker = completionBroker;
_glyphService = glyphService;
+ _completionSetFactory = VersionSelector.SelectHighest(completionSetFactories);
}
ICompletionPresenterSession IIntelliSensePresenter.CreateSession(ITextView textView, ITextBuffer subjectBuffer, ICompletionSession sessionOpt)
{
AssertIsForeground();
- return new CompletionPresenterSession(_completionBroker, _glyphService, textView, subjectBuffer);
+ return new CompletionPresenterSession(
+ _completionSetFactory, _completionBroker, _glyphService, textView, subjectBuffer);
}
ICompletionSource ICompletionSourceProvider.TryCreateCompletionSource(ITextBuffer textBuffer)
diff --git a/src/InteractiveWindow/Editor/InteractiveWindow.csproj b/src/InteractiveWindow/Editor/InteractiveWindow.csproj
index 465892b7ccf20..92aebded3ae88 100644
--- a/src/InteractiveWindow/Editor/InteractiveWindow.csproj
+++ b/src/InteractiveWindow/Editor/InteractiveWindow.csproj
@@ -26,10 +26,6 @@
-
- False
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Text.Internal.dll
-
@@ -136,4 +132,4 @@
-
\ No newline at end of file
+
diff --git a/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj b/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj
index ba9821948ddfa..48b1bf2cc6451 100644
--- a/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj
+++ b/src/InteractiveWindow/EditorTest/InteractiveWindowTest.csproj
@@ -49,13 +49,6 @@
-
-
- $(DevEnvDir)\CommonExtensions\Microsoft\Editor\Microsoft.VisualStudio.Platform.VSEditor.dll
-
-
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Platform.VSEditor.Interop.dll
-
@@ -90,4 +83,4 @@
-
\ No newline at end of file
+
diff --git a/src/InteractiveWindow/EditorTest/project.json b/src/InteractiveWindow/EditorTest/project.json
index e53cf7d8d3964..be64b90fb3ac3 100644
--- a/src/InteractiveWindow/EditorTest/project.json
+++ b/src/InteractiveWindow/EditorTest/project.json
@@ -1,6 +1,7 @@
{
"dependencies": {
"BasicUndo": "0.9.3",
+ "RoslynDependencies.Microsoft.VisualStudio.Platform.VSEditor": "14.2.25123"
},
"frameworks": {
"net46": {}
@@ -8,4 +9,4 @@
"runtimes": {
"win7-x86": {}
}
-}
\ No newline at end of file
+}
diff --git a/src/Test/Perf/bootstrap.bat b/src/Test/Perf/bootstrap.bat
index 374ec5eeede51..936ec284ec277 100644
--- a/src/Test/Perf/bootstrap.bat
+++ b/src/Test/Perf/bootstrap.bat
@@ -2,8 +2,8 @@
call "%~dp0..\..\..\Restore.cmd"
-set MSBuild=%ProgramFiles%\MSBuild\14.0\bin\msbuild.exe
-if not exist "%MSBuild%" set MSBuild=%ProgramFiles(x86)%\MSBuild\14.0\bin\msbuild.exe
+set MSBuild=%ProgramFiles%\MSBuild\%VisualStudioVersion%\bin\msbuild.exe
+if not exist "%MSBuild%" set MSBuild=%ProgramFiles(x86)%\MSBuild\%VisualStudioVersion%\bin\msbuild.exe
"%MSBuild%" "%~dp0..\..\..\src\Interactive\csi\csi.csproj" /p:Configuration=Release /p:OutDir="%~dp0infra\bin\\"
if "%USERDNSDOMAIN%" == "REDMOND.CORP.MICROSOFT.COM" (
@@ -12,4 +12,4 @@ if "%USERDNSDOMAIN%" == "REDMOND.CORP.MICROSOFT.COM" (
robocopy \\mlangfs1\public\basoundr\vibenchcsv2json %SYSTEMDRIVE%\CPC /s
) else (
echo "Machine not in Microsoft Corp Net Domain. Hence not downloading internal tools"
-)
\ No newline at end of file
+)
diff --git a/src/Test/Perf/infra/install.csx b/src/Test/Perf/infra/install.csx
index 395fc3b65768a..b56daa17ba695 100644
--- a/src/Test/Perf/infra/install.csx
+++ b/src/Test/Perf/infra/install.csx
@@ -12,6 +12,7 @@ using System.Diagnostics;
using System.IO;
using Roslyn.Test.Performance.Utilities;
using static Roslyn.Test.Performance.Utilities.TestUtilities;
+using static System.FormattableString;
TestUtilities.InitUtilitiesFromCsx();
@@ -35,7 +36,8 @@ foreach (var processName in new[] { "devenv", "msbuild", "VBCSCompiler"})
var logger = new ConsoleAndFileLogger();
logger.Log($"\n{message} Roslyn binaries to VS folder.");
-var devenvFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Microsoft Visual Studio 14.0\Common7\IDE");
+var vsVersion = Environment.GetEnvironmentVariable("VisualStudioVersion") ?? "14.0";
+var devenvFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), Invariant($@"Microsoft Visual Studio {vsVersion}\Common7\IDE"));
var destinationFolder = Path.Combine(devenvFolder, "PrivateAssemblies");
var filesToNGen = new List();
foreach (var file in IDEFiles)
@@ -60,8 +62,8 @@ ShellOutVital(devenv, "/updateconfiguration", IsVerbose(), logger);
ShellOutVital(devenv, $"/resetsettingsfull {Path.Combine(sourceFolder, "Default.vssettings")} /command \"File.Exit\"", IsVerbose(), logger);
logger.Log($"\n{message} compilers in MSBuild folders.");
-destinationFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"MSBuild\14.0\Bin");
-var destinationFolder64 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"MSBuild\14.0\Bin\amd64");
+destinationFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), Invariant($@"MSBuild\{vsVersion}\Bin"));
+var destinationFolder64 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), Invariant($@"MSBuild\14.0\{vsVersion}\amd64"));
filesToNGen = new List();
foreach (var file in MSBuildFiles)
{
diff --git a/src/Test/Utilities/Desktop/TestHelpers.cs b/src/Test/Utilities/Desktop/TestHelpers.cs
index 0d72db714f760..df087788134c7 100644
--- a/src/Test/Utilities/Desktop/TestHelpers.cs
+++ b/src/Test/Utilities/Desktop/TestHelpers.cs
@@ -12,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
+using Microsoft.Win32;
namespace Roslyn.Test.Utilities
{
@@ -145,5 +146,24 @@ public static string AsXmlCommentText(string text)
Debug.Assert(!result.Contains("--"));
return result;
}
+
+ public static string GetMSBuildDirectory()
+ {
+ var vsVersion = Environment.GetEnvironmentVariable("VisualStudioVersion") ?? "14.0";
+ using (var key = Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{vsVersion}", false))
+ {
+ if (key != null)
+ {
+ var toolsPath = key.GetValue("MSBuildToolsPath");
+ if (toolsPath != null)
+ {
+ return toolsPath.ToString();
+ }
+ }
+ }
+
+ return null;
+ }
+
}
}
diff --git a/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj b/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
index a28a9bd238516..2ee17a0ee6bf5 100644
--- a/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
+++ b/src/VisualStudio/CSharp/Impl/CSharpVisualStudio.csproj
@@ -93,7 +93,6 @@
false
-
@@ -270,4 +269,4 @@
-
\ No newline at end of file
+
diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs
index d55e278dcdf14..a64177cc27c10 100644
--- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs
+++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs
@@ -33,6 +33,12 @@ public int AutoComment
set { SetBooleanOption(FeatureOnOffOptions.AutoXmlDocCommentGeneration, value); }
}
+ public int AutoInsertAsteriskForNewLinesOfBlockComments
+ {
+ get { return GetBooleanOption(FeatureOnOffOptions.AutoInsertBlockCommentStartString); }
+ set { SetBooleanOption(FeatureOnOffOptions.AutoInsertBlockCommentStartString, value); }
+ }
+
public int BringUpOnIdentifier
{
get { return GetBooleanOption(CompletionOptions.TriggerOnTypingLetters); }
diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs
index c31fbb5b62dc4..4a78e6517145c 100644
--- a/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs
+++ b/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs
@@ -161,6 +161,7 @@ private bool SupportsOnOffOption(IOption option)
option == FeatureOnOffOptions.KeywordHighlighting ||
option == FeatureOnOffOptions.FormatOnPaste ||
option == FeatureOnOffOptions.AutoXmlDocCommentGeneration ||
+ option == FeatureOnOffOptions.AutoInsertBlockCommentStartString ||
option == FeatureOnOffOptions.RefactoringVerification ||
option == FeatureOnOffOptions.RenameTracking ||
option == FeatureOnOffOptions.RenameTrackingPreview;
diff --git a/src/VisualStudio/CSharp/Test/CSharpVisualStudioTest.csproj b/src/VisualStudio/CSharp/Test/CSharpVisualStudioTest.csproj
index acc45e5ece87f..68a4432990438 100644
--- a/src/VisualStudio/CSharp/Test/CSharpVisualStudioTest.csproj
+++ b/src/VisualStudio/CSharp/Test/CSharpVisualStudioTest.csproj
@@ -15,11 +15,6 @@
v4.6
-
-
- $(DevEnvDir)\CommonExtensions\Microsoft\Editor\Microsoft.VisualStudio.Platform.VSEditor.dll
-
-
{92412d1a-0f23-45b5-b196-58839c524917}
@@ -131,9 +126,6 @@
false
-
- $(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.Text.Internal.dll
-
@@ -205,4 +197,4 @@
-
\ No newline at end of file
+
diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/SuppressionStateColumnFilterDefinition.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/SuppressionStateColumnFilterDefinition.cs
deleted file mode 100644
index 3ee9b9afaa3cc..0000000000000
--- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/Suppression/SuppressionStateColumnFilterDefinition.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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.ComponentModel.Composition;
-using Microsoft.VisualStudio.Utilities;
-using Microsoft.Internal.VisualStudio.Shell.TableControl;
-using System;
-
-namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
-{
- // we are disabling this due to this issue. https://github.com/dotnet/roslyn/pull/9201
-
- //
- // Supporession column definition filter
- //
- //
- // TODO: Move this column down to the shell as it is shared by multiple issue sources (Roslyn and FxCop).
- //
- // [Export(typeof(EntryFilterDefinition))]
- // [Name(SuppressionStateColumnDefinition.ColumnName)]
- // internal class SuppressionStateColumnFilterDefinition : EntryFilterDefinition
- // {
- // public override bool HasAttribute(string key) => string.Equals(NonActionable, key, StringComparison.OrdinalIgnoreCase);
- // }
-}
-
diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
index 8ab649beed204..71f32589f2442 100644
--- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
+++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj
@@ -107,7 +107,6 @@
-
@@ -155,6 +154,7 @@
+
@@ -245,9 +245,6 @@
-
- $(DevEnvDir)\Microsoft.VisualStudio.CallHierarchy.Package.Definitions.dll
-
$(DevEnvDir)\PrivateAssemblies\Microsoft.VisualStudio.ExtensionManager.dll
@@ -295,21 +292,6 @@
false
-
-
-
-
- $(DevEnvDir)\CommonExtensions\Microsoft\Architecture Tools\GraphProviderPackage\Microsoft.VisualStudio.Progression.CodeSchema.dll
-
-
- $(DevEnvDir)\CommonExtensions\Microsoft\Architecture Tools\GraphProviderPackage\Microsoft.VisualStudio.Progression.Common.dll
-
-
- $(DevEnvDir)\CommonExtensions\Microsoft\Architecture Tools\GraphProviderPackage\Microsoft.VisualStudio.Progression.Interfaces.dll
-
-
- false
-
diff --git a/src/VisualStudio/Core/Def/SymbolSearch/IAddReferenceDatabaseWrapper.cs b/src/VisualStudio/Core/Def/SymbolSearch/IAddReferenceDatabaseWrapper.cs
new file mode 100644
index 0000000000000..bb3d82d1aa05a
--- /dev/null
+++ b/src/VisualStudio/Core/Def/SymbolSearch/IAddReferenceDatabaseWrapper.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Elfie.Model;
+
+namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch
+{
+ // Wrapper types to ensure we delay load the elfie database.
+ internal interface IAddReferenceDatabaseWrapper
+ {
+ AddReferenceDatabase Database { get; }
+ }
+
+ internal class AddReferenceDatabaseWrapper : IAddReferenceDatabaseWrapper
+ {
+ public AddReferenceDatabase Database { get; }
+
+ public AddReferenceDatabaseWrapper(AddReferenceDatabase database)
+ {
+ Database = database;
+ }
+ }
+}
diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs
index e588990c77485..894bdef8002d1 100644
--- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs
+++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs
@@ -44,8 +44,6 @@ internal partial class SymbolSearchService
private const string MicrosoftAssemblyReferencesName = "MicrosoftAssemblyReferences";
private static readonly LinkedList s_log = new LinkedList();
- private readonly int _dataFormatVersion = AddReferenceDatabase.TextFileFormatVersion;
-
///
/// Cancellation support for the task we use to keep the local database up to date.
/// When VS shuts down it will dispose us. We'll cancel the task at that point.
@@ -58,9 +56,6 @@ internal partial class SymbolSearchService
private readonly ConcurrentDictionary _sourceToUpdateSentinel =
new ConcurrentDictionary();
- private readonly DirectoryInfo _cacheDirectoryInfo;
- //private readonly FileInfo _databaseFileInfo;
-
// Interfaces that abstract out the external functionality we need. Used so we can easily
// mock behavior during tests.
private readonly IPackageInstallerService _installerService;
@@ -70,6 +65,7 @@ internal partial class SymbolSearchService
private readonly IRemoteControlService _remoteControlService;
private readonly IPatchService _patchService;
private readonly IDatabaseFactoryService _databaseFactoryService;
+ private readonly string _localSettingsDirectory;
private readonly Func _reportAndSwallowException;
public void Dispose()
@@ -125,23 +121,26 @@ internal Task UpdateSourceInBackgroundAsync(string source)
// We were the first ones to try to update this source. Spawn off a task to do
// the updating.
- return new Updater(this, source).UpdateInBackgroundAsync();
+ return new Updater(this, source, _localSettingsDirectory).UpdateInBackgroundAsync();
}
private class Updater
{
private readonly SymbolSearchService _service;
private readonly string _source;
+ private readonly DirectoryInfo _cacheDirectoryInfo;
private readonly FileInfo _databaseFileInfo;
- public Updater(SymbolSearchService service, string source)
+ public Updater(SymbolSearchService service, string source, string localSettingsDirectory)
{
_service = service;
_source = source;
- var fileName = ConvertToFileName(source);
+ _cacheDirectoryInfo = new DirectoryInfo(Path.Combine(
+ localSettingsDirectory, "PackageCache", string.Format(Invariant($"Format{AddReferenceDatabase.TextFileFormatVersion}"))));
+
_databaseFileInfo = new FileInfo(
- Path.Combine(_service._cacheDirectoryInfo.FullName, fileName + ".txt"));
+ Path.Combine(_cacheDirectoryInfo.FullName, ConvertToFileName(source) + ".txt"));
}
///
@@ -254,12 +253,12 @@ private void CleanCacheDirectory()
_service.LogInfo("Cleaning cache directory");
// (intentionally not wrapped in IOUtilities. If this throws we want to restart).
- if (!_service._ioService.Exists(_service._cacheDirectoryInfo))
+ if (!_service._ioService.Exists(_cacheDirectoryInfo))
{
_service.LogInfo("Creating cache directory");
// (intentionally not wrapped in IOUtilities. If this throws we want to restart).
- _service._ioService.Create(_service._cacheDirectoryInfo);
+ _service._ioService.Create(_cacheDirectoryInfo);
_service.LogInfo("Cache directory created");
}
@@ -268,7 +267,7 @@ private void CleanCacheDirectory()
private async Task DownloadFullDatabaseAsync()
{
- var serverPath = Invariant($"Elfie_V{_service._dataFormatVersion}/Latest.xml");
+ var serverPath = Invariant($"Elfie_V{AddReferenceDatabase.TextFileFormatVersion}/Latest.xml");
_service.LogInfo($"Downloading and processing full database: {serverPath}");
@@ -332,7 +331,7 @@ private async Task WriteDatabaseFile(byte[] bytes)
() =>
{
var guidString = Guid.NewGuid().ToString();
- var tempFilePath = Path.Combine(_service._cacheDirectoryInfo.FullName, guidString + ".tmp");
+ var tempFilePath = Path.Combine(_cacheDirectoryInfo.FullName, guidString + ".tmp");
_service.LogInfo($"Temp file path: {tempFilePath}");
@@ -402,7 +401,7 @@ private async Task PatchLocalDatabaseAsync()
var databaseVersion = database.DatabaseVersion;
// Now attempt to download and apply patch file.
- var serverPath = Invariant($"Elfie_V{_service._dataFormatVersion}/{database.DatabaseVersion}_Patch.xml");
+ var serverPath = Invariant($"Elfie_V{AddReferenceDatabase.TextFileFormatVersion}/{database.DatabaseVersion}_Patch.xml");
_service.LogInfo("Downloading and processing patch file: " + serverPath);
@@ -424,7 +423,7 @@ private async Task PatchLocalDatabaseAsync()
private AddReferenceDatabase CreateAndSetInMemoryDatabase(byte[] bytes)
{
var database = CreateDatabaseFromBytes(bytes);
- _service._sourceToDatabase[_source] = database;
+ _service._sourceToDatabase[_source] = new AddReferenceDatabaseWrapper(database);
return database;
}
diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs
index f2a30c81729e6..1da89cb57f852 100644
--- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs
+++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs
@@ -36,7 +36,8 @@ internal partial class SymbolSearchService :
ISymbolSearchService,
IDisposable
{
- private ConcurrentDictionary _sourceToDatabase = new ConcurrentDictionary();
+ private ConcurrentDictionary _sourceToDatabase =
+ new ConcurrentDictionary();
public SymbolSearchService(
VSShell.SVsServiceProvider serviceProvider,
@@ -104,12 +105,9 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi
_remoteControlService = remoteControlService;
_patchService = patchService;
_databaseFactoryService = databaseFactoryService;
+ _localSettingsDirectory = localSettingsDirectory;
_reportAndSwallowException = reportAndSwallowException;
- _cacheDirectoryInfo = new DirectoryInfo(Path.Combine(
- localSettingsDirectory, "PackageCache", string.Format(Invariant($"Format{_dataFormatVersion}"))));
- // _databaseFileInfo = new FileInfo(Path.Combine(_cacheDirectoryInfo.FullName, "NuGetCache.txt"));
-
_cancellationTokenSource = cancellationTokenSource;
_cancellationToken = _cancellationTokenSource.Token;
}
@@ -117,13 +115,14 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi
public IEnumerable FindPackagesWithType(
string source, string name, int arity, CancellationToken cancellationToken)
{
- AddReferenceDatabase database;
- if (!_sourceToDatabase.TryGetValue(source, out database))
+ IAddReferenceDatabaseWrapper databaseWrapper;
+ if (!_sourceToDatabase.TryGetValue(source, out databaseWrapper))
{
// Don't have a database to search.
yield break;
}
+ var database = databaseWrapper.Database;
if (name == "var")
{
// never find anything named 'var'.
@@ -190,13 +189,14 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi
string name, int arity, CancellationToken cancellationToken)
{
// Our reference assembly data is stored in the nuget.org DB.
- AddReferenceDatabase database;
- if (!_sourceToDatabase.TryGetValue(NugetOrgSource, out database))
+ IAddReferenceDatabaseWrapper databaseWrapper;
+ if (!_sourceToDatabase.TryGetValue(NugetOrgSource, out databaseWrapper))
{
// Don't have a database to search.
yield break;
}
+ var database = databaseWrapper.Database;
if (name == "var")
{
// never find anything named 'var'.
diff --git a/src/VisualStudio/Core/Def/project.json b/src/VisualStudio/Core/Def/project.json
index 27cf21c74e555..f95e0ad699efd 100644
--- a/src/VisualStudio/Core/Def/project.json
+++ b/src/VisualStudio/Core/Def/project.json
@@ -2,6 +2,9 @@
"dependencies": {
"ManagedEsent": "1.9.2.0",
"Microsoft.CodeAnalysis.Elfie": "0.10.6-rc2",
+ "RoslynDependencies.Microsoft.VisualStudio.Progression": "14.2.25123",
+ "RoslynDependencies.Microsoft.VisualStudio.GraphModel": "14.2.25123",
+ "RoslynDependencies.Microsoft.VisualStudio.CallHierarchy.Package.Definitions": "14.0.23107",
"NuGet.VisualStudio": {
"version": "3.3.0",
"suppressParent": "all"
diff --git a/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb b/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb
index 0c926bbc2f848..c4c9d3d78b8be 100644
--- a/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb
+++ b/src/VisualStudio/Core/Test/AnalyzerSupport/AnalyzerDependencyCheckerTests.vb
@@ -9,6 +9,8 @@ Imports Microsoft.VisualStudio.LanguageServices.Implementation
Imports Microsoft.Win32
Imports Roslyn.Test.Utilities
+Imports System.FormattableString
+
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests
Public Class AnalyzerDependencyCheckerTests
Inherits TestBase
@@ -17,7 +19,8 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests
Private Shared ReadOnly Property MSBuildDirectory As String
Get
If s_msbuildDirectory Is Nothing Then
- Dim key = Registry.LocalMachine.OpenSubKey("SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0", False)
+ Dim vsVersion = If(Environment.GetEnvironmentVariable("VisualStudioVersion"), "14.0")
+ Dim key = Registry.LocalMachine.OpenSubKey(Invariant($"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{vsVersion}"), False)
If key IsNot Nothing Then
Dim toolsPath = key.GetValue("MSBuildToolsPath")
diff --git a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
index f86f3652ef6e7..4b986efd92773 100644
--- a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
+++ b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj
@@ -13,7 +13,13 @@
AnyCPU
v4.6
+ true
+
+
+ $(VisualStudioReferenceAssemblyVersion)
+
+
{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}
@@ -125,13 +131,6 @@
false
-
-
-
-
-
- false
-
@@ -143,16 +142,6 @@
-
-
-
-
- false
-
-
-
@@ -402,4 +391,4 @@
-
\ No newline at end of file
+
diff --git a/src/VisualStudio/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs b/src/VisualStudio/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs
new file mode 100644
index 0000000000000..8115e68393410
--- /dev/null
+++ b/src/VisualStudio/IntegrationTests/CSharp/CSharpAutomaticBraceCompletion.cs
@@ -0,0 +1,208 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Threading.Tasks;
+using Roslyn.Test.Utilities;
+using Roslyn.VisualStudio.IntegrationTests;
+using Roslyn.VisualStudio.Test.Utilities;
+using Xunit;
+
+namespace Roslyn.VisualStudio.CSharp.IntegrationTests
+{
+ [Collection(nameof(SharedIntegrationHostFixture))]
+ public class CSharpAutomaticBraceCompletion : IDisposable
+ {
+ private readonly VisualStudioInstanceContext _visualStudio;
+ private readonly Workspace _workspace;
+ private readonly Solution _solution;
+ private readonly Project _project;
+ private readonly EditorWindow _editorWindow;
+
+ public CSharpAutomaticBraceCompletion(VisualStudioInstanceFactory instanceFactory)
+ {
+ _visualStudio = instanceFactory.GetNewOrUsedInstance();
+
+ _solution = _visualStudio.Instance.SolutionExplorer.CreateSolution(nameof(CSharpAutomaticBraceCompletion));
+ _project = _solution.AddProject("TestProj", ProjectTemplate.ClassLibrary, ProjectLanguage.CSharp);
+
+ _workspace = _visualStudio.Instance.Workspace;
+ _workspace.UseSuggestionMode = false;
+
+ _editorWindow = _visualStudio.Instance.EditorWindow;
+ }
+
+ public void Dispose()
+ {
+ _visualStudio.Dispose();
+ }
+
+ [Fact]
+ public async Task BracesInsertionAndTabCompleting()
+ {
+ _editorWindow.Text = @"class C {
+ void Foo() {
+ // Marker
+ }
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("if (true) {");
+
+ Assert.Equal(" if (true) { ", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal("}", _editorWindow.CurrentLineTextAfterCursor);
+
+ await _editorWindow.TypeTextAsync($"{EditorWindow.TAB}");
+
+ Assert.Equal(" if (true) { }", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task BracesOvertyping()
+ {
+ _editorWindow.Text = @"class C {
+ void Foo() {
+ // Marker
+ }
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("if (true) {");
+ await _editorWindow.TypeTextAsync("}");
+
+ Assert.Equal(" if (true) { }", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task BracesOnReturnNoFormattingOnlyIndentationBeforeCloseBrace()
+ {
+ _editorWindow.Text = @"class C {
+ void Foo() {
+ // Marker
+ }
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("if (true) {");
+ await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}");
+ await _editorWindow.TypeTextAsync("var a = 1;");
+
+ Assert.Equal(" var a = 1;", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task BracesOnReturnOvertypingTheClosingBrace()
+ {
+ _editorWindow.Text = @"class C {
+ void Foo() {
+ // Marker
+ }
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("if (true) {");
+ await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}");
+ await _editorWindow.TypeTextAsync("var a = 1;}");
+
+ Assert.Equal(" }", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+
+ Assert.Contains(@"if (true)
+ {
+ var a = 1;
+ }
+", _editorWindow.Text);
+ }
+
+ [Fact]
+ [WorkItem(653540, "DevDiv")]
+ public async Task BracesOnReturnWithNonWhitespaceSpanInside()
+ {
+ _editorWindow.Text = string.Empty;
+
+ await _editorWindow.TypeTextAsync("class A { int i;");
+ await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}");
+
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal("}", _editorWindow.CurrentLineTextAfterCursor);
+
+ Assert.Contains(@"class A { int i;
+}", _editorWindow.Text);
+ }
+
+ [Fact]
+ public async Task ParenInsertionAndTabCompleting()
+ {
+ _editorWindow.Text = @"class C {
+ //Marker
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("void Foo(");
+
+ Assert.Equal(" void Foo(", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(")", _editorWindow.CurrentLineTextAfterCursor);
+
+ await _editorWindow.TypeTextAsync("int x");
+ await _editorWindow.TypeTextAsync($"{EditorWindow.TAB}");
+
+ Assert.Equal(" void Foo(int x)", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task ParenOvertyping()
+ {
+ _editorWindow.Text = @"class C {
+ //Marker
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("void Foo(");
+ await _editorWindow.TypeTextAsync($"{EditorWindow.ESC}");
+ await _editorWindow.TypeTextAsync(")");
+
+ Assert.Equal(" void Foo()", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(")", _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task SquareBracketInsertion()
+ {
+ _editorWindow.Text = @"class C {
+ //Marker
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("int [");
+
+ Assert.Equal(" int [", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal("]", _editorWindow.CurrentLineTextAfterCursor);
+ }
+
+ [Fact]
+ public async Task SquareBracketOvertyping()
+ {
+ _editorWindow.Text = @"class C {
+ //Marker
+}";
+
+ _editorWindow.PlaceCursor("// Marker");
+
+ await _editorWindow.TypeTextAsync("int [");
+ await _editorWindow.TypeTextAsync("]");
+
+ Assert.Equal(" int []", _editorWindow.CurrentLineTextBeforeCursor);
+ Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor);
+ }
+ }
+}
diff --git a/src/VisualStudio/IntegrationTests/CSharp/CSharpBuild.cs b/src/VisualStudio/IntegrationTests/CSharp/CSharpBuild.cs
index e18fb34a13cd1..d58125542997c 100644
--- a/src/VisualStudio/IntegrationTests/CSharp/CSharpBuild.cs
+++ b/src/VisualStudio/IntegrationTests/CSharp/CSharpBuild.cs
@@ -1,10 +1,11 @@
// 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 Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;
-namespace Roslyn.VisualStudio.Integration.UnitTests
+namespace Roslyn.VisualStudio.CSharp.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpBuild : IDisposable
diff --git a/src/VisualStudio/IntegrationTests/CSharp/CSharpInteractiveDemo.cs b/src/VisualStudio/IntegrationTests/CSharp/CSharpInteractiveDemo.cs
index b3e8156d916cf..6cbe3a359123e 100644
--- a/src/VisualStudio/IntegrationTests/CSharp/CSharpInteractiveDemo.cs
+++ b/src/VisualStudio/IntegrationTests/CSharp/CSharpInteractiveDemo.cs
@@ -2,10 +2,11 @@
using System;
using System.Threading.Tasks;
+using Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;
-namespace Roslyn.VisualStudio.Integration.UnitTests
+namespace Roslyn.VisualStudio.CSharp.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpInteractiveDemo : IDisposable
diff --git a/src/VisualStudio/IntegrationTests/SharedIntegrationHostFixture.cs b/src/VisualStudio/IntegrationTests/SharedIntegrationHostFixture.cs
index 6df83be155393..0a59dcdcd6106 100644
--- a/src/VisualStudio/IntegrationTests/SharedIntegrationHostFixture.cs
+++ b/src/VisualStudio/IntegrationTests/SharedIntegrationHostFixture.cs
@@ -3,7 +3,7 @@
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;
-namespace Roslyn.VisualStudio.Integration.UnitTests
+namespace Roslyn.VisualStudio.IntegrationTests
{
[CollectionDefinition(nameof(SharedIntegrationHostFixture))]
public sealed class SharedIntegrationHostFixture : ICollectionFixture
diff --git a/src/VisualStudio/IntegrationTests/VisualBasic/BasicBuild.cs b/src/VisualStudio/IntegrationTests/VisualBasic/BasicBuild.cs
index 5620f807cad14..66f6fc2662a4a 100644
--- a/src/VisualStudio/IntegrationTests/VisualBasic/BasicBuild.cs
+++ b/src/VisualStudio/IntegrationTests/VisualBasic/BasicBuild.cs
@@ -1,9 +1,10 @@
// 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 Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;
-namespace Roslyn.VisualStudio.Integration.UnitTests
+namespace Roslyn.VisualStudio.Basic.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class BasicBuild
diff --git a/src/VisualStudio/IntegrationTests/VisualStudioIntegrationTests.csproj b/src/VisualStudio/IntegrationTests/VisualStudioIntegrationTests.csproj
index 94d50c204fb85..5999dfafbaefb 100644
--- a/src/VisualStudio/IntegrationTests/VisualStudioIntegrationTests.csproj
+++ b/src/VisualStudio/IntegrationTests/VisualStudioIntegrationTests.csproj
@@ -15,6 +15,7 @@
+
@@ -31,6 +32,10 @@
{8635cb8f-d210-41ed-b4ff-71502cdb475c}
xUnit.net
+
+ {76c6f005-c89d-4348-bb4a-391898dbeb52}
+ TestUtilities.Desktop
+
{3BED15FD-D608-4573-B432-1569C1026F6D}
VisualStudioTestUtilities
diff --git a/src/VisualStudio/Setup.Next/AssemblyRedirects.cs b/src/VisualStudio/Setup.Next/AssemblyRedirects.cs
new file mode 100644
index 0000000000000..f25c23bffe5c6
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/AssemblyRedirects.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.Shell;
+using Roslyn.VisualStudio.Setup;
+
+[assembly: ProvideRoslynBindingRedirection("Microsoft.CodeAnalysis.EditorFeatures.Next.dll")]
+[assembly: ProvideBindingRedirection(
+ AssemblyName = "Microsoft.VisualStudio.CallHierarchy.Package.Definitions",
+ GenerateCodeBase = false,
+ PublicKeyToken = "31BF3856AD364E35",
+ OldVersionLowerBound = "14.0.0.0",
+ OldVersionUpperBound = "14.9.9.9",
+ NewVersion = "15.0.0.0")]
\ No newline at end of file
diff --git a/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj b/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj
new file mode 100644
index 0000000000000..db8a237254fc3
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/VisualStudioSetup.Next.csproj
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+ Debug
+ AnyCPU
+ {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ {143FE684-6E1C-41DF-9C60-84C7772DC49C}
+ Library
+ Roslyn.VisualStudio.Setup.Next
+ Roslyn.VisualStudio.Setup.Next
+ true
+ true
+ RoslynDev
+ false
+ false
+ false
+ $(VisualStudioVersion)
+ true
+ v4.6
+ true
+
+
+
+ {8da861d8-0cce-4334-b6c0-01a846c881ec}
+ VisualStudio
+ False
+
+
+ {366BBCDC-B05F-4677-9B5B-78BA816A1484}
+ EditorFeatures.Next
+ BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup%3b
+ DebugSymbolsProjectOutputGroup%3b
+
+
+ VisualStudioSetup
+ false
+
+
+
+ AnyCPU
+
+
+ AnyCPU
+
+
+ Program
+ $(DevEnvDir)devenv.exe
+ /rootsuffix RoslynDev /log
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+ ProvideRoslynBindingRedirection.cs
+
+
+
+
+
+
+
diff --git a/src/VisualStudio/Setup.Next/project.json b/src/VisualStudio/Setup.Next/project.json
new file mode 100644
index 0000000000000..0b16291820b67
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/project.json
@@ -0,0 +1,10 @@
+{
+ "dependencies": {
+ },
+ "frameworks": {
+ "net46": { }
+ },
+ "runtimes": {
+ "win7": { }
+ }
+}
diff --git a/src/VisualStudio/Setup.Next/source.extension.vsixmanifest b/src/VisualStudio/Setup.Next/source.extension.vsixmanifest
new file mode 100644
index 0000000000000..02a77efbd27d3
--- /dev/null
+++ b/src/VisualStudio/Setup.Next/source.extension.vsixmanifest
@@ -0,0 +1,21 @@
+
+
+
+
+ Roslyn Language Services for Visual Studio 15
+ C# and VB.NET language services for Visual Studio 15.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VisualStudio/Setup/VisualStudioSetup.csproj b/src/VisualStudio/Setup/VisualStudioSetup.csproj
index 04de9e3669042..8b0f1b02d782b 100644
--- a/src/VisualStudio/Setup/VisualStudioSetup.csproj
+++ b/src/VisualStudio/Setup/VisualStudioSetup.csproj
@@ -138,9 +138,6 @@
true
-
-
-
@@ -183,4 +180,4 @@
-
\ No newline at end of file
+
diff --git a/src/VisualStudio/TestUtilities/Extensions/DteExtensions.cs b/src/VisualStudio/TestUtilities/Extensions/DteExtensions.cs
new file mode 100644
index 0000000000000..45264ceb05ef1
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Extensions/DteExtensions.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Threading.Tasks;
+using EnvDTE;
+
+namespace Roslyn.VisualStudio.Test.Utilities
+{
+ public static class DteExtensions
+ {
+ public static async Task ExecuteCommandAsync(this DTE dte, string command, string args = "")
+ {
+ // args is "" the default because it is the default value used by Dte.ExecuteCommand and changing our default
+ // to something more logical, like null, would change the expected behavior of Dte.ExecuteCommand
+
+ await dte.WaitForCommandAvailabilityAsync(command).ConfigureAwait(continueOnCapturedContext: false);
+ IntegrationHelper.RetryRpcCall(() => dte.ExecuteCommand(command, args));
+ }
+
+ public static Window LocateWindow(this DTE dte, string windowTitle)
+ {
+ var dteWindows = IntegrationHelper.RetryRpcCall(() => dte.Windows);
+
+ foreach (Window window in dteWindows)
+ {
+ var windowCaption = IntegrationHelper.RetryRpcCall(() => window.Caption);
+
+ if (windowCaption.Equals(windowTitle))
+ {
+ return window;
+ }
+ }
+ return null;
+ }
+
+ public static Task WaitForCommandAvailabilityAsync(this DTE dte, string command)
+ => IntegrationHelper.WaitForResultAsync(() => IntegrationHelper.RetryRpcCall(() => dte.Commands.Item(command).IsAvailable), expectedResult: true);
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/Extensions/IntegrationServiceExtensions.cs b/src/VisualStudio/TestUtilities/Extensions/IntegrationServiceExtensions.cs
new file mode 100644
index 0000000000000..a0a0d56e88c68
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Extensions/IntegrationServiceExtensions.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Reflection;
+
+namespace Roslyn.VisualStudio.Test.Utilities
+{
+ internal static class IntegrationServiceExtensions
+ {
+ public static void Execute(this IntegrationService integrationService, Type type, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters)
+ => Execute(integrationService, type.Assembly.Location, type.FullName, methodName, bindingFlags, parameters);
+
+ public static T Execute(this IntegrationService integrationService, Type type, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters)
+ => Execute(integrationService, type.Assembly.Location, type.FullName, methodName, bindingFlags, parameters);
+
+ public static void Execute(this IntegrationService integrationService, string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters)
+ {
+ var result = integrationService.Execute(assemblyFilePath, typeFullName, methodName, bindingFlags, parameters);
+
+ if (result != null)
+ {
+ throw new InvalidOperationException("The specified call was not expected to return a value.");
+ }
+ }
+
+ public static T Execute(this IntegrationService integrationService, string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters)
+ {
+ var objectUri = integrationService.Execute(assemblyFilePath, typeFullName, methodName, bindingFlags, parameters);
+
+ if (objectUri == null)
+ {
+ throw new InvalidOperationException("The specified call was expected to return a value.");
+ }
+
+ return (T)(Activator.GetObject(typeof(T), $"{integrationService.Uri}/{objectUri}"));
+ }
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/IntegrationHelper.cs b/src/VisualStudio/TestUtilities/IntegrationHelper.cs
index 16d6df0e5b59c..95ee98862f1e2 100644
--- a/src/VisualStudio/TestUtilities/IntegrationHelper.cs
+++ b/src/VisualStudio/TestUtilities/IntegrationHelper.cs
@@ -23,6 +23,40 @@ namespace Roslyn.VisualStudio.Test.Utilities
/// Provides some helper functions used by the other classes in the project.
internal static class IntegrationHelper
{
+ public static bool AttachThreadInput(uint idAttach, uint idAttachTo)
+ {
+ var success = User32.AttachThreadInput(idAttach, idAttachTo, true);
+
+ if (!success)
+ {
+ var hresult = Marshal.GetHRForLastWin32Error();
+ Marshal.ThrowExceptionForHR(hresult);
+ }
+
+ return success;
+ }
+
+ public static bool BlockInput()
+ {
+ var success = User32.BlockInput(true);
+
+ if (!success)
+ {
+ var hresult = Marshal.GetHRForLastWin32Error();
+
+ if (hresult == VSConstants.E_ACCESSDENIED)
+ {
+ Debug.WriteLine("Input cannot be blocked because the system requires Administrative privileges.");
+ }
+ else
+ {
+ Debug.WriteLine("Input cannot be blocked because another thread has blocked the input.");
+ }
+ }
+
+ return success;
+ }
+
public static void CreateDirectory(string path, bool deleteExisting = false)
{
if (deleteExisting)
@@ -41,6 +75,19 @@ public static void DeleteDirectoryRecursively(string path)
}
}
+ public static bool DetachThreadInput(uint idAttach, uint idAttachTo)
+ {
+ var success = User32.AttachThreadInput(idAttach, idAttachTo, false);
+
+ if (!success)
+ {
+ var hresult = Marshal.GetHRForLastWin32Error();
+ Marshal.ThrowExceptionForHR(hresult);
+ }
+
+ return success;
+ }
+
public static async Task DownloadFileAsync(string downloadUrl, string fileName)
{
using (var webClient = new WebClient())
@@ -49,12 +96,33 @@ public static async Task DownloadFileAsync(string downloadUrl, string fileName)
}
}
+ public static IntPtr GetForegroundWindow()
+ {
+ // Attempt to get the foreground window in a loop, as the User32 function can return IntPtr.Zero
+ // in certain circumstances, such as when a window is losing activation.
+
+ var foregroundWindow = IntPtr.Zero;
+
+ do
+ {
+ foregroundWindow = User32.GetForegroundWindow();
+ }
+ while (foregroundWindow == IntPtr.Zero);
+
+ return foregroundWindow;
+ }
+
/// Gets the Modal Window that is currently blocking interaction with the specified window or if none exists.
public static IntPtr GetModalWindowFromParentWindow(IntPtr parentWindow)
{
foreach (var topLevelWindow in GetTopLevelWindows())
{
- // Windows has several concepts of 'Parent Window', make sure we cover all ones for 'Modal Dialogs'
+ // GetParent will return the parent or owner of the specified window, unless:
+ // * The window is a top-level window that is unowned
+ // * The window is a top-level does not have the WS_POPUP style
+ // * The owner window has the WS_POPUP style
+ // GetWindow with GW_OWNER specified will return the owner window, but not the parent window
+ // GetAncestor with GA_PARENT specified will return the parent window, but not the owner window
if ((User32.GetParent(topLevelWindow) == parentWindow) ||
(User32.GetWindow(topLevelWindow, User32.GW_OWNER) == parentWindow) ||
(User32.GetAncestor(topLevelWindow, User32.GA_PARENT) == parentWindow))
@@ -66,6 +134,19 @@ public static IntPtr GetModalWindowFromParentWindow(IntPtr parentWindow)
return IntPtr.Zero;
}
+ public static object GetRegistryKeyValue(RegistryKey baseKey, string subKeyName, string valueName)
+ {
+ using (var registryKey = baseKey.OpenSubKey(subKeyName))
+ {
+ if (registryKey == null)
+ {
+ throw new Exception($@"The specified registry key could not be found. Registry Key: '{baseKey}\{subKeyName}'");
+ }
+
+ return registryKey.GetValue(valueName);
+ }
+ }
+
/// Gets the title text for the specified window.
/// GetWindowText() does not work across the process boundary.
public static string GetTitleForWindow(IntPtr window)
@@ -91,7 +172,14 @@ public static IEnumerable GetTopLevelWindows()
topLevelWindows.Add(hWnd);
return true;
});
- User32.EnumWindows(enumFunc, IntPtr.Zero);
+
+ var success = User32.EnumWindows(enumFunc, IntPtr.Zero);
+
+ if (!success)
+ {
+ var hresult = Marshal.GetHRForLastWin32Error();
+ Marshal.ThrowExceptionForHR(hresult);
+ }
return topLevelWindows;
}
@@ -114,6 +202,108 @@ public static void KillProcess(string processName)
}
}
+ public static void RetryRpcCall(Action action)
+ {
+ do
+ {
+ try
+ {
+ action();
+ return;
+ }
+ catch (COMException exception) when ((exception.HResult == VSConstants.RPC_E_CALL_REJECTED) ||
+ (exception.HResult == VSConstants.RPC_E_SERVERCALL_RETRYLATER))
+ {
+ // We'll just try again in this case
+ }
+ }
+ while (true);
+ }
+
+ public static T RetryRpcCall(Func action)
+ {
+ T returnValue = default(T);
+ RetryRpcCall(() => {
+ returnValue = action();
+ });
+ return returnValue;
+ }
+
+ public static void SetForegroundWindow(IntPtr window)
+ {
+ var foregroundWindow = GetForegroundWindow();
+
+ if (window == foregroundWindow)
+ {
+ return;
+ }
+
+ var activeThreadId = User32.GetWindowThreadProcessId(foregroundWindow, IntPtr.Zero);
+ var currentThreadId = Kernel32.GetCurrentThreadId();
+
+ bool threadInputsAttached = false;
+
+ try
+ {
+ // Attach the thread inputs so that 'SetActiveWindow' and 'SetFocus' work
+ threadInputsAttached = AttachThreadInput(currentThreadId, activeThreadId);
+
+ // Make the window a top-most window so it will appear above any existing top-most windows
+ User32.SetWindowPos(window, (IntPtr)(User32.HWND_TOPMOST), 0, 0, 0, 0, (User32.SWP_NOSIZE | User32.SWP_NOMOVE));
+
+ // Move the window into the foreground as it may not have been achieved by the 'SetWindowPos' call
+ var success = User32.SetForegroundWindow(window);
+
+ if (!success)
+ {
+ throw new InvalidOperationException("Setting the foreground window failed.");
+ }
+
+ // Ensure the window is 'Active' as it may not have been achieved by 'SetForegroundWindow'
+ User32.SetActiveWindow(window);
+
+ // Give the window the keyboard focus as it may not have been achieved by 'SetActiveWindow'
+ User32.SetFocus(window);
+
+ // Remove the 'Top-Most' qualification from the window
+ User32.SetWindowPos(window, (IntPtr)(User32.HWND_NOTOPMOST), 0, 0, 0, 0, (User32.SWP_NOSIZE | User32.SWP_NOMOVE));
+ }
+ finally
+ {
+ if (threadInputsAttached)
+ {
+ // Finally, detach the thread inputs from eachother
+ DetachThreadInput(currentThreadId, activeThreadId);
+ }
+ }
+ }
+
+ public static void SendInput(User32.INPUT[] input)
+ {
+ var eventsInserted = User32.SendInput((uint)(input.Length), input, User32.SizeOf_INPUT);
+
+ if (eventsInserted == 0)
+ {
+ var hresult = Marshal.GetHRForLastWin32Error();
+ throw new ExternalException("Sending input failed because input was blocked by another thread.", hresult);
+ }
+ }
+
+ public static bool TryDeleteDirectoryRecursively(string path)
+ {
+ try
+ {
+ DeleteDirectoryRecursively(path);
+ return true;
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine($"Warning: Failed to recursively delete the specified directory. (Name: '{path}')");
+ Debug.WriteLine($"\t{e}");
+ return false;
+ }
+ }
+
/// Locates the DTE object for the specified process.
public static DTE TryLocateDteForProcess(Process process)
{
@@ -172,31 +362,14 @@ public static DTE TryLocateDteForProcess(Process process)
return (DTE)(dte);
}
- public static object GetRegistryKeyValue(RegistryKey baseKey, string subKeyName, string valueName)
+ public static void UnblockInput()
{
- using (var registryKey = baseKey.OpenSubKey(subKeyName))
- {
- if (registryKey == null)
- {
- throw new Exception($"The specified registry key could not be found. Registry Key: '{registryKey}'");
- }
-
- return registryKey.GetValue(valueName);
- }
- }
+ var success = User32.BlockInput(false);
- public static bool TryDeleteDirectoryRecursively(string path)
- {
- try
+ if (!success)
{
- DeleteDirectoryRecursively(path);
- return true;
- }
- catch (Exception e)
- {
- Debug.WriteLine($"Warning: Failed to recursively delete the specified directory. (Name: '{path}')");
- Debug.WriteLine($"\t{e}");
- return false;
+ var hresult = Marshal.GetHRForLastWin32Error();
+ throw new ExternalException("Input cannot be unblocked because it was blocked by another thread.", hresult);
}
}
@@ -208,29 +381,6 @@ public static async Task WaitForResultAsync(Func action, T expectedResult)
}
}
- public static void RetryDteCall(Action action)
- {
- while (true)
- {
- try
- {
- action();
- return;
- }
- catch (COMException exception) when (exception.HResult == VSConstants.RPC_E_CALL_REJECTED)
- {
- // We'll just try again in this case
- }
- }
- }
-
- public static T RetryDteCall(Func action)
- {
- T returnValue = default(T);
- RetryDteCall(() => { returnValue = action(); });
- return returnValue;
- }
-
public static async Task WaitForNotNullAsync(Func action) where T : class
{
var result = action();
diff --git a/src/VisualStudio/TestUtilities/IntegrationService.cs b/src/VisualStudio/TestUtilities/IntegrationService.cs
index 86a7f13a0fd87..9d4b222203aab 100644
--- a/src/VisualStudio/TestUtilities/IntegrationService.cs
+++ b/src/VisualStudio/TestUtilities/IntegrationService.cs
@@ -14,7 +14,7 @@ internal class IntegrationService : MarshalByRefObject
// Make the channel name well known by using a static base and appending the process ID of the host
public static readonly string PortNameFormatString = $"{nameof(IntegrationService)}_{{0}}";
- private ConcurrentDictionary _marshalledObjects = new ConcurrentDictionary();
+ private readonly ConcurrentDictionary _marshalledObjects = new ConcurrentDictionary();
public string Execute(string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags, params object[] parameters)
{
@@ -41,5 +41,9 @@ public string Execute(string assemblyFilePath, string typeFullName, string metho
return objectUri;
}
+
+ /// The base Uri of the service.
+ /// This resolves to a string such as ipc://IntegrationService_{HostProcessId}"
+ public string Uri { get; set; }
}
}
diff --git a/src/VisualStudio/TestUtilities/Interop/Kernel32.cs b/src/VisualStudio/TestUtilities/Interop/Kernel32.cs
new file mode 100644
index 0000000000000..1d9d1a7e738a1
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Interop/Kernel32.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Runtime.InteropServices;
+
+namespace Roslyn.VisualStudio.Test.Utilities.Interop
+{
+ internal static class Kernel32
+ {
+ [DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "GetCurrentThreadId", PreserveSig = true, SetLastError = false)]
+ public static extern uint GetCurrentThreadId();
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/Interop/User32.cs b/src/VisualStudio/TestUtilities/Interop/User32.cs
index a744b6e2c8b0c..3fab7a12a3fcd 100644
--- a/src/VisualStudio/TestUtilities/Interop/User32.cs
+++ b/src/VisualStudio/TestUtilities/Interop/User32.cs
@@ -8,6 +8,8 @@ namespace Roslyn.VisualStudio.Test.Utilities.Interop
{
internal static class User32
{
+ public static readonly int SizeOf_INPUT = Marshal.SizeOf();
+
public const uint GA_PARENT = 1;
public const uint GA_ROOT = 2;
public const uint GA_ROOTOWNER = 3;
@@ -20,9 +22,101 @@ internal static class User32
public const uint GW_CHILD = 5;
public const uint GW_ENABLEDPOPUP = 6;
+ public const int HWND_NOTOPMOST = -2;
+ public const int HWND_TOPMOST = -1;
+ public const int HWND_TOP = 0;
+ public const int HWND_BOTTOM = 1;
+
+ public const uint INPUT_MOUSE = 0;
+ public const uint INPUT_KEYBOARD = 1;
+ public const uint INPUT_HARDWARE = 2;
+
+ public const uint KEYEVENTF_NONE = 0x0000;
+ public const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
+ public const uint KEYEVENTF_KEYUP = 0x0002;
+ public const uint KEYEVENTF_UNICODE = 0x0004;
+ public const uint KEYEVENTF_SCANCODE = 0x0008;
+
+ public const uint SWP_NOSIZE = 0x0001;
+ public const uint SWP_NOMOVE = 0x0002;
+ public const uint SWP_NOZORDER = 0x0004;
+ public const uint SWP_NOREDRAW = 0x008;
+ public const uint SWP_NOACTIVATE = 0x0010;
+ public const uint SWP_DRAWFRAME = 0x0020;
+ public const uint SWP_FRAMECHANGED = 0x0020;
+ public const uint SWP_SHOWWINDOW = 0x0040;
+ public const uint SWP_HIDEWINDOW = 0x0080;
+ public const uint SWP_NOCOPYBITS = 0x0100;
+ public const uint SWP_NOOWNERZORDER = 0x0200;
+ public const uint SWP_NOREPOSITION = 0x0200;
+ public const uint SWP_NOSENDCHANGING = 0x0400;
+ public const uint SWP_DEFERERASE = 0x2000;
+ public const uint SWP_ASYNCWINDOWPOS = 0x4000;
+
+ public const ushort VK_SHIFT = 0x0010;
+ public const ushort VK_CONTROL = 0x0011;
+ public const ushort VK_MENU = 0x0012;
+
+ public const ushort VK_PRIOR = 0x0021;
+ public const ushort VK_NEXT = 0x0022;
+ public const ushort VK_END = 0x0023;
+ public const ushort VK_HOME = 0x0024;
+ public const ushort VK_LEFT = 0x0025;
+ public const ushort VK_UP = 0x0026;
+ public const ushort VK_RIGHT = 0x0027;
+ public const ushort VK_DOWN = 0x0028;
+
+ public const ushort VK_INSERT = 0x002D;
+ public const ushort VK_DELETE = 0x002E;
+
public const uint WM_GETTEXT = 0x000D;
public const uint WM_GETTEXTLENGTH = 0x000E;
+ [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct INPUT
+ {
+ [FieldOffset(0)]
+ public uint Type;
+
+ [FieldOffset(4)]
+ public MOUSEINPUT mi;
+
+ [FieldOffset(4)]
+ public KEYBDINPUT ki;
+
+ [FieldOffset(4)]
+ public HARDWAREINPUT hi;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct HARDWAREINPUT
+ {
+ public uint uMsg;
+ public ushort wParamL;
+ public ushort wParamH;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct KEYBDINPUT
+ {
+ public ushort wVk;
+ public ushort wScan;
+ public uint dwFlags;
+ public uint time;
+ public IntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 8)]
+ public struct MOUSEINPUT
+ {
+ public int dx;
+ public int dy;
+ public uint mouseData;
+ public uint dwFlags;
+ public uint time;
+ public IntPtr dwExtraInfo;
+ }
+
[UnmanagedFunctionPointer(CallingConvention.Winapi, SetLastError = false)]
[return: MarshalAs(UnmanagedType.Bool)]
public delegate bool WNDENUMPROC(
@@ -30,10 +124,24 @@ internal static class User32
[In] IntPtr lParam
);
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "AttachThreadInput", PreserveSig = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool AttachThreadInput(
+ [In] uint idAttach,
+ [In] uint idAttachTo,
+ [In, MarshalAs(UnmanagedType.Bool)] bool fAttach
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "BlockInput", PreserveSig = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool BlockInput(
+ [In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt
+ );
+
[DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "EnumWindows", PreserveSig = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(
- [In] WNDENUMPROC lpEnumFunc,
+ [In, MarshalAs(UnmanagedType.FunctionPtr)] WNDENUMPROC lpEnumFunc,
[In] IntPtr lParam
);
@@ -43,6 +151,10 @@ internal static class User32
[In] uint gaFlags
);
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "GetForegroundWindow", PreserveSig = true, SetLastError = false)]
+ public static extern IntPtr GetForegroundWindow(
+ );
+
[DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "GetParent", PreserveSig = true, SetLastError = true)]
public static extern IntPtr GetParent(
[In] IntPtr hWnd
@@ -54,6 +166,25 @@ internal static class User32
[In] uint uCmd
);
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "GetWindowThreadProcessId", PreserveSig = true, SetLastError = false)]
+ public static extern uint GetWindowThreadProcessId(
+ [In] IntPtr hWnd,
+ [Out, Optional] IntPtr lpdwProcessId
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "GetWindowThreadProcessId", PreserveSig = true, SetLastError = false)]
+ public static extern uint GetWindowThreadProcessId(
+ [In] IntPtr hWnd,
+ [Out, Optional] out uint lpdwProcessId
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SendInput", PreserveSig = true, SetLastError = true)]
+ public static extern uint SendInput(
+ [In] uint nInputs,
+ [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] INPUT[] pInputs,
+ [In] int cbSize
+ );
+
[DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SendMessageW", PreserveSig = true, SetLastError = true)]
public static extern IntPtr SendMessage(
[In] IntPtr hWnd,
@@ -69,5 +200,38 @@ internal static class User32
[In] IntPtr wParam,
[Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam
);
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SetActiveWindow", PreserveSig = true, SetLastError = true)]
+ public static extern IntPtr SetActiveWindow(
+ [In] IntPtr hWnd
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SetFocus", PreserveSig = true, SetLastError = true)]
+ public static extern IntPtr SetFocus(
+ [In] IntPtr hWnd
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SetForegroundWindow", PreserveSig = true, SetLastError = false)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetForegroundWindow(
+ [In] IntPtr hWnd
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "SetWindowPos", PreserveSig = true, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ public static extern bool SetWindowPos(
+ [In] IntPtr hWnd,
+ [In, Optional] IntPtr hWndInsertAfter,
+ [In] int X,
+ [In] int Y,
+ [In] int cx,
+ [In] int cy,
+ [In] uint uFlags
+ );
+
+ [DllImport("User32.dll", CallingConvention = CallingConvention.Winapi, EntryPoint = "VkKeyScanW", PreserveSig = true, SetLastError = false)]
+ public static extern short VkKeyScan(
+ [In] char ch
+ );
}
}
diff --git a/src/VisualStudio/TestUtilities/Remoting/EditorWindowWrapper.cs b/src/VisualStudio/TestUtilities/Remoting/EditorWindowWrapper.cs
new file mode 100644
index 0000000000000..6bab91737ab1a
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Remoting/EditorWindowWrapper.cs
@@ -0,0 +1,28 @@
+// 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;
+
+namespace Roslyn.VisualStudio.Test.Utilities.Remoting
+{
+ internal class EditorWindowWrapper : MarshalByRefObject
+ {
+ public static EditorWindowWrapper Create() => new EditorWindowWrapper();
+
+ private EditorWindowWrapper()
+ {
+ }
+
+ public string Contents
+ {
+ get
+ {
+ return RemotingHelper.ActiveTextViewContents;
+ }
+
+ set
+ {
+ RemotingHelper.ActiveTextViewContents = value;
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/Remoting/InteractiveWindowWrapper.cs b/src/VisualStudio/TestUtilities/Remoting/InteractiveWindowWrapper.cs
index 5969a6b17a308..aa31c5789f163 100644
--- a/src/VisualStudio/TestUtilities/Remoting/InteractiveWindowWrapper.cs
+++ b/src/VisualStudio/TestUtilities/Remoting/InteractiveWindowWrapper.cs
@@ -9,9 +9,11 @@ namespace Roslyn.VisualStudio.Test.Utilities.Remoting
/// This object exists in the Visual Studio host and is marhsalled across the process boundary.
internal class InteractiveWindowWrapper : MarshalByRefObject
{
- private IInteractiveWindow _interactiveWindow;
+ private readonly IInteractiveWindow _interactiveWindow;
- public InteractiveWindowWrapper(IInteractiveWindow interactiveWindow)
+ public static InteractiveWindowWrapper CreateForCSharp() => new InteractiveWindowWrapper(RemotingHelper.CSharpInteractiveWindow);
+
+ private InteractiveWindowWrapper(IInteractiveWindow interactiveWindow)
{
_interactiveWindow = interactiveWindow;
}
diff --git a/src/VisualStudio/TestUtilities/Remoting/RemotingHelper.cs b/src/VisualStudio/TestUtilities/Remoting/RemotingHelper.cs
index caf3e22fcb1c7..b281efe756935 100644
--- a/src/VisualStudio/TestUtilities/Remoting/RemotingHelper.cs
+++ b/src/VisualStudio/TestUtilities/Remoting/RemotingHelper.cs
@@ -1,16 +1,28 @@
// 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.ObjectModel;
+using System.ComponentModel.Composition.Hosting;
+using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Threading;
-using Microsoft.VisualStudio;
+using EnvDTE;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Host;
+using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.ComponentModelHost;
+using Microsoft.VisualStudio.InteractiveWindow;
+using Microsoft.VisualStudio.InteractiveWindow.Shell;
+using Microsoft.VisualStudio.Language.Intellisense;
+using Microsoft.VisualStudio.LanguageServices;
using Microsoft.VisualStudio.LanguageServices.CSharp.Interactive;
using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.TextManager.Interop;
+using Roslyn.Hosting.Diagnostics.Waiters;
namespace Roslyn.VisualStudio.Test.Utilities.Remoting
{
@@ -18,69 +30,142 @@ namespace Roslyn.VisualStudio.Test.Utilities.Remoting
/// This methods should be executed Visual Studio host via the method.
internal static class RemotingHelper
{
- private static Guid IWpfTextViewId = new Guid("8C40265E-9FDB-4F54-A0FD-EBB72B7D0476");
+ private static readonly Guid IWpfTextViewId = new Guid("8C40265E-9FDB-4F54-A0FD-EBB72B7D0476");
+ private static readonly Guid RoslynPackageId = new Guid("6cf2e545-6109-4730-8883-cf43d7aec3e1");
- public static InteractiveWindowWrapper CreateCSharpInteractiveWindowWrapper()
- {
- var componentModel = (IComponentModel)(ServiceProvider.GlobalProvider.GetService(typeof(SComponentModel)));
- var vsInteractiveWindowProvider = componentModel.GetService();
- var vsInteractiveWindow = ExecuteOnUIThread(() => vsInteractiveWindowProvider.Open(0, true));
- return new InteractiveWindowWrapper(vsInteractiveWindow.InteractiveWindow);
- }
+ private static readonly string[] SupportedLanguages = new string[] { LanguageNames.CSharp, LanguageNames.VisualBasic };
- public static string GetActiveTextViewContents()
+ public static string ActiveTextViewContents
{
- var textViewHost = GetActiveTextViewHost();
- return ExecuteOnUIThread(textViewHost.TextView.TextSnapshot.GetText);
+ get
+ {
+ return InvokeOnUIThread(ActiveTextView.TextSnapshot.GetText);
+ }
+
+ set
+ {
+ InvokeOnUIThread(() => {
+ var textSnapshot = ActiveTextView.TextSnapshot;
+ var replacementSpan = new SnapshotSpan(textSnapshot, 0, textSnapshot.Length);
+ ActiveTextView.TextBuffer.Replace(replacementSpan, value);
+ });
+ }
}
- public static void SetActiveTextViewContents(string text)
+ public static ReadOnlyCollection ActiveTextViewCompletionSessions => CompletionBroker.GetSessions(ActiveTextView);
+
+ public static IComponentModel ComponentModel => GetGlobalService(typeof(SComponentModel));
+
+ public static IInteractiveWindow CSharpInteractiveWindow => CSharpVsInteractiveWindow.InteractiveWindow;
+
+ public static VisualStudioWorkspace VisualStudioWorkspace => ComponentModel.GetService();
+
+ private static ITextView ActiveTextView => ActiveTextViewHost.TextView;
+
+ private static IWpfTextViewHost ActiveTextViewHost
{
- var textViewHost = GetActiveTextViewHost();
- ExecuteOnUIThread(() => {
- var textView = textViewHost.TextView;
- var textSnapshot = textView.TextSnapshot;
- var replacementSpan = new SnapshotSpan(textSnapshot, 0, textSnapshot.Length);
- textView.TextBuffer.Replace(replacementSpan, text);
- });
+ get
+ {
+ // The active text view might not have finished composing yet, waiting for the application to 'idle'
+ // means that it is done pumping messages (including WM_PAINT) and the window should return the correct text view
+ WaitForApplicationIdle();
+
+ var activeVsTextView = (IVsUserData)(VsTextManagerActiveView);
+
+ var wpfTextViewId = IWpfTextViewId;
+ object wpfTextViewHost = null;
+
+ var hresult = activeVsTextView.GetData(ref wpfTextViewId, out wpfTextViewHost);
+ Marshal.ThrowExceptionForHR(hresult);
+
+ return (IWpfTextViewHost)(wpfTextViewHost);
+ }
}
- private static void ExecuteOnUIThread(Action action)
- => Application.Current.Dispatcher.Invoke(action);
+ private static ICompletionBroker CompletionBroker => ComponentModel.GetService();
+
+ private static IVsInteractiveWindow CSharpVsInteractiveWindow => InvokeOnUIThread(() => CSharpVsInteractiveWindowProvider.Open(0, true));
+
+ private static CSharpVsInteractiveWindowProvider CSharpVsInteractiveWindowProvider => ComponentModel.GetService();
+
+ private static Application CurrentApplication => Application.Current;
+
+ private static Dispatcher CurrentApplicationDispatcher => CurrentApplication.Dispatcher;
+
+ private static ExportProvider DefaultComponentModelExportProvider => ComponentModel.DefaultExportProvider;
- private static T ExecuteOnUIThread(Func action)
- => Application.Current.Dispatcher.Invoke(action);
+ public static DTE DTE => GetGlobalService(typeof(SDTE));
- private static IWpfTextViewHost GetActiveTextViewHost()
+ private static ServiceProvider GlobalServiceProvider => ServiceProvider.GlobalProvider;
+
+ private static HostWorkspaceServices VisualStudioWorkspaceServices => VisualStudioWorkspace.Services;
+
+ private static IVsShell VsShell => GetGlobalService(typeof(SVsShell));
+
+ private static IVsTextManager VsTextManager => GetGlobalService(typeof(SVsTextManager));
+
+ private static IVsTextView VsTextManagerActiveView
{
- // The active text view might not have finished composing yet, waiting for the application to 'idle'
- // means that it is done pumping messages (including WM_PAINT) and the window should have finished composing
- WaitForApplicationIdle();
+ get
+ {
+ IVsTextView vsTextView = null;
- var vsTextManager = (IVsTextManager)(ServiceProvider.GlobalProvider.GetService(typeof(SVsTextManager)));
+ var hresult = VsTextManager.GetActiveView(fMustHaveFocus: 1, pBuffer: null, ppView: out vsTextView);
+ Marshal.ThrowExceptionForHR(hresult);
- IVsTextView vsTextView = null;
- var hresult = vsTextManager.GetActiveView(fMustHaveFocus: 1, pBuffer: null, ppView: out vsTextView);
+ return vsTextView;
+ }
+ }
+
+ private static TestingOnly_WaitingService WaitingService => DefaultComponentModelExportProvider.GetExport().Value;
- if (hresult != VSConstants.S_OK)
+ public static void ActivateMainWindow() => InvokeOnUIThread(() =>
+ {
+ var activeVisualStudioWindow = (IntPtr)(IntegrationHelper.RetryRpcCall(() => DTE.ActiveWindow.HWnd));
+
+ if (activeVisualStudioWindow == IntPtr.Zero)
{
- throw Marshal.GetExceptionForHR(hresult);
+ activeVisualStudioWindow = (IntPtr)(IntegrationHelper.RetryRpcCall(() => DTE.MainWindow.HWnd));
}
- var vsUserData = (IVsUserData)(vsTextView);
+ IntegrationHelper.SetForegroundWindow(activeVisualStudioWindow);
+ });
- object wpfTextViewHost = null;
- vsUserData.GetData(ref IWpfTextViewId, out wpfTextViewHost);
+ public static void CleanupWaitingService()
+ {
+ var asynchronousOperationWaiterExports = DefaultComponentModelExportProvider.GetExports();
- if (hresult != VSConstants.S_OK)
+ if (!asynchronousOperationWaiterExports.Any())
{
- throw Marshal.GetExceptionForHR(hresult);
+ throw new InvalidOperationException("The test waiting service could not be located.");
}
- return (IWpfTextViewHost)(wpfTextViewHost);
+ WaitingService.EnableActiveTokenTracking(true);
}
- private static void WaitForApplicationIdle()
- => Application.Current.Dispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle);
+ public static void CleanupWorkspace()
+ {
+ LoadRoslynPackage();
+ VisualStudioWorkspace.TestHookPartialSolutionsDisabled = true;
+ }
+
+ public static void WaitForSystemIdle() => CurrentApplicationDispatcher.Invoke(() => { }, DispatcherPriority.SystemIdle);
+
+ public static void WaitForApplicationIdle() => CurrentApplicationDispatcher.Invoke(() => { }, DispatcherPriority.ApplicationIdle);
+
+ private static T GetGlobalService(Type serviceType) => InvokeOnUIThread(() => (T)(GlobalServiceProvider.GetService(serviceType)));
+
+ private static void InvokeOnUIThread(Action action) => CurrentApplicationDispatcher.Invoke(action);
+
+ private static T InvokeOnUIThread(Func action) => CurrentApplicationDispatcher.Invoke(action);
+
+ private static void LoadRoslynPackage()
+ {
+ var roslynPackageGuid = RoslynPackageId;
+ IVsPackage roslynPackage = null;
+
+ var hresult = VsShell.LoadPackage(ref roslynPackageGuid, out roslynPackage);
+ Marshal.ThrowExceptionForHR(hresult);
+ }
}
}
diff --git a/src/VisualStudio/TestUtilities/Remoting/WorkspaceWrapper.cs b/src/VisualStudio/TestUtilities/Remoting/WorkspaceWrapper.cs
new file mode 100644
index 0000000000000..6dc73393d1557
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Remoting/WorkspaceWrapper.cs
@@ -0,0 +1,55 @@
+// 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 Microsoft.CodeAnalysis.Editor.Options;
+using Microsoft.CodeAnalysis.Options;
+using Microsoft.VisualStudio.LanguageServices;
+
+namespace Roslyn.VisualStudio.Test.Utilities.Remoting
+{
+ internal class WorkspaceWrapper : MarshalByRefObject
+ {
+ private readonly VisualStudioWorkspace _workspace;
+
+ public static WorkspaceWrapper Create()
+ {
+ var visualStudioWorkspace = RemotingHelper.VisualStudioWorkspace;
+ return new WorkspaceWrapper(visualStudioWorkspace);
+ }
+
+ private WorkspaceWrapper(VisualStudioWorkspace workspace)
+ {
+ _workspace = workspace;
+ }
+
+ public bool UseSuggestionMode
+ {
+ get
+ {
+ return Options.GetOption(EditorCompletionOptions.UseSuggestionMode);
+ }
+
+ set
+ {
+ if (value != UseSuggestionMode)
+ {
+ RemotingHelper.DTE.ExecuteCommandAsync("Edit.ToggleCompletionMode").GetAwaiter().GetResult();
+ }
+ }
+ }
+
+ private OptionSet Options
+ {
+ get
+ {
+ return _workspace.Options;
+ }
+
+ set
+ {
+ _workspace.Options = value;
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/VisualStudioCommandNames.cs b/src/VisualStudio/TestUtilities/VisualStudioCommandNames.cs
index 235d77aaae247..3fc7f415963d8 100644
--- a/src/VisualStudio/TestUtilities/VisualStudioCommandNames.cs
+++ b/src/VisualStudio/TestUtilities/VisualStudioCommandNames.cs
@@ -1,11 +1,5 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
namespace Roslyn.VisualStudio.Test.Utilities
{
internal static class VisualStudioCommandNames
diff --git a/src/VisualStudio/TestUtilities/VisualStudioInstance.cs b/src/VisualStudio/TestUtilities/VisualStudioInstance.cs
index c1c019ddc8a32..e7570d1eb8d43 100644
--- a/src/VisualStudio/TestUtilities/VisualStudioInstance.cs
+++ b/src/VisualStudio/TestUtilities/VisualStudioInstance.cs
@@ -2,15 +2,13 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
-using System.Reflection;
-using System.Runtime.InteropServices;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Threading.Tasks;
using System.Windows.Automation;
using EnvDTE;
+using Roslyn.VisualStudio.Test.Utilities.Remoting;
using Process = System.Diagnostics.Process;
@@ -20,42 +18,58 @@ public class VisualStudioInstance
{
private readonly Process _hostProcess;
private readonly DTE _dte;
- private readonly IntegrationService _service;
- private readonly string _serviceUri;
- private readonly IpcClientChannel _serviceChannel;
+ private readonly IntegrationService _integrationService;
+ private readonly IpcClientChannel _integrationServiceChannel;
// TODO: We could probably expose all the windows/services/features of the host process in a better manner
- private readonly Lazy _csharpInteractiveWindow;
+ private readonly Lazy _csharpInteractiveWindow;
private readonly Lazy _editorWindow;
private readonly Lazy _solutionExplorer;
+ private readonly Lazy _workspace;
public VisualStudioInstance(Process process, DTE dte)
{
_hostProcess = process;
_dte = dte;
- ExecuteDteCommandAsync("Tools.StartIntegrationTestService").GetAwaiter().GetResult();
+ dte.ExecuteCommandAsync(VisualStudioCommandNames.VsStartServiceCommand).GetAwaiter().GetResult();
- _serviceChannel = new IpcClientChannel($"ipc channel client for {_hostProcess.Id}", sinkProvider: null);
- ChannelServices.RegisterChannel(_serviceChannel, ensureSecurity: true);
+ _integrationServiceChannel = new IpcClientChannel($"IPC channel client for {_hostProcess.Id}", sinkProvider: null);
+ ChannelServices.RegisterChannel(_integrationServiceChannel, ensureSecurity: true);
// Connect to a 'well defined, shouldn't conflict' IPC channel
- _serviceUri = string.Format($"ipc://{IntegrationService.PortNameFormatString}", _hostProcess.Id);
- _service = (IntegrationService)(Activator.GetObject(typeof(IntegrationService), $"{_serviceUri}/{typeof(IntegrationService).FullName}"));
+ var serviceUri = string.Format($"ipc://{IntegrationService.PortNameFormatString}", _hostProcess.Id);
+ _integrationService = (IntegrationService)(Activator.GetObject(typeof(IntegrationService), $"{serviceUri}/{typeof(IntegrationService).FullName}"));
+ _integrationService.Uri = serviceUri;
- _csharpInteractiveWindow = new Lazy(() => InteractiveWindow.CreateCSharpInteractiveWindow(this));
+ // There is a lot of VS initialization code that goes on, so we want to wait for that to 'settle' before
+ // we start executing any actual code.
+ _integrationService.Execute(typeof(RemotingHelper), nameof(RemotingHelper.WaitForSystemIdle));
+
+ _csharpInteractiveWindow = new Lazy(() => new CSharpInteractiveWindow(this));
_editorWindow = new Lazy(() => new EditorWindow(this));
_solutionExplorer = new Lazy(() => new SolutionExplorer(this));
+ _workspace = new Lazy(() => new Workspace(this));
+
+ // Ensure we are in a known 'good' state by cleaning up anything changed by the previous instance
+ Cleanup();
}
public DTE Dte => _dte;
public bool IsRunning => !_hostProcess.HasExited;
- public InteractiveWindow CSharpInteractiveWindow => _csharpInteractiveWindow.Value;
+ public CSharpInteractiveWindow CSharpInteractiveWindow => _csharpInteractiveWindow.Value;
+
public EditorWindow EditorWindow => _editorWindow.Value;
+
public SolutionExplorer SolutionExplorer => _solutionExplorer.Value;
+ public Workspace Workspace => _workspace.Value;
+
+ internal IntegrationService IntegrationService => _integrationService;
+
+ #region Automation Elements
public async Task ClickAutomationElementAsync(string elementName, bool recursive = false)
{
var automationElement = await LocateAutomationElementAsync(elementName, recursive).ConfigureAwait(continueOnCapturedContext: false);
@@ -67,31 +81,7 @@ public async Task ClickAutomationElementAsync(string elementName, bool recursive
}
}
- internal async Task ExecuteDteCommandAsync(string command, string args = "")
- {
- // args is "" by default because thats what Dte.ExecuteCommand does by default and changing our default
- // to something more logical, like null, would change the expected behavior of Dte.ExecuteCommand
-
- await WaitForDteCommandAvailabilityAsync(command).ConfigureAwait(continueOnCapturedContext: false);
- IntegrationHelper.RetryDteCall(() => _dte.ExecuteCommand(command, args));
- }
-
- internal T ExecuteOnHostProcess(Type type, string methodName, BindingFlags bindingFlags, params object[] parameters)
- => ExecuteOnHostProcess(type.Assembly.Location, type.FullName, methodName, bindingFlags, parameters);
-
- internal T ExecuteOnHostProcess(string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags, params object[] parameters)
- {
- var objectUri = _service.Execute(assemblyFilePath, typeFullName, methodName, bindingFlags, parameters);
-
- if (string.IsNullOrWhiteSpace(objectUri))
- {
- return default(T);
- }
-
- return (T)(Activator.GetObject(typeof(T), $"{_serviceUri}/{objectUri}"));
- }
-
- internal async Task LocateAutomationElementAsync(string elementName, bool recursive = false)
+ private async Task LocateAutomationElementAsync(string elementName, bool recursive = false)
{
AutomationElement automationElement = null;
var scope = (recursive ? TreeScope.Descendants : TreeScope.Children);
@@ -105,63 +95,58 @@ internal async Task LocateAutomationElementAsync(string eleme
return automationElement;
}
+ #endregion
- internal Task LocateDteWindowAsync(string windowTitle)
- => IntegrationHelper.WaitForNotNullAsync(() => IntegrationHelper.RetryDteCall(() =>
- {
- foreach (Window window in _dte.Windows)
- {
- if (window.Caption.Equals(windowTitle, StringComparison.OrdinalIgnoreCase))
- {
- return window;
- }
- }
- return null;
- }));
-
- internal Task WaitForDteCommandAvailabilityAsync(string command)
- => IntegrationHelper.WaitForResultAsync(() => IntegrationHelper.RetryDteCall(() => Dte.Commands.Item(command).IsAvailable), expectedResult: true);
-
- public void Close()
+ #region Cleanup
+ public void Cleanup()
{
- if (!IsRunning)
- {
- return;
- }
+ CleanupOpenSolution();
+ CleanupInteractiveWindow();
+ CleanupWaitingService();
+ CleanupWorkspace();
+ }
- CloseAndDeleteOpenSolution();
- CleanupRemotingService();
- CleanupHostProcess();
+ private void CleanupInteractiveWindow()
+ {
+ var csharpInteractiveWindow = _dte.LocateWindow(CSharpInteractiveWindow.DteWindowTitle);
+ IntegrationHelper.RetryRpcCall(() => csharpInteractiveWindow?.Close());
}
- public void CloseAndDeleteOpenSolution()
+ private void CleanupOpenSolution()
{
- IntegrationHelper.RetryDteCall(() => _dte.Documents.CloseAll(EnvDTE.vsSaveChanges.vsSaveChangesNo));
+ IntegrationHelper.RetryRpcCall(() => _dte.Documents.CloseAll(vsSaveChanges.vsSaveChangesNo));
- if (IntegrationHelper.RetryDteCall(() => _dte.Solution) != null)
+ var dteSolution = IntegrationHelper.RetryRpcCall(() => _dte.Solution);
+
+ if (dteSolution != null)
{
- var directoriesToDelete = IntegrationHelper.RetryDteCall(() =>
+ var directoriesToDelete = IntegrationHelper.RetryRpcCall(() =>
{
var directoryList = new List();
+ var dteSolutionProjects = IntegrationHelper.RetryRpcCall(() => dteSolution.Projects);
+
// Save the full path to each project in the solution. This is so we can cleanup any folders after the solution is closed.
- foreach (EnvDTE.Project project in _dte.Solution.Projects)
+ foreach (EnvDTE.Project project in dteSolutionProjects)
{
- directoryList.Add(Path.GetDirectoryName(project.FullName));
+ var projectFullName = IntegrationHelper.RetryRpcCall(() => project.FullName);
+ directoryList.Add(Path.GetDirectoryName(projectFullName));
}
// Save the full path to the solution. This is so we can cleanup any folders after the solution is closed.
// The solution might be zero-impact and thus has no name, so deal with that
- if (!string.IsNullOrEmpty(_dte.Solution.FullName))
+ var dteSolutionFullName = IntegrationHelper.RetryRpcCall(() => dteSolution.FullName);
+
+ if (!string.IsNullOrEmpty(dteSolutionFullName))
{
- directoryList.Add(Path.GetDirectoryName(_dte.Solution.FullName));
+ directoryList.Add(Path.GetDirectoryName(dteSolutionFullName));
}
return directoryList;
});
- IntegrationHelper.RetryDteCall(() => _dte.Solution.Close(SaveFirst: false));
+ IntegrationHelper.RetryRpcCall(() => dteSolution.Close(SaveFirst: false));
foreach (var directoryToDelete in directoriesToDelete)
{
@@ -170,29 +155,48 @@ public void CloseAndDeleteOpenSolution()
}
}
- private void CleanupHostProcess()
+ private void CleanupWaitingService() => _integrationService.Execute(typeof(RemotingHelper), nameof(RemotingHelper.CleanupWaitingService));
+
+ private void CleanupWorkspace() => _integrationService.Execute(typeof(RemotingHelper), nameof(RemotingHelper.CleanupWorkspace));
+ #endregion
+
+ #region Close
+ public void Close()
+ {
+ if (!IsRunning)
+ {
+ return;
+ }
+ Cleanup();
+
+ CloseRemotingService();
+ CloseHostProcess();
+ }
+
+ private void CloseHostProcess()
{
- IntegrationHelper.RetryDteCall(() => _dte.Quit());
+ IntegrationHelper.RetryRpcCall(() => _dte.Quit());
IntegrationHelper.KillProcess(_hostProcess);
}
- private void CleanupRemotingService()
+ private void CloseRemotingService()
{
try
{
- if ((IntegrationHelper.RetryDteCall(() => _dte?.Commands.Item(VisualStudioCommandNames.VsStopServiceCommand).IsAvailable).GetValueOrDefault()))
+ if ((IntegrationHelper.RetryRpcCall(() => _dte?.Commands.Item(VisualStudioCommandNames.VsStopServiceCommand).IsAvailable).GetValueOrDefault()))
{
- ExecuteDteCommandAsync(VisualStudioCommandNames.VsStopServiceCommand).GetAwaiter().GetResult();
+ _dte.ExecuteCommandAsync(VisualStudioCommandNames.VsStopServiceCommand).GetAwaiter().GetResult();
}
}
finally
{
- if (_serviceChannel != null)
+ if (_integrationServiceChannel != null)
{
- ChannelServices.UnregisterChannel(_serviceChannel);
+ ChannelServices.UnregisterChannel(_integrationServiceChannel);
}
}
}
+ #endregion
}
}
diff --git a/src/VisualStudio/TestUtilities/VisualStudioInstanceContext.cs b/src/VisualStudio/TestUtilities/VisualStudioInstanceContext.cs
index e877232628e5c..9609a63e06859 100644
--- a/src/VisualStudio/TestUtilities/VisualStudioInstanceContext.cs
+++ b/src/VisualStudio/TestUtilities/VisualStudioInstanceContext.cs
@@ -1,8 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+// 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;
namespace Roslyn.VisualStudio.Test.Utilities
{
@@ -28,7 +26,7 @@ public void Dispose()
{
try
{
- _instance.CloseAndDeleteOpenSolution();
+ _instance.Cleanup();
_instanceFactory.NotifyCurrentInstanceContextDisposed(canReuse: true);
}
catch (Exception)
diff --git a/src/VisualStudio/TestUtilities/VisualStudioInstanceFactory.cs b/src/VisualStudio/TestUtilities/VisualStudioInstanceFactory.cs
index 909e79e925ccd..29bcdbfcaa143 100644
--- a/src/VisualStudio/TestUtilities/VisualStudioInstanceFactory.cs
+++ b/src/VisualStudio/TestUtilities/VisualStudioInstanceFactory.cs
@@ -11,7 +11,6 @@ public sealed class VisualStudioInstanceFactory : IDisposable
{
internal static readonly string VsProductVersion = Settings.Default.VsProductVersion;
-
internal static readonly string VsProgId = $"VisualStudio.DTE.{VsProductVersion}";
internal static readonly string Wow6432Registry = Environment.Is64BitProcess ? "WOW6432Node" : string.Empty;
@@ -78,10 +77,7 @@ private void StartNewInstance()
private static Process StartNewVisualStudioProcess()
{
- // TODO: This might not be needed anymore as I don't believe we do things which risk corrupting the MEF cache. However,
- // it is still useful to do in case some other action corruped the MEF cache as we don't have to restart the host
- Process.Start(VsExeFile, $"/clearcache {VsLaunchArgs}").WaitForExit();
- Process.Start(VsExeFile, $"/updateconfiguration {VsLaunchArgs}").WaitForExit();
+ Process.Start(VsExeFile, $"/resetsettings General.vssettings /command \"File.Exit\" {VsLaunchArgs}").WaitForExit();
// Make sure we kill any leftover processes spawned by the host
IntegrationHelper.KillProcess("DbgCLR");
diff --git a/src/VisualStudio/TestUtilities/VisualStudioTestUtilities.csproj b/src/VisualStudio/TestUtilities/VisualStudioTestUtilities.csproj
index 8785e1897ea25..d6c5ce41efdac 100644
--- a/src/VisualStudio/TestUtilities/VisualStudioTestUtilities.csproj
+++ b/src/VisualStudio/TestUtilities/VisualStudioTestUtilities.csproj
@@ -18,14 +18,19 @@
AnyCPU
+
+
+
+
+
+
-
True
True
@@ -33,13 +38,15 @@
+
-
+
+
@@ -64,20 +71,33 @@
+
+
+ {1ee8cad3-55f9-4d91-96b2-084641da9a6c}
+ CodeAnalysis
+
{8da861d8-0cce-4334-b6c0-01a846c881ec}
VisualStudio
+
+ {3cdeeab7-2256-418a-beb2-620b5cb16302}
+ EditorFeatures
+
{76c6f005-c89d-4348-bb4a-39189ddbeb52}
ServicesTestUtilities
+
+ {edc68a0e-c68d-4a74-91b7-bf38ec909888}
+ Features
+
{01e9bd68-0339-4a13-b42f-a3ca84d164f3}
InteractiveWindow
@@ -86,6 +106,18 @@
{20bb6fac-44d2-4d76-abfe-0c1e163a1a4f}
VisualStudioInteractiveWindow
+
+ {e2e889a5-2489-4546-9194-47c63e49eaeb}
+ Diagnostics
+
+
+ {5f8d2414-064a-4b3a-9b42-8e2a04246be5}
+ Workspaces
+
+
+ {86fd5b9a-4fa0-4b10-b59f-cfaf077a859c}
+ ServicesVisualStudio
+
{737ff62c-f068-4317-84d0-bfb210c17a4e}
CSharpVisualStudioRepl
diff --git a/src/VisualStudio/TestUtilities/Window/CSharpInteractiveWindow.cs b/src/VisualStudio/TestUtilities/Window/CSharpInteractiveWindow.cs
new file mode 100644
index 0000000000000..0fe871a39e4b8
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Window/CSharpInteractiveWindow.cs
@@ -0,0 +1,17 @@
+// 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 Roslyn.VisualStudio.Test.Utilities.Remoting;
+
+namespace Roslyn.VisualStudio.Test.Utilities
+{
+ public class CSharpInteractiveWindow : InteractiveWindow
+ {
+ internal const string CreateMethodName = nameof(InteractiveWindowWrapper.CreateForCSharp);
+ internal const string DteViewCommand = "View.C#Interactive";
+ internal const string DteWindowTitle = "C# Interactive";
+
+ public CSharpInteractiveWindow(VisualStudioInstance visualStudioInstance) : base(visualStudioInstance, DteViewCommand, DteWindowTitle, CreateMethodName)
+ {
+ }
+ }
+}
diff --git a/src/VisualStudio/TestUtilities/Window/EditorWindow.cs b/src/VisualStudio/TestUtilities/Window/EditorWindow.cs
index 21aceee010cf2..93df5d7b8e881 100644
--- a/src/VisualStudio/TestUtilities/Window/EditorWindow.cs
+++ b/src/VisualStudio/TestUtilities/Window/EditorWindow.cs
@@ -1,5 +1,10 @@
// 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.Reflection;
+using System.Threading.Tasks;
+using EnvDTE;
+using Roslyn.VisualStudio.Test.Utilities.Interop;
using Roslyn.VisualStudio.Test.Utilities.Remoting;
namespace Roslyn.VisualStudio.Test.Utilities
@@ -7,24 +12,295 @@ namespace Roslyn.VisualStudio.Test.Utilities
/// Provides a means of interacting with the active editor window in the Visual Studio host.
public class EditorWindow
{
- private readonly VisualStudioInstance _visualStudio;
+ public const char ENTER = '\u000D';
+ public const char TAB = '\u0009';
+ public const char ESC = '\u001B';
+ public const char ESCAPE = '\u001B';
+ public const char HOME = '\u0024';
+ public const char END = '\u0023';
+ public const char LEFT = '\u0025';
+ public const char RIGHT = '\u0027';
+ public const char UP = '\u0026';
+ public const char DOWN = '\u0028';
+ public const char PGUP = '\u0021';
+ public const char PGDN = '\u0022';
+ public const char NUMLOCK = '\u0090';
+ public const char SCROLLLOCK = '\u0091';
+ public const char PRTSC = '\u002C';
+ public const char BREAK = '\u0003';
+ public const char BACKSPACE = '\u0008';
+ public const char BKSP = '\u0008';
+ public const char BS = '\u0008';
+ public const char CLEAR = '\u000C';
+ public const char CAPSLOCK = '\u0014';
+ public const char INSERT = '\u002D';
+ public const char DEL = '\u002E';
+ public const char DELETE = '\u002E';
+ public const char HELP = '\u002F';
+ public const char F1 = '\u0070';
+ public const char F2 = '\u0071';
+ public const char F3 = '\u0072';
+ public const char F4 = '\u0073';
+ public const char F5 = '\u0074';
+ public const char F6 = '\u0075';
+ public const char F7 = '\u0076';
+ public const char F8 = '\u0077';
+ public const char F9 = '\u0078';
+ public const char F10 = '\u0079';
+ public const char F11 = '\u007A';
+ public const char F12 = '\u007B';
+ public const char F13 = '\u007C';
+ public const char F14 = '\u007D';
+ public const char F15 = '\u007E';
+ public const char F16 = '\u007F';
+ public const char MULTIPLY = '\u006A';
+ public const char ADD = '\u006B';
+ public const char SUBTRACT = '\u006D';
+ public const char DIVIDE = '\u006F';
- internal EditorWindow(VisualStudioInstance visualStudio)
+ private readonly VisualStudioInstance _visualStudioInstance;
+ private readonly EditorWindowWrapper _editorWindowWrapper;
+
+ internal EditorWindow(VisualStudioInstance visualStudioInstance)
+ {
+ _visualStudioInstance = visualStudioInstance;
+
+ var integrationService = _visualStudioInstance.IntegrationService;
+ _editorWindowWrapper = integrationService.Execute(typeof(EditorWindowWrapper), nameof(EditorWindowWrapper.Create), (BindingFlags.Public | BindingFlags.Static));
+ }
+
+ public string CurrentLineTextBeforeCursor
+ {
+ get
+ {
+ // Clear the current selected text, if any, so it is not included in the returned value
+ if (!string.IsNullOrEmpty(TextSelection.Text))
+ {
+ TextSelection.CharLeft(Extend: false, Count: 1);
+ }
+
+ // Select everything from the cursor to the beginning of the line
+ TextSelection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, Extend: true);
+
+ var currentLineTextBeforeCursor = TextSelection.Text;
+
+ // Restore the cursor to its previous position
+ if (currentLineTextBeforeCursor != string.Empty)
+ {
+ TextSelection.CharRight(Extend: false, Count: 1);
+ }
+
+ return currentLineTextBeforeCursor;
+ }
+ }
+
+ public string CurrentLineTextAfterCursor
{
- _visualStudio = visualStudio;
+ get
+ {
+ // Clear the current selected text, if any, so it is not included in the returned value
+ if (!string.IsNullOrEmpty(TextSelection.Text))
+ {
+ TextSelection.CharRight(Extend: false, Count: 1);
+ }
+
+ // Select everything from the cursor to the end of the line
+ TextSelection.EndOfLine(Extend: true);
+
+ var currentLineTextAfterCursor = TextSelection.Text;
+
+ // Restore the cursor to its previous position
+ if (currentLineTextAfterCursor != string.Empty)
+ {
+ TextSelection.CharLeft(Extend: false, Count: 1);
+ }
+
+ return currentLineTextAfterCursor;
+ }
}
public string Text
{
get
{
- return _visualStudio.ExecuteOnHostProcess(typeof(RemotingHelper), nameof(RemotingHelper.GetActiveTextViewContents), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
+ return _editorWindowWrapper.Contents;
}
set
{
- _visualStudio.ExecuteOnHostProcess(typeof(RemotingHelper), nameof(RemotingHelper.SetActiveTextViewContents), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static, value);
+ _editorWindowWrapper.Contents = value;
+ }
+ }
+
+ private TextSelection TextSelection => (TextSelection)(IntegrationHelper.RetryRpcCall(() => _visualStudioInstance.Dte.ActiveDocument.Selection));
+
+ public void Activate() => IntegrationHelper.RetryRpcCall(() => _visualStudioInstance.Dte.ActiveDocument.Activate());
+
+ public void ClearTextSelection() => TextSelection?.Cancel();
+
+ public void Find(string expectedText)
+ {
+ Activate();
+ ClearTextSelection();
+
+ var dteFind = IntegrationHelper.RetryRpcCall(() => _visualStudioInstance.Dte.Find);
+
+ dteFind.Action = vsFindAction.vsFindActionFind;
+ dteFind.FindWhat = expectedText;
+ dteFind.MatchCase = true;
+ dteFind.MatchInHiddenText = true;
+ dteFind.MatchWholeWord = true;
+ dteFind.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxLiteral;
+ dteFind.Target = vsFindTarget.vsFindTargetCurrentDocument;
+
+ var findResult = IntegrationHelper.RetryRpcCall(() => dteFind.Execute());
+
+ if (findResult != vsFindResult.vsFindResultFound)
+ {
+ throw new Exception($"The specified text was not found. ExpectedText: '{expectedText}'; ActualText: '{Text}'");
}
}
+
+ public void PlaceCursor(string marker) => Find(marker);
+
+ public Task TypeTextAsync(string text, int wordsPerMinute = 120)
+ {
+ Activate();
+ return SendKeysAsync(text.Replace("\r\n", "\r").Replace("\n", "\r"), wordsPerMinute);
+ }
+
+ private async Task SendKeysAsync(string text, int wordsPerMinute)
+ {
+ var charactersPerSecond = (wordsPerMinute * 4.5) / 60;
+ var delayBetweenCharacters = (int)((1 / charactersPerSecond) * 1000);
+
+ foreach (var character in text)
+ {
+ var foregroundWindow = IntPtr.Zero;
+ var inputBlocked = false;
+
+ try
+ {
+ inputBlocked = IntegrationHelper.BlockInput();
+ foregroundWindow = IntegrationHelper.GetForegroundWindow();
+
+ _visualStudioInstance.IntegrationService.Execute(typeof(RemotingHelper), nameof(RemotingHelper.ActivateMainWindow));
+
+ var vk = User32.VkKeyScan(character);
+
+ if (vk == -1)
+ {
+ SendCharacter(character);
+ }
+ else
+ {
+ if ((vk & 0x0100) != 0) // SHIFT
+ {
+ SendKey(User32.VK_SHIFT, User32.KEYEVENTF_NONE);
+ }
+
+ if ((vk & 0x0200) != 0) // CTRL
+ {
+ SendKey(User32.VK_CONTROL, User32.KEYEVENTF_NONE);
+ }
+
+ if ((vk & 0x0400) != 0) // ALT
+ {
+ SendKey(User32.VK_MENU, User32.KEYEVENTF_NONE);
+ }
+
+ SendKey((ushort)(vk & 0xFF));
+
+ if ((vk & 0x0100) != 0) // SHIFT
+ {
+ SendKey(User32.VK_SHIFT, User32.KEYEVENTF_KEYUP);
+ }
+
+ if ((vk & 0x0200) != 0) // CTRL
+ {
+ SendKey(User32.VK_CONTROL, User32.KEYEVENTF_KEYUP);
+ }
+
+ if ((vk & 0x0400) != 0) // ALT
+ {
+ SendKey(User32.VK_MENU, User32.KEYEVENTF_KEYUP);
+ }
+ }
+ }
+ finally
+ {
+ if (foregroundWindow != IntPtr.Zero)
+ {
+ IntegrationHelper.SetForegroundWindow(foregroundWindow);
+ }
+
+ if (inputBlocked)
+ {
+ IntegrationHelper.UnblockInput();
+ }
+ }
+
+ await Task.Delay(delayBetweenCharacters);
+ }
+ }
+
+ private bool IsExtendedKey(ushort vk) => ((vk >= User32.VK_PRIOR) && (vk <= User32.VK_DOWN)) || (vk == User32.VK_INSERT) || (vk == User32.VK_DELETE);
+
+ private void SendKey(ushort vk)
+ {
+ SendKey(vk, User32.KEYEVENTF_NONE);
+ SendKey(vk, User32.KEYEVENTF_KEYUP);
+ }
+
+ private void SendKey(ushort vk, uint dwFlags)
+ {
+ var input = new User32.INPUT[] {
+ new User32.INPUT() {
+ Type = User32.INPUT_KEYBOARD,
+ ki = new User32.KEYBDINPUT() {
+ wVk = vk,
+ wScan = 0,
+ dwFlags = dwFlags,
+ time = 0,
+ dwExtraInfo = IntPtr.Zero
+ }
+ }
+ };
+
+ if (IsExtendedKey(vk))
+ {
+ input[0].ki.dwFlags |= User32.KEYEVENTF_EXTENDEDKEY;
+ }
+
+ IntegrationHelper.SendInput(input);
+ }
+
+ private void SendCharacter(char character)
+ {
+ var input = new User32.INPUT[] {
+ new User32.INPUT() {
+ Type = User32.INPUT_KEYBOARD,
+ ki = new User32.KEYBDINPUT() {
+ wVk = 0,
+ wScan = character,
+ dwFlags = User32.KEYEVENTF_UNICODE,
+ time = 0,
+ dwExtraInfo = IntPtr.Zero
+ }
+ },
+ new User32.INPUT() {
+ Type = User32.INPUT_KEYBOARD,
+ ki = new User32.KEYBDINPUT() {
+ wVk = 0,
+ wScan = character,
+ dwFlags = User32.KEYEVENTF_UNICODE | User32.KEYEVENTF_KEYUP,
+ time = 0,
+ dwExtraInfo = IntPtr.Zero
+ }
+ }
+ };
+
+ IntegrationHelper.SendInput(input);
+ }
}
}
diff --git a/src/VisualStudio/TestUtilities/Window/InteractiveWindow.cs b/src/VisualStudio/TestUtilities/Window/InteractiveWindow.cs
index e2dec2a1d565e..dc3c888c5353c 100644
--- a/src/VisualStudio/TestUtilities/Window/InteractiveWindow.cs
+++ b/src/VisualStudio/TestUtilities/Window/InteractiveWindow.cs
@@ -1,43 +1,36 @@
// 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.Reflection;
using System.Threading.Tasks;
using Roslyn.VisualStudio.Test.Utilities.Remoting;
namespace Roslyn.VisualStudio.Test.Utilities
{
/// Provides a means of interacting with the interactive window in the Visual Studio host.
- public class InteractiveWindow
+ public abstract class InteractiveWindow
{
- private const string DteCSharpViewCommand = "View.C#Interactive";
- private const string DteCSharpWindowTitle = "C# Interactive";
private const string DteReplResetCommand = "InteractiveConsole.Reset";
-
private const string ReplPromptText = "> ";
private const string ReplSubmissionText = ". ";
private readonly string _dteViewCommand;
- private readonly VisualStudioInstance _host;
+ private readonly VisualStudioInstance _visualStudioInstance;
private readonly InteractiveWindowWrapper _interactiveWindowWrapper;
- /// Creates a instance that can interact with the C# interactive window in the Visual Studio host.
- internal static InteractiveWindow CreateCSharpInteractiveWindow(VisualStudioInstance host)
- => new InteractiveWindow(host, DteCSharpViewCommand, DteCSharpWindowTitle);
-
- internal InteractiveWindow(VisualStudioInstance host, string dteViewCommand, string dteWindowTitle)
+ internal InteractiveWindow(VisualStudioInstance visualStudioInstance, string dteViewCommand, string dteWindowTitle, string createMethodName)
{
- _host = host;
+ _visualStudioInstance = visualStudioInstance;
_dteViewCommand = dteViewCommand;
// We have to show the window at least once to ensure the interactive service is loaded.
ShowAsync(waitForPrompt: false).GetAwaiter().GetResult();
- var dteWindow = _host.LocateDteWindowAsync(dteWindowTitle).GetAwaiter().GetResult();
- dteWindow.Close();
+ var dteWindow = IntegrationHelper.WaitForNotNullAsync(() => _visualStudioInstance.Dte.LocateWindow(dteWindowTitle)).GetAwaiter().GetResult();
+ IntegrationHelper.RetryRpcCall(() => dteWindow.Close());
// Return a wrapper to the actual interactive window service that exists in the host process
- _interactiveWindowWrapper = _host.ExecuteOnHostProcess(typeof(RemotingHelper), nameof(RemotingHelper.CreateCSharpInteractiveWindowWrapper), (BindingFlags.Public | BindingFlags.Static));
+ var integrationService = _visualStudioInstance.IntegrationService;
+ _interactiveWindowWrapper = integrationService.Execute(typeof(InteractiveWindowWrapper), createMethodName);
}
/// Gets the last output from the REPL.
@@ -100,7 +93,7 @@ public string ReplTextWithoutPrompt
public async Task ResetAsync(bool waitForPrompt = true)
{
- await _host.ExecuteDteCommandAsync(DteReplResetCommand).ConfigureAwait(continueOnCapturedContext: false);
+ await _visualStudioInstance.Dte.ExecuteCommandAsync(DteReplResetCommand).ConfigureAwait(continueOnCapturedContext: false);
if (waitForPrompt)
{
@@ -110,7 +103,7 @@ public async Task ResetAsync(bool waitForPrompt = true)
public async Task ShowAsync(bool waitForPrompt = true)
{
- await _host.ExecuteDteCommandAsync(_dteViewCommand).ConfigureAwait(continueOnCapturedContext: false);
+ await _visualStudioInstance.Dte.ExecuteCommandAsync(_dteViewCommand).ConfigureAwait(continueOnCapturedContext: false);
if (waitForPrompt)
{
diff --git a/src/VisualStudio/TestUtilities/Workspace/SolutionExplorer.cs b/src/VisualStudio/TestUtilities/Window/SolutionExplorer.cs
similarity index 60%
rename from src/VisualStudio/TestUtilities/Workspace/SolutionExplorer.cs
rename to src/VisualStudio/TestUtilities/Window/SolutionExplorer.cs
index 424a60d296e16..290308efc63ff 100644
--- a/src/VisualStudio/TestUtilities/Workspace/SolutionExplorer.cs
+++ b/src/VisualStudio/TestUtilities/Window/SolutionExplorer.cs
@@ -18,29 +18,27 @@ internal SolutionExplorer(VisualStudioInstance visualStudio)
}
/// Gets the solution currently loaded in the host process or null if no solution is currently loaded.
- public Solution Solution
- => _solution;
+ public Solution Solution => _solution;
- /// Creates and loads a new solution in the host process, closing the existing solution without saving if one exists.
- public Solution CreateSolution(string solutionName)
+ /// Creates and loads a new solution in the host process, optionally saving the existing solution if one exists.
+ public Solution CreateSolution(string solutionName, bool saveExistingSolutionIfExists = false)
{
- var dteSolution = _visualStudio.Dte.Solution;
+ var dteSolution = IntegrationHelper.RetryRpcCall(() => _visualStudio.Dte.Solution);
- if (dteSolution.IsOpen)
+ if (IntegrationHelper.RetryRpcCall(() => dteSolution.IsOpen))
{
- CloseSolution(saveFirst: false);
+ CloseSolution(saveExistingSolutionIfExists);
}
var solutionPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
- dteSolution.Create(solutionPath, solutionName);
+ IntegrationHelper.DeleteDirectoryRecursively(solutionPath);
+ IntegrationHelper.RetryRpcCall(() => dteSolution.Create(solutionPath, solutionName));
_solution = new Solution((Solution2)(dteSolution), Path.Combine(solutionPath, $"{solutionName}.sln"));
+
return _solution;
}
- public void CloseSolution(bool saveFirst = false)
- {
- _visualStudio.Dte.Solution.Close(saveFirst);
- }
+ public void CloseSolution(bool saveFirst = false) => IntegrationHelper.RetryRpcCall(() => _visualStudio.Dte.Solution.Close(saveFirst));
}
}
diff --git a/src/VisualStudio/TestUtilities/Workspace/Project.cs b/src/VisualStudio/TestUtilities/Workspace/Project.cs
index 86859fa2b7cd4..df4d3878c0ce9 100644
--- a/src/VisualStudio/TestUtilities/Workspace/Project.cs
+++ b/src/VisualStudio/TestUtilities/Workspace/Project.cs
@@ -1,5 +1,7 @@
// 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 DteProject = EnvDTE.Project;
namespace Roslyn.VisualStudio.Test.Utilities
@@ -13,18 +15,25 @@ public class Project
internal Project(DteProject dteProject, Solution solution, ProjectLanguage language)
{
+ if (dteProject == null)
+ {
+ throw new ArgumentNullException(nameof(dteProject));
+ }
+
+ if (solution == null)
+ {
+ throw new ArgumentNullException(nameof(solution));
+ }
+
_dteProject = dteProject;
_solution = solution;
_language = language;
}
- public DteProject DteProject
- => _dteProject;
+ public DteProject DteProject => _dteProject;
- public ProjectLanguage Language
- => _language;
+ public ProjectLanguage Language => _language;
- public Solution Solution
- => _solution;
+ public Solution Solution => _solution;
}
}
diff --git a/src/VisualStudio/TestUtilities/Workspace/Solution.cs b/src/VisualStudio/TestUtilities/Workspace/Solution.cs
index 2aae0afbaa5a5..5cabfef88a9e8 100644
--- a/src/VisualStudio/TestUtilities/Workspace/Solution.cs
+++ b/src/VisualStudio/TestUtilities/Workspace/Solution.cs
@@ -1,8 +1,10 @@
// 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.IO;
+using DteProject = EnvDTE.Project;
using DteSolution = EnvDTE80.Solution2;
namespace Roslyn.VisualStudio.Test.Utilities
@@ -10,53 +12,86 @@ namespace Roslyn.VisualStudio.Test.Utilities
/// Provides a means of interacting with the current solution loaded by the host process.
public class Solution
{
- private static readonly IDictionary ProjectTemplateName = new Dictionary {
- [ProjectTemplate.ClassLibrary] = "ClassLibrary.zip",
- [ProjectTemplate.ConsoleApplication] = "ConsoleApplication.zip",
- [ProjectTemplate.Website] = "EmptyWeb.zip",
- [ProjectTemplate.WinFormsApplication] = "WindowsApplication.zip",
- [ProjectTemplate.WpfApplication] = "WpfApplication.zip",
- [ProjectTemplate.WebApplication] = "WebApplicationProject40"
- };
-
- private static readonly IDictionary ProjectLanguageName = new Dictionary {
+ private static readonly IDictionary ProjectLanguages = new Dictionary {
[ProjectLanguage.CSharp] = "CSharp",
[ProjectLanguage.VisualBasic] = "VisualBasic"
};
private readonly DteSolution _dteSolution;
- private readonly string _fileName; // Cache the filename as `_dteSolution` won't expose it unless the solution has been saved
+ private readonly string _fileName; // Cache the filename because `_dteSolution` won't expose it unless the solution has been saved
+ private readonly IDictionary _projectTemplates;
internal Solution(DteSolution dteSolution, string fileName)
{
+ if (dteSolution == null)
+ {
+ throw new ArgumentNullException(nameof(dteSolution));
+ }
+
+ if (string.IsNullOrWhiteSpace(fileName))
+ {
+ throw new ArgumentNullException(nameof(fileName));
+ }
+
_dteSolution = dteSolution;
_fileName = fileName;
+
+ _projectTemplates = new Dictionary {
+ [ProjectTemplate.ClassLibrary] = $@"Windows\{dteSolution.DTE.LocaleID}\ClassLibrary.zip",
+ [ProjectTemplate.ConsoleApplication] = "ConsoleApplication.zip",
+ [ProjectTemplate.Website] = "EmptyWeb.zip",
+ [ProjectTemplate.WinFormsApplication] = "WindowsApplication.zip",
+ [ProjectTemplate.WpfApplication] = "WpfApplication.zip",
+ [ProjectTemplate.WebApplication] = "WebApplicationProject40"
+ };
}
- public DteSolution DteSolution
- => _dteSolution;
+ public string DirectoryName => Path.GetDirectoryName(FileName);
+
+ public DteSolution DteSolution => _dteSolution;
public string FileName
{
get
{
- var solutionFullName = _dteSolution.FullName;
+ var solutionFullName = IntegrationHelper.RetryRpcCall(() => _dteSolution.FullName);
return string.IsNullOrEmpty(solutionFullName) ? _fileName : solutionFullName;
}
}
public Project AddProject(string projectName, ProjectTemplate projectTemplate, ProjectLanguage projectLanguage)
{
- var solutionFolder = Path.GetDirectoryName(FileName);
- var projectPath = Path.Combine(solutionFolder, projectName);
+ var projectPath = Path.Combine(DirectoryName, projectName);
var projectTemplatePath = GetProjectTemplatePath(projectTemplate, projectLanguage);
- var dteProject = _dteSolution.AddFromTemplate(projectTemplatePath, projectPath, projectName, Exclusive: false);
+ var dteProject = IntegrationHelper.RetryRpcCall(() => _dteSolution.AddFromTemplate(projectTemplatePath, projectPath, projectName, Exclusive: false));
+
+ if (dteProject == null)
+ {
+ var dteSolutionProjects = IntegrationHelper.RetryRpcCall(() => _dteSolution.Projects);
+
+ foreach (DteProject project in dteSolutionProjects)
+ {
+ var dteProjectName = IntegrationHelper.RetryRpcCall(() => project.Name);
+
+ if (dteProjectName == projectName)
+ {
+ dteProject = project;
+ }
+ }
+ }
+
return new Project(dteProject, this, projectLanguage);
}
+ public void Save()
+ {
+ Directory.CreateDirectory(DirectoryName);
+ IntegrationHelper.RetryRpcCall(() => _dteSolution.SaveAs(FileName));
+ }
+
// TODO: Adjust language name based on whether we are using a web template
private string GetProjectTemplatePath(ProjectTemplate projectTemplate, ProjectLanguage projectLanguage)
- => _dteSolution.GetProjectTemplate(ProjectTemplateName[projectTemplate], ProjectLanguageName[projectLanguage]);
+ => IntegrationHelper.RetryRpcCall(() => _dteSolution.GetProjectTemplate(_projectTemplates[projectTemplate], ProjectLanguages[projectLanguage]));
}
}
diff --git a/src/VisualStudio/TestUtilities/Workspace/Workspace.cs b/src/VisualStudio/TestUtilities/Workspace/Workspace.cs
new file mode 100644
index 0000000000000..fb324bb021f15
--- /dev/null
+++ b/src/VisualStudio/TestUtilities/Workspace/Workspace.cs
@@ -0,0 +1,34 @@
+// 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.Reflection;
+using Roslyn.VisualStudio.Test.Utilities.Remoting;
+
+namespace Roslyn.VisualStudio.Test.Utilities
+{
+ public class Workspace
+ {
+ private readonly VisualStudioInstance _visualStudioInstance;
+ private readonly WorkspaceWrapper _workspaceWrapper;
+
+ internal Workspace(VisualStudioInstance visualStudioInstance)
+ {
+ _visualStudioInstance = visualStudioInstance;
+
+ var integrationService = _visualStudioInstance.IntegrationService;
+ _workspaceWrapper = integrationService.Execute(typeof(WorkspaceWrapper), nameof(WorkspaceWrapper.Create));
+ }
+
+ public bool UseSuggestionMode
+ {
+ get
+ {
+ return _workspaceWrapper.UseSuggestionMode;
+ }
+
+ set
+ {
+ _workspaceWrapper.UseSuggestionMode = value;
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj b/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
index 658843418208e..cf977b0180e08 100644
--- a/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
+++ b/src/VisualStudio/VisualBasic/Impl/BasicVisualStudio.vbproj
@@ -189,7 +189,6 @@
false
-
@@ -240,4 +239,4 @@
-
\ No newline at end of file
+
diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
index a7572892445d3..4f182b14d43f4 100644
--- a/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
+++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolTree/SymbolTreeInfo_Metadata.cs
@@ -6,26 +6,13 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.Collections;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.FindSymbols
{
internal partial class SymbolTreeInfo
{
- private static SimplePool> s_definitionMapPool =
- new SimplePool>(() => new MultiDictionary());
-
- private static MultiDictionary AllocateDefinitionMap()
- {
- return s_definitionMapPool.Allocate();
- }
-
- private static void FreeDefinitionMap(MultiDictionary definitionMap)
- {
- definitionMap.Clear();
- s_definitionMapPool.Free(definitionMap);
- }
-
///
/// this gives you SymbolTreeInfo for a metadata
///
@@ -117,7 +104,7 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List unsortedNodes)
{
- var definitionMap = AllocateDefinitionMap();
+ var definitionMap = OrderPreservingMultiDictionary.GetInstance();
try
{
LookupMetadataDefinitions(reader, globalNamespace, definitionMap);
@@ -132,7 +119,7 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List.ValueSet definitionsWithSameName,
+ OrderPreservingMultiDictionary.ValueSet definitionsWithSameName,
List unsortedNodes)
{
var node = new Node(name, parentIndex);
@@ -148,7 +135,7 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List.GetInstance();
try
{
foreach (var definition in definitionsWithSameName)
@@ -166,13 +153,13 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List definitionMap)
+ OrderPreservingMultiDictionary definitionMap)
{
switch (definition.Kind)
{
@@ -187,7 +174,7 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List definitionMap)
+ OrderPreservingMultiDictionary definitionMap)
{
// Only bother looking for extension methods in static types.
if ((typeDefinition.Attributes & TypeAttributes.Abstract) != 0 &&
@@ -235,7 +222,7 @@ private static void GenerateMetadataNodes(MetadataReader metadataReader, List definitionMap)
+ OrderPreservingMultiDictionary definitionMap)
{
foreach (var child in namespaceDefinition.NamespaceDefinitions)
{
diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj
index ad3eecdf0c2d0..880ce32443c74 100644
--- a/src/Workspaces/Core/Portable/Workspaces.csproj
+++ b/src/Workspaces/Core/Portable/Workspaces.csproj
@@ -41,6 +41,9 @@
InternalUtilities\ImmutableArrayExtensions.cs
+
+ Utilities\CompilerUtilities\OrderPreservingMultiDictionary.cs
+
Collections\PooledStringBuilder.cs
@@ -280,6 +283,7 @@
+
diff --git a/src/Workspaces/CoreTest/ServicesTest.csproj b/src/Workspaces/CoreTest/ServicesTest.csproj
index 3db534bcb7513..7d1d4c535fe33 100644
--- a/src/Workspaces/CoreTest/ServicesTest.csproj
+++ b/src/Workspaces/CoreTest/ServicesTest.csproj
@@ -13,7 +13,9 @@
Microsoft.CodeAnalysis.UnitTests
Roslyn.Services.UnitTests
v4.6
+ true
+
$(DefineConstants);MSBUILD12
diff --git a/src/Workspaces/CoreTest/app.config b/src/Workspaces/CoreTest/app.config
index a5e030b1e06b6..5c69694d20f0f 100644
--- a/src/Workspaces/CoreTest/app.config
+++ b/src/Workspaces/CoreTest/app.config
@@ -13,36 +13,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-