This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 227271
Collapse All | Expand All

(-)a/java.hints.test/apichanges.xml (+17 lines)
Lines 107-112 Link Here
107
107
108
    <changes>
108
    <changes>
109
109
110
        <change id="HintTest-ensureJavaFixes">
111
             <api name="JavaHintsTest"/>
112
             <summary>Added assertFixes method to HintWarning</summary>
113
             <version major="1" minor="8"/>
114
             <date day="18" month="3" year="2013"/>
115
             <author login="jlahoda"/>
116
             <compatibility addition="no" binary="yes" deletion="no" deprecation="no" modification="no" semantic="incompatible" source="compatible"/>
117
             <description>
118
                 <code>HintTest.HintWarning.applyFix</code> now enforces constraints for Inspect&amp;Transform. Unless a hint
119
                 is marked as <code>Options.QUERY</code>, <code>Options.NO_BULK</code> or <code>Kind.ACTION</code>,
120
                 the <code>Fix</code> that is being applied is tested to be <code>JavaFix</code> and repeatable,
121
                 which are the requirements of Inspect&amp;Transform.
122
             </description>
123
             <class name="HintTest" package="org.netbeans.modules.java.hints.test.api"/>
124
             <issue number="227271"/>
125
        </change>
126
        
110
        <change id="HintWarning-assertFixes">
127
        <change id="HintWarning-assertFixes">
111
             <api name="JavaHintsTest"/>
128
             <api name="JavaHintsTest"/>
112
             <summary>Added assertFixes method to HintWarning</summary>
129
             <summary>Added assertFixes method to HintWarning</summary>
(-)a/java.hints.test/nbproject/project.properties (-1 / +1 lines)
Lines 1-7 Link Here
1
is.autoload=true
1
is.autoload=true
2
javac.source=1.6
2
javac.source=1.6
3
javac.compilerargs=-Xlint -Xlint:-serial
3
javac.compilerargs=-Xlint -Xlint:-serial
4
spec.version.base=1.7.0
4
spec.version.base=1.8.0
5
javadoc.arch=${basedir}/arch.xml
5
javadoc.arch=${basedir}/arch.xml
6
javadoc.apichanges=${basedir}/apichanges.xml
6
javadoc.apichanges=${basedir}/apichanges.xml
7
requires.nb.javac=true
7
requires.nb.javac=true
(-)a/java.hints.test/nbproject/project.xml (+8 lines)
Lines 129-134 Link Here
129
                    </run-dependency>
129
                    </run-dependency>
130
                </dependency>
130
                </dependency>
131
                <dependency>
131
                <dependency>
132
                    <code-name-base>org.netbeans.modules.refactoring.api</code-name-base>
133
                    <build-prerequisite/>
134
                    <compile-dependency/>
135
                    <run-dependency>
136
                        <specification-version>1.34</specification-version>
137
                    </run-dependency>
138
                </dependency>
139
                <dependency>
132
                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
140
                    <code-name-base>org.netbeans.spi.editor.hints</code-name-base>
133
                    <build-prerequisite/>
141
                    <build-prerequisite/>
134
                    <compile-dependency/>
142
                    <compile-dependency/>
