Skip to content
Open
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
4 changes: 2 additions & 2 deletions ApprovalTestTool/ApprovalTestTool.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CodeParser\CodeParser.csproj" />
<ProjectReference Include="..\CodeGraph\CodeGraph.csproj" />
<ProjectReference Include="..\CSharpCodeAnalyst.CodeGraph\CSharpCodeAnalyst.CodeGraph.csproj" />
<ProjectReference Include="..\CSharpCodeAnalyst.CodeParser\CSharpCodeAnalyst.CodeParser.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions ApprovalTestTool/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Reflection;
using CodeParser.Parser;
using CodeParser.Parser.Config;
using CSharpCodeAnalyst.CodeParser.Parser;
using CSharpCodeAnalyst.CodeParser.Parser.Config;
using LibGit2Sharp;

namespace ApprovalTestTool;
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,4 @@ The ~200-element soft limit (`AppSettings.WarningCodeElementLimit`) still applie

- `.editorconfig` is authoritative and ReSharper-tuned: braces required on all `if`/`foreach`/`while`, max line length 199, expression-bodied accessors preferred, `internal` first in modifier order. Analyzer severities default to `none` — do not add warning-as-error enforcement without discussion.
- Nullable reference types are enabled everywhere; honour the annotations rather than suppressing with `!`.
- Namespaces match folders. `CodeGraph.Graph.CodeGraph` is a class inside the `CodeGraph` assembly — fully-qualify it (`CodeGraph.Graph.CodeGraph`) in places where the namespace/type collision is ambiguous; existing code already does.
- Namespaces match folders, rooted under `CSharpCodeAnalyst.*` for every project (e.g. `CSharpCodeAnalyst.CodeGraph.Graph`, `CSharpCodeAnalyst.CodeParser.Parser`). `CodeGraph` is a class inside `CSharpCodeAnalyst.CodeGraph.Graph` — fully-qualify it (`CSharpCodeAnalyst.CodeGraph.Graph.CodeGraph`) in places where the namespace/type collision is ambiguous; existing code already does.
26 changes: 26 additions & 0 deletions CSharpCodeAnalyst.AnalyzerSdk/CSharpCodeAnalyst.AnalyzerSdk.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<!-- Moved files keep their original CSharpCodeAnalyst.* namespaces; RootNamespace must match
so those namespaces (and any embedded resource manifest names) still line up. -->
<RootNamespace>CSharpCodeAnalyst.AnalyzerSdk</RootNamespace>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\CSharpCodeAnalyst.CodeGraph\CSharpCodeAnalyst.CodeGraph.csproj" />
</ItemGroup>

<ItemGroup>
<Resource Include="Resources\blue-info_16.png" />
<Resource Include="Resources\error.png" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.Build.Framework" Version="18.7.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CSharpCodeAnalyst.Shared.Contracts;
namespace CSharpCodeAnalyst.AnalyzerSdk.Contracts;

public interface IAnalyzer
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CSharpCodeAnalyst.Shared.Contracts;
namespace CSharpCodeAnalyst.AnalyzerSdk.Contracts;

public interface IPublisher
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CSharpCodeAnalyst.Shared.DynamicDataGrid.Contracts.TabularData;
namespace CSharpCodeAnalyst.AnalyzerSdk.DynamicDataGrid.Contracts.TabularData;

/// <summary>
/// Available column types for the dynamic data grid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Windows.Input;
using System.Windows.Markup;

namespace CSharpCodeAnalyst.Shared.DynamicDataGrid.Contracts.TabularData;
namespace CSharpCodeAnalyst.AnalyzerSdk.DynamicDataGrid.Contracts.TabularData;

/// <summary>
/// Main interface for table data.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Collections;
using System.Windows.Input;
using System.Windows.Input;

namespace CSharpCodeAnalyst.Shared.DynamicDataGrid.Contracts.TabularData;
namespace CSharpCodeAnalyst.AnalyzerSdk.DynamicDataGrid.Contracts.TabularData;

public class TableColumnDefinition
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace CSharpCodeAnalyst.Shared.DynamicDataGrid.Contracts.TabularData;
namespace CSharpCodeAnalyst.AnalyzerSdk.DynamicDataGrid.Contracts.TabularData;

