@Override public Void visitIdentifier(DartIdentifier node) { if (foundElement == null) { int start = node.getSourceInfo().getOffset(); int length = node.getSourceInfo().getLength(); int end = start + length; if (start <= startOffset && endOffset <= end) { wordRegion = new Region(start, length); Element targetElement = DartAstUtilities.getElement(node, includeDeclarations); if (targetElement == null) { foundElement = null; } else { if (targetElement instanceof VariableElement) { VariableElement variableElement = (VariableElement) targetElement; resolvedElement = variableElement; if (variableElement.getKind() == ElementKind.PARAMETER || variableElement.getKind() == ElementKind.VARIABLE) { foundElement = BindingUtils.getDartElement(compilationUnit.getLibrary(), variableElement); candidateRegion = new Region( variableElement.getNameLocation().getOffset(), variableElement.getNameLocation().getLength()); } else { foundElement = null; } } else { findElementFor(targetElement); // Import prefix is resolved into LibraryElement, so it is correct that corresponding // DartElement is DartLibrary, but this is not what we (and user) wants, because // it looses information. We want DartImport, it gives both DartLibrary and name. if (foundElement instanceof DartLibrary) { try { DartImport[] imports = compilationUnit.getLibrary().getImports(); for (DartImport imprt : imports) { if (Objects.equal(imprt.getLibrary(), foundElement) && Objects.equal(imprt.getPrefix(), node.getName())) { foundElement = imprt; SourceRange range = imprt.getNameRange(); candidateRegion = new Region(range.getOffset(), range.getLength()); } } } catch (DartModelException e) { DartCore.logError("Cannot resolve import " + foundElement.getElementName(), e); } } } } throw new DartElementFoundException(); } } return null; }
public static FunctionType makeFunctionType( ResolutionErrorListener listener, ClassElement element, List<VariableElement> parameters, Type returnType) { List<Type> parameterTypes = new ArrayList<Type>(parameters.size()); Map<String, Type> optionalParameterTypes = null; Map<String, Type> namedParameterTypes = null; Type restParameter = null; for (VariableElement parameter : parameters) { Type type = parameter.getType(); // TODO(scheglov) one we will make optional parameter not named, // check isOptional() before isNamed() if (parameter.isNamed()) { if (namedParameterTypes == null) { namedParameterTypes = new LinkedHashMap<String, Type>(); } namedParameterTypes.put(parameter.getName(), type); } else if (parameter.isOptional()) { if (optionalParameterTypes == null) { optionalParameterTypes = new LinkedHashMap<String, Type>(); } optionalParameterTypes.put(parameter.getName(), type); } else { parameterTypes.add(type); } } return FunctionTypeImplementation.of( element, parameterTypes, optionalParameterTypes, namedParameterTypes, restParameter, returnType); }
/** * Fills {@link #parameters} with information about used variables, which should be turned into * parameters. */ private RefactoringStatus initializeParameters() { RefactoringStatus result = new RefactoringStatus(); final List<VariableElement> assignedUsedVariables = Lists.newArrayList(); unitNode.accept( new ASTVisitor<Void>() { @Override public Void visitIdentifier(DartIdentifier node) { SourceRange nodeRange = SourceRangeFactory.create(node); if (SourceRangeUtils.covers(selectionRange, nodeRange)) { // analyze local variable VariableElement variableElement = ASTNodes.getVariableOrParameterElement(node); if (variableElement != null) { // if declared outside, add parameter if (!isDeclaredInSelection(variableElement)) { String variableName = variableElement.getName(); // add parameter if (!selectionParametersToRanges.containsKey(variableName)) { parameters.add(new ParameterInfo(variableElement)); } // add reference to parameter { List<SourceRange> ranges = selectionParametersToRanges.get(variableName); if (ranges == null) { ranges = Lists.newArrayList(); selectionParametersToRanges.put(variableName, ranges); } ranges.add(nodeRange); } } // remember, if assigned and used after seleciton if (isLeftHandOfAssignment(node) && isUsedAfterSelection(variableElement)) { if (!assignedUsedVariables.contains(variableElement)) { assignedUsedVariables.add(variableElement); } } } // remember declaration names if (ASTNodes.isNameOfDeclaration(node)) { usedNames.add(node.getName()); } } return null; } }); // may be single variable to return if (assignedUsedVariables.size() == 1) { returnVariable = assignedUsedVariables.get(0); } // fatal, if multiple variables assigned and used after selection if (assignedUsedVariables.size() > 1) { StringBuilder sb = new StringBuilder(); for (VariableElement variable : assignedUsedVariables) { sb.append(variable.getName()); sb.append("\n"); } result.addFatalError( Messages.format( RefactoringCoreMessages.ExtractMethodAnalyzer_assignments_to_local, sb.toString().trim())); } // done return result; }
/** * @return <code>true</code> if the given {@link VariableElement} is declared inside of {@link * #selectionRange}. */ private boolean isDeclaredInSelection(VariableElement element) { return SourceRangeUtils.contains(selectionRange, element.getNameLocation().getOffset()); }
@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(); } }