From 97873ffa69d98d89f1f668ea25307b268a84e207 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Thu, 8 Apr 2010 18:14:49 +0300 Subject: [PATCH] Don't autocomplete magic and private names unless asked (PY-568). --- .../src/com/jetbrains/python/psi/PyUtil.java | 12 ++ .../psi/impl/PyImportReferenceImpl.java | 164 ++++++++++++++- .../python/psi/impl/PyReferenceImpl.java | 39 +++- .../python/psi/resolve/PyResolveUtil.java | 9 +- .../python/psi/resolve/ResolveImportUtil.java | 194 +----------------- .../python/psi/resolve/VariantsProcessor.java | 21 +- 6 files changed, 225 insertions(+), 214 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 5c78f80e258d..e9e18e77ff07 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -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; + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java index 4ff871b5a256..0164218c6451 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java @@ -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 variants = new ArrayList(); + PsiFile current_file = myElement.getContainingFile(); + if (current_file != null) current_file = current_file.getOriginalFile(); + int relative_level = 0; + final Set names_already = new HashSet(); // don't propose already imported names + String ref_name = myElement.getName(); + Condition node_filter = new PyResolveUtil.FilterNameNotIn(names_already); + Condition 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 collected_names, Condition 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 filter, List 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 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(); + 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 getResult() { + return result; } } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java index 9f9245b08b34..8e912c3fa26a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceImpl.java @@ -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 { + 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; + } + } } diff --git a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java index 72421eedff6c..d31f569bcf9e 100644 --- a/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java @@ -294,29 +294,30 @@ public class PyResolveUtil { /** * Accepts only targets that are not the given object. */ - public static class FilterNotInstance implements Condition { + public static class FilterNotInstance implements Condition { 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 { + public static class FilterNameNotIn implements Condition { private final Collection myNames; public FilterNameNotIn(Collection names) { myNames = names; } - public boolean value(Object target) { + public boolean value(PsiElement target) { if (target instanceof PsiNamedElement) { return !myNames.contains(((PsiNamedElement)target).getName()); } diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 093d1babc355..f95aaca727c3 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -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 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(); - 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 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 collected_names, Condition 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 implements Condition { - private Condition myOne; - private Condition myTwo; - - public And(Condition one, Condition two) { - myOne = one; - myTwo = two; - } - - public boolean value(T t) { - return myOne.value(t) && myTwo.value(t); - } - } - - static class UnderscoreFilter implements Condition { - 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 variants = new ArrayList(); - 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 names_already = new java.util.HashSet(); // 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 filter = new And(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 filter, List 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 { + public static class SdkRootVisitingPolicy extends RootPolicy { private final SdkRootVisitor myVisitor; public SdkRootVisitingPolicy(SdkRootVisitor visitor) { diff --git a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java index 5ab6c87de5ad..3d63032ce916 100644 --- a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java @@ -21,16 +21,23 @@ public class VariantsProcessor implements PsiScopeProcessor { protected final PsiElement myContext; protected String myNotice; - protected Condition myFilter; + protected Condition myNodeFilter; + protected Condition myNameFilter; public VariantsProcessor(PsiElement context) { // empty myContext = context; } - public VariantsProcessor(PsiElement context, final Condition filter) { + public VariantsProcessor(PsiElement context, final Condition nodefilter) { myContext = context; - myFilter = filter; + myNodeFilter = nodefilter; + } + + public VariantsProcessor(PsiElement context, final Condition nodefilter, final Condition 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();