Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:
contents: read

env:
version: '10.9.${{ github.run_number }}'
version: '10.10.${{ github.run_number }}'
dotnetVersion: '8'
repoUrl: ${{ github.server_url }}/${{ github.repository }}
vsixPath: src/CodeNav/bin/Release/net472/CodeNav.vsix
Expand Down
2 changes: 1 addition & 1 deletion src/CodeNav.OutOfProc/CodeNav.OutOfProc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

<ItemGroup>
<PackageReference Include="DebounceThrottle" Version="3.0.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="5.3.0" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Sdk" Version="17.14.40608" PrivateAssets="all" />
<PackageReference Include="Microsoft.VisualStudio.Extensibility.Build" Version="17.14.40608" PrivateAssets="all" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/CodeNav.OutOfProc/Constants/CodeItemKindEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ public enum CodeItemKindEnum
[EnumOrder(16)]
Event,

[EnumOrder(22)]
ExtensionBlock,

[EnumOrder(10)]
ImplementedInterface,

Expand Down
3 changes: 2 additions & 1 deletion src/CodeNav.OutOfProc/Languages/CSharp/Mappers/BaseMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ private static string MapFullName(SyntaxNode source, string name, SemanticModel
/// <returns>String display name</returns>
private static string MapName(SyntaxToken? identifier, NameSyntax? nameSyntax, string name = "")
{
if (identifier != null)
if (identifier != null &&
!identifier.Value.IsKind(SyntaxKind.None))
{
return identifier.Value.Text;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ SyntaxKind.RecordDeclaration when member is RecordDeclarationSyntax recordSyntax
=> RecordMapper.MapRecord(recordSyntax, semanticModel, codeDocumentViewModel),
SyntaxKind.StructDeclaration when member is StructDeclarationSyntax structSyntax
=> StructMapper.MapStruct(structSyntax, semanticModel, tree, codeDocumentViewModel),
SyntaxKind.ExtensionBlockDeclaration when member is ExtensionBlockDeclarationSyntax extensionBlockSyntax
=> ExtensionBlockMapper.MapExtensionBlock(extensionBlockSyntax, semanticModel, tree, codeDocumentViewModel),
_ => null,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using CodeNav.OutOfProc.Constants;
using CodeNav.OutOfProc.Mappers;
using CodeNav.OutOfProc.ViewModels;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.VisualStudio.Extensibility;

namespace CodeNav.OutOfProc.Languages.CSharp.Mappers;

public class ExtensionBlockMapper
{
public static CodeClassItem MapExtensionBlock(ExtensionBlockDeclarationSyntax member,
SemanticModel semanticModel, SyntaxTree tree, CodeDocumentViewModel codeDocumentViewModel)
{
var codeItem = BaseMapper.MapBase<CodeClassItem>(member, semanticModel, codeDocumentViewModel,
member.Identifier, modifiers: member.Modifiers, name: "Extension");
codeItem.Kind = CodeItemKindEnum.ExtensionBlock;
codeItem.Moniker = IconMapper.MapMoniker(codeItem.Kind, codeItem.Access);
codeItem.OverlayMoniker = ImageMoniker.KnownValues.OverlayLoginDisabled;
codeItem.Parameters = ParameterMapper.MapParameters(member.ParameterList);
codeItem.Tooltip = TooltipMapper.Map(member, codeItem.Access, string.Empty, codeItem.Name, codeItem.Parameters);

// Map regions
var regions = RegionMapper.MapRegions(tree, member.Span, codeDocumentViewModel);

// Map block members
foreach (var blockMember in member.Members)
{
var memberItem = DocumentMapper.MapMember(blockMember, tree, semanticModel, codeDocumentViewModel);

if (memberItem == null)
{
continue;
}

// Add member to region if it is part of one
if (RegionMapper.AddToRegion(regions, memberItem))
{
continue;
}

// Still here? Add the member to the block
codeItem.Members.Add(memberItem);
}

// Add regions to block
codeItem.Members.AddRange(regions);

return codeItem;
}
}
11 changes: 9 additions & 2 deletions src/CodeNav.OutOfProc/Languages/CSharp/Mappers/MethodMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ private static CodeItem MapMethod(SyntaxNode node, SyntaxToken identifier,

codeItem.Id = IdMapper.MapId(codeItem.FullName, parameterList);
codeItem.Kind = kind;
codeItem.Moniker = IconMapper.MapMoniker(codeItem.Kind, codeItem.Access);
codeItem.Moniker = IsExtensionMethod(node, semanticModel)
? ImageMoniker.KnownValues.ExtensionMethod
: IconMapper.MapMoniker(codeItem.Kind, codeItem.Access);

return codeItem;
}
Expand All @@ -70,8 +72,13 @@ public static CodeItem MapConstructor(ConstructorDeclarationSyntax member,
codeItem.Id = IdMapper.MapId(member.Identifier, member.ParameterList);
codeItem.Kind = CodeItemKindEnum.Constructor;
codeItem.Moniker = IconMapper.MapMoniker(codeItem.Kind, codeItem.Access);
codeItem.OverlayMoniker = ImageMoniker.KnownValues.Add;

return codeItem;
}

private static bool IsExtensionMethod(SyntaxNode node, SemanticModel semanticModel)
{
var symbol = semanticModel.GetDeclaredSymbol(node);
return symbol is IMethodSymbol { IsExtensionMethod: true };
}
}
6 changes: 4 additions & 2 deletions src/CodeNav.OutOfProc/Mappers/FilterRuleMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ or CodeItemKindEnum.Region
or CodeItemKindEnum.ImplementedInterface
or CodeItemKindEnum.Constructor
or CodeItemKindEnum.LocalFunction
or CodeItemKindEnum.BaseClass => [CodeItemAccessEnum.All],
or CodeItemKindEnum.BaseClass
or CodeItemKindEnum.ExtensionBlock => [CodeItemAccessEnum.All],
CodeItemKindEnum.Struct => [CodeItemAccessEnum.Public, CodeItemAccessEnum.Internal, CodeItemAccessEnum.Private, CodeItemAccessEnum.All],
_ => [.. Enum.GetValues<CodeItemAccessEnum>().Except([CodeItemAccessEnum.Unknown])],
};
Expand All @@ -29,7 +30,8 @@ or CodeItemKindEnum.Region
or CodeItemKindEnum.ImplementedInterface
or CodeItemKindEnum.Interface
or CodeItemKindEnum.Method
or CodeItemKindEnum.BaseClass => true,
or CodeItemKindEnum.BaseClass
or CodeItemKindEnum.ExtensionBlock => true,
_ => false,
};

