All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.checkerframework.framework.util.StringToJavaExpression Maven / Gradle / Ivy

Go to download

The Checker Framework enhances Java's type system to make it more powerful and useful. This lets software developers detect and prevent errors in their Java programs. The Checker Framework includes compiler plug-ins ("checkers") that find bugs or verify their absence. It also permits you to write your own compiler plug-ins.

There is a newer version: 3.44.0
Show newest version
package org.checkerframework.framework.util;

import com.sun.source.tree.LambdaExpressionTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.NewClassTree;
import com.sun.source.tree.VariableTree;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.dataflow.cfg.node.MethodInvocationNode;
import org.checkerframework.dataflow.expression.FormalParameter;
import org.checkerframework.dataflow.expression.JavaExpression;
import org.checkerframework.dataflow.expression.LocalVariable;
import org.checkerframework.dataflow.expression.ThisReference;
import org.checkerframework.dataflow.expression.ViewpointAdaptJavaExpression;
import org.checkerframework.framework.source.SourceChecker;
import org.checkerframework.framework.util.JavaExpressionParseUtil.JavaExpressionParseException;
import org.checkerframework.javacutil.BugInCF;
import org.checkerframework.javacutil.ElementUtils;
import org.checkerframework.javacutil.TreePathUtil;
import org.checkerframework.javacutil.TreeUtils;

