Get PsiMethod wrappers for properties and property accessors
This commit is contained in:
@@ -31,10 +31,13 @@ import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.PsiFileStub;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.java.JetClsMethod;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
|
||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
@@ -42,6 +45,7 @@ import org.jetbrains.jet.utils.KotlinVfsUtil;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class LightClassUtil {
|
||||
private static final Logger LOG = Logger.getInstance(LightClassUtil.class);
|
||||
@@ -116,42 +120,70 @@ public class LightClassUtil {
|
||||
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).getPsiClass(classOrObject);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getLightClassAccessorMethod(@NotNull JetPropertyAccessor accessor) {
|
||||
return getPsiMethodWrapper(accessor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PropertyAccessorsPsiMethods getLightClassPropertyMethods(@NotNull JetProperty property) {
|
||||
JetPropertyAccessor getter = property.getGetter();
|
||||
JetPropertyAccessor setter = property.getSetter();
|
||||
|
||||
PsiMethod getterWrapper = getter != null ? getLightClassAccessorMethod(getter) : null;
|
||||
PsiMethod setterWrapper = setter != null ? getLightClassAccessorMethod(setter) : null;
|
||||
|
||||
if (getterWrapper == null || setterWrapper == null) {
|
||||
List<PsiMethod> wrappers = getPsiMethodWrappers(property, true);
|
||||
assert wrappers.size() <= 2 : "Maximum two wrappers are expected to be generated for property";
|
||||
|
||||
for (PsiMethod wrapper : wrappers) {
|
||||
if (wrapper.getName().startsWith(JvmAbi.SETTER_PREFIX)) {
|
||||
assert setterWrapper == null : String.format(
|
||||
"Setter accessor isn't expected to be reassigned (old: %s, new: %s)", setterWrapper, wrapper);
|
||||
|
||||
setterWrapper = wrapper;
|
||||
}
|
||||
else {
|
||||
assert getterWrapper == null : String.format(
|
||||
"Getter accessor isn't expected to be reassigned (old: %s, new: %s)", getterWrapper, wrapper);
|
||||
|
||||
getterWrapper = wrapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new PropertyAccessorsPsiMethods(getterWrapper, setterWrapper);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiMethod getLightClassMethod(@NotNull JetNamedFunction function) {
|
||||
//noinspection unchecked
|
||||
if (PsiTreeUtil.getParentOfType(function, JetFunction.class, JetProperty.class) != null) {
|
||||
// Don't genClassOrObject method wrappers for internal declarations. Their classes are not generated during calcStub
|
||||
// with ClassBuilderMode.SIGNATURES mode, and this produces "Class not found exception" in getDelegate()
|
||||
return null;
|
||||
return getPsiMethodWrapper(function);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod getPsiMethodWrapper(@NotNull JetDeclaration declaration) {
|
||||
List<PsiMethod> wrappers = getPsiMethodWrappers(declaration, false);
|
||||
return !wrappers.isEmpty() ? wrappers.get(0) : null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiMethod> getPsiMethodWrappers(@NotNull JetDeclaration declaration, boolean collectAll) {
|
||||
PsiClass psiClass = getWrappingClass(declaration);
|
||||
if (psiClass == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Project project = function.getProject();
|
||||
|
||||
PsiElement parent = function.getParent();
|
||||
PsiClass psiClass;
|
||||
if (parent == function.getContainingFile()) {
|
||||
// top-level function
|
||||
JvmClassName jvmClassName = PsiCodegenPredictor.getPredefinedJvmClassName((JetFile) parent, true);
|
||||
if (jvmClassName == null) return null;
|
||||
|
||||
String fqName = jvmClassName.getFqName().getFqName();
|
||||
psiClass = JavaElementFinder.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project));
|
||||
}
|
||||
else {
|
||||
if (!(parent instanceof JetClassBody)) return null;
|
||||
assert parent.getParent() instanceof JetClassOrObject;
|
||||
|
||||
// function in a class
|
||||
JetClassOrObject classOrObject = (JetClassOrObject) parent.getParent();
|
||||
psiClass = getPsiClass(classOrObject);
|
||||
}
|
||||
|
||||
if (psiClass == null) return null;
|
||||
|
||||
List<PsiMethod> methods = new SmartList<PsiMethod>();
|
||||
for (PsiMethod method : psiClass.getMethods()) {
|
||||
try {
|
||||
if (method instanceof PsiCompiledElement && ((PsiCompiledElement) method).getMirror() == function) {
|
||||
return method;
|
||||
if (method instanceof JetClsMethod) {
|
||||
if (method instanceof PsiCompiledElement && ((PsiCompiledElement) method).getMirror() == declaration) {
|
||||
methods.add(method);
|
||||
if (!collectAll) {
|
||||
return methods;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
@@ -159,24 +191,94 @@ public class LightClassUtil {
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new IllegalStateException(
|
||||
"Error while wrapping function " + function.getName() +
|
||||
"Error while wrapping declaration " + declaration.getName() +
|
||||
"Context\n:" +
|
||||
String.format("=== In file ===\n" +
|
||||
"%s\n" +
|
||||
"===On element===\n" +
|
||||
"%s\n" +
|
||||
"===WrappedElement===\n" +
|
||||
"%s\n",
|
||||
function.getContainingFile().getText(),
|
||||
function.getText(),
|
||||
method.toString()),
|
||||
"%s\n" +
|
||||
"=== On element ===\n" +
|
||||
"%s\n" +
|
||||
"=== WrappedElement ===\n" +
|
||||
"%s\n",
|
||||
declaration.getContainingFile().getText(),
|
||||
declaration.getText(),
|
||||
method.toString()),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass getWrappingClass(@NotNull JetDeclaration declaration) {
|
||||
if (declaration instanceof JetPropertyAccessor) {
|
||||
PsiElement propertyParent = declaration.getParent();
|
||||
assert propertyParent instanceof JetProperty : "JetProperty is expected to be parent of accessor";
|
||||
|
||||
declaration = (JetProperty) propertyParent;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
if (PsiTreeUtil.getParentOfType(declaration, JetFunction.class, JetProperty.class) != null) {
|
||||
// Can't get wrappers for internal declarations. Their classes are not generated during calcStub
|
||||
// with ClassBuilderMode.SIGNATURES mode, and this produces "Class not found exception" in getDelegate()
|
||||
return null;
|
||||
}
|
||||
|
||||
PsiElement parent = declaration.getParent();
|
||||
|
||||
if (parent instanceof JetFile) {
|
||||
// top-level declaration
|
||||
JvmClassName jvmName = PsiCodegenPredictor.getPredefinedJvmClassName((JetFile) parent, true);
|
||||
if (jvmName != null) {
|
||||
Project project = declaration.getProject();
|
||||
|
||||
String fqName = jvmName.getFqName().getFqName();
|
||||
return JavaElementFinder.getInstance(project).findClass(fqName, GlobalSearchScope.allScope(project));
|
||||
}
|
||||
}
|
||||
else if (parent instanceof JetClassBody) {
|
||||
assert parent.getParent() instanceof JetClassOrObject;
|
||||
return getPsiClass((JetClassOrObject) parent.getParent());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class PropertyAccessorsPsiMethods implements Iterable<PsiMethod> {
|
||||
private final PsiMethod getter;
|
||||
private final PsiMethod setter;
|
||||
private final Collection<PsiMethod> accessors = new ArrayList<PsiMethod>(2);
|
||||
|
||||
PropertyAccessorsPsiMethods(@Nullable PsiMethod getter, @Nullable PsiMethod setter) {
|
||||
this.getter = getter;
|
||||
if (getter != null) {
|
||||
accessors.add(getter);
|
||||
}
|
||||
|
||||
this.setter = setter;
|
||||
if (setter != null) {
|
||||
accessors.add(setter);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiMethod getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiMethod getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<PsiMethod> iterator() {
|
||||
return accessors.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
private LightClassUtil() {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user