diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index d3c0504d197..7a05ab5ea94 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -16,13 +16,8 @@ package org.jetbrains.kotlin.diagnostics.rendering; -import com.google.common.collect.ImmutableList; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.Extensions; import kotlin.Function1; -import kotlin.KotlinPackage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; @@ -38,9 +33,11 @@ import org.jetbrains.kotlin.renderer.MultiRenderer; import org.jetbrains.kotlin.renderer.Renderer; import org.jetbrains.kotlin.resolve.varianceChecker.VarianceChecker.VarianceConflictDiagnosticData; import org.jetbrains.kotlin.types.JetType; +import org.jetbrains.kotlin.util.MappedExtensionProvider; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -58,61 +55,36 @@ public class DefaultErrorMessages { } private static final DiagnosticFactoryToRendererMap MAP = new DiagnosticFactoryToRendererMap(); - private static List maps = null; - private static Application application = ApplicationManager.getApplication(); - private static DispatchingDiagnosticRenderer renderer = null; + private static final MappedExtensionProvider> RENDERER_MAPS = MappedExtensionProvider.create( + Extension.EP_NAME, + new Function1, List>() { + @Override + public List invoke(List extensions) { + List result = new ArrayList(extensions.size() + 1); + for (Extension extension : extensions) { + result.add(extension.getMap()); + } + result.add(MAP); + return result; + } + }); @NotNull public static String render(@NotNull Diagnostic diagnostic) { - return getRenderer().render(diagnostic); - } - - @NotNull - private static DiagnosticRenderer getRenderer() { - boolean mapsChanged = resetMapsIfNeeded(); - - // Renderer is changed in tests only - if (renderer == null || mapsChanged) { - renderer = new DispatchingDiagnosticRenderer(maps); + for (DiagnosticFactoryToRendererMap map : RENDERER_MAPS.get()) { + DiagnosticRenderer renderer = map.get(diagnostic.getFactory()); + if (renderer != null) { + //noinspection unchecked + return renderer.render(diagnostic); + } } - - return renderer; - } - - private static boolean resetMapsIfNeeded() { - boolean needToResetMaps = maps == null; - Application newApp = ApplicationManager.getApplication(); - - if (application != newApp) { - assert newApp.isUnitTestMode(): "Expected application switch only in tests"; - application = newApp; - needToResetMaps = true; - } - - if (!needToResetMaps) return false; - - maps = ImmutableList.builder() - .addAll( - KotlinPackage.map( - Extensions.getExtensions(Extension.EP_NAME), - new Function1() { - @Override - public DiagnosticFactoryToRendererMap invoke(Extension extension) { - return extension.getMap(); - } - } - ) - ) - .add(MAP) - .build(); - - return true; + throw new IllegalArgumentException("Don't know how to render diagnostic of type " + diagnostic.getFactory().getName()); } @TestOnly @Nullable public static DiagnosticRenderer getRendererForDiagnostic(@NotNull Diagnostic diagnostic) { - for (DiagnosticFactoryToRendererMap map : maps) { + for (DiagnosticFactoryToRendererMap map : RENDERER_MAPS.get()) { DiagnosticRenderer renderer = map.get(diagnostic.getFactory()); if (renderer != null) return renderer; @@ -642,8 +614,6 @@ public class DefaultErrorMessages { } } } - - resetMapsIfNeeded(); } private DefaultErrorMessages() { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DispatchingDiagnosticRenderer.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DispatchingDiagnosticRenderer.java deleted file mode 100644 index f01b56e7fe1..00000000000 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DispatchingDiagnosticRenderer.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2010-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.kotlin.diagnostics.rendering; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.diagnostics.Diagnostic; - -import java.util.List; - -public class DispatchingDiagnosticRenderer implements DiagnosticRenderer { - @NotNull - private final List maps; - - public DispatchingDiagnosticRenderer(@NotNull List maps) { - this.maps = maps; - } - - @NotNull - @Override - public String render(@NotNull Diagnostic diagnostic) { - for (DiagnosticFactoryToRendererMap map : maps) { - DiagnosticRenderer renderer = map.get(diagnostic.getFactory()); - if (renderer != null) { - //noinspection unchecked - return renderer.render(diagnostic); - } - } - throw new IllegalArgumentException("Don't know how to render diagnostic of type " + diagnostic.getFactory().getName()); - } -} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java index f4d1107ac51..85a01b8899d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/DiagnosticsWithSuppression.java @@ -17,11 +17,8 @@ package org.jetbrains.kotlin.resolve.diagnostics; import com.google.common.collect.ImmutableSet; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.ExtensionPointName; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.ModificationTracker; import com.intellij.psi.PsiElement; @@ -35,15 +32,12 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.diagnostics.Severity; -import org.jetbrains.kotlin.psi.JetAnnotated; -import org.jetbrains.kotlin.psi.JetAnnotationEntry; -import org.jetbrains.kotlin.psi.JetFile; -import org.jetbrains.kotlin.psi.JetStubbedPsiUtil; -import org.jetbrains.kotlin.psi.PsiPackage; +import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.constants.ArrayValue; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.constants.StringValue; +import org.jetbrains.kotlin.util.ExtensionProvider; import java.util.*; @@ -64,36 +58,10 @@ public class DiagnosticsWithSuppression implements Diagnostics { private static final Logger LOG = Logger.getInstance(DiagnosticsWithSuppression.class); - private static Application app = null; - private static SuppressStringProvider[] ADDITIONAL_SUPPRESS_STRING_PROVIDERS = null; - private static DiagnosticSuppressor[] DIAGNOSTIC_SUPPRESSORS = null; - - static { - resetExtensionsIfNeed(); - } - - private static SuppressStringProvider[] getAdditionalSuppressStringProviders() { - resetExtensionsIfNeed(); - return ADDITIONAL_SUPPRESS_STRING_PROVIDERS; - } - - private static DiagnosticSuppressor[] getDiagnosticSuppressors() { - resetExtensionsIfNeed(); - return DIAGNOSTIC_SUPPRESSORS; - } - - // We need to update extensions in tests because they may be different for different tests. - private static void resetExtensionsIfNeed() { - if (app != null && !app.isUnitTestMode()) return; - - Application newApp = ApplicationManager.getApplication(); - if (app == newApp) return; - - app = newApp; - - ADDITIONAL_SUPPRESS_STRING_PROVIDERS = Extensions.getExtensions(SuppressStringProvider.EP_NAME); - DIAGNOSTIC_SUPPRESSORS = Extensions.getExtensions(DiagnosticSuppressor.EP_NAME); - } + private static final ExtensionProvider ADDITIONAL_SUPPRESS_STRING_PROVIDERS + = ExtensionProvider.create(SuppressStringProvider.EP_NAME); + private static final ExtensionProvider DIAGNOSTIC_SUPPRESSORS + = ExtensionProvider.create(DiagnosticSuppressor.EP_NAME); private final BindingContext context; private final Collection diagnostics; @@ -153,7 +121,7 @@ public class DiagnosticsWithSuppression implements Diagnostics { if (PsiPackage.getDoNotAnalyze((JetFile) file) != null) return true; } - for (DiagnosticSuppressor suppressor : getDiagnosticSuppressors()) { + for (DiagnosticSuppressor suppressor : DIAGNOSTIC_SUPPRESSORS.get()) { if (suppressor.isSuppressed(diagnostic)) return true; } @@ -239,7 +207,7 @@ public class DiagnosticsWithSuppression implements Diagnostics { AnnotationDescriptor annotationDescriptor = context.get(BindingContext.ANNOTATION, annotationEntry); if (annotationDescriptor == null) continue; - for (SuppressStringProvider suppressStringProvider : getAdditionalSuppressStringProviders()) { + for (SuppressStringProvider suppressStringProvider : ADDITIONAL_SUPPRESS_STRING_PROVIDERS.get()) { builder.addAll(suppressStringProvider.get(annotationDescriptor)); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/util/MappedExtensionProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/util/MappedExtensionProvider.kt new file mode 100644 index 00000000000..1680eaec558 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/util/MappedExtensionProvider.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2010-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.kotlin.util + +import com.intellij.openapi.application.Application +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.extensions.ExtensionPointName +import java.lang.ref.WeakReference +import kotlin.platform.platformStatic + +public open class MappedExtensionProvider protected (private val epName: ExtensionPointName, private val map: (List) -> R) { + private var cached = WeakReference>(null) + + public fun get(): R { + val cached = cached.get() ?: return update() + val (app, extensions) = cached + if (app == ApplicationManager.getApplication()) { + return extensions + } + else { + return update() + } + } + + private fun update(): R { + val newVal = ApplicationManager.getApplication().let { app -> + Pair(app, map(app.getExtensions(epName).toList())) + } + cached = WeakReference(newVal) + return newVal.second + } + + companion object { + platformStatic public fun create(epName: ExtensionPointName, map: (List) -> R): MappedExtensionProvider + = MappedExtensionProvider(epName, map) + } +} + +public class ExtensionProvider(epName: ExtensionPointName) : MappedExtensionProvider>(epName, { it }) { + companion object { + platformStatic public fun create(epName: ExtensionPointName): ExtensionProvider = ExtensionProvider(epName) + } +} \ No newline at end of file