Skip to content

Commit fb38a30

Browse files
committed
Move PluginClassInfo related to shared helper
1 parent 6171e92 commit fb38a30

File tree

5 files changed

+127
-79
lines changed

5 files changed

+127
-79
lines changed

Flow.Launcher.Localization.Analyzers/Localize/ContextAvailabilityAnalyzer.cs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Flow.Launcher.Localization.Analyzers.Localize
1111
[DiagnosticAnalyzer(LanguageNames.CSharp)]
1212
public class ContextAvailabilityAnalyzer : DiagnosticAnalyzer
1313
{
14+
#region DiagnosticAnalyzer
15+
1416
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(
1517
AnalyzerDiagnostics.ContextIsAField,
1618
AnalyzerDiagnostics.ContextIsNotStatic,
@@ -25,47 +27,55 @@ public override void Initialize(AnalysisContext context)
2527
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ClassDeclaration);
2628
}
2729

30+
#endregion
31+
32+
#region Analyze Methods
33+
2834
private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
2935
{
3036
var configOptions = context.Options.AnalyzerConfigOptionsProvider;
3137
var useDI = configOptions.GetFLLUseDependencyInjection();
32-
33-
// If we use dependency injection, we don't need to check for this context property
34-
if (useDI) return;
38+
if (useDI)
39+
{
40+
// If we use dependency injection, we don't need to check for this context property
41+
return;
42+
}
3543

3644
var classDeclaration = (ClassDeclarationSyntax)context.Node;
3745
var semanticModel = context.SemanticModel;
38-
var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration);
39-
40-
if (!IsPluginEntryClass(classSymbol)) return;
41-
42-
var contextProperty = classDeclaration.Members.OfType<PropertyDeclarationSyntax>()
43-
.Select(p => semanticModel.GetDeclaredSymbol(p))
44-
.FirstOrDefault(p => p?.Type.Name is Constants.PluginContextTypeName);
46+
var pluginClassInfo = Helper.GetPluginClassInfo(classDeclaration, semanticModel, context.CancellationToken);
47+
if (pluginClassInfo == null)
48+
{
49+
// Cannot find class that implements IPluginI18n
50+
return;
51+
}
4552

46-
if (contextProperty != null)
53+
// Context property is found, check if it's a valid property
54+
if (pluginClassInfo.PropertyName != null)
4755
{
48-
if (!contextProperty.IsStatic)
56+
if (!pluginClassInfo.IsStatic)
4957
{
5058
context.ReportDiagnostic(Diagnostic.Create(
5159
AnalyzerDiagnostics.ContextIsNotStatic,
52-
contextProperty.DeclaringSyntaxReferences[0].GetSyntax().GetLocation()
60+
pluginClassInfo.CodeFixLocatioin
5361
));
5462
return;
5563
}
5664

57-
if (contextProperty.DeclaredAccessibility is Accessibility.Private || contextProperty.DeclaredAccessibility is Accessibility.Protected)
65+
if (pluginClassInfo.IsPrivate || pluginClassInfo.IsProtected)
5866
{
5967
context.ReportDiagnostic(Diagnostic.Create(
6068
AnalyzerDiagnostics.ContextAccessIsTooRestrictive,
61-
contextProperty.DeclaringSyntaxReferences[0].GetSyntax().GetLocation()
69+
pluginClassInfo.CodeFixLocatioin
6270
));
6371
return;
6472
}
6573

74+
// If the context property is valid, we don't need to check for anything else
6675
return;
6776
}
6877

