Skip to content

Commit 2f0f5ca

Browse files
Merge branch 'main' into user/arcadiog/shorterExpressionStrings
2 parents 8e49fc4 + e4e06cb commit 2f0f5ca

File tree

107 files changed

+6739
-847
lines changed

Some content is hidden

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

107 files changed

+6739
-847
lines changed

.gitattributes

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#
1818
# Merging from the command prompt will add diff markers to the files if there
1919
# are conflicts (Merging from VS is not affected by the settings below, in VS
20-
# the diff markers are never inserted). Diff markers may cause the following
20+
# the diff markers are never inserted). Diff markers may cause the following
2121
# file extensions to fail to load in VS. An alternative would be to treat
2222
# these files as binary and thus will always conflict and require user
2323
# intervention with every merge. To do so, just uncomment the entries below
@@ -46,9 +46,9 @@
4646

4747
###############################################################################
4848
# diff behavior for common document formats
49-
#
49+
#
5050
# Convert binary document formats to text before diffing them. This feature
51-
# is only available from the command line. Turn it on by uncommenting the
51+
# is only available from the command line. Turn it on by uncommenting the
5252
# entries below.
5353
###############################################################################
5454
#*.doc diff=astextplain

.runsettings

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<RunSettings>
22
<MSTest>
3-
<MaxCpuCount>0</MaxCpuCount>
3+
<MaxCpuCount>0</MaxCpuCount>
44
<Parallelize>
55
<Workers>0</Workers>
66
<Scope>ClassLevel</Scope>
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
; Shipped analyzer releases
2+
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; Unshipped analyzer release
2+
; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md
3+
4+
### New Rules
5+
6+
Rule ID | Category | Severity | Notes
7+
--------|----------|----------|-------
8+
MVVMTK0001 | Microsoft.Toolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator | Error | See https://aka.ms/mvvmtoolkit/error
9+
MVVMTK0002 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableObjectGenerator | Error | See https://aka.ms/mvvmtoolkit/error
10+
MVVMTK0003 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableRecipientGenerator | Error | See https://aka.ms/mvvmtoolkit/error
11+
MVVMTK0004 | Microsoft.Toolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator | Error | See https://aka.ms/mvvmtoolkit/error
12+
MVVMTK0005 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableObjectGenerator | Error | See https://aka.ms/mvvmtoolkit/error
13+
MVVMTK0006 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableObjectGenerator | Error | See https://aka.ms/mvvmtoolkit/error
14+
MVVMTK0007 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableRecipientGenerator | Error | See https://aka.ms/mvvmtoolkit/error
15+
MVVMTK0008 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservableRecipientGenerator | Error | See https://aka.ms/mvvmtoolkit/error
16+
MVVMTK0009 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
17+
MVVMTK0010 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
18+
MVVMTK0011 | Microsoft.Toolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator | Error | See https://aka.ms/mvvmtoolkit/error
19+
MVVMTK0012 | Microsoft.Toolkit.Mvvm.SourceGenerators.ICommandGenerator | Error | See https://aka.ms/mvvmtoolkit/error
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
namespace System.Diagnostics.CodeAnalysis
6+
{
7+
/// <summary>Specifies that when a method returns <see cref="ReturnValue"/>, the parameter will not be null even if the corresponding type allows it.</summary>
8+
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
9+
internal sealed class NotNullWhenAttribute : Attribute
10+
{
11+
/// <summary>
12+
/// Initializes a new instance of the <see cref="NotNullWhenAttribute"/> class.
13+
/// </summary>
14+
/// <param name="returnValue">The return value condition. If the method returns this value, the associated parameter will not be null.</param>
15+
public NotNullWhenAttribute(bool returnValue)
16+
{
17+
ReturnValue = returnValue;
18+
}
19+
20+
/// <summary>
21+
/// Gets a value indicating whether the annotated parameter will be null depending on the return value.
22+
/// </summary>
23+
public bool ReturnValue { get; }
24+
}
25+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Linq;
8+
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
10+
using Microsoft.Toolkit.Mvvm.SourceGenerators.Extensions;
11+
using static Microsoft.Toolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
12+
13+
namespace Microsoft.Toolkit.Mvvm.SourceGenerators
14+
{
15+
/// <summary>
16+
/// A source generator for the <c>INotifyPropertyChangedAttribute</c> type.
17+
/// </summary>
18+
[Generator]
19+
public sealed class INotifyPropertyChangedGenerator : TransitiveMembersGenerator
20+
{
21+
/// <summary>
22+
/// Initializes a new instance of the <see cref="INotifyPropertyChangedGenerator"/> class.
23+
/// </summary>
24+
public INotifyPropertyChangedGenerator()
25+
: base("Microsoft.Toolkit.Mvvm.ComponentModel.INotifyPropertyChangedAttribute")
26+
{
27+
}
28+
29+
/// <inheritdoc/>
30+
protected override DiagnosticDescriptor TargetTypeErrorDescriptor => INotifyPropertyChangedGeneratorError;
31+
32+
/// <inheritdoc/>
33+
protected override bool ValidateTargetType(
34+
GeneratorExecutionContext context,
35+
AttributeData attributeData,
36+
ClassDeclarationSyntax classDeclaration,
37+
INamedTypeSymbol classDeclarationSymbol,
38+
[NotNullWhen(false)] out DiagnosticDescriptor? descriptor)
39+
{
40+
INamedTypeSymbol iNotifyPropertyChangedSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged")!;
41+
42+
// Check if the type already implements INotifyPropertyChanged
43+
if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangedSymbol)))
44+
{
45+
descriptor = DuplicateINotifyPropertyChangedInterfaceForINotifyPropertyChangedAttributeError;
46+
47+
return false;
48+
}
49+
50+
descriptor = null;
51+
52+
return true;
53+
}
54+
55+
/// <inheritdoc/>
56+
protected override IEnumerable<MemberDeclarationSyntax> FilterDeclaredMembers(
57+
GeneratorExecutionContext context,
58+
AttributeData attributeData,
59+
ClassDeclarationSyntax classDeclaration,
60+
INamedTypeSymbol classDeclarationSymbol,
61+
ClassDeclarationSyntax sourceDeclaration)
62+
{
63+
// If requested, only include the event and the basic methods to raise it, but not the additional helpers
64+
if (attributeData.HasNamedArgument("IncludeAdditionalHelperMethods", false))
65+
{
66+
return sourceDeclaration.Members.Where(static member =>
67+
{
68+
return member
69+
is EventFieldDeclarationSyntax
70+
or MethodDeclarationSyntax { Identifier: { ValueText: "OnPropertyChanged" } };
71+
});
72+
}
73+
74+
return sourceDeclaration.Members;
75+
}
76+
}
77+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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.Diagnostics.CodeAnalysis;
6+
using System.Linq;
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp.Syntax;
9+
using static Microsoft.Toolkit.Mvvm.SourceGenerators.Diagnostics.DiagnosticDescriptors;
10+
11+
namespace Microsoft.Toolkit.Mvvm.SourceGenerators
12+
{
13+
/// <summary>
14+
/// A source generator for the <c>ObservableObjectAttribute</c> type.
15+
/// </summary>
16+
[Generator]
17+
public sealed class ObservableObjectGenerator : TransitiveMembersGenerator
18+
{
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="ObservableObjectGenerator"/> class.
21+
/// </summary>
22+
public ObservableObjectGenerator()
23+
: base("Microsoft.Toolkit.Mvvm.ComponentModel.ObservableObjectAttribute")
24+
{
25+
}
26+
27+
/// <inheritdoc/>
28+
protected override DiagnosticDescriptor TargetTypeErrorDescriptor => ObservableObjectGeneratorError;
29+
30+
/// <inheritdoc/>
31+
protected override bool ValidateTargetType(
32+
GeneratorExecutionContext context,
33+
AttributeData attributeData,
34+
ClassDeclarationSyntax classDeclaration,
35+
INamedTypeSymbol classDeclarationSymbol,
36+
[NotNullWhen(false)] out DiagnosticDescriptor? descriptor)
37+
{
38+
INamedTypeSymbol
39+
iNotifyPropertyChangedSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanged")!,
40+
iNotifyPropertyChangingSymbol = context.Compilation.GetTypeByMetadataName("System.ComponentModel.INotifyPropertyChanging")!;
41+
42+
// Check if the type already implements INotifyPropertyChanged...
43+
if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangedSymbol)))
44+
{
45+
descriptor = DuplicateINotifyPropertyChangedInterfaceForObservableObjectAttributeError;
46+
47+
return false;
48+
}
49+
50+
// ...or INotifyPropertyChanging
51+
if (classDeclarationSymbol.AllInterfaces.Any(i => SymbolEqualityComparer.Default.Equals(i, iNotifyPropertyChangingSymbol)))
52+
{
53+
descriptor = DuplicateINotifyPropertyChangingInterfaceForObservableObjectAttributeError;
54+
55+
return false;
56+
}
57+
58+
descriptor = null;
59+
60+
return true;
61+
}
62+
}
63+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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.Collections.Generic;
6+
using System.Linq;
7+
using Microsoft.CodeAnalysis;
8+
using Microsoft.CodeAnalysis.CSharp;
9+
using Microsoft.CodeAnalysis.CSharp.Syntax;
10+
11+
namespace Microsoft.Toolkit.Mvvm.SourceGenerators
12+
{
13+
/// <inheritdoc cref="ObservablePropertyGenerator"/>
14+
public sealed partial class ObservablePropertyGenerator
15+
{
16+
/// <summary>
17+
/// An <see cref="ISyntaxContextReceiver"/> that selects candidate nodes to process.
18+
/// </summary>
19+
private sealed class SyntaxReceiver : ISyntaxContextReceiver
20+
{
21+
/// <summary>
22+
/// The list of info gathered during exploration.
23+
/// </summary>
24+
private readonly List<Item> gatheredInfo = new();
25+
26+
/// <summary>
27+
/// Gets the collection of gathered info to process.
28+
/// </summary>
29+
public IReadOnlyCollection<Item> GatheredInfo => this.gatheredInfo;
30+
31+
/// <inheritdoc/>
32+
public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
33+
{
34+
if (context.Node is FieldDeclarationSyntax { AttributeLists: { Count: > 0 } } fieldDeclaration &&
35+
context.SemanticModel.Compilation.GetTypeByMetadataName("Microsoft.Toolkit.Mvvm.ComponentModel.ObservablePropertyAttribute") is INamedTypeSymbol attributeSymbol)
36+
{
37+
SyntaxTriviaList leadingTrivia = fieldDeclaration.GetLeadingTrivia();
38+
39+
foreach (VariableDeclaratorSyntax variableDeclarator in fieldDeclaration.Declaration.Variables)
40+
{
41+
if (context.SemanticModel.GetDeclaredSymbol(variableDeclarator) is IFieldSymbol fieldSymbol &&
42+
fieldSymbol.GetAttributes().Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeSymbol)))
43+
{
44+
this.gatheredInfo.Add(new Item(leadingTrivia, fieldSymbol));
45+
}
46+
}
47+
}
48+
}
49+
50+
/// <summary>
51+
/// A model for a group of item representing a discovered type to process.
52+
/// </summary>
53+
/// <param name="LeadingTrivia">The leading trivia for the field declaration.</param>
54+
/// <param name="FieldSymbol">The <see cref="IFieldSymbol"/> instance for the target field.</param>
55+
public sealed record Item(SyntaxTriviaList LeadingTrivia, IFieldSymbol FieldSymbol);
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)