use of com.perl5.lang.perl.psi.impl.PsiPerlStatementImpl in project Perl5-IDEA by Camelcade.
the class PerlLoopControlInspection method buildVisitor.
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
PerlSubDefinitionElement breakDefinition = PerlBuiltInSubsService.getInstance(holder.getProject()).findSub("break");
return new PerlVisitor() {
@Override
public void visitNextExpr(@NotNull PsiPerlNextExpr o) {
processLoopsControl(o);
}
@Override
public void visitRedoExpr(@NotNull PsiPerlRedoExpr o) {
processLoopsControl(o);
}
@Override
public void visitLastExpr(@NotNull PsiPerlLastExpr o) {
processLoopsControl(o);
}
@Override
public void visitContinueExpr(@NotNull PsiPerlContinueExpr o) {
PsiElement position = o;
boolean isInsideTheLoop = false;
while (true) {
PsiElement closestBlockContainer = getClosestBlockContainer(position);
if (closestBlockContainer == null) {
break;
}
IElementType blockContainerElementType = PsiUtilCore.getElementType(closestBlockContainer);
if (blockContainerElementType == WHEN_COMPOUND || blockContainerElementType == DEFAULT_COMPOUND) {
return;
} else if (LOOPS_CONTAINERS.contains(blockContainerElementType)) {
isInsideTheLoop = true;
} else if (blockContainerElementType == NAMED_BLOCK) {
break;
} else if (MAP_GREP.contains(blockContainerElementType)) {
break;
} else if (BLOCKS_WITH_RETURN_VALUE.contains(blockContainerElementType)) {
break;
} else if (blockContainerElementType == GIVEN_COMPOUND) {
break;
}
position = closestBlockContainer;
}
if (isInsideTheLoop) {
holder.registerProblem(o, PerlBundle.message("perl.inspection.loop.control.continue.instead.of.next"), new ReplaceWithExpressionQuickFix("next"));
} else {
problem(o, "perl.inspection.loop.control.continue");
}
}
@Override
public void visitSubNameElement(@NotNull PerlSubNameElement o) {
PsiReference reference = o.getReference();
if (reference == null) {
return;
}
if (reference.resolve() != breakDefinition) {
return;
}
PsiElement position = o;
boolean isInsideTheLoop = false;
while (true) {
PsiElement closestBlockContainer = getClosestBlockContainer(position);
if (closestBlockContainer == null) {
break;
}
IElementType blockContainerElementType = PsiUtilCore.getElementType(closestBlockContainer);
if (LOOPS_CONTAINERS.contains(blockContainerElementType)) {
isInsideTheLoop = true;
} else if (blockContainerElementType == NAMED_BLOCK) {
break;
} else if (MAP_GREP.contains(blockContainerElementType)) {
break;
} else if (BLOCKS_WITH_RETURN_VALUE.contains(blockContainerElementType)) {
break;
} else if (blockContainerElementType == GIVEN_COMPOUND) {
return;
}
position = closestBlockContainer;
}
if (isInsideTheLoop) {
holder.registerProblem(o, PerlBundle.message("perl.inspection.loop.control.break.instead.of.last"), new ReplaceWithExpressionQuickFix("last"));
} else {
problem(o, "perl.inspection.loop.control.break");
}
}
private void problem(@NotNull PsiElement anchor, @NotNull String key, @NotNull String... args) {
registerProblem(holder, anchor, PerlBundle.message(key, (Object[]) args));
}
/**
* @return parent psi element for closest parent block element
*/
@Nullable
private PsiElement getClosestBlockContainer(@NotNull PsiElement position) {
PsiPerlBlock enclosingBlock = PsiTreeUtil.getParentOfType(position, PsiPerlBlock.class);
if (enclosingBlock == null) {
return null;
}
PsiElement blockContainer = enclosingBlock.getParent();
return PsiUtilCore.getElementType(blockContainer) == LP_CODE_BLOCK ? blockContainer.getParent() : blockContainer;
}
/**
* Traversing blocks up, trying to figure out if last/next/redo are in right place.
*
* @param expr last/next/redo expression
*/
private void processLoopsControl(@NotNull PsiElement expr) {
PsiElement keyword = expr.getFirstChild();
if (keyword == null) {
return;
}
String keywordText = keyword.getText();
// checks modifier
PsiPerlStatementImpl containingStatement = PsiTreeUtil.getParentOfType(expr, PsiPerlStatementImpl.class);
PsiPerlStatementModifier modifier = containingStatement == null ? null : containingStatement.getModifier();
if (modifier instanceof PsiPerlForStatementModifier) {
return;
}
// traversing up
PsiElement position = expr;
boolean isInsideGiven = false;
boolean isInsideWhenOrDefault = false;
while (true) {
PsiElement closestBlockContainer = getClosestBlockContainer(position);
if (closestBlockContainer == null) {
break;
}
IElementType blockContainerType = PsiUtilCore.getElementType(closestBlockContainer);
if (LOOPS_CONTAINERS.contains(blockContainerType)) {
return;
} else if (blockContainerType == NAMED_BLOCK) {
problem(expr, "perl.inspection.loop.control.in.named.block", keywordText);
return;
} else if (MAP_GREP.contains(blockContainerType)) {
problem(expr, "perl.inspection.loop.control.in.map", keywordText);
return;
} else if (BLOCKS_WITH_RETURN_VALUE.contains(blockContainerType)) {
problem(expr, "perl.inspection.loop.control.in.do", keywordText);
return;
} else if (blockContainerType == GIVEN_COMPOUND) {
isInsideGiven = true;
} else if (blockContainerType == WHEN_COMPOUND || blockContainerType == DEFAULT_COMPOUND) {
isInsideWhenOrDefault = true;
}
position = closestBlockContainer;
}
if (expr instanceof PsiPerlNextExpr && isInsideWhenOrDefault) {
holder.registerProblem(expr, PerlBundle.message("perl.inspection.loop.control.next.instead.of.continue"), new ReplaceWithExpressionQuickFix("continue"));
} else if (expr instanceof PsiPerlLastExpr && isInsideGiven) {
holder.registerProblem(expr, PerlBundle.message("perl.inspection.loop.control.last.instead.of.break"), new ReplaceWithExpressionQuickFix("break"));
} else {
problem(expr, "perl.inspection.loop.control.outside", keywordText);
}
}
};
}
use of com.perl5.lang.perl.psi.impl.PsiPerlStatementImpl in project Perl5-IDEA by Camelcade.
the class CompoundToStatementIntention method replaceWithStatement.
/**
* Generating new code, extracting declarations from control expression and replacing compound statement if possible.
*
* @param compound compound statement
* @param statementText statement text
* @param controlExpr control expression (condition or iterable)
*/
private static void replaceWithStatement(@NotNull PerlConvertableCompound compound, @NotNull String statementText, @NotNull PsiPerlExpr controlExpr) {
List<PsiElement> declarations = new ArrayList<>();
controlExpr.accept(new PerlRecursiveVisitor() {
@Override
public void visitPerlVariableDeclarationExpr(@NotNull PerlVariableDeclarationExpr o) {
declarations.add(o);
super.visitPerlVariableDeclarationExpr(o);
}
});
String controlExprText = controlExpr.getText();
StringBuilder sb = new StringBuilder();
if (!declarations.isEmpty()) {
// extracting declarations from control statement
TextRange controlExprTextRange = controlExpr.getTextRange();
for (int i = declarations.size() - 1; i >= 0; i--) {
PsiElement declaration = declarations.get(i);
sb.append(declaration.getText()).append(";\n");
PsiElement keywordElement = declaration.getFirstChild();
if (keywordElement instanceof LeafPsiElement) {
// removing keyword from control expression my $var => $var, my ($var1, $var2) => ($var1, $var2)
controlExprText = keywordElement.getTextRange().shiftRight(-controlExprTextRange.getStartOffset()).replace(controlExprText, "");
}
}
}
sb.append(statementText).append(" ").append(compound.getFirstChild().getText()).append(" ").append(controlExprText).append(";");
PerlFileImpl perlFile = PerlElementFactory.createFile(compound.getProject(), sb.toString());
PsiPerlStatementImpl[] statements = PsiTreeUtil.getChildrenOfType(perlFile, PsiPerlStatementImpl.class);
if (statements == null || statements.length == 0) {
return;
}
PsiElement container = compound.getParent();
if (container == null) {
return;
}
container.addRangeBefore(statements[0], statements[statements.length - 1], compound);
compound.delete();
}
use of com.perl5.lang.perl.psi.impl.PsiPerlStatementImpl in project Perl5-IDEA by Camelcade.
the class StatementToCompoundIntention method invoke.
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
PsiPerlStatementImpl statement = getStatement(element);
if (statement == null) {
return;
}
PsiPerlStatementModifier modifier = statement.getModifier();
if (modifier == null) {
return;
}
PsiElement keyword = modifier.getFirstChild();
if (keyword == null) {
return;
}
PsiPerlExpr modifierExpression = PsiTreeUtil.getChildOfType(modifier, PsiPerlExpr.class);
PsiPerlExpr valueExpression = modifierExpression instanceof PsiPerlParenthesisedExpr ? ((PsiPerlParenthesisedExpr) modifierExpression).getExpr() : modifierExpression;
String conditionText = valueExpression == null ? "" : valueExpression.getText();
TextRange modifierRangeInStatement = TextRange.from(modifier.getStartOffsetInParent(), modifier.getTextLength());
String statementText = modifierRangeInStatement.replace(statement.getText(), "");
StringBuilder newCode = new StringBuilder();
newCode.append(keyword.getText()).append("(").append(conditionText).append("){\n").append(statementText).append("\n}");
PerlFileImpl fakeFile = PerlElementFactory.createFile(project, newCode.toString());
PsiElement[] children = fakeFile.getChildren();
assert children.length == 1;
statement.replace(children[0]);
}
Aggregations