blob: 7152ad345388d22c4014753ebfbbd3df00aea8b0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Till Brychcy and others.
*
* 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:
* Till Brychcy - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.dom;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.List;
import org.eclipse.text.edits.TextEditGroup;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.IMemberValuePairBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.internal.corext.util.JDTUIHelperClasses;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
/**
* Rewrite helper for type annotations.
*
* @see JDTUIHelperClasses
* @since 3.13
*/
public class TypeAnnotationRewrite {
/**
* Removes all {@link Annotation} whose only {@link Target} is {@link ElementType#TYPE_USE} from
* <code>node</code>'s <code>childListProperty</code>.
* <p>
* In a combination of {@link ElementType#TYPE_USE} and {@link ElementType#TYPE_PARAMETER}
* the latter is ignored, because this is implied by the former and creates no ambiguity.</p>
*
* @param node ASTNode
* @param childListProperty child list property
* @param rewrite rewrite that removes the nodes
* @param editGroup the edit group in which to collect the corresponding text edits, or null if
* ungrouped
*/
public static void removePureTypeAnnotations(ASTNode node, ChildListPropertyDescriptor childListProperty, ASTRewrite rewrite, TextEditGroup editGroup) {
CompilationUnit root= (CompilationUnit) node.getRoot();
if (!JavaModelUtil.is1d8OrHigher(root.getJavaElement().getJavaProject())) {
return;
}
ListRewrite listRewrite= rewrite.getListRewrite(node, childListProperty);
@SuppressWarnings("unchecked")
List<? extends ASTNode> children= (List<? extends ASTNode>) node.getStructuralProperty(childListProperty);
for (ASTNode child : children) {
if (child instanceof Annotation) {
Annotation annotation= (Annotation) child;
if (isPureTypeAnnotation(annotation)) {
listRewrite.remove(child, editGroup);
}
}
}
}
private static boolean isPureTypeAnnotation(Annotation annotation) {
IAnnotationBinding binding= annotation.resolveAnnotationBinding();
if (binding == null) {
return false;
}
IAnnotationBinding targetAnnotationBinding= findTargetAnnotation(binding.getAnnotationType().getAnnotations());
if (targetAnnotationBinding == null) {
return false;
}
return isTypeUseOnly(targetAnnotationBinding);
}
private static IAnnotationBinding findTargetAnnotation(IAnnotationBinding[] metaAnnotations) {
for (IAnnotationBinding binding : metaAnnotations) {
ITypeBinding annotationType= binding.getAnnotationType();
if (annotationType != null && annotationType.getQualifiedName().equals(Target.class.getName())) {
return binding;
}
}
return null;
}
private static boolean isTypeUseOnly(IAnnotationBinding binding) {
boolean typeUseSeen= false;
boolean otherSeen= false;
for (final IMemberValuePairBinding pair : binding.getAllMemberValuePairs()) {
if (pair.getKey() == null || pair.getKey().equals("value")) { //$NON-NLS-1$
Object value= pair.getValue();
if (value instanceof Object[]) {
for (Object v : (Object[]) value) {
if (v instanceof IVariableBinding) {
String name= ((IVariableBinding) v).getName();
if (name.equals(ElementType.TYPE_USE.name())) {
typeUseSeen= true;
} else if (!name.equals(ElementType.TYPE_PARAMETER.name())) {
otherSeen= true;
}
}
}
} else if (value instanceof IVariableBinding) {
String name= ((IVariableBinding) value).getName();
if (name.equals(ElementType.TYPE_USE.name())) {
typeUseSeen= true;
} else if (!name.equals(ElementType.TYPE_PARAMETER.name())) {
otherSeen= true;
}
}
}
}
return typeUseSeen && !otherSeen;
}
private TypeAnnotationRewrite() {
}
}