Dreamine.MVVM.Generators
1.0.13
Dreamine.MVVM.Generators 프로젝트의 API와 구성 요소를 제공합니다.
Toggle main menu visibility
로딩중...
검색중...
일치하는것 없음
DreamineEntryGenerator.cs
이 파일의 문서화 페이지로 가기
1
using
Microsoft.CodeAnalysis;
2
using
Microsoft.CodeAnalysis.CSharp.Syntax;
3
using
Microsoft.CodeAnalysis.Text;
4
using
System.Collections.Immutable;
5
using
System.Linq;
6
using
System.Text;
7
8
namespace
Dreamine.MVVM.Generators
9
{
14
[Generator]
15
public
sealed
class
DreamineEntryGenerator
: IIncrementalGenerator
16
{
17
private
const
string
EntryAttributeMetadataName
=
"Dreamine.MVVM.Attributes.DreamineEntryAttribute"
;
18
private
const
string
WpfApplicationMetadataName
=
"System.Windows.Application"
;
19
20
private
static
readonly DiagnosticDescriptor
EntryMustBePartialDescriptor
=
new
(
21
id:
"DMG001"
,
22
title:
"Entry class must be partial"
,
23
messageFormat:
"Class '{0}' marked with [DreamineEntry] must be declared partial"
,
24
category:
"Dreamine.MVVM.Generators"
,
25
defaultSeverity: DiagnosticSeverity.Error,
26
isEnabledByDefault:
true
);
27
28
private
static
readonly DiagnosticDescriptor
EntryMustInheritApplicationDescriptor
=
new
(
29
id:
"DMG002"
,
30
title:
"Entry class must inherit Application"
,
31
messageFormat:
"Class '{0}' marked with [DreamineEntry] must inherit System.Windows.Application"
,
32
category:
"Dreamine.MVVM.Generators"
,
33
defaultSeverity: DiagnosticSeverity.Error,
34
isEnabledByDefault:
true
);
35
36
private
static
readonly DiagnosticDescriptor
DuplicateEntryDescriptor
=
new
(
37
id:
"DMG003"
,
38
title:
"Only one entry class is allowed"
,
39
messageFormat:
"Only one valid [DreamineEntry] class is allowed but '{0}' is also marked as an entry"
,
40
category:
"Dreamine.MVVM.Generators"
,
41
defaultSeverity: DiagnosticSeverity.Error,
42
isEnabledByDefault:
true
);
43
48
public
void
Initialize
(IncrementalGeneratorInitializationContext context)
49
{
50
IncrementalValueProvider<INamedTypeSymbol?> entryAttributeSymbolProvider =
51
context.CompilationProvider.Select(
52
static
(compilation, _) => compilation.GetTypeByMetadataName(
EntryAttributeMetadataName
));
53
54
IncrementalValueProvider<INamedTypeSymbol?> applicationSymbolProvider =
55
context.CompilationProvider.Select(
56
static
(compilation, _) => compilation.GetTypeByMetadataName(
WpfApplicationMetadataName
));
57
58
IncrementalValueProvider<(INamedTypeSymbol? EntryAttributeSymbol, INamedTypeSymbol? ApplicationSymbol)> symbolsProvider =
59
entryAttributeSymbolProvider.Combine(applicationSymbolProvider);
60
61
IncrementalValueProvider<ImmutableArray<EntryCandidateModel>> candidateProvider =
62
context.SyntaxProvider
63
.CreateSyntaxProvider(
64
predicate:
static
(node, _) =>
IsCandidateSyntax
(node),
65
transform:
static
(syntaxContext, _) => syntaxContext)
66
.Combine(symbolsProvider)
67
.Select(
static
(pair, _) =>
TryCreateCandidate
(pair.Left, pair.Right.EntryAttributeSymbol, pair.Right.ApplicationSymbol))
68
.Where(
static
candidate => candidate is not
null
)
69
.Select(
static
(candidate, _) => candidate!)
70
.Collect();
71
72
context.RegisterSourceOutput(candidateProvider,
static
(sourceProductionContext, candidates) =>
73
{
74
Emit
(sourceProductionContext, candidates);
75
});
76
}
77
83
private
static
bool
IsCandidateSyntax
(SyntaxNode node)
84
{
85
return
node is ClassDeclarationSyntax classDeclaration &&
86
classDeclaration.AttributeLists.Count > 0;
87
}
88
99
private
static
EntryCandidateModel?
TryCreateCandidate
(
100
GeneratorSyntaxContext context,
101
INamedTypeSymbol? entryAttributeSymbol,
102
INamedTypeSymbol? applicationSymbol)
103
{
104
if
(entryAttributeSymbol is
null
|| applicationSymbol is
null
)
105
{
106
return
null
;
107
}
108
109
if
(context.Node is not ClassDeclarationSyntax classDeclaration)
110
{
111
return
null
;
112
}
113
114
if
(context.SemanticModel.GetDeclaredSymbol(classDeclaration) is not INamedTypeSymbol classSymbol)
115
{
116
return
null
;
117
}
118
119
bool
hasEntryAttribute = classSymbol
120
.GetAttributes()
121
.Any(attribute => SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, entryAttributeSymbol));
122
123
if
(!hasEntryAttribute)
124
{
125
return
null
;
126
}
127
128
string
namespaceName = classSymbol.ContainingNamespace is { IsGlobalNamespace:
false
}
129
? classSymbol.ContainingNamespace.ToDisplayString()
130
:
string
.Empty;
131
132
return
new
EntryCandidateModel(
133
classSymbol,
134
classDeclaration,
135
namespaceName,
136
classSymbol.Name,
137
IsPartial
(classDeclaration),
138
InheritsFrom
(classSymbol, applicationSymbol));
139
}
140
146
private
static
void
Emit
(
147
SourceProductionContext context,
148
ImmutableArray<EntryCandidateModel> candidates)
149
{
150
if
(candidates.IsDefaultOrEmpty)
151
{
152
return
;
153
}
154
155
foreach
(EntryCandidateModel candidate
in
candidates)
156
{
157
if
(!candidate.IsPartial)
158
{
159
context.ReportDiagnostic(Diagnostic.Create(
160
EntryMustBePartialDescriptor
,
161
candidate.ClassDeclaration.Identifier.GetLocation(),
162
candidate.ClassName));
163
}
164
165
if
(!candidate.IsApplicationDerived)
166
{
167
context.ReportDiagnostic(Diagnostic.Create(
168
EntryMustInheritApplicationDescriptor
,
169
candidate.ClassDeclaration.Identifier.GetLocation(),
170
candidate.ClassName));
171
}
172
}
173
174
ImmutableArray<EntryCandidateModel> validCandidates = candidates
175
.Where(
static
candidate => candidate.IsPartial && candidate.IsApplicationDerived)
176
.ToImmutableArray();
177
178
if
(validCandidates.Length == 0)
179
{
180
return
;
181
}
182
183
if
(validCandidates.Length > 1)
184
{
185
foreach
(EntryCandidateModel candidate
in
validCandidates)
186
{
187
context.ReportDiagnostic(Diagnostic.Create(
188
DuplicateEntryDescriptor
,
189
candidate.ClassDeclaration.Identifier.GetLocation(),
190
candidate.ClassName));
191
}
192
193
return
;
194
}
195
196
EntryCandidateModel entryCandidate = validCandidates[0];
197
string
source =
BuildEntrySource
(entryCandidate.Namespace, entryCandidate.ClassName);
198
199
context.AddSource(
200
$
"{entryCandidate.ClassName}.DreamineEntry.g.cs"
,
201
SourceText.From(source, Encoding.UTF8));
202
}
203
209
private
static
bool
IsPartial
(ClassDeclarationSyntax classDeclaration)
210
{
211
return
classDeclaration.Modifiers.Any(
static
modifier => modifier.IsKind(Microsoft.CodeAnalysis.CSharp.SyntaxKind.PartialKeyword));
212
}
213
220
private
static
bool
InheritsFrom
(INamedTypeSymbol symbol, INamedTypeSymbol baseTypeSymbol)
221
{
222
INamedTypeSymbol? current = symbol;
223
224
while
(current is not
null
)
225
{
226
if
(SymbolEqualityComparer.Default.Equals(current, baseTypeSymbol))
227
{
228
return
true
;
229
}
230
231
current = current.BaseType;
232
}
233
234
return
false
;
235
}
236
243
private
static
string
BuildEntrySource
(
string
namespaceName,
string
className)
244
{
245
string
namespaceBlockStart =
string
.IsNullOrWhiteSpace(namespaceName)
246
? string.Empty
247
: $
"namespace {namespaceName}\r\n{{"
;
248
249
string
namespaceBlockEnd =
string
.IsNullOrWhiteSpace(namespaceName)
250
? string.Empty
251
:
"}"
;
252
253
return
$$
""
"
254
// <auto-generated />
255
#nullable enable
256
using System.Windows;
257
using Dreamine.MVVM.Wpf;
258
259
{{namespaceBlockStart}}
260
public partial class {{className}}
261
{
266
protected override void OnStartup(StartupEventArgs e)
267
{
268
base.OnStartup(e);
269
270
var rootAssembly = typeof({{className}}).Assembly;
271
272
RegisterBefore();
273
274
DreamineWpfOptions options = DreamineWpfOptions.CreateDefault();
275
ConfigureDreamine(options);
276
277
DreamineAppBuilder.Initialize(rootAssembly, options);
278
279
ShowMainWindow();
280
Dispatcher.InvokeAsync(() => RegisterAfter());
281
}
282
286
static partial void RegisterBefore();
287
292
static partial void ConfigureDreamine(DreamineWpfOptions options);
293
297
static partial void RegisterAfter();
298
302
static partial void ShowMainWindow();
303
}
304
{{namespaceBlockEnd}}
305
"
""
;
306
}
307
}
308
}
Dreamine.MVVM.Generators
Definition
DreamineAutoWiringGenerator.cs:11
Dreamine.MVVM.Generators.DreamineEntryGenerator
DreamineEntryAttribute가 적용된 WPF 엔트리 클래스를 분석하고 Dreamine 부트스트랩 코드를 생성하는 증분 생성기입니다.
Definition
DreamineEntryGenerator.cs:16
Dreamine.MVVM.Generators.DreamineEntryGenerator.EntryMustBePartialDescriptor
static readonly DiagnosticDescriptor EntryMustBePartialDescriptor
Definition
DreamineEntryGenerator.cs:20
Dreamine.MVVM.Generators.DreamineEntryGenerator.Initialize
void Initialize(IncrementalGeneratorInitializationContext context)
증분 생성기 파이프라인을 초기화합니다.
Definition
DreamineEntryGenerator.cs:48
Dreamine.MVVM.Generators.DreamineEntryGenerator.IsPartial
static bool IsPartial(ClassDeclarationSyntax classDeclaration)
클래스 선언이 partial인지 확인합니다.
Definition
DreamineEntryGenerator.cs:209
Dreamine.MVVM.Generators.DreamineEntryGenerator.TryCreateCandidate
static ? EntryCandidateModel TryCreateCandidate(GeneratorSyntaxContext context, INamedTypeSymbol? entryAttributeSymbol, INamedTypeSymbol? applicationSymbol)
구문/시맨틱 정보를 기반으로 엔트리 후보 모델을 생성합니다.
Definition
DreamineEntryGenerator.cs:99
Dreamine.MVVM.Generators.DreamineEntryGenerator.EntryMustInheritApplicationDescriptor
static readonly DiagnosticDescriptor EntryMustInheritApplicationDescriptor
Definition
DreamineEntryGenerator.cs:28
Dreamine.MVVM.Generators.DreamineEntryGenerator.Emit
static void Emit(SourceProductionContext context, ImmutableArray< EntryCandidateModel > candidates)
수집된 엔트리 후보를 진단하고 소스를 생성합니다.
Definition
DreamineEntryGenerator.cs:146
Dreamine.MVVM.Generators.DreamineEntryGenerator.DuplicateEntryDescriptor
static readonly DiagnosticDescriptor DuplicateEntryDescriptor
Definition
DreamineEntryGenerator.cs:36
Dreamine.MVVM.Generators.DreamineEntryGenerator.InheritsFrom
static bool InheritsFrom(INamedTypeSymbol symbol, INamedTypeSymbol baseTypeSymbol)
대상 클래스가 지정한 기반 타입을 상속하는지 확인합니다.
Definition
DreamineEntryGenerator.cs:220
Dreamine.MVVM.Generators.DreamineEntryGenerator.IsCandidateSyntax
static bool IsCandidateSyntax(SyntaxNode node)
엔트리 후보가 될 수 있는 구문인지 확인합니다.
Definition
DreamineEntryGenerator.cs:83
Dreamine.MVVM.Generators.DreamineEntryGenerator.BuildEntrySource
static string BuildEntrySource(string namespaceName, string className)
엔트리 부트스트랩 소스 코드를 생성합니다.
Definition
DreamineEntryGenerator.cs:243
Dreamine.MVVM.Generators.DreamineEntryGenerator.EntryAttributeMetadataName
const string EntryAttributeMetadataName
Definition
DreamineEntryGenerator.cs:17
Dreamine.MVVM.Generators.DreamineEntryGenerator.WpfApplicationMetadataName
const string WpfApplicationMetadataName
Definition
DreamineEntryGenerator.cs:18
DreamineEntryGenerator.cs
다음에 의해 생성됨 :
1.17.0