]>
Commit | Line | Data |
---|---|---|
1b2798f6 EK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2009, 2011 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 | * Mateusz Wenus <mateusz.wenus@gmail.com> - [override method] generate in declaration order [code generation] - https://bugs.eclipse.org/bugs/show_bug.cgi?id=140971 | |
10 | * IBM Corporation - bug fixes | |
11 | *******************************************************************************/ | |
12 | package org.eclipse.jdt.internal.corext.util; | |
13 | ||
14 | import java.util.Comparator; | |
15 | ||
16 | import org.eclipse.jdt.core.IMethod; | |
17 | import org.eclipse.jdt.core.ISourceRange; | |
18 | import org.eclipse.jdt.core.JavaModelException; | |
19 | import org.eclipse.jdt.core.SourceRange; | |
20 | import org.eclipse.jdt.core.dom.IMethodBinding; | |
21 | import org.eclipse.jdt.core.dom.ITypeBinding; | |
22 | ||
23 | /** | |
24 | * A comparator which sorts methods (IMethodBinding) of a type passed as constructor argument, | |
25 | * according to their order in source files. More formally, if <code>m1</code> and <code>m2</code> | |
26 | * are methods of type <code>T</code> then according to this comparator <code>m1</code> is less than | |
27 | * <code>m2</code> iff one of following holds: | |
28 | * <ul> | |
29 | * <li><code>m1</code> and <code>m2</code> are defined in the same type (<code>T</code> or any | |
30 | * supertype of <code>T</code>), that type has a source attachment and <code>m1</code> appears | |
31 | * before <code>m2</code> in source of that type</li> | |
32 | * <li><code>m1</code> and <code>m2</code> are defined in the same type (<code>T</code> or any | |
33 | * supertype of <code>T</code>), that type doesn't have a source attachment and name of | |
34 | * <code>m1</code> alphabetically precedes name of <code>m2</code></li> | |
35 | * | |
36 | * <li><code>m2</code> is defined in <code>T</code> and <code>m1</code> is defined in any supertype | |
37 | * of <code>T</code></li> | |
38 | * <li><code>m2</code> is defined in a superclass of <code>T</code> and <code>m1</code> is defined | |
39 | * in a superinterface of <code>T</code></li> | |
40 | * <li><code>m1</code> and <code>m2</code> are defined in different superclasses of <code>T</code> | |
41 | * and a class which defines <code>m1</code> extends class which defines <code>m2</code> | |
42 | * <li><code>m1</code> and <code>m2</code> are defined in different superinterfaces of | |
43 | * <code>T</code> and an interface which defines <code>m2</code> appears before an interface which | |
44 | * defines <code>m1</code> in <code>implements</code> clause of declaration of type <code>T</code></li> | |
45 | * </ul> | |
46 | */ | |
47 | public class MethodsSourcePositionComparator implements Comparator<IMethodBinding> { | |
48 | ||
49 | private final ITypeBinding fTypeBinding; | |
50 | ||
51 | public MethodsSourcePositionComparator(ITypeBinding typeBinding) { | |
52 | if (typeBinding == null) { | |
53 | throw new IllegalArgumentException(); | |
54 | } | |
55 | fTypeBinding= typeBinding; | |
56 | } | |
57 | ||
58 | public int compare(IMethodBinding firstMethodBinding, IMethodBinding secondMethodBinding) { | |
59 | if (firstMethodBinding == null || secondMethodBinding == null) { | |
60 | return 0; | |
61 | } | |
62 | ITypeBinding firstMethodType= firstMethodBinding.getDeclaringClass(); | |
63 | ITypeBinding secondMethodType= secondMethodBinding.getDeclaringClass(); | |
64 | ||
65 | if (firstMethodType.equals(secondMethodType)) { | |
66 | return compareInTheSameType(firstMethodBinding, secondMethodBinding); | |
67 | } | |
68 | ||
69 | if (firstMethodType.equals(fTypeBinding)) { | |
70 | return 1; | |
71 | } | |
72 | if (secondMethodType.equals(fTypeBinding)) { | |
73 | return -1; | |
74 | } | |
75 | ||
76 | ITypeBinding type= fTypeBinding; | |
77 | int count= 0, firstCount= -1, secondCount= -1; | |
78 | while ((type= type.getSuperclass()) != null) { | |
79 | if (firstMethodType.equals(type)) { | |
80 | firstCount= count; | |
81 | } | |
82 | if (secondMethodType.equals(type)) { | |
83 | secondCount= count; | |
84 | } | |
85 | count++; | |
86 | } | |
87 | if (firstCount != -1 && secondCount != -1) { | |
88 | return (firstCount - secondCount); | |
89 | } | |
90 | if (firstCount != -1 && secondCount == -1) { | |
91 | return 1; | |
92 | } | |
93 | if (firstCount == -1 && secondCount != -1) { | |
94 | return -1; | |
95 | } | |
96 | ||
97 | ITypeBinding[] interfaces= fTypeBinding.getInterfaces(); | |
98 | for (int i= 0; i < interfaces.length; i++) { | |
99 | if (firstMethodType.equals(interfaces[i])) { | |
100 | return 1; | |
101 | } | |
102 | if (secondMethodType.equals(interfaces[i])) { | |
103 | return -1; | |
104 | } | |
105 | } | |
106 | return 0; | |
107 | } | |
108 | ||
109 | private int compareInTheSameType(IMethodBinding firstMethodBinding, IMethodBinding secondMethodBinding) { | |
110 | try { | |
111 | IMethod firstMethod= (IMethod)firstMethodBinding.getJavaElement(); | |
112 | IMethod secondMethod= (IMethod)secondMethodBinding.getJavaElement(); | |
113 | if (firstMethod == null || secondMethod == null) { | |
114 | return 0; | |
115 | } | |
116 | ISourceRange firstSourceRange= firstMethod.getSourceRange(); | |
117 | ISourceRange secondSourceRange= secondMethod.getSourceRange(); | |
118 | ||
119 | if (!SourceRange.isAvailable(firstSourceRange) || !SourceRange.isAvailable(secondSourceRange)) { | |
120 | return firstMethod.getElementName().compareTo(secondMethod.getElementName()); | |
121 | } else { | |
122 | return firstSourceRange.getOffset() - secondSourceRange.getOffset(); | |
123 | } | |
124 | } catch (JavaModelException e) { | |
125 | return 0; | |
126 | } | |
127 | } | |
128 | } |