use of com.github.javaparser.ast.expr.LambdaExpr in project javaparser by javaparser.
the class TypeExtractor method resolveLambda.
private ResolvedType resolveLambda(LambdaExpr node, ResolvedType result) {
// We need to replace the type variables
Context ctx = JavaParserFactory.getContext(node, typeSolver);
result = solveGenericTypes(result, ctx);
// We should find out which is the functional method (e.g., apply) and replace the params of the
// solveLambdas with it, to derive so the values. We should also consider the value returned by the
// lambdas
Optional<MethodUsage> functionalMethod = FunctionalInterfaceLogic.getFunctionalMethod(result);
if (functionalMethod.isPresent()) {
LambdaExpr lambdaExpr = node;
InferenceContext lambdaCtx = new InferenceContext(MyObjectProvider.INSTANCE);
InferenceContext funcInterfaceCtx = new InferenceContext(MyObjectProvider.INSTANCE);
// At this point parameterType
// if Function<T=? super Stream.T, ? extends map.R>
// we should replace Stream.T
ResolvedType functionalInterfaceType = ReferenceTypeImpl.undeterminedParameters(functionalMethod.get().getDeclaration().declaringType(), typeSolver);
lambdaCtx.addPair(result, functionalInterfaceType);
ResolvedType actualType;
if (lambdaExpr.getBody() instanceof ExpressionStmt) {
actualType = facade.getType(((ExpressionStmt) lambdaExpr.getBody()).getExpression());
} else if (lambdaExpr.getBody() instanceof BlockStmt) {
BlockStmt blockStmt = (BlockStmt) lambdaExpr.getBody();
// Get all the return statements in the lambda block
List<ReturnStmt> returnStmts = blockStmt.findAll(ReturnStmt.class);
if (returnStmts.size() > 0) {
actualType = returnStmts.stream().map(returnStmt -> returnStmt.getExpression().map(e -> facade.getType(e)).orElse(ResolvedVoidType.INSTANCE)).filter(x -> x != null && !x.isVoid() && !x.isNull()).findFirst().orElse(ResolvedVoidType.INSTANCE);
} else {
actualType = ResolvedVoidType.INSTANCE;
}
} else {
throw new UnsupportedOperationException();
}
ResolvedType formalType = functionalMethod.get().returnType();
// Infer the functional interfaces' return vs actual type
funcInterfaceCtx.addPair(formalType, actualType);
// Substitute to obtain a new type
ResolvedType functionalTypeWithReturn = funcInterfaceCtx.resolve(funcInterfaceCtx.addSingle(functionalInterfaceType));
// we don't need to bother inferring types
if (!(formalType instanceof ResolvedVoidType)) {
lambdaCtx.addPair(result, functionalTypeWithReturn);
result = lambdaCtx.resolve(lambdaCtx.addSingle(result));
}
}
return result;
}
use of com.github.javaparser.ast.expr.LambdaExpr in project javaparser by javaparser.
the class StatementContext method solveSymbol.
/**
* Used where a symbol is being used (e.g. solving {@code x} when used as an argument {@code doubleThis(x)}, or calculation {@code return x * 2;}).
* @param name the variable / reference / identifier used.
* @param iterateAdjacentStmts flag to iterate adjacent statements, should be set to {@code true} except when calling itself in order to prevent revisiting already visited symbols.
* @return // FIXME: Better documentation on how this is different to solveSymbolAsValue()
*/
private SymbolReference<? extends ResolvedValueDeclaration> solveSymbol(String name, boolean iterateAdjacentStmts) {
/*
* If we're in a variable declaration line.
* Example: {@code double a=0, b=a;}
* Example: {@code a instanceof String s;}
*/
SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(wrappedNode, typeSolver);
SymbolReference<? extends ResolvedValueDeclaration> symbolReference = solveWith(symbolDeclarator, name);
if (symbolReference.isSolved()) {
return symbolReference;
}
/*
* If we're in a statement that contains a pattern expression.
* Example: {@code double x = a instanceof String s;}
*/
List<PatternExpr> patternExprs = patternExprsExposedFromChildren();
for (int i = 0; i < patternExprs.size(); i++) {
PatternExpr patternExpr = patternExprs.get(i);
if (patternExpr.getNameAsString().equals(name)) {
return SymbolReference.solved(JavaParserSymbolDeclaration.patternVar(patternExpr, typeSolver));
}
}
Optional<Node> optionalParentNode = wrappedNode.getParentNode();
if (!optionalParentNode.isPresent()) {
return SymbolReference.unsolved(ResolvedValueDeclaration.class);
}
Node parentOfWrappedNode = optionalParentNode.get();
// we should look in all the statements preceding, treating them as SymbolDeclarators
if (parentOfWrappedNode instanceof MethodDeclaration) {
return solveSymbolInParentContext(name);
} else if (parentOfWrappedNode instanceof ConstructorDeclaration) {
return solveSymbolInParentContext(name);
} else if (parentOfWrappedNode instanceof LambdaExpr) {
return solveSymbolInParentContext(name);
} else if (parentOfWrappedNode instanceof NodeWithStatements) {
// to prevent revisiting the same contexts over and over again.
if (!iterateAdjacentStmts) {
return SymbolReference.unsolved(ResolvedValueDeclaration.class);
}
NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) parentOfWrappedNode;
// Assuming the wrapped node exists within the parent's collection of statements...
int position = nodeWithStmt.getStatements().indexOf(wrappedNode);
if (position == -1) {
throw new IllegalStateException("This node is not a statement within the current NodeWithStatements");
}
// Start at the current node and work backwards...
ListIterator<Statement> statementListIterator = nodeWithStmt.getStatements().listIterator(position);
while (statementListIterator.hasPrevious()) {
Context prevContext = JavaParserFactory.getContext(statementListIterator.previous(), typeSolver);
if (prevContext instanceof StatementContext) {
// We have an explicit check for "StatementContext" to prevent a factorial increase of visited statements.
//
// For example consider the following:
// String a = "a";
// String b = "b";
// String c = get();
//
// If we simply call "prevContext.solveSymbol(name)" we will call the current method with the adjacent statement "prevContext".
// Then "prevContext" will look at its previous adjacent statement. And so on and so forth.
// When there are no more previous statements in this chain of method calls, we come back to here...
// Then we look at the next "prevContext" which causes the entire process to start again.
// This is how we get a factorial increase in calls to "solveSymbol".
//
// So what we do instead with this check is we pass in a flag to say "Do not look at previous adjacent statements".
// Since each visited "prevContext" does not look at its adjacent statements we only visit each statement once in this while loop.
symbolReference = ((StatementContext<?>) prevContext).solveSymbol(name, false);
} else {
symbolReference = prevContext.solveSymbol(name);
}
if (symbolReference.isSolved()) {
return symbolReference;
}
}
}
// If nothing is found, attempt to solve within the parent context
return solveSymbolInParentContext(name);
}
use of com.github.javaparser.ast.expr.LambdaExpr in project javaparser by javaparser.
the class StatementContext method solveSymbolAsValue.
@Override
public Optional<Value> solveSymbolAsValue(String name) {
// if we're in a multiple Variable declaration line (for ex: double a=0, b=a;)
SymbolDeclarator symbolDeclarator = JavaParserFactory.getSymbolDeclarator(wrappedNode, typeSolver);
Optional<Value> symbolReference = solveWithAsValue(symbolDeclarator, name);
if (symbolReference.isPresent()) {
return symbolReference;
}
// If there is no parent
if (!getParent().isPresent()) {
return Optional.empty();
}
Context parentContext = getParent().get();
Optional<Node> optionalParentNode = wrappedNode.getParentNode();
if (!optionalParentNode.isPresent()) {
return Optional.empty();
}
Node parentOfWrappedNode = optionalParentNode.get();
// we should look in all the statements preceding, treating them as SymbolDeclarators
if (parentOfWrappedNode instanceof MethodDeclaration) {
return parentContext.solveSymbolAsValue(name);
} else if (parentOfWrappedNode instanceof LambdaExpr) {
return parentContext.solveSymbolAsValue(name);
} else if (!(parentOfWrappedNode instanceof NodeWithStatements)) {
return parentContext.solveSymbolAsValue(name);
}
NodeWithStatements<?> nodeWithStmt = (NodeWithStatements<?>) parentOfWrappedNode;
int position = -1;
// Get the position of the wrapped node.
for (int i = 0; i < nodeWithStmt.getStatements().size(); i++) {
if (nodeWithStmt.getStatements().get(i).equals(wrappedNode)) {
position = i;
}
}
if (position == -1) {
throw new RuntimeException();
}
// Working backwards from the node, try to solve the symbol. This limits the scope to declarations that appear prior to usage.
for (int statementIndex = position - 1; statementIndex >= 0; statementIndex--) {
Statement statement = nodeWithStmt.getStatements().get(statementIndex);
symbolDeclarator = JavaParserFactory.getSymbolDeclarator(statement, typeSolver);
symbolReference = solveWithAsValue(symbolDeclarator, name);
if (symbolReference.isPresent()) {
return symbolReference;
}
}
// If nothing is found we should ask the parent context.
return solveSymbolAsValueInParentContext(name);
}
use of com.github.javaparser.ast.expr.LambdaExpr in project javaparser by javaparser.
the class Issue186Test method lambdaPrimitivesIssue.
@Test
void lambdaPrimitivesIssue() {
CompilationUnit cu = parseSample("Issue186");
ClassOrInterfaceDeclaration clazz = Navigator.demandClass(cu, "JavaTest");
MethodDeclaration methodDeclaration = Navigator.demandMethod(clazz, "bar");
List<LambdaExpr> lambdas = methodDeclaration.findAll(LambdaExpr.class);
TypeSolver typeSolver = new ReflectionTypeSolver();
JavaParserFacade javaParserFacade = JavaParserFacade.get(typeSolver);
assertEquals("java.util.function.Predicate<? super java.lang.String>", javaParserFacade.getType(lambdas.get(0)).describe());
assertEquals("java.util.function.Function<? super java.lang.String, ? extends java.lang.Integer>", javaParserFacade.getType(lambdas.get(1)).describe());
assertEquals("java.util.function.Predicate<? super java.lang.Integer>", javaParserFacade.getType(lambdas.get(2)).describe());
}
use of com.github.javaparser.ast.expr.LambdaExpr in project javaparser by javaparser.
the class LambdaResolutionTest method typeOfVoidLambda.
@Test
void typeOfVoidLambda() {
CompilationUnit cu = parseSample("LambdaVoid");
com.github.javaparser.ast.body.ClassOrInterfaceDeclaration clazz = Navigator.demandClass(cu, "Agenda");
MethodDeclaration method = Navigator.demandMethod(clazz, "lambdaEmpty");
ReturnStmt returnStmt = Navigator.demandReturnStmt(method);
Expression expression = returnStmt.getExpression().get();
LambdaExpr lambdaExpr = Navigator.demandNodeOfGivenClass(expression, LambdaExpr.class);
JavaParserFacade javaParserFacade = JavaParserFacade.get(new ReflectionTypeSolver());
ResolvedType type = javaParserFacade.getType(lambdaExpr);
assertEquals("java.util.function.Consumer<? super java.lang.String>", type.describe());
}
Aggregations