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.BlockTree;
31
import com.sun.source.tree.DoWhileLoopTree;
32
import com.sun.source.tree.EnhancedForLoopTree;
33
import com.sun.source.tree.ExpressionStatementTree;
34
import com.sun.source.tree.ForLoopTree;
35
import com.sun.source.tree.IfTree;
36
import com.sun.source.tree.IfTree;
37
import com.sun.source.tree.StatementTree;
38
import com.sun.source.tree.Tree;
39
import com.sun.source.tree.Tree.Kind;
40
import com.sun.source.tree.WhileLoopTree;
41
import com.sun.source.util.TreePath;
42
import java.io.IOException;
43
import java.util.ArrayList;
44
import java.util.Collections;
45
import java.util.EnumSet;
46
import java.util.List;
48
import org.netbeans.api.java.lexer.JavaTokenId;
49
import org.netbeans.api.java.source.Task;
50
import org.netbeans.api.java.source.CompilationInfo;
51
import org.netbeans.api.java.source.JavaSource;
52
import org.netbeans.api.java.source.TreeMaker;
53
import org.netbeans.api.java.source.TreePathHandle;
54
import org.netbeans.api.java.source.WorkingCopy;
55
import org.netbeans.modules.java.hints.spi.AbstractHint;
56
import org.netbeans.spi.editor.hints.ChangeInfo;
57
import org.netbeans.spi.editor.hints.ErrorDescription;
58
import org.netbeans.spi.editor.hints.ErrorDescriptionFactory;
59
import org.netbeans.spi.editor.hints.Fix;
60
import org.openide.filesystems.FileObject;
61
import org.openide.util.Exceptions;
62
import org.openide.util.NbBundle;
68
public class Braces extends AbstractHint {
70
static final EnumSet<JavaTokenId> nonRelevant = EnumSet.<JavaTokenId>of(
71
JavaTokenId.LINE_COMMENT,
72
JavaTokenId.BLOCK_COMMENT,
73
JavaTokenId.JAVADOC_COMMENT,
74
JavaTokenId.WHITESPACE
77
private static final List<Fix> NO_FIXES = Collections.<Fix>emptyList();
79
private String BRACES_ID = "Braces_"; // NOI18N
81
private Tree.Kind treeKind;
82
private Set<Tree.Kind> treeKinds;
84
private Braces( Tree.Kind treeKind ) {
85
super( false, true, HintSeverity.WARNING );
86
this.treeKind = treeKind;
87
if ( treeKind == Tree.Kind.FOR_LOOP ) {
88
this.treeKinds = EnumSet.<Tree.Kind>of(treeKind, Tree.Kind.ENHANCED_FOR_LOOP);
91
this.treeKinds = Collections.<Tree.Kind>singleton(treeKind);
95
public static Braces createFor() {
96
return new Braces( Tree.Kind.FOR_LOOP );
99
public static Braces createWhile() {
100
return new Braces( Tree.Kind.WHILE_LOOP );
103
public static Braces createDoWhile() {
104
return new Braces( Tree.Kind.DO_WHILE_LOOP );
107
public static Braces createIf() {
108
return new Braces( Tree.Kind.IF );
111
public Set<Kind> getTreeKinds() {
115
public List<ErrorDescription> run(CompilationInfo compilationInfo, TreePath treePath) {
117
Tree tree = treePath.getLeaf();
119
ErrorDescription ed = null;
121
switch( tree.getKind() ) {
123
ForLoopTree flt = (ForLoopTree) tree;
124
ed = checkStatement(flt.getStatement(), treePath, compilationInfo);
126
return Collections.singletonList(ed);
129
case ENHANCED_FOR_LOOP:
130
EnhancedForLoopTree eflt = (EnhancedForLoopTree) tree;
131
ed = checkStatement( eflt.getStatement(), treePath, compilationInfo );
133
return Collections.singletonList(ed);
137
WhileLoopTree wlt = (WhileLoopTree) tree;
138
ed = checkStatement( wlt.getStatement(), treePath, compilationInfo);
140
return Collections.singletonList(ed);
144
DoWhileLoopTree dwlt = (DoWhileLoopTree) tree;
145
ed = checkStatement( dwlt.getStatement(), treePath, compilationInfo);
147
return Collections.singletonList(ed);
151
IfTree it = (IfTree)tree;
152
List<ErrorDescription> eds = checkifStatements(it.getThenStatement(), it.getElseStatement(), treePath, compilationInfo );
156
return Collections.<ErrorDescription>emptyList();
159
public void cancel() {
163
public String getId() {
164
return BRACES_ID + treeKind;
167
public String getDisplayName() {
170
return NbBundle.getMessage(Braces.class, "LBL_Braces_For"); // NOI18N
172
return NbBundle.getMessage(Braces.class, "LBL_Braces_While"); // NOI18N
174
return NbBundle.getMessage(Braces.class, "LBL_Braces_DoWhile"); // NOI18N
176
return NbBundle.getMessage(Braces.class, "LBL_Braces_If"); // NOI18N
178
return "No Name"; // NOI18N
182
public String getDescription() {
185
return NbBundle.getMessage(Braces.class, "DSC_Braces_For"); // NOI18N
187
return NbBundle.getMessage(Braces.class, "DSC_Braces_While"); // NOI18N
189
return NbBundle.getMessage(Braces.class, "DSC_Braces_DoWhile"); // NOI18N
191
return NbBundle.getMessage(Braces.class, "DSC_Braces_If"); // NOI18N
193
return "No Description"; // NOI18N
197
// Private methods ---------------------------------------------------------
199
private ErrorDescription checkStatement( StatementTree statement, TreePath tp, CompilationInfo info ) {
201
if ( statement != null &&
202
statement.getKind() != Tree.Kind.EMPTY_STATEMENT &&
203
statement.getKind() != Tree.Kind.BLOCK &&
204
statement.getKind() != Tree.Kind.ERRONEOUS &&
205
!isErroneousExpression( statement ) ) {
206
return ErrorDescriptionFactory.createErrorDescription(
207
getSeverity().toEditorSeverity(),
209
Collections.<Fix>singletonList(new BracesFix( info.getFileObject(), TreePathHandle.create(tp, info) ) ),
210
info.getFileObject(),
211
(int)info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), statement ),
212
(int)info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), statement ) );
219
private List<ErrorDescription> checkifStatements( StatementTree thenSt, StatementTree elseSt, TreePath tp, CompilationInfo info ) {
221
boolean fixThen = false;
222
boolean fixElse = false;
224
if ( thenSt != null &&
225
thenSt.getKind() != Tree.Kind.EMPTY_STATEMENT &&
226
thenSt.getKind() != Tree.Kind.BLOCK &&
227
thenSt.getKind() != Tree.Kind.ERRONEOUS &&
228
!isErroneousExpression( thenSt )) {
232
if ( elseSt != null &&
233
elseSt.getKind() != Tree.Kind.EMPTY_STATEMENT &&
234
elseSt.getKind() != Tree.Kind.BLOCK &&
235
elseSt.getKind() != Tree.Kind.ERRONEOUS &&
236
elseSt.getKind() != Tree.Kind.IF &&
237
!isErroneousExpression( elseSt )) {
241
List<ErrorDescription> result = new ArrayList<ErrorDescription>();
244
BracesFix bf = new BracesFix( info.getFileObject(), TreePathHandle.create(tp, info));
245
bf.fixThen = fixThen;
246
bf.fixElse = fixElse;
247
result.add( ErrorDescriptionFactory.createErrorDescription(
248
getSeverity().toEditorSeverity(),
250
Collections.<Fix>singletonList( bf ),
251
info.getFileObject(),
252
(int)info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), thenSt ),
253
(int)info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), thenSt ) ) );
257
BracesFix bf = new BracesFix( info.getFileObject(), TreePathHandle.create(tp, info));
258
bf.fixThen = fixThen;
259
bf.fixElse = fixElse;
260
result.add( ErrorDescriptionFactory.createErrorDescription(
261
getSeverity().toEditorSeverity(),
263
Collections.<Fix>singletonList( bf ),
264
info.getFileObject(),
265
(int)info.getTrees().getSourcePositions().getStartPosition(info.getCompilationUnit(), elseSt ),
266
(int)info.getTrees().getSourcePositions().getEndPosition(info.getCompilationUnit(), elseSt ) ) );
273
private boolean isErroneousExpression(StatementTree statement) {
274
if ( statement instanceof ExpressionStatementTree ) {
275
if ( ((ExpressionStatementTree)statement).getExpression().getKind() == Kind.ERRONEOUS ) {
282
private static class BracesFix implements Fix, Task<WorkingCopy> {
292
public BracesFix(FileObject file, TreePathHandle tph) {
297
public String getText() {
298
return NbBundle.getMessage(Braces.class, "LBL_Braces_Fix"); // NOI18N
301
public ChangeInfo implement() throws IOException {
302
JavaSource js = JavaSource.forFileObject(file);
303
js.runModificationTask(this).commit();
307
public void run(WorkingCopy copy) throws Exception {
308
copy.toPhase(JavaSource.Phase.PARSED);
309
TreePath path = tph.resolve(copy);
311
if ( path != null ) {
313
TreeMaker make = copy.getTreeMaker();
314
Tree oldTree = path.getLeaf();
316
switch( oldTree.getKind() ) {
318
ForLoopTree oldFor = (ForLoopTree)oldTree;
319
StatementTree oldBlock = oldFor.getStatement();
320
BlockTree newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
321
copy.rewrite(oldBlock, newBlock);
323
case ENHANCED_FOR_LOOP:
324
EnhancedForLoopTree oldEnhancedFor = (EnhancedForLoopTree)oldTree;
325
oldBlock = oldEnhancedFor.getStatement();
326
newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
327
copy.rewrite(oldBlock, newBlock);
330
WhileLoopTree oldWhile = (WhileLoopTree)oldTree;
331
oldBlock = oldWhile.getStatement();
332
newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
333
copy.rewrite(oldBlock, newBlock);
336
DoWhileLoopTree oldDoWhile = (DoWhileLoopTree)oldTree;
337
oldBlock = oldDoWhile.getStatement();
338
newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
339
copy.rewrite(oldBlock, newBlock);
342
IfTree oldIf = (IfTree)oldTree;
344
oldBlock = oldIf.getThenStatement();
345
newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
346
copy.rewrite(oldBlock, newBlock);
349
oldBlock = oldIf.getElseStatement();
350
newBlock = make.Block(Collections.<StatementTree>singletonList(oldBlock), false);
351
copy.rewrite(oldBlock, newBlock);