/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.lang.psi.impl;
import com.intellij.ProjectTopics;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootEvent;
import com.intellij.openapi.roots.ModuleRootListener;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ConcurrentWeakHashMap;
import com.intellij.util.containers.ContainerUtil;
import gw.plugin.ij.lang.psi.IGosuPsiElement;
import gw.plugin.ij.lang.psi.api.statements.typedef.IGosuTypeDefinition;
import gw.plugin.ij.lang.psi.stubs.GosuShortNamesCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class GosuPsiManager {
private static final Logger LOG = Logger.getInstance("gw.plugin.ij.lang.psi.impl.GosuPsiManager");
@NotNull
private final Project myProject;
private IGosuTypeDefinition myArrayClass;
private final ConcurrentWeakHashMap<IGosuPsiElement, PsiType> myCalculatedTypes = new ConcurrentWeakHashMap<>();
@Nullable
private final GosuShortNamesCache myCache;
private static final String SYNTHETIC_CLASS_TEXT = "class __ARRAY__ { public int length }";
public GosuPsiManager(@NotNull Project project) {
myProject = project;
myCache = ContainerUtil.findInstance(project.getExtensions(PsiShortNamesCache.EP_NAME), GosuShortNamesCache.class);
((PsiManagerEx) PsiManager.getInstance(myProject)).registerRunnableToRunOnAnyChange(new Runnable() {
public void run() {
dropTypesCache();
}
});
myProject.getMessageBus().connect().subscribe(ProjectTopics.PROJECT_ROOTS,
new ModuleRootListener() {
public void beforeRootsChange(ModuleRootEvent event) {
}
public void rootsChanged(ModuleRootEvent event) {
dropTypesCache();
}
});
}
public void dropTypesCache() {
myCalculatedTypes.clear();
}
public static GosuPsiManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, GosuPsiManager.class);
}
@Nullable
public <T extends IGosuPsiElement> PsiType getType(@NotNull T element, @NotNull Function<T, PsiType> calculator) {
PsiType type = myCalculatedTypes.get(element);
if (type == null) {
type = calculator.fun(element);
if (type == null) {
type = PsiType.NULL;
}
type = ConcurrencyUtil.cacheOrGet(myCalculatedTypes, element, type);
}
if (!type.isValid()) {
LOG.error("Type is invalid: " + type + "; element: " + element + " of class " + element.getClass());
}
return PsiType.NULL.equals(type) ? null : type;
}
}