44 */
55package net .minecraftforge .eventbus .validator ;
66
7+ import com .sun .source .tree .IdentifierTree ;
8+ import com .sun .source .tree .MemberSelectTree ;
9+ import com .sun .source .tree .MethodInvocationTree ;
10+ import com .sun .source .tree .TypeCastTree ;
11+ import com .sun .source .tree .VariableTree ;
12+ import com .sun .source .util .TreePath ;
13+ import com .sun .source .util .Trees ;
14+
715import javax .annotation .processing .ProcessingEnvironment ;
816import javax .annotation .processing .RoundEnvironment ;
917import javax .lang .model .element .Element ;
1826
1927public final class EventBusValidator extends AbstractValidator {
2028 private Types types ;
29+ private Trees trees ;
2130
2231 @ Override
2332 public void init (ProcessingEnvironment processingEnv ) {
2433 super .init (processingEnv );
2534 types = processingEnv .getTypeUtils ();
35+ trees = Trees .instance (processingEnv );
2636 }
2737
2838 @ Override
@@ -38,7 +48,8 @@ private void process(Element element) {
3848 if (element .getKind () == ElementKind .FIELD ) {
3949 TypeMirror erasedFieldType = types .erasure (element .asType ());
4050 var isStandardEventBus = types .isSameType (erasedFieldType , BusTypes .eventBus );
41- if (!(isStandardEventBus || types .isSameType (erasedFieldType , BusTypes .cancellableEventBus )))
51+ var isCancellableEventBus = false ;
52+ if (!(isStandardEventBus || (isCancellableEventBus = types .isSameType (erasedFieldType , BusTypes .cancellableEventBus ))))
4253 return ; // only interested in (Cancellable)EventBus fields
4354
4455 // Show a warning if the bus field is not final
@@ -62,11 +73,44 @@ private void process(Element element) {
6273 );
6374 }
6475 }
76+
77+ // Show a warning if the field initialiser casts the result of EventBus.create(...) to CancellableEventBus
78+ if (isCancellableEventBus ) {
79+ checkForCastedEventBusCreate (element );
80+ }
6581 }
6682
6783
6884 for (var child : element .getEnclosedElements ()) {
6985 process (child );
7086 }
7187 }
88+
89+ private void checkForCastedEventBusCreate (Element fieldElement ) {
90+ TreePath path = trees .getPath (fieldElement );
91+ if (path == null || !(path .getLeaf () instanceof VariableTree variableTree )) return ;
92+
93+ // Check if initialiser is a cast expression and the expression being cast is a method invocation
94+ if (!(variableTree .getInitializer () instanceof TypeCastTree cast
95+ && cast .getExpression () instanceof MethodInvocationTree methodInvocation )) return ;
96+
97+ // Check if it's a call to EventBus.create(...)
98+ if (!(methodInvocation .getMethodSelect () instanceof MemberSelectTree memberSelectTree
99+ && memberSelectTree .getExpression () instanceof IdentifierTree identifierTree
100+ && identifierTree .getName ().contentEquals ("EventBus" )
101+ && memberSelectTree .getIdentifier ().contentEquals ("create" ))) return ;
102+
103+ // And that its result is being cast to CancellableEventBus...
104+ // Note: Can't use types#getTypeMirror here because it returns null for TypeCastTree when wrapped in TreePath in
105+ // this context, so we have to manually resolve the type element from the tree instead.
106+ if (trees .getElement (new TreePath (new TreePath (path , cast ), cast .getType ())) instanceof TypeElement typeElement ) {
107+ if (types .isSameType (types .erasure (typeElement .asType ()), BusTypes .cancellableEventBus )) {
108+ processingEnv .getMessager ().printWarning (
109+ "CancellableEventBus field " + fieldElement .getEnclosingElement ().getSimpleName () + '.' + fieldElement .getSimpleName () +
110+ " should call CancellableEventBus#create(Class) directly instead of casting the result from EventBus#create(Class)" ,
111+ fieldElement
112+ );
113+ }
114+ }
115+ }
72116}
0 commit comments