javac ast indices: store actual qualifier type for method call

This commit is contained in:
Dmitry Batkovich
2017-04-11 17:24:49 +03:00
parent 80548595d3
commit 1b66fe8e6c
3 changed files with 100 additions and 26 deletions
@@ -196,7 +196,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
// member import
for (Element memberElement : myElementUtility.getAllMembers((TypeElement)ownerElement)) {
if (memberElement.getSimpleName() == name) {
incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(memberElement, myNameTableCache));
incrementOrAdd(elements, JavacRef.JavacElementRefBase.fromElement(memberElement, null, myNameTableCache));
}
}
}
@@ -213,7 +213,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
for (Element element = baseImport;
element != null && element.getKind() != ElementKind.PACKAGE;
element = element.getEnclosingElement()) {
incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache));
incrementOrAdd(collector, JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache));
}
}
@@ -221,6 +221,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
private final JavacFileData myFileData;
private final JavacTreeHelper myTreeHelper;
private int myRemainDeclarations;
public CompilationUnitTree myUnitTree;
private ReferenceCollector(int remainDeclarations,
String filePath,
@@ -231,6 +232,7 @@ final class JavacReferenceCollectorListener implements TaskListener {
myDivideImportRefs ? createReferenceHolder() : EMPTY_T_OBJ_INT_MAP,
createDefinitionHolder());
myTreeHelper = new JavacTreeHelper(unitTree, myTreeUtility);
myUnitTree = unitTree;
}
void sinkReference(@Nullable JavacRef.JavacElementRefBase ref) {
@@ -243,13 +245,18 @@ final class JavacReferenceCollectorListener implements TaskListener {
@Nullable
JavacRef.JavacElementRefBase asJavacRef(Element element) {
return JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache);
return asJavacRef(element, null);
}
@Nullable
JavacRef.JavacElementRefBase asJavacRef(Element element, Element qualifier) {
return JavacRef.JavacElementRefBase.fromElement(element, qualifier, myNameTableCache);
}
@Nullable
JavacRef.JavacElementRefBase asJavacRef(TypeMirror typeMirror) {
final Element element = getTypeUtility().asElement(typeMirror);
return element == null ? null : JavacRef.JavacElementRefBase.fromElement(element, myNameTableCache);
return element == null ? null : JavacRef.JavacElementRefBase.fromElement(element, null, myNameTableCache);
}
Element getReferencedElement(Tree tree) {
@@ -267,6 +274,14 @@ final class JavacReferenceCollectorListener implements TaskListener {
private int decrementRemainDeclarationsAndGet(Tree declarationToProcess) {
return declarationToProcess == null ? myRemainDeclarations : --myRemainDeclarations;
}
public Elements getElementUtility() {
return myElementUtility;
}
public Trees getTrees() {
return myTreeUtility;
}
}
private static TObjectIntHashMap<JavacRef> createReferenceHolder() {
@@ -15,14 +15,18 @@
*/
package org.jetbrains.jps.javac.ast;
import com.intellij.util.containers.Stack;
import com.sun.source.tree.*;
import com.sun.source.util.TreeScanner;
import org.jetbrains.jps.javac.ast.api.JavacDef;
import org.jetbrains.jps.javac.ast.api.JavacRef;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
@@ -87,7 +91,13 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
public Tree visitMemberSelect(MemberSelectTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
final Element element = refCollector.getReferencedElement(node);
if (element != null && element.getKind() != ElementKind.PACKAGE) {
refCollector.sinkReference(refCollector.asJavacRef(element));
ExpressionTree qualifierExpression = node.getExpression();
Element qualifierType = null;
TypeMirror type = refCollector.getType(qualifierExpression);
if (type instanceof DeclaredType) {
qualifierType = ((DeclaredType)type).asElement();
}
refCollector.sinkReference(refCollector.asJavacRef(element, qualifierType));
}
return super.visitMemberSelect(node, refCollector);
}
@@ -107,11 +117,48 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
}
return super.visitMethod(node, refCollector);
}
@Override
public Tree visitMethodInvocation(MethodInvocationTree node, JavacReferenceCollectorListener.ReferenceCollector collector) {
if (node.getMethodSelect() instanceof IdentifierTree) {
Element element = collector.getReferencedElement(node.getMethodSelect());
if (element.getKind() != ElementKind.CONSTRUCTOR && !element.getModifiers().contains(Modifier.STATIC)) {
TypeElement currentClass = myCurrentEnclosingElement.peek();
Elements elements = collector.getElementUtility();
Types types = collector.getTypeUtility();
TypeElement actualQualifier = null;
while (currentClass != null) {
List<? extends Element> members = elements.getAllMembers(currentClass);
for (Element member : members) {
if (member == element /*cheaper then the next condition*/ || types.isSameType(member.asType(), element.asType())) {
actualQualifier = currentClass;
break;
}
}
if (actualQualifier != null) {
break;
}
currentClass = getEnclosingClass(currentClass);
}
if (actualQualifier == null) {
throw new NullPointerException();
}
collector.sinkReference(collector.asJavacRef(element, actualQualifier));
scan(node.getTypeArguments(), collector);
scan(node.getArguments(), collector);
return null;
}
}
return super.visitMethodInvocation(node, collector);
}
final Stack<TypeElement> myCurrentEnclosingElement = new Stack<TypeElement>();
@Override
public Tree visitClass(ClassTree node, JavacReferenceCollectorListener.ReferenceCollector refCollector) {
TypeElement element = (TypeElement)refCollector.getReferencedElement(node);
if (element == null) return null;
myCurrentEnclosingElement.add(element);
final TypeMirror superclass = element.getSuperclass();
final List<? extends TypeMirror> interfaces = element.getInterfaces();
@@ -136,7 +183,9 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
if (aClass == null) return null;
refCollector.sinkReference(aClass);
refCollector.sinkDeclaration(new JavacDef.JavacClassDef(aClass, supers));
return super.visitClass(node, refCollector);
super.visitClass(node, refCollector);
myCurrentEnclosingElement.pop();
return null;
}
static JavacTreeRefScanner createASTScanner() {
@@ -152,4 +201,13 @@ class JavacTreeRefScanner extends TreeScanner<Tree, JavacReferenceCollectorListe
private static boolean isStatic(Element element) {
return element.getModifiers().contains(Modifier.STATIC);
}
private static TypeElement getEnclosingClass(TypeElement element) {
Element current = element;
while (true) {
current = current.getEnclosingElement();
if (current == null) return null;
if (current instanceof TypeElement) return (TypeElement)current;
}
}
}
@@ -121,18 +121,15 @@ public interface JavacRef {
abstract class JavacElementRefBase implements JavacRef {
protected final @NotNull Element myOriginalElement;
@Nullable private final Element myQualifier;
protected final JavacNameTable myNameTableCache;
protected JavacElementRefBase(@NotNull Element element, JavacNameTable nameTableCache) {
protected JavacElementRefBase(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) {
myOriginalElement = element;
myQualifier = qualifier;
myNameTableCache = nameTableCache;
}
@NotNull
public Element getOriginalElement() {
return myOriginalElement;
}
@NotNull
@Override
public String getName() {
@@ -147,19 +144,19 @@ public interface JavacRef {
@NotNull
@Override
public String getOwnerName() {
return myNameTableCache.parseBinaryName(myOriginalElement.getEnclosingElement());
return myNameTableCache.parseBinaryName(myQualifier != null ? myQualifier : myOriginalElement.getEnclosingElement());
}
@Nullable
public static JavacElementRefBase fromElement(Element element, JavacNameTable nameTableCache) {
public static JavacElementRefBase fromElement(Element element, Element qualifier, JavacNameTable nameTableCache) {
if (element instanceof TypeElement) {
return new JavacElementClassImpl(element, nameTableCache);
return new JavacElementClassImpl(element, qualifier, nameTableCache);
}
else if (element instanceof VariableElement) {
return new JavacElementFieldImpl(element, nameTableCache);
return new JavacElementFieldImpl(element, qualifier, nameTableCache);
}
else if (element instanceof ExecutableElement) {
return new JavacElementMethodImpl(element, nameTableCache);
return new JavacElementMethodImpl(element, qualifier, nameTableCache);
}
else if (element == null || element.getKind() == ElementKind.OTHER || element.getKind() == ElementKind.TYPE_PARAMETER) {
// javac reserved symbol kind (e.g: com.sun.tools.javac.comp.Resolve.ResolveError)
@@ -175,18 +172,22 @@ public interface JavacRef {
JavacElementRefBase base = (JavacElementRefBase)o;
return myOriginalElement == base.myOriginalElement;
return myOriginalElement == base.myOriginalElement && myQualifier == base.myQualifier;
}
@Override
public int hashCode() {
return myOriginalElement.hashCode();
int hashCode = myOriginalElement.hashCode();
if (myQualifier != null) {
hashCode += myQualifier.hashCode();
}
return hashCode;
}
}
class JavacElementClassImpl extends JavacElementRefBase implements JavacClass {
public JavacElementClassImpl(@NotNull Element element, JavacNameTable nameTableCache) {
super(element, nameTableCache);
public JavacElementClassImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) {
super(element, qualifier, nameTableCache);
}
@NotNull
@@ -202,8 +203,8 @@ public interface JavacRef {
}
class JavacElementMethodImpl extends JavacElementRefBase implements JavacMethod {
public JavacElementMethodImpl(@NotNull Element element, JavacNameTable nameTableCache) {
super(element, nameTableCache);
public JavacElementMethodImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) {
super(element, qualifier, nameTableCache);
}
@Override
@@ -213,8 +214,8 @@ public interface JavacRef {
}
class JavacElementFieldImpl extends JavacElementRefBase implements JavacField {
public JavacElementFieldImpl(@NotNull Element element, JavacNameTable nameTableCache) {
super(element, nameTableCache);
public JavacElementFieldImpl(@NotNull Element element, @Nullable Element qualifier, JavacNameTable nameTableCache) {
super(element, qualifier, nameTableCache);
}
}
}