Skip to content

Commit 713cd56

Browse files
Move off of Progression for solution explorer. (#78714)
2 parents 63c55df + 8506a18 commit 713cd56

File tree

86 files changed

+2904
-7329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+2904
-7329
lines changed

src/Compilers/Test/Core/Traits/Traits.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ public static class Features
315315
public const string SmartIndent = nameof(SmartIndent);
316316
public const string SmartTokenFormatting = nameof(SmartTokenFormatting);
317317
public const string Snippets = nameof(Snippets);
318+
public const string SolutionExplorer = nameof(SolutionExplorer);
318319
public const string SourceGenerators = nameof(SourceGenerators);
319320
public const string SplitComment = nameof(SplitComment);
320321
public const string SplitStringLiteral = nameof(SplitStringLiteral);

src/Features/CSharp/Portable/SolutionExplorer/CSharpSolutionExplorerSymbolTreeItemProvider.cs

Lines changed: 470 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Threading.Tasks;
6+
using Microsoft.CodeAnalysis.CSharp;
7+
using Microsoft.CodeAnalysis.CSharp.Syntax;
8+
using Microsoft.CodeAnalysis.Test.Utilities;
9+
using Microsoft.CodeAnalysis.Test.Utilities.SolutionExplorer;
10+
using Xunit;
11+
12+
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SolutionExplorer;
13+
14+
[UseExportProvider, Trait(Traits.Feature, Traits.Features.SolutionExplorer)]
15+
public sealed class CSharpSolutionExplorerSymbolTreeItemProviderTests
16+
: AbstractSolutionExplorerSymbolTreeItemProviderTests
17+
{
18+
protected override TestWorkspace CreateWorkspace(string code)
19+
{
20+
return TestWorkspace.CreateCSharp(
21+
code, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview));
22+
}
23+
24+
private Task TestCompilationUnit(
25+
string code, string expected)
26+
{
27+
return TestNode<CompilationUnitSyntax>(code, expected);
28+
}
29+
30+
[Fact]
31+
public async Task TestEmptyFile()
32+
{
33+
await TestCompilationUnit("", "");
34+
}
35+
36+
[Fact]
37+
public async Task TestTopLevelClass()
38+
{
39+
await TestCompilationUnit("""
40+
class [|C|]
41+
{
42+
}
43+
""", """
44+
Name="C" Glyph=ClassInternal HasItems=False
45+
""");
46+
}
47+
48+
[Fact]
49+
public async Task TestTwoTopLevelTypes()
50+
{
51+
await TestCompilationUnit("""
52+
class [|C|]
53+
{
54+
}
55+
56+
class [|D|]
57+
{
58+
}
59+
""", """
60+
Name="C" Glyph=ClassInternal HasItems=False
61+
Name="D" Glyph=ClassInternal HasItems=False
62+
""");
63+
}
64+
65+
[Fact]
66+
public async Task TestDelegatesAndEnums()
67+
{
68+
await TestCompilationUnit("""
69+
delegate string [|D|](int x);
70+
71+
enum [|E|]
72+
{
73+
}
74+
""", """
75+
Name="D(int) : string" Glyph=DelegateInternal HasItems=False
76+
Name="E" Glyph=EnumInternal HasItems=False
77+
""");
78+
}
79+
80+
[Fact]
81+
public async Task TestTypesInBlockNamespace()
82+
{
83+
await TestCompilationUnit("""
84+
namespace N
85+
{
86+
class [|C|]
87+
{
88+
}
89+
90+
class [|D|]
91+
{
92+
}
93+
}
94+
""", """
95+
Name="C" Glyph=ClassInternal HasItems=False
96+
Name="D" Glyph=ClassInternal HasItems=False
97+
""");
98+
}
99+
100+
[Fact]
101+
public async Task TestTypesInFileScopedNamespace()
102+
{
103+
await TestCompilationUnit("""
104+
namespace N;
105+
106+
class [|C|]
107+
{
108+
}
109+
110+
class [|D|]
111+
{
112+
}
113+
""", """
114+
Name="C" Glyph=ClassInternal HasItems=False
115+
Name="D" Glyph=ClassInternal HasItems=False
116+
""");
117+
}
118+
119+
[Fact]
120+
public async Task TestTypesAcrossNamespaces()
121+
{
122+
await TestCompilationUnit("""
123+
class [|C|]
124+
{
125+
}
126+
127+
namespace N
128+
{
129+
class [|D|]
130+
{
131+
}
132+
}
133+
""", """
134+
Name="C" Glyph=ClassInternal HasItems=False
135+
Name="D" Glyph=ClassInternal HasItems=False
136+
""");
137+
}
138+
139+
[Theory, CombinatorialData]
140+
public async Task TestTypePermutations(
141+
[CombinatorialValues("Public", "Private", "Protected", "Internal")] string accessibility,
142+
[CombinatorialValues("Record", "Class", "Interface", "Struct")] string type)
143+
{
144+
await TestCompilationUnit($$"""
145+
{{accessibility.ToLowerInvariant()}} {{type.ToLowerInvariant()}} [|C|]
146+
{
147+
}
148+
""", $$"""
149+
Name="C" Glyph={{type switch { "Record" => "Class", "Struct" => "Structure", _ => type }}}{{accessibility}} HasItems=False
150+
""");
151+
}
152+
153+
[Theory, CombinatorialData]
154+
public async Task TestTypeHasItems(
155+
[CombinatorialValues("Record", "Class", "Interface", "Struct")] string type)
156+
{
157+
await TestCompilationUnit($$"""
158+
{{type.ToLowerInvariant()}} [|C|]
159+
{
160+
int i;
161+
}
162+
""", $$"""
163+
Name="C" Glyph={{type switch { "Record" => "Class", "Struct" => "Structure", _ => type }}}Internal HasItems=True
164+
""");
165+
}
166+
167+
[Fact]
168+
public async Task TestEnumHasItems()
169+
{
170+
await TestCompilationUnit("""
171+
enum [|E|]
172+
{
173+
A,
174+
B,
175+
C
176+
}
177+
""", """
178+
Name="E" Glyph=EnumInternal HasItems=True
179+
""");
180+
}
181+
182+
[Theory]
183+
[InlineData("int", "int")]
184+
[InlineData("int[]", "int[]")]
185+
[InlineData("int[][]", "int[][]")]
186+
[InlineData("int[,][,,]", "int[,][,,]")]
187+
[InlineData("int*", "int*")]
188+
[InlineData("int?", "int?")]
189+
[InlineData("(int, string)", "(int, string)")]
190+
[InlineData("(int a, string b)", "(int a, string b)")]
191+
[InlineData("delegate*unmanaged[a]<int, string>", "delegate*<int, string>")]
192+
[InlineData("A.B", "B")]
193+
[InlineData("A::B", "B")]
194+
[InlineData("A::B.C", "C")]
195+
[InlineData("A", "A")]
196+
[InlineData("A.B<C::D, E::F.G<int>>", "B<D, G<int>>")]
197+
public async Task TestTypes(
198+
string parameterType, string resultType)
199+
{
200+
await TestCompilationUnit($$"""
201+
delegate void [|D|]({{parameterType}} x);
202+
""", $$"""
203+
Name="D({{resultType}}) : void" Glyph=DelegateInternal HasItems=False
204+
""");
205+
}
206+
207+
[Fact]
208+
public async Task TestGenericClass()
209+
{
210+
await TestCompilationUnit("""
211+
class [|C|]<T>
212+
{
213+
}
214+
""", """
215+
Name="C<T>" Glyph=ClassInternal HasItems=False
216+
""");
217+
}
218+
219+
[Fact]
220+
public async Task TestGenericDelegate()
221+
{
222+
await TestCompilationUnit("""
223+
delegate void [|D|]<T>();
224+
""", """
225+
Name="D<T>() : void" Glyph=DelegateInternal HasItems=False
226+
""");
227+
}
228+
229+
[Fact]
230+
public async Task TestEnumMembers()
231+
{
232+
await TestNode<EnumDeclarationSyntax>("""
233+
enum E
234+
{
235+
[|A|], [|B|], [|C|]
236+
}
237+
""", """
238+
Name="A" Glyph=EnumMemberPublic HasItems=False
239+
Name="B" Glyph=EnumMemberPublic HasItems=False
240+
Name="C" Glyph=EnumMemberPublic HasItems=False
241+
""");
242+
}
243+
244+
[Fact]
245+
public async Task TestClassMembers()
246+
{
247+
await TestNode<ClassDeclarationSyntax>("""
248+
class C
249+
{
250+
private int [|a|], [|b|];
251+
public P [|Prop|] => default;
252+
internal [|C|]() { }
253+
~[|C|]() { }
254+
255+
protected R [|this|][string s] => default;
256+
private event Action [|A|] { }
257+
public event Action [|B|], [|C|];
258+
259+
void [|M|]<T>(int a) { }
260+
public void IInterface.[|O|]() { }
261+
262+
public static C operator [|+|](C c1, int a) => default;
263+
264+
internal static implicit operator [|int|](C c1) => default;
265+
}
266+
""", """
267+
Name="a : int" Glyph=FieldPrivate HasItems=False
268+
Name="b : int" Glyph=FieldPrivate HasItems=False
269+
Name="Prop : P" Glyph=PropertyPublic HasItems=False
270+
Name="C()" Glyph=MethodInternal HasItems=False
271+
Name="~C()" Glyph=MethodPrivate HasItems=False
272+
Name="this[string] : R" Glyph=PropertyProtected HasItems=False
273+
Name="A : Action" Glyph=EventPrivate HasItems=False
274+
Name="B : Action" Glyph=EventPublic HasItems=False
275+
Name="C : Action" Glyph=EventPublic HasItems=False
276+
Name="M<T>(int) : void" Glyph=MethodPrivate HasItems=False
277+
Name="O() : void" Glyph=MethodPublic HasItems=False
278+
Name="operator +(C, int) : C" Glyph=OperatorPublic HasItems=False
279+
Name="implicit operator int(C)" Glyph=OperatorInternal HasItems=False
280+
""");
281+
}
282+
283+
[Fact]
284+
public async Task TestExtension1()
285+
{
286+
await TestNode<ClassDeclarationSyntax>("""
287+
static class C
288+
{
289+
[|extension|]<T>(int i)
290+
{
291+
}
292+
293+
public static void [|M|](this int i) {}
294+
}
295+
""", """
296+
Name="extension<T>(int)" Glyph=ClassPublic HasItems=False
297+
Name="M(int) : void" Glyph=ExtensionMethodPublic HasItems=False
298+
""");
299+
}
300+
301+
[Fact]
302+
public async Task TestExtension2()
303+
{
304+
await TestNode<ExtensionBlockDeclarationSyntax>("""
305+
static class C
306+
{
307+
extension<T>(int i)
308+
{
309+
public void [|M|]() { }
310+
}
311+
}
312+
""", """
313+
Name="M() : void" Glyph=ExtensionMethodPublic HasItems=False
314+
""");
315+
}
316+
}

