/******************************************************************************* * Copyright (c) 2008, 2013 Institute for Software, HSR Hochschule fuer Technik * Rapperswil, University of applied sciences and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Institute for Software - initial API and implementation * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.extractfunction; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.eclipse.text.edits.TextEditGroup; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement; import org.eclipse.cdt.core.dom.ast.IASTIdExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; import org.eclipse.cdt.core.dom.ast.IBasicType.Kind; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.INodeFactory; import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.rewrite.ASTRewrite; import org.eclipse.cdt.core.dom.rewrite.DeclarationGenerator; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPBasicType; import org.eclipse.cdt.internal.ui.refactoring.NameInformation; /** * Handles the extraction of expression nodes, for example, return type determination. * * @author Mirko Stocker */ public class ExpressionExtractor extends FunctionExtractor { @Override public boolean canChooseReturnValue() { return false; } @Override public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> nodes, List<NameInformation> parameters, ASTRewrite rewrite, TextEditGroup group) { CPPASTReturnStatement statement = new CPPASTReturnStatement(); statement.setReturnValue(getExpression(nodes)); ASTRewrite subRewrite = rewrite.insertBefore(compound, null, statement, group); Map<IASTName, NameInformation> changedParameters = getChangedParameterReferences(parameters); INodeFactory nodeFactory = nodes.get(0).getTranslationUnit().getASTNodeFactory(); adjustParameterReferences(statement, changedParameters, nodeFactory, subRewrite, group); } private IASTExpression getExpression(List<IASTNode> nodes) { if (nodes.size() > 1) { CPPASTBinaryExpression expression = new CPPASTBinaryExpression(); expression.setParent(nodes.get(0).getParent()); expression.setOperand1((IASTExpression) nodes.get(0).copy(CopyStyle.withLocations)); expression.setOperator(((IASTBinaryExpression) nodes.get(1).getParent()).getOperator()); expression.setOperand2(getExpression(nodes.subList(1, nodes.size()))); return expression; } else { return (IASTExpression) nodes.get(0).copy(CopyStyle.withLocations); } } @Override public IASTDeclSpecifier determineReturnType(IASTNode extractedNode, NameInformation _, List<IASTPointerOperator> pointerOperators) { IType returnType = determineReturnType(extractedNode); INodeFactory factory = extractedNode.getTranslationUnit().getASTNodeFactory(); DeclarationGenerator generator = DeclarationGenerator.create(factory); IASTDeclarator declarator = generator.createDeclaratorFromType(returnType, null); ArrayUtil.addAll(pointerOperators, declarator.getPointerOperators()); return generator.createDeclSpecFromType(returnType); } private IType determineReturnType(IASTNode extractedNode) { List<ITypedef> typedefs = getTypedefs(extractedNode); if (extractedNode instanceof IASTExpression) { IType expressionType = ((IASTExpression) extractedNode).getExpressionType(); for (ITypedef typedef : typedefs) { if (typedef.getType().isSameType(expressionType)) { return typedef; } } return expressionType; } else { // Fallback return new CPPBasicType(Kind.eVoid, 0); } } private List<ITypedef> getTypedefs(IASTNode extractedNode) { final ArrayList<ITypedef> typeDefs = new ArrayList<ITypedef>(); extractedNode.accept(new ASTVisitor() { { shouldVisitExpressions = true; } @Override public int visit(IASTExpression expression) { if (expression instanceof IASTIdExpression) { IASTIdExpression id = (IASTIdExpression) expression; IBinding binding = id.getName().resolveBinding(); IType expressionType = null; if (binding instanceof IVariable) { expressionType = ((IVariable) binding).getType(); } if (binding instanceof IType) { expressionType = (IType) binding; } if (expressionType != null && expressionType instanceof ITypedef) { ITypedef typdef = (ITypedef) expressionType; typeDefs.add(typdef); } } return PROCESS_CONTINUE; } }); return typeDefs; } @Override public IASTNode createReturnAssignment(IASTNode node, IASTExpressionStatement stmt, IASTExpression callExpression) { return callExpression; } }