(-)a/java.hints.test/src/org/netbeans/modules/java/hints/test/api/HintTest.java (-14 / +102 lines)
Lines 93-100 Link Here
93
import org.netbeans.api.java.source.CompilationInfo;
93
import org.netbeans.api.java.source.CompilationInfo;
94
import org.netbeans.api.java.source.JavaSource;
94
import org.netbeans.api.java.source.JavaSource;
95
import org.netbeans.api.java.source.JavaSource.Phase;
95
import org.netbeans.api.java.source.JavaSource.Phase;
96
import org.netbeans.api.java.source.ModificationResult;
97
import org.netbeans.api.java.source.ModificationResult.Difference;
96
import org.netbeans.api.java.source.Task;
98
import org.netbeans.api.java.source.Task;
99
import org.netbeans.api.java.source.WorkingCopy;
97
import org.netbeans.api.lexer.Language;
100
import org.netbeans.api.lexer.Language;
101
import org.netbeans.api.project.Project;
98
import org.netbeans.core.startup.Main;
102
import org.netbeans.core.startup.Main;
99
import org.netbeans.junit.NbTestCase;
103
import org.netbeans.junit.NbTestCase;
100
import org.netbeans.modules.java.JavaDataLoader;
104
import org.netbeans.modules.java.JavaDataLoader;
Lines 102-121 Link Here
102
import org.netbeans.modules.java.hints.providers.code.FSWrapper;
106
import org.netbeans.modules.java.hints.providers.code.FSWrapper;
103
import org.netbeans.modules.java.hints.providers.code.FSWrapper.ClassWrapper;
107
import org.netbeans.modules.java.hints.providers.code.FSWrapper.ClassWrapper;
104
import org.netbeans.modules.java.hints.providers.spi.HintDescription;
108
import org.netbeans.modules.java.hints.providers.spi.HintDescription;
109
import org.netbeans.modules.java.hints.providers.spi.HintDescription.Worker;
110
import org.netbeans.modules.java.hints.providers.spi.HintDescriptionFactory;
105
import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
111
import org.netbeans.modules.java.hints.providers.spi.HintMetadata;
112
import org.netbeans.modules.java.hints.providers.spi.HintMetadata.Options;
113
import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl;
114
import org.netbeans.modules.java.hints.spiimpl.JavaFixImpl.Accessor;
106
import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
115
import org.netbeans.modules.java.hints.spiimpl.MessageImpl;
107
import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
116
import org.netbeans.modules.java.hints.spiimpl.SyntheticFix;
117
import org.netbeans.modules.java.hints.spiimpl.batch.BatchUtilities;
108
import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
118
import org.netbeans.modules.java.hints.spiimpl.hints.HintsInvoker;
109
import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
119
import org.netbeans.modules.java.hints.spiimpl.options.HintsSettings;
110
import org.netbeans.modules.java.hints.test.Utilities.TestLookup;
120
import org.netbeans.modules.java.hints.test.Utilities.TestLookup;
121
import org.netbeans.modules.java.source.JavaSourceAccessor;
111
import org.netbeans.modules.java.source.TreeLoader;
122
import org.netbeans.modules.java.source.TreeLoader;
112
import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
123
import org.netbeans.modules.parsing.impl.indexing.CacheFolder;
113
import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
124
import org.netbeans.modules.parsing.impl.indexing.MimeTypes;
125
import org.netbeans.modules.refactoring.spi.RefactoringElementImplementation;
114
import org.netbeans.spi.editor.hints.ErrorDescription;
126
import org.netbeans.spi.editor.hints.ErrorDescription;
115
import org.netbeans.spi.editor.hints.Fix;
127
import org.netbeans.spi.editor.hints.Fix;
116
import org.netbeans.spi.editor.hints.Severity;
128
import org.netbeans.spi.editor.hints.Severity;
117
import org.netbeans.spi.java.classpath.ClassPathProvider;
129
import org.netbeans.spi.java.classpath.ClassPathProvider;
118
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
130
import org.netbeans.spi.java.classpath.support.ClassPathSupport;
131
import org.netbeans.spi.java.hints.Hint.Kind;
132
import org.netbeans.spi.java.hints.HintContext;
133
import org.netbeans.spi.java.hints.JavaFix;
119
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
134
import org.netbeans.spi.java.queries.SourceForBinaryQueryImplementation;
120
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
135
import org.netbeans.spi.java.queries.SourceLevelQueryImplementation;
121
import org.openide.LifecycleManager;
136
import org.openide.LifecycleManager;
Lines 448-456 Link Here
448
        }
463
        }
449
464
450
        List<HintDescription> total = new LinkedList<HintDescription>();
465
        List<HintDescription> total = new LinkedList<HintDescription>();
466
        final Set<ErrorDescription> requiresJavaFix = Collections.newSetFromMap(new IdentityHashMap<ErrorDescription, Boolean>());
