/*
* Copyright 2017-present Facebook, Inc.
*
* 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.facebook.buck.jvm.java.abi.source;
import com.facebook.buck.util.liteinfersupport.Nullable;
import com.facebook.buck.util.liteinfersupport.Preconditions;
import com.sun.source.tree.MethodTree;
import com.sun.source.tree.ModifiersTree;
import com.sun.source.util.TreePath;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
/**
* An implementation of {@link ExecutableElement} that uses only the information available from a
* {@link MethodTree}. This results in an incomplete implementation; see documentation for
* individual methods and {@link com.facebook.buck.jvm.java.abi.source} for more information.
*/
class TreeBackedExecutableElement extends TreeBackedParameterizable implements ExecutableElement {
private final ExecutableElement underlyingElement;
private final List<TreeBackedVariableElement> parameters = new ArrayList<>();
@Nullable private final MethodTree tree;
@Nullable private TypeMirror returnType;
@Nullable private TypeMirror receiverType;
@Nullable private List<TypeMirror> thrownTypes;
@Nullable private TreeBackedAnnotationValue defaultValue;
@Nullable private StandaloneExecutableType typeMirror;
TreeBackedExecutableElement(
ExecutableElement underlyingElement,
TreeBackedElement enclosingElement,
@Nullable TreePath path,
TreeBackedElementResolver resolver) {
super(underlyingElement, enclosingElement, path, resolver);
this.underlyingElement = underlyingElement;
tree = path != null ? (MethodTree) path.getLeaf() : null;
enclosingElement.addEnclosedElement(this);
}
@Override
public StandaloneTypeMirror asType() {
if (typeMirror == null) {
typeMirror = getResolver().createType(this);
}
return typeMirror;
}
@Override
@Nullable
protected ModifiersTree getModifiersTree() {
return tree != null ? tree.getModifiers() : null;
}
@Override
public TypeMirror getReturnType() {
if (returnType == null) {
returnType = getResolver().getCanonicalType(underlyingElement.getReturnType());
}
return returnType;
}
@Override
public List<? extends VariableElement> getParameters() {
return Collections.unmodifiableList(parameters);
}
/* package */ void addParameter(TreeBackedVariableElement parameter) {
parameters.add(parameter);
}
@Override
public TypeMirror getReceiverType() {
if (receiverType == null) {
receiverType = getResolver().getCanonicalType(underlyingElement.getReceiverType());
}
return receiverType;
}
@Override
public boolean isVarArgs() {
return underlyingElement.isVarArgs();
}
@Override
public boolean isDefault() {
return underlyingElement.isDefault();
}
@Override
public List<? extends TypeMirror> getThrownTypes() {
if (thrownTypes == null) {
thrownTypes =
Collections.unmodifiableList(
underlyingElement
.getThrownTypes()
.stream()
.map(getResolver()::getCanonicalType)
.collect(Collectors.toList()));
}
return thrownTypes;
}
@Override
@Nullable
public TreeBackedAnnotationValue getDefaultValue() {
if (defaultValue == null) {
AnnotationValue underlyingValue = underlyingElement.getDefaultValue();
if (underlyingValue != null) {
defaultValue =
new TreeBackedAnnotationValue(
underlyingValue,
new TreePath(getTreePath(), Preconditions.checkNotNull(tree).getDefaultValue()),
getResolver());
}
}
return defaultValue;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitExecutable(this, p);
}
}