78+
// Context property is not found, check if it's declared as a field
6979
var fieldDeclaration = classDeclaration.Members
7080
.OfType<FieldDeclarationSyntax>()
7181
.SelectMany(f => f.Declaration.Variables)
@@ -75,7 +85,6 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
7585
?.DeclaringSyntaxReferences[0]
7686
.GetSyntax()
7787
.FirstAncestorOrSelf<FieldDeclarationSyntax>();
78-
7988
if (parentSyntax != null)
8089
{
8190
context.ReportDiagnostic(Diagnostic.Create(
@@ -85,13 +94,13 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
8594
return;
8695
}
8796

97+
// Context property is not found, report an error
8898
context.ReportDiagnostic(Diagnostic.Create(
8999
AnalyzerDiagnostics.ContextIsNotDeclared,
90100
classDeclaration.Identifier.GetLocation()
91101
));
92102
}
93103

94-
private static bool IsPluginEntryClass(INamedTypeSymbol namedTypeSymbol) =>
95-
namedTypeSymbol?.Interfaces.Any(i => i.Name == Constants.PluginInterfaceName) ?? false;
104+
#endregion
96105
}
97106
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Microsoft.CodeAnalysis;
2+
3+
namespace Flow.Launcher.Localization.Shared
4+
{
5+
public class PluginClassInfo
6+
{
7+
public Location Location { get; }
8+
public string ClassName { get; }
9+
public string PropertyName { get; }
10+
public bool IsStatic { get; }
11+
public bool IsPrivate { get; }
12+
public bool IsProtected { get; }
13+
public Location CodeFixLocatioin { get; }
14+
15+
public string ContextAccessor => $"{ClassName}.{PropertyName}";
16+
public bool IsValid => PropertyName != null && IsStatic && (!IsPrivate) && (!IsProtected);
17+
18+
public PluginClassInfo(Location location, string className, string propertyName, bool isStatic, bool isPrivate, bool isProtected, Location codeFixLocatioin)
19+
{
20+
Location = location;
21+
ClassName = className;
22+
PropertyName = propertyName;
23+
IsStatic = isStatic;
24+
IsPrivate = isPrivate;
25+
IsProtected = isProtected;
26+
CodeFixLocatioin = codeFixLocatioin;
27+
}
28+
}
29+
}

Flow.Launcher.Localization.Shared/Flow.Launcher.Localization.Shared.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.13.0" />
11+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
1212
</ItemGroup>
1313

1414
</Project>

Flow.Launcher.Localization.Shared/Helper.cs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
using Microsoft.CodeAnalysis.Diagnostics;
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
using System.Linq;
6+
using System.Threading;
27

38
namespace Flow.Launcher.Localization.Shared
49
{
510
public static class Helper
611
{
12+
#region Build Properties
13+
714
public static bool GetFLLUseDependencyInjection(this AnalyzerConfigOptionsProvider configOptions)
815
{
916
if (!configOptions.GlobalOptions.TryGetValue("build_property.FLLUseDependencyInjection", out var result) ||
@@ -13,5 +20,66 @@ public static bool GetFLLUseDependencyInjection(this AnalyzerConfigOptionsProvid
1320
}
1421
return useDI;
1522
}
23+
24+
#endregion
25+
26+
#region Plugin Class Info
27+
28+
/// <summary>
29+
/// If cannot find the class that implements IPluginI18n, return null.
30+
/// If cannot find the context property, return PluginClassInfo with null context property name.
31+
/// </summary>
32+
public static PluginClassInfo GetPluginClassInfo(ClassDeclarationSyntax classDecl, SemanticModel semanticModel, CancellationToken ct)
33+
{
34+
var classSymbol = semanticModel.GetDeclaredSymbol(classDecl, ct);
35+
if (!IsPluginEntryClass(classSymbol))
36+
{
37+
// Cannot find class that implements IPluginI18n
38+
return null;
39+
}
40+
41+
var property = GetContextProperty(classDecl);
42+
var location = GetLocation(semanticModel.SyntaxTree, classDecl);
43+
if (property is null)
44+
{
45+
// Cannot find context
46+
return new PluginClassInfo(location, classDecl.Identifier.Text, null, false, false, false, null);
47+
}
48+
49+
var modifiers = property.Modifiers;
50+
var codeFixLocation = GetCodeFixLocation(property, semanticModel);
51+
return new PluginClassInfo(
52+
location,
53+
classDecl.Identifier.Text,
54+
property.Identifier.Text,
55+
modifiers.Any(SyntaxKind.StaticKeyword),
56+
modifiers.Any(SyntaxKind.PrivateKeyword),
57+
modifiers.Any(SyntaxKind.ProtectedKeyword),
58+
codeFixLocation);
59+
}
60+
61+
private static bool IsPluginEntryClass(INamedTypeSymbol namedTypeSymbol)
62+
{
63+
return namedTypeSymbol?.Interfaces.Any(i => i.Name == Constants.PluginInterfaceName) ?? false;
64+
}
65+
66+
private static PropertyDeclarationSyntax GetContextProperty(ClassDeclarationSyntax classDecl)
67+
{
68+
return classDecl.Members
69+
.OfType<PropertyDeclarationSyntax>()
70+
.FirstOrDefault(p => p.Type.ToString() == Constants.PluginContextTypeName);
71+
}
72+
73+
private static Location GetLocation(SyntaxTree syntaxTree, CSharpSyntaxNode classDeclaration)
74+
{
75+
return Location.Create(syntaxTree, classDeclaration.GetLocation().SourceSpan);
76+
}
77+
78+
private static Location GetCodeFixLocation(PropertyDeclarationSyntax property, SemanticModel semanticModel)
79+
{
80+
return semanticModel.GetDeclaredSymbol(property).DeclaringSyntaxReferences[0].GetSyntax().GetLocation();
81+
}
82+
83+
#endregion
1684
}
1785
}

Flow.Launcher.Localization.SourceGenerators/Localize/LocalizeSourceGenerator.cs

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Xml.Linq;
88
using Flow.Launcher.Localization.Shared;
99
using Microsoft.CodeAnalysis;
10-
using Microsoft.CodeAnalysis.CSharp;
1110
using Microsoft.CodeAnalysis.CSharp.Syntax;
1211
using Microsoft.CodeAnalysis.Diagnostics;
1312
using Microsoft.CodeAnalysis.Text;
@@ -57,7 +56,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
5756
var pluginClasses = context.SyntaxProvider
5857
.CreateSyntaxProvider(
5958
predicate: (n, _) => n is ClassDeclarationSyntax,
60-
transform: GetPluginClassInfo)
59+
transform: (c, t) => Helper.GetPluginClassInfo((ClassDeclarationSyntax)c.Node, c.SemanticModel, t))
6160
.Where(info => info != null)
6261
.Collect();
6362

