boolean (PsiClass patternClass, PsiClass matchClass) { final PsiClass saveClazz = myClazz; myClazz = matchClass; final MatchContext context = myMatchingVisitor.getMatchContext(); final JavaCompiledPattern javaPattern = (JavaCompiledPattern)context.getPattern(); final Set<PsiElement> matchedElements = new HashSet<>(); context.pushMatchedElementsListener(elements -> matchedElements.addAll(elements)); try { final boolean templateIsInterface = patternClass.isInterface(); if (templateIsInterface && !matchClass.isInterface()) return false; if (templateIsInterface && patternClass.isAnnotationType() && !matchClass.isAnnotationType()) return false; if (patternClass.isEnum() && !matchClass.isEnum()) return false; if (patternClass instanceof PsiTypeParameter != matchClass instanceof PsiTypeParameter) return false; if (patternClass.isRecord() && !matchClass.isRecord()) return false; if (!myMatchingVisitor.match(patternClass.getRecordHeader(), matchClass.getRecordHeader())) { return false; } if (!matchInAnyOrder(patternClass.getExtendsList(), matchClass.getExtendsList())) { return false; } // check if implements is in extended classes implements final PsiReferenceList implementsList = patternClass.getImplementsList(); if (implementsList != null) { if (implementsList.getFirstChild() != null && matchClass.isInterface()) return false; final List<PsiJavaCodeReferenceElement> elements = new SmartList<>(); for (PsiJavaCodeReferenceElement element : implementsList.getReferenceElements()) { final MatchingHandler handler = javaPattern.getHandler(element); if (handler instanceof SubstitutionHandler substitutionHandler && (substitutionHandler.isSubtype() || substitutionHandler.isStrictSubtype())) { if (!matchWithinHierarchy(element, matchClass, substitutionHandler)) { return false; } continue; } elements.add(element); } if (!elements.isEmpty()) { final PsiReferenceList implementsList2 = matchClass.getImplementsList(); final PsiElement[] matchElements = (implementsList2 == null) ? PsiElement.EMPTY_ARRAY : implementsList2.getReferenceElements(); if (!myMatchingVisitor.matchInAnyOrder(elements.toArray(PsiElement.EMPTY_ARRAY), matchElements)) { return false; } } } final PsiField[] fields = PsiTreeUtil.getChildrenOfType(patternClass, PsiField.class); if (fields != null) { final PsiField[] fields2 = javaPattern.isRequestsSuperFields() ? matchClass.getAllFields() : matchClass.getFields(); if (!myMatchingVisitor.matchInAnyOrder(fields, fields2)) { return false; } } final PsiMethod[] methods = PsiTreeUtil.getChildrenOfType(patternClass, PsiMethod.class); if (methods != null) { final PsiMethod[] methods2 = javaPattern.isRequestsSuperMethods() ? matchClass.getAllMethods() : matchClass.getMethods(); if (!myMatchingVisitor.matchInAnyOrder(methods, methods2)) { return false; } } final PsiClass[] nestedClasses = PsiTreeUtil.getChildrenOfType(patternClass, PsiClass.class); if (nestedClasses != null) { final PsiClass[] nestedClasses2 = javaPattern.isRequestsSuperInners() ? matchClass.getAllInnerClasses() : matchClass.getInnerClasses(); if (!myMatchingVisitor.matchInAnyOrder(nestedClasses, nestedClasses2)) { return false; } } final PsiClassInitializer[] initializers = patternClass.getInitializers(); if (initializers.length > 0) { final PsiClassInitializer[] initializers2 = matchClass.getInitializers(); if (!myMatchingVisitor.matchInAnyOrder(initializers, initializers2)) { return false; } } final List<PsiElement> unmatchedElements = new SmartList<>(PsiTreeUtil.getChildrenOfTypeAsList(matchClass, PsiMember.class)); unmatchedElements.removeAll(matchedElements); MatchingHandler unmatchedSubstitutionHandler = null; for (PsiElement element = patternClass.getLBrace(); element != null; element = element.getNextSibling()) { if (element instanceof PsiTypeElement && element.getNextSibling() instanceof PsiErrorElement) { unmatchedSubstitutionHandler = javaPattern.getHandler(element); break; } } if (unmatchedSubstitutionHandler instanceof SubstitutionHandler) { final SubstitutionHandler handler = (SubstitutionHandler)unmatchedSubstitutionHandler; for (PsiElement element : unmatchedElements) { handler.handle(element, context); } } else { matchClass.putUserData(GlobalMatchingVisitor.UNMATCHED_ELEMENTS_KEY, unmatchedElements); } return true; } finally { myClazz = saveClazz; context.popMatchedElementsListener(); } }