package com.jetbrains.lang.dart.ide.index;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.indexing.FileContent;
import com.jetbrains.lang.dart.DartComponentType;
import com.jetbrains.lang.dart.psi.*;
import com.jetbrains.lang.dart.util.DartControlFlowUtil;
import com.jetbrains.lang.dart.util.DartResolveUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
import static com.jetbrains.lang.dart.ide.index.DartImportOrExportInfo.Kind;
public class DartIndexUtil {
// inc when change parser
public static final int INDEX_VERSION = 23;
private static final Key<DartFileIndexData> ourDartCachesData = Key.create("dart.caches.index.data");
public static DartFileIndexData indexFile(FileContent content) {
DartFileIndexData indexData = content.getUserData(ourDartCachesData);
if (indexData != null) return indexData;
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (content) {
indexData = content.getUserData(ourDartCachesData);
if (indexData != null) return indexData;
indexData = indexFileRoots(content.getPsiFile());
}
return indexData;
}
private static DartFileIndexData indexFileRoots(PsiFile psiFile) {
DartFileIndexData result = new DartFileIndexData();
result.setLibraryName(DartResolveUtil.getLibraryName(psiFile));
result.setIsPart(PsiTreeUtil.getChildOfType(psiFile, DartPartOfStatement.class) != null);
for (PsiElement rootElement : DartResolveUtil.findDartRoots(psiFile)) {
PsiElement[] children = rootElement.getChildren();
for (DartComponentName componentName : DartControlFlowUtil.getSimpleDeclarations(children, null, false)) {
final String name = componentName.getName();
if (name == null) {
continue;
}
result.addSymbol(name);
PsiElement parent = componentName.getParent();
final DartComponentType type = DartComponentType.typeOf(parent);
if (type != null) {
result.addComponentInfo(name, new DartComponentInfo(type, result.getLibraryName()));
}
if (parent instanceof DartClass) {
result.addClassName(name);
if (((DartClass)parent).isEnum()) {
for (DartEnumConstantDeclaration enumConstantDeclaration : ((DartClass)parent).getEnumConstantDeclarationList()) {
result.addSymbol(enumConstantDeclaration.getName());
}
}
else {
for (DartComponent subComponent : DartResolveUtil.getNamedSubComponents((DartClass)parent)) {
result.addSymbol(subComponent.getName());
}
}
}
}
for (PsiElement child : children) {
if (child instanceof DartImportOrExportStatement) {
processImportOrExportStatement(result, (DartImportOrExportStatement)child);
}
if (child instanceof DartPartStatement) {
result.addPartUri(((DartPartStatement)child).getUriString());
}
}
}
return result;
}
private static void processImportOrExportStatement(final @NotNull DartFileIndexData result,
final @NotNull DartImportOrExportStatement importOrExportStatement) {
final String uri = importOrExportStatement.getUriString();
final Set<String> showComponentNames = new THashSet<>();
for (DartShowCombinator showCombinator : importOrExportStatement.getShowCombinatorList()) {
final DartLibraryReferenceList libraryReferenceList = showCombinator.getLibraryReferenceList();
if (libraryReferenceList != null) {
for (DartExpression expression : libraryReferenceList.getLibraryComponentReferenceExpressionList()) {
showComponentNames.add(expression.getText());
}
}
}
final Set<String> hideComponentNames = new THashSet<>();
for (DartHideCombinator hideCombinator : importOrExportStatement.getHideCombinatorList()) {
final DartLibraryReferenceList libraryReferenceList = hideCombinator.getLibraryReferenceList();
if (libraryReferenceList != null) {
for (DartExpression expression : libraryReferenceList.getLibraryComponentReferenceExpressionList()) {
hideComponentNames.add(expression.getText());
}
}
}
final DartComponentName importPrefixComponent = importOrExportStatement instanceof DartImportStatement
? ((DartImportStatement)importOrExportStatement).getImportPrefix()
: null;
final String importPrefix = importPrefixComponent != null ? importPrefixComponent.getName() : null;
final Kind kind = importOrExportStatement instanceof DartImportStatement ? Kind.Import : Kind.Export;
result.addImportInfo(new DartImportOrExportInfo(kind, uri, importPrefix, showComponentNames, hideComponentNames));
result.addComponentInfo(importPrefix, new DartComponentInfo(DartComponentType.LABEL, null));
}
}