Browse Source

Merge pull request #11029 from AvaloniaUI/include-analyzers-in-the-main-package

Include analyzers in the main package
pull/11158/head
Max Katz 3 years ago
committed by GitHub
parent
commit
4455d373ec
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      .editorconfig
  2. 2
      Avalonia.sln
  3. 2
      build/DevAnalyzers.props
  4. 5
      nukebuild/numerge.config
  5. 4
      packages/Avalonia/Avalonia.csproj
  6. 11
      samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
  7. 1
      samples/IntegrationTestApp/IntegrationTestApp.csproj
  8. 2
      src/Avalonia.Base/ClassBindingManager.cs
  9. 2
      src/Avalonia.Base/Media/DashStyle.cs
  10. 2
      src/Avalonia.Base/Media/GradientBrush.cs
  11. 2
      src/Avalonia.Base/Media/PolyLineSegment.cs
  12. 2
      src/Avalonia.Base/Media/TransformGroup.cs
  13. 1
      src/Avalonia.Base/StyledElement.cs
  14. 4
      src/Avalonia.Base/Styling/ThemeVariant.cs
  15. 1
      src/Avalonia.Base/Visual.cs
  16. 2
      src/Avalonia.Controls/Application.cs
  17. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  18. 2
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteFilterMode.cs
  19. 2
      src/Avalonia.Controls/ColumnDefinition.cs
  20. 2
      src/Avalonia.Controls/ContextMenu.cs
  21. 12
      src/Avalonia.Controls/DefinitionBase.cs
  22. 2
      src/Avalonia.Controls/Documents/Span.cs
  23. 2
      src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs
  24. 4
      src/Avalonia.Controls/LayoutTransformControl.cs
  25. 8
      src/Avalonia.Controls/ListBox.cs
  26. 6
      src/Avalonia.Controls/MenuItem.cs
  27. 2
      src/Avalonia.Controls/Primitives/UniformGrid.cs
  28. 3
      src/Avalonia.Controls/Primitives/VisualLayerManager.cs
  29. 1
      src/Avalonia.Controls/PullToRefresh/RefreshVisualizer.cs
  30. 4
      src/Avalonia.Controls/RowDefinition.cs
  31. 2
      src/Avalonia.Controls/SplitView/SplitViewTemplateSettings.cs
  32. 2
      src/Avalonia.Controls/TabControl.cs
  33. 4
      src/Avalonia.Controls/TabItem.cs
  34. 2
      src/Avalonia.Controls/ToggleSwitch.cs
  35. 4
      src/Avalonia.Controls/TopLevel.cs
  36. 4
      src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs
  37. 1
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  38. 1
      src/Avalonia.ReactiveUI/ReactiveUserControl.cs
  39. 1
      src/Avalonia.ReactiveUI/ReactiveWindow.cs
  40. 1
      src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj
  41. 25
      src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml
  42. 1
      src/Avalonia.Themes.Simple/Avalonia.Themes.Simple.csproj
  43. 22
      src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj
  44. 0
      src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs
  45. 24
      src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.cs
  46. 8
      src/tools/Avalonia.Analyzers/GlobalSuppressions.cs
  47. 59
      src/tools/Avalonia.Analyzers/OnPropertyChangedOverrideAnalyzer.cs
  48. 2
      src/tools/Avalonia.Generators/GeneratorContextExtensions.cs
  49. 17
      src/tools/PublicAnalyzers/Avalonia.Analyzers.csproj

17
.editorconfig