451
467
452
        for (Collection<? extends HintDescription> l : hints.values()) {
468
        for (final Entry<HintMetadata, Collection<HintDescription>> e : hints.entrySet()) {
453
            total.addAll(l);
469
            if (   e.getKey().options.contains(Options.NO_BATCH)
470
                || e.getKey().options.contains(Options.QUERY)
471
                || e.getKey().kind == Kind.ACTION) {
472
                total.addAll(e.getValue());
473
                continue;
474
            }
475
            for (final HintDescription hd : e.getValue()) {
476
                total.add(HintDescriptionFactory.create()
477
                                               .setTrigger(hd.getTrigger())
478
                                               .setMetadata(e.getKey())
479
                                               .setAdditionalConstraints(hd.getAdditionalConstraints())
480
                                               .addOptions(hd.getOptions().toArray(new Options[0]))
481
                                               .setWorker(new Worker() {
482
                                                    @Override public Collection<? extends ErrorDescription> createErrors(HintContext ctx) {
483
                                                        Collection<? extends ErrorDescription> errors = hd.getWorker().createErrors(ctx);
484
 
485
                                                        if (errors != null) {
486
                                                            for (ErrorDescription ed : errors) {
487
                                                                requiresJavaFix.add(ed);
488
                                                            }
489
                                                        }
490
                                                        
491
                                                        return errors;
492
                                                     }
493
                                                })
494
                                              .produce());
495
            }
454
        }
496
        }
455
        
497
        
456
        CompilationInfo info = parse(testFile);
498
        CompilationInfo info = parse(testFile);
Lines 489-495 Link Here
489
        NbTestCase.assertGC("noone holds javac", cut);
531
        NbTestCase.assertGC("noone holds javac", cut);
490
        DEBUGGING_HELPER.remove(result);
532
        DEBUGGING_HELPER.remove(result);
491
        
533
        
492
        return new HintOutput(result);
534
        return new HintOutput(result, requiresJavaFix);
493
    }
535
    }
494
    
536
    
495
    //must keep the error descriptions (and their Fixes through them) in a field
537
    //must keep the error descriptions (and their Fixes through them) in a field
Lines 721-729 Link Here
721
    public final class HintOutput {
763
    public final class HintOutput {
722
        
764
        
723
        private final List<ErrorDescription> errors;
765
        private final List<ErrorDescription> errors;
766
        private final Set<ErrorDescription> requiresJavaFix;
724
767
725
        private HintOutput(List<ErrorDescription> errors) {
768
        private HintOutput(List<ErrorDescription> errors, Set<ErrorDescription> requiresJavaFix) {
726
            this.errors = errors;
769
            this.errors = errors;
770
            this.requiresJavaFix = requiresJavaFix;
727
771
728
        }
772
        }
729
773
Lines 809-815 Link Here
809
853
810
            assertNotNull("Warning: \"" + warning + "\" not found. All ErrorDescriptions: " + errors.toString(), toFix);
854
            assertNotNull("Warning: \"" + warning + "\" not found. All ErrorDescriptions: " + errors.toString(), toFix);
811
855
812
            return new HintWarning(toFix);
856
            return new HintWarning(toFix, requiresJavaFix.contains(toFix));
813
        }
857
        }
814
    }
858
    }
815
859
Lines 817-824 Link Here
817
     */
861
     */
