Lines 55-60
Link Here
|
55 |
import org.eclipse.jdt.core.compiler.IProblem; |
55 |
import org.eclipse.jdt.core.compiler.IProblem; |
56 |
import org.eclipse.jdt.core.dom.AST; |
56 |
import org.eclipse.jdt.core.dom.AST; |
57 |
import org.eclipse.jdt.core.dom.ASTNode; |
57 |
import org.eclipse.jdt.core.dom.ASTNode; |
|
|
58 |
import org.eclipse.jdt.core.dom.ASTVisitor; |
58 |
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; |
59 |
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; |
59 |
import org.eclipse.jdt.core.dom.ArrayCreation; |
60 |
import org.eclipse.jdt.core.dom.ArrayCreation; |
60 |
import org.eclipse.jdt.core.dom.ArrayInitializer; |
61 |
import org.eclipse.jdt.core.dom.ArrayInitializer; |
Lines 87-92
Link Here
|
87 |
import org.eclipse.jdt.core.dom.Name; |
88 |
import org.eclipse.jdt.core.dom.Name; |
88 |
import org.eclipse.jdt.core.dom.ParenthesizedExpression; |
89 |
import org.eclipse.jdt.core.dom.ParenthesizedExpression; |
89 |
import org.eclipse.jdt.core.dom.PrimitiveType; |
90 |
import org.eclipse.jdt.core.dom.PrimitiveType; |
|
|
91 |
import org.eclipse.jdt.core.dom.ReturnStatement; |
90 |
import org.eclipse.jdt.core.dom.SimpleName; |
92 |
import org.eclipse.jdt.core.dom.SimpleName; |
91 |
import org.eclipse.jdt.core.dom.SimpleType; |
93 |
import org.eclipse.jdt.core.dom.SimpleType; |
92 |
import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
94 |
import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
Lines 116-121
Link Here
|
116 |
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; |
118 |
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; |
117 |
import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
119 |
import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
118 |
import org.eclipse.jdt.internal.corext.dom.Bindings; |
120 |
import org.eclipse.jdt.internal.corext.dom.Bindings; |
|
|
121 |
import org.eclipse.jdt.internal.corext.dom.GenericVisitor; |
119 |
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; |
122 |
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder; |
120 |
import org.eclipse.jdt.internal.corext.dom.Selection; |
123 |
import org.eclipse.jdt.internal.corext.dom.Selection; |
121 |
import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer; |
124 |
import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer; |
Lines 193-198
Link Here
|
193 |
|| getPickoutTypeFromMulticatchProposals(context, coveringNode, coveredNodes, null) |
196 |
|| getPickoutTypeFromMulticatchProposals(context, coveringNode, coveredNodes, null) |
194 |
|| getConvertToMultiCatchProposals(context, coveringNode, null) |
197 |
|| getConvertToMultiCatchProposals(context, coveringNode, null) |
195 |
|| getUnrollMultiCatchProposals(context, coveringNode, null) |
198 |
|| getUnrollMultiCatchProposals(context, coveringNode, null) |
|
|
199 |
|| getTryWithResourcesProposals(context, coveringNode, null) |
196 |
|| getRenameLocalProposals(context, coveringNode, null, null) |
200 |
|| getRenameLocalProposals(context, coveringNode, null, null) |
197 |
|| getRenameRefactoringProposal(context, coveringNode, null, null) |
201 |
|| getRenameRefactoringProposal(context, coveringNode, null, null) |
198 |
|| getAssignToVariableProposals(context, coveringNode, null, null) |
202 |
|| getAssignToVariableProposals(context, coveringNode, null, null) |
Lines 240-245
Link Here
|
240 |
getPickoutTypeFromMulticatchProposals(context, coveringNode, coveredNodes, resultingCollections); |
244 |
getPickoutTypeFromMulticatchProposals(context, coveringNode, coveredNodes, resultingCollections); |
241 |
getConvertToMultiCatchProposals(context, coveringNode, resultingCollections); |
245 |
getConvertToMultiCatchProposals(context, coveringNode, resultingCollections); |
242 |
getUnrollMultiCatchProposals(context, coveringNode, resultingCollections); |
246 |
getUnrollMultiCatchProposals(context, coveringNode, resultingCollections); |
|
|
247 |
getTryWithResourcesProposals(context, coveringNode, resultingCollections); |
243 |
getUnWrapProposals(context, coveringNode, resultingCollections); |
248 |
getUnWrapProposals(context, coveringNode, resultingCollections); |
244 |
getJoinVariableProposals(context, coveringNode, resultingCollections); |
249 |
getJoinVariableProposals(context, coveringNode, resultingCollections); |
245 |
getSplitVariableProposals(context, coveringNode, resultingCollections); |
250 |
getSplitVariableProposals(context, coveringNode, resultingCollections); |
Lines 1555-1560
Link Here
|
1555 |
return true; |
1560 |
return true; |
1556 |
} |
1561 |
} |
1557 |
|
1562 |
|
|
|
1563 |
private static boolean getTryWithResourcesProposals(IInvocationContext context, ASTNode covering, Collection<ICommandAccess> resultingCollections) { |
1564 |
if (!JavaModelUtil.is17OrHigher(context.getCompilationUnit().getJavaProject())) |
1565 |
return false; |
1566 |
|
1567 |
//TODO: should the user be able to select more than one resource and enclose in one twr ? This should be doable |
1568 |
ASTNode node= covering; |
1569 |
while (!(node instanceof Statement) && node != null) { |
1570 |
node= node.getParent(); |
1571 |
} |
1572 |
|
1573 |
if (!(node instanceof VariableDeclarationStatement)) |
1574 |
return false; |
1575 |
|
1576 |
VariableDeclarationStatement variableDeclarationStatement= (VariableDeclarationStatement) node; |
1577 |
Type type= variableDeclarationStatement.getType(); |
1578 |
ITypeBinding typeBinding= type.resolveBinding(); |
1579 |
if (typeBinding == null) { |
1580 |
return false; |
1581 |
} |
1582 |
String autocloseable= "java.lang.AutoCloseable"; //$NON-NLS-1$ |
1583 |
ITypeBinding typeInHierarchy= Bindings.findTypeInHierarchy(typeBinding, autocloseable); |
1584 |
if (typeInHierarchy == null) |
1585 |
return false; |
1586 |
|
1587 |
MethodDeclaration methodDeclaration= ASTResolving.findParentMethodDeclaration(variableDeclarationStatement); |
1588 |
List<VariableDeclarationFragment> fragments= variableDeclarationStatement.fragments(); |
1589 |
VariableDeclarationFragment variableDeclarationFragment= fragments.get(0); //TODO: More than one fragment ? |
1590 |
|
1591 |
VariableReferenceAnalyzer analyzer= new VariableReferenceAnalyzer(variableDeclarationFragment.resolveBinding()); |
1592 |
methodDeclaration.accept(analyzer); |
1593 |
if (!analyzer.canProduceQuickAssist()) |
1594 |
return false; |
1595 |
|
1596 |
if (resultingCollections == null) { |
1597 |
return true; |
1598 |
} |
1599 |
|
1600 |
TryStatement tryStatement= analyzer.getTryStatement(); |
1601 |
List<MethodInvocation> closeInvocations= analyzer.getCloseInvocations(); |
1602 |
if (tryStatement != null) { |
1603 |
AST ast= node.getAST(); |
1604 |
ASTRewrite rewrite= ASTRewrite.create(ast); |
1605 |
ListRewrite listRewrite= rewrite.getListRewrite(tryStatement, TryStatement.RESOURCES_PROPERTY); |
1606 |
|
1607 |
VariableDeclarationExpression newVariableDeclarationExpression= ast.newVariableDeclarationExpression((VariableDeclarationFragment) rewrite.createCopyTarget(variableDeclarationFragment)); |
1608 |
newVariableDeclarationExpression.setType((Type) rewrite.createCopyTarget(variableDeclarationStatement.getType())); |
1609 |
|
1610 |
listRewrite.insertLast(newVariableDeclarationExpression, null); |
1611 |
rewrite.remove(variableDeclarationStatement, null); |
1612 |
|
1613 |
if (closeInvocations != null) |
1614 |
removeCloseInvocations(closeInvocations, rewrite); |
1615 |
|
1616 |
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
1617 |
String label= Messages.format(CorrectionMessages.QuickAssistProcessor_addresourcetotry_description, variableDeclarationFragment.getName().getIdentifier()); |
1618 |
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 6, image); |
1619 |
resultingCollections.add(proposal); |
1620 |
} else { |
1621 |
AST ast= node.getAST(); |
1622 |
ASTRewrite rewrite= ASTRewrite.create(ast); |
1623 |
|
1624 |
TryStatement newTryStatement= ast.newTryStatement(); |
1625 |
List<ASTNode> nodes= analyzer.getReferences(); |
1626 |
|
1627 |
ASTNode start= ASTResolving.findParentStatement(nodes.get(0)); |
1628 |
ASTNode end= ASTResolving.findParentStatement(nodes.get(nodes.size() - 1)); |
1629 |
|
1630 |
ListRewrite tryResourcesListRewrite= rewrite.getListRewrite(newTryStatement, TryStatement.RESOURCES_PROPERTY); |
1631 |
VariableDeclarationExpression newVariableDeclarationExpression= ast.newVariableDeclarationExpression((VariableDeclarationFragment) rewrite.createCopyTarget(variableDeclarationFragment)); |
1632 |
newVariableDeclarationExpression.setType((Type) rewrite.createCopyTarget(variableDeclarationStatement.getType())); |
1633 |
tryResourcesListRewrite.insertLast(newVariableDeclarationExpression, null); |
1634 |
|
1635 |
ListRewrite tryStatementsListRewrite= rewrite.getListRewrite(newTryStatement.getBody(), Block.STATEMENTS_PROPERTY); |
1636 |
MethodDeclaration parentMethodDeclaration= ASTResolving.findParentMethodDeclaration(node); |
1637 |
ArrayList<ASTNode> coveredNodes= getCoveredNodes(start.getStartPosition(), end.getStartPosition() + end.getLength(), parentMethodDeclaration); |
1638 |
|
1639 |
if (closeInvocations != null) |
1640 |
removeCloseInvocations(closeInvocations, rewrite); |
1641 |
|
1642 |
if (coveredNodes.size() >= 1) { |
1643 |
ListRewrite bodyStatementsListRewrite= rewrite.getListRewrite(coveredNodes.get(1).getParent(), (ChildListPropertyDescriptor) coveredNodes.get(1).getLocationInParent()); |
1644 |
ASTNode toMove= bodyStatementsListRewrite.createMoveTarget(coveredNodes.get(1), coveredNodes.get(coveredNodes.size() - 1), newTryStatement, null); |
1645 |
tryStatementsListRewrite.insertLast(toMove, null); |
1646 |
} |
1647 |
|
1648 |
rewrite.remove(variableDeclarationStatement, null); |
1649 |
|
1650 |
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); |
1651 |
String label= Messages.format(CorrectionMessages.QuickAssistProcessor_surroundresourcewithtry_description, variableDeclarationFragment.getName().getIdentifier()); |
1652 |
ASTRewriteCorrectionProposal proposal= new ASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, 6, image); |
1653 |
resultingCollections.add(proposal); |
1654 |
} |
1655 |
return true; |
1656 |
} |
1657 |
|
1658 |
private static void removeCloseInvocations(List<MethodInvocation> closeInvocations, ASTRewrite rewrite) { |
1659 |
for (Iterator<MethodInvocation> iterator= closeInvocations.iterator(); iterator.hasNext();) { |
1660 |
MethodInvocation closeInvocation= iterator.next(); |
1661 |
IfStatement parentif= (IfStatement) ASTResolving.findAncestor(closeInvocation, ASTNode.IF_STATEMENT); |
1662 |
Statement parentStatement= ASTResolving.findParentStatement(closeInvocation); |
1663 |
if (parentif != null) { |
1664 |
Statement thenStatement= parentif.getThenStatement(); |
1665 |
if (thenStatement instanceof Block) { |
1666 |
Block block= (Block) thenStatement; |
1667 |
if (block.statements().size() > 1) { |
1668 |
rewrite.remove(parentStatement, null); |
1669 |
} else { |
1670 |
rewrite.remove(parentif, null); |
1671 |
} |
1672 |
} else { |
1673 |
rewrite.remove(parentif, null); |
1674 |
} |
1675 |
} else { |
1676 |
rewrite.remove(parentStatement, null); |
1677 |
} |
1678 |
} |
1679 |
} |
1680 |
|
1681 |
private static ArrayList<ASTNode> getCoveredNodes(final int selectionBegin, final int selectionEnd, ASTNode coveringNode) { |
1682 |
final ArrayList<ASTNode> coveredNodes= new ArrayList<ASTNode>(); |
1683 |
coveringNode.accept(new GenericVisitor() { |
1684 |
@Override |
1685 |
protected boolean visitNode(ASTNode node) { |
1686 |
int nodeStart= node.getStartPosition(); |
1687 |
int nodeEnd= nodeStart + node.getLength(); |
1688 |
// if node does not intersects with selection, don't visit children |
1689 |
if (nodeEnd < selectionBegin || selectionEnd < nodeStart) { |
1690 |
return false; |
1691 |
} |
1692 |
// if node is covered, we don't need to visit children |
1693 |
if (isCovered(node)) { |
1694 |
ASTNode parent= node.getParent(); |
1695 |
if (parent == null || !isCovered(parent)) { |
1696 |
coveredNodes.add(node); |
1697 |
return false; |
1698 |
} |
1699 |
} |
1700 |
// if node only partly intersects with selection, we try to find fully covered children |
1701 |
return true; |
1702 |
} |
1703 |
|
1704 |
private boolean isCovered(ASTNode node) { |
1705 |
int begin= node.getStartPosition(); |
1706 |
int end= begin + node.getLength(); |
1707 |
return (begin >= selectionBegin && end <= selectionEnd) || (begin <= selectionBegin && end <= selectionEnd) || (begin >= selectionBegin && end >= selectionEnd); |
1708 |
} |
1709 |
}); |
1710 |
return coveredNodes; |
1711 |
} |
1712 |
|
1713 |
static class VariableReferenceAnalyzer extends ASTVisitor { |
1714 |
private List<ASTNode> fReferences= null; |
1715 |
private List<MethodInvocation> fCloseInvocations= null; |
1716 |
private TryStatement fTryStatement= null; |
1717 |
private boolean fIsEnclosedInOneTryStatement= true; |
1718 |
private IVariableBinding fBinding; |
1719 |
private boolean fCanProduceQuickAssist= true; |
1720 |
|
1721 |
public VariableReferenceAnalyzer(IVariableBinding binding) { |
1722 |
fBinding= binding; |
1723 |
} |
1724 |
|
1725 |
public List<ASTNode> getReferences() { |
1726 |
return fReferences; |
1727 |
} |
1728 |
|
1729 |
public List<MethodInvocation> getCloseInvocations() { |
1730 |
return fCloseInvocations; |
1731 |
} |
1732 |
|
1733 |
public TryStatement getTryStatement() { |
1734 |
return fTryStatement; |
1735 |
} |
1736 |
|
1737 |
public boolean canProduceQuickAssist() { |
1738 |
return fCanProduceQuickAssist; |
1739 |
} |
1740 |
|
1741 |
@Override |
1742 |
public boolean visit(SimpleName node) { |
1743 |
if (fReferences == null) { |
1744 |
fReferences= new ArrayList<ASTNode>(); |
1745 |
} |
1746 |
if (Bindings.equals(fBinding, node.resolveBinding())) { |
1747 |
fReferences.add(node); |
1748 |
|
1749 |
StructuralPropertyDescriptor locationInParent= node.getLocationInParent(); |
1750 |
if (locationInParent instanceof ChildListPropertyDescriptor && locationInParent != InfixExpression.EXTENDED_OPERANDS_PROPERTY) { |
1751 |
// e.g. argument lists of MethodInvocation, ClassInstanceCreation ... |
1752 |
fCanProduceQuickAssist= false; |
1753 |
} |
1754 |
|
1755 |
if (locationInParent == ReturnStatement.EXPRESSION_PROPERTY || locationInParent == Assignment.LEFT_HAND_SIDE_PROPERTY) { |
1756 |
fCanProduceQuickAssist= false; |
1757 |
} |
1758 |
|
1759 |
ASTNode tryStatement= ASTResolving.findAncestor(node, ASTNode.TRY_STATEMENT); |
1760 |
if (tryStatement != null) { |
1761 |
if (fTryStatement == null && fIsEnclosedInOneTryStatement) { |
1762 |
fTryStatement= (TryStatement) tryStatement; |
1763 |
} else if (fTryStatement != tryStatement) { |
1764 |
fIsEnclosedInOneTryStatement= false; |
1765 |
fTryStatement= null; |
1766 |
} |
1767 |
} |
1768 |
|
1769 |
ASTNode parent= node.getParent(); |
1770 |
if (parent instanceof MethodInvocation && node.getLocationInParent() == MethodInvocation.EXPRESSION_PROPERTY) { |
1771 |
MethodInvocation methodInvocation= (MethodInvocation) parent; |
1772 |
IMethodBinding methodBinding= methodInvocation.resolveMethodBinding(); |
1773 |
if (methodBinding != null) { |
1774 |
if ("close".equals(methodBinding.getName())) { //$NON-NLS-1$ |
1775 |
if (fCloseInvocations == null) |
1776 |
fCloseInvocations= new ArrayList<MethodInvocation>(); |
1777 |
fCloseInvocations.add(methodInvocation); |
1778 |
} |
1779 |
} |
1780 |
} |
1781 |
} |
1782 |
return false; |
1783 |
} |
1784 |
} |
1785 |
|
1558 |
private static boolean getRenameLocalProposals(IInvocationContext context, ASTNode node, IProblemLocation[] locations, Collection<ICommandAccess> resultingCollections) { |
1786 |
private static boolean getRenameLocalProposals(IInvocationContext context, ASTNode node, IProblemLocation[] locations, Collection<ICommandAccess> resultingCollections) { |
1559 |
if (!(node instanceof SimpleName)) { |
1787 |
if (!(node instanceof SimpleName)) { |
1560 |
return false; |
1788 |
return false; |