@ -186,6 +186,23 @@ csharp_wrap_before_ternary_opsigns = false
# Avalonia DevAnalyzer preferences
dotnet_diagnostic.AVADEV2001.severity = error
# Avalonia PublicAnalyzer preferences
dotnet_diagnostic.AVP1000.severity = error
dotnet_diagnostic.AVP1001.severity = error
dotnet_diagnostic.AVP1002.severity = error
dotnet_diagnostic.AVP1010.severity = error
dotnet_diagnostic.AVP1011.severity = error
dotnet_diagnostic.AVP1012.severity = warning
dotnet_diagnostic.AVP1013.severity = error
dotnet_diagnostic.AVP1020.severity = error
dotnet_diagnostic.AVP1021.severity = error
dotnet_diagnostic.AVP1022.severity = error
dotnet_diagnostic.AVP1030.severity = error
dotnet_diagnostic.AVP1031.severity = error
dotnet_diagnostic.AVP1032.severity = error
dotnet_diagnostic.AVP1040.severity = error
dotnet_diagnostic.AVA2001.severity = error
# Xaml files
[*.{xaml,axaml}]
indent_size = 2

2
Avalonia.sln

@ -233,7 +233,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUIDemo", "samples\R
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GpuInterop", "samples\GpuInterop\GpuInterop.csproj", "{C810060E-3809-4B74-A125-F11533AF9C1B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Analyzers", "src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj", "{C692FE73-43DB-49CE-87FC-F03ED61F25C9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{176582E8-46AF-416A-85C1-13A5C6744497}"
ProjectSection(SolutionItems) = preProject

2
build/DevAnalyzers.props

@ -5,7 +5,7 @@
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"
SetTargetFramework="TargetFramework=netstandard2.0"/>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\PublicAnalyzers\Avalonia.Analyzers.csproj"
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
PrivateAssets="all"
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"

5
nukebuild/numerge.config

@ -16,6 +16,11 @@
"Id": "Avalonia.Generators",
"IgnoreMissingFrameworkBinaries": true,
"DoNotMergeDependencies": true
},
{
"Id": "Avalonia.Analyzers",
"IgnoreMissingFrameworkBinaries": true,
"DoNotMergeDependencies": true
}
]
}

4
packages/Avalonia/Avalonia.csproj

@ -16,6 +16,10 @@
ReferenceOutputAssembly="false"
PrivateAssets="all"
OutputItemType="Analyzer" />
<ProjectReference Include="..\..\src\tools\Avalonia.Analyzers\Avalonia.Analyzers.csproj"
ReferenceOutputAssembly="false"
PrivateAssets="all"
OutputItemType="Analyzer" />
</ItemGroup>
<PropertyGroup>

11
samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs

@ -19,18 +19,16 @@ namespace ControlCatalog.Pages
public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
public static readonly StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
public static readonly StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation),
coerce: (_, val) => val % (Math.PI * 2));
/// <summary>
/// Rotation, measured in Radians!
/// </summary>
public double Rotation
{
get => GetValue(RotationProperty);
set
{
double valueToUse = value % (Math.PI * 2);
SetValue(RotationProperty, valueToUse);
}
set => SetValue(RotationProperty, value);
}
public static readonly StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
@ -213,5 +211,6 @@ namespace ControlCatalog.Pages
return workingPoint;
}
}
}

1
samples/IntegrationTestApp/IntegrationTestApp.csproj

@ -3,6 +3,7 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);AVP1012</NoWarn>
</PropertyGroup>
<PropertyGroup>

2
src/Avalonia.Base/ClassBindingManager.cs

