// Copyright 2014 Pants project contributors (see CONTRIBUTORS.md). // Licensed under the Apache License, Version 2.0 (see LICENSE). package com.twitter.intellij.pants.index; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiPolyVariantReference; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.indexing.*; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.KeyDescriptor; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyReferenceExpression; import com.twitter.intellij.pants.util.PantsPsiUtil; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; public class PantsTargetIndex extends ScalarIndexExtension<String> { public static final ID<String, Void> NAME = ID.create("PantsTargetIndex"); public static Collection<String> getTargets(@NotNull Project project) { return FileBasedIndex.getInstance().getAllKeys(NAME, project); } public static List<PsiElement> resolveTargetByName(@Nls String name, @NotNull Project project) { return resolveTargetByName(name, project, GlobalSearchScope.allScope(project)); } public static List<PsiElement> resolveTargetByName(@Nls String name, @NotNull Project project, GlobalSearchScope scope) { final PsiManager psiManager = PsiManager.getInstance(project); final ArrayList<PsiElement> result = new ArrayList<PsiElement>(); final Collection<VirtualFile> containingFiles = FileBasedIndex.getInstance().getContainingFiles(NAME, name, scope); for (VirtualFile virtualFile : containingFiles) { final PsiFile psiFile = psiManager.findFile(virtualFile); if (psiFile instanceof PyFile) { final PyReferenceExpression referenceExpression = PantsPsiUtil.findTargetDefinitions((PyFile)psiFile).get(name); final PsiPolyVariantReference reference = referenceExpression != null ? referenceExpression.getReference() : null; final PsiElement definition = reference != null ? reference.resolve() : null; if (definition != null) { result.add(definition); } else if (referenceExpression != null) { // at least something result.add(referenceExpression); } } } return result; } @NotNull @Override public ID<String, Void> getName() { return NAME; } @NotNull @Override public DataIndexer<String, Void, FileContent> getIndexer() { return myIndexer; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new DefaultFileTypeSpecificInputFilter(PythonFileType.INSTANCE); } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 0; } private static DataIndexer<String, Void, FileContent> myIndexer = new DataIndexer<String, Void, FileContent>() { @Override @NotNull public Map<String, Void> map(@NotNull final FileContent inputData) { final PsiFile psiFile = inputData.getPsiFile(); if (psiFile instanceof PyFile) { final Map<String, PyReferenceExpression> targetDefinitions = PantsPsiUtil.findTargetDefinitions((PyFile)psiFile); return ContainerUtil.newMapFromKeys( targetDefinitions.keySet().iterator(), new Convertor<String, Void>() { @Override public Void convert(String o) { return null; } } ); } return Collections.emptyMap(); } }; }