boolean (Project project, Editor editor, PsiFile file, int offsetBefore) { if (offsetBefore == 0) return false; HighlighterIterator it = editor.getHighlighter().createIterator(offsetBefore); if (it.atEnd()) return false; IElementType curToken = it.getTokenType(); if (JavaTypingTokenSets.UNWANTED_TOKEN_AT_QUESTION.contains(curToken)) return false; int nesting = 0; while (true) { it.retreat(); if (it.atEnd()) return false; curToken = it.getTokenType(); if (curToken == JavaTokenType.LPARENTH || curToken == JavaTokenType.LBRACKET || curToken == JavaTokenType.LBRACE) { nesting--; if (nesting < 0) return false; } else if (curToken == JavaTokenType.RPARENTH || curToken == JavaTokenType.RBRACKET || curToken == JavaTokenType.RBRACE) { nesting++; } else if (nesting == 0) { if (JavaTypingTokenSets.UNWANTED_TOKEN_BEFORE_QUESTION.contains(curToken)) return false; if (JavaTypingTokenSets.WANTED_TOKEN_BEFORE_QUESTION.contains(curToken)) break; } } Document doc = editor.getDocument(); doc.insertString(offsetBefore, "?"); editor.getCaretModel().moveToOffset(offsetBefore + 1); PsiDocumentManager.getInstance(project).commitDocument(doc); PsiElement element = file.findElementAt(offsetBefore); if (!PsiUtil.isJavaToken(element, JavaTokenType.QUEST)) return true; PsiConditionalExpression cond = ObjectUtils.tryCast(element.getParent(), PsiConditionalExpression.class); if (cond == null || cond.getThenExpression() != null || cond.getElseExpression() != null) return true; PsiExpression condition = cond.getCondition(); if (PsiUtilCore.hasErrorElementChild(condition)) return true; // intVal+bool? => intVal+(bool?) if (condition instanceof PsiPolyadicExpression && !PsiTypes.booleanType().equals(condition.getType())) { PsiExpression lastOperand = ArrayUtil.getLastElement(((PsiPolyadicExpression)condition).getOperands()); if (lastOperand != null && PsiTypes.booleanType().equals(lastOperand.getType())) { int openingOffset = lastOperand.getTextRange().getStartOffset(); int closingOffset = cond.getTextRange().getEndOffset(); wrapWithParentheses(file, doc, openingOffset, closingOffset); } } return true; }