New warning - global field can be final, and fixing problems found while testing it.
1.1 --- a/java.hints/hintsimpl/manifest.mf Fri May 10 16:16:49 2013 +0200
1.2 +++ b/java.hints/hintsimpl/manifest.mf Fri May 10 21:52:04 2013 +0200
1.3 @@ -1,5 +1,5 @@
1.4 Manifest-Version: 1.0
1.5 OpenIDE-Module: org.netbeans.modules.jackpot30.hintsimpl
1.6 +OpenIDE-Module-Implementation-Version: 1
1.7 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/jackpot30/hintsimpl/Bundle.properties
1.8 -OpenIDE-Module-Specification-Version: 1.0
1.9
2.1 --- a/java.hints/hintsimpl/nbproject/genfiles.properties Fri May 10 16:16:49 2013 +0200
2.2 +++ b/java.hints/hintsimpl/nbproject/genfiles.properties Fri May 10 21:52:04 2013 +0200
2.3 @@ -1,8 +1,8 @@
2.4 -build.xml.data.CRC32=c75a6f96
2.5 +build.xml.data.CRC32=4bedd36b
2.6 build.xml.script.CRC32=ef577a91
2.7 build.xml.stylesheet.CRC32=a56c6a5b@2.58
2.8 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
2.9 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
2.10 -nbproject/build-impl.xml.data.CRC32=c75a6f96
2.11 +nbproject/build-impl.xml.data.CRC32=4bedd36b
2.12 nbproject/build-impl.xml.script.CRC32=9204f652
2.13 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.58
3.1 --- a/java.hints/hintsimpl/nbproject/project.properties Fri May 10 16:16:49 2013 +0200
3.2 +++ b/java.hints/hintsimpl/nbproject/project.properties Fri May 10 21:52:04 2013 +0200
3.3 @@ -1,3 +1,4 @@
3.4 javac.source=1.7
3.5 javac.compilerargs=-Xlint -Xlint:-serial
3.6 requires.nb.javac=true
3.7 +spec.version.base=1.0
4.1 --- a/java.hints/hintsimpl/nbproject/project.xml Fri May 10 16:16:49 2013 +0200
4.2 +++ b/java.hints/hintsimpl/nbproject/project.xml Fri May 10 21:52:04 2013 +0200
4.3 @@ -7,6 +7,15 @@
4.4 <suite-component/>
4.5 <module-dependencies>
4.6 <dependency>
4.7 + <code-name-base>org.netbeans.api.annotations.common</code-name-base>
4.8 + <build-prerequisite/>
4.9 + <compile-dependency/>
4.10 + <run-dependency>
4.11 + <release-version>1</release-version>
4.12 + <specification-version>1.20</specification-version>
4.13 + </run-dependency>
4.14 + </dependency>
4.15 + <dependency>
4.16 <code-name-base>org.netbeans.libs.javacapi</code-name-base>
4.17 <build-prerequisite/>
4.18 <compile-dependency/>
4.19 @@ -15,6 +24,15 @@
4.20 </run-dependency>
4.21 </dependency>
4.22 <dependency>
4.23 + <code-name-base>org.netbeans.modules.java.hints</code-name-base>
4.24 + <build-prerequisite/>
4.25 + <compile-dependency/>
4.26 + <run-dependency>
4.27 + <release-version>1</release-version>
4.28 + <implementation-version/>
4.29 + </run-dependency>
4.30 + </dependency>
4.31 + <dependency>
4.32 <code-name-base>org.netbeans.modules.java.source</code-name-base>
4.33 <build-prerequisite/>
4.34 <compile-dependency/>
4.35 @@ -39,6 +57,14 @@
4.36 <specification-version>2.0</specification-version>
4.37 </run-dependency>
4.38 </dependency>
4.39 + <dependency>
4.40 + <code-name-base>org.openide.util</code-name-base>
4.41 + <build-prerequisite/>
4.42 + <compile-dependency/>
4.43 + <run-dependency>
4.44 + <specification-version>8.32</specification-version>
4.45 + </run-dependency>
4.46 + </dependency>
4.47 </module-dependencies>
4.48 <test-dependencies>
4.49 <test-type>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/java.hints/hintsimpl/src/org/netbeans/modules/jackpot30/hintsimpl/NonPrivateMakeFinal.java Fri May 10 21:52:04 2013 +0200
5.3 @@ -0,0 +1,152 @@
5.4 +/*
5.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5.6 + *
5.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
5.8 + *
5.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
5.10 + * Other names may be trademarks of their respective owners.
5.11 + *
5.12 + * The contents of this file are subject to the terms of either the GNU
5.13 + * General Public License Version 2 only ("GPL") or the Common
5.14 + * Development and Distribution License("CDDL") (collectively, the
5.15 + * "License"). You may not use this file except in compliance with the
5.16 + * License. You can obtain a copy of the License at
5.17 + * http://www.netbeans.org/cddl-gplv2.html
5.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
5.19 + * specific language governing permissions and limitations under the
5.20 + * License. When distributing the software, include this License Header
5.21 + * Notice in each file and include the License file at
5.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
5.23 + * particular file as subject to the "Classpath" exception as provided
5.24 + * by Oracle in the GPL Version 2 section of the License file that
5.25 + * accompanied this code. If applicable, add the following below the
5.26 + * License Header, with the fields enclosed by brackets [] replaced by
5.27 + * your own identifying information:
5.28 + * "Portions Copyrighted [year] [name of copyright owner]"
5.29 + *
5.30 + * If you wish your version of this file to be governed by only the CDDL
5.31 + * or only the GPL Version 2, indicate your decision by adding
5.32 + * "[Contributor] elects to include this software in this distribution
5.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
5.34 + * single choice of license, a recipient has the option to distribute
5.35 + * your version of this file under either the CDDL, the GPL Version 2 or
5.36 + * to extend the choice of license to its licensees as provided above.
5.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
5.38 + * Version 2 license, then the option applies only if the new code is
5.39 + * made subject to such option by the copyright holder.
5.40 + *
5.41 + * Contributor(s):
5.42 + *
5.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
5.44 + */
5.45 +package org.netbeans.modules.jackpot30.hintsimpl;
5.46 +
5.47 +import com.sun.source.tree.Tree.Kind;
5.48 +import com.sun.source.tree.VariableTree;
5.49 +import com.sun.source.util.TreePath;
5.50 +import java.util.EnumSet;
5.51 +import javax.lang.model.element.Element;
5.52 +import javax.lang.model.element.ElementKind;
5.53 +import javax.lang.model.element.Modifier;
5.54 +import javax.lang.model.element.VariableElement;
5.55 +import org.netbeans.api.annotations.common.NonNull;
5.56 +import org.netbeans.api.java.source.TreePathHandle;
5.57 +import org.netbeans.modules.java.hints.introduce.Flow;
5.58 +import org.netbeans.modules.java.hints.introduce.Flow.FlowResult;
5.59 +import org.netbeans.spi.editor.hints.ErrorDescription;
5.60 +import org.netbeans.spi.editor.hints.Fix;
5.61 +import org.netbeans.spi.java.hints.Decision;
5.62 +import org.netbeans.spi.java.hints.Decision.Factory;
5.63 +import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
5.64 +import org.netbeans.spi.java.hints.Hint;
5.65 +import org.netbeans.spi.java.hints.HintContext;
5.66 +import org.netbeans.spi.java.hints.TriggerDecision;
5.67 +import org.netbeans.spi.java.hints.TriggerPattern;
5.68 +import org.netbeans.spi.java.hints.TriggerTreeKind;
5.69 +import org.netbeans.spi.java.hints.support.FixFactory;
5.70 +import org.openide.util.NbBundle.Messages;
5.71 +
5.72 +/**
5.73 + *
5.74 + * @author lahvac
5.75 + */
5.76 +@Hint(displayName="Non Private Make Final", description="Non Private Make Final", category="general")
5.77 +public class NonPrivateMakeFinal {
5.78 +
5.79 + @TriggerPattern("$variable = $value")
5.80 + public static ErrorDescription write(HintContext ctx) {
5.81 + Element field = ctx.getInfo().getTrees().getElement(ctx.getVariables().get("$variable"));
5.82 +
5.83 + if (field == null || field.getKind() != ElementKind.FIELD) {
5.84 + //unknown, or not a field, ignore.
5.85 + return null;
5.86 + }
5.87 +
5.88 + if (ctx.getInfo().getTopLevelElements().contains(ctx.getInfo().getElementUtilities().outermostTypeElement(field))) {
5.89 + //field in current CU, ignore (will be handled by local flow)
5.90 + return null;
5.91 + }
5.92 +
5.93 + decision(ctx, (VariableElement) field).recordLocalFact(ctx.getInfo(), false);
5.94 +
5.95 + return null;
5.96 + }
5.97 +
5.98 + @TriggerTreeKind({Kind.VARIABLE})
5.99 + public static ErrorDescription declaration(HintContext ctx) {
5.100 + Element ve = ctx.getInfo().getTrees().getElement(ctx.getPath());
5.101 +
5.102 + if (ve == null || ve.getKind() != ElementKind.FIELD || ve.getModifiers().contains(Modifier.FINAL) || /*TODO: the point of volatile?*/ve.getModifiers().contains(Modifier.VOLATILE)) return null;
5.103 +
5.104 + //handle all fields, even the private ones, which are handled by the standard hints.
5.105 +
5.106 + FlowResult flow = Flow.assignmentsForUse(ctx);
5.107 +
5.108 + if (flow == null || ctx.isCanceled()) return null;
5.109 +
5.110 + DecisionImpl decision = decision(ctx, (VariableElement) ve);
5.111 +
5.112 + decision.recordLocalFact(ctx.getInfo(), flow.getFinalCandidates().contains((VariableElement) ve));
5.113 +
5.114 + return null;
5.115 + }
5.116 +
5.117 + @TriggerDecision(DecisionImpl.class)
5.118 + @Messages("FIX_CanBeFinal={0} can be final")
5.119 + public static ErrorDescription produceWarning(HintContext ctx) {
5.120 + if (((DecisionImpl) ctx.decision).getCurrentResult() == Boolean.TRUE) {
5.121 + VariableTree vt = (VariableTree) ctx.getPath().getLeaf();
5.122 + Fix fix = FixFactory.addModifiersFix(ctx.getInfo(), new TreePath(ctx.getPath(), vt.getModifiers()), EnumSet.of(Modifier.FINAL), Bundle.FIX_CanBeFinal(vt.getName().toString()));
5.123 + return ErrorDescriptionFactory.forName(ctx, ctx.getPath(), "Can be final", fix);
5.124 + }
5.125 +
5.126 + return null;
5.127 + }
5.128 +
5.129 + private static @NonNull DecisionImpl decision(HintContext ctx, @NonNull VariableElement field) {
5.130 + TreePathHandle h = TreePathHandle.create(field, ctx.getInfo());
5.131 +
5.132 + return ctx.findDecision(h, new Factory<Boolean, Boolean, DecisionImpl>(DecisionImpl.class) {
5.133 + @Override
5.134 + public DecisionImpl create(TreePathHandle handle) {
5.135 + return new DecisionImpl(handle);
5.136 + }
5.137 + });
5.138 + }
5.139 +
5.140 + private static final class DecisionImpl extends Decision<Boolean, Boolean> {
5.141 +
5.142 + public DecisionImpl(TreePathHandle root) {
5.143 + super(root);
5.144 + }
5.145 +
5.146 + @Override
5.147 + protected Boolean makeDecision(Iterable<? extends Boolean> input) {
5.148 + for (Boolean b : input) {
5.149 + if (b == null || !b) return false;
5.150 + }
5.151 + return true;
5.152 + }
5.153 +
5.154 + }
5.155 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/java.hints/hintsimpl/test/unit/src/org/netbeans/modules/jackpot30/hintsimpl/NonPrivateMakeFinalNGTest.java Fri May 10 21:52:04 2013 +0200
6.3 @@ -0,0 +1,90 @@
6.4 +/*
6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
6.6 + *
6.7 + * Copyright 2013 Oracle and/or its affiliates. All rights reserved.
6.8 + *
6.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
6.10 + * Other names may be trademarks of their respective owners.
6.11 + *
6.12 + * The contents of this file are subject to the terms of either the GNU
6.13 + * General Public License Version 2 only ("GPL") or the Common
6.14 + * Development and Distribution License("CDDL") (collectively, the
6.15 + * "License"). You may not use this file except in compliance with the
6.16 + * License. You can obtain a copy of the License at
6.17 + * http://www.netbeans.org/cddl-gplv2.html
6.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
6.19 + * specific language governing permissions and limitations under the
6.20 + * License. When distributing the software, include this License Header
6.21 + * Notice in each file and include the License file at
6.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
6.23 + * particular file as subject to the "Classpath" exception as provided
6.24 + * by Oracle in the GPL Version 2 section of the License file that
6.25 + * accompanied this code. If applicable, add the following below the
6.26 + * License Header, with the fields enclosed by brackets [] replaced by
6.27 + * your own identifying information:
6.28 + * "Portions Copyrighted [year] [name of copyright owner]"
6.29 + *
6.30 + * If you wish your version of this file to be governed by only the CDDL
6.31 + * or only the GPL Version 2, indicate your decision by adding
6.32 + * "[Contributor] elects to include this software in this distribution
6.33 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
6.34 + * single choice of license, a recipient has the option to distribute
6.35 + * your version of this file under either the CDDL, the GPL Version 2 or
6.36 + * to extend the choice of license to its licensees as provided above.
6.37 + * However, if you add GPL Version 2 code and therefore, elected the GPL
6.38 + * Version 2 license, then the option applies only if the new code is
6.39 + * made subject to such option by the copyright holder.
6.40 + *
6.41 + * Contributor(s):
6.42 + *
6.43 + * Portions Copyrighted 2013 Sun Microsystems, Inc.
6.44 + */
6.45 +package org.netbeans.modules.jackpot30.hintsimpl;
6.46 +
6.47 +import org.netbeans.modules.java.hints.test.api.HintTest;
6.48 +import org.testng.annotations.Test;
6.49 +
6.50 +/**
6.51 + *
6.52 + * @author lahvac
6.53 + */
6.54 +public class NonPrivateMakeFinalNGTest {
6.55 +
6.56 + @Test
6.57 + public void testNotFinal() throws Exception {
6.58 + HintTest.create()
6.59 + .input("test/Test1.java",
6.60 + "package test;\n" +
6.61 + "public class Test1 {\n" +
6.62 + " public String str = \"\";\n" +
6.63 + "}\n")
6.64 + .input("test/Test2.java",
6.65 + "package test;\n" +
6.66 + "public class Test2 {\n" +
6.67 + " {\n" +
6.68 + " new Test1().str = null;\n" +
6.69 + " }\n" +
6.70 + "}\n")
6.71 + .runGlobal(NonPrivateMakeFinal.class)
6.72 + .assertWarnings();
6.73 + }
6.74 +
6.75 + @Test
6.76 + public void testFinal() throws Exception {
6.77 + HintTest.create()
6.78 + .input("test/Test1.java",
6.79 + "package test;\n" +
6.80 + "public class Test1 {\n" +
6.81 + " public String str = \"\";\n" +
6.82 + "}\n")
6.83 + .input("test/Test2.java",
6.84 + "package test;\n" +
6.85 + "public class Test2 {\n" +
6.86 + " {\n" +
6.87 + " System.err.println(new Test1().str);\n" +
6.88 + " }\n" +
6.89 + "}\n")
6.90 + .runGlobal(NonPrivateMakeFinal.class)
6.91 + .assertWarnings("2:18-2:21:verifier:Can be final");
6.92 + }
6.93 +}
7.1 --- a/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java Fri May 10 16:16:49 2013 +0200
7.2 +++ b/java.hints/spi.java.hints/src/org/netbeans/modules/java/hints/spiimpl/batch/BatchSearch.java Fri May 10 21:52:04 2013 +0200
7.3 @@ -210,11 +210,11 @@
7.4 return;
7.5 inner.startNextPart(e.getValue().size());
7.6
7.7 - e.getKey().validateResource(candidates, e.getValue(), inner, callback, doNotRegisterClassPath, problems, cancel);
7.8 + e.getKey().validateResource(e.getValue(), inner, callback, doNotRegisterClassPath, problems, cancel);
7.9 }
7.10 }
7.11
7.12 - private static void getLocalVerifiedSpans(final BatchResult candidates, Collection<? extends Resource> resources, @NonNull final ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems, final AtomicBoolean cancel) {
7.13 + private static void getLocalVerifiedSpans(Collection<? extends Resource> resources, @NonNull final ProgressHandleWrapper progress, final VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, final Collection<? super MessageImpl> problems, final AtomicBoolean cancel) {
7.14 Collection<FileObject> files = new LinkedList<FileObject>();
7.15 final Map<FileObject, Resource> file2Resource = new HashMap<FileObject, Resource>();
7.16
7.17 @@ -252,13 +252,14 @@
7.18 }
7.19 }
7.20
7.21 + callback.groupStarted();
7.22 +
7.23 try {
7.24 final GlobalProcessingContext gpc = new GlobalProcessingContext();
7.25 for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2Files.entrySet()) {
7.26 try {
7.27 List<FileObject> toProcess = new ArrayList<FileObject>(e.getValue());
7.28 final AtomicInteger currentPointer = new AtomicInteger();
7.29 - callback.groupStarted();
7.30
7.31 // for (FileObject f : toProcess) {
7.32 while (currentPointer.get() < toProcess.size()) {
7.33 @@ -319,8 +320,6 @@
7.34 }
7.35 }, true);
7.36 }
7.37 -
7.38 - callback.groupFinished();
7.39 } catch (IOException ex) {
7.40 Exceptions.printStackTrace(ex);
7.41 }
7.42 @@ -340,7 +339,7 @@
7.43 }
7.44 }
7.45 }
7.46 -
7.47 +
7.48 Map<ClasspathInfo, Collection<FileObject>> cp2FilesAfterDecision = BatchUtilities.sortFiles(file2Decision.keySet());
7.49
7.50 for (Entry<ClasspathInfo, Collection<FileObject>> e : cp2FilesAfterDecision.entrySet()) {
7.51 @@ -361,9 +360,9 @@
7.52 }
7.53
7.54 for (Decision<?, ?> d : file2Decision.get(parameter.getFileObject())) {
7.55 - for (HintDescription hd : candidates.getPatterns()) {
7.56 + for (HintDescription hd : r.hints) {
7.57 if (!(hd.getTrigger() instanceof DecisionTrigger)) continue;
7.58 - if (!settings.isEnabled(hd.getMetadata())) continue;
7.59 + if (r.settings == null && !settings.isEnabled(hd.getMetadata())) continue;
7.60 DecisionTrigger dt = (DecisionTrigger) hd.getTrigger();
7.61 if (dt.getDecisionClass() != d.getClass()) continue;
7.62 TreePath tp = d.root.resolve(parameter);
7.63 @@ -382,8 +381,9 @@
7.64 Exceptions.printStackTrace(ex);
7.65 }
7.66 }
7.67 + } finally {
7.68 + callback.groupFinished();
7.69
7.70 - } finally {
7.71 if (toRegister != null) {
7.72 GlobalPathRegistry.getDefault().unregister(ClassPath.SOURCE, toRegister);
7.73 }
7.74 @@ -633,7 +633,7 @@
7.75 this.src = src;
7.76 }
7.77 public abstract Collection<? extends Resource> findResources(Iterable<? extends HintDescription> hints, ProgressHandleWrapper progress, @NullAllowed Callable<BulkPattern> bulkPattern, Collection<? super MessageImpl> problems, HintsSettings settingsProvider);
7.78 - public abstract void validateResource(BatchResult candidates, Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel);
7.79 + public abstract void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel);
7.80 // public int[] getEstimatedSpan(Resource r);
7.81 }
7.82
7.83 @@ -641,8 +641,8 @@
7.84 public LocalIndexEnquirer(FileObject src) {
7.85 super(src);
7.86 }
7.87 - public void validateResource(BatchResult candidates, Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
7.88 - getLocalVerifiedSpans(candidates, resources, progress, callback, doNotRegisterClassPath, problems, cancel);
7.89 + public void validateResource(Collection<? extends Resource> resources, ProgressHandleWrapper progress, VerifiedSpansCallBack callback, boolean doNotRegisterClassPath, Collection<? super MessageImpl> problems, AtomicBoolean cancel) {
7.90 + getLocalVerifiedSpans(resources, progress, callback, doNotRegisterClassPath, problems, cancel);
7.91 }
7.92 }
7.93