-
-
Notifications
You must be signed in to change notification settings - Fork 192
/
IMessagerEx.java
499 lines (406 loc) · 17.9 KB
/
IMessagerEx.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/*
* This file is part of Mixin, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.tools.obfuscation.interfaces;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.processing.Messager;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.tools.Diagnostic.Kind;
import org.spongepowered.tools.obfuscation.SupportedOptions;
import org.spongepowered.tools.obfuscation.interfaces.IMixinAnnotationProcessor.CompilerEnvironment;
/**
* An extended {@link Messager} which supports messages with configurable
* message levels based on the supplied {@link MessageType}.
*/
public interface IMessagerEx extends Messager {
/**
* Message types, centralised so that individual error/warning levels can be
* controlled at runtime.
*/
public static enum MessageType {
/**
* Level for NOTE messages which are informational and can be suppressed
* by quiet
*/
INFO(Kind.NOTE),
/** All other NOTE level messages */
NOTE(Kind.NOTE),
/** Uncategorised (usually unexpected or critical) ERROR messages */
ERROR(Kind.ERROR),
/** Uncategorised (usually unexpected or important) WARNING messages */
WARNING(Kind.WARNING),
/** @Mixin annotation on a non class or interface, eg. package */
MIXIN_ON_INVALID_TYPE(Kind.ERROR),
/** Soft target for mixin not found */
MIXIN_SOFT_TARGET_NOT_FOUND(Kind.ERROR),
/** Soft target for mixin not found, but imaginary type was returned */
MIXIN_SOFT_TARGET_NOT_RESOLVED(Kind.WARNING),
/** Soft target for mixin is public */
MIXIN_SOFT_TARGET_IS_PUBLIC(Kind.WARNING),
/** @Mixin annotation doesn't specify any targets */
MIXIN_NO_TARGETS(Kind.ERROR),
/** Errors raised by the parent validator */
PARENT_VALIDATOR(Kind.ERROR),
/** Errors raised by the target validator */
TARGET_VALIDATOR(Kind.ERROR),
/** Unexpected error attaching accessor/invoker */
ACCESSOR_ATTACH_ERROR(Kind.ERROR),
/** Accessor target could not be found */
ACCESSOR_TARGET_NOT_FOUND(Kind.ERROR),
/** The AP was unable to determine the accessor type for some reason */
ACCESSOR_TYPE_UNSUPPORTED(Kind.WARNING),
/**
* The AP was unable to determine the accessor name either from the
* annotation or using the inflector on the annoated method name
*/
ACCESSOR_NAME_UNRESOLVED(Kind.WARNING),
/** Invoker uses a raw return type when the return type is generic */
INVOKER_RAW_RETURN_TYPE(Kind.WARNING),
/** Generic args of factory invoker incompatible with return type */
FACTORY_INVOKER_GENERIC_ARGS(Kind.ERROR),
/** Return type of factory invoker does not match target type */
FACTORY_INVOKER_RETURN_TYPE(Kind.ERROR),
/** Factory invoker is not declared as static */
FACTORY_INVOKER_NONSTATIC(Kind.ERROR),
/** Constraint violation with supplied tokens */
CONSTRAINT_VIOLATION(Kind.ERROR),
/** Constraint expression is not valid */
INVALID_CONSTRAINT(Kind.WARNING),
/** Mapping conflict encountered on accessor method */
ACCESSOR_MAPPING_CONFLICT(Kind.ERROR),
/** Mapping conflict encountered on injector method */
INJECTOR_MAPPING_CONFLICT(Kind.ERROR),
/** Mapping conflict encountered on overwrite method */
OVERWRITE_MAPPING_CONFLICT(Kind.ERROR),
/** Mapping conflict encountered on shadow method */
SHADOW_MAPPING_CONFLICT(Kind.ERROR),
/** Injector-annotated method encounterd in an interface */
INJECTOR_IN_INTERFACE(Kind.ERROR),
/** Injector annotation encountered on element which is not a method */
INJECTOR_ON_NON_METHOD_ELEMENT(Kind.WARNING),
/** Overwrite annotation encountered on element which is not a method */
OVERWRITE_ON_NON_METHOD_ELEMENT(Kind.ERROR),
/** Accessor annotation encountered on element which is not a method */
ACCESSOR_ON_NON_METHOD_ELEMENT(Kind.ERROR),
/** Shadow annotation encountered on non- field or method element */
SHADOW_ON_INVALID_ELEMENT(Kind.ERROR),
/** Injector annotation encountered on method which isn't in a mixin */
INJECTOR_ON_NON_MIXIN_METHOD(Kind.ERROR),
/** Overwrite annotation encountered on method which isn't in a mixin */
OVERWRITE_ON_NON_MIXIN_METHOD(Kind.ERROR),
/** Accessor annotation encountered on method which isn't in a mixin */
ACCESSOR_ON_NON_MIXIN_METHOD(Kind.ERROR),
/** Shadow annotation encountered on element which isn't in a mixin */
SHADOW_ON_NON_MIXIN_ELEMENT(Kind.ERROR),
/** @Implements annotation on a non- class or interface element */
SOFT_IMPLEMENTS_ON_INVALID_TYPE(Kind.ERROR),
/** @Implements annotation on a non-mixin class or interface */
SOFT_IMPLEMENTS_ON_NON_MIXIN(Kind.ERROR),
/** @Implements annotation has no values */
SOFT_IMPLEMENTS_EMPTY(Kind.WARNING),
/** A target selector failed validation */
TARGET_SELECTOR_VALIDATION(Kind.ERROR),
/** An injection point target is missing owner, descriptor, or both */
INJECTOR_TARGET_NOT_FULLY_QUALIFIED(Kind.ERROR),
/**
* A descriptor is missing on an injector target in a multi-target mixin
*/
MISSING_INJECTOR_DESC_MULTITARGET(Kind.ERROR),
/**
* A descriptor is missing on an injector target in a single-target
* mixin but enclosing type information is unavailable (imaginary) or
* could not be determined from the target class.
*/
MISSING_INJECTOR_DESC_SINGLETARGET(Kind.WARNING),
/**
* A descriptor is missing on an injector target in an @Pseudo mixin
*/
MISSING_INJECTOR_DESC_SIMULATED(Kind.OTHER),
/**
* The target element of an injection could not be located in the target
*/
TARGET_ELEMENT_NOT_FOUND(Kind.WARNING),
/** Mismatched visibility of overwrite with resolved target, warn */
METHOD_VISIBILITY(Kind.WARNING),
/** Obf provider did not return a result for the accessor target */
NO_OBFDATA_FOR_ACCESSOR(Kind.WARNING),
/** Obf provider did not return a result for the specified class */
NO_OBFDATA_FOR_CLASS(Kind.WARNING),
/**
* Obf provider did not return a result for the injector target and the
* target is a normal method
*/
NO_OBFDATA_FOR_TARGET(Kind.ERROR),
/**
* Obf provider did not return a result for the injector target but the
* target is a constructor, warn
*/
NO_OBFDATA_FOR_CTOR(Kind.WARNING),
/**
* Obf provider did not return a result for the specified overwrite and
* the overwrite target is an instance method
*/
NO_OBFDATA_FOR_OVERWRITE(Kind.ERROR),
/**
* Obf provider did not return a result for the specified overwrite but
* the overwrite target is static, warn
*/
NO_OBFDATA_FOR_STATIC_OVERWRITE(Kind.WARNING),
/** Obf provider did not return a result for the specified field */
NO_OBFDATA_FOR_FIELD(Kind.WARNING),
/** Obf provider did not return a result for the specified method */
NO_OBFDATA_FOR_METHOD(Kind.WARNING),
/** Obf provider did not return a result for the shadow target */
NO_OBFDATA_FOR_SHADOW(Kind.WARNING),
/**
* Obf provider did not return a result for the shadow target but the
* enclosing type is simulated, warn
*/
NO_OBFDATA_FOR_SIMULATED_SHADOW(Kind.WARNING),
/**
* Obf provider did not return a result for the specified
* soft-implemented method
*/
NO_OBFDATA_FOR_SOFT_IMPLEMENTS(Kind.ERROR),
/**
* A method in a multi-target mixin has conflicting descriptors so the
* AP is storing the bare reference (name only) in the refmap, which has
* resolvability issues.
*/
BARE_REFERENCE(Kind.WARNING),
/**
* All warnings related to overwrite javadoc contents, can be upgrade to
* error by {@link SupportedOptions#OVERWRITE_ERROR_LEVEL}
*/
OVERWRITE_DOCS(Kind.WARNING);
/**
* Prefix applied to supported commandline options for message levels,
* eg. <tt>INVALID_CONSTRAINT</tt> becomes
* <tt>MSG_INVALID_CONSTRAINT</tt>
*/
private static final String OPTION_PREFIX = "MSG_";
/**
* Development option, enable decoration of messages to make it easier
* to determine message origins.
*/
private static boolean decorate = false;
/**
* Global option, prefix for all annotation processor messages to make
* them easier to differentiate from other messages
*/
private static String prefix = "";
/**
* The original message kind
*/
private final Kind originalKind;
/**
* The current message kind
*/
private Kind kind;
/**
* Whether this message is globally enabled or disabled
*/
private boolean enabled = true;
/**
* Whether this message kind has been specified manually by the user
*/
private boolean setByUser = false;
private MessageType(Kind kind) {
this.originalKind = this.kind = kind;
}
/**
* Get whether the message is treated as an error
*/
public boolean isError() {
return this.kind == Kind.ERROR;
}
/**
* Get the current message kind
*/
public Kind getKind() {
return this.kind;
}
/**
* Set the current kind
*
* @param kind kind to set
*/
public void setKind(Kind kind) {
this.kind = kind;
this.setByUser = true;
}
/**
* Set the current kind to a lower kind, but only if the level has not
* been set manually by the user. Used when an IDE is detected to
* selectively lower the severity of some messages but we don't want to
* override anything manually specified by the user.
*
* @param kind kind to set
*/
public void quench(Kind kind) {
if (!this.setByUser && kind.ordinal() > this.kind.ordinal()) {
this.kind = kind;
}
}
/**
* Get whether this message type is enabled
*/
public boolean isEnabled() {
return this.enabled;
}
/**
* Set whether this message type is enabled
*
* @param enabled true to enable the message
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
this.setByUser = true;
}
/**
* Reset the message kind to the original value and re-enable the
* message if it was disabled
*/
public void reset() {
this.kind = this.originalKind;
this.enabled = true;
this.setByUser = false;
}
/**
* Called when the message is passed to a real Messager, allows the
* message to be decorated in development and other special situations
* such as inside an IDE
*
* @param msg Message to decorate
* @return Decorated message
*/
public CharSequence decorate(CharSequence msg) {
return MessageType.decorate ? String.format("%s[%s] %s", MessageType.prefix, this.name(), msg) : MessageType.prefix + msg;
}
/**
* Set whether development decoration of messages is enabled
*
* @param enabled true to enable dev decorations
*/
public static void setDecoration(boolean enabled) {
MessageType.decorate = enabled;
}
/**
* Set the prefix for all messages, used to distinguish mixin AP
* messages from other compiler messages in IDE for example
*
* @param prefix Prefix to apply to all messages (include trailing
* space)
*/
public static void setPrefix(String prefix) {
MessageType.prefix = prefix;
}
/**
* Get all the available options for configuring message levels
*/
public static Set<String> getSupportedOptions() {
Set<String> supportedOptions = new HashSet<String>();
for (MessageType type : MessageType.values()) {
supportedOptions.add(MessageType.OPTION_PREFIX + type.name());
}
return supportedOptions;
}
/**
* Apply options supplied to the AP which configure individual message
* levels
*
* @param env Compiler environment
* @param options Options to apply
*/
public static void applyOptions(CompilerEnvironment env, IOptionProvider options) {
// Enable decorations if the option is specified
MessageType.setDecoration("true".equalsIgnoreCase(options.getOption(SupportedOptions.SHOW_MESSAGE_TYPES)));
// Apply the "quiet" option if specified, or if in dev env
MessageType.INFO.setEnabled(!(env.isDevelopmentEnvironment() || "true".equalsIgnoreCase(options.getOption(SupportedOptions.QUIET))));
// Selectively enable injector-in-interface as an error based on user option
MessageType.INJECTOR_IN_INTERFACE.setEnabled(options.getOption(SupportedOptions.DISABLE_INTERFACE_MIXINS, false));
// Legacy option
if ("error".equalsIgnoreCase(options.getOption(SupportedOptions.OVERWRITE_ERROR_LEVEL))) {
MessageType.OVERWRITE_DOCS.setKind(Kind.ERROR);
}
// Apply all other custom message levels
for (MessageType type : MessageType.values()) {
String option = options.getOption(MessageType.OPTION_PREFIX + type.name());
if (option == null) {
continue;
}
if ("note".equalsIgnoreCase(option)) {
type.setKind(Kind.NOTE);
} else if ("warning".equalsIgnoreCase(option)) {
type.setKind(Kind.WARNING);
} else if ("error".equalsIgnoreCase(option)) {
type.setKind(Kind.ERROR);
} else if ("disabled".equalsIgnoreCase(option)) {
type.setEnabled(false);
}
}
}
}
/**
* Prints a message of the specified kind.
*
* @param type the message type
* @param msg the message, or an empty string if none
*/
void printMessage(MessageType type, CharSequence msg);
/**
* Prints a message of the specified kind at the location of the
* element.
*
* @param type the message type
* @param msg the message, or an empty string if none
* @param e the element to use as a position hint
*/
void printMessage(MessageType type, CharSequence msg, Element e);
/**
* Prints a message of the specified kind at the location of the
* annotation mirror of the annotated element.
*
* @param type the message type
* @param msg the message, or an empty string if none
* @param e the annotated element
* @param a the annotation to use as a position hint
*/
void printMessage(MessageType type, CharSequence msg, Element e, AnnotationMirror a);
/**
* Prints a message of the specified kind at the location of the
* annotation value inside the annotation mirror of the annotated
* element.
*
* @param type the message type
* @param msg the message, or an empty string if none
* @param e the annotated element
* @param a the annotation containing the annotation value
* @param v the annotation value to use as a position hint
*/
void printMessage(MessageType type, CharSequence msg, Element e, AnnotationMirror a, AnnotationValue v);
}