void (@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { final PsiElement position = parameters.getPosition(); final PyReferenceExpression refExpr = as(position.getParent(), PyReferenceExpression.class); if (refExpr == null || !refExpr.isQualified() || parameters.getCompletionType() != CompletionType.SMART) { return; } final TypeEvalContext typeEvalContext = TypeEvalContext.codeCompletion(refExpr.getProject(), parameters.getOriginalFile()); //noinspection ConstantConditions final PyStructuralType structType = as(typeEvalContext.getType(refExpr.getQualifier()), PyStructuralType.class); LOG.debug("Structural type: " + structType); if (structType != null) { final Set<String> names = Sets.newHashSet(structType.getAttributeNames()); // Remove "dummy" identifier from the set of attributes names.remove(refExpr.getReferencedName()); final Set<PyClass> suitableClasses = suggestClassesFromUsedAttributes(refExpr, names, typeEvalContext); LOG.debug("Result classes that contain attributes " + names + ": ", suitableClasses); for (PyClass pyClass : suitableClasses) { final PsiElement origPosition = parameters.getOriginalPosition(); final String prefix; if (origPosition != null && origPosition.getNode().getElementType() == PyTokenTypes.IDENTIFIER) { prefix = origPosition.getText(); } else { prefix = ""; } final Object[] variants = new PyClassTypeImpl(pyClass, false).getCompletionVariants(prefix, position, context); for (Object variant : variants) { if (variant instanceof LookupElement) { result.addElement((LookupElement)variant); } } } } }