/* * Copyright 2013 Guidewire Software, Inc. */ package gw.plugin.ij.lang.psi.impl.resolvers; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiTypeParameter; import com.intellij.psi.PsiTypeParameterListOwner; import gw.lang.reflect.IFunctionType; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IType; import gw.lang.reflect.ITypeVariableType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.gs.IGosuClass; import gw.plugin.ij.lang.psi.api.ITypeResolver; import gw.plugin.ij.util.ExecutionUtil; import gw.plugin.ij.util.SafeCallable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class PsiTypeResolver { private static final NotNullLazyValue<ITypeResolver[]> resolvers = new NotNullLazyValue<ITypeResolver[]>() { @NotNull @Override protected ITypeResolver[] compute() { final TypeResolverExtensionBean[] extensions = Extensions.getExtensions(TypeResolverExtensionBean.EP_NAME); final ITypeResolver[] resolvers = new ITypeResolver[extensions.length]; for (int i = 0; i < resolvers.length; i++) { resolvers[i] = extensions[i].getHandler(); } return resolvers; } }; @Nullable public static PsiElement resolveType(@NotNull final IType type, @NotNull final PsiElement ctx) { if (TypeSystem.isDeleted(type)) { return null; } return ExecutionUtil.execute(new SafeCallable<PsiElement>(ctx) { public PsiElement execute() throws Exception { for (ITypeResolver resolver : resolvers.getValue()) { final PsiElement element = resolver.resolveType(type, ctx); if (element != null) { return element; } } return null; } }); } @Nullable public static PsiClass resolveType(final String strFullName, @NotNull final PsiElement ctx) { return ExecutionUtil.execute(new SafeCallable<PsiClass>(ctx) { public PsiClass execute() throws Exception { for (ITypeResolver resolver : resolvers.getValue()) { PsiClass element = resolver.resolveType(strFullName, ctx); if (element != null) { return element; } } return null; } }); } @Nullable public static PsiElement resolveTypeVariable(@NotNull final ITypeVariableType tv, @NotNull final PsiElement ctx) { return ExecutionUtil.execute(new SafeCallable<PsiElement>(ctx) { public PsiElement execute() throws Exception { IType encType = tv.getEnclosingType(); PsiTypeParameterListOwner psiTypeParamOwner = null; if (encType instanceof IFunctionType) { IMethodInfo methodInfo = ((IFunctionType) encType).getMethodInfo(); if (methodInfo != null) { psiTypeParamOwner = (PsiTypeParameterListOwner) PsiFeatureResolver.resolveMethodOrConstructor(methodInfo, ctx); } } else { psiTypeParamOwner = resolveType(getTypeName(encType), ctx); } if (psiTypeParamOwner != null) { return findTypeVariable(tv, psiTypeParamOwner); } else { return null; } } }); } @Nullable public static PsiElement findTypeVariable(@NotNull ITypeVariableType tv, @NotNull PsiTypeParameterListOwner psiTypeParamOwner) { for (PsiTypeParameter param : psiTypeParamOwner.getTypeParameters()) { if (param.getName().equals(tv.getRelativeName())) { return param; } } return null; } @Nullable public static PsiElement getProxiedPsiClass(@NotNull final IType proxyType, @NotNull final PsiElement ctx) { return ExecutionUtil.execute(new SafeCallable<PsiElement>(ctx) { public PsiElement execute() throws Exception { String fqProxiedClassName = IGosuClass.ProxyUtil.getNameSansProxy(proxyType.getName()); IType proxiedType = TypeSystem.getByFullNameIfValid(fqProxiedClassName); return resolveType(proxiedType, ctx); } }); } public static String getTypeName(@NotNull IType type) { while (type.isParameterizedType()) { type = type.getGenericType(); } return type.getName(); } }