private Delta deduplicate(CompilationUnit root, ASTRewrite rewrite, Cause cause) { final List<ASTNode> nodes = cause.getAffectedNodes(); final int size = nodes.size(); final int cloneNumber = size == 0 ? size : size - 1; // minus the original declaration if (cloneNumber == 0) { throw new RuntimeException("calling deduplicate() when there are no detected clones"); } else if (cloneNumber >= 1) { // NOTE: THIS WORKS ONLY AT METHOD LEVEL, other forms of duplication will // will be ignored. // The strategy this code follows to perform deduplication is the following: // per duplicated method declaration, find all of its invocations. Then // rename each found invocation using the name of the original method declaration. // After that, remove the duplicated method declaration. if (AstUtil.isOfType(MethodDeclaration.class, nodes.get(0))) { final MethodDeclaration original = AstUtil.exactCast(MethodDeclaration.class, nodes.get(0)); final Iterable<ASTNode> rest = Iterables.skip(nodes, 1); for (ASTNode eachClone : rest) { final MethodDeclaration duplicate = AstUtil.exactCast(MethodDeclaration.class, eachClone); final MethodDeclaration copied = AstUtil.copySubtree(MethodDeclaration.class, root.getAST(), duplicate); final boolean sameReturn = sameReturnType(original, copied); if (!sameReturn) { // all or none. We don't do partial deduplication throw new RuntimeException( "automatic deduplication cannot be done on methods " + "with different return types; please consider " + "manual deduplication."); } final MethodInvocationVisitor invokesOfDuplication = new MethodInvocationVisitor(copied.getName()); root.accept(invokesOfDuplication); final Set<MethodInvocation> invokes = invokesOfDuplication.getMethodInvocations(); for (MethodInvocation each : invokes) { final MethodInvocation copiedInvoke = AstUtil.copySubtree(MethodInvocation.class, root.getAST(), each); copiedInvoke.setName(root.getAST().newSimpleName(original.getName().getIdentifier())); rewrite.replace(each, copiedInvoke, null); } rewrite.remove(duplicate, null); } } } return createDelta(root, rewrite); }
/** * Removes the current variable declaration from the AST and inserts it into the lowest possible * scope where the variable is first used. Returns the modification to the AST within a Change * object. */ private Change recordASTModifications() { AST ast = compilationUnit.getAST(); ASTRewrite rewriter = ASTRewrite.create(ast); // duplicate the original variable declaration in lower scope before getting rid of it VariableDeclarationStatement oldDeclaration = (VariableDeclarationStatement) variableVisitor.getDeclaration(); assert variableVisitor.getFirstAssignment() instanceof Assignment; Assignment variableAssignment = (Assignment) variableVisitor.getFirstAssignment(); ASTNode newScopeParent = variableAssignment.getParent().getParent(); String codeString = oldDeclaration.toString(); ASTNode newDeclaration = rewriter.createStringPlaceholder( codeString.substring(0, codeString.length() - 1), ASTNode.VARIABLE_DECLARATION_STATEMENT); ListRewrite listRewrite = rewriter.getListRewrite(newScopeParent, Block.STATEMENTS_PROPERTY); listRewrite.insertAt(newDeclaration, 0, null); // get rid of the higher scope declaration rewriter.remove(oldDeclaration, null); ICompilationUnit iCompUnit = method.getCompilationUnit(); final String description = "ReduceScopeOfVariable"; final String comment = "ReduceScopeOfVariable does blah..."; // record the change CompilationUnitChange change = new CompilationUnitChange("Reduce scope of variable", iCompUnit) { public ChangeDescriptor getDescriptor() { Map<Object, Object> arguments = new HashMap<Object, Object>(); arguments.put("method", method); arguments.put("var", varName); return new RefactoringChangeDescriptor( new ReduceScopeOfVariableDescriptor( method.getJavaProject().getElementName(), description, comment, arguments)); } }; try { change.setEdit(rewriter.rewriteAST()); } catch (Exception e) { } return change; }
// similar to // org.eclipse.jdt.internal.ui.text.correction.ModifierCorrectionSubProcessor.removeOverrideAnnotationProposal(..) public void removeDeprecatedAnnotation( IDocument document, ICompilationUnit cu, BodyDeclaration decl) { Annotation annot = findAnnotation(decl.modifiers()); if (annot != null) { ASTRewrite rewrite = ASTRewrite.create(annot.getAST()); rewrite.remove(annot, null); callASTRewriteCorrectionProposal(getDisplayString(), cu, rewrite, 6, getImage(), document); ITextViewer viewer = getViewer(JavaPlugin.getActivePage().getActiveEditor()); ITrackedNodePosition trackPos = rewrite.track(decl); if (trackPos != null && viewer != null) { viewer.setSelectedRange(trackPos.getStartPosition(), 0); } } }
@Override protected ASTRewrite getRewrite() throws CoreException { CompilationUnit targetAstRoot = ASTResolving.createQuickFixAST(getCompilationUnit(), null); createImportRewrite(targetAstRoot); ASTRewrite rewrite = ASTRewrite.create(targetAstRoot.getAST()); // Find the method declaration in the AST we just generated (the one that // the AST rewriter is hooked up to). MethodDeclaration rewriterAstMethodDecl = JavaASTUtils.findMethodDeclaration(targetAstRoot, methodDecl.resolveBinding().getKey()); if (rewriterAstMethodDecl == null) { return null; } // Remove the extra method declaration rewrite.remove(rewriterAstMethodDecl, null); return rewrite; }
public static void getRemoveJavadocTagProposals( IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) { ASTNode node = problem.getCoveringNode(context.getASTRoot()); while (node != null && !(node instanceof TagElement)) { node = node.getParent(); } if (node == null) { return; } ASTRewrite rewrite = ASTRewrite.create(node.getAST()); rewrite.remove(node, null); String label = CorrectionMessages.JavadocTagsSubProcessor_removetag_description; Image image = JavaPlugin.getDefault() .getWorkbench() .getSharedImages() .getImage(ISharedImages.IMG_TOOL_DELETE); proposals.add( new ASTRewriteCorrectionProposal( label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_TAG, image)); }
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); } }