JavaDescriptorResolver: resolve constructors lazily

This speeds up analyze a bit (profiler shown about 10% of time
spent in constructor resolver during completion in KDoc).
This commit is contained in:
Stepan Koltsov
2012-06-16 00:22:23 +04:00
parent 8d1ef3ee6b
commit 5f1f854293
4 changed files with 139 additions and 52 deletions
@@ -0,0 +1,71 @@
/*
* Copyright 2010-2012 JetBrains s.r.o.
*
* 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 org.jetbrains.jet.lang.resolve.java;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassKind;
import org.jetbrains.jet.lang.descriptors.ConstructorDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.MutableClassDescriptorLite;
import org.jetbrains.jet.lang.resolve.lazy.LazyClassDescriptor;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author Stepan Koltsov
*
* @see LazyClassDescriptor
*/
public class ClassDescriptorFromJvmBytecode extends MutableClassDescriptorLite {
@NotNull
private final JavaDescriptorResolver javaDescriptorResolver;
@NotNull
private final JavaDescriptorResolver.ResolverBinaryClassData resolverBinaryClassData;
// lazy
private Collection<ConstructorDescriptor> constructors;
public ClassDescriptorFromJvmBytecode(
@NotNull DeclarationDescriptor containingDeclaration, @NotNull ClassKind kind,
@NotNull PsiClass psiClass, @NotNull FqName fqName,
@NotNull JavaDescriptorResolver javaDescriptorResolver) {
super(containingDeclaration, kind);
this.javaDescriptorResolver = javaDescriptorResolver;
this.resolverBinaryClassData = new JavaDescriptorResolver.ResolverBinaryClassData(psiClass, fqName, this);
}
@NotNull
public JavaDescriptorResolver.ResolverBinaryClassData getResolverBinaryClassData() {
return resolverBinaryClassData;
}
@NotNull
@Override
public Collection<ConstructorDescriptor> getConstructors() {
if (constructors == null) {
this.constructors = javaDescriptorResolver.resolveConstructors(resolverBinaryClassData);
}
return constructors;
}
}
@@ -183,9 +183,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
/** Class with instance members */
static class ResolverBinaryClassData extends ResolverScopeData {
private final MutableClassDescriptorLite classDescriptor;
private final ClassDescriptorFromJvmBytecode classDescriptor;
ResolverBinaryClassData(@NotNull PsiClass psiClass, @NotNull FqName fqName, @NotNull MutableClassDescriptorLite classDescriptor) {
ResolverBinaryClassData(@NotNull PsiClass psiClass, @NotNull FqName fqName, @NotNull ClassDescriptorFromJvmBytecode classDescriptor) {
super(psiClass, null, fqName, false, classDescriptor);
this.classDescriptor = classDescriptor;
}
@@ -360,7 +360,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
return classData;
}
classData = new ResolverBinaryClassData(psiClass, fqName, new MutableClassDescriptorLite(containingDeclaration, kind));
classData = new ClassDescriptorFromJvmBytecode(
containingDeclaration, kind, psiClass, fqName, this)
.getResolverBinaryClassData();
classDescriptorCache.put(fqName, classData);
classData.classDescriptor.setName(name);
classData.classDescriptor.setAnnotations(resolveAnnotations(psiClass, taskList));
@@ -392,17 +394,40 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
initializeTypeParameters(classData.typeParameters, classData.classDescriptor, "class " + psiClass.getQualifiedName());
TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver(
classData.classDescriptor,
"class " + psiClass.getQualifiedName());
// TODO: ugly hack: tests crash if initializeTypeParameters called with class containing proper supertypes
supertypes.addAll(getSupertypes(new PsiClassWrapper(psiClass), classData, classData.getTypeParameters()));
MutableClassDescriptorLite classObject = createClassObjectDescriptor(classData.classDescriptor, psiClass);
if (classObject != null) {
classData.classDescriptor.getBuilder().setClassObjectDescriptor(classObject);
}
trace.record(BindingContext.CLASS, psiClass, classData.classDescriptor);
return classData;
}
@NotNull
public Collection<ConstructorDescriptor> resolveConstructors(@NotNull ResolverBinaryClassData classData) {
Collection<ConstructorDescriptor> constructors = Lists.newArrayList();
PsiClass psiClass = classData.psiClass;
TypeVariableResolver resolverForTypeParameters = TypeVariableResolvers.classTypeVariableResolver(
classData.classDescriptor, "class " + psiClass.getQualifiedName());
List<TypeParameterDescriptor> typeParameters = classData.classDescriptor.getTypeConstructor().getParameters();
PsiMethod[] psiConstructors = psiClass.getConstructors();
boolean isStatic = psiClass.hasModifierProperty(PsiModifier.STATIC);
if (psiConstructors.length == 0) {
if (classData.classDescriptor.getKind() == ClassKind.OBJECT) {
// TODO: wrong: class objects do not need visible constructors
ConstructorDescriptorImpl constructor = new ConstructorDescriptorImpl(classData.classDescriptor, new ArrayList<AnnotationDescriptor>(0), true);
constructor.initialize(new ArrayList<TypeParameterDescriptor>(0), new ArrayList<ValueParameterDescriptor>(0), Visibilities.PUBLIC);
constructors.add(constructor);
}
else if (psiConstructors.length == 0) {
// We need to create default constructors for classes and abstract classes.
// Example:
// class Kotlin() : Java() {}
@@ -413,8 +438,7 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
Collections.<AnnotationDescriptor>emptyList(),
false);
constructorDescriptor.initialize(typeParameters, Collections.<ValueParameterDescriptor>emptyList(), classData.classDescriptor.getVisibility(), isStatic);
constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType());
classData.classDescriptor.addConstructor(constructorDescriptor, null);
constructors.add(constructorDescriptor);
trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
}
if (psiClass.isAnnotationType()) {
@@ -454,32 +478,32 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
}
constructorDescriptor.initialize(typeParameters, valueParameters, classData.classDescriptor.getVisibility(), isStatic);
constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType());
classData.classDescriptor.addConstructor(constructorDescriptor, null);
constructors.add(constructorDescriptor);
trace.record(BindingContext.CONSTRUCTOR, psiClass, constructorDescriptor);
}
}
else {
for (PsiMethod psiConstructor : psiConstructors) {
resolveConstructor(psiClass, classData, isStatic, psiConstructor);
ConstructorDescriptor constructor = resolveConstructor(psiClass, classData, isStatic, psiConstructor);
if (constructor != null) {
constructors.add(constructor);
}
}
}
MutableClassDescriptorLite classObject = createClassObjectDescriptor(classData.classDescriptor, psiClass);
if (classObject != null) {
classData.classDescriptor.getBuilder().setClassObjectDescriptor(classObject);
for (ConstructorDescriptor constructor : constructors) {
((ConstructorDescriptorImpl) constructor).setReturnType(classData.classDescriptor.getDefaultType());
}
trace.record(BindingContext.CLASS, psiClass, classData.classDescriptor);
return classData;
return constructors;
}
private void resolveConstructor(PsiClass psiClass, ResolverBinaryClassData classData, boolean aStatic, PsiMethod psiConstructor) {
@Nullable
private ConstructorDescriptor resolveConstructor(PsiClass psiClass, ResolverBinaryClassData classData, boolean aStatic, PsiMethod psiConstructor) {
PsiMethodWrapper constructor = new PsiMethodWrapper(psiConstructor);
if (constructor.getJetConstructor().hidden()) {
return;
return null;
}
ConstructorDescriptorImpl constructorDescriptor = new ConstructorDescriptorImpl(
@@ -496,9 +520,8 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
constructorDescriptor.initialize(classData.classDescriptor.getTypeConstructor().getParameters(),
valueParameterDescriptors.descriptors,
resolveVisibilityFromPsiModifiers(psiConstructor), aStatic);
constructorDescriptor.setReturnType(classData.classDescriptor.getDefaultType());
classData.classDescriptor.addConstructor(constructorDescriptor, null);
trace.record(BindingContext.CONSTRUCTOR, psiConstructor, constructorDescriptor);
return constructorDescriptor;
}
static void checkPsiClassIsNotJet(PsiClass psiClass) {
@@ -531,8 +554,9 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
checkPsiClassIsNotJet(psiClass);
FqName fqName = new FqName(classObjectPsiClass.getQualifiedName());
ResolverBinaryClassData classData = new ResolverBinaryClassData(classObjectPsiClass, fqName,
new MutableClassDescriptorLite(containing, ClassKind.OBJECT));
ResolverBinaryClassData classData = new ClassDescriptorFromJvmBytecode(
containing, ClassKind.OBJECT, classObjectPsiClass, fqName, this)
.getResolverBinaryClassData();
classDescriptorCache.put(fqName, classData);
@@ -544,12 +568,6 @@ public class JavaDescriptorResolver implements DependencyClassByQualifiedNameRes
classData.classDescriptor.createTypeConstructor();
classData.classDescriptor.setScopeForMemberLookup(new JavaClassMembersScope(semanticServices, classData));
// TODO: wrong: class objects do not need visible constructors
ConstructorDescriptorImpl constructor = new ConstructorDescriptorImpl(classData.classDescriptor, new ArrayList<AnnotationDescriptor>(0), true);
constructor.setReturnType(classData.classDescriptor.getDefaultType());
constructor.initialize(new ArrayList<TypeParameterDescriptor>(0), new ArrayList<ValueParameterDescriptor>(0), Visibilities.PUBLIC);
classData.classDescriptor.addConstructor(constructor, null);
return classData.classDescriptor;
}
@@ -38,6 +38,7 @@ import java.util.Set;
* @author abreslav
*/
public class MutableClassDescriptor extends MutableClassDescriptorLite implements ClassDescriptorFromSource {
private final Set<ConstructorDescriptor> constructors = Sets.newLinkedHashSet();
private ConstructorDescriptor primaryConstructor;
private final Set<CallableMemberDescriptor> declaredCallableMembers = Sets.newHashSet();
@@ -72,9 +73,15 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor, @NotNull BindingTrace trace) {
super.addConstructor(constructorDescriptor, trace);
if (constructorDescriptor.getContainingDeclaration() != this) {
throw new IllegalStateException("invalid containing declaration of constructor");
}
constructors.add(constructorDescriptor);
if (defaultType != null) {
((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType());
}
if (constructorDescriptor.isPrimary()) {
setUpScopeForInitializers(constructorDescriptor);
for (ValueParameterDescriptor valueParameterDescriptor : constructorDescriptor.getValueParameters()) {
@@ -93,6 +100,12 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement
addConstructor(constructorDescriptor, trace);
}
@NotNull
@Override
public Set<ConstructorDescriptor> getConstructors() {
return constructors;
}
@Override
@Nullable
public ConstructorDescriptor getUnsubstitutedPrimaryConstructor() {
@@ -141,6 +154,9 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement
@Override
public void createTypeConstructor() {
super.createTypeConstructor();
for (FunctionDescriptor functionDescriptor : getConstructors()) {
((ConstructorDescriptorImpl) functionDescriptor).setReturnType(getDefaultType());
}
scopeForMemberResolution.setImplicitReceiver(new ClassReceiver(this));
}
@@ -36,9 +36,8 @@ import java.util.*;
/**
* @author Stepan Koltsov
*/
public class MutableClassDescriptorLite extends ClassDescriptorBase
public abstract class MutableClassDescriptorLite extends ClassDescriptorBase
implements WithDeferredResolve {
private final Set<ConstructorDescriptor> constructors = Sets.newLinkedHashSet();
private List<AnnotationDescriptor> annotations = Lists.newArrayList();
@@ -134,9 +133,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase
getName().getName(),
typeParameters,
supertypes);
for (FunctionDescriptor functionDescriptor : constructors) {
((ConstructorDescriptorImpl) functionDescriptor).setReturnType(getDefaultType());
}
}
private WritableScope getScopeForMemberLookupAsWritableScope() {
@@ -145,12 +141,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase
}
@NotNull
@Override
public Collection<ConstructorDescriptor> getConstructors() {
return constructors;
}
@NotNull
public JetScope getScopeForMemberLookup() {
return scopeForMemberLookup;
@@ -205,14 +195,6 @@ public class MutableClassDescriptorLite extends ClassDescriptorBase
}
public void addConstructor(@NotNull ConstructorDescriptor constructorDescriptor, @Nullable BindingTrace trace) {
assert constructorDescriptor.getContainingDeclaration() == this;
constructors.add(constructorDescriptor);
if (defaultType != null) {
((ConstructorDescriptorImpl) constructorDescriptor).setReturnType(getDefaultType());
}
}
@Override
@Nullable
public MutableClassDescriptorLite getClassObjectDescriptor() {