diff -r 681895d7a357 java.source/apichanges.xml --- a/java.source/apichanges.xml Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/apichanges.xml Tue Oct 18 11:32:08 2011 +0200 @@ -108,6 +108,19 @@ + + + Added CompilationInfo.getCachedValue, CompilationInfo.putCachedValue and CompilationInfo.CacheClearPolicy. + + + + + + Added CompilationInfo.getCachedValue and CompilationInfo.putCachedValue methods and + CompilationInfo.CacheClearPolicy enum so that tasks can easily store temporary data with predictable termination. + + + Added GeneratorUtilities.addImports and several methods to CodeStyle to support organizing imports. diff -r 681895d7a357 java.source/nbproject/project.properties --- a/java.source/nbproject/project.properties Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/nbproject/project.properties Tue Oct 18 11:32:08 2011 +0200 @@ -46,7 +46,7 @@ javadoc.title=Java Source javadoc.arch=${basedir}/arch.xml javadoc.apichanges=${basedir}/apichanges.xml -spec.version.base=0.88.0 +spec.version.base=0.89.0 test.qa-functional.cp.extra=${refactoring.java.dir}/modules/ext/javac-api-nb-7.0-b07.jar test.unit.run.cp.extra=${o.n.core.dir}/core/core.jar:\ ${o.n.core.dir}/lib/boot.jar:\ diff -r 681895d7a357 java.source/src/org/netbeans/api/java/source/CompilationInfo.java --- a/java.source/src/org/netbeans/api/java/source/CompilationInfo.java Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/src/org/netbeans/api/java/source/CompilationInfo.java Tue Oct 18 11:32:08 2011 +0200 @@ -56,6 +56,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; @@ -66,6 +67,7 @@ import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.CheckReturnValue; import org.netbeans.api.annotations.common.NonNull; +import org.netbeans.api.annotations.common.NullAllowed; import org.netbeans.api.annotations.common.NullUnknown; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.modules.java.preprocessorbridge.spi.WrapperFactory; @@ -412,12 +414,40 @@ return Source.toSourceVersion(Source.instance(impl.getJavacTask().getContext())); } + /**Retrieve a value cached under the given key using the + * {@link #putCachedValue(java.lang.Object, java.lang.Object, org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy)} method. + * + * @param key for which the cached value should be retrieved + * @return value originally passed to {@link #putCachedValue(java.lang.Object, java.lang.Object, org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy)}, or null if none + * @since 0.89 + */ + public @CheckForNull Object getCachedValue(@NonNull Object key) { + Parameters.notNull("key", key); + return impl.getCachedValue(key); + } + + /**Put a value into a cache under the given key. The {@link #clearPolicy} parameter specifies the latest time the + * references to the key and value should be cleared. The infrastructure is free to clear the references at any earlier time. + * The clients should not depend on this cache for correctness, only to improve performance. + * + * @param key a unique key under which the value should be stored + * @param value the value to store - any value previously set under the same key will be erased from the cache + * @param clearPolicy the latest time when the mapping should be cleared from the cache + * @since 0.89 + */ + public void putCachedValue(@NonNull Object key, @NullAllowed Object value, @NonNull CacheClearPolicy clearPolicy) { + Parameters.notNull("key", key); + Parameters.notNull("clearPolicy", clearPolicy); + impl.putCachedValue(key, value, clearPolicy); + } + /** * Marks this {@link CompilationInfo} as invalid, may be used to * verify confinement. */ final void invalidate () { this.invalid = true; + this.impl.taskFinished(); doInvalidate(); } @@ -439,4 +469,10 @@ throw new IllegalStateException (String.format("Access to the shared %s outside a guarded run method.", this.getClass().getSimpleName())); } } + + public enum CacheClearPolicy { + ON_TASK_END, + ON_CHANGE, + ON_SIGNATURE_CHANGE; + } } diff -r 681895d7a357 java.source/src/org/netbeans/modules/java/source/parsing/CompilationInfoImpl.java --- a/java.source/src/org/netbeans/modules/java/source/parsing/CompilationInfoImpl.java Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/src/org/netbeans/modules/java/source/parsing/CompilationInfoImpl.java Tue Oct 18 11:32:08 2011 +0200 @@ -51,6 +51,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.EnumMap; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -66,6 +67,7 @@ import javax.tools.DiagnosticListener; import javax.tools.JavaFileObject; import org.netbeans.api.java.source.ClasspathInfo; +import org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy; import org.netbeans.api.java.source.JavaSource; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.modules.java.source.JavaFileFilterQuery; @@ -89,7 +91,7 @@ private JavacTaskImpl javacTask; private DiagnosticListener diagnosticListener; private final ClasspathInfo cpInfo; - Pair changedMethod; + private Pair changedMethod; private final FileObject file; private final FileObject root; final JavaFileObject jfo; @@ -99,6 +101,7 @@ private final boolean isClassFile; private final boolean isDetached; JavaSource.Phase parserCrashed = JavaSource.Phase.UP_TO_DATE; //When javac throws an error, the moveToPhase sets this to the last safe phase + private final Map> userCache = new EnumMap>(CacheClearPolicy.class); /** * Creates a new CompilationInfoImpl for given source file @@ -387,6 +390,38 @@ return javacTask; } + public Object getCachedValue(Object key) { + for (Map c : userCache.values()) { + Object res = c.get(key); + + if (res != null) return res; + } + + return null; + } + + public void putCachedValue(Object key, Object value, CacheClearPolicy clearPolicy) { + for (Map c : userCache.values()) { + c.remove(key); + } + + Map c = userCache.get(clearPolicy); + + if (c == null) { + userCache.put(clearPolicy, c = new HashMap()); + } + + c.put(key, value); + } + + public void taskFinished() { + userCache.remove(CacheClearPolicy.ON_TASK_END); + } + + public void invalidate() { + userCache.clear(); + } + /** * Returns current {@link DiagnosticListener} * @return listener @@ -410,6 +445,8 @@ */ void setChangedMethod (final Pair changedMethod) { this.changedMethod = changedMethod; + userCache.remove(CacheClearPolicy.ON_TASK_END); + userCache.remove(CacheClearPolicy.ON_CHANGE); } /** diff -r 681895d7a357 java.source/src/org/netbeans/modules/java/source/parsing/JavacParser.java --- a/java.source/src/org/netbeans/modules/java/source/parsing/JavacParser.java Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/src/org/netbeans/modules/java/source/parsing/JavacParser.java Tue Oct 18 11:32:08 2011 +0200 @@ -338,6 +338,7 @@ LOGGER.log(Level.FINE, "parse: task: {0}\n{1}", new Object[]{ //NOI18N task.toString(), snapshot == null ? "null" : snapshot.getText()}); //NOI18N + CompilationInfoImpl oldInfo = ciImpl; switch (this.sourceCount) { case 0: ClasspathInfo _tmpInfo = null; @@ -358,6 +359,9 @@ if (_changedMethod != null && ciImpl != null) { LOGGER.log(Level.FINE, "\t:trying partial reparse:\n{0}", _changedMethod.first.getText()); //NOI18N needsFullReparse = !reparseMethod(ciImpl, snapshot, _changedMethod.second, _changedMethod.first.getText()); + if (!needsFullReparse) { + ciImpl.setChangedMethod(_changedMethod); + } } } if (needsFullReparse) { @@ -372,6 +376,9 @@ ciImpl == null ? null : ciImpl.getJavacTask(), ciImpl == null ? null : ciImpl.getDiagnosticListener()); } + if (oldInfo != ciImpl && oldInfo != null) { + oldInfo.invalidate(); + } cachedSnapShot = snapshot; } diff -r 681895d7a357 java.source/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java --- a/java.source/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java Tue Oct 18 10:26:26 2011 +0200 +++ b/java.source/test/unit/src/org/netbeans/api/java/source/CompilationInfoTest.java Tue Oct 18 11:32:08 2011 +0200 @@ -45,12 +45,22 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; import java.text.MessageFormat; import javax.lang.model.SourceVersion; +import javax.swing.text.Document; import org.junit.Test; +import org.netbeans.api.java.lexer.JavaTokenId; +import org.netbeans.api.java.source.CompilationInfo.CacheClearPolicy; +import org.netbeans.api.java.source.JavaSource.Phase; +import org.netbeans.api.lexer.Language; +import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.junit.NbTestCase; +import org.openide.cookies.EditorCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; +import org.openide.loaders.DataObject; /** * @@ -67,7 +77,7 @@ @Override public void setUp() throws Exception { - SourceUtilsTestUtil.prepareTest(new String[0], new Object[0]); + SourceUtilsTestUtil.prepareTest(new String[] {"META-INF/generated-layer.xml"}, new Object[0]); } /** @@ -105,4 +115,64 @@ return null; } } + + public void testCacheEviction() throws Exception { + clearWorkDir(); + + FileObject source = FileUtil.createData(new File(getWorkDir(), "Test.java")); + DataObject sourceDO = DataObject.find(source); + EditorCookie ec = sourceDO.getLookup().lookup(EditorCookie.class); + + assertNotNull(ec); + + Document doc = ec.openDocument(); + + doc.putProperty(Language.class, JavaTokenId.language()); + + TokenHierarchy.get(doc).tokenSequence().tokenCount(); + + TestUtilities.copyStringToFile(source, "public class Test {\n void test() {\n //whatever\n }\n}\n"); + + JavaSource js = JavaSource.forDocument(doc); + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + parameter.putCachedValue("1", 1, CacheClearPolicy.ON_TASK_END); + parameter.putCachedValue("2", 2, CacheClearPolicy.ON_CHANGE); + parameter.putCachedValue("3", 3, CacheClearPolicy.ON_SIGNATURE_CHANGE); + } + }, true); + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + assertNull(parameter.getCachedValue("1")); + assertEquals(2, parameter.getCachedValue("2")); + assertEquals(3, parameter.getCachedValue("3")); + } + }, true); + + doc.insertString(41, "a", null); + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + assertNull(parameter.getCachedValue("1")); + assertNull(parameter.getCachedValue("2")); + assertEquals(3, parameter.getCachedValue("3")); + } + }, true); + + doc.insertString(20, "void t2() {}", null); + + js.runUserActionTask(new Task() { + public void run(CompilationController parameter) throws Exception { + parameter.toPhase(Phase.RESOLVED); + assertNull(parameter.getCachedValue("1")); + assertNull(parameter.getCachedValue("2")); + assertNull(parameter.getCachedValue("3")); + } + }, true); + } }