1 | /******************************************************************************* |
2 | * Copyright (c) 2008, 2009 IBM Corporation and others. |
3 | * All rights reserved. This program and the accompanying materials |
4 | * are made available under the terms of the Eclipse Public License v1.0 |
5 | * which accompanies this distribution, and is available at |
6 | * http://www.eclipse.org/legal/epl-v10.html |
7 | * |
8 | * Contributors: |
9 | * IBM Corporation - initial API and implementation |
10 | *******************************************************************************/ |
11 | package org.eclipse.pde.api.tools.internal.builder; |
12 | |
13 | import java.util.HashMap; |
14 | |
15 | import org.eclipse.core.runtime.CoreException; |
16 | import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
17 | import org.eclipse.pde.api.tools.internal.provisional.Factory; |
18 | import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations; |
19 | import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; |
20 | import org.eclipse.pde.api.tools.internal.provisional.builder.IReference; |
21 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; |
22 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement; |
23 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiMember; |
24 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; |
25 | import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem; |
26 | import org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblemTypes; |
27 | |
28 | /** |
29 | * Detects when a type illegally implements another type. |
30 | * |
31 | * @since 1.1 |
32 | */ |
33 | public class IllegalImplementsProblemDetector extends AbstractIllegalTypeReference { |
34 | |
35 | /** |
36 | * Map of directly implemented interfaces to implement restricted super-interfaces |
37 | */ |
38 | private HashMap fRestrictedInterfaces = new HashMap(); |
39 | |
40 | /* (non-Javadoc) |
41 | * @see org.eclipse.pde.api.tools.internal.provisional.search.IApiProblemDetector#getReferenceKinds() |
42 | */ |
43 | public int getReferenceKinds() { |
44 | return IReference.REF_IMPLEMENTS; |
45 | } |
46 | |
47 | /* (non-Javadoc) |
48 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#getProblemKind() |
49 | */ |
50 | protected int getProblemKind() { |
51 | return IApiProblem.ILLEGAL_IMPLEMENT; |
52 | } |
53 | |
54 | /* (non-Javadoc) |
55 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#getSeverityKey() |
56 | */ |
57 | protected String getSeverityKey() { |
58 | return IApiProblemTypes.ILLEGAL_IMPLEMENT; |
59 | } |
60 | |
61 | /* (non-Javadoc) |
62 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#considerReference(org.eclipse.pde.api.tools.internal.provisional.model.IReference) |
63 | */ |
64 | public boolean considerReference(IReference reference) { |
65 | try { |
66 | if(super.considerReference(reference)) { |
67 | return true; |
68 | } |
69 | IApiType type = (IApiType) reference.getMember(); |
70 | IApiType[] inters = type.getSuperInterfaces(); |
71 | IApiType inter = null; |
72 | for (int j = 0; j < inters.length; j++) { |
73 | if(inters[j].getName().equals(reference.getReferencedTypeName())) { |
74 | inter = inters[j]; |
75 | break; |
76 | } |
77 | } |
78 | if(inter != null && findRestrictedSuperinterfaces(type.getApiComponent(), reference.getReferencedTypeName(), inter)) { |
79 | retainReference(reference); |
80 | return true; |
81 | } |
82 | } |
83 | catch(CoreException ce) { |
84 | if(DEBUG) { |
85 | ApiPlugin.log(ce); |
86 | } |
87 | } |
88 | return false; |
89 | } |
90 | |
91 | /* (non-Javadoc) |
92 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#isProblem(org.eclipse.pde.api.tools.internal.provisional.model.IReference) |
93 | */ |
94 | protected boolean isProblem(IReference reference) { |
95 | try { |
96 | if(isIllegalType(reference)) { |
97 | return super.isProblem(reference); |
98 | } |
99 | if(fRestrictedInterfaces.size() > 0) { |
100 | IApiMember member = reference.getMember(); |
101 | if(member.getType() == IApiElement.TYPE) { |
102 | IApiType itype = (IApiType) fRestrictedInterfaces.get(reference.getReferencedTypeName()); |
103 | return itype != null && !isImplemented(((IApiType) member).getSuperclass(), itype.getName()); |
104 | } |
105 | } |
106 | return true; |
107 | } |
108 | catch(CoreException ce) { |
109 | if(DEBUG) { |
110 | ApiPlugin.log(ce); |
111 | } |
112 | } |
113 | return super.isProblem(reference); |
114 | } |
115 | /* (non-Javadoc) |
116 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#getMessageArgs(org.eclipse.pde.api.tools.internal.provisional.model.IReference) |
117 | */ |
118 | protected String[] getMessageArgs(IReference reference) throws CoreException { |
119 | if(isIllegalType(reference)) { |
120 | return super.getMessageArgs(reference); |
121 | } |
122 | if(fRestrictedInterfaces.size() > 0) { |
123 | IApiType type = (IApiType) reference.getResolvedReference(); |
124 | IApiType inter = (IApiType) fRestrictedInterfaces.get(type.getName()); |
125 | if(inter != null) { |
126 | return new String[] {getSimpleTypeName(type), inter.getSimpleName(), getSimpleTypeName(reference.getMember())}; |
127 | } |
128 | } |
129 | return super.getMessageArgs(reference); |
130 | } |
131 | /* (non-Javadoc) |
132 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#getMessageArgs(org.eclipse.pde.api.tools.internal.provisional.model.IReference) |
133 | */ |
134 | protected String[] getQualifiedMessageArgs(IReference reference) throws CoreException { |
135 | if(isIllegalType(reference)) { |
136 | return super.getQualifiedMessageArgs(reference); |
137 | } |
138 | if(fRestrictedInterfaces.size() > 0) { |
139 | IApiType type = (IApiType) reference.getResolvedReference(); |
140 | IApiType inter = (IApiType) fRestrictedInterfaces.get(type.getName()); |
141 | if(inter != null) { |
142 | return new String[] {getQualifiedTypeName(type), inter.getName(), getQualifiedTypeName(reference.getMember())}; |
143 | } |
144 | } |
145 | return super.getQualifiedMessageArgs(reference); |
146 | } |
147 | |
148 | /* (non-Javadoc) |
149 | * @see org.eclipse.pde.api.tools.internal.search.AbstractIllegalTypeReference#getProblemFlags(org.eclipse.pde.api.tools.internal.provisional.model.IReference) |
150 | */ |
151 | protected int getProblemFlags(IReference reference) { |
152 | if(isIllegalType(reference)) { |
153 | return super.getProblemFlags(reference); |
154 | } |
155 | return IApiProblem.INDIRECT_REFERENCE; |
156 | } |
157 | |
158 | /** |
159 | * Returns if the given type implements any of the given interfaces anywhere in its lineage |
160 | * @param type |
161 | * @param iname |
162 | * @return true if all of the interfaces are implemented, false otherwise |
163 | * @throws CoreException |
164 | */ |
165 | private boolean isImplemented(IApiType type, final String iname) throws CoreException { |
166 | if(type == null) { |
167 | return false; |
168 | } |
169 | if(isImplemented(iname, type.getSuperInterfaces())) { |
170 | return true; |
171 | } |
172 | return isImplemented(type.getSuperclass(), iname); |
173 | } |
174 | |
175 | /** |
176 | * Inspects the hierarchy of super-interfaces to determine if an interface with the given name is |
177 | * implemented or not |
178 | * @param iname the name of the interface to find |
179 | * @param interfaces the collection of interfaces to inspect |
180 | * @return true if the interface is implemented, false otherwise |
181 | * @throws CoreException |
182 | */ |
183 | private boolean isImplemented(final String iname, IApiType[] interfaces) throws CoreException { |
184 | if(interfaces.length == 0) { |
185 | return false; |
186 | } |
187 | for (int i = 0; i < interfaces.length; i++) { |
188 | if(interfaces[i].getName().equals(iname)) { |
189 | return true; |
190 | } |
191 | if(isImplemented(iname, interfaces[i].getSuperInterfaces())) { |
192 | return true; |
193 | } |
194 | } |
195 | return false; |
196 | } |
197 | |
198 | /** |
199 | * Finds all of the implements restricted interfaces in the hierarchy of this given type |
200 | * @param originalcomponent the original {@link IApiComponent} |
201 | * @param entryinterface the name of the interface we originally entered the recursion with |
202 | * @param type the {@link IApiType} to inspect the interfaces of |
203 | * @throws CoreException |
204 | */ |
205 | private boolean findRestrictedSuperinterfaces(final IApiComponent originalcomponent, final String entryinterface, IApiType type) throws CoreException { |
206 | IApiType[] inters = type.getSuperInterfaces(); |
207 | if(inters.length == 0) { |
208 | return false; |
209 | } |
210 | IApiAnnotations annot = null; |
211 | IApiComponent comp = null; |
212 | for (int i = 0; i < inters.length; i++) { |
213 | comp = inters[i].getApiComponent(); |
214 | if(comp == null) { |
215 | continue; |
216 | } |
217 | if(!comp.equals(originalcomponent)) { |
218 | annot = comp.getApiDescription().resolveAnnotations(Factory.typeDescriptor(inters[i].getName())); |
219 | if(annot != null && RestrictionModifiers.isImplementRestriction(annot.getRestrictions())) { |
220 | return fRestrictedInterfaces.put(entryinterface, inters[i]) == null; |
221 | } |
222 | } |
223 | return findRestrictedSuperinterfaces(originalcomponent, entryinterface, inters[i]); |
224 | } |
225 | return false; |
226 | } |
227 | } |