package org.dlangplugin.psi;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import org.dlangplugin.ide.index.DLangComponentIndex;
import org.dlangplugin.psi.impl.DLangClassDeclarationImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/* Some utils to search in PsiTree */
public class DLangResolveUtil {
@NotNull
public static String findModuleName(PsiFile psiFile) {
final DLangModuleDeclaration moduleStatement = PsiTreeUtil.getChildOfType(psiFile, DLangModuleDeclaration.class);
if(moduleStatement == null) return "";
return getModuleName(moduleStatement);
}
@NotNull
private static String getModuleName(DLangModuleDeclaration moduleStatement) {
final DLangModuleFullyQualifiedName packageStatement = PsiTreeUtil.getChildOfType(moduleStatement, DLangModuleFullyQualifiedName.class);
if(packageStatement==null) return "";
return packageStatement.getText();
}
@Nullable
public static DLangClassDeclarationImpl findClassDeclaration(PsiFile file, String name) {
final Collection<DLangClassDeclarationImpl> classes = PsiTreeUtil.findChildrenOfType(file, DLangClassDeclarationImpl.class);
for(DLangClassDeclarationImpl classDecl : classes) {
if(name.equals(classDecl.getName())) {
return classDecl;
}
}
return null;
}
@NotNull
public static List<DLangNamedComponent> findNamedSubComponents(@NotNull PsiElement... rootDLangClasses) {
return findNamedSubComponents(true, rootDLangClasses);
}
@NotNull
public static List<DLangNamedComponent> findNamedSubComponents(boolean unique, @NotNull PsiElement... rootDLangClasses) {
final List<DLangNamedComponent> unfilteredResult = new ArrayList<DLangNamedComponent>();
final LinkedList<PsiElement> classes = new LinkedList<PsiElement>();
classes.addAll(Arrays.asList(rootDLangClasses));
while (!classes.isEmpty()) {
final PsiElement dLangClass = classes.pollFirst();
for (DLangNamedComponent namedComponent : getNamedSubComponents(dLangClass)) {
if (namedComponent.getName() != null) {
unfilteredResult.add(namedComponent);
}
}
}
if (!unique) {
return unfilteredResult;
}
return new ArrayList<DLangNamedComponent>(namedElementToMap(unfilteredResult).values());
}
@NotNull
private static List<DLangNamedComponent> getNamedSubComponents(@NotNull PsiElement dLangClass) {
final List<DLangNamedComponent> unfilteredResult = new ArrayList<DLangNamedComponent>();
unfilteredResult.addAll(PsiTreeUtil.findChildrenOfType(dLangClass, DLangClassDeclaration.class));
return unfilteredResult;
}
public static Map<String, DLangNamedComponent> namedElementToMap(List<DLangNamedComponent> unfilteredResult) {
final Map<String, DLangNamedComponent> result = new HashMap<String, DLangNamedComponent>();
for (DLangNamedComponent namedComponent : unfilteredResult) {
// need order
if (result.containsKey(namedComponent.getName())) continue;
result.put(namedComponent.getName(), namedComponent);
}
return result;
}
public static DLangClass tryResolveClassByName(PsiElement classNameElement) {
if (classNameElement == null || classNameElement.getContext() == null) {
return null;
}
String name = classNameElement.getText();
return findClassByName(name, classNameElement.getContext());
}
@Nullable
public static DLangClass findClassByNameModule(DLangReference classNameElement, String moduleName) {
if (classNameElement == null || classNameElement.getContext() == null) {
return null;
}
final String className = classNameElement.getText();
final Project project = classNameElement.getProject();
final Module projectModule = ModuleUtilCore.findModuleForPsiElement(classNameElement);
final GlobalSearchScope scope = (projectModule == null) ?
GlobalSearchScope.allScope(project)
: GlobalSearchScope.moduleWithLibrariesScope(projectModule);
final List<DLangClassDeclaration> classFiles = DLangComponentIndex.getItemsByNameModule(className, moduleName, project, scope);
for(DLangClassDeclaration dLangClass : classFiles) {
DLangComponentName componentName = dLangClass.getComponentName();
if(componentName!=null && className.equals(componentName.getText())) {
return dLangClass;
}
}
return null;
}
@Nullable
public static DLangClass findClassByName(final @Nullable String qName, final @Nullable PsiElement context) {
if (context == null || qName == null) {
return null;
}
final Project project = context.getProject();
final GlobalSearchScope scope = GlobalSearchScope.fileScope(context.getContainingFile());
return findClassByName(qName, project, scope);
}
@Nullable
public static DLangClass findClassByName(String qName, Project project, GlobalSearchScope scope) {
final List<DLangClassDeclaration> classFiles = DLangComponentIndex.getItemsByName(qName, project, scope);
for(DLangClassDeclaration dLangClass : classFiles) {
DLangComponentName componentName = dLangClass.getComponentName();
if(componentName!=null && qName.equals(componentName.getText())) {
return dLangClass;
}
}
return null;
}
@NotNull
private static GlobalSearchScope getScopeForElement(PsiElement context) {
final Project project = context.getProject();
if (ApplicationManager.getApplication().isUnitTestMode()) {
return GlobalSearchScope.allScope(project);
}
final Module module = ModuleUtilCore.findModuleForPsiElement(context);
return module != null ? GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module) : GlobalSearchScope.allScope(project);
}
}