ThreeState (ASTNode oldNode, ASTNode newNode) { myIndicator.checkCanceled(); String oldText = TreeUtil.isCollapsedChameleon(oldNode) ? oldNode.getText() : null; String newText = TreeUtil.isCollapsedChameleon(newNode) ? newNode.getText() : null; if (oldText != null && newText != null) return oldText.equals(newText) ? ThreeState.YES : ThreeState.UNSURE; if (oldText != null) { return compareTreeToText((TreeElement)newNode, oldText) ? ThreeState.YES : ThreeState.UNSURE; } if (newText != null) { return compareTreeToText((TreeElement)oldNode, newText) ? ThreeState.YES : ThreeState.UNSURE; } if (oldNode instanceof ForeignLeafPsiElement) { return newNode instanceof ForeignLeafPsiElement && oldNode.getText().equals(newNode.getText()) ? ThreeState.YES : ThreeState.NO; } if (newNode instanceof ForeignLeafPsiElement) return ThreeState.NO; if (oldNode instanceof LeafElement) { return ((LeafElement)oldNode).textMatches(newNode.getChars()) ? ThreeState.YES : ThreeState.NO; } if (newNode instanceof LeafElement) { return ((LeafElement)newNode).textMatches(oldNode.getChars()) ? ThreeState.YES : ThreeState.NO; } if (oldNode instanceof PsiErrorElement && newNode instanceof PsiErrorElement) { PsiErrorElement e1 = (PsiErrorElement)oldNode; PsiErrorElement e2 = (PsiErrorElement)newNode; if (!Objects.equals(e1.getErrorDescription(), e2.getErrorDescription())) return ThreeState.NO; } return ThreeState.UNSURE; }