Skip to content

Commit cecaf32

Browse files
authored
Merge branch 'main' into MediaElementOptionService
2 parents ea35514 + 1df576f commit cecaf32

File tree

7 files changed

+225
-24
lines changed

7 files changed

+225
-24
lines changed

.github/prompts/dotnet/codestyle.prompt.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ This guide provides a set of best practices and coding standards for writing C#
581581

582582
### Element Positioning
583583

584-
Please adhere to [Style Cop SA1201](https://docs.github.com/en/copilot/using-github-copilot/code-review/configuring-coding-guidelines#creating-a-coding-guideline) for organizing code in a file.
584+
Please adhere to [Style Cop SA1201](https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1201.md) for organizing code in a file.
585585

586586
Elements at the file root level or within a namespace should be positioned in the following order:
587587

@@ -609,4 +609,4 @@ Indexers
609609
Methods
610610
Records
611611
Structs
612-
Classes
612+
Classes

src/CommunityToolkit.Maui.Analyzers.UnitTests/UseCommunityToolkitCameraInitializationAnalyzerTests.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,43 @@ public static MauiApp CreateMauiApp()
118118
await VerifyCameraToolkitAnalyzer(source, Diagnostic().WithSpan(12, 4, 12, 61).WithSeverity(DiagnosticSeverity.Error));
119119
}
120120

