Skip to content

Commit 4091e48

Browse files
committed
Improve code quality & Add more diagnostic information
1 parent 7f31bed commit 4091e48

File tree

1 file changed

+122
-48
lines changed

1 file changed

+122
-48
lines changed

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

Lines changed: 122 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -67,44 +67,65 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
6767

6868
var compilation = context.CompilationProvider;
6969

70-
var combined = localizedStrings.Combine(invocationKeys).Combine(pluginClasses).Combine(compilation);
70+
var combined = localizedStrings.Combine(invocationKeys).Combine(pluginClasses).Combine(compilation).Combine(xamlFiles.Collect());
7171

72-
context.RegisterSourceOutput(combined, (spc, data) =>
72+
context.RegisterSourceOutput(combined, Execute);
73+
}
74+
75+
/// <summary>
76+
/// Executes the generation of string properties based on the provided data.
77+
/// </summary>
78+
/// <param name="spc">The source production context.</param>
79+
/// <param name="data">The provided data.</param>
80+
private void Execute(SourceProductionContext spc,
81+
((((ImmutableArray<LocalizableString> LocalizableStrings,
82+
ImmutableHashSet<string> Strings),
83+
ImmutableArray<PluginClassInfo> PluginClassInfos),
84+
Compilation Compilation),
85+
ImmutableArray<AdditionalText> AdditionalTexts) data)
86+
{
87+
var xamlFiles = data.AdditionalTexts;
88+
if (xamlFiles.Length == 0)
7389
{
74-
var (Left, Right) = data;
75-
var localizedStringsList = Left.Left.Left;
76-
var usedKeys = Left.Left.Right;
77-
var pluginClassesList = Left.Right;
78-
var compilationData = Right;
90+
spc.ReportDiagnostic(Diagnostic.Create(
91+
SourceGeneratorDiagnostics.CouldNotFindResourceDictionaries,
92+
Location.None
93+
));
94+
return;
95+
}
7996

80-
var assemblyName = compilationData.AssemblyName ?? DefaultNamespace;
81-
var optimizationLevel = compilationData.Options.OptimizationLevel;
97+
var compilationData = data.Item1.Compilation;
98+
var pluginClassesList = data.Item1.Item1.PluginClassInfos;
99+
var usedKeys = data.Item1.Item1.Item1.Strings;
100+
var localizedStringsList = data.Item1.Item1.Item1.LocalizableStrings;
82101

83-
var unusedKeys = localizedStringsList
84-
.Select(ls => ls.Key)
85-
.ToImmutableHashSet()
86-
.Except(usedKeys);
102+
var assemblyName = compilationData.AssemblyName ?? DefaultNamespace;
103+
var optimizationLevel = compilationData.Options.OptimizationLevel;
87104

88-
foreach (var key in unusedKeys)
89-
{
90-
spc.ReportDiagnostic(Diagnostic.Create(
91-
SourceGeneratorDiagnostics.LocalizationKeyUnused,
92-
Location.None,
93-
key));
94-
}
105+
var unusedKeys = localizedStringsList
106+
.Select(ls => ls.Key)
107+
.ToImmutableHashSet()
108+
.Except(usedKeys);
95109

96-
var pluginInfo = GetValidPluginInfo(pluginClassesList, spc);
97-
var isCoreAssembly = assemblyName == CoreNamespace1 || assemblyName == CoreNamespace2;
98-
99-
GenerateSource(
100-
spc,
101-
localizedStringsList,
102-
unusedKeys,
103-
optimizationLevel,
104-
assemblyName,
105-
isCoreAssembly,
106-
pluginInfo);
107-
});
110+
foreach (var key in unusedKeys)
111+
{
112+
spc.ReportDiagnostic(Diagnostic.Create(
113+
SourceGeneratorDiagnostics.LocalizationKeyUnused,
114+
Location.None,
115+
key));
116+
}
117+
118+
var pluginInfo = GetValidPluginInfo(pluginClassesList, spc);
119+
var isCoreAssembly = assemblyName == CoreNamespace1 || assemblyName == CoreNamespace2;
120+
121+
GenerateSource(
122+
spc,
123+
localizedStringsList,
124+
unusedKeys,
125+
optimizationLevel,
126+
assemblyName,
127+
isCoreAssembly,
128+
pluginInfo);
108129
}
109130

