/*
* 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.event.api.BuckTracing;
import com.facebook.buck.util.liteinfersupport.Preconditions;
import com.sun.source.tree.ClassTree;
import com.sun.source.tree.CompilationUnitTree;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import java.util.ArrayDeque;
import java.util.Deque;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.ElementScanner8;
/**
* Creates {@link TreeBackedElement}s for each element in the {@link CompilationUnitTree}s known to
* the compiler. This is analogous to the "Enter" phase of javac.
*/
class TreeBackedEnter {
private static final BuckTracing BUCK_TRACING = BuckTracing.getInstance("TreeBackedEnter");
private final TreeBackedElements elements;
private final Trees javacTrees;
private final EnteringTreePathScanner treeScanner = new EnteringTreePathScanner();
private final EnteringElementScanner elementScanner = new EnteringElementScanner();
TreeBackedEnter(TreeBackedElements elements, Trees javacTrees) {
this.elements = elements;
this.javacTrees = javacTrees;
}
public void enter(CompilationUnitTree compilationUnit) {
try (BuckTracing.TraceSection t = BUCK_TRACING.traceSection("buck.enter")) {
treeScanner.scan(compilationUnit, null);
}
}
private class EnteringTreePathScanner extends TreePathScanner<Void, Void> {
@Override
public Void visitClass(ClassTree node, Void v) {
return elementScanner.scan(
Preconditions.checkNotNull(javacTrees.getElement(getCurrentPath())));
}
}
private class EnteringElementScanner extends ElementScanner8<Void, Void> {
private final Deque<TreeBackedElement> contextStack = new ArrayDeque<>();
private TreeBackedElement getCurrentContext() {
return contextStack.peek();
}
@Override
public Void visitType(TypeElement e, Void v) {
TreeBackedTypeElement newClass = (TreeBackedTypeElement) elements.enterElement(e);
try (ElementContext c = new ElementContext(newClass)) {
super.visitType(e, v);
super.scan(e.getTypeParameters(), v);
return null;
}
}
@Override
public Void visitTypeParameter(TypeParameterElement e, Void v) {
TreeBackedTypeParameterElement typeParameter =
(TreeBackedTypeParameterElement) elements.enterElement(e);
TreeBackedParameterizable currentParameterizable =
(TreeBackedParameterizable) getCurrentContext();
currentParameterizable.addTypeParameter(typeParameter);
try (ElementContext c = new ElementContext(typeParameter)) {
return super.visitTypeParameter(e, v);
}
}
@Override
public Void visitExecutable(ExecutableElement e, Void v) {
TreeBackedExecutableElement method = (TreeBackedExecutableElement) elements.enterElement(e);
try (ElementContext c = new ElementContext(method)) {
super.visitExecutable(e, v);
super.scan(e.getTypeParameters(), v);
return null;
}
}
@Override
public Void visitVariable(VariableElement e, Void v) {
elements.enterElement(e);
return super.visitVariable(e, v);
}
private class ElementContext implements AutoCloseable {
public ElementContext(TreeBackedElement newContext) {
contextStack.push(newContext);
}
@Override
public void close() {
contextStack.pop();
}
}
}
}