@ -17,6 +17,8 @@ namespace Avalonia
return target.Bind(prop, source, anchor);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1001:The same AvaloniaProperty should not be registered twice",
Justification = "Classes.attr binding feature is implemented using intermediate avalonia properties for each class")]
private static AvaloniaProperty RegisterClassProxyProperty(string className)
{
var prop = AvaloniaProperty.Register<StyledElement, bool>("__AvaloniaReserved::Classes::" + className);

2
src/Avalonia.Base/Media/DashStyle.cs

@ -44,6 +44,8 @@ namespace Avalonia.Media
/// </summary>
/// <param name="dashes">The dashes collection.</param>
/// <param name="offset">The dash sequence offset.</param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public DashStyle(IEnumerable<double>? dashes, double offset)
{
Dashes = (dashes as AvaloniaList<double>) ?? new AvaloniaList<double>(dashes ?? Array.Empty<double>());

2
src/Avalonia.Base/Media/GradientBrush.cs

@ -38,6 +38,8 @@ namespace Avalonia.Media
/// <summary>
/// Initializes a new instance of the <see cref="GradientBrush"/> class.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public GradientBrush()
{
this.GradientStops = new GradientStops();

2
src/Avalonia.Base/Media/PolyLineSegment.cs

@ -28,6 +28,8 @@ namespace Avalonia.Media
/// <summary>
/// Initializes a new instance of the <see cref="PolyLineSegment"/> class.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public PolyLineSegment()
{
Points = new Points();

2
src/Avalonia.Base/Media/TransformGroup.cs

@ -11,6 +11,8 @@ namespace Avalonia.Media
public static readonly StyledProperty<Transforms> ChildrenProperty =
AvaloniaProperty.Register<TransformGroup, Transforms>(nameof(Children));
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public TransformGroup()
{
Children = new Transforms();

1
src/Avalonia.Base/StyledElement.cs

@ -289,6 +289,7 @@ namespace Avalonia
public StyledElement? Parent { get; private set; }
/// <inheritdoc />
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1030:StyledProperty accessors should not have side effects", Justification = "False positive?")]
public ThemeVariant ActualThemeVariant => GetValue(ThemeVariant.ActualThemeVariantProperty);
/// <summary>

4
src/Avalonia.Base/Styling/ThemeVariant.cs

@ -9,6 +9,10 @@ namespace Avalonia.Styling;
/// Specifies a UI theme variant that should be used for the Control and Application types.
/// </summary>
[TypeConverter(typeof(ThemeVariantTypeConverter))]
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010:AvaloniaProperty objects should be owned by the type in which they are stored",
Justification = "ActualThemeVariant and RequestedThemeVariant properties are shared Avalonia.Base and Avalonia.Controls projects," +
"but shouldn't be visible on the StyledElement class." +
"Ideally we woould introduce readonly styled properties.")]
public sealed record ThemeVariant
{
/// <summary>

1
src/Avalonia.Base/Visual.cs

@ -329,6 +329,7 @@ namespace Avalonia
/// <summary>
/// Gets the control's parent visual.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "GetVisualParent extension method is supposed to be used instead.")]
internal Visual? VisualParent => _visualParent;
/// <summary>

2
src/Avalonia.Controls/Application.cs

@ -94,6 +94,8 @@ namespace Avalonia
}
/// <inheritdoc />
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1031", Justification = "This property is supposed to be a styled readonly property.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1030", Justification = "False positive.")]
public ThemeVariant ActualThemeVariant => GetValue(ActualThemeVariantProperty);
/// <summary>

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -2042,6 +2042,8 @@ namespace Avalonia.Controls
/// <summary>
/// Identifies the Value dependency property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002:AvaloniaProperty objects should not be owned by a generic type",
Justification = "This property is not supposed to be used from XAML.")]
public static readonly StyledProperty<T> ValueProperty =
AvaloniaProperty.Register<BindingEvaluator<T>, T>(nameof(Value));

2
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteFilterMode.cs

@ -9,7 +9,7 @@ namespace Avalonia.Controls
{
/// <summary>
/// Specifies how text in the text box portion of the <see cref="AutoCompleteBox" />
/// control is used to filter items specified by the <see cref="AutoCompleteBox.Items" />
/// control is used to filter items specified by the <see cref="AutoCompleteBox.ItemsSource" />
/// property for display in the drop-down.
/// </summary>
public enum AutoCompleteFilterMode

2
src/Avalonia.Controls/ColumnDefinition.cs

@ -46,8 +46,8 @@ namespace Avalonia.Controls
/// <param name="value">The width of the column.</param>
/// <param name="type">The width unit of the column.</param>
public ColumnDefinition(double value, GridUnitType type)
: this(new GridLength(value, type))
{
Width = new GridLength(value, type);
}
/// <summary>

2
src/Avalonia.Controls/ContextMenu.cs

@ -56,6 +56,8 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="Placement"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1013",
Justification = "We keep PlacementModeProperty for backward compatibility.")]
public static readonly StyledProperty<PlacementMode> PlacementProperty =
Popup.PlacementProperty.AddOwner<ContextMenu>();

