blob: 9a92f39f46e4ac3e6c5ff4e45c2aac9e72291adc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Pavel Marek
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Pavel Marek - initial API and implementation
* Marco Stornelli - Improvements
*******************************************************************************/
package org.eclipse.cdt.internal.ui.refactoring.overridemethods;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier.SpecifierKind;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNodeFactory;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
import org.eclipse.cdt.core.dom.rewrite.DeclarationGenerator;
import org.eclipse.cdt.internal.ui.refactoring.CRefactoringContext;
import org.eclipse.cdt.internal.ui.refactoring.utils.DefinitionFinder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.OperationCanceledException;
/**
* Wrapper for ICPPMethod
*/
public class Method {
private IASTDeclSpecifier fDeclSpecifier;
private ICPPMethod fMethod;
private OverrideOptions fOptions;
/**
* Accepts only methods declared as virtual.
* @param method The ICPPMethod to be wrapped
* @param declSpecifier The class declaration specifier
* @param options Override options
*/
public Method(ICPPMethod method, IASTDeclSpecifier declSpecifier, OverrideOptions options) {
fMethod = method;
fOptions = options;
fDeclSpecifier = declSpecifier;
}
/**
* Accepts only methods declared as virtual.
* @param method The ICPPMethod to be wrapped
* @param options Override options
*/
public Method(ICPPMethod method, OverrideOptions options) {
fMethod = method;
fOptions = options;
fDeclSpecifier = null;
}
/**
* Two methods are considered equal if they have same signature ie. name
* and types of parameters in same order.
*/
@Override
public int hashCode() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(fMethod.getName());
for (ICPPParameter parameter : fMethod.getParameters()) {
stringBuilder.append(parameter.getType());
}
return stringBuilder.toString().hashCode();
}
@Override
public boolean equals(Object o) {
return this.hashCode() == o.hashCode();
}
/**
* Get the wrapped method
* @return The method
*/
public ICPPMethod getMethod() {
return fMethod;
}
/**
* Accepts only methods declared as virtual.
* @param fMethod
*/
public void setMethod(ICPPMethod fMethod) {
this.fMethod = fMethod;
}
@Override
public String toString() {
return fMethod.toString();
}
/**
* Get the class declaration specifier
* @return The class declaration specifier
*/
public IASTDeclSpecifier getDeclSpecifier() {
return fDeclSpecifier;
}
/**
* Create a IASTNode for this method
* @param context The refactoring context
* @return The IASTNode for the method declaration
* @throws OperationCanceledException
* @throws CoreException
*/
public IASTNode createNode(CRefactoringContext context) throws OperationCanceledException, CoreException {
ICPPFunctionType functionType = fMethod.getDeclaredType();
ICPPParameter[] parameters = fMethod.getParameters();
IASTName declaration = DefinitionFinder.getMemberDeclaration(fMethod, getDeclSpecifier().getTranslationUnit(),
context, null);
INodeFactory factory = getDeclSpecifier().getTranslationUnit().getASTNodeFactory();
DeclarationGenerator declGen = DeclarationGenerator.create(factory);
if (declaration == null)
return null;
IASTDeclarator declarator = (IASTDeclarator) declaration.getParent();
/**
* We can't just copy the original nodes here but we need to create a new node. We can't do it
* because the original node could lack some information needed in the clone. Example: the node
* in parent has a parameter to an object inside a namespace but namespace miss because the interface
* class is declared in the same namespace too, but in this case the new method of child class may needs
* of fully qualified name for the parameter, so a plain copy doesn't work.
*/
IASTStandardFunctionDeclarator newDeclarator = factory.newFunctionDeclarator(declarator.getName().copy());
IASTDeclSpecifier newDeclSpec = declGen.createDeclSpecFromType(functionType);
if (newDeclSpec instanceof ICPPASTDeclSpecifier && fOptions.preserveVirtual()) {
((ICPPASTDeclSpecifier) newDeclSpec).setVirtual(true);
}
IASTSimpleDeclaration simple = factory.newSimpleDeclaration(newDeclSpec);
if (newDeclarator instanceof ICPPASTFunctionDeclarator) {
ICPPASTFunctionDeclarator funcDeclarator = (ICPPASTFunctionDeclarator) newDeclarator;
funcDeclarator.setPureVirtual(false);
funcDeclarator.setConst(functionType.isConst());
if (fOptions.addOverride()) {
funcDeclarator.addVirtSpecifier(((ICPPNodeFactory) factory).newVirtSpecifier(SpecifierKind.Override));
}
for (ICPPParameter par : parameters) {
IASTDeclarator parDeclarator = declGen.createDeclaratorFromType(par.getType(),
par.getName().toCharArray());
IASTDeclSpecifier parSpecifier = declGen.createDeclSpecFromType(par.getType());
IASTParameterDeclaration parameter = factory.newParameterDeclaration(parSpecifier, parDeclarator);
funcDeclarator.addParameterDeclaration(parameter);
}
for (IASTPointerOperator op : declarator.getPointerOperators())
funcDeclarator.addPointerOperator(op.copy());
if (declarator instanceof ICPPASTFunctionDeclarator) {
ICPPASTFunctionDeclarator orig = (ICPPASTFunctionDeclarator) declarator;
funcDeclarator.setRefQualifier(orig.getRefQualifier());
IASTTypeId[] typesId = orig.getExceptionSpecification();
if (typesId == IASTTypeId.EMPTY_TYPEID_ARRAY)
funcDeclarator.setEmptyExceptionSpecification();
else {
for (IASTTypeId typeId : typesId) {
funcDeclarator.addExceptionSpecificationTypeId(typeId == null ? null : typeId.copy());
}
}
ICPPASTExpression noexceptExpression = orig.getNoexceptExpression();
if (noexceptExpression != null) {
funcDeclarator.setNoexceptExpression(
noexceptExpression == ICPPASTFunctionDeclarator.NOEXCEPT_DEFAULT ? noexceptExpression
: (ICPPASTExpression) noexceptExpression.copy());
}
}
}
simple.addDeclarator(newDeclarator);
simple.setDeclSpecifier(newDeclSpec);
simple.setParent(getDeclSpecifier());
return simple;
}
}