/**
 * This interface is both a functional interface, see {@link #toJavaExpression(String)}, and also a
 * collection of static methods that convert a string to a JavaExpression at common locations.
 *
 * 

Some conversion routines merely do parsing. Other conversion routines parse and then transform * the result of parsing into another {@code JavaExpression}; for all the static methods, this * transformation is viewpoint-adaptation. * *

To parse a string "at a location" means to parse it as if it were written in an annotation * that is written on that location. */ @FunctionalInterface public interface StringToJavaExpression { /** * Convert a string to a {@link JavaExpression}. Returns {@code null} if no conversion exists. * *

Conversion includes parsing {@code stringExpr} to a {@code JavaExpression} and optionally * transforming the result of parsing into another {@code JavaExpression}. An example of * transformation is viewpoint adaptation. * * @param stringExpr a Java expression * @return a {@code JavaExpression} or {@code null} if no conversion from {@code stringExpr} * exists * @throws JavaExpressionParseException if {@code stringExpr} cannot be parsed to a {@code * JavaExpression} */ @Nullable JavaExpression toJavaExpression(String stringExpr) throws JavaExpressionParseException; /** * Parses a string to a {@link JavaExpression} as if it were written at {@code typeElement}. * * @param expression a Java expression to parse * @param typeElement type element at which {@code expression} is parsed * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atTypeDecl( String expression, TypeElement typeElement, SourceChecker checker) throws JavaExpressionParseException { ThisReference thisReference = new ThisReference(typeElement.asType()); List parameters = null; return JavaExpressionParseUtil.parse( expression, typeElement.asType(), thisReference, parameters, null, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); } /** * Parses a string to a {@link JavaExpression} as if it were written at {@code fieldElement}. * * @param expression a Java expression to parse * @param fieldElement variable element at which {@code expression} is parsed * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atFieldDecl( String expression, VariableElement fieldElement, SourceChecker checker) throws JavaExpressionParseException { TypeMirror enclosingType = ElementUtils.enclosingTypeElement(fieldElement).asType(); ThisReference thisReference; if (ElementUtils.isStatic(fieldElement)) { // Can't use "this" on a static fieldElement thisReference = null; } else { thisReference = new ThisReference(enclosingType); } List parameters = null; return JavaExpressionParseUtil.parse( expression, enclosingType, thisReference, parameters, null, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); } /** * Parses a string to a {@link JavaExpression} as if it were written at {@code method}. The * returned {@code JavaExpression} uses {@link FormalParameter}s to represent parameters. Use * {@link #atMethodBody(String, MethodTree, SourceChecker)} if parameters should be {@link * LocalVariable}s instead. * * @param expression a Java expression to parse * @param method method element at which {@code expression} is parsed * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atMethodDecl( String expression, ExecutableElement method, SourceChecker checker) throws JavaExpressionParseException { TypeMirror enclosingType = ElementUtils.enclosingTypeElement(method).asType(); ThisReference thisReference; if (ElementUtils.isStatic(method)) { // Can't use "this" on a static method thisReference = null; } else { thisReference = new ThisReference(enclosingType); } List parameters = JavaExpression.getFormalParameters(method); return JavaExpressionParseUtil.parse( expression, enclosingType, thisReference, parameters, null, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); } /** * Parses a string to a {@link JavaExpression} as if it were written at {@code methodTree}. The * returned {@code JavaExpression} uses {@link LocalVariable}s to represent parameters. Use {@link * #atMethodDecl(String, ExecutableElement, SourceChecker)} if parameters should be {@link * FormalParameter}s instead. * * @param expression a Java expression to parse * @param methodTree method declaration tree at which {@code expression} is parsed * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atMethodBody( String expression, MethodTree methodTree, SourceChecker checker) throws JavaExpressionParseException { ExecutableElement ee = TreeUtils.elementFromDeclaration(methodTree); JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, ee, checker); return javaExpr.atMethodBody(methodTree); } /** * Parses a string as if it were written at the declaration of the invoked method and then * viewpoint-adapts the result to the call site. * * @param expression a Java expression to parse * @param methodInvocationTree method invocation tree * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atMethodInvocation( String expression, MethodInvocationTree methodInvocationTree, SourceChecker checker) throws JavaExpressionParseException { ExecutableElement ee = TreeUtils.elementFromUse(methodInvocationTree); JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, ee, checker); return javaExpr.atMethodInvocation(methodInvocationTree); } /** * Parses a string as if it were written at the declaration of the invoked method and then * viewpoint-adapts the result to the call site. * * @param expression a Java expression to parse * @param methodInvocationNode method invocation node * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atMethodInvocation( String expression, MethodInvocationNode methodInvocationNode, SourceChecker checker) throws JavaExpressionParseException { ExecutableElement ee = TreeUtils.elementFromUse(methodInvocationNode.getTree()); JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, ee, checker); return javaExpr.atMethodInvocation(methodInvocationNode); } /** * Parses a string as if it were written at the declaration of the invoked constructor and then * viewpoint-adapts the result to the call site. * * @param expression a Java expression to parse * @param newClassTree constructor invocation * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atConstructorInvocation( String expression, NewClassTree newClassTree, SourceChecker checker) throws JavaExpressionParseException { ExecutableElement ee = TreeUtils.elementFromUse(newClassTree); JavaExpression javaExpr = StringToJavaExpression.atMethodDecl(expression, ee, checker); return javaExpr.atConstructorInvocation(newClassTree); } /** * uf found Parses a string as if it were written at the declaration of the field and then * viewpoint-adapts the result to the use. * * @param expression a Java expression to parse * @param fieldAccess the field access tree * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atFieldAccess( String expression, MemberSelectTree fieldAccess, SourceChecker checker) throws JavaExpressionParseException { Element ele = TreeUtils.elementFromUse(fieldAccess); if (ele.getKind() != ElementKind.FIELD && ele.getKind() != ElementKind.ENUM_CONSTANT) { throw new BugInCF("Expected a field, but found %s for %s", ele.getKind(), fieldAccess); } VariableElement fieldEle = (VariableElement) ele; JavaExpression receiver = JavaExpression.fromTree(fieldAccess.getExpression()); JavaExpression javaExpr = StringToJavaExpression.atFieldDecl(expression, fieldEle, checker); return javaExpr.atFieldAccess(receiver); } /** * Parses a string as if it were written at one of the parameters of {@code lambdaTree}. * Parameters of the lambda are expressed as {@link LocalVariable}s. * * @param expression a Java expression to parse * @param lambdaTree the lambda tree * @param parentPath path to the parent of {@code lambdaTree}; required because the expression can * reference final local variables of the enclosing method * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atLambdaParameter( String expression, LambdaExpressionTree lambdaTree, TreePath parentPath, SourceChecker checker) throws JavaExpressionParseException { TypeMirror enclosingType = TreeUtils.typeOf(TreePathUtil.enclosingClass(parentPath)); JavaExpression receiver = JavaExpression.getPseudoReceiver(parentPath, enclosingType); // If receiver isn't a ThisReference, then the lambda is in a static context and "this" // cannot be referenced in the expression. ThisReference thisReference = receiver instanceof ThisReference ? (ThisReference) receiver : null; List paramsAsLocals = new ArrayList<>(lambdaTree.getParameters().size()); List parameters = new ArrayList<>(lambdaTree.getParameters().size()); int oneBasedIndex = 1; for (VariableTree arg : lambdaTree.getParameters()) { LocalVariable param = (LocalVariable) JavaExpression.fromVariableTree(arg); paramsAsLocals.add(param); parameters.add(new FormalParameter(oneBasedIndex, (VariableElement) param.getElement())); oneBasedIndex++; } JavaExpression javaExpr = JavaExpressionParseUtil.parse( expression, enclosingType, thisReference, parameters, parentPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); return ViewpointAdaptJavaExpression.viewpointAdapt(javaExpr, paramsAsLocals); } /** * Parses a string as if it were written at {@code localVarPath}. * * @param expression a Java expression to parse * @param localVarPath location at which {@code expression} is parsed * @param checker checker used to get the {@link * javax.annotation.processing.ProcessingEnvironment} and current {@link * com.sun.source.tree.CompilationUnitTree} * @return a {@code JavaExpression} for {@code expression} * @throws JavaExpressionParseException if {@code expression} cannot be parsed */ static JavaExpression atPath(String expression, TreePath localVarPath, SourceChecker checker) throws JavaExpressionParseException { TypeMirror enclosingType = TreeUtils.typeOf(TreePathUtil.enclosingClass(localVarPath)); ThisReference thisReference = TreePathUtil.isTreeInStaticScope(localVarPath) ? null : new ThisReference(enclosingType); MethodTree methodTree = TreePathUtil.enclosingMethod(localVarPath); if (methodTree == null) { return JavaExpressionParseUtil.parse( expression, enclosingType, thisReference, null, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); } ExecutableElement methodEle = TreeUtils.elementFromDeclaration(methodTree); List parameters = JavaExpression.getFormalParameters(methodEle); JavaExpression javaExpr = JavaExpressionParseUtil.parse( expression, enclosingType, thisReference, parameters, localVarPath, checker.getPathToCompilationUnit(), checker.getProcessingEnvironment()); List paramsAsLocals = JavaExpression.getParametersAsLocalVariables(methodEle); return ViewpointAdaptJavaExpression.viewpointAdapt(javaExpr, paramsAsLocals); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy