Skip to content

Commit

Permalink
Merge pull request #2994 from jlerbsc/polyexpression
Browse files Browse the repository at this point in the history
Adding management of the poly and standalone expression
  • Loading branch information
jlerbsc committed Dec 27, 2020
2 parents 1f193dd + e3b2a2d commit 54496f6
Show file tree
Hide file tree
Showing 15 changed files with 448 additions and 245 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.Utils.assertNotNull;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.observer.ObservableProperty;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.VoidVisitor;
import static com.github.javaparser.utils.Utils.assertNotNull;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.metamodel.AssignExprMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.printer.Stringable;
import com.github.javaparser.TokenRange;
import java.util.function.Consumer;
import java.util.Optional;
import com.github.javaparser.ast.Generated;

/**
* An assignment expression. It supports the operators that are found the the AssignExpr.Operator enum.
Expand Down Expand Up @@ -253,4 +255,14 @@ public void ifAssignExpr(Consumer<AssignExpr> action) {
public Optional<AssignExpr> toAssignExpr() {
return Optional.of(this);
}

/*
* Returns true if the expression is an assignment context
* https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.2
* 5.2. Assignment Contexts: Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable;...
*/
@Override
protected boolean isAssignmentContext() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.Utils.assertNotNull;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.nodeTypes.NodeWithCondition;
import com.github.javaparser.ast.observer.ObservableProperty;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.VoidVisitor;
import static com.github.javaparser.utils.Utils.assertNotNull;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.metamodel.ConditionalExprMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.TokenRange;
import java.util.function.Consumer;
import java.util.Optional;
import com.github.javaparser.ast.Generated;

