New parameter for the command line tool: --no-apply that disables application of the fixes and prints 'errors' instead.
1.1 --- a/cmdline/tool/nbproject/genfiles.properties Fri Dec 17 21:19:03 2010 +0100
1.2 +++ b/cmdline/tool/nbproject/genfiles.properties Wed Dec 22 13:43:37 2010 +0100
1.3 @@ -3,6 +3,6 @@
1.4 build.xml.stylesheet.CRC32=a56c6a5b@1.44
1.5 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
1.6 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
1.7 -nbproject/build-impl.xml.data.CRC32=9f4c23ee
1.8 +nbproject/build-impl.xml.data.CRC32=3872d859
1.9 nbproject/build-impl.xml.script.CRC32=08f1fb11
1.10 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.44
2.1 --- a/cmdline/tool/nbproject/project.xml Fri Dec 17 21:19:03 2010 +0100
2.2 +++ b/cmdline/tool/nbproject/project.xml Wed Dec 22 13:43:37 2010 +0100
2.3 @@ -148,6 +148,15 @@
2.4 </run-dependency>
2.5 </dependency>
2.6 <dependency>
2.7 + <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
2.8 + <build-prerequisite/>
2.9 + <compile-dependency/>
2.10 + <run-dependency>
2.11 + <release-version>0</release-version>
2.12 + <specification-version>1.16.0.7.5</specification-version>
2.13 + </run-dependency>
2.14 + </dependency>
2.15 + <dependency>
2.16 <code-name-base>org.openide.filesystems</code-name-base>
2.17 <build-prerequisite/>
2.18 <compile-dependency/>
2.19 @@ -172,6 +181,14 @@
2.20 </run-dependency>
2.21 </dependency>
2.22 <dependency>
2.23 + <code-name-base>org.openide.text</code-name-base>
2.24 + <build-prerequisite/>
2.25 + <compile-dependency/>
2.26 + <run-dependency>
2.27 + <specification-version>6.34</specification-version>
2.28 + </run-dependency>
2.29 + </dependency>
2.30 + <dependency>
2.31 <code-name-base>org.openide.util</code-name-base>
2.32 <build-prerequisite/>
2.33 <compile-dependency/>
3.1 --- a/cmdline/tool/src/org/netbeans/modules/jackpot30/cmdline/Main.java Fri Dec 17 21:19:03 2010 +0100
3.2 +++ b/cmdline/tool/src/org/netbeans/modules/jackpot30/cmdline/Main.java Wed Dec 22 13:43:37 2010 +0100
3.3 @@ -47,7 +47,6 @@
3.4 import java.io.PrintStream;
3.5 import java.net.URL;
3.6 import java.util.ArrayList;
3.7 -import java.util.Arrays;
3.8 import java.util.Collection;
3.9 import java.util.LinkedList;
3.10 import java.util.List;
3.11 @@ -64,13 +63,16 @@
3.12 import joptsimple.OptionParser;
3.13 import joptsimple.OptionSet;
3.14 import org.netbeans.api.java.classpath.ClassPath;
3.15 +import org.netbeans.api.java.source.CompilationController;
3.16 import org.netbeans.api.java.source.ModificationResult;
3.17 import org.netbeans.core.startup.MainLookup;
3.18 import org.netbeans.modules.jackpot30.impl.MessageImpl;
3.19 import org.netbeans.modules.jackpot30.impl.RulesManager;
3.20 import org.netbeans.modules.jackpot30.impl.batch.BatchSearch;
3.21 import org.netbeans.modules.jackpot30.impl.batch.BatchSearch.BatchResult;
3.22 +import org.netbeans.modules.jackpot30.impl.batch.BatchSearch.Resource;
3.23 import org.netbeans.modules.jackpot30.impl.batch.BatchSearch.Scope;
3.24 +import org.netbeans.modules.jackpot30.impl.batch.BatchSearch.VerifiedSpansCallBack;
3.25 import org.netbeans.modules.jackpot30.impl.batch.BatchUtilities;
3.26 import org.netbeans.modules.jackpot30.impl.batch.ProgressHandleWrapper;
3.27 import org.netbeans.modules.jackpot30.impl.batch.ProgressHandleWrapper.ProgressHandleAbstraction;
3.28 @@ -79,6 +81,7 @@
3.29 import org.netbeans.modules.java.source.parsing.JavaPathRecognizer;
3.30 import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
3.31 import org.netbeans.modules.parsing.impl.indexing.RepositoryUpdater;
3.32 +import org.netbeans.spi.editor.hints.ErrorDescription;
3.33 import org.netbeans.spi.java.classpath.ClassPathProvider;
3.34 import org.netbeans.spi.java.classpath.support.ClassPathSupport;
3.35 import org.netbeans.spi.java.queries.SourceLevelQueryImplementation2;
3.36 @@ -97,6 +100,8 @@
3.37 */
3.38 public class Main {
3.39
3.40 + private static final String OPTION_NO_APPLY = "no-apply";
3.41 +
3.42 public static void main(String... args) throws IOException, ClassNotFoundException {
3.43 System.exit(compile(args));
3.44 }
3.45 @@ -117,6 +122,7 @@
3.46 parser.accepts("progress", "show progress");
3.47 parser.accepts("debug", "enable debugging loggers");
3.48 parser.accepts("help", "prints this help");
3.49 + parser.accepts(OPTION_NO_APPLY, "do not apply changes - only print locations were the hint would be applied");
3.50
3.51 OptionSet parsed;
3.52
3.53 @@ -207,7 +213,13 @@
3.54
3.55 FileUtil.setMIMEType("java", "text/x-java");
3.56
3.57 - perform(hints, roots.toArray(new FileObject[0]), parsed.has("progress"), parsed.valueOf(out));
3.58 + ProgressHandleWrapper progress = parsed.has("progress") ? new ProgressHandleWrapper(new ConsoleProgressHandleAbstraction(), 1) : new ProgressHandleWrapper(1);
3.59 +
3.60 + if (parsed.has(OPTION_NO_APPLY)) {
3.61 + findOccurrences(hints, roots.toArray(new FileObject[0]), progress, parsed.valueOf(out));
3.62 + } else {
3.63 + apply(hints, roots.toArray(new FileObject[0]), progress, parsed.valueOf(out));
3.64 + }
3.65 } catch (Throwable e) {
3.66 e.printStackTrace();
3.67 }
3.68 @@ -243,8 +255,49 @@
3.69 TOP_LOGGER.setLevel(Level.OFF);
3.70 }
3.71
3.72 - private static void perform(Iterable<? extends HintDescription> descs, FileObject[] sourceRoot, boolean showProgress, File out) throws IOException {
3.73 - ProgressHandleWrapper w = showProgress ? new ProgressHandleWrapper(new ConsoleProgressHandleAbstraction(), 1, 1) : new ProgressHandleWrapper(1, 1);
3.74 + private static void findOccurrences(Iterable<? extends HintDescription> descs, FileObject[] sourceRoot, ProgressHandleWrapper progress, File out) throws IOException {
3.75 + ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
3.76 + BatchResult occurrences = BatchSearch.findOccurrences(descs, Scope.createGivenSourceRoots(sourceRoot), w);
3.77 +
3.78 + List<MessageImpl> problems = new LinkedList<MessageImpl>();
3.79 + BatchSearch.getVerifiedSpans(occurrences, progress, new VerifiedSpansCallBack() {
3.80 + @Override public void groupStarted() {}
3.81 + @Override public boolean spansVerified(CompilationController wc, Resource r, Collection<? extends ErrorDescription> hints) throws Exception {
3.82 + for (ErrorDescription ed : hints) {
3.83 + print(ed);
3.84 + }
3.85 + return true;
3.86 + }
3.87 + @Override public void groupFinished() {}
3.88 + @Override public void cannotVerifySpan(Resource r) {
3.89 + //TODO: ignored - what to do?
3.90 + }
3.91 + }, problems);
3.92 + }
3.93 +
3.94 + private static void print(ErrorDescription error) throws IOException {
3.95 + int lineNumber = error.getRange().getBegin().getLine();
3.96 + String line = error.getFile().asLines().get(lineNumber);
3.97 + int column = error.getRange().getBegin().getColumn();
3.98 + StringBuilder b = new StringBuilder();
3.99 +
3.100 + for (int i = 0; i < column; i++) {
3.101 + if (Character.isWhitespace(line.charAt(i))) {
3.102 + b.append(line.charAt(i));
3.103 + } else {
3.104 + b.append(' ');
3.105 + }
3.106 + }
3.107 +
3.108 + b.append('^');
3.109 +
3.110 + System.out.println(FileUtil.getFileDisplayName(error.getFile()) + ":" + lineNumber + ":" + error.getDescription());
3.111 + System.out.println(line);
3.112 + System.out.println(b);
3.113 + }
3.114 +
3.115 + private static void apply(Iterable<? extends HintDescription> descs, FileObject[] sourceRoot, ProgressHandleWrapper progress, File out) throws IOException {
3.116 + ProgressHandleWrapper w = progress.startNextPartWithEmbedding(1, 1);
3.117 BatchResult occurrences = BatchSearch.findOccurrences(descs, Scope.createGivenSourceRoots(sourceRoot), w);
3.118
3.119 List<MessageImpl> problems = new LinkedList<MessageImpl>();
4.1 --- a/cmdline/tool/test/unit/src/org/netbeans/modules/jackpot30/cmdline/CreateToolTest.java Fri Dec 17 21:19:03 2010 +0100
4.2 +++ b/cmdline/tool/test/unit/src/org/netbeans/modules/jackpot30/cmdline/CreateToolTest.java Wed Dec 22 13:43:37 2010 +0100
4.3 @@ -39,6 +39,7 @@
4.4
4.5 package org.netbeans.modules.jackpot30.cmdline;
4.6
4.7 +import java.io.ByteArrayOutputStream;
4.8 import java.io.File;
4.9 import java.io.IOException;
4.10 import java.io.InputStream;
4.11 @@ -65,7 +66,7 @@
4.12 private static File compiler;
4.13
4.14 @Override
4.15 - protected void reallyRunCompiler(File workingDir, String... params) throws IOException, Exception {
4.16 + protected void reallyRunCompiler(File workingDir, String[] output, String... params) throws Exception {
4.17 assertNotNull(compiler);
4.18 List<String> ll = new LinkedList<String>();
4.19 ll.add("java");
4.20 @@ -78,11 +79,16 @@
4.21 ll.addAll(Arrays.asList(params));
4.22 try {
4.23 Process p = Runtime.getRuntime().exec(ll.toArray(new String[0]), null, workingDir);
4.24 + CopyStream outCopy = new CopyStream(p.getInputStream(), output, 0);
4.25 + CopyStream errCopy = new CopyStream(p.getErrorStream(), output, 1);
4.26
4.27 - new CopyStream(p.getInputStream(), System.out).start();
4.28 - new CopyStream(p.getErrorStream(), System.err).start();
4.29 + outCopy.start();
4.30 + errCopy.start();
4.31
4.32 assertEquals(0, p.waitFor());
4.33 +
4.34 + outCopy.doJoin();
4.35 + errCopy.doJoin();
4.36 } catch (Throwable t) {
4.37 throw new IOException(t);
4.38 }
4.39 @@ -90,11 +96,15 @@
4.40
4.41 private static final class CopyStream extends Thread {
4.42 private final InputStream ins;
4.43 - private final OutputStream out;
4.44 + private final ByteArrayOutputStream out;
4.45 + private final String[] target;
4.46 + private final int targetIndex;
4.47
4.48 - public CopyStream(InputStream ins, OutputStream out) {
4.49 + public CopyStream(InputStream ins, String[] target, int targetIndex) {
4.50 this.ins = ins;
4.51 - this.out = out;
4.52 + this.out = new ByteArrayOutputStream();
4.53 + this.target = target;
4.54 + this.targetIndex = targetIndex;
4.55 }
4.56
4.57 @Override
4.58 @@ -112,6 +122,12 @@
4.59 }
4.60 }
4.61
4.62 + public void doJoin() throws InterruptedException, IOException {
4.63 + join(60000);
4.64 + out.close();
4.65 + target[targetIndex] = new String(out.toByteArray());
4.66 + }
4.67 +
4.68 }
4.69
4.70 public static Test suite() {
5.1 --- a/cmdline/tool/test/unit/src/org/netbeans/modules/jackpot30/cmdline/MainTest.java Fri Dec 17 21:19:03 2010 +0100
5.2 +++ b/cmdline/tool/test/unit/src/org/netbeans/modules/jackpot30/cmdline/MainTest.java Wed Dec 22 13:43:37 2010 +0100
5.3 @@ -39,11 +39,15 @@
5.4
5.5 package org.netbeans.modules.jackpot30.cmdline;
5.6
5.7 +import java.io.ByteArrayOutputStream;
5.8 import java.io.File;
5.9 +import java.io.PrintStream;
5.10 import java.util.Arrays;
5.11 import java.util.Collections;
5.12 import java.util.LinkedList;
5.13 import java.util.List;
5.14 +import java.util.regex.Matcher;
5.15 +import java.util.regex.Pattern;
5.16 import org.netbeans.api.java.source.TestUtilities;
5.17 import org.netbeans.junit.NbTestCase;
5.18
5.19 @@ -66,19 +70,54 @@
5.20 " }\n" +
5.21 "}\n";
5.22
5.23 - doRunCompiler(golden, "src/test/Test.java",
5.24 - "package test;\n" +
5.25 - "public class Test {\n" +
5.26 - " private void test(java.util.Collection c) {\n" +
5.27 - " boolean b = c.size() == 0;\n" +
5.28 - " }\n" +
5.29 - "}\n",
5.30 - null,
5.31 - "--hint",
5.32 - "Usage of .size() == 0");
5.33 + doRunCompiler(golden,
5.34 + null,
5.35 + null,
5.36 + "src/test/Test.java",
5.37 + "package test;\n" +
5.38 + "public class Test {\n" +
5.39 + " private void test(java.util.Collection c) {\n" +
5.40 + " boolean b = c.size() == 0;\n" +
5.41 + " }\n" +
5.42 + "}\n",
5.43 + null,
5.44 + "--hint",
5.45 + "Usage of .size() == 0");
5.46 }
5.47
5.48 - private void doRunCompiler(String golden, String... fileContentAndExtraOptions) throws Exception {
5.49 + public void testDoNotApply() throws Exception {
5.50 + String golden =
5.51 + "package test;\n" +
5.52 + "public class Test {\n" +
5.53 + " private void test(java.util.Collection c) {\n" +
5.54 + " boolean b1 = c.size() == 0;\n" +
5.55 + "\tboolean b2 = c.size() == 0;\n" +
5.56 + " }\n" +
5.57 + "}\n";
5.58 +
5.59 + doRunCompiler(golden,
5.60 + "${workdir}/src/test/Test.java:3:Usage of .size() == 0 can be replaced with .isEmpty()\n" +
5.61 + " boolean b1 = c.size() == 0;\n" +
5.62 + " ^\n" +
5.63 + "${workdir}/src/test/Test.java:4:Usage of .size() == 0 can be replaced with .isEmpty()\n" +
5.64 + "\tboolean b2 = c.size() == 0;\n" +
5.65 + "\t ^\n",
5.66 + null,
5.67 + "src/test/Test.java",
5.68 + "package test;\n" +
5.69 + "public class Test {\n" +
5.70 + " private void test(java.util.Collection c) {\n" +
5.71 + " boolean b1 = c.size() == 0;\n" +
5.72 + "\tboolean b2 = c.size() == 0;\n" +
5.73 + " }\n" +
5.74 + "}\n",
5.75 + null,
5.76 + "--hint",
5.77 + "Usage of .size() == 0",
5.78 + "--no-apply");
5.79 + }
5.80 +
5.81 + private void doRunCompiler(String golden, String stdOut, String stdErr, String... fileContentAndExtraOptions) throws Exception {
5.82 List<String> fileAndContent = new LinkedList<String>();
5.83 List<String> extraOptions = new LinkedList<String>();
5.84 List<String> fileContentAndExtraOptionsList = Arrays.asList(fileContentAndExtraOptions);
5.85 @@ -114,20 +153,44 @@
5.86 options.addAll(extraOptions);
5.87 options.add(wd.getAbsolutePath());
5.88
5.89 - reallyRunCompiler(wd, options.toArray(new String[0]));
5.90 + String[] output = new String[2];
5.91 +
5.92 + reallyRunCompiler(wd, output, options.toArray(new String[0]));
5.93
5.94 assertEquals(golden, TestUtilities.copyFileToString(source));
5.95 +
5.96 + if (stdOut != null) {
5.97 + assertEquals(stdOut, output[0].replaceAll(Pattern.quote(wd.getAbsolutePath()), Matcher.quoteReplacement("${workdir}")));
5.98 + }
5.99 +
5.100 + if (stdErr != null) {
5.101 + assertEquals(stdErr, output[1].replaceAll(Pattern.quote(wd.getAbsolutePath()), Matcher.quoteReplacement("${workdir}")));
5.102 + }
5.103 }
5.104
5.105 - protected void reallyRunCompiler(File workDir, String... params) throws Exception {
5.106 + protected void reallyRunCompiler(File workDir, String[] output, String... params) throws Exception {
5.107 String oldUserDir = System.getProperty("user.dir");
5.108
5.109 System.setProperty("user.dir", workDir.getAbsolutePath());
5.110 +
5.111 + PrintStream oldOut = System.out;
5.112 + ByteArrayOutputStream outData = new ByteArrayOutputStream();
5.113 + System.setOut(new PrintStream(outData, true, "UTF-8"));
5.114 +
5.115 + PrintStream oldErr = System.err;
5.116 + ByteArrayOutputStream errData = new ByteArrayOutputStream();
5.117 + System.setErr(new PrintStream(errData, true, "UTF-8"));
5.118
5.119 try {
5.120 assertEquals(0, Main.compile(params));
5.121 } finally {
5.122 System.setProperty("user.dir", oldUserDir);
5.123 + System.out.close();
5.124 + output[0] = new String(outData.toByteArray(), "UTF-8");
5.125 + System.setOut(oldOut);
5.126 + System.err.close();
5.127 + output[1] = new String(errData.toByteArray(), "UTF-8");
5.128 + System.setErr(oldErr);
5.129 }
5.130 }
5.131