package com.jetbrains.lang.dart.resolve;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.containers.Stack;
import com.jetbrains.lang.dart.ide.index.DartShowHideInfo;
import com.jetbrains.lang.dart.psi.DartComponentName;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
public abstract class DartPsiScopeProcessor implements PsiScopeProcessor {
private static final Logger LOG = Logger.getInstance(DartResolveProcessor.class.getName());
private final Stack<Pair<VirtualFile, DartShowHideInfo>> myShowHideFilters = new Stack<>();
private final Map<VirtualFile, Collection<PsiElement>> myFilteredOutElements = new THashMap<>();
public void importedFileProcessingStarted(final @NotNull VirtualFile importedFile, final @NotNull DartShowHideInfo showHideInfo) {
myShowHideFilters.push(Pair.create(importedFile, showHideInfo));
}
public void importedFileProcessingFinished(final @NotNull VirtualFile importedFile) {
LOG.assertTrue(!myShowHideFilters.isEmpty(), importedFile.getPath());
final Pair<VirtualFile, DartShowHideInfo> removed = myShowHideFilters.pop();
LOG.assertTrue(importedFile.equals(removed.first), "expected: " + removed.first.getPath() + ", actual: " + importedFile.getPath());
}
public void processFilteredOutElementsForImportedFile(final @NotNull VirtualFile importedFile) {
// removed now, but may be added again in execute();
final Collection<PsiElement> elements = myFilteredOutElements.remove(importedFile);
if (elements != null) {
for (PsiElement element : elements) {
execute(element, ResolveState.initial());
}
}
}
@Override
public final boolean execute(final @NotNull PsiElement element, final @NotNull ResolveState state) {
if (!(element instanceof DartComponentName)) return true;
final String name = ((DartComponentName)element).getName();
if (!myShowHideFilters.isEmpty() && StringUtil.startsWithChar(name, '_')) {
return true;
}
if (isFilteredOut(name)) {
final VirtualFile importedFile = myShowHideFilters.peek().first;
Collection<PsiElement> elements = myFilteredOutElements.get(importedFile);
if (elements == null) {
elements = new ArrayList<>();
myFilteredOutElements.put(importedFile, elements);
}
elements.add(element);
return true;
}
return doExecute((DartComponentName)element);
}
protected abstract boolean doExecute(final @NotNull DartComponentName dartComponentName);
@Override
public <T> T getHint(@NotNull Key<T> hintKey) {
return null;
}
@Override
public void handleEvent(@NotNull Event event, @Nullable Object associated) {
}
protected boolean isFilteredOut(final String name) {
for (Pair<VirtualFile, DartShowHideInfo> filter : myShowHideFilters) {
if (isFilteredOut(name, filter.second)) return true;
}
return false;
}
private static boolean isFilteredOut(final @Nullable String name, final @NotNull DartShowHideInfo showHideInfo) {
if (showHideInfo.getHideComponents().contains(name)) return true;
if (!showHideInfo.getShowComponents().isEmpty() && !showHideInfo.getShowComponents().contains(name)) return true;
return false;
}
}