/**
* The ternary conditional expression.
Expand Down Expand Up @@ -201,4 +203,13 @@ public void ifConditionalExpr(Consumer<ConditionalExpr> action) {
public Optional<ConditionalExpr> toConditionalExpr() {
return Optional.of(this);
}

/*
* A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (§5.2. §5.3).
* Otherwise, it is a standalone expression.
*/
@Override
public boolean isPolyExpression() {
return appearsInAssignmentContext() || appearsInInvocationContext();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,21 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.Utils.assertNotNull;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.observer.ObservableProperty;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.VoidVisitor;
import java.util.Optional;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.metamodel.EnclosedExprMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.TokenRange;
import static com.github.javaparser.utils.Utils.assertNotNull;
import java.util.function.Consumer;
import com.github.javaparser.ast.Generated;

/**
* An expression between ( ).
Expand Down Expand Up @@ -154,4 +156,13 @@ public void ifEnclosedExpr(Consumer<EnclosedExpr> action) {
public Optional<EnclosedExpr> toEnclosedExpr() {
return Optional.of(this);
}

/*
* On Parenthesized Expressions, if the contained expression is a poly expression (§15.2), the parenthesized expression is also a poly expression. Otherwise, it is a standalone expression.
* (https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.8.5)
*/
@Override
public boolean isPolyExpression() {
return getInner().isPolyExpression();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,21 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.CodeGenerationUtils.f;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.nodeTypes.NodeWithOptionalScope;
import com.github.javaparser.ast.nodeTypes.NodeWithTypeArguments;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.metamodel.ExpressionMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.TokenRange;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.ast.Generated;
import java.util.function.Consumer;
import static com.github.javaparser.utils.CodeGenerationUtils.f;
import java.util.Optional;

/**
* A base class for all expressions.
Expand Down Expand Up @@ -790,4 +794,87 @@ public Optional<PatternExpr> toPatternExpr() {
@Generated("com.github.javaparser.generator.core.node.TypeCastingGenerator")
public void ifPatternExpr(Consumer<PatternExpr> action) {
}

/**
* See https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.2
* @return true if the expression is a standalone expression
*/
public boolean isStandaloneExpression() {
return !isPolyExpression();
}

/**
* See https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.2
* @return true if the expression is a poly expression
*/
public boolean isPolyExpression() {
return false;
}

/*
* 6.5.6.2. Qualified Expression Names
* https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.5.6.2
*/
public boolean isQualified() {
return this instanceof NodeWithOptionalScope && ((NodeWithOptionalScope)this).getScope().isPresent();
}

/*
* Verify if the parent node is an assignment context.
*/
public final boolean appearsInAssignmentContext() {
if (getParentNode().isPresent() && getParentNode().get() instanceof Expression) {
return ((Expression)getParentNode().get()).isAssignmentContext();
}
return false;
}

/*
* Returns true if the expression is an assignment context. Default is false.
* https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.2
* 5.2. Assignment Contexts: Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable;...
*/
protected boolean isAssignmentContext() {
return false;
}

/*
* Verify if the parent node is an invocation context.
*/
public final boolean appearsInInvocationContext() {
if (getParentNode().isPresent() && getParentNode().get() instanceof Expression) {
return ((Expression)getParentNode().get()).isInvocationContext();
}
return false;
}

/*
* Returns true if the expression is an invocation context. Default is false.
* https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.3
* 5.3. Invocation Contexts
*/
protected boolean isInvocationContext() {
return false;
}

/*
* returns true if the scope of this expression does not define an type argument or if the expression has not a scope (the expression is not qualified)
* or if there is a scope it uses <> to elide class type arguments
* For exemple :
* m() ==> true because there is no scope
* a.m() ==> true because the scope has no type arguments
* a<>.m() ==> true because the type argument is elided
* a<T>.m() ==> false because the type argument is not elided
*/
public final boolean elidesTypeArguments() {
if (!(this instanceof NodeWithOptionalScope
&& ((NodeWithOptionalScope) this).getScope().isPresent()
&& this instanceof NodeWithTypeArguments)) {
return true;
}
Expression scope = (Expression) ((NodeWithOptionalScope) this).getScope().get();
NodeWithTypeArguments nwta = (NodeWithTypeArguments)this;
return scope.elidesTypeArguments()
&& (!nwta.getTypeArguments().isPresent() || nwta.isUsingDiamondOperator());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.Utils.assertNotNull;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
Expand All @@ -38,9 +43,6 @@
import com.github.javaparser.metamodel.DerivedProperty;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.metamodel.LambdaExprMetaModel;
import java.util.Optional;
import java.util.function.Consumer;
import static com.github.javaparser.utils.Utils.assertNotNull;

/**
* <h1>A lambda expression</h1>
Expand Down Expand Up @@ -262,4 +264,12 @@ public void ifLambdaExpr(Consumer<LambdaExpr> action) {
public Optional<LambdaExpr> toLambdaExpr() {
return Optional.of(this);
}

/*
* Lambda expressions are always poly expressions
*/
@Override
public boolean isPolyExpression() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@
*/
package com.github.javaparser.ast.expr;

import static com.github.javaparser.utils.Utils.assertNotNull;

import java.util.Optional;
import java.util.function.Consumer;

import com.github.javaparser.TokenRange;
import com.github.javaparser.ast.AllFieldsConstructor;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.nodeTypes.NodeWithArguments;
import com.github.javaparser.ast.nodeTypes.NodeWithOptionalScope;
Expand All @@ -29,21 +37,16 @@
import com.github.javaparser.ast.observer.ObservableProperty;
import com.github.javaparser.ast.stmt.ExplicitConstructorInvocationStmt;
import com.github.javaparser.ast.type.Type;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.ast.visitor.GenericVisitor;
import com.github.javaparser.ast.visitor.VoidVisitor;
import java.util.Optional;
import static com.github.javaparser.utils.Utils.assertNotNull;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.visitor.CloneVisitor;
import com.github.javaparser.metamodel.MethodCallExprMetaModel;
import com.github.javaparser.metamodel.JavaParserMetaModel;
import com.github.javaparser.TokenRange;
import com.github.javaparser.metamodel.MethodCallExprMetaModel;
import com.github.javaparser.metamodel.OptionalProperty;
import com.github.javaparser.resolution.Resolvable;
import com.github.javaparser.resolution.UnsolvedSymbolException;
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
import java.util.function.Consumer;
import com.github.javaparser.ast.Generated;
import com.github.javaparser.resolution.types.ResolvedType;

/**
* A method call on an object or a class. <br>{@code circle.circumference()} <br>In <code>a.&lt;String&gt;bb(15);</code> a
Expand Down Expand Up @@ -318,4 +321,68 @@ public ResolvedMethodDeclaration resolve() {
public Optional<MethodCallExpr> toMethodCallExpr() {
return Optional.of(this);
}

/*
* A method invocation expression is a poly expression if all of the following are true:
* 1. The invocation appears in an assignment context or an invocation context (§5.2, §5.3).
* 2. If the invocation is qualified (that is, any form of MethodInvocation except for the first), then
* the invocation elides TypeArguments to the left of the Identifier.
* 3. The method to be invoked, as determined by the following subsections, is generic (§8.4.4) and has a
* return type that mentions at least one of the method's type parameters.
* Otherwise, the method invocation expression is a standalone expression.
*/
@Override
public boolean isPolyExpression() {
// A method invocation expression is a poly expression if all of the following are true:
//
// 1. The invocation appears in an assignment context or an invocation context (§5.2, §5.3).

if (!(appearsInAssignmentContext() || appearsInInvocationContext())) {
return false;
}

// 2. If the invocation is qualified (that is, any form of MethodInvocation except for the form [MethodName (
// [ArgumentList] )]), then the invocation elides TypeArguments to the left of the Identifier.

if (isQualified() && !elidesTypeArguments()) {
return false;
}

// 3. The method to be invoked, as determined by the following subsections, is generic (§8.4.4) and has a
// return type that mentions at least one of the method's type parameters.
// A method is generic if it declares one or more type variables (§4.4).
if (isGenericMethod() && hasParameterwithSameTypeThanResultType(resolve().getReturnType())) {
return true; // it's a poly expression
}

// Otherwise, the method invocation expression is a standalone expression.
return false;
}

/*
* A method is generic if it declares one or more type variables (§4.4).
* Not sure it's enough to verify that the type arguments list is empty or not.
*/
private boolean isGenericMethod() {
return getTypeArguments().isPresent() && !getTypeArguments().get().isEmpty();
}

/*
* return true if at least one of the method's type parameters has the same type as the specified type .
*/
private boolean hasParameterwithSameTypeThanResultType(ResolvedType resolvedReturnType) {
return getTypeArguments().isPresent() && getTypeArguments().get().stream().anyMatch(argType -> argType.resolve().isAssignableBy(resolvedReturnType));
}



/*
* Returns true if the expression is an invocation context.
* https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.3
* 5.3. Invocation Contexts
*/
@Override
protected boolean isInvocationContext() {
return true;
}
}

0 comments on commit 54496f6

Please sign in to comment.