From 810d44fe0f9aad1756a81ec463a56fce3740f266 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Mon, 20 Feb 2017 19:16:12 +0300 Subject: [PATCH 1/8] util: (minor) Suppress unchecked cast in NullableCachedComputable --- platform/util/src/com/intellij/openapi/util/Computable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/util/src/com/intellij/openapi/util/Computable.java b/platform/util/src/com/intellij/openapi/util/Computable.java index 6a6be75d70a4..15b938c9e048 100644 --- a/platform/util/src/com/intellij/openapi/util/Computable.java +++ b/platform/util/src/com/intellij/openapi/util/Computable.java @@ -69,6 +69,7 @@ public interface Computable { final T value = internalCompute(); myValue = value != null ? value : NULL_VALUE; } + //noinspection unchecked return myValue != NULL_VALUE ? (T)myValue : null; } } From b74b9a62aa5b9a3121749cd0947bc5b5792d4ef1 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Mon, 20 Feb 2017 19:47:34 +0300 Subject: [PATCH 2/8] util: Implement cached Computable of appropriate nullity --- platform/util/src/com/intellij/openapi/util/Computable.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/Computable.java b/platform/util/src/com/intellij/openapi/util/Computable.java index 15b938c9e048..4f7697a8b58b 100644 --- a/platform/util/src/com/intellij/openapi/util/Computable.java +++ b/platform/util/src/com/intellij/openapi/util/Computable.java @@ -39,7 +39,7 @@ public interface Computable { } } - abstract class NotNullCachedComputable implements Computable { + abstract class NotNullCachedComputable implements NotNullComputable { private T myValue; @NotNull @@ -55,7 +55,7 @@ public interface Computable { } } - abstract class NullableCachedComputable implements Computable { + abstract class NullableCachedComputable implements NullableComputable { private static final Object NULL_VALUE = new Object(); private Object myValue; From eb1b2a40d0835000c68bd1703284cbffcd93d253 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Mon, 20 Feb 2017 20:10:15 +0300 Subject: [PATCH 3/8] util: Add factory methods for delegating to another Computable Useful in conjunction with Java 8 method references. --- .../com/intellij/openapi/util/Computable.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/platform/util/src/com/intellij/openapi/util/Computable.java b/platform/util/src/com/intellij/openapi/util/Computable.java index 4f7697a8b58b..61f10409e517 100644 --- a/platform/util/src/com/intellij/openapi/util/Computable.java +++ b/platform/util/src/com/intellij/openapi/util/Computable.java @@ -53,6 +53,17 @@ public interface Computable { } return myValue; } + + @NotNull + public static NotNullCachedComputable from(@NotNull final NotNullComputable delegate) { + return new NotNullCachedComputable() { + @NotNull + @Override + protected T internalCompute() { + return delegate.compute(); + } + }; + } } abstract class NullableCachedComputable implements NullableComputable { @@ -72,5 +83,16 @@ public interface Computable { //noinspection unchecked return myValue != NULL_VALUE ? (T)myValue : null; } + + @NotNull + public static NullableCachedComputable from(@NotNull final NullableComputable delegate) { + return new NullableCachedComputable() { + @Nullable + @Override + protected T internalCompute() { + return delegate.compute(); + } + }; + } } } From 3b3860486ba444d99270db1bec52ec1f29b69e0d Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Tue, 28 Feb 2017 13:10:10 +0300 Subject: [PATCH 4/8] util: recursion: (cleanup) Fix deprecation warnings due to JavaDoc links --- .../intellij/openapi/util/RecursionGuard.java | 21 +++++++++---------- .../openapi/util/RecursionManager.java | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/RecursionGuard.java b/platform/util/src/com/intellij/openapi/util/RecursionGuard.java index 4d9baa1e83ce..1df46a37503b 100644 --- a/platform/util/src/com/intellij/openapi/util/RecursionGuard.java +++ b/platform/util/src/com/intellij/openapi/util/RecursionGuard.java @@ -28,9 +28,8 @@ import java.util.List; public abstract class RecursionGuard { /** - * See {@link #doPreventingRecursion(Object, boolean, Computable)} with memoization disabled + * @deprecated Use {@link #doPreventingRecursion(Object, boolean, Computable)} with memoization disabled instead */ - @SuppressWarnings("JavaDoc") @Deprecated @Nullable public T doPreventingRecursion(@NotNull Object key, @NotNull Computable computation) { @@ -49,7 +48,7 @@ public abstract class RecursionGuard { public abstract T doPreventingRecursion(@NotNull Object key, boolean memoize, @NotNull Computable computation); /** - * Used in pair with {@link com.intellij.openapi.util.RecursionGuard.StackStamp#mayCacheNow()} to ensure that cached are only the reliable values, + * Used in pair with {@link RecursionGuard.StackStamp#mayCacheNow()} to ensure that cached are only the reliable values, * not depending on anything incomplete due to recursive prevention policies. * A typical usage is this: * {@code @@ -62,20 +61,19 @@ public abstract class RecursionGuard { * } * return result; * } - * @return an object representing the current stack state, managed by {@link RecursionManager} */ @NotNull public abstract StackStamp markStack(); /** - * @return the current thread-local stack of keys passed to {@link #doPreventingRecursion(Object, Computable)} + * @return the current thread-local stack of keys passed to {@link #doPreventingRecursion(Object, boolean, Computable)} */ @NotNull public abstract List currentStack(); /** - * Makes {@link com.intellij.openapi.util.RecursionGuard.StackStamp#mayCacheNow()} return false for all stamps created since a computation with + * Makes {@link RecursionGuard.StackStamp#mayCacheNow()} return false for all stamps created since a computation with * key {@code since} began. * * Used to prevent caching of results that are non-reliable NOT due to recursion prevention: for example, too deep recursion @@ -90,13 +88,14 @@ public abstract class RecursionGuard { public interface StackStamp { /** - * @return whether a computation that started at the moment of this {@link StackStamp} instance creation does not depend on any re-entrant recursive - * results. When such non-reliable results exist in the thread's call stack, returns false, otherwise true. - * If you use this with {@link RecursionGuard#doPreventingRecursion(Object, Computable)}, then the - * {@link com.intellij.openapi.util.RecursionGuard#markStack()}+{@link #mayCacheNow()} should be outside of recursion prevention call. Otherwise - * even the outer recursive computation result won't be cached. + * @return whether a computation that started at the moment of this {@link StackStamp} instance creation does not depend on any + * re-entrant recursive results. When such non-reliable results exist in the thread's call stack, returns false, otherwise true. * + * If you use this with {@link RecursionGuard#doPreventingRecursion(Object, boolean, Computable)}, then the + * {@link RecursionGuard#markStack()}+{@link #mayCacheNow()} should be outside of recursion prevention call. Otherwise + * even the outer recursive computation result won't be cached. */ + @SuppressWarnings("JavaDoc") boolean mayCacheNow(); } } diff --git a/platform/util/src/com/intellij/openapi/util/RecursionManager.java b/platform/util/src/com/intellij/openapi/util/RecursionManager.java index b40d0bb7318e..6dcb83bf5978 100644 --- a/platform/util/src/com/intellij/openapi/util/RecursionManager.java +++ b/platform/util/src/com/intellij/openapi/util/RecursionManager.java @@ -31,7 +31,7 @@ import java.util.*; /** * There are moments when a computation A requires the result of computation B, which in turn requires C, which (unexpectedly) requires A. * If there are no other ways to solve it, it helps to track all the computations in the thread stack and return some default value when - * asked to compute A for the second time. {@link RecursionGuard#doPreventingRecursion(Object, Computable)} does precisely this. + * asked to compute A for the second time. {@link RecursionGuard#doPreventingRecursion(Object, boolean, Computable)} does precisely this. * * It's quite useful to cache some computation results to avoid performance problems. But not everyone realises that in the above situation it's * incorrect to cache the results of B and C, because they all are based on the default incomplete result of the A calculation. If the actual @@ -40,7 +40,7 @@ import java.util.*; * situation the result of C would depend on the order of invocations of C and A, which can be hardly predictable in multi-threaded environments. * * Therefore if you use any kind of cache, it probably would make your program safer to cache only when it's safe to do this. See - * {@link com.intellij.openapi.util.RecursionGuard#markStack()} and {@link com.intellij.openapi.util.RecursionGuard.StackStamp#mayCacheNow()} + * {@link RecursionGuard#markStack()} and {@link RecursionGuard.StackStamp#mayCacheNow()} * for the advice. * * @see RecursionGuard From 99cd8cde192f6a0c7b70909ba887f96c00525a24 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Tue, 28 Feb 2017 13:54:18 +0300 Subject: [PATCH 5/8] util: Deprecate Computable.*CachedComputable in favor of *LazyValue --- .../com/intellij/openapi/util/Computable.java | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/platform/util/src/com/intellij/openapi/util/Computable.java b/platform/util/src/com/intellij/openapi/util/Computable.java index 61f10409e517..1c4df827081a 100644 --- a/platform/util/src/com/intellij/openapi/util/Computable.java +++ b/platform/util/src/com/intellij/openapi/util/Computable.java @@ -25,6 +25,7 @@ public interface Computable { T compute(); + @Deprecated class PredefinedValueComputable implements Computable { private final T myValue; @@ -39,6 +40,10 @@ public interface Computable { } } + /** + * @deprecated Use {@link NotNullLazyValue}::getValue instead + */ + @Deprecated abstract class NotNullCachedComputable implements NotNullComputable { private T myValue; @@ -53,19 +58,12 @@ public interface Computable { } return myValue; } - - @NotNull - public static NotNullCachedComputable from(@NotNull final NotNullComputable delegate) { - return new NotNullCachedComputable() { - @NotNull - @Override - protected T internalCompute() { - return delegate.compute(); - } - }; - } } + /** + * @deprecated Use {@link NullableLazyValue}::getValue instead + */ + @Deprecated abstract class NullableCachedComputable implements NullableComputable { private static final Object NULL_VALUE = new Object(); private Object myValue; @@ -83,16 +81,5 @@ public interface Computable { //noinspection unchecked return myValue != NULL_VALUE ? (T)myValue : null; } - - @NotNull - public static NullableCachedComputable from(@NotNull final NullableComputable delegate) { - return new NullableCachedComputable() { - @Nullable - @Override - protected T internalCompute() { - return delegate.compute(); - } - }; - } } } From 29c521c88aedaf167e0f146ffdf2f2d7cded65ed Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Wed, 1 Mar 2017 03:50:06 +0300 Subject: [PATCH 6/8] testFramework: (testing) Add UsefulTestCase.assertThrows() --- .../testFramework/UsefulTestCase.java | 39 +++++++++++++++++-- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index 1d76f243e119..bc85f80df55d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -42,10 +42,7 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.refactoring.rename.inplace.InplaceRefactoring; import com.intellij.rt.execution.junit.FileComparisonFailure; import com.intellij.testFramework.exceptionCases.AbstractExceptionCase; -import com.intellij.util.Consumer; -import com.intellij.util.DocumentUtil; -import com.intellij.util.Processor; -import com.intellij.util.ReflectionUtil; +import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.ui.UIUtil; @@ -875,6 +872,40 @@ public abstract class UsefulTestCase extends TestCase { assertExceptionOccurred(true, exceptionCase, expectedErrorMsg); } + /** + * Checks that the code block throws an exception of the specified class. + * + * @param exceptionClass Expected exception type + * @param runnable Block annotated with some exception type + */ + protected void assertThrows(@NotNull Class exceptionClass, + @NotNull ThrowableRunnable runnable) throws Throwable { + assertThrows(exceptionClass, null, runnable); + } + + /** + * Checks that the code block throws an exception of the specified class with expected error msg. + * If expected error message is null it will not be checked. + * + * @param exceptionClass Expected exception type + * @param expectedErrorMsg expected error message, of any + * @param runnable Block annotated with some exception type + */ + protected void assertThrows(@NotNull Class exceptionClass, @Nullable String expectedErrorMsg, + @NotNull ThrowableRunnable runnable) throws Throwable { + assertException(new AbstractExceptionCase() { + @Override + public Class getExpectedExceptionClass() { + return exceptionClass; + } + + @Override + public void tryClosure() throws Throwable { + runnable.run(); + } + }, expectedErrorMsg); + } + /** * Checks that code block doesn't throw corresponding exception. * From 2e4b69cbdfd6ae78b9a5357390fe8815f7994f66 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Wed, 1 Mar 2017 04:25:24 +0300 Subject: [PATCH 7/8] testFramework: (testing) Generify UsefulTestCase.assertThrows() Make it throw T - the same exception type as the tested runnable block declares. --- .../testFramework/UsefulTestCase.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index bc85f80df55d..cf1bbf510df4 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -869,6 +869,7 @@ public abstract class UsefulTestCase extends TestCase { * @param expectedErrorMsg expected error message */ protected void assertException(AbstractExceptionCase exceptionCase, @Nullable String expectedErrorMsg) throws Throwable { + //noinspection unchecked assertExceptionOccurred(true, exceptionCase, expectedErrorMsg); } @@ -878,8 +879,8 @@ public abstract class UsefulTestCase extends TestCase { * @param exceptionClass Expected exception type * @param runnable Block annotated with some exception type */ - protected void assertThrows(@NotNull Class exceptionClass, - @NotNull ThrowableRunnable runnable) throws Throwable { + protected void assertThrows(@NotNull Class exceptionClass, + @NotNull ThrowableRunnable runnable) throws T { assertThrows(exceptionClass, null, runnable); } @@ -891,12 +892,13 @@ public abstract class UsefulTestCase extends TestCase { * @param expectedErrorMsg expected error message, of any * @param runnable Block annotated with some exception type */ - protected void assertThrows(@NotNull Class exceptionClass, @Nullable String expectedErrorMsg, - @NotNull ThrowableRunnable runnable) throws Throwable { - assertException(new AbstractExceptionCase() { + @SuppressWarnings({"unchecked", "SameParameterValue"}) + protected void assertThrows(@NotNull Class exceptionClass, @Nullable String expectedErrorMsg, + @NotNull ThrowableRunnable runnable) throws T { + assertExceptionOccurred(true, new AbstractExceptionCase() { @Override - public Class getExpectedExceptionClass() { - return exceptionClass; + public Class getExpectedExceptionClass() { + return (Class)exceptionClass; } @Override @@ -911,7 +913,7 @@ public abstract class UsefulTestCase extends TestCase { * * @param exceptionCase Block annotated with some exception type */ - protected void assertNoException(final AbstractExceptionCase exceptionCase) throws Throwable { + protected void assertNoException(final AbstractExceptionCase exceptionCase) throws T { assertExceptionOccurred(false, exceptionCase, null); } @@ -926,9 +928,9 @@ public abstract class UsefulTestCase extends TestCase { assertNull(throwableName); } - private static void assertExceptionOccurred(boolean shouldOccur, - AbstractExceptionCase exceptionCase, - String expectedErrorMsg) throws Throwable { + private static void assertExceptionOccurred(boolean shouldOccur, + AbstractExceptionCase exceptionCase, + String expectedErrorMsg) throws T { boolean wasThrown = false; try { exceptionCase.tryClosure(); From cd322c56a0b41bc0796b45ff633827ad8a60dd39 Mon Sep 17 00:00:00 2001 From: Eldar Abusalimov Date: Wed, 1 Mar 2017 14:01:00 +0300 Subject: [PATCH 8/8] testFramework: (testing) Fix type parameters in assertThrows() Follows-up: IDEA-CR-18741 testFramework: (testing) Add UsefulTestCase.assertThrows() --- .../src/com/intellij/testFramework/UsefulTestCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java index cf1bbf510df4..c3709477425b 100644 --- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java @@ -879,7 +879,7 @@ public abstract class UsefulTestCase extends TestCase { * @param exceptionClass Expected exception type * @param runnable Block annotated with some exception type */ - protected void assertThrows(@NotNull Class exceptionClass, + protected void assertThrows(@NotNull Class exceptionClass, @NotNull ThrowableRunnable runnable) throws T { assertThrows(exceptionClass, null, runnable); } @@ -893,7 +893,7 @@ public abstract class UsefulTestCase extends TestCase { * @param runnable Block annotated with some exception type */ @SuppressWarnings({"unchecked", "SameParameterValue"}) - protected void assertThrows(@NotNull Class exceptionClass, @Nullable String expectedErrorMsg, + protected void assertThrows(@NotNull Class exceptionClass, @Nullable String expectedErrorMsg, @NotNull ThrowableRunnable runnable) throws T { assertExceptionOccurred(true, new AbstractExceptionCase() { @Override