read properties from binary classes
(intermediate version)
This commit is contained in:
+7
-12
@@ -21,7 +21,7 @@ public class JavaClassMembersScope implements JetScope {
|
||||
private final boolean staticMembers;
|
||||
private final DeclarationDescriptor containingDeclaration;
|
||||
private final Map<String, Set<FunctionDescriptor>> functionGroups = Maps.newHashMap();
|
||||
private final Map<String, VariableDescriptor> variables = Maps.newHashMap();
|
||||
private final Map<String, Set<VariableDescriptor>> variables = Maps.newHashMap();
|
||||
private final Map<String, ClassifierDescriptor> classifiers = Maps.newHashMap();
|
||||
private Collection<DeclarationDescriptor> allDescriptors;
|
||||
|
||||
@@ -77,13 +77,7 @@ public class JavaClassMembersScope implements JetScope {
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiField field : psiClass.getAllFields()) {
|
||||
if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
|
||||
continue;
|
||||
}
|
||||
VariableDescriptor variableDescriptor = semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field);
|
||||
allDescriptors.add(variableDescriptor);
|
||||
}
|
||||
allDescriptors.addAll(semanticServices.getDescriptorResolver().resolveFieldGroup(containingDeclaration, psiClass, staticMembers));
|
||||
}
|
||||
return allDescriptors;
|
||||
}
|
||||
@@ -116,14 +110,14 @@ public class JavaClassMembersScope implements JetScope {
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<VariableDescriptor> getProperties(@NotNull String name) {
|
||||
VariableDescriptor variableDescriptor = variables.get(name);
|
||||
Set<VariableDescriptor> variableDescriptor = variables.get(name);
|
||||
if (variableDescriptor == null) {
|
||||
variableDescriptor = doGetVariable(name);
|
||||
if (variableDescriptor != null) {
|
||||
variables.put(name, variableDescriptor);
|
||||
}
|
||||
}
|
||||
return variableDescriptor != null ? Collections.singleton(variableDescriptor) : Collections.<VariableDescriptor>emptySet();
|
||||
return variableDescriptor != null ? variableDescriptor : Collections.<VariableDescriptor>emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,14 +126,15 @@ public class JavaClassMembersScope implements JetScope {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VariableDescriptor doGetVariable(String name) {
|
||||
private Set<VariableDescriptor> doGetVariable(String name) {
|
||||
PsiField field = psiClass.findFieldByName(name, true);
|
||||
if (field == null) return null;
|
||||
if (field.hasModifierProperty(PsiModifier.STATIC) != staticMembers) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field);
|
||||
//return semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDeclaration, field);
|
||||
return semanticServices.getDescriptorResolver().resolveFieldGroupByName(containingDeclaration, psiClass, name, staticMembers);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+208
-4
@@ -4,6 +4,7 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.DelegatingGlobalSearchScope;
|
||||
@@ -85,8 +86,14 @@ public class JavaDescriptorResolver {
|
||||
this.lowerBoundsForKotlin = lowerBoundsForKotlin;
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class ResolverScopeData {
|
||||
@Nullable
|
||||
private Set<VariableDescriptor> properties;
|
||||
private boolean kotlin;
|
||||
}
|
||||
|
||||
private static class ResolverClassData {
|
||||
private static class ResolverClassData extends ResolverScopeData {
|
||||
private JavaClassDescriptor classDescriptor;
|
||||
private boolean kotlin;
|
||||
|
||||
@@ -96,7 +103,7 @@ public class JavaDescriptorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ResolverNamespaceData {
|
||||
private static class ResolverNamespaceData extends ResolverScopeData {
|
||||
private JavaNamespaceDescriptor namespaceDescriptor;
|
||||
private boolean kotlin;
|
||||
|
||||
@@ -751,6 +758,7 @@ public class JavaDescriptorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public VariableDescriptor resolveFieldToVariableDescriptor(DeclarationDescriptor containingDeclaration, PsiField field) {
|
||||
VariableDescriptor variableDescriptor = fieldDescriptorCache.get(field);
|
||||
if (variableDescriptor != null) {
|
||||
@@ -772,6 +780,200 @@ public class JavaDescriptorResolver {
|
||||
fieldDescriptorCache.put(field, propertyDescriptor);
|
||||
return propertyDescriptor;
|
||||
}
|
||||
*/
|
||||
|
||||
private static class PropertyKey {
|
||||
@NotNull
|
||||
private final String name;
|
||||
@NotNull
|
||||
private final PsiType type;
|
||||
|
||||
private PropertyKey(String name, PsiType type) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// generated by Idea
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
PropertyKey that = (PropertyKey) o;
|
||||
|
||||
if (!name.equals(that.name)) return false;
|
||||
if (!type.equals(that.type)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = name.hashCode();
|
||||
result = 31 * result + type.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MembersForProperty {
|
||||
private PsiField field;
|
||||
private PsiMethod setter;
|
||||
private PsiMethod getter;
|
||||
}
|
||||
|
||||
private Map<PropertyKey, MembersForProperty> getMembersForProperties(@NotNull PsiClass clazz, boolean staticMembers, boolean kotlin) {
|
||||
Map<PropertyKey, MembersForProperty> membersMap = Maps.newHashMap();
|
||||
if (!kotlin) {
|
||||
for (PsiField field : clazz.getFields()) {
|
||||
if (field.getModifierList().hasExplicitModifier(PsiModifier.STATIC) != staticMembers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (field.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MembersForProperty members = new MembersForProperty();
|
||||
members.field = field;
|
||||
membersMap.put(new PropertyKey(field.getName(), field.getType()), members);
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiMethod method : clazz.getMethods()) {
|
||||
if (method.getModifierList().hasExplicitModifier(PsiModifier.STATIC) != staticMembers) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: "is" prefix
|
||||
if (method.getName().startsWith(JvmAbi.GETTER_PREFIX)) {
|
||||
// TODO: some java properties too
|
||||
if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) {
|
||||
if (method.getParameterList().getParametersCount() == 0) {
|
||||
if (method.getName().equals(JvmStdlibNames.JET_OBJECT_GET_TYPEINFO_METHOD)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.GETTER_PREFIX.length()));
|
||||
PropertyKey key = new PropertyKey(propertyName, method.getReturnType());
|
||||
MembersForProperty members = membersMap.get(key);
|
||||
if (members == null) {
|
||||
members = new MembersForProperty();
|
||||
membersMap.put(key, members);
|
||||
}
|
||||
members.getter = method;
|
||||
}
|
||||
}
|
||||
} else if (method.getName().startsWith(JvmAbi.SETTER_PREFIX)) {
|
||||
if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null) {
|
||||
if (method.getParameterList().getParametersCount() == 1) {
|
||||
String propertyName = StringUtil.decapitalize(method.getName().substring(JvmAbi.SETTER_PREFIX.length()));
|
||||
PropertyKey key = new PropertyKey(propertyName, method.getParameterList().getParameters()[0].getType());
|
||||
MembersForProperty members = membersMap.get(key);
|
||||
if (members == null) {
|
||||
members = new MembersForProperty();
|
||||
membersMap.put(key, members);
|
||||
}
|
||||
members.setter = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return membersMap;
|
||||
}
|
||||
|
||||
public Set<VariableDescriptor> resolveFieldGroupByName(@NotNull DeclarationDescriptor owner, PsiClass psiClass, String fieldName, boolean staticMembers) {
|
||||
Set<VariableDescriptor> r = Sets.newHashSet();
|
||||
// TODO: slow
|
||||
Set<VariableDescriptor> variables = resolveFieldGroup(owner, psiClass, staticMembers);
|
||||
for (VariableDescriptor variable : variables) {
|
||||
if (variable.getName().equals(fieldName)) {
|
||||
r.add(variable);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<VariableDescriptor> resolveFieldGroup(@NotNull DeclarationDescriptor owner, PsiClass psiClass, boolean staticMembers) {
|
||||
|
||||
ResolverScopeData scopeData;
|
||||
if (owner instanceof JavaNamespaceDescriptor) {
|
||||
scopeData = namespaceDescriptorCacheByFqn.get(((JavaNamespaceDescriptor) owner).getQualifiedName());
|
||||
} else if (owner instanceof JavaClassDescriptor) {
|
||||
scopeData = classDescriptorCache.get(psiClass.getQualifiedName());
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (scopeData == null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
if (scopeData.properties != null) {
|
||||
return scopeData.properties;
|
||||
}
|
||||
|
||||
Set<VariableDescriptor> descriptors = Sets.newHashSet();
|
||||
for (Map.Entry<PropertyKey, MembersForProperty> entry : getMembersForProperties(psiClass, staticMembers, scopeData.kotlin).entrySet()) {
|
||||
//VariableDescriptor variableDescriptor = fieldDescriptorCache.get(field);
|
||||
//if (variableDescriptor != null) {
|
||||
// return variableDescriptor;
|
||||
//}
|
||||
String propertyName = entry.getKey().name;
|
||||
PsiType propertyType = entry.getKey().type;
|
||||
MembersForProperty members = entry.getValue();
|
||||
|
||||
JetType type = semanticServices.getTypeTransformer().transformToType(propertyType);
|
||||
boolean isFinal;
|
||||
if (members.setter == null && members.getter == null) {
|
||||
isFinal = members.field.hasModifierProperty(PsiModifier.FINAL);
|
||||
} else if (members.getter != null) {
|
||||
isFinal = members.getter.hasModifierProperty(PsiModifier.FINAL);
|
||||
} else if (members.setter != null) {
|
||||
isFinal = members.setter.hasModifierProperty(PsiModifier.FINAL);
|
||||
} else {
|
||||
isFinal = false;
|
||||
}
|
||||
|
||||
PsiMember anyMember;
|
||||
if (members.getter != null) {
|
||||
anyMember = members.getter;
|
||||
} else if (members.field != null) {
|
||||
anyMember = members.field;
|
||||
} else if (members.setter != null) {
|
||||
anyMember = members.setter;
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
boolean isVar;
|
||||
if (members.getter == null && members.setter == null) {
|
||||
isVar = true;
|
||||
} else {
|
||||
isVar = members.setter != null;
|
||||
}
|
||||
|
||||
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
|
||||
owner,
|
||||
Collections.<AnnotationDescriptor>emptyList(),
|
||||
isFinal && !staticMembers ? Modality.FINAL : Modality.OPEN, // TODO: abstract
|
||||
resolveVisibilityFromPsiModifiers(anyMember),
|
||||
isVar,
|
||||
null,
|
||||
DescriptorUtils.getExpectedThisObjectIfNeeded(owner),
|
||||
propertyName,
|
||||
type);
|
||||
semanticServices.getTrace().record(BindingContext.VARIABLE, anyMember, propertyDescriptor);
|
||||
//fieldDescriptorCache.put(field, propertyDescriptor);
|
||||
descriptors.add(propertyDescriptor);
|
||||
}
|
||||
scopeData.properties = descriptors;
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<FunctionDescriptor> resolveFunctionGroup(@NotNull DeclarationDescriptor owner, @NotNull PsiClass psiClass, @Nullable ClassDescriptor classDescriptor, @NotNull String methodName, boolean staticMembers) {
|
||||
@@ -870,10 +1072,12 @@ public class JavaDescriptorResolver {
|
||||
// TODO: hide getters and setters properly
|
||||
if (kotlin) {
|
||||
if (method.getName().startsWith(JvmAbi.GETTER_PREFIX) && method.getParameterList().getParametersCount() == 0) {
|
||||
return null;
|
||||
if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null)
|
||||
return null;
|
||||
}
|
||||
if (method.getName().startsWith(JvmAbi.SETTER_PREFIX) && method.getParameterList().getParametersCount() == 1) {
|
||||
return null;
|
||||
if (method.getModifierList().findAnnotation(JvmStdlibNames.JET_PROPERTY.getFqName()) != null)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ public class JavaPackageScope extends JetScopeImpl {
|
||||
}
|
||||
|
||||
// TODO: cache
|
||||
return Collections.singleton(semanticServices.getDescriptorResolver().resolveFieldToVariableDescriptor(containingDescriptor, field));
|
||||
return semanticServices.getDescriptorResolver().resolveFieldGroupByName(containingDescriptor, psiClassForPackage, name, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -26,6 +26,8 @@ public class JvmStdlibNames {
|
||||
public static final String JET_METHOD_NULLABLE_RETURN_TYPE_FIELD = "nullableReturnType";
|
||||
public static final String JET_METHOD_RETURN_TYPE_FIELD = "returnType";
|
||||
public static final String JET_METHOD_TYPE_PARAMETERS_FIELD = "typeParameters";
|
||||
|
||||
public static final JvmClassName JET_PROPERTY = new JvmClassName("jet.typeinfo.JetProperty");
|
||||
|
||||
|
||||
public static final JvmClassName JET_CLASS = new JvmClassName("jet.typeinfo.JetClass");
|
||||
@@ -34,6 +36,8 @@ public class JvmStdlibNames {
|
||||
|
||||
|
||||
public static final JvmClassName JET_OBJECT = new JvmClassName("jet.JetObject");
|
||||
|
||||
public static final String JET_OBJECT_GET_TYPEINFO_METHOD = "getTypeInfo";
|
||||
|
||||
|
||||
private JvmStdlibNames() {
|
||||
|
||||
Reference in New Issue
Block a user