private SourcePattern getSourcePattern(final SourceRange partRange) { String originalSource = utils.getText(partRange.getOffset(), partRange.getLength()); final SourcePattern pattern = new SourcePattern(); final List<ReplaceEdit> replaceEdits = Lists.newArrayList(); unitNode.accept( new ASTVisitor<Void>() { @Override public Void visitIdentifier(DartIdentifier node) { SourceRange nodeRange = SourceRangeFactory.create(node); if (SourceRangeUtils.covers(partRange, nodeRange)) { VariableElement variableElement = ASTNodes.getVariableOrParameterElement(node); if (variableElement != null) { String originalName = variableElement.getName(); String patternName = pattern.originalToPatternNames.get(originalName); if (patternName == null) { patternName = "__dartEditorVariable" + pattern.originalToPatternNames.size(); pattern.originalToPatternNames.put(originalName, patternName); } replaceEdits.add( new ReplaceEdit( nodeRange.getOffset() - partRange.getOffset(), nodeRange.getLength(), patternName)); } } return null; } }); pattern.patternSource = ExtractUtils.applyReplaceEdits(originalSource, replaceEdits); return pattern; }
/** @return the selected {@link DartExpression} source, with applying new parameter names. */ private String getMethodBodySource() { String source = utils.getText(selectionStart, selectionLength); // prepare ReplaceEdit operators to replace variables with parameters List<ReplaceEdit> replaceEdits = Lists.newArrayList(); for (Entry<String, List<SourceRange>> entry : selectionParametersToRanges.entrySet()) { String name = entry.getKey(); for (ParameterInfo parameter : parameters) { if (StringUtils.equals(name, parameter.getOldName())) { for (SourceRange range : entry.getValue()) { replaceEdits.add( new ReplaceEdit( range.getOffset() - selectionStart, range.getLength(), parameter.getNewName())); } } } } // apply replacements source = ExtractUtils.applyReplaceEdits(source, replaceEdits); // change indentation if (selectionStatements != null) { String eol = utils.getEndOfLine(); String selectionIndent = utils.getNodePrefix(selectionStatements.get(0)); String targetIndent = utils.getNodePrefix(parentMember) + " "; String[] lines = StringUtils.splitPreserveAllTokens(source, eol); StringBuilder sb = new StringBuilder(); for (int i = 0; i < lines.length; i++) { String line = lines[i]; line = targetIndent + StringUtils.removeStart(line, selectionIndent); sb.append(line); sb.append(eol); } source = sb.toString(); source = StringUtils.stripEnd(source, null); source += eol; } // done return source; }
/** * Checks if {@link #selectionRange} selects {@link DartExpression} or set of {@link * DartStatement}s which can be extracted, and location in AST allows extracting. */ private RefactoringStatus checkSelection(IProgressMonitor pm) throws CoreException { Selection selection = Selection.createFromStartLength(selectionStart, selectionLength); selectionAnalyzer = new ExtractMethodAnalyzer(unit, selection); unitNode.accept(selectionAnalyzer); // may be fatal error { RefactoringStatus status = selectionAnalyzer.getStatus(); if (status.hasFatalError()) { return status; } } // update selection selectionLength = selectionAnalyzer.getSelectionExclusiveEnd() - selectionStart; selectionRange = SourceRangeFactory.forStartLength(selectionStart, selectionLength); // check selected nodes DartNode[] selectedNodes = selectionAnalyzer.getSelectedNodes(); if (selectedNodes.length > 0) { parentMember = ASTNodes.getParent(selectionAnalyzer.getLastCoveringNode(), DartClassMember.class); // single expression selected if (selectedNodes.length == 1 && !utils.rangeIncludesNonWhitespaceOutsideNode( selectionRange, selectionAnalyzer.getFirstSelectedNode())) { DartNode selectedNode = selectionAnalyzer.getFirstSelectedNode(); if (selectedNode instanceof DartExpression) { selectionExpression = (DartExpression) selectedNode; return new RefactoringStatus(); } } // statements selected { List<DartStatement> selectedStatements = Lists.newArrayList(); for (DartNode selectedNode : selectedNodes) { if (selectedNode instanceof DartStatement) { selectedStatements.add((DartStatement) selectedNode); } } if (selectedStatements.size() == selectedNodes.length) { selectionStatements = selectedStatements; return new RefactoringStatus(); } } } // invalid selection return RefactoringStatus.createFatalErrorStatus( RefactoringCoreMessages.ExtractMethodAnalyzer_single_expression_or_set); }
@Override public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { try { pm.beginTask("", 4); // $NON-NLS-1$ RefactoringStatus result = new RefactoringStatus(); // prepare AST utils = new ExtractUtils(unit); unitNode = utils.getUnitNode(); pm.worked(1); // check selection result.merge(checkSelection(new SubProgressMonitor(pm, 3))); if (result.hasFatalError()) { return result; } // prepare parts result.merge(initializeParameters()); initializeOccurrences(); // done return result; } finally { pm.done(); } }
@Override public Change createChange(IProgressMonitor pm) throws CoreException { pm.beginTask("", 1 + occurrences.size()); // $NON-NLS-1$ try { // configure Change { change = new CompilationUnitChange(unit.getElementName(), unit); change.setEdit(new MultiTextEdit()); change.setKeepPreviewEdits(true); } // replace occurrences with method invocation for (Occurrence occurence : occurrences) { pm.worked(1); SourceRange range = occurence.range; // may be replacement of duplicates disabled if (!replaceAllOccurrences && !occurence.isSelection) { continue; } // prepare invocation source String invocationSource; { StringBuilder sb = new StringBuilder(); // may be returns value if (returnVariable != null) { String varTypeName = ExtractUtils.getTypeSource(returnVariable.getType()); String originalName = returnVariable.getName(); String occurrenceName = occurence.parameterOldToOccurrenceName.get(originalName); if (varTypeName.equals("dynamic")) { sb.append("var "); } else { sb.append(varTypeName); sb.append(" "); } sb.append(occurrenceName); sb.append(" = "); } // invocation itself sb.append(methodName); sb.append("("); boolean firstParameter = true; for (ParameterInfo parameter : parameters) { // may be comma if (firstParameter) { firstParameter = false; } else { sb.append(", "); } // argument name { String parameterOldName = parameter.getOldName(); String argumentName = occurence.parameterOldToOccurrenceName.get(parameterOldName); sb.append(argumentName); } } sb.append(")"); invocationSource = sb.toString(); // statements as extracted with their ";", so add new one after invocation if (selectionStatements != null) { invocationSource += ";"; } } // add replace edit TextEdit edit = new ReplaceEdit(range.getOffset(), range.getLength(), invocationSource); change.addEdit(edit); String msg = Messages.format( occurence.isSelection ? RefactoringCoreMessages.ExtractMethodRefactoring_substitute_with_call : RefactoringCoreMessages.ExtractMethodRefactoring_duplicates_single, methodName); change.addTextEditGroup(new TextEditGroup(msg, edit)); } // add method declaration { // prepare environment String prefix = utils.getNodePrefix(parentMember); String eol = utils.getEndOfLine(); // prepare annotations String annotations = ""; { // may be "static" if (staticContext) { annotations = "static "; } } // prepare declaration source String declarationSource = null; { String returnExpressionSource = getMethodBodySource(); // expression if (selectionExpression != null) { // add return type String returnTypeName = ExtractUtils.getTypeSource(selectionExpression); if (returnTypeName != null && !returnTypeName.equals("dynamic")) { annotations += returnTypeName + " "; } // just return expression declarationSource = annotations + getSignature() + " => " + returnExpressionSource + ";"; } // statements if (selectionStatements != null) { if (returnVariable != null) { String returnTypeName = ExtractUtils.getTypeSource(returnVariable.getType()); if (returnTypeName != null && !returnTypeName.equals("dynamic")) { annotations += returnTypeName + " "; } } else { annotations += "void "; } declarationSource = annotations + getSignature() + " {" + eol; declarationSource += returnExpressionSource; if (returnVariable != null) { declarationSource += prefix + " return " + returnVariable.getName() + ";" + eol; } declarationSource += prefix + "}"; } } // insert declaration if (declarationSource != null) { int offset = parentMember.getSourceInfo().getEnd(); TextEdit edit = new ReplaceEdit(offset, 0, eol + eol + prefix + declarationSource); change.addEdit(edit); change.addTextEditGroup( new TextEditGroup( Messages.format( selectionExpression != null ? RefactoringCoreMessages.ExtractMethodRefactoring_add_method_expression : RefactoringCoreMessages.ExtractMethodRefactoring_add_method, methodName), edit)); } } pm.worked(1); // done return change; } finally { pm.done(); } }