12
src/Avalonia.Controls/DefinitionBase.cs

@ -37,7 +37,7 @@ namespace Avalonia.Controls
{
// start with getting SharedSizeGroup value.
// this property is NOT inherited which should result in better overall perf.
if (SharedSizeGroup is { } sharedSizeGroupId && PrivateSharedSizeScope is { } privateSharedSizeScope)
if (SharedSizeGroup is { } sharedSizeGroupId && GetValue(PrivateSharedSizeScopeProperty) is { } privateSharedSizeScope)
{
_sharedState = privateSharedSizeScope.EnsureSharedState(sharedSizeGroupId);
_sharedState.AddMember(this);
@ -333,7 +333,7 @@ namespace Avalonia.Controls
if (definition._sharedState == null
&& sharedSizeGroupId != null
&& definition.PrivateSharedSizeScope is { } privateSharedSizeScope)
&& definition.GetValue(PrivateSharedSizeScopeProperty) is { } privateSharedSizeScope)
{
// if definition is not registered and both: shared size group id AND private shared scope
// are available, then register definition.
@ -412,14 +412,6 @@ namespace Avalonia.Controls
}
}
/// <summary>
/// Private getter of shared state collection dynamic property.
/// </summary>
private SharedSizeScope? PrivateSharedSizeScope
{
get { return GetValue(PrivateSharedSizeScopeProperty); }
}
/// <summary>
/// Convenience accessor to UseSharedMinimum flag
/// </summary>

2
src/Avalonia.Controls/Documents/Span.cs

@ -18,6 +18,8 @@ namespace Avalonia.Controls.Documents
AvaloniaProperty.Register<Span, InlineCollection>(
nameof(Inlines));
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "Collection properties shouldn't be set with SetCurrentValue.")]
public Span()
{
Inlines = new InlineCollection

2
src/Avalonia.Controls/Flyouts/PopupFlyoutBase.cs

@ -44,7 +44,7 @@ namespace Avalonia.Controls.Primitives
/// Defines the <see cref="OverlayInputPassThroughElement"/> property
/// </summary>
public static readonly StyledProperty<IInputElement?> OverlayInputPassThroughElementProperty =
Popup.OverlayInputPassThroughElementProperty.AddOwner<FlyoutBase>();
Popup.OverlayInputPassThroughElementProperty.AddOwner<PopupFlyoutBase>();
private readonly Lazy<Popup> _popupLazy;
private Rect? _enlargedPopupRect;

4
src/Avalonia.Controls/LayoutTransformControl.cs

@ -63,7 +63,7 @@ namespace Avalonia.Controls
{
if (TransformRoot == null || LayoutTransform == null)
{
LayoutTransform = RenderTransform;
SetCurrentValue(LayoutTransformProperty, RenderTransform);
return base.ArrangeOverride(finalSize);
}
@ -176,7 +176,7 @@ namespace Avalonia.Controls
else
{
_renderTransformChangedEvent?.Dispose();
LayoutTransform = null;
ClearValue(LayoutTransformProperty);
}
}
}

8
src/Avalonia.Controls/ListBox.cs

