diff --git a/platform/util/src/com/intellij/openapi/util/NotNullLazyValue.java b/platform/util/src/com/intellij/openapi/util/NotNullLazyValue.java index 4768ac666a35..96eefe8ddf78 100644 --- a/platform/util/src/com/intellij/openapi/util/NotNullLazyValue.java +++ b/platform/util/src/com/intellij/openapi/util/NotNullLazyValue.java @@ -37,4 +37,14 @@ public abstract class NotNullLazyValue { } return myValue; } + + public static NotNullLazyValue createConstantValue(@NotNull final T value) { + return new NotNullLazyValue() { + @NotNull + @Override + protected T compute() { + return value; + } + }; + } } \ No newline at end of file diff --git a/xml/dom-impl/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java b/xml/dom-impl/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java index 52c215398912..8f90fce673cb 100644 --- a/xml/dom-impl/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java +++ b/xml/dom-impl/src/com/intellij/codeInsight/navigation/NavigationGutterIconBuilder.java @@ -26,7 +26,9 @@ import com.intellij.navigation.GotoRelatedItem; import com.intellij.openapi.editor.markup.GutterIconRenderer; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Factory; import com.intellij.openapi.util.NotNullLazyValue; +import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.SmartPointerManager; import com.intellij.psi.SmartPsiElementPointer; @@ -64,7 +66,7 @@ public class NavigationGutterIconBuilder { private final Icon myIcon; private final NotNullFunction> myConverter; - private NotNullLazyValue> myTargets; + private NotNullLazyValue> myTargets; private boolean myLazy; private String myTooltipText; private String myPopupTitle; @@ -134,18 +136,15 @@ public class NavigationGutterIconBuilder { } public NavigationGutterIconBuilder setTargets(@NotNull final NotNullLazyValue> targets) { - myTargets = targets; + //noinspection unchecked + myTargets = (NotNullLazyValue)targets; myLazy = true; return this; } public NavigationGutterIconBuilder setTargets(@NotNull final Collection targets) { - myTargets = new NotNullLazyValue>() { - @NotNull - public Collection compute() { - return targets; - } - }; + //noinspection unchecked + myTargets = NotNullLazyValue.createConstantValue((Collection)targets); return this; } @@ -206,46 +205,55 @@ public class NavigationGutterIconBuilder { public RelatedItemLineMarkerInfo createLineMarkerInfo(@NotNull PsiElement element) { final MyNavigationGutterIconRenderer renderer = createGutterIconRenderer(element.getProject()); final String tooltip = renderer.getTooltipText(); - NotNullLazyValue> gotoTargets = new NotNullLazyValue>() { - @NotNull - @Override - protected Collection compute() { - if (myGotoRelatedItemProvider != null) { - return ContainerUtil.concat(myTargets.getValue(), myGotoRelatedItemProvider); - } - return Collections.emptyList(); - } - }; + NotNullLazyValue> gotoTargets = createGotoTargetsThunk(myLazy, myGotoRelatedItemProvider, + evaluateAndForget(myTargets)); return new RelatedItemLineMarkerInfo(element, element.getTextRange(), renderer.getIcon(), Pass.UPDATE_OVERRIDEN_MARKERS, tooltip == null ? null : new ConstantFunction(tooltip), renderer.isNavigateAction() ? renderer : null, renderer.getAlignment(), gotoTargets); } + private static NotNullLazyValue> createGotoTargetsThunk(boolean lazy, + final NotNullFunction> gotoRelatedItemProvider, + final Factory> factory) { + if (gotoRelatedItemProvider == null) { + return NotNullLazyValue.>createConstantValue(Collections.emptyList()); + } + + if (lazy) { + return new NotNullLazyValue>() { + @NotNull + @Override + protected Collection compute() { + return ContainerUtil.concat(factory.create(), gotoRelatedItemProvider); + } + }; + } + Collection concat = ContainerUtil.concat(factory.create(), gotoRelatedItemProvider); + return NotNullLazyValue.>createConstantValue(concat); + } + private void checkBuilt() { assert myTargets != null : "Must have called .setTargets() before calling create()"; } - - private MyNavigationGutterIconRenderer createGutterIconRenderer(@NotNull Project project) { - checkBuilt(); - final SmartPointerManager manager = SmartPointerManager.getInstance(project); - - NotNullLazyValue> pointers = new NotNullLazyValue>() { - @NotNull - public List compute() { - Set elements = new THashSet(); - Collection targets = myTargets.getValue(); - final List list = new ArrayList(targets.size()); - for (final T target : targets) { - for (final PsiElement psiElement : myConverter.fun(target)) { - if (elements.add(psiElement) && psiElement.isValid()) { - list.add(manager.createSmartPsiElementPointer(psiElement)); - } - } - } - return list; + + private static Factory evaluateAndForget(NotNullLazyValue lazyValue) { + final Ref> ref = Ref.create(lazyValue); + return new Factory() { + @Override + public T create() { + T result = ref.get().getValue(); + ref.set(null); + return result; } }; + } + + private MyNavigationGutterIconRenderer createGutterIconRenderer(@NotNull final Project project) { + checkBuilt(); + + NotNullLazyValue> pointers = createPointersThunk(myLazy, project, evaluateAndForget(myTargets), + myConverter); final boolean empty = isEmpty(); @@ -278,6 +286,37 @@ public class NavigationGutterIconBuilder { return new MyNavigationGutterIconRenderer(this, myAlignment, myIcon, myTooltipText, pointers, renderer, empty); } + private static NotNullLazyValue> createPointersThunk(boolean lazy, + final Project project, + final Factory> targets, + final NotNullFunction> converter) { + if (!lazy) { + return NotNullLazyValue.createConstantValue(calcPsiTargets(project, targets.create(), converter)); + } + + return new NotNullLazyValue>() { + @NotNull + public List compute() { + return calcPsiTargets(project, targets.create(), converter); + } + }; + } + + private static List calcPsiTargets(Project project, Collection targets, + NotNullFunction> converter) { + SmartPointerManager manager = SmartPointerManager.getInstance(project); + Set elements = new THashSet(); + final List list = new ArrayList(targets.size()); + for (final T target : targets) { + for (final PsiElement psiElement : converter.fun(target)) { + if (elements.add(psiElement) && psiElement.isValid()) { + list.add(manager.createSmartPsiElementPointer(psiElement)); + } + } + } + return list; + } + private boolean isEmpty() { if (myLazy) { return false;