@@ -428,35 +427,6 @@ private static string GetLocalizationKeyFromInvocation(GeneratorSyntaxContext co
428427

429428
#region Get Plugin Class Info
430429

431-
private static PluginClassInfo GetPluginClassInfo(GeneratorSyntaxContext context, CancellationToken ct)
432-
{
433-
var classDecl = (ClassDeclarationSyntax)context.Node;
434-
var location = GetLocation(context.SemanticModel.SyntaxTree, classDecl);
435-
if (!classDecl.BaseList?.Types.Any(t => t.Type.ToString() == Constants.PluginInterfaceName) ?? true)
436-
{
437-
// Cannot find class that implements IPluginI18n
438-
return null;
439-
}
440-
441-
var property = classDecl.Members
442-
.OfType<PropertyDeclarationSyntax>()
443-
.FirstOrDefault(p => p.Type.ToString() == Constants.PluginContextTypeName);
444-
if (property is null)
445-
{
446-
// Cannot find context
447-
return new PluginClassInfo(location, classDecl.Identifier.Text, null, false, false, false);
448-
}
449-
450-
var modifiers = property.Modifiers;
451-
return new PluginClassInfo(
452-
location,
453-
classDecl.Identifier.Text,
454-
property.Identifier.Text,
455-
modifiers.Any(SyntaxKind.StaticKeyword),
456-
modifiers.Any(SyntaxKind.PrivateKeyword),
457-
modifiers.Any(SyntaxKind.ProtectedKeyword));
458-
}
459-
460430
private static PluginClassInfo GetValidPluginInfo(
461431
ImmutableArray<PluginClassInfo> pluginClasses,
462432
SourceProductionContext context,
@@ -535,11 +505,6 @@ private static PluginClassInfo GetValidPluginInfo(
535505
return null;
536506
}
537507

538-
private static Location GetLocation(SyntaxTree syntaxTree, CSharpSyntaxNode classDeclaration)
539-
{
540-
return Location.Create(syntaxTree, classDeclaration.GetLocation().SourceSpan);
541-
}
542-
543508
#endregion
544509

545510
#region Generate Source
@@ -772,29 +737,6 @@ public LocalizableString(string key, string value, string summary, IEnumerable<L
772737
}
773738
}
774739

775-
public class PluginClassInfo
776-
{
777-
public Location Location { get; }
778-
public string ClassName { get; }
779-
public string PropertyName { get; }
780-
public bool IsStatic { get; }
781-
public bool IsPrivate { get; }
782-
public bool IsProtected { get; }
783-
784-
public string ContextAccessor => $"{ClassName}.{PropertyName}";
785-
public bool IsValid => PropertyName != null && IsStatic && (!IsPrivate) && (!IsProtected);
786-
787-
public PluginClassInfo(Location location, string className, string propertyName, bool isStatic, bool isPrivate, bool isProtected)
788-
{
789-
Location = location;
790-
ClassName = className;
791-
PropertyName = propertyName;
792-
IsStatic = isStatic;
793-
IsPrivate = isPrivate;
794-
IsProtected = isProtected;
795-
}
796-
}
797-
798740
#endregion
799741
}
800742
}

0 commit comments

Comments
 (0)