@Nullable private static JetBlockExpression findClosestBlock( @NotNull PsiElement anchor, boolean down, boolean strict) { PsiElement current = PsiTreeUtil.getParentOfType(anchor, JetBlockExpression.class, strict); while (current != null) { PsiElement parent = current.getParent(); if (parent instanceof JetClassBody || parent instanceof JetClassInitializer || parent instanceof JetNamedFunction || (parent instanceof JetProperty && !((JetProperty) parent).isLocal())) { return null; } if (parent instanceof JetBlockExpression) return (JetBlockExpression) parent; PsiElement sibling = down ? current.getNextSibling() : current.getPrevSibling(); if (sibling != null) { //noinspection unchecked JetBlockExpression block = (JetBlockExpression) JetPsiUtil.getOutermostDescendantElement(sibling, down, CHECK_BLOCK); if (block != null) return block; current = sibling; } else { current = parent; } } return null; }
// Returns null if standalone closing brace is not found private static BraceStatus checkForMovableClosingBrace( @NotNull Editor editor, @NotNull PsiFile file, @NotNull MoveInfo info, boolean down) { PsiElement closingBrace = getStandaloneClosingBrace(file, editor); if (closingBrace == null) return BraceStatus.NOT_FOUND; PsiElement blockLikeElement = closingBrace.getParent(); if (!(blockLikeElement instanceof JetBlockExpression)) return BraceStatus.NOT_MOVABLE; PsiElement blockParent = blockLikeElement.getParent(); if (blockParent instanceof JetWhenEntry) return BraceStatus.NOT_FOUND; if (PsiTreeUtil.instanceOf(blockParent, FUNCTIONLIKE_ELEMENT_CLASSES)) return BraceStatus.NOT_FOUND; PsiElement enclosingExpression = PsiTreeUtil.getParentOfType(blockLikeElement, JetExpression.class); if (enclosingExpression instanceof JetDoWhileExpression) return BraceStatus.NOT_MOVABLE; if (enclosingExpression instanceof JetIfExpression) { JetIfExpression ifExpression = (JetIfExpression) enclosingExpression; if (blockLikeElement == ifExpression.getThen() && ifExpression.getElse() != null) return BraceStatus.NOT_MOVABLE; } return down ? checkForMovableDownClosingBrace(closingBrace, blockLikeElement, editor, info) : checkForMovableUpClosingBrace(closingBrace, blockLikeElement, editor, info); }
private static BraceStatus checkForMovableDownClosingBrace( @NotNull PsiElement closingBrace, @NotNull PsiElement block, @NotNull Editor editor, @NotNull MoveInfo info) { PsiElement current = block; PsiElement nextElement = null; PsiElement nextExpression = null; do { PsiElement sibling = firstNonWhiteElement(current.getNextSibling(), true); if (sibling != null && nextElement == null) { nextElement = sibling; } if (sibling instanceof JetExpression) { nextExpression = sibling; break; } current = current.getParent(); } while (current != null && !(PsiTreeUtil.instanceOf(current, BLOCKLIKE_ELEMENT_CLASSES))); if (nextExpression == null) return BraceStatus.NOT_MOVABLE; Document doc = editor.getDocument(); info.toMove = new LineRange(closingBrace, closingBrace, doc); info.toMove2 = new LineRange(nextElement, nextExpression); info.indentSource = true; return BraceStatus.MOVABLE; }
@NotNull @Override public Boolean invoke(PsiElement element) { return (!(element instanceof JetExpression) || element instanceof JetDeclaration || element instanceof JetBlockExpression || element.getParent() instanceof JetBlockExpression); }
@Nullable private static PsiElement getMovableElement(@NotNull PsiElement element, boolean lookRight) { //noinspection unchecked PsiElement movableElement = PsiUtilPackage.getParentByTypesAndPredicate( element, false, MOVABLE_ELEMENT_CLASSES, MOVABLE_ELEMENT_CONSTRAINT); if (movableElement == null) return null; if (isBracelessBlock(movableElement)) { movableElement = firstNonWhiteElement( lookRight ? movableElement.getLastChild() : movableElement.getFirstChild(), !lookRight); } return movableElement; }
/** * Add import directive corresponding to a type to file when it is needed. * * @param type type to import * @param file file where import directive should be added */ public static void addImportDirectivesIfNeeded(@NotNull JetType type, @NotNull JetFile file) { if (JetPluginUtil.checkTypeIsStandard(type, file.getProject()) || ErrorUtils.isErrorType(type)) { return; } BindingContext bindingContext = getContextForSingleFile(file); PsiElement element = BindingContextUtils.descriptorToDeclaration( bindingContext, type.getMemberScope().getContainingDeclaration()); if (element != null && element.getContainingFile() == file) { // declaration is in the same file, so no import is needed return; } for (ClassDescriptor clazz : TypeUtils.getAllClassDescriptors(type)) { addImportDirective(DescriptorUtils.getFQName(getTopLevelClass(clazz)).toSafe(), file); } }
public static void addImportDirectiveOrChangeToFqName( @NotNull FqName importFqn, @NotNull JetFile file, int refOffset, @NotNull PsiElement targetElement) { PsiReference reference = file.findReferenceAt(refOffset); if (reference instanceof JetPsiReference) { PsiElement target = reference.resolve(); if (target != null) { boolean same = file.getManager().areElementsEquivalent(target, targetElement); if (!same) { same = target instanceof PsiClass && importFqn.getFqName().equals(((PsiClass) target).getQualifiedName()); } if (!same) { if (target instanceof PsiMethod) { PsiMethod method = (PsiMethod) target; same = (method.isConstructor() && file.getManager() .areElementsEquivalent(method.getContainingClass(), targetElement)); } } if (!same) { if (target instanceof JetObjectDeclarationName) { same = file.getManager().areElementsEquivalent(target.getParent(), targetElement); } } if (!same) { Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file); TextRange refRange = reference.getElement().getTextRange(); document.replaceString( refRange.getStartOffset(), refRange.getEndOffset(), importFqn.getFqName()); } return; } } addImportDirective(new ImportPath(importFqn, false), null, file); }
@Nullable private static LineRange getWhenEntryTargetRange( @NotNull Editor editor, @NotNull PsiElement sibling, boolean down) { if (sibling.getNode().getElementType() == (down ? JetTokens.RBRACE : JetTokens.LBRACE) && PsiTreeUtil.getParentOfType(sibling, JetWhenEntry.class) == null) { return null; } return new LineRange(sibling, sibling, editor.getDocument()); }
@Override protected LineRange getElementSourceLineRange( @NotNull PsiElement element, @NotNull Editor editor, @NotNull LineRange oldRange) { TextRange textRange = element.getTextRange(); if (editor.getDocument().getTextLength() < textRange.getEndOffset()) return null; int startLine = editor.offsetToLogicalPosition(textRange.getStartOffset()).line; int endLine = editor.offsetToLogicalPosition(textRange.getEndOffset()).line + 1; return new LineRange(startLine, endLine); }
@Nullable private LineRange getValueParamOrArgTargetRange( @NotNull Editor editor, @NotNull PsiElement elementToCheck, @NotNull PsiElement sibling, boolean down) { PsiElement next = sibling; if (next.getNode().getElementType() == JetTokens.COMMA) { next = firstNonWhiteSibling(next, down); } LineRange range = (next instanceof JetParameter || next instanceof JetValueArgument) ? new LineRange(next, next, editor.getDocument()) : null; if (range != null) { parametersOrArgsToMove = new Pair<PsiElement, PsiElement>(elementToCheck, next); } return range; }
protected static PsiElement adjustSibling( @NotNull Editor editor, @NotNull LineRange sourceRange, @NotNull MoveInfo info, boolean down) { PsiElement element = down ? sourceRange.lastElement : sourceRange.firstElement; PsiElement sibling = down ? element.getNextSibling() : element.getPrevSibling(); PsiElement whiteSpaceTestSubject = sibling; if (sibling == null) { PsiElement parent = element.getParent(); if (parent != null && isBracelessBlock(parent)) { whiteSpaceTestSubject = down ? parent.getNextSibling() : parent.getPrevSibling(); } } if (whiteSpaceTestSubject instanceof PsiWhiteSpace) { if (getElementLineCount(whiteSpaceTestSubject, editor) > 1) { int nearLine = down ? sourceRange.endLine : sourceRange.startLine - 1; info.toMove = sourceRange; info.toMove2 = new LineRange(nearLine, nearLine + 1); info.indentTarget = false; return null; } if (sibling != null) { sibling = firstNonWhiteElement(sibling, down); } } if (sibling == null) { JetCallExpression callExpression = PsiTreeUtil.getParentOfType(element, JetCallExpression.class); if (callExpression != null) { JetBlockExpression dslBlock = getDSLLambdaBlock(callExpression, down); if (PsiTreeUtil.isAncestor(dslBlock, element, false)) { //noinspection ConstantConditions PsiElement blockParent = dslBlock.getParent(); return down ? JetPsiUtil.findChildByType(blockParent, JetTokens.RBRACE) : JetPsiUtil.findChildByType(blockParent, JetTokens.LBRACE); } } info.toMove2 = null; return null; } return sibling; }
private static void fixCommaIfNeeded(@NotNull PsiElement element, boolean willBeLast) { PsiElement comma = getComma(element); if (willBeLast && comma != null) { comma.delete(); } else if (!willBeLast && comma == null) { PsiElement parent = element.getParent(); assert parent != null; parent.addAfter(JetPsiFactory(parent.getProject()).createComma(), element); } }
private static PsiElement getComma(@NotNull PsiElement element) { PsiElement sibling = firstNonWhiteSibling(element, true); return sibling != null && (sibling.getNode().getElementType() == JetTokens.COMMA) ? sibling : null; }
private static boolean isLastOfItsKind(@NotNull PsiElement element, boolean down) { return getSiblingOfType(element, down, element.getClass()) == null; }
@Nullable private static LineRange getExpressionTargetRange( @NotNull Editor editor, @NotNull PsiElement sibling, boolean down) { if (sibling instanceof JetIfExpression && !down) { JetExpression elseBranch = ((JetIfExpression) sibling).getElse(); if (elseBranch instanceof JetBlockExpression) { sibling = elseBranch; } } PsiElement start = sibling; PsiElement end = sibling; // moving out of code block if (sibling.getNode().getElementType() == (down ? JetTokens.RBRACE : JetTokens.LBRACE)) { PsiElement parent = sibling.getParent(); if (!(parent instanceof JetBlockExpression || parent instanceof JetFunctionLiteral)) return null; JetBlockExpression newBlock; if (parent instanceof JetFunctionLiteral) { //noinspection ConstantConditions newBlock = findClosestBlock(((JetFunctionLiteral) parent).getBodyExpression(), down, false); if (!down) { ASTNode arrow = ((JetFunctionLiteral) parent).getArrowNode(); if (arrow != null) { end = arrow.getPsi(); } } } else { newBlock = findClosestBlock(sibling, down, true); } if (newBlock == null) return null; if (PsiTreeUtil.isAncestor(newBlock, parent, true)) { PsiElement outermostParent = JetPsiUtil.getOutermostParent(parent, newBlock, true); if (down) { end = outermostParent; } else { start = outermostParent; } } else { if (down) { end = newBlock.getLBrace(); } else { start = newBlock.getRBrace(); } } } // moving into code block else { PsiElement blockLikeElement; JetBlockExpression dslBlock = getDSLLambdaBlock(sibling, down); if (dslBlock != null) { // Use JetFunctionLiteral (since it contains braces) blockLikeElement = dslBlock.getParent(); } else { // JetBlockExpression and other block-like elements blockLikeElement = JetPsiUtil.getOutermostDescendantElement(sibling, down, CHECK_BLOCK_LIKE_ELEMENT); } if (blockLikeElement != null) { if (down) { end = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.LBRACE); if (blockLikeElement instanceof JetFunctionLiteral) { ASTNode arrow = ((JetFunctionLiteral) blockLikeElement).getArrowNode(); if (arrow != null) { end = arrow.getPsi(); } } } else { start = JetPsiUtil.findChildByType(blockLikeElement, JetTokens.RBRACE); } } } return start != null && end != null ? new LineRange(start, end, editor.getDocument()) : null; }