Expand Down
4 changes: 3 additions & 1 deletion src/CodeNav.OutOfProc/Mappers/IconMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ public static ImageMoniker MapMoniker(CodeItemKindEnum kind, CodeItemAccessEnum
CodeItemKindEnum.BaseClass => "ClassShortcut",
CodeItemKindEnum.Class => $"Class{accessString}",
CodeItemKindEnum.Constant => $"Constant{accessString}",
CodeItemKindEnum.Constructor or CodeItemKindEnum.Method => $"Method{accessString}",
CodeItemKindEnum.Constructor => "NewMethod",
CodeItemKindEnum.Delegate => $"Delegate{accessString}",
CodeItemKindEnum.Enum => $"Enumeration{accessString}",
CodeItemKindEnum.EnumMember => $"EnumerationItem{accessString}",
CodeItemKindEnum.Event => $"Event{accessString}",
CodeItemKindEnum.ExtensionBlock => $"Class",
CodeItemKindEnum.ImplementedInterface => "ImplementInterface",
CodeItemKindEnum.Interface => $"Interface{accessString}",
CodeItemKindEnum.Method => $"Method{accessString}",
CodeItemKindEnum.Namespace => $"Namespace{accessString}",
CodeItemKindEnum.Property or CodeItemKindEnum.Indexer => $"Property{accessString}",
CodeItemKindEnum.Region => $"Numeric",
Expand Down
16 changes: 10 additions & 6 deletions src/CodeNav.OutOfProc/ToolWindows/Templates/CodeItemStyles.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,16 @@
HorizontalAlignment="Stretch">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<vs:Image
Source="{Binding Moniker}"
Width="16"
Height="16"
Margin="0 0 3 0"
VerticalAlignment="Center" />
<Grid Width="17" Height="17">
<vs:Image Source="{Binding Moniker}"
Width="16" Height="16"
HorizontalAlignment="Left" VerticalAlignment="Top"
Panel.ZIndex="0" />
<vs:Image Source="{Binding OverlayMoniker}"
Width="14" Height="14"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Panel.ZIndex="1" />
</Grid>
<TextBlock
FontSize="{Binding FontSize}"
VerticalAlignment="Center">
Expand Down
2 changes: 2 additions & 0 deletions test/CodeNav.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<TargetFramework>net8.0-windows8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>14</LangVersion>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
Expand Down
16 changes: 16 additions & 0 deletions test/Files/ExtensionBlock/TestExtensionBlock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace CodeNav.Test.Files.ExtensionBlock;

public static class MyExtensions
{
public static IEnumerable<int> ValuesLessThan(this IEnumerable<int> source, int threshold)
=> source.Where(x => x < threshold);

extension(IEnumerable<int> source)
{
public IEnumerable<int> ValuesGreaterThan(int threshold)
=> source.Where(x => x > threshold);

public IEnumerable<int> ValuesGreaterThanZero
=> source.ValuesGreaterThan(0);
}
}
21 changes: 21 additions & 0 deletions test/MapperTests/MapperTestExtensionBlock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace CodeNav.Test.MapperTests;

[TestFixture]
internal class MapperTestExtensionBlock : BaseTest
{
[Test]
public async Task TestInlineBaseClassShouldBeOk()
{
var codeItems = await MapToCodeItems("ExtensionBlock/TestExtensionBlock.cs");

// First item should be a namespace
var namespaceItem = GetNamespace(codeItems);

var classItem = GetFirstClass(namespaceItem);

var extensionBlockItem = GetMemberAtIndex(classItem, 1) as CodeClassItem;

// Extension block item should have 2 members
Assert.That(extensionBlockItem!.Members, Has.Count.EqualTo(2));
}
}
Loading