Skip to content

Commit

Permalink
Features/944 tidy stream nullability propagator (#985)
Browse files Browse the repository at this point in the history
#944 - Tidy function `StreamNullabilityPropagator ::
onMatchMethodInvocation`

- As suggested in #944, I have extracted three dedicated utility
functions for handling filter/map/collect methods.
- Following that, I have inverted 2 of the if statements to eliminate
the multiple levels of nesting

(the two changes described above can be seen in the 2 different commits)

Fixes #944
  • Loading branch information
etrandafir93 committed Jun 21, 2024
1 parent e2500c8 commit cc3dee3
Showing 1 changed file with 68 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -214,61 +214,75 @@ public void onMatchMethodInvocation(
VisitorState state = methodAnalysisContext.state();
Type receiverType = ASTHelpers.getReceiverType(tree);
for (StreamTypeRecord streamType : models) {
if (streamType.matchesType(receiverType, state)) {
// Build observable call chain
buildObservableCallChain(tree);

// Dispatch to code handling specific observer methods
if (streamType.isFilterMethod(methodSymbol) && methodSymbol.getParameters().length() == 1) {
ExpressionTree argTree = tree.getArguments().get(0);
if (argTree instanceof NewClassTree) {
ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
// Ensure that this `new A() ...` has a custom class body, otherwise, we skip for now.
// In the future, we could look at the declared type and its inheritance chain, at least
// for
// filters.
if (annonClassBody != null) {
handleFilterAnonClass(streamType, tree, annonClassBody, state);
}
} else if (argTree instanceof LambdaExpressionTree) {
LambdaExpressionTree lambdaTree = (LambdaExpressionTree) argTree;
handleFilterLambda(streamType, tree, lambdaTree, state);
}
} else if (streamType.isMapMethod(methodSymbol)
&& methodSymbol.getParameters().length() == 1) {
ExpressionTree argTree = tree.getArguments().get(0);
if (argTree instanceof NewClassTree) {
ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
// Ensure that this `new B() ...` has a custom class body, otherwise, we skip for now.
if (annonClassBody != null) {
MapLikeMethodRecord methodRecord = streamType.getMaplikeMethodRecord(methodSymbol);
handleMapOrCollectAnonClassBody(
methodRecord,
annonClassBody,
t -> observableCallToInnerMethodOrLambda.put(tree, t));
}
} else if (argTree instanceof LambdaExpressionTree) {
observableCallToInnerMethodOrLambda.put(tree, argTree);
} else if (argTree instanceof MemberReferenceTree) {
observableCallToInnerMethodOrLambda.put(tree, argTree);
}
} else {
if (methodSymbol.getParameters().length() == 1) {
// We can have multiple CollectLikeMethodRecords for a single collect method, reflecting
// the different possible collector factory methods whose result may be passed to a
// collect call. At a single collect call site, at most one of these records will be
// relevant. So, we loop through them all, but break out of the loop as soon as we find
// one that matches.
for (CollectLikeMethodRecord collectlikeMethodRecord :
streamType.getCollectlikeMethodRecords(methodSymbol)) {
boolean handled = handleCollectCall(tree, collectlikeMethodRecord);
if (handled) {
break;
}
}
}
}
if (!streamType.matchesType(receiverType, state)) {
continue;
}
// Build observable call chain
buildObservableCallChain(tree);
if (methodSymbol.getParameters().length() != 1) {
continue;
}

// Dispatch to code handling specific observer methods
if (streamType.isFilterMethod(methodSymbol)) {
handleFilterMethod(tree, streamType, state);
} else if (streamType.isMapMethod(methodSymbol)) {
handleMapMethod(tree, streamType, methodSymbol);
} else {
handleCollectMethod(tree, streamType, methodSymbol);
}
}
}

private void handleCollectMethod(
MethodInvocationTree tree, StreamTypeRecord streamType, Symbol.MethodSymbol methodSymbol) {
// We can have multiple CollectLikeMethodRecords for a single collect method, reflecting
// the different possible collector factory methods whose result may be passed to a
// collect call. At a single collect call site, at most one of these records will be
// relevant. So, we loop through them all, but break out of the loop as soon as we find
// one that matches.
for (CollectLikeMethodRecord collectlikeMethodRecord :
streamType.getCollectlikeMethodRecords(methodSymbol)) {
boolean handled = handleCollectCall(tree, collectlikeMethodRecord);
if (handled) {
break;
}
}
}

private void handleFilterMethod(
MethodInvocationTree tree, StreamTypeRecord streamType, VisitorState state) {
ExpressionTree argTree = tree.getArguments().get(0);
if (argTree instanceof NewClassTree) {
ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
// Ensure that this `new A() ...` has a custom class body, otherwise, we skip for now.
// In the future, we could look at the declared type and its inheritance chain, at least
// for
// filters.
if (annonClassBody != null) {
handleFilterAnonClass(streamType, tree, annonClassBody, state);
}
} else if (argTree instanceof LambdaExpressionTree) {
LambdaExpressionTree lambdaTree = (LambdaExpressionTree) argTree;
handleFilterLambda(streamType, tree, lambdaTree, state);
}
}

private void handleMapMethod(
MethodInvocationTree tree, StreamTypeRecord streamType, Symbol.MethodSymbol methodSymbol) {
ExpressionTree argTree = tree.getArguments().get(0);
if (argTree instanceof NewClassTree) {
ClassTree annonClassBody = ((NewClassTree) argTree).getClassBody();
// Ensure that this `new B() ...` has a custom class body, otherwise, we skip for now.
if (annonClassBody != null) {
MapLikeMethodRecord methodRecord = streamType.getMaplikeMethodRecord(methodSymbol);
handleMapOrCollectAnonClassBody(
methodRecord, annonClassBody, t -> observableCallToInnerMethodOrLambda.put(tree, t));
}
} else if (argTree instanceof LambdaExpressionTree) {
observableCallToInnerMethodOrLambda.put(tree, argTree);
} else if (argTree instanceof MemberReferenceTree) {
observableCallToInnerMethodOrLambda.put(tree, argTree);
}
}

Expand Down

0 comments on commit cc3dee3

Please sign in to comment.