2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* Portions Copyrighted 2007 Sun Microsystems, Inc.
28
package org.netbeans.modules.java.hints;
30
import com.sun.source.tree.ClassTree;
31
import com.sun.source.tree.ExpressionTree;
32
import com.sun.source.tree.MethodTree;
33
import com.sun.source.tree.ModifiersTree;
34
import com.sun.source.tree.StatementTree;
35
import com.sun.source.tree.Tree;
36
import com.sun.source.tree.Tree.Kind;
37
import com.sun.source.tree.TypeParameterTree;
38
import com.sun.source.tree.VariableTree;
39
import com.sun.source.util.TreePath;
40
import java.io.IOException;
41
import java.util.Collections;
42
import java.util.EnumSet;
43
import java.util.List;
45
import java.util.prefs.Preferences;
46
import javax.lang.model.element.Element;
47
import javax.lang.model.element.ElementKind;
48
import javax.lang.model.element.ElementVisitor;
49
import javax.lang.model.element.ExecutableElement;
50
import javax.lang.model.element.Modifier;
51
import javax.lang.model.element.Name;
52
import javax.lang.model.element.PackageElement;
53
import javax.lang.model.element.TypeElement;
54
import javax.lang.model.element.TypeParameterElement;
55
import javax.lang.model.element.VariableElement;
56
import javax.lang.model.type.TypeMirror;
57
import javax.swing.JComponent;
58
import javax.swing.text.BadLocationException;
59
import javax.swing.text.Document;
60
import org.netbeans.api.java.source.Task;
61
import org.netbeans.api.java.source.CompilationInfo;
62
import org.netbeans.api.java.source.JavaSource;
63
import org.netbeans.api.java.source.ModificationResult;
64
import org.netbeans.api.java.source.TreePathHandle;
65
import org.netbeans.api.java.source.WorkingCopy;
66
import org.netbeans.modules.java.editor.semantic.Utilities;
67
import org.netbeans.modules.java.hints.spi.AbstractHint;
68
import org.netbeans.spi.editor.hints.ChangeInfo;
69
import org.netbeans.spi.editor.hints.ErrorDescription;
70
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
71
import org.netbeans.spi.editor.hints.Fix;
72
import org.openide.filesystems.FileObject;
73
import org.openide.util.Exceptions;
74
import org.openide.util.NbBundle;
78
* @author Jaroslav tulach
80
public class UtilityClass extends AbstractHint implements ElementVisitor<Boolean,CompilationInfo> {
81
private boolean clazz;
82
private transient volatile boolean stop;
84
/** Creates a new instance of AddOverrideAnnotation */
85
private UtilityClass(boolean b) {
86
super( false, true, b ? AbstractHint.HintSeverity.WARNING : AbstractHint.HintSeverity.CURRENT_LINE_WARNING);
90
public Set<Kind> getTreeKinds() {
91
return EnumSet.of(clazz ? Kind.CLASS : Kind.METHOD);
94
public static UtilityClass withoutConstructor() {
95
return new UtilityClass(true);
97
public static UtilityClass withConstructor() {
98
return new UtilityClass(false);
101
public List<ErrorDescription> run(CompilationInfo compilationInfo,
105
Document doc = compilationInfo.getDocument();
111
Element e = compilationInfo.getTrees().getElement(treePath);
117
if (e.getKind() == ElementKind.ENUM) {
120
if (e.getKind() == ElementKind.INTERFACE) {
123
if (e.getKind() == ElementKind.ANNOTATION_TYPE) {
126
if (e.getKind() == ElementKind.CLASS) {
127
TypeMirror supr = ((TypeElement)e).getSuperclass();
131
Element superElem = compilationInfo.getTypes().asElement(supr);
132
if (superElem instanceof TypeElement) {
133
Name superName = compilationInfo.getElements().getBinaryName((TypeElement)superElem);
134
if (superName != null && !superName.contentEquals("java.lang.Object")) {
141
for (Element m : e.getEnclosedElements()) {
145
if (m.accept(this, compilationInfo)) {
148
if (m.getKind() == ElementKind.METHOD || m.getKind() == ElementKind.FIELD) {
158
if (e.getKind() != ElementKind.CONSTRUCTOR) {
161
ExecutableElement x = (ExecutableElement)e;
162
for (Element m : x.getEnclosingElement().getEnclosedElements()) {
166
if (m.accept(this, compilationInfo)) {
170
if (x.getModifiers().contains(Modifier.PROTECTED) || x.getModifiers().contains(Modifier.PUBLIC)) {
176
List<Fix> fixes = Collections.<Fix>singletonList(new FixImpl(
178
TreePathHandle.create(e, compilationInfo),
179
compilationInfo.getFileObject()
182
int[] span = Utilities.findIdentifierSpan(treePath, compilationInfo, doc);
184
if (span[0] != (-1) && span[1] != (-1)) {
185
ErrorDescription ed = ErrorDescriptionFactory.createErrorDescription(
186
getSeverity().toEditorSeverity(),
187
NbBundle.getMessage(UtilityClass.class, clazz ? "MSG_UtilityClass" : "MSG_PublicConstructor"), // NOI18N
190
doc.createPosition(span[0]),
191
doc.createPosition(span[1])
194
return Collections.singletonList(ed);
196
} catch (BadLocationException e) {
197
Exceptions.printStackTrace(e);
198
} catch (IOException e) {
199
Exceptions.printStackTrace(e);
205
public String getId() {
206
return getClass().getName();
209
public String getDisplayName() {
210
return NbBundle.getMessage(UtilityClass.class, clazz ? "MSG_UtilityClass" : "MSG_PublicConstructor"); // NOI18N
213
public String getDescription() {
214
return NbBundle.getMessage(UtilityClass.class, clazz ? "HINT_UtilityClass" : "HINT_PublicConstructor"); // NOI18N
217
public void cancel() {
221
public Preferences getPreferences() {
226
public JComponent getCustomizer(Preferences node) {
230
public Boolean visit(Element arg0, CompilationInfo arg1) {
234
public Boolean visit(Element arg0) {
238
public Boolean visitPackage(PackageElement arg0, CompilationInfo arg1) {
242
public Boolean visitType(TypeElement arg0, CompilationInfo arg1) {
246
public Boolean visitVariable(VariableElement v, CompilationInfo arg1) {
247
return !v.getModifiers().contains(Modifier.STATIC);
250
public Boolean visitExecutable(ExecutableElement m, CompilationInfo arg1) {
252
return !m.getModifiers().contains(Modifier.STATIC) && !arg1.getElementUtilities().isSynthetic(m);
254
return !m.getModifiers().contains(Modifier.STATIC) && !m.getSimpleName().contentEquals("<init>"); // NOI18N
258
public Boolean visitTypeParameter(TypeParameterElement arg0, CompilationInfo arg1) {
262
public Boolean visitUnknown(Element arg0, CompilationInfo arg1) {
266
private static final class FixImpl implements Fix, Task<WorkingCopy> {
267
private TreePathHandle handle;
268
private FileObject file;
269
private boolean clazz;
271
public FixImpl(boolean clazz, TreePathHandle handle, FileObject file) {
272
this.handle = handle;
277
public String getText() {
278
return NbBundle.getMessage(UtilityClass.class, clazz ? "MSG_PrivateConstructor" : "MSG_MakePrivate"); // NOI18N
281
public ChangeInfo implement() throws IOException {
282
ModificationResult result = JavaSource.forFileObject(file).runModificationTask(this);
287
@Override public String toString() {
288
return "FixUtilityClass"; // NOI18N
291
public void run(WorkingCopy wc) throws Exception {
292
wc.toPhase(JavaSource.Phase.RESOLVED);
294
Element e = handle.resolveElement(wc);
298
Tree outer = wc.getTrees().getTree(e);
300
if (outer == null || outer.getKind() != Kind.CLASS) {
303
ClassTree cls = (ClassTree)outer;
305
ModifiersTree modifiers = wc.getTreeMaker().Modifiers(Collections.singleton(Modifier.PRIVATE));
306
MethodTree m = wc.getTreeMaker().Constructor(
308
Collections.<TypeParameterTree>emptyList(),
309
Collections.<VariableTree>emptyList(),
310
Collections.<ExpressionTree>emptyList(),
311
wc.getTreeMaker().Block(Collections.<StatementTree>emptyList(), false)
313
wc.rewrite(cls, wc.getTreeMaker().addClassMember(cls, m));
315
if (outer == null || outer.getKind() != Kind.METHOD) {
318
MethodTree met = (MethodTree)outer;
320
ModifiersTree modifiers = wc.getTreeMaker().Modifiers(Collections.singleton(Modifier.PRIVATE), met.getModifiers().getAnnotations());
321
wc.rewrite(met.getModifiers(), modifiers);