Move KotlinPsiElementFinderImpl and add wrapper interface to avoid creating many unsupported methods
This commit is contained in:
+149
-16
@@ -16,30 +16,45 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.jvm;
|
package org.jetbrains.kotlin.resolve.jvm;
|
||||||
|
|
||||||
|
import com.intellij.core.CoreJavaFileManager;
|
||||||
|
import com.intellij.openapi.components.ServiceManager;
|
||||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||||
|
import com.intellij.openapi.project.DumbAware;
|
||||||
import com.intellij.openapi.project.DumbService;
|
import com.intellij.openapi.project.DumbService;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.roots.PackageIndex;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.psi.PsiElementFinder;
|
import com.intellij.psi.PsiElementFinder;
|
||||||
|
import com.intellij.psi.PsiManager;
|
||||||
import com.intellij.psi.PsiPackage;
|
import com.intellij.psi.PsiPackage;
|
||||||
|
import com.intellij.psi.impl.file.PsiPackageImpl;
|
||||||
|
import com.intellij.psi.impl.file.impl.JavaFileManager;
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
import com.intellij.reference.SoftReference;
|
import com.intellij.reference.SoftReference;
|
||||||
|
import com.intellij.util.CommonProcessors;
|
||||||
import com.intellij.util.ConcurrencyUtil;
|
import com.intellij.util.ConcurrencyUtil;
|
||||||
|
import com.intellij.util.Query;
|
||||||
import com.intellij.util.containers.ConcurrentHashMap;
|
import com.intellij.util.containers.ConcurrentHashMap;
|
||||||
|
import kotlin.Function1;
|
||||||
|
import kotlin.KotlinPackage;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
public abstract class JavaPsiFacadeImpl {
|
public class JavaPsiFacadeImpl {
|
||||||
private volatile PsiElementFinder[] myElementFinders;
|
private volatile KotlinPsiElementFinderWrapper[] myElementFinders;
|
||||||
private volatile SoftReference<ConcurrentMap<String, PsiPackage>> myPackageCache;
|
private volatile SoftReference<ConcurrentMap<String, PsiPackage>> myPackageCache;
|
||||||
private final Project myProject;
|
private final Project Project;
|
||||||
|
private final GlobalSearchScope searchScope;
|
||||||
|
|
||||||
public JavaPsiFacadeImpl(Project project) {
|
public JavaPsiFacadeImpl(@NotNull Project project, @NotNull GlobalSearchScope searchScope) {
|
||||||
myProject = project;
|
this.Project = project;
|
||||||
|
this.searchScope = searchScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
@@ -53,7 +68,7 @@ public abstract class JavaPsiFacadeImpl {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PsiElementFinder finder : finders()) {
|
for (KotlinPsiElementFinderWrapper finder : finders()) {
|
||||||
PsiClass aClass = finder.findClass(qualifiedName, scope);
|
PsiClass aClass = finder.findClass(qualifiedName, scope);
|
||||||
if (aClass != null) return aClass;
|
if (aClass != null) return aClass;
|
||||||
}
|
}
|
||||||
@@ -83,8 +98,8 @@ public abstract class JavaPsiFacadeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private PsiElementFinder[] finders() {
|
private KotlinPsiElementFinderWrapper[] finders() {
|
||||||
PsiElementFinder[] answer = myElementFinders;
|
KotlinPsiElementFinderWrapper[] answer = myElementFinders;
|
||||||
if (answer == null) {
|
if (answer == null) {
|
||||||
answer = calcFinders();
|
answer = calcFinders();
|
||||||
myElementFinders = answer;
|
myElementFinders = answer;
|
||||||
@@ -94,7 +109,27 @@ public abstract class JavaPsiFacadeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
protected abstract PsiElementFinder[] calcFinders();
|
protected KotlinPsiElementFinderWrapper[] calcFinders() {
|
||||||
|
List<KotlinPsiElementFinderWrapper> elementFinders = new ArrayList<KotlinPsiElementFinderWrapper>();
|
||||||
|
elementFinders.add(new KotlinPsiElementFinderImpl(getProject()));
|
||||||
|
|
||||||
|
List<PsiElementFinder> nonKotlinFinders = KotlinPackage.filter(
|
||||||
|
getProject().getExtensions(PsiElementFinder.EP_NAME), new Function1<PsiElementFinder, Boolean>() {
|
||||||
|
@Override
|
||||||
|
public Boolean invoke(PsiElementFinder finder) {
|
||||||
|
return !(finder instanceof KotlinFinderMarker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
elementFinders.addAll(KotlinPackage.map(nonKotlinFinders, new Function1<PsiElementFinder, KotlinPsiElementFinderWrapper>() {
|
||||||
|
@Override
|
||||||
|
public KotlinPsiElementFinderWrapper invoke(PsiElementFinder finder) {
|
||||||
|
return wrap(finder);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return elementFinders.toArray(new KotlinPsiElementFinderWrapper[elementFinders.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
||||||
ConcurrentMap<String, PsiPackage> cache = SoftReference.dereference(myPackageCache);
|
ConcurrentMap<String, PsiPackage> cache = SoftReference.dereference(myPackageCache);
|
||||||
@@ -107,8 +142,8 @@ public abstract class JavaPsiFacadeImpl {
|
|||||||
return aPackage;
|
return aPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PsiElementFinder finder : filteredFinders()) {
|
for (KotlinPsiElementFinderWrapper finder : filteredFinders()) {
|
||||||
aPackage = finder.findPackage(qualifiedName);
|
aPackage = finder.findPackage(qualifiedName, searchScope);
|
||||||
if (aPackage != null) {
|
if (aPackage != null) {
|
||||||
return ConcurrencyUtil.cacheOrGet(cache, qualifiedName, aPackage);
|
return ConcurrencyUtil.cacheOrGet(cache, qualifiedName, aPackage);
|
||||||
}
|
}
|
||||||
@@ -118,18 +153,116 @@ public abstract class JavaPsiFacadeImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private PsiElementFinder[] filteredFinders() {
|
private KotlinPsiElementFinderWrapper[] filteredFinders() {
|
||||||
DumbService dumbService = DumbService.getInstance(getProject());
|
DumbService dumbService = DumbService.getInstance(getProject());
|
||||||
PsiElementFinder[] finders = finders();
|
KotlinPsiElementFinderWrapper[] finders = finders();
|
||||||
if (dumbService.isDumb()) {
|
if (dumbService.isDumb()) {
|
||||||
List<PsiElementFinder> list = dumbService.filterByDumbAwareness(Arrays.asList(finders));
|
List<KotlinPsiElementFinderWrapper> list = dumbService.filterByDumbAwareness(Arrays.asList(finders));
|
||||||
finders = list.toArray(new PsiElementFinder[list.size()]);
|
finders = list.toArray(new KotlinPsiElementFinderWrapper[list.size()]);
|
||||||
}
|
}
|
||||||
return finders;
|
return finders;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Project getProject() {
|
public Project getProject() {
|
||||||
return myProject;
|
return Project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KotlinPsiElementFinderWrapper wrap(PsiElementFinder finder) {
|
||||||
|
return finder instanceof DumbAware
|
||||||
|
? new KotlinPsiElementFinderWrapperImplDumbAware(finder)
|
||||||
|
: new KotlinPsiElementFinderWrapperImpl(finder);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KotlinPsiElementFinderWrapper {
|
||||||
|
PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
|
||||||
|
PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper {
|
||||||
|
private final PsiElementFinder finder;
|
||||||
|
|
||||||
|
private KotlinPsiElementFinderWrapperImpl(PsiElementFinder finder) {
|
||||||
|
this.finder = finder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
|
return finder.findClass(qualifiedName, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
|
// Original element finder can't search packages with scope
|
||||||
|
return finder.findPackage(qualifiedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class KotlinPsiElementFinderWrapperImplDumbAware extends KotlinPsiElementFinderWrapperImpl implements DumbAware {
|
||||||
|
private KotlinPsiElementFinderWrapperImplDumbAware(PsiElementFinder finder) {
|
||||||
|
super(finder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class KotlinPsiElementFinderImpl implements KotlinPsiElementFinderWrapper, DumbAware {
|
||||||
|
private final JavaFileManager javaFileManager;
|
||||||
|
private final boolean isCoreJavaFileManager;
|
||||||
|
|
||||||
|
private final PsiManager psiManager;
|
||||||
|
private final PackageIndex packageIndex;
|
||||||
|
|
||||||
|
public KotlinPsiElementFinderImpl(Project project) {
|
||||||
|
this.javaFileManager = findJavaFileManager(project);
|
||||||
|
this.isCoreJavaFileManager = javaFileManager instanceof CoreJavaFileManager;
|
||||||
|
|
||||||
|
this.packageIndex = PackageIndex.getInstance(project);
|
||||||
|
this.psiManager = PsiManager.getInstance(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static JavaFileManager findJavaFileManager(@NotNull Project project) {
|
||||||
|
JavaFileManager javaFileManager = ServiceManager.getService(project, JavaFileManager.class);
|
||||||
|
if (javaFileManager == null) {
|
||||||
|
throw new IllegalStateException("JavaFileManager component is not found in project");
|
||||||
|
}
|
||||||
|
|
||||||
|
return javaFileManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
|
PsiClass aClass = javaFileManager.findClass(qualifiedName, scope);
|
||||||
|
if (aClass != null) {
|
||||||
|
//TODO: (module refactoring) CoreJavaFileManager should check scope
|
||||||
|
if (!isCoreJavaFileManager || scope.contains(aClass.getContainingFile().getOriginalFile().getVirtualFile())) {
|
||||||
|
return aClass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
|
if (isCoreJavaFileManager) {
|
||||||
|
return javaFileManager.findPackage(qualifiedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Query<VirtualFile> dirs = packageIndex.getDirsByPackageName(qualifiedName, true);
|
||||||
|
return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasDirectoriesInScope(Query<VirtualFile> dirs, final GlobalSearchScope scope) {
|
||||||
|
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
|
||||||
|
@Override
|
||||||
|
protected boolean accept(VirtualFile file) {
|
||||||
|
return scope.accept(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dirs.forEach(findProcessor);
|
||||||
|
return findProcessor.isFound();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-150
@@ -16,34 +16,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.jvm;
|
package org.jetbrains.kotlin.resolve.jvm;
|
||||||
|
|
||||||
import com.intellij.core.CoreJavaFileManager;
|
|
||||||
import com.intellij.openapi.components.ServiceManager;
|
|
||||||
import com.intellij.openapi.project.DumbAware;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.roots.PackageIndex;
|
import com.intellij.psi.PsiClass;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.psi.PsiPackage;
|
||||||
import com.intellij.psi.*;
|
|
||||||
import com.intellij.psi.impl.file.PsiPackageImpl;
|
|
||||||
import com.intellij.psi.impl.file.impl.JavaFileManager;
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope;
|
import com.intellij.psi.search.GlobalSearchScope;
|
||||||
import com.intellij.util.CommonProcessors;
|
|
||||||
import com.intellij.util.Processor;
|
|
||||||
import com.intellij.util.Query;
|
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
|
||||||
import kotlin.Function1;
|
|
||||||
import kotlin.KotlinPackage;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class KotlinJavaPsiFacade {
|
public class KotlinJavaPsiFacade {
|
||||||
private final KotlinJavaPsiFacadeWrapper javaPsiFacadeWrapper;
|
private final JavaPsiFacadeImpl javaPsiFacadeWrapper;
|
||||||
|
|
||||||
public KotlinJavaPsiFacade(Project project, GlobalSearchScope searchScope) {
|
public KotlinJavaPsiFacade(Project project, GlobalSearchScope searchScope) {
|
||||||
javaPsiFacadeWrapper = new KotlinJavaPsiFacadeWrapper(project, searchScope);
|
javaPsiFacadeWrapper = new JavaPsiFacadeImpl(project, searchScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
||||||
@@ -53,133 +36,4 @@ public class KotlinJavaPsiFacade {
|
|||||||
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
||||||
return javaPsiFacadeWrapper.findPackage(qualifiedName);
|
return javaPsiFacadeWrapper.findPackage(qualifiedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class KotlinJavaPsiFacadeWrapper extends JavaPsiFacadeImpl {
|
|
||||||
private final GlobalSearchScope searchScope;
|
|
||||||
|
|
||||||
public KotlinJavaPsiFacadeWrapper(Project project, GlobalSearchScope searchScope) {
|
|
||||||
super(project);
|
|
||||||
this.searchScope = searchScope;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
protected PsiElementFinder[] calcFinders() {
|
|
||||||
List<PsiElementFinder> elementFinders = new ArrayList<PsiElementFinder>();
|
|
||||||
elementFinders.add(new KotlinPsiElementFinderImpl(getProject(), searchScope));
|
|
||||||
|
|
||||||
ContainerUtil.addAll(elementFinders, KotlinPackage.filter(
|
|
||||||
getProject().getExtensions(PsiElementFinder.EP_NAME), new Function1<PsiElementFinder, Boolean>() {
|
|
||||||
@Override
|
|
||||||
public Boolean invoke(PsiElementFinder finder) {
|
|
||||||
return !(finder instanceof KotlinFinderMarker);
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
return elementFinders.toArray(new PsiElementFinder[elementFinders.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static JavaFileManager findJavaFileManager(@NotNull Project project) {
|
|
||||||
JavaFileManager javaFileManager = ServiceManager.getService(project, JavaFileManager.class);
|
|
||||||
if (javaFileManager == null) {
|
|
||||||
throw new IllegalStateException("JavaFileManager component is not found in project");
|
|
||||||
}
|
|
||||||
|
|
||||||
return javaFileManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class KotlinPsiElementFinderImpl extends PsiElementFinder implements DumbAware {
|
|
||||||
private final GlobalSearchScope searchScope;
|
|
||||||
|
|
||||||
private final JavaFileManager javaFileManager;
|
|
||||||
private final boolean isCoreJavaFileManager;
|
|
||||||
|
|
||||||
private final PsiManager psiManager;
|
|
||||||
private final PackageIndex packageIndex;
|
|
||||||
|
|
||||||
public KotlinPsiElementFinderImpl(Project project, GlobalSearchScope searchScope) {
|
|
||||||
this.searchScope = searchScope;
|
|
||||||
|
|
||||||
this.javaFileManager = findJavaFileManager(project);
|
|
||||||
this.isCoreJavaFileManager = javaFileManager instanceof CoreJavaFileManager;
|
|
||||||
|
|
||||||
this.packageIndex = PackageIndex.getInstance(project);
|
|
||||||
this.psiManager = PsiManager.getInstance(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
|
||||||
PsiClass aClass = javaFileManager.findClass(qualifiedName, scope);
|
|
||||||
if (aClass != null) {
|
|
||||||
//TODO: (module refactoring) CoreJavaFileManager should check scope
|
|
||||||
if (!isCoreJavaFileManager || scope.contains(aClass.getContainingFile().getOriginalFile().getVirtualFile())) {
|
|
||||||
return aClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PsiPackage findPackage(@NotNull String qualifiedName) {
|
|
||||||
if (isCoreJavaFileManager) {
|
|
||||||
return javaFileManager.findPackage(qualifiedName);
|
|
||||||
}
|
|
||||||
|
|
||||||
Query<VirtualFile> dirs = packageIndex.getDirsByPackageName(qualifiedName, true);
|
|
||||||
return hasDirectoriesInScope(dirs) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasDirectoriesInScope(Query<VirtualFile> dirs) {
|
|
||||||
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
|
|
||||||
@Override
|
|
||||||
protected boolean accept(VirtualFile file) {
|
|
||||||
return searchScope.accept(file);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
dirs.forEach(findProcessor);
|
|
||||||
return findProcessor.isFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NotNull
|
|
||||||
public PsiClass[] findClasses(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NotNull
|
|
||||||
public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NotNull
|
|
||||||
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@NotNull
|
|
||||||
public PsiClass[] getClasses(@Nullable String shortName, @NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean processPackageDirectories(@NotNull PsiPackage psiPackage,
|
|
||||||
@NotNull GlobalSearchScope scope,
|
|
||||||
@NotNull Processor<PsiDirectory> consumer,
|
|
||||||
boolean includeLibrarySources) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user