public void processIntention(@NotNull PsiElement element) throws IncorrectOperationException { final GrIfStatement parentStatement = (GrIfStatement) element; assert parentStatement != null; final GrStatement parentThenBranch = (GrStatement) parentStatement.getThenBranch(); final GrIfStatement childStatement = (GrIfStatement) ConditionalUtils.stripBraces(parentThenBranch); final GrExpression childCondition = (GrExpression) childStatement.getCondition(); final String childConditionText; if (ParenthesesUtils.getPrecendence(childCondition) > ParenthesesUtils.AND_PRECEDENCE) { childConditionText = '(' + childCondition.getText() + ')'; } else { childConditionText = childCondition.getText(); } final GrExpression parentCondition = (GrExpression) parentStatement.getCondition(); final String parentConditionText; if (ParenthesesUtils.getPrecendence(parentCondition) > ParenthesesUtils.AND_PRECEDENCE) { parentConditionText = '(' + parentCondition.getText() + ')'; } else { parentConditionText = parentCondition.getText(); } final GrStatement childThenBranch = (GrStatement) childStatement.getThenBranch(); @NonNls final String statement = "if(" + parentConditionText + "&&" + childConditionText + ')' + childThenBranch.getText(); IntentionUtils.replaceStatement(statement, parentStatement); }
private static Collection<GrVariable> collectUsedLocalVarsOrParamsDeclaredOutside( GrStatement[] statements) { final Collection<GrVariable> result = new HashSet<GrVariable>(); final int start = statements[0].getTextRange().getStartOffset(); final int end = statements[statements.length - 1].getTextRange().getEndOffset(); final GroovyRecursiveElementVisitor visitor = new GroovyRecursiveElementVisitor() { @Override public void visitReferenceExpression(GrReferenceExpression ref) { final PsiElement resolved = ref.resolve(); if ((resolved instanceof GrParameter || GroovyRefactoringUtil.isLocalVariable(resolved)) && resolved.isPhysical()) { final int offset = resolved.getTextRange().getStartOffset(); // var is declared outside of selected code if (offset < start || end <= offset) { result.add((GrVariable) resolved); } } } }; for (GrStatement statement : statements) { statement.accept(visitor); } return result; }
public static void removeNewLineAfter(@NotNull GrStatement statement) { ASTNode parentNode = statement.getParent().getNode(); ASTNode next = statement.getNode().getTreeNext(); if (parentNode != null && next != null && mNLS == next.getElementType()) { parentNode.removeChild(next); } }
@Override public void visitCaseSection(GrCaseSection caseSection) { for (GrCaseLabel label : caseSection.getCaseLabels()) { GrExpression value = label.getValue(); if (value != null) { value.accept(this); } } final GrStatement[] statements = caseSection.getStatements(); // infer 'may be return' position int i; for (i = statements.length - 1; i >= 0 && statements[i] instanceof GrBreakStatement; i--) {} for (int j = 0; j < statements.length; j++) { GrStatement statement = statements[j]; statement.accept(this); if (j == i) handlePossibleReturn(statement); } if (myHead != null) { addPendingEdge(caseSection, myHead); } }
public void visitForStatement(GrForStatement forStatement) { final GrForClause clause = forStatement.getClause(); processForLoopInitializer(clause); InstructionImpl start = startNode(forStatement); addForLoopBreakingEdge(forStatement, clause); flushForeachLoopVariable(clause); final GrStatement body = forStatement.getBody(); if (body != null) { InstructionImpl bodyInstruction = startNode(body); body.accept(this); finishNode(bodyInstruction); } checkPending(start); // check for breaks targeted here if (clause instanceof GrTraditionalForClause) { acceptNullable(((GrTraditionalForClause) clause).getUpdate()); } if (myHead != null) addEdge(myHead, start); // loop interruptFlow(); finishNode(start); }
private static void generateElseBranchTextAndRemoveTailStatements( @NotNull GrIfStatement ifStatement, @NotNull GrIfStatement newIf) { final GrStatement thenBranch = newIf.getThenBranch(); assert thenBranch != null; GrStatement elseBranch = ifStatement.getElseBranch(); if (elseBranch != null) { thenBranch.replaceWithStatement(elseBranch); return; } PsiElement parent = ifStatement.getParent(); if (!(parent instanceof GrStatementOwner)) return; if (!isTailAfterIf(ifStatement, ((GrStatementOwner) parent))) return; final PsiElement start = ifStatement.getNextSibling(); PsiElement end = parent instanceof GrCodeBlock ? ((GrCodeBlock) parent).getRBrace().getPrevSibling() : parent.getLastChild(); final GrOpenBlock block = ((GrBlockStatement) thenBranch).getBlock(); block.addRangeAfter(start, end, block.getLBrace()); parent.deleteChildRange(start, end); }
@Override protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException { PsiElement parent = element.getParent(); if (!"if".equals(element.getText()) || !(parent instanceof GrIfStatement)) { throw new IncorrectOperationException("Not invoked on an if"); } GrIfStatement parentIf = (GrIfStatement) parent; GroovyPsiElementFactory groovyPsiElementFactory = GroovyPsiElementFactory.getInstance(project); GrExpression condition = parentIf.getCondition(); if (condition == null) { throw new IncorrectOperationException("Invoked on an if with empty condition"); } GrExpression negatedCondition = null; if (condition instanceof GrUnaryExpression) { GrUnaryExpression unaryCondition = (GrUnaryExpression) condition; if ("!".equals(unaryCondition.getOperationToken().getText())) { negatedCondition = stripParenthesis(unaryCondition.getOperand()); } } if (negatedCondition == null) { // Now check whether this is a simple expression condition = stripParenthesis(condition); String negatedExpressionText; if (condition instanceof GrCallExpression || condition instanceof GrReferenceExpression) { negatedExpressionText = "!" + condition.getText(); } else { negatedExpressionText = "!(" + condition.getText() + ")"; } negatedCondition = groovyPsiElementFactory.createExpressionFromText(negatedExpressionText, parentIf); } GrStatement thenBranch = parentIf.getThenBranch(); final boolean thenIsNotEmpty = isNotEmpty(thenBranch); String newIfText = "if (" + negatedCondition.getText() + ") {}"; if (thenIsNotEmpty) { newIfText += " else {}"; } GrIfStatement newIf = (GrIfStatement) groovyPsiElementFactory.createStatementFromText(newIfText, parentIf.getContext()); generateElseBranchTextAndRemoveTailStatements(parentIf, newIf); if (thenIsNotEmpty) { final GrStatement elseBranch = newIf.getElseBranch(); assert elseBranch != null; elseBranch.replaceWithStatement(thenBranch); } parentIf.replace(newIf); }
public static PsiField[] findUsedFieldsWithGetters( GrStatement[] statements, PsiClass containingClass) { if (containingClass == null) return PsiField.EMPTY_ARRAY; final FieldSearcher searcher = new FieldSearcher(containingClass); for (GrStatement statement : statements) { statement.accept(searcher); } return searcher.getResult(); }
public void visitIfStatement(GrIfStatement ifStatement) { InstructionImpl ifInstruction = startNode(ifStatement); final GrCondition condition = ifStatement.getCondition(); final GrStatement thenBranch = ifStatement.getThenBranch(); final GrStatement elseBranch = ifStatement.getElseBranch(); InstructionImpl conditionEnd = null; InstructionImpl thenEnd = null; InstructionImpl elseEnd = null; if (condition != null) { condition.accept(this); conditionEnd = myHead; } List<GotoInstruction> negations = collectAndRemoveAllPendingNegations(ifStatement); if (thenBranch != null) { thenBranch.accept(this); handlePossibleReturn(thenBranch); thenEnd = myHead; interruptFlow(); readdPendingEdge(ifStatement); } myHead = reduceAllNegationsIntoInstruction(ifStatement, negations); if (myHead == null && conditionEnd != null) { myHead = conditionEnd; } if (elseBranch != null) { elseBranch.accept(this); handlePossibleReturn(elseBranch); elseEnd = myHead; interruptFlow(); } if (thenBranch != null || elseBranch != null) { if (thenEnd != null || elseEnd != null || elseBranch == null) { final InstructionImpl end = new IfEndInstruction(ifStatement); addNode(end); if (thenEnd != null) { addEdge(thenEnd, end); } if (elseEnd != null) { addEdge(elseEnd, end); } else if (elseBranch == null) { addEdge(conditionEnd != null ? conditionEnd : ifInstruction, end); } } } finishNode(ifInstruction); }
private static PsiElement generateTryCatch(PsiElement element, PsiClassType[] exceptions) { if (exceptions.length == 0) return element; GrTryCatchStatement tryCatch = (GrTryCatchStatement) GroovyPsiElementFactory.getInstance(element.getProject()) .createStatementFromText("try{} catch (Exception e){}"); final GrStatement statement = PsiTreeUtil.getParentOfType(element, GrStatement.class); assert statement != null; tryCatch.getTryBlock().addStatementBefore(statement, null); tryCatch = (GrTryCatchStatement) statement.replace(tryCatch); tryCatch.getCatchClauses()[0].delete(); fixCatchBlock(tryCatch, exceptions); return tryCatch; }
public static PsiElement findTailingSemicolon(@NotNull GrStatement statement) { final PsiElement nextNonSpace = PsiUtil.skipWhitespaces(statement.getNextSibling(), true); if (nextNonSpace != null && nextNonSpace.getNode().getElementType() == mSEMI) { return nextNonSpace; } return null; }
protected TextRange surroundExpression(GrExpression expression, PsiElement context) { GrIfStatement ifStatement = (GrIfStatement) GroovyPsiElementFactory.getInstance(expression.getProject()) .createStatementFromText("if(a){4\n} else{\n}", context); replaceToOldExpression(ifStatement.getCondition(), expression); ifStatement = expression.replaceWithStatement(ifStatement); GrStatement psiElement = ifStatement.getThenBranch(); assert psiElement instanceof GrBlockStatement; GrStatement[] statements = ((GrBlockStatement) psiElement).getBlock().getStatements(); assert statements.length > 0; GrStatement statement = statements[0]; int endOffset = statement.getTextRange().getStartOffset(); statement.getNode().getTreeParent().removeChild(statement.getNode()); return new TextRange(endOffset, endOffset); }
/** * check whether statement is return (the statement which provides return value) statement of * method or closure. * * @param st * @return */ public static boolean isCertainlyReturnStatement(GrStatement st) { final PsiElement parent = st.getParent(); if (parent instanceof GrOpenBlock) { if (st != ArrayUtil.getLastElement(((GrOpenBlock) parent).getStatements())) return false; PsiElement pparent = parent.getParent(); if (pparent instanceof GrMethod) { return true; } if (pparent instanceof GrBlockStatement || pparent instanceof GrCatchClause || pparent instanceof GrLabeledStatement) { pparent = pparent.getParent(); } if (pparent instanceof GrIfStatement || pparent instanceof GrControlStatement || pparent instanceof GrTryCatchStatement) { return isCertainlyReturnStatement((GrStatement) pparent); } } else if (parent instanceof GrClosableBlock) { return st == ArrayUtil.getLastElement(((GrClosableBlock) parent).getStatements()); } else if (parent instanceof GroovyFileBase) { return st == ArrayUtil.getLastElement(((GroovyFileBase) parent).getStatements()); } else if (parent instanceof GrForStatement || parent instanceof GrIfStatement && st != ((GrIfStatement) parent).getCondition() || parent instanceof GrSynchronizedStatement && st != ((GrSynchronizedStatement) parent).getMonitor() || parent instanceof GrWhileStatement && st != ((GrWhileStatement) parent).getCondition() || parent instanceof GrConditionalExpression && st != ((GrConditionalExpression) parent).getCondition() || parent instanceof GrElvisExpression) { return isCertainlyReturnStatement((GrStatement) parent); } else if (parent instanceof GrCaseSection) { final GrStatement[] statements = ((GrCaseSection) parent).getStatements(); final GrStatement last = ArrayUtil.getLastElement(statements); final GrSwitchStatement switchStatement = (GrSwitchStatement) parent.getParent(); if (last instanceof GrBreakStatement && statements.length > 1 && statements[statements.length - 2] == st) { return isCertainlyReturnStatement(switchStatement); } else if (st == last) { if (st instanceof GrBreakStatement || isLastStatementInCaseSection((GrCaseSection) parent, switchStatement)) { return isCertainlyReturnStatement(switchStatement); } } } return false; }
public static <T extends GrCondition> T replaceBody( T newBody, GrStatement body, ASTNode node, Project project) { if (body == null || newBody == null) { throw new IncorrectOperationException(); } ASTNode oldBodyNode = body.getNode(); if (oldBodyNode.getTreePrev() != null && mNLS.equals(oldBodyNode.getTreePrev().getElementType())) { ASTNode whiteNode = GroovyPsiElementFactory.getInstance(project).createWhiteSpace().getNode(); node.replaceChild(oldBodyNode.getTreePrev(), whiteNode); } node.replaceChild(oldBodyNode, newBody.getNode()); return newBody; }
public static int getCaretOffset(@NotNull GrStatement statement) { if (statement instanceof GrVariableDeclaration) { GrVariable[] variables = ((GrVariableDeclaration) statement).getVariables(); if (variables.length > 0) { GrExpression initializer = variables[0].getInitializerGroovy(); if (initializer != null) { return initializer.getTextOffset(); } } } else if (statement instanceof GrAssignmentExpression) { GrExpression value = ((GrAssignmentExpression) statement).getRValue(); if (value != null) { return value.getTextOffset(); } } return statement.getTextOffset(); }
@NotNull public GrStatement addStatementBefore(@NotNull GrStatement element, @Nullable GrStatement anchor) throws IncorrectOperationException { if (anchor == null && getRBrace() == null) { throw new IncorrectOperationException(); } if (anchor != null && !this.equals(anchor.getParent())) { throw new IncorrectOperationException(); } final LeafElement nls = Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, getManager()); PsiElement actualAnchor = anchor == null ? getRBrace() : anchor; if (mayUseNewLinesAsSeparators()) { PsiElement prev = actualAnchor.getPrevSibling(); if (prev instanceof GrParameterList && prev.getTextLength() == 0 && prev.getPrevSibling() != null) { prev = prev.getPrevSibling(); } if (!PsiUtil.isLineFeed(prev)) { addBefore(nls.getPsi(), actualAnchor); } } element = (GrStatement) addBefore(element, actualAnchor); if (mayUseNewLinesAsSeparators()) { addBefore(nls.getPsi(), actualAnchor); } else { addBefore( Factory.createSingleLeafElement(GroovyTokenTypes.mNLS, "\n", 0, 1, null, getManager()) .getPsi(), actualAnchor); } return element; }
public void visitStatementOwner(GrStatementOwner owner, boolean shouldInsertReturnNull) { boolean hasLineFeed = false; for (PsiElement e = owner.getFirstChild(); e != null; e = e.getNextSibling()) { if (e instanceof GrStatement) { ((GrStatement) e).accept(this); hasLineFeed = false; } else if (TokenSets.COMMENT_SET.contains(e.getNode().getElementType())) { builder.append(e.getText()); } else if (org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.isLineFeed(e)) { hasLineFeed = true; if (IN_TEST) { builder.append(genSameLineFeed(e.getText())); } else { builder.append(e.getText()); } } } if (shouldInsertReturnNull) { if (!hasLineFeed) { builder.append('\n'); } builder.append("return null;\n"); } }
public static void generateBody( ExtractInfoHelper helper, boolean isVoid, StringBuilder buffer, boolean forceReturn) { VariableInfo[] outputInfos = helper.getOutputVariableInfos(); ParameterInfo[] infos = helper.getParameterInfos(); Set<String> declaredVars = new HashSet<String>(); for (ParameterInfo info : infos) { declaredVars.add(info.getName()); } for (VariableInfo info : mustAddVariableDeclaration(helper.getStatements(), outputInfos)) { declaredVars.add(info.getName()); } List<VariableInfo> genDecl = new ArrayList<VariableInfo>(); final Collection<GrVariable> outside = collectUsedLocalVarsOrParamsDeclaredOutside(helper.getStatements()); for (final GrVariable variable : outside) { if (!declaredVars.contains(variable.getName())) { genDecl.add( new VariableInfo() { @NotNull @Override public String getName() { return variable.getName(); } @Override public PsiType getType() { return variable.getDeclaredType(); } }); } } final List<GrStatement> statements = generateVarDeclarations(genDecl, helper.getProject(), null); for (GrStatement statement : statements) { buffer.append(statement.getText()).append('\n'); } if (!isSingleExpression(helper.getStatements()) || statements.size() > 0) { for (PsiElement element : helper.getInnerElements()) { buffer.append(element.getText()); } // append return statement if (!isVoid && outputInfos.length > 0) { buffer.append('\n'); if (forceReturn) { buffer.append("return "); } if (outputInfos.length > 1) buffer.append('['); for (VariableInfo info : outputInfos) { buffer.append(info.getName()).append(", "); } buffer.delete(buffer.length() - 2, buffer.length()); if (outputInfos.length > 1) buffer.append(']'); } } else { GrExpression expr = (GrExpression) PsiUtil.skipParentheses(helper.getStatements()[0], false); boolean addReturn = !isVoid && forceReturn; if (addReturn) { buffer.append("return "); expr = ApplicationStatementUtil.convertToMethodCallExpression(expr); buffer.append(expr.getText()); } else { buffer.append(expr != null ? expr.getText() : ""); } } }
private static GrForStatement updateReturnStatements(GrForStatement forStatement) { GrStatement body = forStatement.getBody(); assert body != null; final Set<String> usedLabels = ContainerUtil.newHashSet(); final Ref<Boolean> needLabel = Ref.create(false); body.accept( new GroovyRecursiveElementVisitor() { private int myLoops = 0; @Override public void visitReturnStatement(GrReturnStatement returnStatement) { if (returnStatement.getReturnValue() != null) return; if (myLoops > 0) needLabel.set(true); } @Override public void visitLabeledStatement(GrLabeledStatement labeledStatement) { super.visitLabeledStatement(labeledStatement); usedLabels.add(labeledStatement.getName()); } @Override public void visitForStatement(GrForStatement forStatement) { myLoops++; super.visitForStatement(forStatement); myLoops--; } @Override public void visitWhileStatement(GrWhileStatement whileStatement) { myLoops++; super.visitWhileStatement(whileStatement); myLoops--; } @Override public void visitClosure(GrClosableBlock closure) { // don't go into closures } @Override public void visitAnonymousClassDefinition( GrAnonymousClassDefinition anonymousClassDefinition) { // don't go into anonymous } }); GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(forStatement.getProject()); final String continueText; if (needLabel.get()) { int i = 0; String label = OUTER; while (usedLabels.contains(label)) { label = OUTER + i; i++; } continueText = "continue " + label; GrLabeledStatement labeled = (GrLabeledStatement) factory.createStatementFromText(label + ": while (true){}"); labeled.getStatement().replaceWithStatement(forStatement); labeled = forStatement.replaceWithStatement(labeled); forStatement = (GrForStatement) labeled.getStatement(); body = forStatement.getBody(); assert body != null; } else { continueText = "continue"; } final GrStatement continueStatement = factory.createStatementFromText(continueText); body.accept( new GroovyRecursiveElementVisitor() { @Override public void visitReturnStatement(GrReturnStatement returnStatement) { if (returnStatement.getReturnValue() == null) { returnStatement.replaceWithStatement(continueStatement); } } @Override public void visitClosure(GrClosableBlock closure) { // don't go into closures } @Override public void visitAnonymousClassDefinition( GrAnonymousClassDefinition anonymousClassDefinition) { // don't go into anonymous } }); return forStatement; }
private static GrStatement copyElement(GrStatement e) throws IncorrectOperationException { // We cannot call el.copy() for 'else' since it sets context to parent 'if'. // This causes copy to be invalidated after parent 'if' is removed by setElseBranch method. GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(e.getProject()); return factory.createStatementFromText(e.getText(), null); }
@Override public void visitForStatement(GrForStatement forStatement) { // final StringBuilder builder = new StringBuilder(); builder.append("for("); final GrForClause clause = forStatement.getClause(); ExpressionContext forContext = context.extend(); if (clause instanceof GrForInClause) { final GrExpression expression = ((GrForInClause) clause).getIteratedExpression(); final GrVariable declaredVariable = clause.getDeclaredVariable(); LOG.assertTrue(declaredVariable != null); writeVariableWithoutSemicolonAndInitializer(builder, declaredVariable, context); builder.append(" : "); if (expression != null) { final ExpressionContext context = forContext.copy(); writeExpression(expression, builder, context); } } else if (clause instanceof GrTraditionalForClause) { final GrTraditionalForClause cl = (GrTraditionalForClause) clause; final GrCondition initialization = cl.getInitialization(); final GrExpression condition = cl.getCondition(); final GrExpression update = cl.getUpdate(); if (initialization instanceof GrParameter) { StringBuilder partBuilder = new StringBuilder(); writeVariableWithoutSemicolonAndInitializer( partBuilder, (GrParameter) initialization, context); final GrExpression initializer = ((GrParameter) initialization).getInitializerGroovy(); if (initializer != null) { final ExpressionContext partContext = forContext.copy(); partBuilder.append(" = "); writeExpression(initializer, partBuilder, partContext); for (String statement : partContext.myStatements) { builder.append(statement).append(", "); } builder.append(partBuilder); } } else if (initialization != null) { StringBuilder partBuilder = new StringBuilder(); final ExpressionContext partContext = forContext.copy(); genForPart(builder, initialization, new CodeBlockGenerator(partBuilder, partContext, null)); } builder.append(';'); if (condition != null) { genForPart(builder, condition, forContext.copy()); // todo??? } builder.append(';'); if (update != null) { genForPart(builder, update, forContext.copy()); } } builder.append(')'); final GrStatement body = forStatement.getBody(); if (body != null) { body.accept(new CodeBlockGenerator(builder, forContext, null)); } }