121+
[Fact]
122+
public async Task VerifyNoErrorsWhenUseMauiCommunityToolkitCameraWrapInPreprocessorDirectives()
123+
{
124+
const string source =
125+
/* language=C#-test */
126+
//lang=csharp
127+
"""
128+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
129+
{
130+
using Microsoft.Maui.Controls.Hosting;
131+
using Microsoft.Maui.Hosting;
132+
using CommunityToolkit.Maui;
133+
134+
public static class MauiProgram
135+
{
136+
public static MauiApp CreateMauiApp()
137+
{
138+
var builder = MauiApp.CreateBuilder();
139+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
140+
#if ANDROID || IOS
141+
.UseMauiCommunityToolkitCamera()
142+
#endif
143+
.ConfigureFonts(fonts =>
144+
{
145+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
146+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
147+
});
148+
149+
return builder.Build();
150+
}
151+
}
152+
}
153+
""";
154+
155+
await VerifyCameraToolkitAnalyzer(source);
156+
}
157+
121158
static Task VerifyCameraToolkitAnalyzer(string source, params IReadOnlyList<DiagnosticResult> diagnosticResults)
122159
{
123160
return VerifyAnalyzerAsync(

src/CommunityToolkit.Maui.Analyzers.UnitTests/UseCommunityToolkitInitializationAnalyzerTests.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,79 @@ public static MauiApp CreateMauiApp()
118118
await VerifyMauiToolkitAnalyzer(source, Diagnostic().WithSpan(12, 4, 12, 61).WithSeverity(DiagnosticSeverity.Error));
119119
}
120120

121+
[Fact]
122+
public async Task VerifyNoErrorsWhenUseMauiCommunityToolkitWrapInPreprocessorDirectives()
123+
{
124+
const string source =
125+
/* language=C#-test */
126+
//lang=csharp
127+
"""
128+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
129+
{
130+
using Microsoft.Maui.Controls.Hosting;
131+
using Microsoft.Maui.Hosting;
132+
using CommunityToolkit.Maui;
133+
134+
public static class MauiProgram
135+
{
136+
public static MauiApp CreateMauiApp()
137+
{
138+
var builder = MauiApp.CreateBuilder();
139+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
140+
#if ANDROID || IOS
141+
.UseMauiCommunityToolkit()
142+
#endif
143+
.ConfigureFonts(fonts =>
144+
{
145+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
146+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
147+
});
148+
149+
return builder.Build();
150+
}
151+
}
152+
}
153+
""";
154+
155+
156+
await VerifyMauiToolkitAnalyzer(source);
157+
}
158+
159+
[Fact]
160+
public async Task VerifyErrorsWhenUseMauiCommunityToolkitIsCommentedOut()
161+
{
162+
const string source =
163+
/* language=C#-test */
164+
//lang=csharp
165+
"""
166+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
167+
{
168+
using Microsoft.Maui.Controls.Hosting;
169+
using Microsoft.Maui.Hosting;
170+
using CommunityToolkit.Maui;
171+
172+
public static class MauiProgram
173+
{
174+
public static MauiApp CreateMauiApp()
175+
{
176+
var builder = MauiApp.CreateBuilder();
177+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
178+
//.UseMauiCommunityToolkit()
179+
.ConfigureFonts(fonts =>
180+
{
181+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
182+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
183+
});
184+
185+
return builder.Build();
186+
}
187+
}
188+
}
189+
""";
190+
191+
await VerifyMauiToolkitAnalyzer(source, Diagnostic().WithSpan(12, 4, 12, 61).WithSeverity(DiagnosticSeverity.Error));
192+
}
193+
121194
static Task VerifyMauiToolkitAnalyzer(string source, params IReadOnlyList<DiagnosticResult> expected)
122195
{
123196
return VerifyAnalyzerAsync(

src/CommunityToolkit.Maui.Analyzers.UnitTests/UseCommunityToolkitMediaElementInitializationAnalyzerTests.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using CommunityToolkit.Maui.MediaElement.Analyzers;
1+
using CommunityToolkit.Maui.Core;
2+
using CommunityToolkit.Maui.MediaElement.Analyzers;
23
using Microsoft.CodeAnalysis;
34
using Microsoft.CodeAnalysis.Testing;
45
using Xunit;
@@ -118,12 +119,49 @@ public static MauiApp CreateMauiApp()
118119
await VerifyMediaElementToolkitAnalyzer(source, Diagnostic().WithSpan(12, 4, 12, 61).WithSeverity(DiagnosticSeverity.Error));
119120
}
120121

122+
[Fact]
123+
public async Task VerifyNoErrorsWhenUseMauiCommunityToolkitMediaElementWrapInPreprocessorDirectives()
124+
{
125+
const string source =
126+
/* language=C#-test */
127+
//lang=csharp
128+
"""
129+
namespace CommunityToolkit.Maui.Analyzers.UnitTests
130+
{
131+
using Microsoft.Maui.Controls.Hosting;
132+
using Microsoft.Maui.Hosting;
133+
using CommunityToolkit.Maui;
134+
135+
public static class MauiProgram
136+
{
137+
public static MauiApp CreateMauiApp()
138+
{
139+
var builder = MauiApp.CreateBuilder();
140+
builder.UseMauiApp<Microsoft.Maui.Controls.Application>()
141+
#if ANDROID || IOS
142+
.UseMauiCommunityToolkitMediaElement()
143+
#endif
144+
.ConfigureFonts(fonts =>
145+
{
146+
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
147+
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
148+
});
149+
150+
return builder.Build();
151+
}
152+
}
153+
}
154+
""";
155+
156+
await VerifyMediaElementToolkitAnalyzer(source);
157+
}
158+
121159
static Task VerifyMediaElementToolkitAnalyzer(string source, params IReadOnlyList<DiagnosticResult> diagnosticResults)
122160
{
123161
return VerifyAnalyzerAsync(
124162
source,
125163
[
126-
typeof(Views.MediaElement) // CommunityToolkit.Maui.MediaElement
164+
typeof(MediaElementOptions) // CommunityToolkit.Maui.MediaElement
127165
],
128166
diagnosticResults);
129167
}

src/CommunityToolkit.Maui.Analyzers/UseCommunityToolkitInitializationAnalyzer.cs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ namespace CommunityToolkit.Maui.Analyzers;
1010
public class UseCommunityToolkitInitializationAnalyzer : DiagnosticAnalyzer
1111
{
1212
public const string DiagnosticId = "MCT001";
13-
1413
const string category = "Initialization";
1514
const string useMauiAppMethodName = "UseMauiApp";
1615
const string useMauiCommunityToolkitMethodName = "UseMauiCommunityToolkit";
1716

1817
static readonly LocalizableString title = new LocalizableResourceString(nameof(Resources.InitializationErrorTitle), Resources.ResourceManager, typeof(Resources));
1918
static readonly LocalizableString messageFormat = new LocalizableResourceString(nameof(Resources.InitalizationMessageFormat), Resources.ResourceManager, typeof(Resources));
2019
static readonly LocalizableString description = new LocalizableResourceString(nameof(Resources.InitializationErrorMessage), Resources.ResourceManager, typeof(Resources));
21-
2220
static readonly DiagnosticDescriptor rule = new(DiagnosticId, title, messageFormat, category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: description);
2321

2422
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = [rule];
@@ -32,21 +30,42 @@ public override void Initialize(AnalysisContext context)
3230

3331
static void AnalyzeNode(SyntaxNodeAnalysisContext context)
3432
{
35-
if (context.Node is InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax { Name.Identifier.ValueText: useMauiAppMethodName } } invocationExpression)
33+
if (context.Node is InvocationExpressionSyntax invocationExpression
34+
&& invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression
35+
&& memberAccessExpression.Name.Identifier.ValueText == useMauiAppMethodName)
3636
{
37-
var root = invocationExpression.SyntaxTree.GetRoot();
38-
var methodDeclaration = root.FindNode(invocationExpression.FullSpan)
37+
var methodDeclaration = invocationExpression
3938
.Ancestors()
4039
.OfType<MethodDeclarationSyntax>()
4140
.FirstOrDefault();
4241

43-
if (methodDeclaration is not null
44-
&& !methodDeclaration.DescendantNodes().OfType<InvocationExpressionSyntax>().Any(static n =>
45-
n.Expression is MemberAccessExpressionSyntax { Name.Identifier.ValueText: useMauiCommunityToolkitMethodName }))
42+
if (methodDeclaration is not null && !HasUseMauiCommunityToolkitCall(methodDeclaration))
4643
{
4744
var diagnostic = Diagnostic.Create(rule, invocationExpression.GetLocation());
4845
context.ReportDiagnostic(diagnostic);
4946
}
5047
}
5148
}
49+
50+
static bool HasUseMauiCommunityToolkitCall(MethodDeclarationSyntax methodDeclaration)
51+
{
52+
// Check syntax nodes first (handles active code)
53+
var hasInSyntaxTree = methodDeclaration
54+
.DescendantNodes()
55+
.OfType<InvocationExpressionSyntax>()
56+
.Any(static invocation => invocation.Expression is MemberAccessExpressionSyntax memberAccess
57+
&& memberAccess.Name.Identifier.ValueText == useMauiCommunityToolkitMethodName);
58+
59+
if (hasInSyntaxTree)
60+
{
61+
return true;
62+
}
63+
64+
// Check trivia (comments, preprocessor directives, disabled code)
65+
return methodDeclaration
66+
.DescendantTrivia()
67+
.Any(static trivia =>
68+
trivia.IsKind(SyntaxKind.DisabledTextTrivia) &&
69+
trivia.ToString().Contains(useMauiCommunityToolkitMethodName, StringComparison.Ordinal));
70+
}
5271
}

src/CommunityToolkit.Maui.Camera.Analyzers/UseCommunityToolkitCameraInitializationAnalyzer.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,37 @@ static void AnalyzeNode(SyntaxNodeAnalysisContext context)
3636
&& invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression
3737
&& memberAccessExpression.Name.Identifier.ValueText == useMauiAppMethodName)
3838
{
39-
var root = invocationExpression.SyntaxTree.GetRoot();
40-
var methodDeclaration = root.FindNode(invocationExpression.FullSpan)
39+
var methodDeclaration = invocationExpression
4140
.Ancestors()
4241
.OfType<MethodDeclarationSyntax>()
4342
.FirstOrDefault();
4443

45-
if (methodDeclaration is not null
46-
&& !methodDeclaration.DescendantNodes().OfType<InvocationExpressionSyntax>().Any(static n =>
47-
n.Expression is MemberAccessExpressionSyntax m &&
48-
m.Name.Identifier.ValueText == useMauiCommunityToolkitCameraMethodName))
44+
if (methodDeclaration is not null && !HasUseMauiCommunityToolkitCameraCall(methodDeclaration))
4945
{
5046
var diagnostic = Diagnostic.Create(rule, invocationExpression.GetLocation());
5147
context.ReportDiagnostic(diagnostic);
5248
}
5349
}
5450
}
51+
52+
static bool HasUseMauiCommunityToolkitCameraCall(MethodDeclarationSyntax methodDeclaration)
53+
{
54+
// Check syntax nodes first (handles active code)
55+
var hasInSyntaxTree = methodDeclaration
56+
.DescendantNodes()
57+
.OfType<InvocationExpressionSyntax>()
58+
.Any(static invocation => invocation.Expression is MemberAccessExpressionSyntax memberAccess
59+
&& memberAccess.Name.Identifier.ValueText == useMauiCommunityToolkitCameraMethodName);
60+
61+
if (hasInSyntaxTree)
62+
{
63+
return true;
64+
}
65+
66+
// Check trivia (comments, preprocessor directives, disabled code)
67+
return methodDeclaration
68+
.DescendantTrivia()
69+
.Any(static trivia => trivia.IsKind(SyntaxKind.DisabledTextTrivia)
70+
&& trivia.ToString().Contains(useMauiCommunityToolkitCameraMethodName, StringComparison.Ordinal));
71+
}
5572
}

