Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -47,195 +47,193 @@ public class ExplicitLambdaArgumentTypes extends Recipe {

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new ExplicitLambdaArgumentTypesVisitor();
}

private static class ExplicitLambdaArgumentTypesVisitor extends JavaIsoVisitor<ExecutionContext> {
return new JavaIsoVisitor<ExecutionContext>() {

@Override
public J.Lambda visitLambda(J.Lambda lambda, ExecutionContext ctx) {

J.Lambda l = super.visitLambda(lambda, ctx);
if (l.getParameters().getParameters().size() <= 2 && !(l.getBody() instanceof J.Block)) {
return l;
}
@Override
public J.Lambda visitLambda(J.Lambda lambda, ExecutionContext ctx) {

J.Lambda after = l.withParameters(
l.getParameters().withParameters(
ListUtils.map(l.getParameters().getParameters(), parameter -> {
if (parameter instanceof J.VariableDeclarations) {
return maybeAddTypeExpression((J.VariableDeclarations) parameter);
}
return parameter;
})
)
);

if (after != l) {
after = after.withParameters(after.getParameters().withParenthesized(true));
}
return after;
}

private J.VariableDeclarations maybeAddTypeExpression(J.VariableDeclarations multiVariable) {
// if the type expression is null, it implies the types on the lambda arguments are implicit.
if (multiVariable.getTypeExpression() == null) {
J.VariableDeclarations.NamedVariable nv = multiVariable.getVariables().get(0);
TypeTree typeExpression = buildTypeTree(nv.getType(), Space.EMPTY);
if (typeExpression != null) {
// "? extends Foo" is not a valid type definition on its own. Unwrap wildcard and replace with its bound
if (typeExpression instanceof J.Wildcard) {
J.Wildcard wildcard = (J.Wildcard) typeExpression;
if (wildcard.getBoundedType() == null) {
return multiVariable;
}
typeExpression = buildTypeTree(wildcard.getBoundedType().getType(), Space.EMPTY);
}
multiVariable = multiVariable.withTypeExpression(typeExpression);
multiVariable = multiVariable.withVariables(ListUtils.map(multiVariable.getVariables(), (index, variable) -> {
if (index == 0) {
return variable.withPrefix(variable.getPrefix().withWhitespace(" "));
}
return variable;
}));
J.Lambda l = super.visitLambda(lambda, ctx);
if (l.getParameters().getParameters().size() <= 2 && !(l.getBody() instanceof J.Block)) {
return l;
}
}
return multiVariable;
}

private @Nullable TypeTree buildTypeTree(@Nullable JavaType type, Space space) {
if (type == null || type instanceof JavaType.Unknown) {
return null;
}
if (type instanceof JavaType.Primitive) {
return new J.Primitive(
Tree.randomId(),
space,
Markers.EMPTY,
(JavaType.Primitive) type
J.Lambda after = l.withParameters(
l.getParameters().withParameters(
ListUtils.map(l.getParameters().getParameters(), parameter -> {
if (parameter instanceof J.VariableDeclarations) {
return maybeAddTypeExpression((J.VariableDeclarations) parameter);
}
return parameter;
})
)
);
}
if (type instanceof JavaType.FullyQualified) {

JavaType.FullyQualified fq = (JavaType.FullyQualified) type;

J.Identifier identifier = new J.Identifier(Tree.randomId(),
space,
Markers.EMPTY,
emptyList(),
fq.getClassName(),
type instanceof JavaType.Parameterized ? ((JavaType.Parameterized) type).getType() : type,
null
);
if (after != l) {
after = after.withParameters(after.getParameters().withParenthesized(true));
}
return after;
}

if (!fq.getTypeParameters().isEmpty()) {
JContainer<Expression> typeParameters = buildTypeParameters(fq.getTypeParameters());
if (typeParameters == null) {
//If there is a problem resolving one of the type parameters, then do not return a type
//expression for the fully-qualified type.
return null;
private J.VariableDeclarations maybeAddTypeExpression(J.VariableDeclarations multiVariable) {
// if the type expression is null, it implies the types on the lambda arguments are implicit.
if (multiVariable.getTypeExpression() == null) {
J.VariableDeclarations.NamedVariable nv = multiVariable.getVariables().get(0);
TypeTree typeExpression = buildTypeTree(nv.getType(), Space.EMPTY);
if (typeExpression != null) {
// "? extends Foo" is not a valid type definition on its own. Unwrap wildcard and replace with its bound
if (typeExpression instanceof J.Wildcard) {
J.Wildcard wildcard = (J.Wildcard) typeExpression;
if (wildcard.getBoundedType() == null) {
return multiVariable;
}
typeExpression = buildTypeTree(wildcard.getBoundedType().getType(), Space.EMPTY);
}
multiVariable = multiVariable.withTypeExpression(typeExpression);
multiVariable = multiVariable.withVariables(ListUtils.map(multiVariable.getVariables(), (index, variable) -> {
if (index == 0) {
return variable.withPrefix(variable.getPrefix().withWhitespace(" "));
}
return variable;
}));
}
return new J.ParameterizedType(
Tree.randomId(),
space,
Markers.EMPTY,
identifier,
typeParameters,
new JavaType.Parameterized(null, fq, fq.getTypeParameters())
);

}
maybeAddImport(fq);
return identifier;
return multiVariable;
}
if (type instanceof JavaType.Array) {
JavaType.Array arrayType = (JavaType.Array) type;
// Get the base element type
JavaType elemType = arrayType.getElemType();
while (elemType instanceof JavaType.Array) {
elemType = ((JavaType.Array) elemType).getElemType();
}

// Build the base type expression
TypeTree result = buildTypeTree(elemType, space);
if (result == null) {
private @Nullable TypeTree buildTypeTree(@Nullable JavaType type, Space space) {
if (type == null || type instanceof JavaType.Unknown) {
return null;
}

// Count dimensions and build array type
JavaType currentType = type;
while (currentType instanceof JavaType.Array) {
result = new J.ArrayType(
if (type instanceof JavaType.Primitive) {
return new J.Primitive(
Tree.randomId(),
Space.EMPTY,
space,
Markers.EMPTY,
result,
null,
new JLeftPadded<>(Space.EMPTY, Space.EMPTY, Markers.EMPTY),
currentType
(JavaType.Primitive) type
);
currentType = ((JavaType.Array) currentType).getElemType();
}
return result;
}
if (type instanceof JavaType.Variable) {
return buildTypeTree(((JavaType.Variable) type).getType(), space);
}
if (type instanceof JavaType.GenericTypeVariable) {
JavaType.GenericTypeVariable genericType = (JavaType.GenericTypeVariable) type;
if (type instanceof JavaType.FullyQualified) {

JavaType.FullyQualified fq = (JavaType.FullyQualified) type;

if (!"?".equals(genericType.getName())) {
return new J.Identifier(Tree.randomId(),
J.Identifier identifier = new J.Identifier(Tree.randomId(),
space,
Markers.EMPTY,
emptyList(),
genericType.getName(),
type,
fq.getClassName(),
type instanceof JavaType.Parameterized ? ((JavaType.Parameterized) type).getType() : type,
null
);

if (!fq.getTypeParameters().isEmpty()) {
JContainer<Expression> typeParameters = buildTypeParameters(fq.getTypeParameters());
if (typeParameters == null) {
//If there is a problem resolving one of the type parameters, then do not return a type
//expression for the fully-qualified type.
return null;
}
return new J.ParameterizedType(
Tree.randomId(),
space,
Markers.EMPTY,
identifier,
typeParameters,
new JavaType.Parameterized(null, fq, fq.getTypeParameters())
);

}
maybeAddImport(fq);
return identifier;
}
JLeftPadded<J.Wildcard.Bound> bound = null;
NameTree boundedType = null;
if (genericType.getVariance() == JavaType.GenericTypeVariable.Variance.COVARIANT) {
bound = new JLeftPadded<>(Space.format(" "), J.Wildcard.Bound.Extends, Markers.EMPTY);
} else if (genericType.getVariance() == JavaType.GenericTypeVariable.Variance.CONTRAVARIANT) {
bound = new JLeftPadded<>(Space.format(" "), J.Wildcard.Bound.Super, Markers.EMPTY);
}
if (type instanceof JavaType.Array) {
JavaType.Array arrayType = (JavaType.Array) type;
// Get the base element type
JavaType elemType = arrayType.getElemType();
while (elemType instanceof JavaType.Array) {
elemType = ((JavaType.Array) elemType).getElemType();
}

if (!genericType.getBounds().isEmpty()) {
boundedType = buildTypeTree(genericType.getBounds().get(0), Space.format(" "));
if (boundedType == null) {
// Build the base type expression
TypeTree result = buildTypeTree(elemType, space);
if (result == null) {
return null;
}

// Count dimensions and build array type
JavaType currentType = type;
while (currentType instanceof JavaType.Array) {
result = new J.ArrayType(
Tree.randomId(),
Space.EMPTY,
Markers.EMPTY,
result,
null,
new JLeftPadded<>(Space.EMPTY, Space.EMPTY, Markers.EMPTY),
currentType
);
currentType = ((JavaType.Array) currentType).getElemType();
}
return result;
}
if (type instanceof JavaType.Variable) {
return buildTypeTree(((JavaType.Variable) type).getType(), space);
}
if (type instanceof JavaType.GenericTypeVariable) {
JavaType.GenericTypeVariable genericType = (JavaType.GenericTypeVariable) type;

if (!"?".equals(genericType.getName())) {
return new J.Identifier(Tree.randomId(),
space,
Markers.EMPTY,
emptyList(),
genericType.getName(),
type,
null
);
}
JLeftPadded<J.Wildcard.Bound> bound = null;
NameTree boundedType = null;
if (genericType.getVariance() == JavaType.GenericTypeVariable.Variance.COVARIANT) {
bound = new JLeftPadded<>(Space.format(" "), J.Wildcard.Bound.Extends, Markers.EMPTY);
} else if (genericType.getVariance() == JavaType.GenericTypeVariable.Variance.CONTRAVARIANT) {
bound = new JLeftPadded<>(Space.format(" "), J.Wildcard.Bound.Super, Markers.EMPTY);
}

return new J.Wildcard(
Tree.randomId(),
space,
Markers.EMPTY,
bound,
boundedType
);
if (!genericType.getBounds().isEmpty()) {
boundedType = buildTypeTree(genericType.getBounds().get(0), Space.format(" "));
if (boundedType == null) {
return null;
}
}

return new J.Wildcard(
Tree.randomId(),
space,
Markers.EMPTY,
bound,
boundedType
);
}
return null;
}
return null;
}

private @Nullable JContainer<Expression> buildTypeParameters(List<JavaType> typeParameters) {
List<JRightPadded<Expression>> typeExpressions = new ArrayList<>();
private @Nullable JContainer<Expression> buildTypeParameters(List<JavaType> typeParameters) {
List<JRightPadded<Expression>> typeExpressions = new ArrayList<>();

for (JavaType type : typeParameters) {
Expression typeParameterExpression = (Expression) buildTypeTree(type, Space.EMPTY);
if (typeParameterExpression == null) {
return null;
for (JavaType type : typeParameters) {
Expression typeParameterExpression = (Expression) buildTypeTree(type, Space.EMPTY);
if (typeParameterExpression == null) {
return null;
}
typeExpressions.add(new JRightPadded<>(
typeParameterExpression,
Space.EMPTY,
Markers.EMPTY
));
}
typeExpressions.add(new JRightPadded<>(
typeParameterExpression,
Space.EMPTY,
Markers.EMPTY
));
return JContainer.build(Space.EMPTY, typeExpressions, Markers.EMPTY);
}
return JContainer.build(Space.EMPTY, typeExpressions, Markers.EMPTY);
}
};
}

}
Loading
Loading