Added
Link Here
|
1 |
/** |
2 |
* Copyright (c) 2006 Eclipse.org |
3 |
* |
4 |
* All rights reserved. This program and the accompanying materials |
5 |
* are made available under the terms of the Eclipse Public License v1.0 |
6 |
* which accompanies this distribution, and is available at |
7 |
* http://www.eclipse.org/legal/epl-v10.html |
8 |
* |
9 |
* Contributors: |
10 |
* bblajer - initial API and implementation |
11 |
*/ |
12 |
package org.eclipse.gmf.tests; |
13 |
|
14 |
import java.text.MessageFormat; |
15 |
|
16 |
import org.eclipse.core.resources.IProject; |
17 |
import org.eclipse.core.runtime.IStatus; |
18 |
import org.eclipse.core.runtime.MultiStatus; |
19 |
import org.eclipse.core.runtime.Status; |
20 |
import org.eclipse.jdt.core.ICompilationUnit; |
21 |
import org.eclipse.jdt.core.IJavaElement; |
22 |
import org.eclipse.jdt.core.IJavaProject; |
23 |
import org.eclipse.jdt.core.IMember; |
24 |
import org.eclipse.jdt.core.IPackageFragment; |
25 |
import org.eclipse.jdt.core.IPackageFragmentRoot; |
26 |
import org.eclipse.jdt.core.ISourceRange; |
27 |
import org.eclipse.jdt.core.IType; |
28 |
import org.eclipse.jdt.core.JavaCore; |
29 |
import org.eclipse.jdt.core.JavaModelException; |
30 |
|
31 |
/** |
32 |
* Utility that checks various assumptions on the generated code. Currently, only the correct placement of <code>@generated</code> tags is checked. |
33 |
*/ |
34 |
public class JDTUtil { |
35 |
private final IJavaProject myJavaProject; |
36 |
private ViolationAggregator myAggregator; |
37 |
|
38 |
private static interface IMemberProcessor { |
39 |
public IStatus processMember(IMember member, boolean isLocalMember) throws JavaModelException; |
40 |
} |
41 |
|
42 |
private static class ViolationAggregator { |
43 |
private MultiStatus myStatus = new MultiStatus(Plugin.getPluginID(), 0, "JDT Violations", null); |
44 |
|
45 |
public void add(IStatus status) { |
46 |
myStatus.merge(status); |
47 |
} |
48 |
|
49 |
public IStatus getStatus() { |
50 |
if (myStatus.isOK()) { |
51 |
return Status.OK_STATUS; |
52 |
} |
53 |
StringBuffer buffer = new StringBuffer(); |
54 |
IStatus[] children = myStatus.getChildren(); |
55 |
for(int i = 0; i < children.length; i++) { |
56 |
if (children[i].matches(myStatus.getSeverity())) { |
57 |
buffer.append(children[i].getMessage()).append("\n"); |
58 |
} |
59 |
} |
60 |
return new Status(myStatus.getSeverity(), Plugin.getPluginID(), 0, buffer.toString(), null); |
61 |
} |
62 |
} |
63 |
|
64 |
public JDTUtil(IJavaProject javaProject) { |
65 |
myJavaProject = javaProject; |
66 |
} |
67 |
|
68 |
public JDTUtil(IProject p) { |
69 |
this(JavaCore.create(p)); |
70 |
} |
71 |
|
72 |
public IStatus collectProblems() { |
73 |
return collectProblems(new IMemberProcessor[] {new GeneratedTagEnsurer(), new GeneratedTagAbsenceInLocalMembersEnsurer()}); |
74 |
} |
75 |
|
76 |
private IStatus collectProblems(IMemberProcessor[] processors) { |
77 |
if (myAggregator == null) { |
78 |
myAggregator = new ViolationAggregator(); |
79 |
collectProblems(myJavaProject, processors); |
80 |
} |
81 |
return myAggregator.getStatus(); |
82 |
} |
83 |
|
84 |
private void collectProblems(IJavaElement jElement, IMemberProcessor[] processors) { |
85 |
try { |
86 |
switch (jElement.getElementType()) { |
87 |
case IJavaElement.JAVA_PROJECT: |
88 |
{ |
89 |
IJavaProject jProject = (IJavaProject) jElement; |
90 |
IPackageFragmentRoot[] roots = jProject.getPackageFragmentRoots(); |
91 |
for(int i = 0; i < roots.length; i++) { |
92 |
if (roots[i].getKind() == IPackageFragmentRoot.K_SOURCE) { |
93 |
collectProblems(roots[i], processors); |
94 |
} |
95 |
} |
96 |
} |
97 |
break; |
98 |
case IJavaElement.PACKAGE_FRAGMENT_ROOT: |
99 |
{ |
100 |
IPackageFragmentRoot root = (IPackageFragmentRoot) jElement; |
101 |
IJavaElement[] children = root.getChildren(); |
102 |
for(int i = 0; i < children.length; i++) { |
103 |
collectProblems(children[i], processors); |
104 |
} |
105 |
} |
106 |
break; |
107 |
case IJavaElement.PACKAGE_FRAGMENT: |
108 |
{ |
109 |
IPackageFragment pf = (IPackageFragment) jElement; |
110 |
ICompilationUnit[] compilationUnits = pf.getCompilationUnits(); |
111 |
for(int i = 0; i < compilationUnits.length; i++) { |
112 |
collectProblems(compilationUnits[i], processors); |
113 |
} |
114 |
} |
115 |
break; |
116 |
case IJavaElement.COMPILATION_UNIT: |
117 |
{ |
118 |
ICompilationUnit compilationUnit = (ICompilationUnit) jElement; |
119 |
IType[] types = compilationUnit.getTypes(); |
120 |
for(int i = 0; i < types.length; i++) { |
121 |
collectProblems(types[i], processors); |
122 |
} |
123 |
} |
124 |
break; |
125 |
case IJavaElement.TYPE: |
126 |
{ |
127 |
IMember member = (IMember) jElement; |
128 |
collectProblems(member, processors, false); |
129 |
} |
130 |
break; |
131 |
} |
132 |
} catch (JavaModelException e) { |
133 |
myAggregator.add(e.getStatus()); |
134 |
} |
135 |
} |
136 |
|
137 |
private void collectProblems(IMember member, IMemberProcessor[] processors, boolean isLocalMember) throws JavaModelException { |
138 |
for (int i = 0; i < processors.length; i++) { |
139 |
IStatus status = processors[i].processMember(member, isLocalMember); |
140 |
if (status != null && !status.isOK()) { |
141 |
myAggregator.add(status); |
142 |
} |
143 |
} |
144 |
isLocalMember |= !(member instanceof IType); |
145 |
IJavaElement[] children = member.getChildren(); |
146 |
for(int i = 0; i < children.length; i++) { |
147 |
collectProblems((IMember) children[i], processors, isLocalMember); |
148 |
} |
149 |
} |
150 |
|
151 |
private abstract static class JavadocMemberProcessor implements IMemberProcessor { |
152 |
protected static final String GENERATED = "@generated"; //$NON-NLS-1$ |
153 |
protected final String getJavadoc(IMember member) throws JavaModelException { |
154 |
ISourceRange javadocRange = member.getJavadocRange(); |
155 |
if (javadocRange == null) { |
156 |
return ""; //$NON-NLS-1$ |
157 |
} |
158 |
return member.getCompilationUnit().getSource().substring(javadocRange.getOffset(), javadocRange.getLength() + javadocRange.getOffset()); |
159 |
} |
160 |
} |
161 |
|
162 |
private static class GeneratedTagEnsurer extends JavadocMemberProcessor { |
163 |
public IStatus processMember(IMember member, boolean isLocalMember) throws JavaModelException { |
164 |
if (isLocalMember) { |
165 |
return null; |
166 |
} |
167 |
if (member.getElementType() == IJavaElement.INITIALIZER && member.getOccurrenceCount() > 1) { |
168 |
return newViolation(member, "Multiple sibling initializers should be avoided in the generated code: they may not always be merged correctly"); |
169 |
} |
170 |
String javadoc = getJavadoc(member); |
171 |
int index = javadoc.lastIndexOf(GENERATED); |
172 |
if (index == -1) { |
173 |
return newViolation(member, "@generated is missing"); |
174 |
} |
175 |
if (javadoc.indexOf(GENERATED) != index) { |
176 |
return newViolation(member, "There is more than one @generated tag"); |
177 |
} |
178 |
String afterGenerated = javadoc.substring(index + GENERATED.length()).trim(); |
179 |
String asteriskIgnored = afterGenerated.replace('*', ' ').trim(); |
180 |
if (asteriskIgnored.length() == 0) { |
181 |
return newViolation(member, "JavaDoc comment with @generated tag is not terminated properly"); |
182 |
} |
183 |
switch (asteriskIgnored.charAt(0)) { |
184 |
case '@': |
185 |
//Next tag starts here, thus @generated is OK |
186 |
break; |
187 |
case '/': |
188 |
//Most likely, this is an end of a JavaDoc comment terminator. |
189 |
//TODO: check this assumption using the content of afterGenerated |
190 |
break; |
191 |
default: |
192 |
return newViolation(member, "@generated tag will be interpreted as @generated NOT"); |
193 |
} |
194 |
return null; |
195 |
} |
196 |
} |
197 |
|
198 |
private static class GeneratedTagAbsenceInLocalMembersEnsurer extends JavadocMemberProcessor { |
199 |
public IStatus processMember(IMember member, boolean isLocalMember) throws JavaModelException { |
200 |
if (!isLocalMember) { |
201 |
return null; |
202 |
} |
203 |
String javadoc = getJavadoc(member); |
204 |
if (javadoc.indexOf(GENERATED) != -1) { |
205 |
return newViolation(member, "@generated tag in local members is misleading"); |
206 |
} |
207 |
return null; |
208 |
} |
209 |
} |
210 |
|
211 |
private static IStatus newViolation(IMember member, String description) { |
212 |
return new Status(IStatus.ERROR, Plugin.getPluginID(), 0, MessageFormat.format("{0} has problem: {1}", new Object[] {member.getHandleIdentifier(), description}), null); |
213 |
} |
214 |
} |