110131
#endregion
@@ -187,47 +208,93 @@ private static string GetLocalizationKeyFromInvocation(GeneratorSyntaxContext co
187208
private static PluginClassInfo GetPluginClassInfo(GeneratorSyntaxContext context, CancellationToken ct)
188209
{
189210
var classDecl = (ClassDeclarationSyntax)context.Node;
211+
var location = GetLocation(context.SemanticModel.SyntaxTree, classDecl);
190212
if (!classDecl.BaseList?.Types.Any(t => t.Type.ToString() == PluginInterfaceName) ?? true)
213+
{
214+
// Cannot find class that implements IPluginI18n
191215
return null;
216+
}
192217

193218
var property = classDecl.Members
194219
.OfType<PropertyDeclarationSyntax>()
195220
.FirstOrDefault(p => p.Type.ToString() == PluginContextTypeName);
196-
197221
if (property is null)
198-
return new PluginClassInfo(classDecl.Identifier.Text, null, false);
222+
{
223+
// Cannot find context
224+
return new PluginClassInfo(location, classDecl.Identifier.Text, null, false, false, false);
225+
}
199226

200227
var modifiers = property.Modifiers;
201-
var isValid = modifiers.Any(SyntaxKind.StaticKeyword) &&
202-
!modifiers.Any(SyntaxKind.PrivateKeyword) &&
203-
!modifiers.Any(SyntaxKind.ProtectedKeyword);
204-
205228
return new PluginClassInfo(
229+
location,
206230
classDecl.Identifier.Text,
207231
property.Identifier.Text,
208-
isValid);
232+
modifiers.Any(SyntaxKind.StaticKeyword),
233+
modifiers.Any(SyntaxKind.PrivateKeyword),
234+
modifiers.Any(SyntaxKind.ProtectedKeyword));
209235
}
210236

211237
private static PluginClassInfo GetValidPluginInfo(
212238
ImmutableArray<PluginClassInfo> pluginClasses,
213239
SourceProductionContext context)
214240
{
241+
if (pluginClasses.All(p => p is null || p.PropertyName == null))
242+
{
243+
context.ReportDiagnostic(Diagnostic.Create(
244+
SourceGeneratorDiagnostics.CouldNotFindPluginEntryClass,
245+
Location.None
246+
));
247+
return null;
248+
}
249+
215250
foreach (var pluginClass in pluginClasses)
216251
{
217-
if (pluginClass?.IsValid == true)
252+
if (pluginClass == null || pluginClass.PropertyName is null)
253+
{
254+
continue;
255+
}
256+
257+
if (pluginClass.IsValid == true)
258+
{
218259
return pluginClass;
260+
}
261+
262+
if (!pluginClass.IsStatic)
263+
{
264+
context.ReportDiagnostic(Diagnostic.Create(
265+
SourceGeneratorDiagnostics.ContextPropertyNotStatic,
266+
pluginClass.Location,
267+
pluginClass.PropertyName
268+
));
269+
}
270+
271+
if (pluginClass.IsPrivate)
272+
{
273+
context.ReportDiagnostic(Diagnostic.Create(
274+
SourceGeneratorDiagnostics.ContextPropertyIsPrivate,
275+
pluginClass.Location,
276+
pluginClass.PropertyName
277+
));
278+
}
219279

220-
if (pluginClass.IsValid == false)
280+
if (pluginClass.IsProtected)
221281
{
222-
// TODO
223-
//context.ReportDiagnostic(Diagnostic.Create(
224-
// SourceGeneratorDiagnostics.InvalidPluginConfiguration,
225-
// Location.None));
282+
context.ReportDiagnostic(Diagnostic.Create(
283+
SourceGeneratorDiagnostics.ContextPropertyIsProtected,
284+
pluginClass.Location,
285+
pluginClass.PropertyName
286+
));
226287
}
227288
}
289+
228290
return null;
229291
}
230292

293+
private static Location GetLocation(SyntaxTree syntaxTree, CSharpSyntaxNode classDeclaration)
294+
{
295+
return Location.Create(syntaxTree, classDeclaration.GetLocation().SourceSpan);
296+
}
297+
231298
#endregion
232299

233300
#region Generate Source
@@ -384,17 +451,24 @@ public LocalizableString(string key, string value, string summary, IEnumerable<L
384451

385452
public class PluginClassInfo
386453
{
454+
public Location Location { get; }
387455
public string ClassName { get; }
388456
public string PropertyName { get; }
389-
public bool IsValid { get; }
457+
public bool IsStatic { get; }
458+
public bool IsPrivate { get; }
459+
public bool IsProtected { get; }
390460

391461
public string ContextAccessor => $"{ClassName}.{PropertyName}";
462+
public bool IsValid => PropertyName != null && IsStatic && (!IsPrivate) && (!IsProtected);
392463

393-
public PluginClassInfo(string className, string propertyName, bool isValid)
464+
public PluginClassInfo(Location location, string className, string propertyName, bool isStatic, bool isPrivate, bool isProtected)
394465
{
466+
Location = location;
395467
ClassName = className;
396468
PropertyName = propertyName;
397-
IsValid = isValid;
469+
IsStatic = isStatic;
470+
IsPrivate = isPrivate;
471+
IsProtected = isProtected;
398472
}
399473
}
400474

0 commit comments

Comments
 (0)