void (@NotNull PyElement node, @NotNull final PsiReference reference, @NotNull HighlightSeverity severity) { if (reference instanceof DocStringTypeReference) { return; } String description = null; PsiElement element = reference.getElement(); final String text = element.getText(); TextRange rangeInElement = reference.getRangeInElement(); String refText = text; // text of the part we're working with if (rangeInElement.getStartOffset() >= 0 && rangeInElement.getEndOffset() > 0) { refText = rangeInElement.substring(text); } final String refName = (element instanceof PyQualifiedExpression) ? ((PyQualifiedExpression)element).getReferencedName() : refText; // Empty text, nothing to highlight if (StringUtil.isEmpty(refName)) { return; } final List<QualifiedName> qualifiedNames = getCanonicalNames(reference, myTypeEvalContext); for (QualifiedName name : qualifiedNames) { final String canonicalName = name.toString(); for (String ignored : myIgnoredIdentifiers) { if (ignored.endsWith(END_WILDCARD)) { final String prefix = ignored.substring(0, ignored.length() - END_WILDCARD.length()); if (canonicalName.startsWith(prefix)) { return; } } else if (canonicalName.equals(ignored)) { return; } } } // Legacy non-qualified ignore patterns if (myIgnoredIdentifiers.contains(refName)) { return; } List<LocalQuickFix> fixes = new ArrayList<>(); if (element instanceof PyReferenceExpression expr) { if (PyNames.COMPARISON_OPERATORS.contains(refName)) { return; } if (!expr.isQualified()) { if (PyInspectionsUtil.hasAnyInterruptedControlFlowPaths(expr)) { return; } ContainerUtil.addIfNotNull(fixes, getTrueFalseQuickFix(refText)); ContainerUtil.addAll(fixes, getAddSelfFixes(myTypeEvalContext, node, expr)); ContainerUtil.addIfNotNull(fixes, getCreateFunctionQuickFix(expr)); ContainerUtil.addIfNotNull(fixes, getAddParameterQuickFix(refName, expr)); fixes.add(new PyRenameUnresolvedRefQuickFix()); } // unqualified: // may be module's if (PyModuleType.getPossibleInstanceMembers().contains(refName)) { return; } // may be a "try: import ..."; not an error not to resolve if (( PsiTreeUtil.getParentOfType( PsiTreeUtil.getParentOfType(node, PyImportElement.class), PyTryExceptStatement.class, PyIfStatement.class ) != null )) { severity = HighlightSeverity.WEAK_WARNING; description = PyPsiBundle.message("INSP.unresolved.refs.module.not.found", refText); // TODO: mark the node so that future references pointing to it won't result in a error, but in a warning } } if (reference instanceof PsiReferenceEx && description == null) { description = ((PsiReferenceEx)reference).getUnresolvedDescription(); } if (description == null) { boolean markedQualified = false; if (element instanceof PyQualifiedExpression) { // TODO: Add __qualname__ for Python 3.3 to the skeleton of <class 'object'>, introduce a pseudo-class skeleton for // <class 'function'> if ("__qualname__".equals(refText) && !LanguageLevel.forElement(element).isPython2()) { return; } if (PyNames.COMPARISON_OPERATORS.contains(refName)) { return; } } final PyExpression qualifier = getReferenceQualifier(reference); if (qualifier != null) { final PyType type = myTypeEvalContext.getType(qualifier); if (type != null) { if (ignoreUnresolvedMemberForType(type, reference, refName) || isDeclaredInSlots(type, refName)) { return; } ContainerUtil.addAll(fixes, getCreateMemberFromUsageFixes(type, reference, refText)); if (type instanceof PyClassType classType) { if (reference instanceof PyOperatorReference) { String className = type.getName(); if (classType.isDefinition()) { final PyClassLikeType metaClassType = classType.getMetaClassType(myTypeEvalContext, true); if (metaClassType != null) { className = metaClassType.getName(); } } description = PyPsiBundle.message("INSP.unresolved.refs.class.does.not.define.operator", className, refName, ((PyOperatorReference)reference).getReadableOperatorName()); } else { description = PyPsiBundle.message("INSP.unresolved.refs.unresolved.attribute.for.class", refText, type.getName()); } } else { description = PyPsiBundle.message("INSP.unresolved.refs.cannot.find.reference.in.type", refText, type.getName()); } markedQualified = true; } } if (!markedQualified) { description = PyPsiBundle.message("INSP.unresolved.refs.unresolved.reference", refText); ContainerUtil.addAll(fixes, getAutoImportFixes(node, reference, element)); ContainerUtil.addIfNotNull(fixes, getCreateClassFix(refText, element)); } } ProblemHighlightType hl_type; if (severity == HighlightSeverity.WARNING) { hl_type = ProblemHighlightType.GENERIC_ERROR_OR_WARNING; } else if (severity == HighlightSeverity.ERROR) { hl_type = ProblemHighlightType.GENERIC_ERROR; } else { hl_type = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL; } ContainerUtil.addAll(fixes, getImportStatementQuickFixes(element)); ContainerUtil.addAll(fixes, getAddIgnoredIdentifierQuickFixes(qualifiedNames)); ContainerUtil.addAll(fixes, getInstallPackageQuickFixes(node, reference, refName)); if (reference instanceof PySubstitutionChunkReference) { return; } getPluginQuickFixes(fixes, reference); registerProblem(node, description, hl_type, null, rangeInElement, fixes.toArray(LocalQuickFix.EMPTY_ARRAY)); }