mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Don't autocomplete magic and private names unless asked (PY-568).
This commit is contained in:
@@ -692,4 +692,16 @@ public class PyUtil {
|
||||
}
|
||||
else return target; // don't touch non-dirs
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts initial underscores of an identifier.
|
||||
* @param name identifier
|
||||
* @return 0 if no initial underscores found, 1 if there's only one underscore, 2 if there's two or more initial underscores.
|
||||
*/
|
||||
public static int getInitialUnderscores(String name) {
|
||||
int underscores=0;
|
||||
if (name.startsWith("__")) underscores = 2;
|
||||
else if (name.startsWith("_")) underscores = 1;
|
||||
return underscores;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
package com.jetbrains.python.psi.impl;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiDirectory;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.jetbrains.python.psi.PyExpression;
|
||||
import com.jetbrains.python.psi.PyUtil;
|
||||
import com.jetbrains.python.psi.RatedResolveResult;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveUtil;
|
||||
import com.jetbrains.python.psi.resolve.ResolveImportUtil;
|
||||
import com.jetbrains.python.psi.resolve.SdkRootVisitor;
|
||||
import com.jetbrains.python.psi.resolve.VariantsProcessor;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -51,7 +63,149 @@ public class PyImportReferenceImpl extends PyReferenceImpl {
|
||||
}
|
||||
else {
|
||||
// complete to possible modules
|
||||
return ResolveImportUtil.suggestImportVariants(myElement);
|
||||
List<Object> variants = new ArrayList<Object>();
|
||||
PsiFile current_file = myElement.getContainingFile();
|
||||
if (current_file != null) current_file = current_file.getOriginalFile();
|
||||
int relative_level = 0;
|
||||
final Set<String> names_already = new HashSet<String>(); // don't propose already imported names
|
||||
String ref_name = myElement.getName();
|
||||
Condition<PsiElement> node_filter = new PyResolveUtil.FilterNameNotIn(names_already);
|
||||
Condition<String> underscore_filter = new UnderscoreFilter(PyUtil.getInitialUnderscores(ref_name));
|
||||
// are we in "import _" or "from foo import _"?
|
||||
PyFromImportStatement from_import = PsiTreeUtil.getParentOfType(myElement, PyFromImportStatement.class);
|
||||
if (from_import != null && myElement.getParent() != from_import) { // in "from foo import _"
|
||||
PyReferenceExpression src = from_import.getImportSource();
|
||||
if (src != null) {
|
||||
PsiElement mod_candidate = src.getReference().resolve();
|
||||
if (mod_candidate instanceof PyExpression) {
|
||||
addImportedNames(from_import.getImportElements(), names_already, underscore_filter); // don't propose already imported items
|
||||
// collect what's within module file
|
||||
final VariantsProcessor processor = new VariantsProcessor(myElement, node_filter, underscore_filter);
|
||||
PyResolveUtil.treeCrawlUp(processor, true, mod_candidate);
|
||||
variants.addAll(processor.getResultList());
|
||||
// try to collect submodules
|
||||
PyExpression module = (PyExpression)mod_candidate;
|
||||
PyType qualifierType = module.getType();
|
||||
if (qualifierType != null) {
|
||||
ProcessingContext ctx = new ProcessingContext();
|
||||
for (Object ex : variants) { // just in case: file's definitions shadow submodules
|
||||
if (ex instanceof PyReferenceExpression) {
|
||||
names_already.add(((PyReferenceExpression)ex).getReferencedName());
|
||||
}
|
||||
}
|
||||
// collect submodules
|
||||
ctx.put(PyType.CTX_NAMES, names_already);
|
||||
Collections.addAll(variants, qualifierType.getCompletionVariants(myElement, ctx));
|
||||
}
|
||||
return variants.toArray();
|
||||
}
|
||||
}
|
||||
else { // null source, must be a "from ... import"
|
||||
relative_level = from_import.getRelativeLevel();
|
||||
if (relative_level > 0) {
|
||||
PsiDirectory relative_dir = ResolveImportUtil.stepBackFrom(current_file, relative_level);
|
||||
if (relative_dir != null) {
|
||||
addImportedNames(from_import.getImportElements(), names_already, underscore_filter);
|
||||
fillFromDir(relative_dir, current_file, underscore_filter, variants);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// in "import _" or "from _ import"
|
||||
if (from_import != null) addImportedNames(from_import.getImportElements(), names_already, underscore_filter);
|
||||
else {
|
||||
names_already.add(PyNames.FUTURE_MODULE); // never add it to "import ..."
|
||||
PyImportStatement import_stmt = PsiTreeUtil.getParentOfType(myElement, PyImportStatement.class);
|
||||
if (import_stmt != null) {
|
||||
addImportedNames(import_stmt.getImportElements(), names_already, underscore_filter);
|
||||
}
|
||||
}
|
||||
// look at current dir
|
||||
if (current_file != null && relative_level == 0 && ! ResolveImportUtil.isAbsoluteImportEnabledFor(current_file)) {
|
||||
fillFromDir(current_file.getParent(), current_file, underscore_filter, variants);
|
||||
}
|
||||
if (relative_level == 0) {
|
||||
// look in SDK
|
||||
final CollectingRootVisitor visitor = new CollectingRootVisitor(((PyReferenceExpression)myElement).getManager());
|
||||
final Module module = ModuleUtil.findModuleForPsiElement(myElement);
|
||||
if (module != null) {
|
||||
ModuleRootManager.getInstance(module).processOrder(new ResolveImportUtil.SdkRootVisitingPolicy(visitor), null);
|
||||
for (String name : visitor.getResult()) {
|
||||
if (PyNames.isIdentifier(name) && underscore_filter.value(name)) variants.add(name); // to thwart stuff like "__phello__.foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayUtil.toObjectArray(variants);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addImportedNames(PyImportElement[] import_elts, Collection<String> collected_names, Condition<String> filter) {
|
||||
if (import_elts != null && collected_names != null) {
|
||||
for (PyImportElement ielt : import_elts) {
|
||||
String s;
|
||||
PyReferenceExpression ref = ielt.getImportReference();
|
||||
if (ref != null) {
|
||||
s = ref.getReferencedName();
|
||||
if (s != null && filter.value(s)) collected_names.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adds variants found under given dir
|
||||
private static void fillFromDir(PsiDirectory target_dir, PsiFile source_file, Condition<String> filter, List<Object> variants) {
|
||||
if (target_dir != null) {
|
||||
for (PsiElement dir_item : target_dir.getChildren()) {
|
||||
if (dir_item != source_file) {
|
||||
if (dir_item instanceof PsiDirectory) {
|
||||
final PsiDirectory dir = (PsiDirectory)dir_item;
|
||||
if (dir.findFile(PyNames.INIT_DOT_PY) != null) {
|
||||
final String name = dir.getName();
|
||||
if (PyNames.isIdentifier(name) && filter.value(name)) variants.add(name);
|
||||
}
|
||||
}
|
||||
else if (dir_item instanceof PsiFile) { // plain file
|
||||
String filename = ((PsiFile)dir_item).getName();
|
||||
if (!PyNames.INIT_DOT_PY.equals(filename) && filename.endsWith(PyNames.DOT_PY)) {
|
||||
final String name = filename.substring(0, filename.length() - PyNames.DOT_PY.length());
|
||||
if (PyNames.isIdentifier(name) && filter.value(name)) variants.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CollectingRootVisitor implements SdkRootVisitor {
|
||||
Set<String> result;
|
||||
PsiManager psimgr;
|
||||
|
||||
static String cutExt(String name) {
|
||||
return name.substring(0, Math.max(name.length() - PyNames.DOT_PY.length(), 0));
|
||||
}
|
||||
|
||||
public CollectingRootVisitor(PsiManager psimgr) {
|
||||
result = new com.intellij.util.containers.HashSet<String>();
|
||||
this.psimgr = psimgr;
|
||||
}
|
||||
|
||||
public boolean visitRoot(final VirtualFile root) {
|
||||
for (VirtualFile vfile : root.getChildren()) {
|
||||
if (vfile.getName().endsWith(PyNames.DOT_PY)) {
|
||||
PsiFile pfile = psimgr.findFile(vfile);
|
||||
if (pfile != null) result.add(cutExt(pfile.getName()));
|
||||
}
|
||||
else if (vfile.isDirectory() && (vfile.findChild(PyNames.INIT_DOT_PY) != null)) {
|
||||
PsiDirectory pdir = psimgr.findDirectory(vfile);
|
||||
if (pdir != null) result.add(pdir.getName());
|
||||
}
|
||||
}
|
||||
return true; // continue forever
|
||||
}
|
||||
|
||||
public Collection<String> getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +284,9 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
final PsiElement realContext = PyPsiUtils.getRealContext(myElement);
|
||||
|
||||
// include our own names
|
||||
final VariantsProcessor processor = new VariantsProcessor(myElement);
|
||||
final int underscores = PyUtil.getInitialUnderscores(myElement.getName());
|
||||
final UnderscoreFilter filter = new UnderscoreFilter(underscores);
|
||||
final VariantsProcessor processor = new VariantsProcessor(myElement, null, filter);
|
||||
PyResolveUtil.treeCrawlUp(processor, realContext); // names from here
|
||||
PyResolveUtil.scanOuterContext(processor, realContext); // possible names from around us at call time
|
||||
|
||||
@@ -315,7 +317,8 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
if (from_import_stmt != null) {
|
||||
final PyReferenceExpression import_src = from_import_stmt.getImportSource();
|
||||
if (import_src != null) {
|
||||
processor.setNotice(import_src.getName());
|
||||
final String imported_name = import_src.getName();
|
||||
processor.setNotice(imported_name);
|
||||
PyResolveUtil.treeCrawlUp(processor, true, import_src.getReference().resolve()); // names from that module
|
||||
}
|
||||
}
|
||||
@@ -324,11 +327,13 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
processor.setNotice("__builtin__");
|
||||
PyResolveUtil.treeCrawlUp(processor, true, PyBuiltinCache.getInstance(getElement()).getBuiltinsFile()); // names from __builtin__
|
||||
|
||||
// if we're a normal module, add module's attrs
|
||||
PsiFile f = realContext.getContainingFile();
|
||||
if (f instanceof PyFile) {
|
||||
for (String name : PyModuleType.getPossibleInstanceMembers()) {
|
||||
ret.add(LookupElementBuilder.create(name).setIcon(Icons.FIELD_ICON));
|
||||
if (underscores >= 2) {
|
||||
// if we're a normal module, add module's attrs
|
||||
PsiFile f = realContext.getContainingFile();
|
||||
if (f instanceof PyFile) {
|
||||
for (String name : PyModuleType.getPossibleInstanceMembers()) {
|
||||
ret.add(LookupElementBuilder.create(name).setIcon(Icons.FIELD_ICON));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,4 +424,24 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
|
||||
public int hashCode() {
|
||||
return myElement.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical conjunction.
|
||||
*/
|
||||
protected static class UnderscoreFilter implements Condition<String> {
|
||||
private int myAllowed; // how many starting underscores is allowed: 0 is none, 1 is only one, 2 is two and more.
|
||||
|
||||
public UnderscoreFilter(int allowed) {
|
||||
myAllowed = allowed;
|
||||
}
|
||||
|
||||
public boolean value(String name) {
|
||||
if (name == null) return false;
|
||||
if (name.length() < 1) return false; // empty strings make no sense
|
||||
int have_underscores = 0;
|
||||
if (name.charAt(0) == '_') have_underscores = 1;
|
||||
if (have_underscores != 0 && name.length() > 1 && name.charAt(1) == '_') have_underscores = 2;
|
||||
return myAllowed >= have_underscores;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,29 +294,30 @@ public class PyResolveUtil {
|
||||
/**
|
||||
* Accepts only targets that are not the given object.
|
||||
*/
|
||||
public static class FilterNotInstance implements Condition<Object> {
|
||||
public static class FilterNotInstance implements Condition<PsiElement> {
|
||||
Object instance;
|
||||
|
||||
public FilterNotInstance(Object instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public boolean value(final Object target) {
|
||||
public boolean value(final PsiElement target) {
|
||||
return (instance != target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts only names not contained in a given collection.
|
||||
*/
|
||||
public static class FilterNameNotIn implements Condition<Object> {
|
||||
public static class FilterNameNotIn implements Condition<PsiElement> {
|
||||
private final Collection<String> myNames;
|
||||
|
||||
public FilterNameNotIn(Collection<String> names) {
|
||||
myNames = names;
|
||||
}
|
||||
|
||||
public boolean value(Object target) {
|
||||
public boolean value(PsiElement target) {
|
||||
if (target instanceof PsiNamedElement) {
|
||||
return !myNames.contains(((PsiNamedElement)target).getName());
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ResolveImportUtil {
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean isAbsoluteImportEnabledFor(PsiElement foothold) {
|
||||
public static boolean isAbsoluteImportEnabledFor(PsiElement foothold) {
|
||||
if (foothold != null) {
|
||||
PsiFile file = foothold.getContainingFile();
|
||||
if (file instanceof PyFile) {
|
||||
@@ -71,7 +71,7 @@ public class ResolveImportUtil {
|
||||
* @return found directory, or null.
|
||||
*/
|
||||
@Nullable
|
||||
private static PsiDirectory stepBackFrom(PsiFile base, int depth) {
|
||||
public static PsiDirectory stepBackFrom(PsiFile base, int depth) {
|
||||
PsiDirectory result;
|
||||
if (base != null) {
|
||||
base = base.getOriginalFile(); // just to make sure
|
||||
@@ -540,37 +540,6 @@ public class ResolveImportUtil {
|
||||
}
|
||||
}
|
||||
|
||||
static class CollectingRootVisitor implements SdkRootVisitor {
|
||||
Set<String> result;
|
||||
PsiManager psimgr;
|
||||
|
||||
static String cutExt(String name) {
|
||||
return name.substring(0, Math.max(name.length() - PyNames.DOT_PY.length(), 0));
|
||||
}
|
||||
|
||||
public CollectingRootVisitor(PsiManager psimgr) {
|
||||
result = new HashSet<String>();
|
||||
this.psimgr = psimgr;
|
||||
}
|
||||
|
||||
public boolean visitRoot(final VirtualFile root) {
|
||||
for (VirtualFile vfile : root.getChildren()) {
|
||||
if (vfile.getName().endsWith(PyNames.DOT_PY)) {
|
||||
PsiFile pfile = psimgr.findFile(vfile);
|
||||
if (pfile != null) result.add(cutExt(pfile.getName()));
|
||||
}
|
||||
else if (vfile.isDirectory() && (vfile.findChild(PyNames.INIT_DOT_PY) != null)) {
|
||||
PsiDirectory pdir = psimgr.findDirectory(vfile);
|
||||
if (pdir != null) result.add(pdir.getName());
|
||||
}
|
||||
}
|
||||
return true; // continue forever
|
||||
}
|
||||
|
||||
public Collection<String> getResult() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Tries to find referencedName under the parent element. Used to resolve any names that look imported.
|
||||
@@ -645,163 +614,6 @@ public class ResolveImportUtil {
|
||||
}
|
||||
|
||||
|
||||
private static void addImportedNames(PyImportElement[] import_elts, Collection<String> collected_names, Condition<Object> filter) {
|
||||
if (import_elts != null && collected_names != null) {
|
||||
for (PyImportElement ielt : import_elts) {
|
||||
String s;
|
||||
PyReferenceExpression ref = ielt.getImportReference();
|
||||
if (ref != null) {
|
||||
s = ref.getReferencedName();
|
||||
if (s != null && filter.value(s)) collected_names.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logical conjunction.
|
||||
*/
|
||||
static class And<T> implements Condition<T> {
|
||||
private Condition<T> myOne;
|
||||
private Condition<T> myTwo;
|
||||
|
||||
public And(Condition<T> one, Condition<T> two) {
|
||||
myOne = one;
|
||||
myTwo = two;
|
||||
}
|
||||
|
||||
public boolean value(T t) {
|
||||
return myOne.value(t) && myTwo.value(t);
|
||||
}
|
||||
}
|
||||
|
||||
static class UnderscoreFilter implements Condition<Object> {
|
||||
private int myAllowed; // how many starting underscores is allowed: 0 is none, 1 is only one, 2 is two and more.
|
||||
|
||||
public UnderscoreFilter(int allowed) {
|
||||
myAllowed = allowed;
|
||||
}
|
||||
|
||||
public boolean value(Object o) {
|
||||
if (o == null) return false;
|
||||
String name = o.toString();
|
||||
if (name.length() < 1) return false; // empty strings make no sense
|
||||
int have_underscores = 0;
|
||||
if (name.charAt(0) == '_') have_underscores = 1;
|
||||
if (have_underscores != 0 && name.length() > 1 && name.charAt(1) == '_') have_underscores = 2;
|
||||
return myAllowed >= have_underscores;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds reasonable names to import to complete a patrial name.
|
||||
* @param partial_ref reference containing the partial name.
|
||||
* @return an array of names ready for getVariants().
|
||||
*/
|
||||
public static Object[] suggestImportVariants(final PyReferenceExpression partial_ref) {
|
||||
List<Object> variants = new ArrayList<Object>();
|
||||
if (partial_ref == null) return variants.toArray();
|
||||
PsiFile current_file = partial_ref.getContainingFile();
|
||||
if (current_file != null) current_file = current_file.getOriginalFile();
|
||||
int relative_level = 0;
|
||||
final Set<String> names_already = new java.util.HashSet<String>(); // don't propose already imported names
|
||||
int underscores=0; // the number of underscores we're interested in
|
||||
String ref_name = partial_ref.getName();
|
||||
if (ref_name.startsWith("__")) underscores = 2;
|
||||
else if (ref_name.startsWith("_")) underscores = 1;
|
||||
final And<Object> filter = new And<Object>(new PyResolveUtil.FilterNameNotIn(names_already), new UnderscoreFilter(underscores));
|
||||
// are we in "import _" or "from foo import _"?
|
||||
PyFromImportStatement from_import = PsiTreeUtil.getParentOfType(partial_ref, PyFromImportStatement.class);
|
||||
if (from_import != null && partial_ref.getParent() != from_import) { // in "from foo import _"
|
||||
PyReferenceExpression src = from_import.getImportSource();
|
||||
if (src != null) {
|
||||
PsiElement mod_candidate = src.getReference().resolve();
|
||||
if (mod_candidate instanceof PyExpression) {
|
||||
addImportedNames(from_import.getImportElements(), names_already, filter); // don't propose already imported items
|
||||
// collect what's within module file
|
||||
final VariantsProcessor processor = new VariantsProcessor(partial_ref, filter
|
||||
);
|
||||
PyResolveUtil.treeCrawlUp(processor, true, mod_candidate);
|
||||
variants.addAll(processor.getResultList());
|
||||
// try to collect submodules
|
||||
PyExpression module = (PyExpression)mod_candidate;
|
||||
PyType qualifierType = module.getType();
|
||||
if (qualifierType != null) {
|
||||
ProcessingContext ctx = new ProcessingContext();
|
||||
for (Object ex : variants) { // just in case: file's definitions shadow submodules
|
||||
if (ex instanceof PyReferenceExpression) {
|
||||
names_already.add(((PyReferenceExpression)ex).getReferencedName());
|
||||
}
|
||||
}
|
||||
// collect submodules
|
||||
ctx.put(PyType.CTX_NAMES, names_already);
|
||||
Collections.addAll(variants, qualifierType.getCompletionVariants(partial_ref, ctx));
|
||||
}
|
||||
return variants.toArray();
|
||||
}
|
||||
}
|
||||
else { // null source, must be a "from ... import"
|
||||
relative_level = from_import.getRelativeLevel();
|
||||
if (relative_level > 0) {
|
||||
PsiDirectory relative_dir = stepBackFrom(current_file, relative_level);
|
||||
if (relative_dir != null) {
|
||||
addImportedNames(from_import.getImportElements(), names_already, filter);
|
||||
fillFromDir(relative_dir, current_file, filter, variants);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// in "import _" or "from _ import"
|
||||
if (from_import != null) addImportedNames(from_import.getImportElements(), names_already, filter);
|
||||
else {
|
||||
names_already.add(PyNames.FUTURE_MODULE); // never add it to "import ..."
|
||||
PyImportStatement import_stmt = PsiTreeUtil.getParentOfType(partial_ref, PyImportStatement.class);
|
||||
if (import_stmt != null) {
|
||||
addImportedNames(import_stmt.getImportElements(), names_already, filter);
|
||||
}
|
||||
}
|
||||
// look at current dir
|
||||
if (current_file != null && relative_level == 0 && ! isAbsoluteImportEnabledFor(current_file)) {
|
||||
fillFromDir(current_file.getParent(), current_file, filter, variants);
|
||||
}
|
||||
if (relative_level == 0) {
|
||||
// look in SDK
|
||||
final CollectingRootVisitor visitor = new CollectingRootVisitor(partial_ref.getManager());
|
||||
final Module module = ModuleUtil.findModuleForPsiElement(partial_ref);
|
||||
if (module != null) {
|
||||
ModuleRootManager.getInstance(module).processOrder(new SdkRootVisitingPolicy(visitor), null);
|
||||
for (String name : visitor.getResult()) {
|
||||
if (PyNames.isIdentifier(name) && filter.value(name)) variants.add(name); // to thwart stuff like "__phello__.foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ArrayUtil.toObjectArray(variants);
|
||||
}
|
||||
|
||||
// adds variants found under given dir
|
||||
private static void fillFromDir(PsiDirectory target_dir, PsiFile source_file, Condition<Object> filter, List<Object> variants) {
|
||||
if (target_dir != null) {
|
||||
for (PsiElement dir_item : target_dir.getChildren()) {
|
||||
if (dir_item != source_file) {
|
||||
if (dir_item instanceof PsiDirectory) {
|
||||
final PsiDirectory dir = (PsiDirectory)dir_item;
|
||||
if (dir.findFile(PyNames.INIT_DOT_PY) != null) {
|
||||
final String name = dir.getName();
|
||||
if (PyNames.isIdentifier(name) && filter.value(name)) variants.add(name);
|
||||
}
|
||||
}
|
||||
else if (dir_item instanceof PsiFile) { // plain file
|
||||
String filename = ((PsiFile)dir_item).getName();
|
||||
if (!PyNames.INIT_DOT_PY.equals(filename) && filename.endsWith(PyNames.DOT_PY)) {
|
||||
final String name = filename.substring(0, filename.length() - PyNames.DOT_PY.length());
|
||||
if (PyNames.isIdentifier(name) && filter.value(name)) variants.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find roots that contain given vfile, and among them the root that contains at the smallest depth.
|
||||
@@ -859,7 +671,7 @@ public class ResolveImportUtil {
|
||||
}
|
||||
|
||||
|
||||
private static class SdkRootVisitingPolicy extends RootPolicy<PsiElement> {
|
||||
public static class SdkRootVisitingPolicy extends RootPolicy<PsiElement> {
|
||||
private final SdkRootVisitor myVisitor;
|
||||
|
||||
public SdkRootVisitingPolicy(SdkRootVisitor visitor) {
|
||||
|
||||
@@ -21,16 +21,23 @@ public class VariantsProcessor implements PsiScopeProcessor {
|
||||
|
||||
protected final PsiElement myContext;
|
||||
protected String myNotice;
|
||||
protected Condition<Object> myFilter;
|
||||
protected Condition<PsiElement> myNodeFilter;
|
||||
protected Condition<String> myNameFilter;
|
||||
|
||||
public VariantsProcessor(PsiElement context) {
|
||||
// empty
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
public VariantsProcessor(PsiElement context, final Condition<Object> filter) {
|
||||
public VariantsProcessor(PsiElement context, final Condition<PsiElement> nodefilter) {
|
||||
myContext = context;
|
||||
myFilter = filter;
|
||||
myNodeFilter = nodefilter;
|
||||
}
|
||||
|
||||
public VariantsProcessor(PsiElement context, final Condition<PsiElement> nodefilter, final Condition<String> namefilter) {
|
||||
myContext = context;
|
||||
myNodeFilter = nodefilter;
|
||||
myNameFilter = namefilter;
|
||||
}
|
||||
|
||||
public void setNotice(@Nullable String notice) {
|
||||
@@ -61,19 +68,19 @@ public class VariantsProcessor implements PsiScopeProcessor {
|
||||
}
|
||||
|
||||
public boolean execute(PsiElement element, ResolveState substitutor) {
|
||||
if (myFilter != null && !myFilter.value(element)) return true; // skip whatever the filter rejects
|
||||
if (myNodeFilter != null && !myNodeFilter.value(element)) return true; // skip whatever the filter rejects
|
||||
// TODO: refactor to look saner; much code duplication
|
||||
if (element instanceof PsiNamedElement) {
|
||||
final PsiNamedElement psiNamedElement = (PsiNamedElement)element;
|
||||
final String name = psiNamedElement.getName();
|
||||
if (name != null && !myVariants.containsKey(name)) {
|
||||
if (name != null && !myVariants.containsKey(name) && myNameFilter != null && myNameFilter.value(name)) {
|
||||
myVariants.put(name, setupItem(LookupElementBuilder.create(psiNamedElement).setIcon(element.getIcon(0))));
|
||||
}
|
||||
}
|
||||
else if (element instanceof PyReferenceExpression) {
|
||||
PyReferenceExpression expr = (PyReferenceExpression)element;
|
||||
String referencedName = expr.getReferencedName();
|
||||
if (referencedName != null && !myVariants.containsKey(referencedName)) {
|
||||
if (referencedName != null && !myVariants.containsKey(referencedName) && myNameFilter != null && myNameFilter.value(referencedName)) {
|
||||
myVariants.put(referencedName, setupItem(LookupElementBuilder.create(referencedName)));
|
||||
}
|
||||
}
|
||||
@@ -85,7 +92,7 @@ public class VariantsProcessor implements PsiScopeProcessor {
|
||||
Icon icon = element.getIcon(0);
|
||||
// things like PyTargetExpression cannot have a general icon, but here we only have variables
|
||||
if (icon == null) icon = Icons.VARIABLE_ICON;
|
||||
if (referencedName != null && !myVariants.containsKey(referencedName)) {
|
||||
if (referencedName != null && !myVariants.containsKey(referencedName) && myNameFilter != null && myNameFilter.value(referencedName)) {
|
||||
LookupElementBuilder lookup_item = setupItem(LookupElementBuilder.create(referencedName).setIcon(icon));
|
||||
if (definer instanceof PyImportElement) { // set notice to imported module name if needed
|
||||
PsiElement maybe_from_import = definer.getParent();
|
||||
|
||||
Reference in New Issue
Block a user