@ -29,18 +29,24 @@ namespace Avalonia.Controls
/// <summary>
/// Defines the <see cref="SelectedItems"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new DirectProperty<SelectingItemsControl, IList?> SelectedItemsProperty =
SelectingItemsControl.SelectedItemsProperty;
/// <summary>
/// Defines the <see cref="Selection"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new DirectProperty<SelectingItemsControl, ISelectionModel> SelectionProperty =
SelectingItemsControl.SelectionProperty;
/// <summary>
/// Defines the <see cref="SelectionMode"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public static readonly new StyledProperty<SelectionMode> SelectionModeProperty =
SelectingItemsControl.SelectionModeProperty;
@ -84,6 +90,8 @@ namespace Avalonia.Controls
/// Note that the selection mode only applies to selections made via user interaction.
/// Multiple selections can be made programmatically regardless of the value of this property.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "This property is owned by SelectingItemsControl, but protected there. ListBox changes its visibility.")]
public new SelectionMode SelectionMode
{
get { return base.SelectionMode; }

6
src/Avalonia.Controls/MenuItem.cs

@ -53,12 +53,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<KeyGesture?> InputGestureProperty =
AvaloniaProperty.Register<MenuItem, KeyGesture?>(nameof(InputGesture));
/// <summary>
/// Defines the <see cref="IsSelected"/> property.
/// </summary>
public static readonly StyledProperty<bool> IsSelectedProperty =
SelectingItemsControl.IsSelectedProperty.AddOwner<MenuItem>();
/// <summary>
/// Defines the <see cref="IsSubMenuOpen"/> property.
/// </summary>

2
src/Avalonia.Controls/Primitives/UniformGrid.cs

@ -123,7 +123,7 @@ namespace Avalonia.Controls.Primitives
if (FirstColumn >= Columns)
{
FirstColumn = 0;
SetCurrentValue(FirstColumnProperty, 0);
}
var itemCount = FirstColumn;

3
src/Avalonia.Controls/Primitives/VisualLayerManager.cs

@ -29,6 +29,9 @@ namespace Avalonia.Controls.Primitives
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1030")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1031",
Justification = "A hack to make ChromeOverlayLayer lazily creatable. It is expected that GetValue(ChromeOverlayLayerProperty) alone won't work.")]
public ChromeOverlayLayer ChromeOverlayLayer
{
get

1
src/Avalonia.Controls/PullToRefresh/RefreshVisualizer.cs

@ -71,6 +71,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets a value that indicates the refresh state of the visualizer.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "False positive")]
protected RefreshVisualizerState RefreshVisualizerState
{
get

4
src/Avalonia.Controls/RowDefinition.cs

@ -46,8 +46,8 @@ namespace Avalonia.Controls
/// <param name="value">The height of the row.</param>
/// <param name="type">The height unit of the column.</param>
public RowDefinition(double value, GridUnitType type)
: this(new GridLength(value, type))
{
Height = new GridLength(value, type);
}
/// <summary>
@ -56,7 +56,7 @@ namespace Avalonia.Controls
/// <param name="height">The height of the column.</param>
public RowDefinition(GridLength height)
{
Height = height;
SetCurrentValue(HeightProperty, height);
}
/// <summary>

2
src/Avalonia.Controls/SplitView/SplitViewTemplateSettings.cs

@ -17,12 +17,14 @@
AvaloniaProperty.Register<SplitViewTemplateSettings, GridLength>(
nameof(PaneColumnGridLength));
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public double ClosedPaneWidth
{
get => GetValue(ClosedPaneWidthProperty);
internal set => SetValue(ClosedPaneWidthProperty, value);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public GridLength PaneColumnGridLength
{
get => GetValue(PaneColumnGridLengthProperty);

2
src/Avalonia.Controls/TabControl.cs

@ -115,6 +115,7 @@ namespace Avalonia.Controls
/// <value>
/// The content of the selected tab.
/// </value>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public object? SelectedContent
{
get { return GetValue(SelectedContentProperty); }
@ -127,6 +128,7 @@ namespace Avalonia.Controls
/// <value>
/// The content template of the selected tab.
/// </value>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1032", Justification = "This property is supposed to be a styled readonly property.")]
public IDataTemplate? SelectedContentTemplate
{
get { return GetValue(SelectedContentTemplateProperty); }

4
src/Avalonia.Controls/TabItem.cs

@ -42,6 +42,8 @@ namespace Avalonia.Controls
/// <value>
/// The tab strip placement.
/// </value>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1031",
Justification = "This property is supposed to be inherited only and settable on parent TabControl.")]
public Dock TabStripPlacement
{
get { return GetValue(TabStripPlacementProperty); }
@ -83,7 +85,7 @@ namespace Avalonia.Controls
{
Header = obj.NewValue;
}
}
}
}
}
}

