Property (@Nullable Processor<? super Property> filter) { // look at @property decorators final MultiMap<String, PyFunction> grouped = new MultiMap<>(); // group suitable same-named methods, each group defines a property for (PyFunction method : getMethods()) { grouped.putValue(method.getName(), method); } for (Map.Entry<String, Collection<PyFunction>> entry : grouped.entrySet()) { Maybe<PyCallable> getter = NONE; Maybe<PyCallable> setter = NONE; Maybe<PyCallable> deleter = NONE; final String decoratorName = entry.getKey(); for (PyFunction method : entry.getValue()) { final PyDecoratorList decoratorList = method.getDecoratorList(); if (decoratorList != null) { for (PyDecorator deco : decoratorList.getDecorators()) { final QualifiedName qname = deco.getQualifiedName(); if (qname != null) { String decoName = qname.toString(); for (PyKnownDecoratorProvider provider : PyKnownDecoratorProvider.EP_NAME.getExtensionList()) { final String knownName = provider.toKnownDecorator(decoName); if (knownName != null) { decoName = knownName; } } if (PyNames.PROPERTY.equals(decoName) || PyKnownDecoratorUtil.isPropertyDecorator(deco, TypeEvalContext.codeInsightFallback(getProject())) || qname.matches(decoratorName, PyNames.GETTER)) { getter = new Maybe<>(method); } else if (qname.matches(decoratorName, PyNames.SETTER)) { setter = new Maybe<>(method); } else if (qname.matches(decoratorName, PyNames.DELETER)) { deleter = new Maybe<>(method); } } } } if (getter != NONE && setter != NONE && deleter != NONE) break; // can't improve } if (getter != NONE || setter != NONE || deleter != NONE) { final PropertyImpl prop = new PropertyImpl(decoratorName, getter, setter, deleter, null, null); if (filter == null || filter.process(prop)) return prop; } } return null; }