| /******************************************************************************* |
| * Copyright (c) 2008, 2013 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.pde.api.tools.internal.builder; |
| |
| import java.util.HashMap; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
| import org.eclipse.pde.api.tools.internal.provisional.Factory; |
| import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations; |
| import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; |
| import org.eclipse.pde.api.tools.internal.provisional.builder.IReference; |
| import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; |
| import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement; |
| import org.eclipse.pde.api.tools.internal.provisional.model.IApiMember; |
| import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; |
| import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem; |
| import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes; |
| |
| /** |
| * Detects when a type illegally implements another type. |
| * |
| * @since 1.1 |
| */ |
| public class IllegalImplementsProblemDetector extends AbstractIllegalTypeReference { |
| |
| /** |
| * Map of directly implemented interfaces to implement restricted |
| * super-interfaces |
| */ |
| private HashMap<String, IApiType> fRestrictedInterfaces = new HashMap<>(); |
| |
| @Override |
| public int getReferenceKinds() { |
| return IReference.REF_IMPLEMENTS; |
| } |
| |
| @Override |
| protected int getProblemKind() { |
| return IApiProblem.ILLEGAL_IMPLEMENT; |
| } |
| |
| @Override |
| protected String getSeverityKey() { |
| return IApiProblemTypes.ILLEGAL_IMPLEMENT; |
| } |
| |
| @Override |
| public boolean considerReference(IReference reference, IProgressMonitor monitor) { |
| try { |
| if (super.considerReference(reference, monitor)) { |
| return true; |
| } |
| IApiType type = (IApiType) reference.getMember(); |
| IApiType[] inters = type.getSuperInterfaces(); |
| IApiType inter = null; |
| for (IApiType interLoop : inters) { |
| if (interLoop.getName().equals(reference.getReferencedTypeName())) { |
| inter = interLoop; |
| break; |
| } |
| } |
| if (inter != null && findRestrictedSuperinterfaces(type.getApiComponent(), reference.getReferencedTypeName(), inter)) { |
| retainReference(reference); |
| return true; |
| } |
| } catch (CoreException ce) { |
| if (ApiPlugin.DEBUG_PROBLEM_DETECTOR) { |
| ApiPlugin.log(ce); |
| } |
| checkIfDisposed(reference.getMember().getApiComponent(), monitor); |
| } |
| return false; |
| } |
| |
| @Override |
| protected boolean isProblem(IReference reference, IProgressMonitor monitor) { |
| try { |
| if (isIllegalType(reference)) { |
| return super.isProblem(reference, monitor); |
| } |
| if (fRestrictedInterfaces.size() > 0) { |
| IApiMember member = reference.getMember(); |
| if (member.getType() == IApiElement.TYPE) { |
| IApiType itype = fRestrictedInterfaces.get(reference.getReferencedTypeName()); |
| return itype != null && !isImplemented(((IApiType) member).getSuperclass(), itype.getName()); |
| } |
| } |
| return true; |
| } catch (CoreException ce) { |
| if (ApiPlugin.DEBUG_PROBLEM_DETECTOR) { |
| ApiPlugin.log(ce); |
| } |
| IApiMember member = reference.getMember(); |
| if (member != null) { |
| checkIfDisposed(member.getApiComponent(), monitor); |
| } |
| } |
| return super.isProblem(reference, monitor); |
| } |
| |
| @Override |
| protected String[] getMessageArgs(IReference reference) throws CoreException { |
| String[] args = super.getMessageArgs(reference); |
| if (!isIllegalType(reference) && fRestrictedInterfaces.size() > 0) { |
| IApiType type = (IApiType) reference.getResolvedReference(); |
| IApiType inter = fRestrictedInterfaces.get(type.getName()); |
| if (inter != null) { |
| String[] newargs = new String[args.length + 1]; |
| System.arraycopy(args, 0, newargs, 0, args.length); |
| newargs[args.length] = getSimpleTypeName(inter); |
| return newargs; |
| } |
| } |
| return args; |
| } |
| |
| @Override |
| protected String[] getQualifiedMessageArgs(IReference reference) throws CoreException { |
| String[] args = super.getQualifiedMessageArgs(reference); |
| if (!isIllegalType(reference) && fRestrictedInterfaces.size() > 0) { |
| IApiType type = (IApiType) reference.getResolvedReference(); |
| IApiType inter = fRestrictedInterfaces.get(type.getName()); |
| if (inter != null) { |
| String[] newargs = new String[args.length + 1]; |
| System.arraycopy(args, 0, newargs, 0, args.length); |
| newargs[args.length] = inter.getName(); |
| return newargs; |
| } |
| } |
| return args; |
| } |
| |
| @Override |
| protected int getProblemFlags(IReference reference) { |
| if (isIllegalType(reference)) { |
| return super.getProblemFlags(reference); |
| } |
| IApiType type = (IApiType) reference.getMember(); |
| if (type.isLocal()) { |
| return IApiProblem.INDIRECT_LOCAL_REFERENCE; |
| } |
| return IApiProblem.INDIRECT_REFERENCE; |
| } |
| |
| /** |
| * Returns if the given type implements any of the given interfaces anywhere |
| * in its lineage |
| * |
| * @param type |
| * @param iname |
| * @return true if all of the interfaces are implemented, false otherwise |
| * @throws CoreException |
| */ |
| private boolean isImplemented(IApiType type, final String iname) throws CoreException { |
| if (type == null) { |
| return false; |
| } |
| if (isImplemented(iname, type.getSuperInterfaces())) { |
| return true; |
| } |
| return isImplemented(type.getSuperclass(), iname); |
| } |
| |
| /** |
| * Inspects the hierarchy of super-interfaces to determine if an interface |
| * with the given name is implemented or not |
| * |
| * @param iname the name of the interface to find |
| * @param interfaces the collection of interfaces to inspect |
| * @return true if the interface is implemented, false otherwise |
| * @throws CoreException |
| */ |
| private boolean isImplemented(final String iname, IApiType[] interfaces) throws CoreException { |
| if (interfaces.length == 0) { |
| return false; |
| } |
| for (IApiType interfaceLoop : interfaces) { |
| if (interfaceLoop.getName().equals(iname)) { |
| return true; |
| } |
| if (isImplemented(iname, interfaceLoop.getSuperInterfaces())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Finds all of the implements restricted interfaces in the hierarchy of |
| * this given type |
| * |
| * @param originalcomponent the original {@link IApiComponent} |
| * @param entryinterface the name of the interface we originally entered the |
| * recursion with |
| * @param type the {@link IApiType} to inspect the interfaces of |
| * @throws CoreException |
| */ |
| private boolean findRestrictedSuperinterfaces(final IApiComponent originalcomponent, final String entryinterface, IApiType type) throws CoreException { |
| IApiType[] inters = type.getSuperInterfaces(); |
| if (inters.length == 0) { |
| return false; |
| } |
| IApiAnnotations annot = null; |
| IApiComponent comp = null; |
| for (IApiType inter : inters) { |
| comp = inter.getApiComponent(); |
| if (comp == null) { |
| continue; |
| } |
| if (!comp.equals(originalcomponent)) { |
| annot = comp.getApiDescription().resolveAnnotations(Factory.typeDescriptor(inter.getName())); |
| if (annot != null && RestrictionModifiers.isImplementRestriction(annot.getRestrictions())) { |
| fRestrictedInterfaces.put(entryinterface, inter); |
| return true; |
| } |
| } |
| return findRestrictedSuperinterfaces(originalcomponent, entryinterface, inter); |
| } |
| return false; |
| } |
| } |