diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java index b84cea3d8c65..bf7be68fd114 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyMethodResult.java @@ -15,7 +15,7 @@ */ package org.jetbrains.plugins.groovy.lang.psi.impl; -import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiSubstitutor; @@ -25,22 +25,28 @@ import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState; public class GroovyMethodResult extends GroovyResolveResultImpl { - private final NotNullLazyValue mySubstitutorComputer; + private final @NotNull NotNullComputable mySubstitutorComputer; public GroovyMethodResult(@NotNull PsiMethod method, @Nullable PsiElement resolveContext, @Nullable SpreadState spreadState, - @NotNull PsiSubstitutor substitutor, + @NotNull final PsiSubstitutor substitutor, boolean isAccessible, boolean staticsOK) { super(method, resolveContext, spreadState, substitutor, isAccessible, staticsOK, true, true); - mySubstitutorComputer = NotNullLazyValue.createConstantValue(substitutor); + mySubstitutorComputer = new NotNullComputable() { + @NotNull + @Override + public PsiSubstitutor compute() { + return substitutor; + } + }; } public GroovyMethodResult(@NotNull PsiMethod element, @Nullable PsiElement resolveContext, @Nullable SpreadState spreadState, @NotNull PsiSubstitutor partialSubstitutor, - @NotNull NotNullLazyValue substitutorComputer, + @NotNull NotNullComputable substitutorComputer, boolean isAccessible, boolean staticsOK, boolean isApplicable) { super(element, resolveContext, spreadState, partialSubstitutor, isAccessible, staticsOK, false, isApplicable); mySubstitutorComputer = substitutorComputer; @@ -55,11 +61,11 @@ public class GroovyMethodResult extends GroovyResolveResultImpl { @NotNull @Override public PsiSubstitutor getSubstitutor() { - return mySubstitutorComputer.getValue(); + return mySubstitutorComputer.compute(); } @NotNull public PsiSubstitutor getSubstitutor(boolean infer) { - return infer ? mySubstitutorComputer.getValue() : super.getSubstitutor(); + return infer ? mySubstitutorComputer.compute() : super.getSubstitutor(); } -} +} \ No newline at end of file diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java index 7ad48d1f7a80..b07b4871dcff 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/MethodResolverProcessor.java @@ -16,7 +16,7 @@ package org.jetbrains.plugins.groovy.lang.resolve.processors; -import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.NotNullComputable; import com.intellij.psi.*; import com.intellij.psi.scope.JavaScopeProcessorEvent; import com.intellij.psi.util.InheritanceUtil; @@ -33,6 +33,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.GrMethodComparator; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.util.NotNullCachedComputableWrapper; import java.util.Iterator; import java.util.List; @@ -108,14 +109,24 @@ public class MethodResolverProcessor extends ResolverProcessor substitutorComputer - = myByShape ? NotNullLazyValue.createConstantValue(partialSubstitutor) : new NotNullLazyValue() { - @NotNull - @Override - protected PsiSubstitutor compute() { - return mySubstitutorComputer.obtainSubstitutor(partialSubstitutor, method, resolveContext); - } - }; + final NotNullComputable substitutorComputer; + if (myByShape) { + substitutorComputer = new NotNullComputable() { + @NotNull + @Override + public PsiSubstitutor compute() { + return partialSubstitutor; + } + }; + } else { + substitutorComputer = new NotNullCachedComputableWrapper(new NotNullComputable() { + @NotNull + @Override + public PsiSubstitutor compute() { + return mySubstitutorComputer.obtainSubstitutor(partialSubstitutor, method, resolveContext); + } + }); + } boolean isAccessible = isAccessible(method); boolean isStaticsOK = isStaticsOK(method, resolveContext, false); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/NotNullCachedComputableWrapper.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/NotNullCachedComputableWrapper.java new file mode 100644 index 000000000000..3e534fa6d764 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/util/NotNullCachedComputableWrapper.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.util; + +import com.intellij.openapi.util.NotNullComputable; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; +import org.jetbrains.annotations.NotNull; + +public class NotNullCachedComputableWrapper implements NotNullComputable { + + private static final RecursionGuard ourGuard = RecursionManager.createGuard(NotNullCachedComputableWrapper.class.getName()); + + private NotNullComputable myComputable; + private T myValue; + + public NotNullCachedComputableWrapper(@NotNull NotNullComputable computable) { + myComputable = computable; + } + + @NotNull + @Override + public T compute() { + T result = myValue; + if (result == null) { + final RecursionGuard.StackStamp stamp = ourGuard.markStack(); + result = myComputable.compute(); + if (stamp.mayCacheNow()) { + myValue = result; + myComputable = null; // allow gc to clean this up + } + } + return result; + } +}