public abstract class TableRow : INotifyPropertyChanged
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using CodeGraph.Graph;

using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Shared.Messages;
namespace CSharpCodeAnalyst.AnalyzerSdk.Messages;

public class AddNodeToGraphRequest
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.AnalyzerSdk.Messages;

public class OpenSourceLocationRequest(SourceLocation location)
{
public SourceLocation Location { get; } = location;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CodeGraph.Graph;
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Shared.Messages;
namespace CSharpCodeAnalyst.AnalyzerSdk.Messages;

public class ShowPartitionsRequest
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CSharpCodeAnalyst.Shared.DynamicDataGrid.Contracts.TabularData;
using CSharpCodeAnalyst.AnalyzerSdk.DynamicDataGrid.Contracts.TabularData;

namespace CSharpCodeAnalyst.Shared.Messages;
namespace CSharpCodeAnalyst.AnalyzerSdk.Messages;

/// <summary>
/// Requests a dynamic result tab. <see cref="Id" /> keys the tab: publishing again under the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CSharpCodeAnalyst.Shared.Notifications;
namespace CSharpCodeAnalyst.AnalyzerSdk.Notifications;

public interface IUserNotification
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Text;
using System.Text.RegularExpressions;

namespace CSharpCodeAnalyst.Shared.Search;
namespace CSharpCodeAnalyst.AnalyzerSdk.Search;

public static class PascalCaseSearch
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System.Text.RegularExpressions;
using CodeGraph.Graph;
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Shared.Search;
namespace CSharpCodeAnalyst.AnalyzerSdk.Search;

/// <summary>
/// Helper to build (very) simple search expressions with AND/OR/TERM
/// </summary>
internal interface IExpression
public interface IExpression
{
bool Evaluate(CodeElement? item);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace CSharpCodeAnalyst.Shared.Search;
namespace CSharpCodeAnalyst.AnalyzerSdk.Search;

internal static class SearchExpressionFactory
public static class SearchExpressionFactory
{
private static Term CreateTerm(string search, TextSearchField searchField)
{
Expand Down Expand Up @@ -39,7 +39,7 @@ public static IExpression CreateSearchExpression(string searchText, TextSearchFi
return root;
}

internal enum TextSearchField
public enum TextSearchField
{
FullName,
Name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Setter Property="ToolTipService.InitialShowDelay" Value="100"/>
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Source" Value="/Resources/blue-info_16.png" />
<Setter Property="Source" Value="/CSharpCodeAnalyst.AnalyzerSdk;component/Resources/blue-info_16.png" />
<Setter Property="Margin" Value="2 0 2 0" />
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
Expand Down
60 changes: 60 additions & 0 deletions CSharpCodeAnalyst.AnalyzerSdk/Wpf/IconLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Reflection;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace CSharpCodeAnalyst.AnalyzerSdk.Wpf;

public static class IconLoader
{
private static readonly Dictionary<string, ImageSource?> IconCache = new();

/// <summary>
/// Loads an icon embedded as a WPF "Resource" in the calling assembly (e.g. the host or an
/// analyzer plugin), not necessarily the entry assembly - so each assembly can ship its own
/// icons without depending on another assembly's resources.
/// </summary>
public static ImageSource? LoadIcon(string iconPath)
{
var assemblyName = Assembly.GetCallingAssembly().GetName().Name;
return LoadIcon(assemblyName, iconPath);
}

/// <summary>
/// Loads an icon embedded as a WPF "Resource" in the given assembly - use this for icons
/// shared across assemblies (e.g. SDK icons referenced by an analyzer plugin).
/// </summary>
public static ImageSource? LoadIcon(string? assemblyName, string iconPath)
{
try
{
var cacheKey = $"{assemblyName}|{iconPath}";

if (IconCache.TryGetValue(cacheKey, out var icon))
{
return icon;
}

var bitmap = Load(assemblyName, iconPath);

IconCache[cacheKey] = bitmap;
return bitmap;
}
catch
{
return null;
}
}

private static BitmapImage Load(string? assemblyName, string iconPath)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri($"pack://application:,,,/{assemblyName};component/{iconPath}");
bitmap.DecodePixelWidth = 16;
bitmap.DecodePixelHeight = 16;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Windows.Input;

namespace CSharpCodeAnalyst.Shared.Wpf;
namespace CSharpCodeAnalyst.AnalyzerSdk.Wpf;

public class WpfCommand : ICommand
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
using System.IO;
using System.Text.Json;
using System.Windows;
using CodeGraph.Graph;
using CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Presentation;
using CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Rules;
using CSharpCodeAnalyst.Resources;
using CSharpCodeAnalyst.Shared.Contracts;
using CSharpCodeAnalyst.Shared.Messages;
using CSharpCodeAnalyst.Shared.Notifications;
using CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Presentation;
using CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Rules;
using CSharpCodeAnalyst.Analyzers.Resources;
using CSharpCodeAnalyst.AnalyzerSdk.Contracts;
using CSharpCodeAnalyst.AnalyzerSdk.Messages;
using CSharpCodeAnalyst.AnalyzerSdk.Notifications;
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules;
namespace CSharpCodeAnalyst.Analyzers.ArchitecturalRules;

public class Analyzer : IAnalyzer
{
Expand Down Expand Up @@ -115,8 +115,10 @@ public void SetPersistentData(string? data)
var persistentData = JsonSerializer.Deserialize<PersistenceData>(data);
if (persistentData != null)
{
var rulesText = persistentData.RulesText ?? string.Empty;
ParseAndStoreRules(rulesText);
// Set directly instead of going through ParseAndStoreRules: loading a saved
// project is not a user edit and must not mark the analyzer dirty.
_rulesText = persistentData.RulesText ?? string.Empty;
_rules = RuleParser.ParseRules(_rulesText);
}
}
catch (Exception ex)
Expand All @@ -127,6 +129,8 @@ public void SetPersistentData(string? data)
_rulesText = string.Empty;
_rules.Clear();
}

SetDirty(false);
}

public bool IsDirty()
Expand Down Expand Up @@ -163,7 +167,7 @@ private void OnValidateRules(string rulesText)
else
{
// Show violations in tabular format
var violationsViewModel = new RuleViolationsViewModel(violations, _currentGraph);
var violationsViewModel = new RuleViolationsViewModel(violations, _currentGraph, _messaging);
_messaging.Publish(new ShowTabularDataRequest(Id, Name, violationsViewModel));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CodeGraph.Graph;
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules;
namespace CSharpCodeAnalyst.Analyzers.ArchitecturalRules;

public static class PatternMatcher
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules;
namespace CSharpCodeAnalyst.Analyzers.ArchitecturalRules;

public class PersistenceData
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Window x:Class="CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Presentation.ArchitecturalRulesDialog"
<Window x:Class="CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Presentation.ArchitecturalRulesDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resources="clr-namespace:CSharpCodeAnalyst.Resources"
xmlns:resources="clr-namespace:CSharpCodeAnalyst.Analyzers.Resources"
mc:Ignorable="d"
Title="{x:Static resources:Strings.ArchitecturalRules_Title}"
Height="600" Width="800"
Expand All @@ -14,7 +14,7 @@
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/ImageStyles.xaml" />
<ResourceDictionary Source="/CSharpCodeAnalyst.AnalyzerSdk;component/Styles/ImageStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using CSharpCodeAnalyst.Resources;
using CSharpCodeAnalyst.Analyzers.Resources;
using Microsoft.Win32;

namespace CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Presentation;
namespace CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Presentation;

public partial class ArchitecturalRulesDialog : INotifyPropertyChanged
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using CodeGraph.Graph;
using CSharpCodeAnalyst.CodeGraph.Graph;

namespace CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Presentation;
namespace CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Presentation;

/// <summary>
/// A line in the detail view. Note a view model is created for each source location in a relationship.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:presentation="clr-namespace:CSharpCodeAnalyst.Features.Analyzers.ArchitecturalRules.Presentation"
xmlns:presentation="clr-namespace:CSharpCodeAnalyst.Analyzers.ArchitecturalRules.Presentation"
mc:Ignorable="d">
<ItemsControl
d:DataContext="{d:DesignInstance presentation:RuleViolationViewModel }"
Expand Down
Loading