/*******************************************************************************
* Copyright (c) 2008, 2011 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
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.extractfunction;
import java.util.ArrayList;
import java.util.List;
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.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTExpressionStatement;
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression;
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.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IBasicType;
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.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.cdt.core.dom.rewrite.DeclarationGenerator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTBinaryExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFunctionDefinition;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTReturnStatement;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTSimpleDeclaration;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
import org.eclipse.cdt.internal.ui.refactoring.NodeContainer.NameInformation;
/**
* Handles the extraction of expression nodes, like return type determination.
*
* @author Mirko Stocker
*/
public class ExtractExpression extends ExtractedFunctionConstructionHelper {
final static char[] ZERO= { '0' };
@Override
public void constructMethodBody(IASTCompoundStatement compound, List<IASTNode> list,
ASTRewrite rewrite, TextEditGroup group) {
CPPASTReturnStatement statement = new CPPASTReturnStatement();
IASTExpression nullReturnExp = new CPPASTLiteralExpression(IASTLiteralExpression.lk_integer_constant, ZERO);
statement.setReturnValue(nullReturnExp);
ASTRewrite nestedRewrite = rewrite.insertBefore(compound, null, statement, group);
nestedRewrite.replace(nullReturnExp, getExpression(list), group);
}
private IASTExpression getExpression(List<IASTNode> list) {
if (list.size()> 1) {
CPPASTBinaryExpression bExp = new CPPASTBinaryExpression();
bExp.setParent(list.get(0).getParent());
bExp.setOperand1((IASTExpression) list.get(0).copy(CopyStyle.withLocations));
bExp.setOperator(((IASTBinaryExpression)list.get(1).getParent()).getOperator());
bExp.setOperand2(getExpression(list.subList(1, list.size())));
return bExp;
} else {
return (IASTExpression) list.get(0).copy(CopyStyle.withLocations);
}
}
@Override
public IASTDeclSpecifier determineReturnType(IASTNode extractedNode, NameInformation _) {
List<ITypedef> typedefs = getTypedefs(extractedNode);
if (extractedNode instanceof IASTExpression) {
IASTExpression exp = (IASTExpression) extractedNode;
INodeFactory factory = extractedNode.getTranslationUnit().getASTNodeFactory();
DeclarationGenerator generator = DeclarationGenerator.create(factory);
IType expressionType = exp.getExpressionType();
for (ITypedef typedef : typedefs) {
if (typedef.getType().isSameType(expressionType)) {
return generator.createDeclSpecFromType(typedef);
}
}
return generator.createDeclSpecFromType(expressionType);
} else { // Fallback
return createSimpleDeclSpecifier(Kind.eVoid);
}
}
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;
}
private static IASTDeclSpecifier createSimpleDeclSpecifier(IBasicType.Kind type) {
IASTSimpleDeclSpecifier declSpec = new CPPASTSimpleDeclSpecifier();
declSpec.setType(type);
return declSpec;
}
private static IASTName findCalledFunctionName(IASTFunctionCallExpression callExpression) {
IASTExpression functionNameExpression = callExpression.getFunctionNameExpression();
IASTName functionName = null;
if (functionNameExpression instanceof CPPASTIdExpression) {
CPPASTIdExpression idExpression = (CPPASTIdExpression) functionNameExpression;
functionName = idExpression.getName();
} else if (functionNameExpression instanceof CPPASTFieldReference) {
CPPASTFieldReference fieldReference = (CPPASTFieldReference) functionNameExpression;
functionName = fieldReference.getFieldName();
}
return functionName;
}
@Override
protected boolean isReturnTypeAPointer(IASTNode node) {
if (node instanceof ICPPASTNewExpression) {
return true;
} else if (!(node instanceof IASTFunctionCallExpression)) {
return false;
}
IASTName functionName = findCalledFunctionName((IASTFunctionCallExpression) node);
if (functionName != null) {
IBinding binding = functionName.resolveBinding();
if (binding instanceof CPPFunction) {
CPPFunction function = (CPPFunction) binding;
if (function.getDefinition() != null) {
IASTNode parent = function.getDefinition().getParent();
if (parent instanceof CPPASTFunctionDefinition) {
CPPASTFunctionDefinition definition = (CPPASTFunctionDefinition) parent;
return definition.getDeclarator().getPointerOperators().length > 0;
}
} else if (hasDeclaration(function)) {
IASTNode parent = function.getDeclarations()[0].getParent();
if (parent instanceof CPPASTSimpleDeclaration) {
CPPASTSimpleDeclaration declaration = (CPPASTSimpleDeclaration) parent;
return declaration.getDeclarators().length > 0 &&
declaration.getDeclarators()[0].getPointerOperators().length > 0;
}
}
}
}
return false;
}
private static boolean hasDeclaration(CPPFunction function) {
return function != null && function.getDeclarations() != null && function.getDeclarations().length > 0;
}
@Override
public IASTNode createReturnAssignment(IASTNode node, IASTExpressionStatement stmt, IASTExpression callExpression) {
return callExpression;
}
}