src/Features/Core/Portable/Common/GlyphExtensions.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Collections.Immutable;
7+
using Microsoft.CodeAnalysis.FindSymbols;
78
using Microsoft.CodeAnalysis.PooledObjects;
89
using Microsoft.CodeAnalysis.Shared.Extensions;
910
using Microsoft.CodeAnalysis.Tags;
@@ -244,4 +245,55 @@ public static Accessibility GetAccessibility(ReadOnlySpan<string> tags)
244245

245246
return Accessibility.NotApplicable;
246247
}
248+
249+
public static Glyph GetGlyph(DeclaredSymbolInfoKind kind, Accessibility accessibility)
250+
{
251+
// Glyphs are stored in this order:
252+
// ClassPublic,
253+
// ClassProtected,
254+
// ClassPrivate,
255+
// ClassInternal,
256+
257+
var rawGlyph = GetPublicGlyph(kind);
258+
259+
switch (accessibility)
260+
{
261+
case Accessibility.Private:
262+
rawGlyph += (Glyph.ClassPrivate - Glyph.ClassPublic);
263+
break;
264+
case Accessibility.Internal:
265+
rawGlyph += (Glyph.ClassInternal - Glyph.ClassPublic);
266+
break;
267+
case Accessibility.Protected:
268+
case Accessibility.ProtectedOrInternal:
269+
case Accessibility.ProtectedAndInternal:
270+
rawGlyph += (Glyph.ClassProtected - Glyph.ClassPublic);
271+
break;
272+
}
273+
274+
return rawGlyph;
275+
}
276+
277+
private static Glyph GetPublicGlyph(DeclaredSymbolInfoKind kind)
278+
=> kind switch
279+
{
280+
DeclaredSymbolInfoKind.Class => Glyph.ClassPublic,
281+
DeclaredSymbolInfoKind.Constant => Glyph.ConstantPublic,
282+
DeclaredSymbolInfoKind.Constructor => Glyph.MethodPublic,
283+
DeclaredSymbolInfoKind.Delegate => Glyph.DelegatePublic,
284+
DeclaredSymbolInfoKind.Enum => Glyph.EnumPublic,
285+
DeclaredSymbolInfoKind.EnumMember => Glyph.EnumMemberPublic,
286+
DeclaredSymbolInfoKind.Event => Glyph.EventPublic,
287+
DeclaredSymbolInfoKind.ExtensionMethod => Glyph.ExtensionMethodPublic,
288+
DeclaredSymbolInfoKind.Field => Glyph.FieldPublic,
289+
DeclaredSymbolInfoKind.Indexer => Glyph.PropertyPublic,
290+
DeclaredSymbolInfoKind.Interface => Glyph.InterfacePublic,
291+
DeclaredSymbolInfoKind.Method => Glyph.MethodPublic,
292+
DeclaredSymbolInfoKind.Module => Glyph.ModulePublic,
293+
DeclaredSymbolInfoKind.Operator => Glyph.OperatorPublic,
294+
DeclaredSymbolInfoKind.Property => Glyph.PropertyPublic,
295+
DeclaredSymbolInfoKind.Struct => Glyph.StructurePublic,
296+
DeclaredSymbolInfoKind.RecordStruct => Glyph.StructurePublic,
297+
_ => Glyph.ClassPublic,
298+
};
247299
}

src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.InProcess.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ private static string GetItemKind(DeclaredSymbolInfo declaredSymbolInfo)
215215
return NavigateToItemKind.Property;
216216
case DeclaredSymbolInfoKind.Struct:
217217
return NavigateToItemKind.Structure;
218+
case DeclaredSymbolInfoKind.Operator:
219+
return NavigateToItemKind.OtherSymbol;
218220
default:
219221
throw ExceptionUtilities.UnexpectedValue(declaredSymbolInfo.Kind);
220222
}

0 commit comments

Comments
 (0)