818
    public final class HintWarning {
862
    public final class HintWarning {
819
        private final ErrorDescription warning;
863
        private final ErrorDescription warning;
820
        HintWarning(ErrorDescription warning) {
864
        private final boolean requiresJavaFix;
865
        HintWarning(ErrorDescription warning, boolean requiresJavaFix) {
821
            this.warning = warning;
866
            this.warning = warning;
867
            this.requiresJavaFix = requiresJavaFix;
822
        }
868
        }
823
        /**Applies the only fix of the current warning. Fails if the given warning
869
        /**Applies the only fix of the current warning. Fails if the given warning
824
         * does not have exactly one fix.
870
         * does not have exactly one fix.
Lines 840-852 Link Here
840
886
841
            assertEquals(1, fixes.size());
887
            assertEquals(1, fixes.size());
842
888
843
            Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
889
            doApplyFix(fixes.get(0));
844
            preferences.putBoolean("importInnerClasses", true);
845
            try {
846
                fixes.get(0).implement();
847
            } finally {
848
                preferences.remove("importInnerClasses");
849
            }
850
890
851
            if (saveAll)
891
            if (saveAll)
852
                LifecycleManager.getDefault().saveAll();
892
                LifecycleManager.getDefault().saveAll();
Lines 879-889 Link Here
879
919
880
            assertNotNull("Cannot find fix to invoke: " + fixNames.toString(), toApply);
920
            assertNotNull("Cannot find fix to invoke: " + fixNames.toString(), toApply);
881
921
882
            toApply.implement();
922
            doApplyFix(toApply);
923
            
883
            LifecycleManager.getDefault().saveAll();
924
            LifecycleManager.getDefault().saveAll();
884
925
885
            return new AppliedFix();
926
            return new AppliedFix();
886
        }
927
        }
928
        private void doApplyFix(Fix f) throws Exception {
929
            Preferences preferences = MimeLookup.getLookup(JavaTokenId.language().mimeType()).lookup(Preferences.class);
930
            preferences.putBoolean("importInnerClasses", true);
931
            try {
932
                if (requiresJavaFix) {
933
                    assertTrue("The fix must be a JavaFix", f instanceof JavaFixImpl);
934
                    
935
                    ModificationResult result1 = runJavaFix(((JavaFixImpl) f).jf);
936
                    ModificationResult result2 = runJavaFix(((JavaFixImpl) f).jf);
937
                    
938
                    //ensure the results are the same:
939
                    assertEquals("The fix must be repeatable", result1.getModifiedFileObjects(), result2.getModifiedFileObjects());
940
                    
941
                    for (FileObject file : result1.getModifiedFileObjects()) {
942
                        assertEquals("The fix must be repeatable", result1.getResultingSource(file), result2.getResultingSource(file));
943
                    }
944
                    
945
                    result1.commit();
946
                } else {
947
                    f.implement();
948
                }
949
            } finally {
950
                preferences.remove("importInnerClasses");
951
            }
952
        }
953
        private ModificationResult runJavaFix(final JavaFix jf) throws IOException {
954
            FileObject file = Accessor.INSTANCE.getFile(jf);
955
            JavaSource js = JavaSource.forFileObject(file);
956
            final Map<FileObject, List<Difference>> changes = new HashMap<FileObject, List<Difference>>();
957
958
            ModificationResult mr = js.runModificationTask(new Task<WorkingCopy>() {
959
                public void run(WorkingCopy wc) throws Exception {
960
                    if (wc.toPhase(Phase.RESOLVED).compareTo(Phase.RESOLVED) < 0) {
961
                        return;
962
                    }
963
964
                    Map<FileObject, byte[]> resourceContentChanges = new HashMap<FileObject, byte[]>();
965
                    Accessor.INSTANCE.process(jf, wc, true, resourceContentChanges, /*Ignored for now:*/new ArrayList<RefactoringElementImplementation>());
966
                    BatchUtilities.addResourceContentChanges(resourceContentChanges, changes);
967
                    
968
                }
969
            });
970
            
971
            changes.putAll(JavaSourceAccessor.getINSTANCE().getDiffsFromModificationResult(mr));
972
            
973
            return JavaSourceAccessor.getINSTANCE().createModificationResult(changes, Collections.<Object, int[]>emptyMap());
974
        }
