1.1 --- a/api/src/org/netbeans/modules/jackpot30/spi/JavaFix.java Fri Jan 21 23:13:54 2011 +0100
1.2 +++ b/api/src/org/netbeans/modules/jackpot30/spi/JavaFix.java Sun Jan 23 13:59:19 2011 +0100
1.3 @@ -41,6 +41,7 @@
1.4
1.5 import com.sun.javadoc.Doc;
1.6 import com.sun.javadoc.Tag;
1.7 +import com.sun.source.tree.AnnotationTree;
1.8 import com.sun.source.tree.AssignmentTree;
1.9 import com.sun.source.tree.BinaryTree;
1.10 import com.sun.source.tree.BlockTree;
1.11 @@ -48,6 +49,7 @@
1.12 import com.sun.source.tree.CatchTree;
1.13 import com.sun.source.tree.ClassTree;
1.14 import com.sun.source.tree.CompoundAssignmentTree;
1.15 +import com.sun.source.tree.DisjunctiveTypeTree;
1.16 import com.sun.source.tree.ExpressionStatementTree;
1.17 import com.sun.source.tree.ExpressionTree;
1.18 import com.sun.source.tree.LiteralTree;
1.19 @@ -62,10 +64,13 @@
1.20 import java.util.regex.Matcher;
1.21 import com.sun.source.tree.IdentifierTree;
1.22 import com.sun.source.tree.MemberSelectTree;
1.23 +import com.sun.source.tree.MethodTree;
1.24 +import com.sun.source.tree.ModifiersTree;
1.25 import com.sun.source.tree.Scope;
1.26 import com.sun.source.tree.StatementTree;
1.27 import com.sun.source.tree.Tree;
1.28 import com.sun.source.tree.Tree.Kind;
1.29 +import com.sun.source.tree.TypeParameterTree;
1.30 import com.sun.source.util.SourcePositions;
1.31 import com.sun.source.util.TreePath;
1.32 import com.sun.source.util.TreePathScanner;
1.33 @@ -92,6 +97,7 @@
1.34 import org.netbeans.api.java.source.ClasspathInfo;
1.35 import org.netbeans.api.java.source.CompilationInfo;
1.36 import org.netbeans.api.java.source.SourceUtils;
1.37 +import org.netbeans.api.java.source.TreeMaker;
1.38 import org.netbeans.api.java.source.TreePathHandle;
1.39 import org.netbeans.api.java.source.TypeMirrorHandle;
1.40 import org.netbeans.api.java.source.WorkingCopy;
1.41 @@ -106,6 +112,7 @@
1.42 import org.openide.filesystems.FileObject;
1.43 import org.openide.modules.SpecificationVersion;
1.44 import org.openide.util.Lookup;
1.45 +import org.openide.util.NbBundle.Messages;
1.46
1.47 /**
1.48 *
1.49 @@ -1103,5 +1110,167 @@
1.50 }
1.51 };
1.52 }
1.53 -
1.54 +
1.55 + @Messages("FIX_RemoveFromParent=Remove {0} from parent")
1.56 + public static Fix removeFromParent(HintContext ctx, TreePath what) {
1.57 + return removeFromParent(ctx, Bundle.FIX_RemoveFromParent(/*TODO: better short name:*/what.getLeaf().toString()), what);
1.58 + }
1.59 +
1.60 + public static Fix removeFromParent(HintContext ctx, String displayName, TreePath what) {
1.61 + return toEditorFix(new RemoveFromParent(displayName, ctx.getInfo(), what));
1.62 + }
1.63 +
1.64 + private static final class RemoveFromParent extends JavaFix {
1.65 +
1.66 + private final String displayName;
1.67 +
1.68 + public RemoveFromParent(String displayName, CompilationInfo info, TreePath toRemove) {
1.69 + super(info, toRemove);
1.70 + this.displayName = displayName;
1.71 + }
1.72 +
1.73 + @Override
1.74 + protected String getText() {
1.75 + return displayName;
1.76 + }
1.77 +
1.78 + @Override
1.79 + protected void performRewrite(WorkingCopy wc, TreePath tp, boolean canShowUI) {
1.80 + TreeMaker make = wc.getTreeMaker();
1.81 + Tree leaf = tp.getLeaf();
1.82 + Tree parentLeaf = tp.getParentPath().getLeaf();
1.83 +
1.84 + switch (parentLeaf.getKind()) {
1.85 + case ANNOTATION:
1.86 + AnnotationTree at = (AnnotationTree) parentLeaf;
1.87 + AnnotationTree newAnnot;
1.88 +
1.89 + newAnnot = make.removeAnnotationAttrValue(at, (ExpressionTree) leaf);
1.90 +
1.91 + wc.rewrite(at, newAnnot);
1.92 + break;
1.93 + case BLOCK:
1.94 + BlockTree bt = (BlockTree) parentLeaf;
1.95 +
1.96 + wc.rewrite(bt, make.removeBlockStatement(bt, (StatementTree) leaf));
1.97 + break;
1.98 + case CASE:
1.99 + CaseTree caseTree = (CaseTree) parentLeaf;
1.100 +
1.101 + wc.rewrite(caseTree, make.removeCaseStatement(caseTree, (StatementTree) leaf));
1.102 + break;
1.103 + case CLASS:
1.104 + ClassTree classTree = (ClassTree) parentLeaf;
1.105 + ClassTree nueClassTree;
1.106 +
1.107 + if (classTree.getTypeParameters().contains(leaf)) {
1.108 + nueClassTree = make.removeClassTypeParameter(classTree, (TypeParameterTree) leaf);
1.109 + } else if (classTree.getExtendsClause() == leaf) {
1.110 + nueClassTree = make.Class(classTree.getModifiers(), classTree.getSimpleName(), classTree.getTypeParameters(), null, classTree.getImplementsClause(), classTree.getMembers());
1.111 + } else if (classTree.getImplementsClause().contains(leaf)) {
1.112 + nueClassTree = make.removeClassImplementsClause(classTree, leaf);
1.113 + } else if (classTree.getMembers().contains(leaf)) {
1.114 + nueClassTree = make.removeClassMember(classTree, leaf);
1.115 + } else {
1.116 + throw new UnsupportedOperationException();
1.117 + }
1.118 +
1.119 + wc.rewrite(classTree, nueClassTree);
1.120 + break;
1.121 + case DISJUNCTIVE_TYPE:
1.122 + DisjunctiveTypeTree disjunct = (DisjunctiveTypeTree) parentLeaf;
1.123 + List<? extends Tree> alternatives = new LinkedList<Tree>(disjunct.getTypeAlternatives());
1.124 +
1.125 + alternatives.remove(leaf);
1.126 +
1.127 + wc.rewrite(disjunct, make.DisjunctiveType(alternatives));
1.128 + break;
1.129 + case METHOD:
1.130 + MethodTree mTree = (MethodTree) parentLeaf;
1.131 + MethodTree newMethod;
1.132 +
1.133 + if (mTree.getTypeParameters().contains(leaf)) {
1.134 + newMethod = make.removeMethodTypeParameter(mTree, (TypeParameterTree) leaf);
1.135 + } else if (mTree.getParameters().contains(leaf)) {
1.136 + newMethod = make.removeMethodParameter(mTree, (VariableTree) leaf);
1.137 + } else if (mTree.getThrows().contains(leaf)) {
1.138 + newMethod = make.removeMethodThrows(mTree, (ExpressionTree) leaf);
1.139 + } else {
1.140 + throw new UnsupportedOperationException();
1.141 + }
1.142 +
1.143 + wc.rewrite(mTree, newMethod);
1.144 + break;
1.145 + case METHOD_INVOCATION:
1.146 + MethodInvocationTree iTree = (MethodInvocationTree) parentLeaf;
1.147 + MethodInvocationTree newInvocation;
1.148 +
1.149 + if (iTree.getTypeArguments().contains(leaf)) {
1.150 + newInvocation = make.removeMethodInvocationTypeArgument(iTree, (ExpressionTree) leaf);
1.151 + } else if (iTree.getArguments().contains(leaf)) {
1.152 + newInvocation = make.removeMethodInvocationArgument(iTree, (ExpressionTree) leaf);
1.153 + } else {
1.154 + throw new UnsupportedOperationException();
1.155 + }
1.156 +
1.157 + wc.rewrite(iTree, newInvocation);
1.158 + break;
1.159 + case MODIFIERS:
1.160 + ModifiersTree modsTree = (ModifiersTree) parentLeaf;
1.161 +
1.162 + wc.rewrite(modsTree, make.removeModifiersAnnotation(modsTree, (AnnotationTree) leaf));
1.163 + break;
1.164 + case NEW_CLASS:
1.165 + NewClassTree newCTree = (NewClassTree) parentLeaf;
1.166 + NewClassTree newNCT;
1.167 +
1.168 + if (newCTree.getTypeArguments().contains(leaf)) {
1.169 + newNCT = make.removeNewClassTypeArgument(newCTree, (ExpressionTree) leaf);
1.170 + } else if (newCTree.getArguments().contains(leaf)) {
1.171 + newNCT = make.removeNewClassArgument(newCTree, (ExpressionTree) leaf);
1.172 + } else {
1.173 + throw new UnsupportedOperationException();
1.174 + }
1.175 +
1.176 + wc.rewrite(newCTree, newNCT);
1.177 + break;
1.178 + case PARAMETERIZED_TYPE:
1.179 + ParameterizedTypeTree parTree = (ParameterizedTypeTree) parentLeaf;
1.180 +
1.181 + wc.rewrite(parTree, make.removeParameterizedTypeTypeArgument(parTree, (ExpressionTree) leaf));
1.182 + break;
1.183 + case SWITCH:
1.184 + SwitchTree switchTree = (SwitchTree) parentLeaf;
1.185 + SwitchTree newSwitch;
1.186 +
1.187 + if (switchTree.getCases().contains(leaf)) {
1.188 + newSwitch = make.removeSwitchCase(switchTree, (CaseTree) leaf);
1.189 + } else {
1.190 + throw new UnsupportedOperationException();
1.191 + }
1.192 +
1.193 + wc.rewrite(switchTree, newSwitch);
1.194 + break;
1.195 + case TRY:
1.196 + TryTree tryTree = (TryTree) parentLeaf;
1.197 + TryTree newTry;
1.198 +
1.199 + if (tryTree.getResources().contains(leaf)) {
1.200 + LinkedList<Tree> resources = new LinkedList<Tree>(tryTree.getResources());
1.201 +
1.202 + resources.remove(leaf);
1.203 +
1.204 + newTry = make.Try(resources, tryTree.getBlock(), tryTree.getCatches(), tryTree.getFinallyBlock());
1.205 + } else if (tryTree.getCatches().contains(leaf)) {
1.206 + newTry = make.removeTryCatch(tryTree, (CatchTree) leaf);
1.207 + } else {
1.208 + throw new UnsupportedOperationException();
1.209 + }
1.210 +
1.211 + wc.rewrite(tryTree, newTry);
1.212 + break;
1.213 + }
1.214 + }
1.215 +
1.216 + }
1.217 }
2.1 --- a/api/test/unit/src/org/netbeans/modules/jackpot30/spi/JavaFixTest.java Fri Jan 21 23:13:54 2011 +0100
2.2 +++ b/api/test/unit/src/org/netbeans/modules/jackpot30/spi/JavaFixTest.java Sun Jan 23 13:59:19 2011 +0100
2.3 @@ -435,6 +435,27 @@
2.4 "}\n");
2.5 }
2.6
2.7 + public void testRemoveFromParent1() throws Exception {
2.8 + performRemoveFromParentTest("package test;\n" +
2.9 + "public class Test {\n" +
2.10 + " private int I;" +
2.11 + "}\n",
2.12 + "$mods$ int $f;",
2.13 + "package test;\n" +
2.14 + "public class Test {\n" +
2.15 + "}\n");
2.16 + }
2.17 +
2.18 + public void testRemoveFromParent2() throws Exception {
2.19 + performRemoveFromParentTest("package test;\n" +
2.20 + "public class Test extends java.util.ArrayList {\n" +
2.21 + "}\n",
2.22 + "java.util.ArrayList",
2.23 + "package test;\n" +
2.24 + "public class Test {\n" +
2.25 + "}\n");
2.26 + }
2.27 +
2.28 public void performRewriteTest(String code, String rule, String golden) throws Exception {
2.29 prepareTest("test/Test.java", code);
2.30
2.31 @@ -462,4 +483,30 @@
2.32
2.33 assertEquals(golden, doc.getText(0, doc.getLength()));
2.34 }
2.35 +
2.36 + public void performRemoveFromParentTest(String code, String rule, String golden) throws Exception {
2.37 + prepareTest("test/Test.java", code);
2.38 +
2.39 + HintDescription hd = HintDescriptionFactory.create()
2.40 + .setTriggerPattern(PatternDescription.create(rule, Collections.<String, String>emptyMap()))
2.41 + .setWorker(new HintDescription.Worker() {
2.42 + @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
2.43 + return Collections.singletonList(ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "", JavaFix.removeFromParent(ctx, "", ctx.getPath())));
2.44 + }
2.45 + }).produce();
2.46 +
2.47 + Map<PatternDescription, List<HintDescription>> patternHints = new HashMap<PatternDescription, List<HintDescription>>();
2.48 + HashMap<Kind, List<HintDescription>> kindHints = new HashMap<Kind, List<HintDescription>>();
2.49 +
2.50 + RulesManager.sortOut(Collections.singleton(hd), kindHints, patternHints);
2.51 + List<ErrorDescription> computeHints = new HintsInvoker(info, new AtomicBoolean()).computeHints(info, kindHints, patternHints);
2.52 +
2.53 + assertEquals(computeHints.toString(), 1, computeHints.size());
2.54 +
2.55 + Fix fix = computeHints.get(0).getFixes().getFixes().get(0);
2.56 +
2.57 + fix.implement();
2.58 +
2.59 + assertEquals(golden, doc.getText(0, doc.getLength()));
2.60 + }
2.61 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/file/src/org/netbeans/modules/jackpot30/file/DeclarativeHintsOptions.java Sun Jan 23 13:59:19 2011 +0100
3.3 @@ -0,0 +1,55 @@
3.4 +/*
3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.6 + *
3.7 + * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
3.8 + *
3.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
3.10 + * Other names may be trademarks of their respective owners.
3.11 + *
3.12 + * The contents of this file are subject to the terms of either the GNU
3.13 + * General Public License Version 2 only ("GPL") or the Common
3.14 + * Development and Distribution License("CDDL") (collectively, the
3.15 + * "License"). You may not use this file except in compliance with the
3.16 + * License. You can obtain a copy of the License at
3.17 + * http://www.netbeans.org/cddl-gplv2.html
3.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
3.19 + * specific language governing permissions and limitations under the
3.20 + * License. When distributing the software, include this License Header
3.21 + * Notice in each file and include the License file at
3.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
3.23 + * particular file as subject to the "Classpath" exception as provided
3.24 + * by Oracle in the GPL Version 2 section of the License file that
3.25 + * accompanied this code. If applicable, add the following below the
3.26 + * License Header, with the fields enclosed by brackets [] replaced by
3.27 + * your own identifying information:
3.28 + * "Portions Copyrighted [year] [name of copyright owner]"
3.29 + *
3.30 + * If you wish your version of this file to be governed by only the CDDL
3.31 + * or only the GPL Version 2, indicate your decision by adding
3.32 + * "[Contributor] elects to include this software in this distribution
3.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
3.34 + * single choice of license, a recipient has the option to distribute
3.35 + * your version of this file under either the CDDL, the GPL Version 2 or
3.36 + * to extend the choice of license to its licensees as provided above.
3.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
3.38 + * Version 2 license, then the option applies only if the new code is
3.39 + * made subject to such option by the copyright holder.
3.40 + *
3.41 + * Contributor(s):
3.42 + *
3.43 + * Portions Copyrighted 2011 Sun Microsystems, Inc.
3.44 + */
3.45 +
3.46 +package org.netbeans.modules.jackpot30.file;
3.47 +
3.48 +/**
3.49 + *
3.50 + * @author lahvac
3.51 + */
3.52 +public class DeclarativeHintsOptions {
3.53 +
3.54 + public static final String OPTION_ERROR = "error";
3.55 + public static final String OPTION_WARNING = "warning";
3.56 + public static final String OPTION_REMOVE_FROM_PARENT = "remove-from-parent";
3.57 +
3.58 +}
4.1 --- a/file/src/org/netbeans/modules/jackpot30/file/DeclarativeHintsWorker.java Fri Jan 21 23:13:54 2011 +0100
4.2 +++ b/file/src/org/netbeans/modules/jackpot30/file/DeclarativeHintsWorker.java Sun Jan 23 13:59:19 2011 +0100
4.3 @@ -1,7 +1,7 @@
4.4 /*
4.5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4.6 *
4.7 - * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
4.8 + * Copyright 2008-2011 Sun Microsystems, Inc. All rights reserved.
4.9 *
4.10 * The contents of this file are subject to the terms of either the GNU
4.11 * General Public License Version 2 only ("GPL") or the Common
4.12 @@ -34,18 +34,19 @@
4.13 *
4.14 * Contributor(s):
4.15 *
4.16 - * Portions Copyrighted 2008-2009 Sun Microsystems, Inc.
4.17 + * Portions Copyrighted 2008-2011 Sun Microsystems, Inc.
4.18 */
4.19
4.20 package org.netbeans.modules.jackpot30.file;
4.21
4.22 -import com.sun.source.util.TreePath;
4.23 import java.util.Collection;
4.24 import java.util.Collections;
4.25 +import java.util.EnumSet;
4.26 import java.util.LinkedList;
4.27 import java.util.List;
4.28 import java.util.Map;
4.29 -import javax.lang.model.type.TypeMirror;
4.30 +import org.netbeans.api.lexer.TokenHierarchy;
4.31 +import org.netbeans.api.lexer.TokenSequence;
4.32 import org.netbeans.modules.jackpot30.file.Condition.Otherwise;
4.33 import org.netbeans.modules.jackpot30.file.conditionapi.Context;
4.34 import org.netbeans.modules.jackpot30.spi.HintContext;
4.35 @@ -121,17 +122,35 @@
4.36
4.37 reportErrorWarning(ctx, fix.getOptions());
4.38
4.39 - //XXX: empty/noop fixes should not be realized:
4.40 - editorFixes.add(JavaFix.rewriteFix(ctx.getInfo(),
4.41 - fix.getDisplayName(),
4.42 - ctx.getPath(),
4.43 - fix.getPattern(),
4.44 - APIAccessor.IMPL.getVariables(context),
4.45 - APIAccessor.IMPL.getMultiVariables(context),
4.46 - APIAccessor.IMPL.getVariableNames(context),
4.47 - ctx.getConstraints(),
4.48 - fix.getOptions(),
4.49 - imports));
4.50 + TokenSequence<DeclarativeHintTokenId> ts = TokenHierarchy.create(fix.getPattern(),
4.51 + false,
4.52 + DeclarativeHintTokenId.language(),
4.53 + EnumSet.of(DeclarativeHintTokenId.BLOCK_COMMENT,
4.54 + DeclarativeHintTokenId.LINE_COMMENT,
4.55 + DeclarativeHintTokenId.WHITESPACE),
4.56 + null).tokenSequence(DeclarativeHintTokenId.language());
4.57 +
4.58 + boolean empty = !ts.moveNext();
4.59 +
4.60 + if (empty) {
4.61 + if ( ( !fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_ERROR)
4.62 + && !fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_WARNING))
4.63 + || fix.getOptions().containsKey(DeclarativeHintsOptions.OPTION_REMOVE_FROM_PARENT)) {
4.64 + editorFixes.add(JavaFix.removeFromParent(ctx, ctx.getPath()));
4.65 + }
4.66 + //not realizing empty fixes
4.67 + } else {
4.68 + editorFixes.add(JavaFix.rewriteFix(ctx.getInfo(),
4.69 + fix.getDisplayName(),
4.70 + ctx.getPath(),
4.71 + fix.getPattern(),
4.72 + APIAccessor.IMPL.getVariables(context),
4.73 + APIAccessor.IMPL.getMultiVariables(context),
4.74 + APIAccessor.IMPL.getVariableNames(context),
4.75 + ctx.getConstraints(),
4.76 + fix.getOptions(),
4.77 + imports));
4.78 + }
4.79 } finally {
4.80 context.leaveScope();
4.81 }
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/file/test/unit/src/org/netbeans/modules/jackpot30/file/remove-from-parent.hint Sun Jan 23 13:59:19 2011 +0100
5.3 @@ -0,0 +1,9 @@
5.4 + int i
5.5 +=> /*remove-from-parent*/
5.6 +;;
5.7 + float f
5.8 +=> <!error="err">
5.9 +;;
5.10 + double d
5.11 +=> <!error="err",remove-from-parent=true>
5.12 +;;
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/file/test/unit/src/org/netbeans/modules/jackpot30/file/remove-from-parent.test Sun Jan 23 13:59:19 2011 +0100
6.3 @@ -0,0 +1,27 @@
6.4 +%%TestCase pos-1
6.5 +package test;
6.6 +public class Test {
6.7 + private void g(int i) {}
6.8 +}
6.9 +%%=>
6.10 +package test;
6.11 +public class Test {
6.12 + private void g() {}
6.13 +}
6.14 +%%TestCase pos-2
6.15 +package test;
6.16 +public class Test {
6.17 + private void g(double d) {}
6.18 +}
6.19 +%%=>
6.20 +package test;
6.21 +public class Test {
6.22 + private void g() {}
6.23 +}
6.24 +%%TestCase neg-1
6.25 +package test;
6.26 +public class Test {
6.27 + private void g(float f) {}
6.28 +}
6.29 +%%=>
6.30 +remove-from-parent:f