2
src/Avalonia.Controls/ToggleSwitch.cs

@ -201,7 +201,7 @@ namespace Avalonia.Controls
}
else
{
IsChecked = shouldBecomeChecked;
SetCurrentValue(IsCheckedProperty, shouldBecomeChecked);
}
}
else

4
src/Avalonia.Controls/TopLevel.cs

@ -83,11 +83,11 @@ namespace Avalonia.Controls
/// <inheritdoc cref="ThemeVariantScope.ActualThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant> ActualThemeVariantProperty =
ThemeVariantScope.ActualThemeVariantProperty.AddOwner<Application>();
ThemeVariantScope.ActualThemeVariantProperty.AddOwner<TopLevel>();
/// <inheritdoc cref="ThemeVariantScope.RequestedThemeVariantProperty" />
public static readonly StyledProperty<ThemeVariant?> RequestedThemeVariantProperty =
ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<Application>();
ThemeVariantScope.RequestedThemeVariantProperty.AddOwner<TopLevel>();
/// <summary>
/// Defines the SystemBarColor attached property.

4
src/Avalonia.Diagnostics/Diagnostics/Controls/Application.cs

@ -37,7 +37,7 @@ namespace Avalonia.Diagnostics.Controls
_ => null
};
RequestedThemeVariant = application.RequestedThemeVariant;
SetCurrentValue(RequestedThemeVariantProperty, application.RequestedThemeVariant);
_application.PropertyChanged += ApplicationOnPropertyChanged;
}
@ -131,7 +131,7 @@ namespace Avalonia.Diagnostics.Controls
{
if (e.Property == Avalonia.Application.RequestedThemeVariantProperty)
{
RequestedThemeVariant = e.GetNewValue<ThemeVariant>();
SetCurrentValue(RequestedThemeVariantProperty, e.GetNewValue<ThemeVariant>());
}
}

1
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@ -12,4 +12,5 @@
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\NullableEnable.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" />
</Project>

1
src/Avalonia.ReactiveUI/ReactiveUserControl.cs

@ -17,6 +17,7 @@ namespace Avalonia.ReactiveUI
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveUserControl<TViewModel> : UserControl, IViewFor<TViewModel> where TViewModel : class
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002", Justification = "Generic avalonia property is expected here.")]
public static readonly StyledProperty<TViewModel?> ViewModelProperty = AvaloniaProperty
.Register<ReactiveUserControl<TViewModel>, TViewModel?>(nameof(ViewModel));

1
src/Avalonia.ReactiveUI/ReactiveWindow.cs

@ -17,6 +17,7 @@ namespace Avalonia.ReactiveUI
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveWindow<TViewModel> : Window, IViewFor<TViewModel> where TViewModel : class
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1002", Justification = "Generic avalonia property is expected here.")]
public static readonly StyledProperty<TViewModel?> ViewModelProperty = AvaloniaProperty
.Register<ReactiveWindow<TViewModel>, TViewModel?>(nameof(ViewModel));

1
src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj

@ -15,4 +15,5 @@
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" />
</Project>

25
src/Avalonia.Themes.Fluent/Controls/AutoCompleteBox.xaml

@ -1,18 +1,21 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:generic="using:System.Collections.Generic">
<Design.PreviewWith>
<Border Padding="20">
<AutoCompleteBox Width="200">
<AutoCompleteBox.Items>
Alabama
Alaska
Arizona
Arkansas
California
Colorado
Connecticut
Delaware
</AutoCompleteBox.Items>
<AutoCompleteBox.ItemsSource>
<generic:List x:TypeArguments="x:String">
Alabama
Alaska
Arizona
Arkansas
California
Colorado
Connecticut
Delaware
</generic:List>
</AutoCompleteBox.ItemsSource>
</AutoCompleteBox>
</Border>
</Design.PreviewWith>

1
src/Avalonia.Themes.Simple/Avalonia.Themes.Simple.csproj