887
        /**Verifies that the current warning provides the given fixes.
975
        /**Verifies that the current warning provides the given fixes.
888
         *
976
         *
889
         * @param fixes the {@link Fix#getText() } of the expected fixes
977
         * @param fixes the {@link Fix#getText() } of the expected fixes
(-)a/java.hints.test/test/unit/src/org/netbeans/modules/java/hints/test/api/HintTestTest.java (+69 lines)
Lines 55-65 Link Here
55
import org.netbeans.api.java.source.ClasspathInfo.PathKind;
55
import org.netbeans.api.java.source.ClasspathInfo.PathKind;
56
import org.netbeans.api.java.source.CompilationInfo;
56
import org.netbeans.api.java.source.CompilationInfo;
57
import org.netbeans.api.java.source.JavaSource;
57
import org.netbeans.api.java.source.JavaSource;
58
import org.netbeans.spi.editor.hints.ChangeInfo;
58
import org.netbeans.spi.editor.hints.ErrorDescription;
59
import org.netbeans.spi.editor.hints.ErrorDescription;
60
import org.netbeans.spi.editor.hints.Fix;
59
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
61
import org.netbeans.spi.java.hints.ErrorDescriptionFactory;
60
import org.netbeans.spi.java.hints.Hint;
62
import org.netbeans.spi.java.hints.Hint;
61
import org.netbeans.spi.java.hints.HintContext;
63
import org.netbeans.spi.java.hints.HintContext;
62
import org.netbeans.spi.java.hints.JavaFix;
64
import org.netbeans.spi.java.hints.JavaFix;
65
import org.netbeans.spi.java.hints.JavaFix.TransformationContext;
63
import org.netbeans.spi.java.hints.TriggerTreeKind;
66
import org.netbeans.spi.java.hints.TriggerTreeKind;
64
import org.openide.cookies.EditorCookie;
67
import org.openide.cookies.EditorCookie;
65
import org.openide.filesystems.FileObject;
68
import org.openide.filesystems.FileObject;
Lines 235-238 Link Here
235
            throw new NullPointerException("a");
238
            throw new NullPointerException("a");
236
        }
239
        }
237
    }
240
    }
241
242
    @Test
243
    public void testNonJavaFix() throws Exception {
244
        HintTest ht = HintTest.create()
245
                              .input("package test;\n" +
246
                                     "public class Test { }\n");
247
        try {
248
            ht.run(NonJavaFix.class)
249
              .findWarning("1:0-1:21:verifier:Test")
250
              .applyFix();
251
            Assert.fail("No exception thrown");
252
        } catch (AssertionError ae) {
253
            //ok
254
            Assert.assertEquals("The fix must be a JavaFix", ae.getMessage());
255
        }
256
    }
257
    
258
    @Hint(displayName="nonJavaFix", description="nonJavaFix", category="test")
259
    public static final class NonJavaFix {
260
        @TriggerTreeKind(Kind.CLASS)
261
        public static ErrorDescription hint(HintContext ctx) {
262
            return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), "Test", new Fix() {
263
                @Override public String getText() {
264
                    return "Fix";
265
                }
266
                @Override public ChangeInfo implement() throws Exception {
267
                    return null;
268
                }
269
            });
270
        }
271
    }
272
    
273
    @Test
274
    public void testNotRepeatableJavaFix() throws Exception {
275
        HintTest ht = HintTest.create()
276
                              .input("package test;\n" +
277
                                     "public class Test { }\n");
278
        try {
279
            ht.run(NotRepeatableJavaFix.class)
280
              .findWarning("1:0-1:21:verifier:Test")
281
              .applyFix();
282
            Assert.fail("No exception thrown");
283
        } catch (AssertionError ae) {
284
            //ok
285
            Assert.assertTrue(ae.getMessage().startsWith("The fix must be repeatable"));
286
        }
287
    }
288
    
289
    @Hint(displayName="notRepeatableJavaFix", description="notRepeatableJavaFix", category="test")
290
    public static final class NotRepeatableJavaFix {
291
        @TriggerTreeKind(Kind.CLASS)
292
        public static ErrorDescription hint(HintContext ctx) {
293
            Fix f = new JavaFix(ctx.getInfo(), ctx.getPath()) {
294
                private boolean wasRun;
295
                @Override protected String getText() {
296
                    return "Fix";
297
                }
298
                @Override protected void performRewrite(TransformationContext ctx) throws Exception {
299
                    if (wasRun) return ;
300
                    ctx.getWorkingCopy().rewrite(ctx.getPath().getLeaf(), ctx.getWorkingCopy().getTreeMaker().setLabel(ctx.getPath().getLeaf(), "Nue"));
301
                    wasRun = true;
302
                }
303
            }.toEditorFix();
304
            return ErrorDescriptionFactory.forTree(ctx, ctx.getPath(), "Test", f);
305
        }
306
    }
238
}
307
}

Return to bug 227271