src/CommunityToolkit.Maui.MediaElement.Analyzers/UseCommunityToolkitMediaElementInitializationAnalyzer.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,37 @@ static void AnalyzeNode(SyntaxNodeAnalysisContext context)
3636
&& invocationExpression.Expression is MemberAccessExpressionSyntax memberAccessExpression
3737
&& memberAccessExpression.Name.Identifier.ValueText == useMauiAppMethodName)
3838
{
39-
var root = invocationExpression.SyntaxTree.GetRoot();
40-
var methodDeclaration = root.FindNode(invocationExpression.FullSpan)
39+
var methodDeclaration = invocationExpression
4140
.Ancestors()
4241
.OfType<MethodDeclarationSyntax>()
4342
.FirstOrDefault();
4443

45-
if (methodDeclaration is not null
46-
&& !methodDeclaration.DescendantNodes().OfType<InvocationExpressionSyntax>().Any(static n =>
47-
n.Expression is MemberAccessExpressionSyntax m &&
48-
m.Name.Identifier.ValueText == useMauiCommunityToolkitMediaElementMethodName))
44+
if (methodDeclaration is not null && !HasUseMauiCommunityToolkitMediaElementCall(methodDeclaration))
4945
{
5046
var diagnostic = Diagnostic.Create(rule, invocationExpression.GetLocation());
5147
context.ReportDiagnostic(diagnostic);
5248
}
5349
}
5450
}
51+
52+
static bool HasUseMauiCommunityToolkitMediaElementCall(MethodDeclarationSyntax methodDeclaration)
53+
{
54+
// Check syntax nodes first (handles active code)
55+
var hasInSyntaxTree = methodDeclaration
56+
.DescendantNodes()
57+
.OfType<InvocationExpressionSyntax>()
58+
.Any(static invocation => invocation.Expression is MemberAccessExpressionSyntax memberAccess
59+
&& memberAccess.Name.Identifier.ValueText == useMauiCommunityToolkitMediaElementMethodName);
60+
61+
if (hasInSyntaxTree)
62+
{
63+
return true;
64+
}
65+
66+
// Check trivia (comments, preprocessor directives, disabled code)
67+
return methodDeclaration
68+
.DescendantTrivia()
69+
.Any(static trivia => trivia.IsKind(SyntaxKind.DisabledTextTrivia)
70+
&& trivia.ToString().Contains(useMauiCommunityToolkitMediaElementMethodName, StringComparison.Ordinal));
71+
}
5572
}

0 commit comments

Comments
 (0)