/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.errorprone.suppliers;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.errorprone.VisitorState;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
/**
* @author alexeagle@google.com (Alex Eagle)
*/
public class Suppliers {
/**
* Supplies the n'th generic type of the given expression. For example, in {@code Map<A,B> c;} for
* the expression c and n=1, the result is the type of {@code B}. If there are an insufficient number of
* type arguments, this method will return the {@code java.lang.Object} type from symbol table.
*
* @param expressionSupplier a supplier of the expression which has a generic type
* @param n the position of the generic argument
*/
public static Supplier<Type> genericTypeOf(final Supplier<ExpressionTree> expressionSupplier, final int n) {
return new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
JCExpression jcExpression = (JCExpression) expressionSupplier.get(state);
if (jcExpression.type.getTypeArguments().size() <= n) {
return state.getSymtab().objectType;
}
return jcExpression.type.getTypeArguments().get(n);
}
};
}
/**
* Supplies the n'th generic type of the given expression. For example, in {@code Map<A,B> c;} for
* the type of c and n=1, the result is the type of {@code B}. If there are an insufficient number of
* type arguments, this method will return the {@code java.lang.Object} type from symbol table.
*
* @param typeSupplier a supplier of the expression which has a generic type
* @param n the position of the generic argument
*/
public static Supplier<Type> genericTypeOfType(final Supplier<Type> typeSupplier, final int n) {
return new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
Type type = typeSupplier.get(state);
if (type.getTypeArguments().size() <= n) {
return state.getSymtab().objectType;
}
return type.getTypeArguments().get(n);
}
};
}
/**
* Supplies the expression which gives the instance of an object that will receive the method call.
* For example, in
* {@code a.getB().getC()}
* if the visitor is currently visiting the {@code getC()} method invocation, then this supplier gives the
* expression {@code a.getB()}.
*/
public static Supplier<Type> receiverType() {
return new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
MethodInvocationTree methodInvocation = (MethodInvocationTree) state.getPath().getLeaf();
return ASTHelpers.getReceiverType(methodInvocation.getMethodSelect());
}
};
}
/**
* Supplies the expression which gives the instance of an object that will receive the method call.
* For example, in
* {@code a.getB().getC()}
* if the visitor is currently visiting the {@code getC()} method invocation, then this supplier gives the
* expression {@code a.getB()}.
*/
public static Supplier<ExpressionTree> receiverInstance() {
return new Supplier<ExpressionTree>() {
@Override
public ExpressionTree get(VisitorState state) {
MethodInvocationTree method = (MethodInvocationTree) state.getPath().getLeaf();
return ((JCFieldAccess) method.getMethodSelect()).getExpression();
}
};
}
/**
* Given the string representation of a type, supplies the corresponding type.
*
* @param typeString a string representation of a type, e.g., "java.util.List"
*/
public static Supplier<Type> typeFromString(final String typeString) {
return new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getTypeFromString(typeString);
}
};
}
/** Given the class representation of a type, supplies the corresponding type. */
public static Supplier<Type> typeFromClass(Class<?> inputClass) {
return typeFromString(inputClass.getName());
}
public static final Supplier<Type> JAVA_LANG_VOID_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getTypeFromString("java.lang.Void");
}
};
public static final Supplier<Type> VOID_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().voidType;
}
};
public static final Supplier<Type> JAVA_LANG_BOOLEAN_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getTypeFromString("java.lang.Boolean");
}
};
public static final Supplier<Type> STRING_TYPE =
new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().stringType;
}
};
public static final Supplier<Type> BOOLEAN_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().booleanType;
}
};
public static final Supplier<Type> BYTE_TYPE =
new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().byteType;
}
};
public static final Supplier<Type> INT_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().intType;
}
};
public static final Supplier<Type> CHAR_TYPE =
new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().charType;
}
};
public static final Supplier<Type> OBJECT_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().objectType;
}
};
public static final Supplier<Type> EXCEPTION_TYPE = new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().exceptionType;
}
};
public static final Supplier<Type> ANNOTATION_TYPE =
new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return state.getSymtab().annotationType;
}
};
/**
* Supplies what was given. Useful for adapting to methods that require a supplier.
*
* @param toSupply the item to supply
*/
public static <T> Supplier<T> identitySupplier(final T toSupply) {
return new Supplier<T>() {
@Override
public T get(VisitorState state) {
return toSupply;
}
};
}
public static final Supplier<Type> ENCLOSING_CLASS =
new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return ((JCTree) state.findEnclosing(ClassTree.class)).type;
}
};
public static Supplier<Type> arrayOf(final Supplier<Type> elementType) {
return new Supplier<Type>() {
@Override
public Type get(VisitorState state) {
return new Type.ArrayType(elementType.get(state), state.getSymtab().arraysType.tsym);
}
};
}
public static ImmutableList<Supplier<Type>> fromStrings(Iterable<String> types) {
return ImmutableList.copyOf(
Iterables.transform(
types,
new Function<String, Supplier<Type>>() {
@Override
public Supplier<Type> apply(String input) {
return Suppliers.typeFromString(input);
}
}));
}
}