@ -15,4 +15,5 @@
<Import Project="..\..\build\BuildTargets.targets" />
<Import Project="..\..\build\ApiDiff.props" />
<Import Project="..\..\build\TrimmingEnable.props" />
<Import Project="..\..\build\DevAnalyzers.props" />
</Project>

22
src/tools/Avalonia.Analyzers/Avalonia.Analyzers.csproj

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<IncludeBuildOutput>false</IncludeBuildOutput>
<PackageId>Avalonia.Analyzers</PackageId>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
<IsPackable>true</IsPackable>
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" PrivateAssets="all"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.9.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
<Import Project="..\..\..\build\TrimmingEnable.props" />
<Import Project="..\..\..\build\NullableEnable.props" />
</Project>

0
src/tools/PublicAnalyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs → src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.CompileAnalyzer.cs

24
src/tools/PublicAnalyzers/AvaloniaPropertyAnalyzer.cs → src/tools/Avalonia.Analyzers/AvaloniaPropertyAnalyzer.cs

@ -3,7 +3,6 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.Serialization;
using Microsoft.CodeAnalysis;
@ -14,7 +13,6 @@ using Microsoft.CodeAnalysis.Operations;
namespace Avalonia.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
[SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")]
public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
{
private const string Category = "AvaloniaProperty";
@ -68,7 +66,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Type mismatch: AvaloniaProperty owner is {0}, which is not the containing type",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The owner of an AvaloniaProperty should generally be the containing type. This ensures that the property can be used as expected in XAML.",
TypeMismatchTag);
@ -78,7 +76,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Unexpected property use: {0} is neither owned by nor attached to {1}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"It is possible to use any AvaloniaProperty with any AvaloniaObject. However, each AvaloniaProperty an object uses on itself should be either owned by that object, or attached to that object.",
InappropriateReadWriteTag);
@ -88,7 +86,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Inappropriate assignment: An AvaloniaObject should use SetCurrentValue when setting its own StyledProperty or AttachedProperty values",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The standard means of setting an AvaloniaProperty is to call the SetValue method (often via a CLR property setter). This will forcibly overwrite values from sources like styles and templates, " +
"which is something that should only be done by consumers of the control, not the control itself. Controls which want to set their own values should instead call the SetCurrentValue method, or " +
"refactor the property into a DirectProperty. An assignment is exempt from this diagnostic in two scenarios: when it is forwarding a constructor parameter, and when the target object is derived " +
@ -101,7 +99,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Superfluous owner: {0} is already an owner of {1} via {2}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"Ownership of an AvaloniaProperty is inherited along the type hierarchy. There is no need for a derived type to assert ownership over a base type's properties. This diagnostic can be a symptom of an incorrect property owner elsewhere.",
InappropriateReadWriteTag);
@ -111,7 +109,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Name collision: {0} has the same name as {1}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"Querying for an AvaloniaProperty by name requires that each property associated with a type have a unique name.",
NameCollisionTag);
@ -121,7 +119,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Name collision: {0} owns multiple Avalonia properties with the name '{1}' {2}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"It is unclear which AvaloniaProperty this CLR property refers to. Ensure that each AvaloniaProperty associated with a type has a unique name. If you need to change behaviour of a base property in your class, call its OverrideMetadata or OverrideDefaultValue methods.",
NameCollisionTag);
@ -131,7 +129,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Bad name: An AvaloniaProperty named '{0}' is being assigned to {1}. These names do not relate.",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"An AvaloniaProperty should be stored in a field or property which contains its name. For example, a property named \"Brush\" should be assigned to a field called \"BrushProperty\".\nPrivate symbols are exempt from this diagnostic.",
NameCollisionTag);
@ -141,7 +139,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Side effects: '{0}' is an AvaloniaProperty which can be {1} without the use of this CLR property. This {2} accessor should do nothing except call {3}.",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The AvaloniaObject.GetValue and AvaloniaObject.SetValue methods are public, and do not call any user CLR properties. To execute code before or after the property is set, consider: 1) adding a Coercion method, b) adding a static observer with AvaloniaProperty.Changed.AddClassHandler, and/or c) overriding the AvaloniaObject.OnPropertyChanged method.",
AssociatedClrPropertyTag);
@ -151,7 +149,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Missing accessor: {0} is {1}, but this CLR property lacks a {2} accessor",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The AvaloniaObject.GetValue and AvaloniaObject.SetValue methods are public, and do not call CLR properties on the owning type. Not providing both CLR property accessors is ineffective.",
AssociatedClrPropertyTag);
@ -161,7 +159,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Inconsistent accessibility: CLR {0} accessibility does not match accessibility of {1}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The AvaloniaObject.GetValue and AvaloniaObject.SetValue methods are public, and do not call CLR properties on the owning type. Defining a CLR property with different accessibility from its associated AvaloniaProperty is ineffective.",
AssociatedClrPropertyTag);
@ -171,7 +169,7 @@ public partial class AvaloniaPropertyAnalyzer : DiagnosticAnalyzer
"Type mismatch: CLR property type differs from the value type of {0} {1}",
Category,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
isEnabledByDefault: false, // TODO: autogenerate property metadata preserved in ref assembly
"The AvaloniaObject.GetValue and AvaloniaObject.SetValue methods are public, and do not call CLR properties on the owning type. A CLR property changing the value type (even when an implicit cast is possible) is ineffective and can lead to InvalidCastException to be thrown.",
TypeMismatchTag, AssociatedClrPropertyTag);

8
src/tools/Avalonia.Analyzers/GlobalSuppressions.cs

@ -0,0 +1,8 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("MicrosoftCodeAnalysisReleaseTracking", "RS2008:Enable analyzer release tracking")]

59
src/tools/Avalonia.Analyzers/OnPropertyChangedOverrideAnalyzer.cs

@ -0,0 +1,59 @@
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
namespace Avalonia.Analyzers;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class OnPropertyChangedOverrideAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "AVA2001";
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor(
DiagnosticId,
"Missing invoke base.OnPropertyChanged",
"Method '{0}' do not invoke base.{0}",
"Potential issue",
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: "The OnPropertyChanged of the base class was not invoked in the override method declaration, which could lead to unwanted behavior.");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
context.EnableConcurrentExecution();
context.RegisterSyntaxNodeAction(AnalyzeMethod, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)
{
var method = (MethodDeclarationSyntax)context.Node;
if (context.SemanticModel.GetDeclaredSymbol(method, context.CancellationToken) is IMethodSymbol currentMethod
&& currentMethod.Name == "OnPropertyChanged"
&& currentMethod.OverriddenMethod is IMethodSymbol originalMethod)
{
var baseInvocations = method.Body?.DescendantNodes().OfType<BaseExpressionSyntax>();
if (baseInvocations?.Any() == true)
{
foreach (var baseInvocation in baseInvocations)
{
if (baseInvocation.Parent is SyntaxNode parent)
{
var targetSymbol = context.SemanticModel.GetSymbolInfo(parent, context.CancellationToken);
if (SymbolEqualityComparer.Default.Equals(targetSymbol.Symbol, originalMethod))
{
return;
}
}
}
}
context.ReportDiagnostic(Diagnostic.Create(Rule, currentMethod.Locations[0], currentMethod.Name));
}
}
}

2
src/tools/Avalonia.Generators/GeneratorContextExtensions.cs

@ -20,7 +20,7 @@ internal static class GeneratorContextExtensions
public static void ReportNameGeneratorUnhandledError(this GeneratorExecutionContext context, Exception error) =>
context.Report(UnhandledErrorDescriptorId,
"Unhandled exception occured while generating typed Name references. " +
"Please file an issue: https://github.com/avaloniaui/Avalonia.Generators",
"Please file an issue: https://github.com/avaloniaui/Avalonia",
error.ToString());
public static void ReportNameGeneratorInvalidType(this GeneratorExecutionContext context, string typeName) =>

17
src/tools/PublicAnalyzers/Avalonia.Analyzers.csproj

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" />
</ItemGroup>
</Project>
Loading…
Cancel
Save