1 | /******************************************************************************* |
2 | * Copyright (c) 2007, 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.provisional.comparator; |
12 | |
13 | import org.eclipse.jdt.core.Flags; |
14 | import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; |
15 | import org.eclipse.pde.api.tools.internal.util.Util; |
16 | |
17 | |
18 | /** |
19 | * Class used to process the delta to find out if they are compatible or not. |
20 | * |
21 | * @since 1.0.0 |
22 | */ |
23 | public class DeltaProcessor { |
24 | |
25 | /** |
26 | * Return true is the given delta is compatible, false otherwise. |
27 | * |
28 | * @param delta the given delta |
29 | * @return true is the given delta is compatible, false otherwise. |
30 | */ |
31 | public static boolean isCompatible(IDelta delta) { |
32 | class CompatibleVisitor extends DeltaVisitor { |
33 | boolean isCompatible = true; |
34 | |
35 | public boolean visit(IDelta delta) { |
36 | if (!this.isCompatible) return false; |
37 | return true; |
38 | } |
39 | public void endVisit(IDelta delta) { |
40 | if (this.isCompatible) { |
41 | this.isCompatible = isCompatible0(delta); |
42 | } |
43 | } |
44 | }; |
45 | if (delta.getChildren().length != 0) { |
46 | CompatibleVisitor visitor = new CompatibleVisitor(); |
47 | delta.accept(visitor); |
48 | return visitor.isCompatible; |
49 | } else { |
50 | return isCompatible0(delta); |
51 | } |
52 | } |
53 | |
54 | /** |
55 | * Returns if the delta is compatible or not |
56 | * @param delta |
57 | * @return true if the delta represents a compatible change or not |
58 | */ |
59 | static boolean isCompatible0(IDelta delta) { |
60 | switch(delta.getElementType()) { |
61 | case IDelta.API_PROFILE_ELEMENT_TYPE : { |
62 | return isApiProfileCompatible(delta); |
63 | } |
64 | case IDelta.API_COMPONENT_ELEMENT_TYPE : { |
65 | return isApiComponentCompatible(delta); |
66 | } |
67 | case IDelta.INTERFACE_ELEMENT_TYPE : { |
68 | return isInterfaceCompatible(delta); |
69 | } |
70 | case IDelta.ANNOTATION_ELEMENT_TYPE : { |
71 | return isAnnotationCompatible(delta); |
72 | } |
73 | case IDelta.METHOD_ELEMENT_TYPE : { |
74 | return isMethodCompatible(delta); |
75 | } |
76 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : { |
77 | return isConstructorCompatible(delta); |
78 | } |
79 | case IDelta.FIELD_ELEMENT_TYPE : { |
80 | return isFieldCompatible(delta); |
81 | } |
82 | case IDelta.CLASS_ELEMENT_TYPE : { |
83 | return isClassCompatible(delta); |
84 | } |
85 | case IDelta.ENUM_ELEMENT_TYPE : { |
86 | return isEnumCompatible(delta); |
87 | } |
88 | case IDelta.TYPE_PARAMETER_ELEMENT_TYPE : { |
89 | return isTypeParameterCompatible(delta); |
90 | } |
91 | } |
92 | return true; |
93 | } |
94 | |
95 | /** |
96 | * Returns if the API profile is compatible |
97 | * @param delta |
98 | * @return true if compatible, false otherwise |
99 | */ |
100 | private static boolean isApiProfileCompatible(IDelta delta) { |
101 | switch(delta.getKind()) { |
102 | case IDelta.REMOVED : |
103 | switch(delta.getFlags()) { |
104 | case IDelta.API_COMPONENT : |
105 | return false; |
106 | } |
107 | } |
108 | return true; |
109 | } |
110 | |
111 | /** |
112 | * Returns if the API component is compatible |
113 | * @param delta |
114 | * @return true if compatible, false otherwise |
115 | */ |
116 | private static boolean isApiComponentCompatible(IDelta delta) { |
117 | switch(delta.getKind()) { |
118 | case IDelta.REMOVED : |
119 | switch(delta.getFlags()) { |
120 | case IDelta.TYPE : |
121 | case IDelta.API_TYPE : |
122 | case IDelta.REEXPORTED_API_TYPE : |
123 | case IDelta.REEXPORTED_TYPE : |
124 | return false; |
125 | } |
126 | break; |
127 | } |
128 | return true; |
129 | } |
130 | |
131 | /** |
132 | * Returns if the annotation is compatible or not |
133 | * @param delta |
134 | * @return true if compatible, false otherwise |
135 | */ |
136 | private static boolean isAnnotationCompatible(IDelta delta) { |
137 | switch(delta.getKind()) { |
138 | case IDelta.ADDED : |
139 | switch(delta.getFlags()) { |
140 | case IDelta.FIELD : |
141 | case IDelta.TYPE_PARAMETER : |
142 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : |
143 | return false; |
144 | } |
145 | break; |
146 | case IDelta.REMOVED : |
147 | switch(delta.getFlags()) { |
148 | case IDelta.FIELD : |
149 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : |
150 | case IDelta.METHOD_WITH_DEFAULT_VALUE : |
151 | case IDelta.API_FIELD : |
152 | case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE : |
153 | case IDelta.API_METHOD_WITH_DEFAULT_VALUE : |
154 | case IDelta.TYPE_MEMBER : |
155 | case IDelta.TYPE_PARAMETER : |
156 | return false; |
157 | } |
158 | break; |
159 | case IDelta.CHANGED : |
160 | switch(delta.getFlags()) { |
161 | case IDelta.CONTRACTED_SUPERINTERFACES_SET : |
162 | case IDelta.TYPE_CONVERSION : |
163 | return false; |
164 | } |
165 | break; |
166 | } |
167 | return true; |
168 | } |
169 | |
170 | /** |
171 | * Returns if the method is compatible or not |
172 | * @param delta |
173 | * @return true if compatible, false otherwise |
174 | */ |
175 | private static boolean isMethodCompatible(IDelta delta) { |
176 | int restrictions = delta.getRestrictions(); |
177 | if (RestrictionModifiers.isReferenceRestriction(restrictions)) { |
178 | return true; |
179 | } |
180 | switch(delta.getKind()) { |
181 | case IDelta.REMOVED : |
182 | switch(delta.getFlags()) { |
183 | case IDelta.ANNOTATION_DEFAULT_VALUE : |
184 | case IDelta.TYPE_PARAMETER : |
185 | return !Util.isVisible(delta.getOldModifiers()); |
186 | } |
187 | break; |
188 | case IDelta.ADDED : |
189 | switch(delta.getFlags()) { |
190 | case IDelta.TYPE_PARAMETER : |
191 | case IDelta.RESTRICTIONS : |
192 | return !Util.isVisible(delta.getNewModifiers()); |
193 | } |
194 | break; |
195 | case IDelta.CHANGED : |
196 | switch(delta.getFlags()) { |
197 | case IDelta.VARARGS_TO_ARRAY : |
198 | case IDelta.NON_ABSTRACT_TO_ABSTRACT : |
199 | case IDelta.NON_STATIC_TO_STATIC : |
200 | case IDelta.STATIC_TO_NON_STATIC : |
201 | return !Util.isVisible(delta.getNewModifiers()); |
202 | case IDelta.DECREASE_ACCESS : |
203 | return !Util.isVisible(delta.getOldModifiers()) |
204 | || RestrictionModifiers.isExtendRestriction(restrictions); |
205 | case IDelta.NON_FINAL_TO_FINAL : |
206 | return !Util.isVisible(delta.getOldModifiers()) |
207 | || !Util.isVisible(delta.getNewModifiers()) |
208 | || RestrictionModifiers.isExtendRestriction(restrictions) |
209 | || RestrictionModifiers.isOverrideRestriction(restrictions); |
210 | } |
211 | break; |
212 | } |
213 | return true; |
214 | } |
215 | |
216 | /** |
217 | * Returns if the field is compatible or not |
218 | * @param delta |
219 | * @return true if compatible, false otherwise |
220 | */ |
221 | private static boolean isFieldCompatible(IDelta delta) { |
222 | int restrictions = delta.getRestrictions(); |
223 | if (RestrictionModifiers.isReferenceRestriction(restrictions)) { |
224 | return true; |
225 | } |
226 | int newModifiers = delta.getNewModifiers(); |
227 | int oldModifiers = delta.getOldModifiers(); |
228 | switch(delta.getKind()) { |
229 | case IDelta.REMOVED : |
230 | switch(delta.getFlags()) { |
231 | case IDelta.VALUE : |
232 | if (Flags.isProtected(oldModifiers)) { |
233 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
234 | } |
235 | if (Flags.isPublic(oldModifiers)) { |
236 | return false; |
237 | } |
238 | // not visible |
239 | return true; |
240 | case IDelta.TYPE_ARGUMENTS : |
241 | case IDelta.TYPE_ARGUMENT : |
242 | return !Util.isVisible(oldModifiers); |
243 | } |
244 | break; |
245 | case IDelta.CHANGED : |
246 | if (!Util.isVisible(oldModifiers)) { |
247 | return true; |
248 | } |
249 | switch(delta.getFlags()) { |
250 | case IDelta.TYPE : |
251 | if (Flags.isProtected(newModifiers)) { |
252 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
253 | } |
254 | return !Util.isVisible(newModifiers); |
255 | case IDelta.TYPE_ARGUMENT : |
256 | case IDelta.NON_FINAL_TO_FINAL : |
257 | case IDelta.STATIC_TO_NON_STATIC : |
258 | case IDelta.NON_STATIC_TO_STATIC : |
259 | return !Util.isVisible(newModifiers); |
260 | case IDelta.VALUE : |
261 | case IDelta.FINAL_TO_NON_FINAL_STATIC_CONSTANT : |
262 | if (Flags.isProtected(newModifiers)) { |
263 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
264 | } |
265 | if (Flags.isPublic(newModifiers)) { |
266 | return false; |
267 | } |
268 | // not visible |
269 | return true; |
270 | case IDelta.DECREASE_ACCESS : |
271 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
272 | } |
273 | break; |
274 | case IDelta.ADDED : |
275 | switch(delta.getFlags()) { |
276 | case IDelta.TYPE_ARGUMENT : |
277 | return !Util.isVisible(newModifiers); |
278 | } |
279 | } |
280 | return true; |
281 | } |
282 | |
283 | /** |
284 | * Returns if the constructor is compatible or not |
285 | * @param delta |
286 | * @return true if compatible, false otherwise |
287 | */ |
288 | private static boolean isConstructorCompatible(IDelta delta) { |
289 | int restrictions = delta.getRestrictions(); |
290 | if (RestrictionModifiers.isReferenceRestriction(restrictions)) { |
291 | return true; |
292 | } |
293 | switch(delta.getKind()) { |
294 | case IDelta.REMOVED : |
295 | switch(delta.getFlags()) { |
296 | case IDelta.TYPE_PARAMETER : |
297 | return !Util.isVisible(delta.getOldModifiers()); |
298 | } |
299 | break; |
300 | case IDelta.ADDED : |
301 | switch(delta.getFlags()) { |
302 | case IDelta.TYPE_PARAMETER : |
303 | return !Util.isVisible(delta.getNewModifiers()); |
304 | } |
305 | break; |
306 | case IDelta.CHANGED : |
307 | switch(delta.getFlags()) { |
308 | case IDelta.VARARGS_TO_ARRAY : |
309 | case IDelta.NON_ABSTRACT_TO_ABSTRACT : |
310 | case IDelta.NON_STATIC_TO_STATIC : |
311 | case IDelta.STATIC_TO_NON_STATIC : |
312 | return !Util.isVisible(delta.getNewModifiers()); |
313 | case IDelta.DECREASE_ACCESS : |
314 | return RestrictionModifiers.isExtendRestriction(restrictions); |
315 | } |
316 | break; |
317 | } |
318 | return true; |
319 | } |
320 | |
321 | /** |
322 | * Returns if the enum is compatible or not |
323 | * @param delta |
324 | * @return true if compatible, false otherwise |
325 | */ |
326 | private static boolean isEnumCompatible(IDelta delta) { |
327 | switch(delta.getKind()) { |
328 | case IDelta.ADDED : |
329 | switch(delta.getFlags()) { |
330 | case IDelta.FIELD : |
331 | case IDelta.METHOD : |
332 | return !Util.isVisible(delta.getNewModifiers()); |
333 | } |
334 | break; |
335 | case IDelta.REMOVED : |
336 | switch(delta.getFlags()) { |
337 | case IDelta.FIELD : |
338 | case IDelta.ENUM_CONSTANT : |
339 | case IDelta.METHOD : |
340 | case IDelta.CONSTRUCTOR : |
341 | case IDelta.TYPE_MEMBER : |
342 | return !Util.isVisible(delta.getOldModifiers()); |
343 | case IDelta.API_FIELD : |
344 | case IDelta.API_ENUM_CONSTANT : |
345 | case IDelta.API_METHOD : |
346 | case IDelta.API_CONSTRUCTOR : |
347 | return false; |
348 | } |
349 | break; |
350 | case IDelta.CHANGED : |
351 | if (!Util.isVisible(delta.getNewModifiers())) { |
352 | return true; |
353 | } |
354 | switch(delta.getFlags()) { |
355 | case IDelta.CONTRACTED_SUPERINTERFACES_SET : |
356 | case IDelta.NON_ABSTRACT_TO_ABSTRACT : |
357 | case IDelta.TYPE_CONVERSION : |
358 | return false; |
359 | case IDelta.DECREASE_ACCESS : |
360 | return !Util.isVisible(delta.getOldModifiers()); |
361 | } |
362 | break; |
363 | } |
364 | return true; |
365 | } |
366 | |
367 | /** |
368 | * Returns if a class file is compatible |
369 | * @param delta |
370 | * @return true if compatible, false otherwise |
371 | */ |
372 | private static boolean isClassCompatible(IDelta delta) { |
373 | switch(delta.getKind()) { |
374 | case IDelta.ADDED: |
375 | int newModifiers = delta.getNewModifiers(); |
376 | switch(delta.getFlags()) { |
377 | case IDelta.FIELD : |
378 | return true; |
379 | case IDelta.METHOD : |
380 | if (Util.isVisible(newModifiers)) { |
381 | if (Flags.isAbstract(newModifiers)) { |
382 | // case where the implementation is provided and the class cannot be instantiated by the client |
383 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
384 | } |
385 | } |
386 | return true; |
387 | case IDelta.TYPE_PARAMETER : |
388 | case IDelta.RESTRICTIONS : |
389 | return !Util.isVisible(newModifiers); |
390 | } |
391 | break; |
392 | case IDelta.REMOVED : |
393 | switch(delta.getFlags()) { |
394 | case IDelta.FIELD : |
395 | case IDelta.API_FIELD : |
396 | case IDelta.API_METHOD : |
397 | case IDelta.METHOD : |
398 | case IDelta.TYPE_MEMBER : |
399 | if (Flags.isPublic(delta.getOldModifiers())) { |
400 | return false; |
401 | } |
402 | if (Flags.isProtected(delta.getOldModifiers())) { |
403 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
404 | } |
405 | return true; |
406 | case IDelta.CONSTRUCTOR : |
407 | case IDelta.API_CONSTRUCTOR : |
408 | if (Util.isVisible(delta.getOldModifiers())) { |
409 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()) |
410 | && (Flags.isProtected(delta.getOldModifiers()) || |
411 | RestrictionModifiers.isInstantiateRestriction(delta.getRestrictions())); |
412 | } |
413 | return true; |
414 | case IDelta.TYPE_PARAMETER : |
415 | case IDelta.SUPERCLASS : |
416 | return !Util.isVisible(delta.getOldModifiers()); |
417 | } |
418 | break; |
419 | case IDelta.CHANGED : |
420 | switch(delta.getFlags()) { |
421 | case IDelta.NON_ABSTRACT_TO_ABSTRACT : |
422 | if (Util.isVisible(delta.getNewModifiers())) { |
423 | return RestrictionModifiers.isInstantiateRestriction(delta.getRestrictions()); |
424 | } |
425 | return true; |
426 | case IDelta.TYPE_CONVERSION : |
427 | case IDelta.CONTRACTED_SUPERINTERFACES_SET : |
428 | case IDelta.STATIC_TO_NON_STATIC : |
429 | case IDelta.NON_STATIC_TO_STATIC : |
430 | return !Util.isVisible(delta.getNewModifiers()); |
431 | case IDelta.NON_FINAL_TO_FINAL: |
432 | if (Util.isVisible(delta.getNewModifiers())) { |
433 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
434 | } |
435 | return true; |
436 | case IDelta.DECREASE_ACCESS : |
437 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
438 | } |
439 | break; |
440 | } |
441 | return true; |
442 | } |
443 | /** |
444 | * Returns if the interface element is compatible |
445 | * @param delta |
446 | * @return true if compatible, false otherwise |
447 | */ |
448 | private static boolean isTypeParameterCompatible(IDelta delta) { |
449 | switch(delta.getKind()) { |
450 | case IDelta.ADDED : |
451 | switch(delta.getFlags()) { |
452 | case IDelta.CLASS_BOUND : |
453 | case IDelta.INTERFACE_BOUND : |
454 | return false; |
455 | } |
456 | break; |
457 | case IDelta.REMOVED : |
458 | switch(delta.getFlags()) { |
459 | case IDelta.CLASS_BOUND : |
460 | case IDelta.INTERFACE_BOUND : |
461 | return false; |
462 | } |
463 | break; |
464 | case IDelta.CHANGED : |
465 | switch(delta.getFlags()) { |
466 | case IDelta.CLASS_BOUND : |
467 | case IDelta.INTERFACE_BOUND : |
468 | return false; |
469 | } |
470 | break; |
471 | } |
472 | return true; |
473 | } |
474 | /** |
475 | * Returns if the interface element is compatible |
476 | * @param delta |
477 | * @return true if compatible, false otherwise |
478 | */ |
479 | private static boolean isInterfaceCompatible(IDelta delta) { |
480 | switch(delta.getKind()) { |
481 | case IDelta.ADDED : |
482 | switch(delta.getFlags()) { |
483 | case IDelta.FIELD : |
484 | return RestrictionModifiers.isImplementRestriction(delta.getRestrictions()); |
485 | case IDelta.METHOD : |
486 | case IDelta.SUPER_INTERFACE_WITH_METHODS : |
487 | return RestrictionModifiers.isImplementRestriction(delta.getRestrictions()); |
488 | case IDelta.TYPE_PARAMETER : |
489 | return false; |
490 | case IDelta.RESTRICTIONS : |
491 | return false; |
492 | } |
493 | break; |
494 | case IDelta.REMOVED : |
495 | switch(delta.getFlags()) { |
496 | case IDelta.FIELD : |
497 | case IDelta.METHOD : |
498 | case IDelta.API_FIELD : |
499 | case IDelta.API_METHOD : |
500 | case IDelta.TYPE_MEMBER : |
501 | case IDelta.TYPE_PARAMETER : |
502 | return false; |
503 | } |
504 | break; |
505 | case IDelta.CHANGED : |
506 | switch(delta.getFlags()) { |
507 | case IDelta.CONTRACTED_SUPERINTERFACES_SET : |
508 | case IDelta.TYPE_CONVERSION : |
509 | return false; |
510 | case IDelta.DECREASE_ACCESS : |
511 | return RestrictionModifiers.isExtendRestriction(delta.getRestrictions()); |
512 | } |
513 | break; |
514 | } |
515 | return true; |
516 | } |
517 | } |