private ITypeBinding[] computeTypeVariables(ITypeBinding[] bindings) { Selection selection = getSelection(); Set<ITypeBinding> result = new HashSet<>(); // first remove all type variables that come from outside of the method // or are covered by the selection CompilationUnit compilationUnit = (CompilationUnit) fEnclosingBodyDeclaration.getRoot(); for (int i = 0; i < bindings.length; i++) { ASTNode decl = compilationUnit.findDeclaringNode(bindings[i]); if (decl == null || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration)) result.add(bindings[i]); } // all all type variables which are needed since a local variable uses it for (int i = 0; i < fArguments.length; i++) { IVariableBinding arg = fArguments[i]; ITypeBinding type = arg.getType(); if (type != null && type.isTypeVariable()) { ASTNode decl = compilationUnit.findDeclaringNode(type); if (decl == null || (!selection.covers(decl) && decl.getParent() instanceof MethodDeclaration)) result.add(type); } } return result.toArray(new ITypeBinding[result.size()]); }
private IVariableBinding[] removeSelectedDeclarations(IVariableBinding[] bindings) { List<IVariableBinding> result = new ArrayList<>(bindings.length); Selection selection = getSelection(); for (int i = 0; i < bindings.length; i++) { ASTNode decl = ((CompilationUnit) fEnclosingBodyDeclaration.getRoot()).findDeclaringNode(bindings[i]); if (!selection.covers(decl)) result.add(bindings[i]); } return result.toArray(new IVariableBinding[result.size()]); }
@Override public boolean visit(MethodDeclaration node) { Block body = node.getBody(); if (body == null) return false; Selection selection = getSelection(); int nodeStart = body.getStartPosition(); int nodeExclusiveEnd = nodeStart + body.getLength(); // if selection node inside of the method body ignore method if (!(nodeStart < selection.getOffset() && selection.getExclusiveEnd() < nodeExclusiveEnd)) return false; return super.visit(node); }
public static SurroundWithTryCatchRefactoring create( ICompilationUnit cu, ITextSelection selection, boolean isMultiCatch) { return new SurroundWithTryCatchRefactoring( cu, Selection.createFromStartLength(selection.getOffset(), selection.getLength()), isMultiCatch); }
/* non Java-doc * @see IRefactoring#createChange(IProgressMonitor) */ @Override public Change createChange(IProgressMonitor pm) throws CoreException { final String NN = ""; // $NON-NLS-1$ if (pm == null) pm = new NullProgressMonitor(); pm.beginTask(NN, 2); try { final CompilationUnitChange result = new CompilationUnitChange(getName(), fCUnit); if (fLeaveDirty) result.setSaveMode(TextFileChange.LEAVE_DIRTY); MultiTextEdit root = new MultiTextEdit(); result.setEdit(root); fRewriter = ASTRewrite.create(fAnalyzer.getEnclosingBodyDeclaration().getAST()); fRewriter.setTargetSourceRangeComputer( new SelectionAwareSourceRangeComputer( fAnalyzer.getSelectedNodes(), fCUnit.getBuffer(), fSelection.getOffset(), fSelection.getLength())); fImportRewrite = StubUtility.createImportRewrite(fRootNode, true); fLinkedProposalModel = new LinkedProposalModel(); fScope = CodeScopeBuilder.perform(fAnalyzer.getEnclosingBodyDeclaration(), fSelection) .findScope(fSelection.getOffset(), fSelection.getLength()); fScope.setCursor(fSelection.getOffset()); fSelectedNodes = fAnalyzer.getSelectedNodes(); createTryCatchStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator()); if (fImportRewrite.hasRecordedChanges()) { TextEdit edit = fImportRewrite.rewriteImports(null); root.addChild(edit); result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit})); } TextEdit change = fRewriter.rewriteAST(); root.addChild(change); result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change})); return result; } finally { pm.done(); } }
@Override public boolean visit(LambdaExpression node) { Selection selection = getSelection(); int selectionStart = selection.getOffset(); int selectionExclusiveEnd = selection.getExclusiveEnd(); int lambdaStart = node.getStartPosition(); int lambdaExclusiveEnd = lambdaStart + node.getLength(); ASTNode body = node.getBody(); int bodyStart = body.getStartPosition(); int bodyExclusiveEnd = bodyStart + body.getLength(); boolean isValidSelection = false; if ((body instanceof Block) && (bodyStart < selectionStart && selectionExclusiveEnd <= bodyExclusiveEnd)) { // if selection is inside lambda body's block isValidSelection = true; } else if (body instanceof Expression) { try { TokenScanner scanner = new TokenScanner(fCUnit); int arrowExclusiveEnd = scanner.getTokenEndOffset(ITerminalSymbols.TokenNameARROW, lambdaStart); if (selectionStart >= arrowExclusiveEnd) { isValidSelection = true; } } catch (CoreException e) { // ignore } } if (selectionStart <= lambdaStart && selectionExclusiveEnd >= lambdaExclusiveEnd) { // if selection covers the lambda node isValidSelection = true; } if (!isValidSelection) { return false; } return super.visit(node); }
private void computeOutput(RefactoringStatus status) { // First find all writes inside the selection. FlowContext flowContext = new FlowContext(0, fMaxVariableId + 1); flowContext.setConsiderAccessMode(true); flowContext.setComputeMode(FlowContext.RETURN_VALUES); FlowInfo returnInfo = new InOutFlowAnalyzer(flowContext).perform(getSelectedNodes()); IVariableBinding[] returnValues = returnInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN); // Compute a selection that exactly covers the selected nodes IRegion region = getSelectedNodeRange(); Selection selection = Selection.createFromStartLength(region.getOffset(), region.getLength()); List<IVariableBinding> localReads = new ArrayList<>(); flowContext.setComputeMode(FlowContext.ARGUMENTS); FlowInfo argInfo = new InputFlowAnalyzer(flowContext, selection, true).perform(fEnclosingBodyDeclaration); IVariableBinding[] reads = argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN); outer: for (int i = 0; i < returnValues.length && localReads.size() < returnValues.length; i++) { IVariableBinding binding = returnValues[i]; for (int x = 0; x < reads.length; x++) { if (reads[x] == binding) { localReads.add(binding); fReturnValue = binding; continue outer; } } } switch (localReads.size()) { case 0: fReturnValue = null; break; case 1: break; default: fReturnValue = null; StringBuffer affectedLocals = new StringBuffer(); for (int i = 0; i < localReads.size(); i++) { IVariableBinding binding = localReads.get(i); String bindingName = BindingLabelProvider.getBindingLabel( binding, BindingLabelProvider.DEFAULT_TEXTFLAGS | JavaElementLabels.F_PRE_TYPE_SIGNATURE); affectedLocals.append(bindingName); if (i != localReads.size() - 1) { affectedLocals.append('\n'); } } String message = MessageFormat.format( RefactoringCoreMessages.ExtractMethodAnalyzer_assignments_to_local, new Object[] {affectedLocals.toString()}); status.addFatalError(message, JavaStatusContext.create(fCUnit, getSelection())); return; } List<IVariableBinding> callerLocals = new ArrayList<>(5); FlowInfo localInfo = new InputFlowAnalyzer(flowContext, selection, false).perform(fEnclosingBodyDeclaration); IVariableBinding[] writes = localInfo.get(flowContext, FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN); for (int i = 0; i < writes.length; i++) { IVariableBinding write = writes[i]; if (getSelection().covers(ASTNodes.findDeclaration(write, fEnclosingBodyDeclaration))) callerLocals.add(write); } fCallerLocals = callerLocals.toArray(new IVariableBinding[callerLocals.size()]); if (fReturnValue != null && getSelection().covers(ASTNodes.findDeclaration(fReturnValue, fEnclosingBodyDeclaration))) fReturnLocal = fReturnValue; }
private void createTryCatchStatement(org.eclipse.jdt.core.IBuffer buffer, String lineDelimiter) throws CoreException { List<Statement> result = new ArrayList<>(1); TryStatement tryStatement = getAST().newTryStatement(); ITypeBinding[] exceptions = fAnalyzer.getExceptions(); ImportRewriteContext context = new ContextSensitiveImportRewriteContext( fAnalyzer.getEnclosingBodyDeclaration(), fImportRewrite); if (!fIsMultiCatch) { for (int i = 0; i < exceptions.length; i++) { ITypeBinding exception = exceptions[i]; CatchClause catchClause = getAST().newCatchClause(); tryStatement.catchClauses().add(catchClause); SingleVariableDeclaration decl = getAST().newSingleVariableDeclaration(); String varName = StubUtility.getExceptionVariableName(fCUnit.getJavaProject()); String name = fScope.createName(varName, false); decl.setName(getAST().newSimpleName(name)); Type type = fImportRewrite.addImport(exception, getAST(), context); decl.setType(type); catchClause.setException(decl); Statement st = getCatchBody(ASTNodes.getQualifiedTypeName(type), name, lineDelimiter); if (st != null) { catchClause.getBody().statements().add(st); } fLinkedProposalModel .getPositionGroup(GROUP_EXC_TYPE + i, true) .addPosition(fRewriter.track(decl.getType()), i == 0); fLinkedProposalModel .getPositionGroup(GROUP_EXC_NAME + i, true) .addPosition(fRewriter.track(decl.getName()), false); } } else { List<ITypeBinding> filteredExceptions = filterSubtypeExceptions(exceptions); CatchClause catchClause = getAST().newCatchClause(); SingleVariableDeclaration decl = getAST().newSingleVariableDeclaration(); String varName = StubUtility.getExceptionVariableName(fCUnit.getJavaProject()); String name = fScope.createName(varName, false); decl.setName(getAST().newSimpleName(name)); UnionType unionType = getAST().newUnionType(); List<Type> types = unionType.types(); int i = 0; for (ITypeBinding exception : filteredExceptions) { Type type = fImportRewrite.addImport(exception, getAST(), context); types.add(type); fLinkedProposalModel .getPositionGroup(GROUP_EXC_TYPE + i, true) .addPosition(fRewriter.track(type), i == 0); i++; } decl.setType(unionType); catchClause.setException(decl); fLinkedProposalModel .getPositionGroup(GROUP_EXC_NAME + 0, true) .addPosition(fRewriter.track(decl.getName()), false); Statement st = getCatchBody("Exception", name, lineDelimiter); // $NON-NLS-1$ if (st != null) { catchClause.getBody().statements().add(st); } tryStatement.catchClauses().add(catchClause); } List<ASTNode> variableDeclarations = getSpecialVariableDeclarationStatements(); ListRewrite statements = fRewriter.getListRewrite(tryStatement.getBody(), Block.STATEMENTS_PROPERTY); boolean selectedNodeRemoved = false; ASTNode expressionStatement = null; for (int i = 0; i < fSelectedNodes.length; i++) { ASTNode node = fSelectedNodes[i]; if (node instanceof VariableDeclarationStatement && variableDeclarations.contains(node)) { AST ast = getAST(); VariableDeclarationStatement statement = (VariableDeclarationStatement) node; // Create a copy and remove the initializer VariableDeclarationStatement copy = (VariableDeclarationStatement) ASTNode.copySubtree(ast, statement); List<IExtendedModifier> modifiers = copy.modifiers(); for (Iterator<IExtendedModifier> iter = modifiers.iterator(); iter.hasNext(); ) { IExtendedModifier modifier = iter.next(); if (modifier.isModifier() && Modifier.isFinal(((Modifier) modifier).getKeyword().toFlagValue())) { iter.remove(); } } List<VariableDeclarationFragment> fragments = copy.fragments(); for (Iterator<VariableDeclarationFragment> iter = fragments.iterator(); iter.hasNext(); ) { VariableDeclarationFragment fragment = iter.next(); fragment.setInitializer(null); } CompilationUnit root = (CompilationUnit) statement.getRoot(); int extendedStart = root.getExtendedStartPosition(statement); // we have a leading comment and the comment is covered by the selection if (extendedStart != statement.getStartPosition() && extendedStart >= fSelection.getOffset()) { String commentToken = buffer.getText(extendedStart, statement.getStartPosition() - extendedStart); commentToken = Strings.trimTrailingTabsAndSpaces(commentToken); Type type = statement.getType(); String typeName = buffer.getText(type.getStartPosition(), type.getLength()); copy.setType( (Type) fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType())); } result.add(copy); // convert the fragments into expression statements fragments = statement.fragments(); if (!fragments.isEmpty()) { List<ExpressionStatement> newExpressionStatements = new ArrayList<>(); for (Iterator<VariableDeclarationFragment> iter = fragments.iterator(); iter.hasNext(); ) { VariableDeclarationFragment fragment = iter.next(); Expression initializer = fragment.getInitializer(); if (initializer != null) { Assignment assignment = ast.newAssignment(); assignment.setLeftHandSide( (Expression) fRewriter.createCopyTarget(fragment.getName())); assignment.setRightHandSide((Expression) fRewriter.createCopyTarget(initializer)); newExpressionStatements.add(ast.newExpressionStatement(assignment)); } } if (!newExpressionStatements.isEmpty()) { if (fSelectedNodes.length == 1) { expressionStatement = fRewriter.createGroupNode( newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])); } else { fRewriter.replace( statement, fRewriter.createGroupNode( newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])), null); } } else { fRewriter.remove(statement, null); selectedNodeRemoved = true; } } else { fRewriter.remove(statement, null); selectedNodeRemoved = true; } } } result.add(tryStatement); ASTNode replacementNode; if (result.size() == 1) { replacementNode = result.get(0); } else { replacementNode = fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()])); } if (fSelectedNodes.length == 1) { ASTNode selectedNode = fSelectedNodes[0]; if (selectedNode instanceof MethodReference) { MethodReference methodReference = (MethodReference) selectedNode; IMethodBinding functionalMethod = QuickAssistProcessor.getFunctionalMethodForMethodReference(methodReference); // functionalMethod is non-null and non-generic. See // ExceptionAnalyzer.handleMethodReference(MethodReference node). Assert.isTrue(functionalMethod != null && !functionalMethod.isGenericMethod()); LambdaExpression lambda = QuickAssistProcessor.convertMethodRefernceToLambda( methodReference, functionalMethod, fRootNode, fRewriter, null, true); ASTNode statementInBlock = (ASTNode) ((Block) lambda.getBody()).statements().get(0); fRewriter.replace(statementInBlock, replacementNode, null); statements.insertLast(statementInBlock, null); return; } LambdaExpression enclosingLambda = ASTResolving.findEnclosingLambdaExpression(selectedNode); if (enclosingLambda != null && selectedNode.getLocationInParent() == LambdaExpression.BODY_PROPERTY && enclosingLambda.resolveMethodBinding() != null) { QuickAssistProcessor.changeLambdaBodyToBlock(enclosingLambda, getAST(), fRewriter); Block blockBody = (Block) fRewriter.get(enclosingLambda, LambdaExpression.BODY_PROPERTY); ASTNode statementInBlock = (ASTNode) blockBody.statements().get(0); fRewriter.replace(statementInBlock, replacementNode, null); statements.insertLast(statementInBlock, null); return; } if (expressionStatement != null) { statements.insertLast(expressionStatement, null); } else { if (!selectedNodeRemoved) statements.insertLast(fRewriter.createMoveTarget(selectedNode), null); } fRewriter.replace(selectedNode, replacementNode, null); } else { ListRewrite source = fRewriter.getListRewrite( fSelectedNodes[0].getParent(), (ChildListPropertyDescriptor) fSelectedNodes[0].getLocationInParent()); ASTNode toMove = source.createMoveTarget( fSelectedNodes[0], fSelectedNodes[fSelectedNodes.length - 1], replacementNode, null); statements.insertLast(toMove, null); } }
public static SurroundWithTryCatchRefactoring create( ICompilationUnit cu, int offset, int length, boolean isMultiCatch) { return new SurroundWithTryCatchRefactoring( cu, Selection.createFromStartLength(offset, length), isMultiCatch); }