Introduce MutableDiagnosticsWithSuppression and use it in BindingTrace implementations
Exposes the fact that Diagnostics is in fact a mutable entity with readonly API Update readonly view when diagnostics are modified Allows to avoid recreating DiagnosticsWithSuppression every time getDiagnostics() is called in DelegatingBindingTrace which led to severe performance issues for large files with lots of diagnostics
This commit is contained in:
@@ -17,31 +17,27 @@
|
||||
package org.jetbrains.jet.lang.resolve;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.util.slicedmap.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class BindingTraceContext implements BindingTrace {
|
||||
private final List<Diagnostic> diagnosticList = Lists.newArrayList();
|
||||
private final Diagnostics diagnostics;
|
||||
|
||||
// These flags are used for debugging of "Rewrite at slice..." exceptions
|
||||
/* package */ final static boolean TRACK_REWRITES = false;
|
||||
/* package */ final static boolean TRACK_WITH_STACK_TRACES = true;
|
||||
|
||||
private final MutableSlicedMap map;
|
||||
private final MutableDiagnosticsWithSuppression mutableDiagnostics;
|
||||
|
||||
private final BindingContext bindingContext = new BindingContext() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Diagnostics getDiagnostics() {
|
||||
return diagnostics;
|
||||
return mutableDiagnostics;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,7 +67,7 @@ public class BindingTraceContext implements BindingTrace {
|
||||
|
||||
private BindingTraceContext(@NotNull MutableSlicedMap map) {
|
||||
this.map = map;
|
||||
this.diagnostics = new DiagnosticsWithSuppression(getBindingContext(), diagnosticList);
|
||||
this.mutableDiagnostics = new MutableDiagnosticsWithSuppression(bindingContext, Diagnostics.EMPTY);
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
@@ -81,11 +77,11 @@ public class BindingTraceContext implements BindingTrace {
|
||||
|
||||
@Override
|
||||
public void report(@NotNull Diagnostic diagnostic) {
|
||||
diagnosticList.add(diagnostic);
|
||||
mutableDiagnostics.report(diagnostic);
|
||||
}
|
||||
|
||||
public void clearDiagnostics() {
|
||||
diagnosticList.clear();
|
||||
mutableDiagnostics.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -25,7 +25,6 @@ import org.jetbrains.annotations.TestOnly;
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||
import org.jetbrains.jet.util.slicedmap.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -35,16 +34,14 @@ public class DelegatingBindingTrace implements BindingTrace {
|
||||
private final MutableSlicedMap map = BindingTraceContext.TRACK_REWRITES ? new TrackingSlicedMap(BindingTraceContext.TRACK_WITH_STACK_TRACES) : SlicedMapImpl.create();
|
||||
|
||||
private final BindingContext parentContext;
|
||||
private final List<Diagnostic> diagnostics = Lists.newArrayList();
|
||||
private final String name;
|
||||
private final MutableDiagnosticsWithSuppression mutableDiagnostics;
|
||||
|
||||
private final BindingContext bindingContext = new BindingContext() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Diagnostics getDiagnostics() {
|
||||
ArrayList<Diagnostic> mergedDiagnostics = new ArrayList<Diagnostic>(diagnostics);
|
||||
mergedDiagnostics.addAll(parentContext.getDiagnostics().noSuppression().all());
|
||||
return new DiagnosticsWithSuppression(this, mergedDiagnostics);
|
||||
return mutableDiagnostics;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,6 +70,7 @@ public class DelegatingBindingTrace implements BindingTrace {
|
||||
public DelegatingBindingTrace(BindingContext parentContext, String debugName) {
|
||||
this.parentContext = parentContext;
|
||||
this.name = debugName;
|
||||
this.mutableDiagnostics = new MutableDiagnosticsWithSuppression(bindingContext, parentContext.getDiagnostics());
|
||||
}
|
||||
|
||||
public DelegatingBindingTrace(BindingContext parentContext, String debugName, @Nullable Object resolutionSubjectForMessage) {
|
||||
@@ -147,7 +145,7 @@ public class DelegatingBindingTrace implements BindingTrace {
|
||||
|
||||
if (!commitDiagnostics) return;
|
||||
|
||||
for (Diagnostic diagnostic : diagnostics) {
|
||||
for (Diagnostic diagnostic : mutableDiagnostics.getOwnDiagnostics()) {
|
||||
if (filter == null || filter.accept(null, diagnostic.getPsiElement())) {
|
||||
trace.report(diagnostic);
|
||||
}
|
||||
@@ -156,12 +154,12 @@ public class DelegatingBindingTrace implements BindingTrace {
|
||||
|
||||
public void clear() {
|
||||
map.clear();
|
||||
diagnostics.clear();
|
||||
mutableDiagnostics.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void report(@NotNull Diagnostic diagnostic) {
|
||||
diagnostics.add(diagnostic);
|
||||
mutableDiagnostics.report(diagnostic);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,8 +18,13 @@ package org.jetbrains.jet.lang.resolve
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
|
||||
public trait Diagnostics : Iterable<Diagnostic> {
|
||||
//should not be called on readonly views
|
||||
public val modificationTracker: ModificationTracker
|
||||
get() = throw IllegalStateException("Trying to obtain modification tracker for Diagnostics object of class $javaClass")
|
||||
|
||||
public fun all(): Collection<Diagnostic>
|
||||
|
||||
public fun forElement(psiElement: PsiElement): Collection<Diagnostic>
|
||||
@@ -31,9 +36,9 @@ public trait Diagnostics : Iterable<Diagnostic> {
|
||||
override fun iterator() = all().iterator()
|
||||
|
||||
class object {
|
||||
|
||||
public val EMPTY: Diagnostics = object : Diagnostics {
|
||||
override fun noSuppression(): Diagnostics = this
|
||||
override val modificationTracker: ModificationTracker = ModificationTracker.NEVER_CHANGED
|
||||
override fun all() = listOf<Diagnostic>()
|
||||
override fun forElement(psiElement: PsiElement) = listOf<Diagnostic>()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.ModificationTracker;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.containers.ConcurrentWeakValueHashMap;
|
||||
@@ -217,6 +218,12 @@ public class DiagnosticsWithSuppression implements Diagnostics {
|
||||
return strings.contains(diagnostic.getFactory().getName().toLowerCase());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ModificationTracker getModificationTracker() {
|
||||
throw new IllegalStateException("Trying to obtain modification tracker for readonly DiagnosticsWithSuppression.");
|
||||
}
|
||||
|
||||
private static abstract class Suppressor {
|
||||
private final JetAnnotated annotated;
|
||||
|
||||
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2014 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.jet.lang.resolve
|
||||
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic
|
||||
import java.util.ArrayList
|
||||
import com.intellij.openapi.util.CompositeModificationTracker
|
||||
import com.intellij.util.CachedValueImpl
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
public class MutableDiagnosticsWithSuppression(
|
||||
private val bindingContext: BindingContext,
|
||||
private val delegateDiagnostics: Diagnostics = Diagnostics.EMPTY
|
||||
) : Diagnostics {
|
||||
private val diagnosticList = ArrayList<Diagnostic>()
|
||||
|
||||
//NOTE: CachedValuesManager is not used because it requires Project passed to this object
|
||||
private val cache = CachedValueImpl(CachedValueProvider {
|
||||
val allDiagnostics = delegateDiagnostics.noSuppression().all() + diagnosticList
|
||||
CachedValueProvider.Result(DiagnosticsWithSuppression(bindingContext, allDiagnostics), modificationTracker)
|
||||
})
|
||||
|
||||
private fun readonlyView() = cache.getValue()!!
|
||||
|
||||
public override val modificationTracker = CompositeModificationTracker(delegateDiagnostics.modificationTracker)
|
||||
|
||||
override fun all(): Collection<Diagnostic> = readonlyView().all()
|
||||
override fun forElement(psiElement: PsiElement) = readonlyView().forElement(psiElement)
|
||||
override fun noSuppression() = readonlyView().noSuppression()
|
||||
|
||||
//essential that this list is readonly
|
||||
fun getOwnDiagnostics(): List<Diagnostic> = diagnosticList
|
||||
|
||||
fun report(diagnostic: Diagnostic) {
|
||||
diagnosticList.add(diagnostic)
|
||||
modificationTracker.incModificationCount()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
diagnosticList.clear()
|
||||
modificationTracker.incModificationCount()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class JetTestUtils {
|
||||
@NotNull
|
||||
@Override
|
||||
public Diagnostics getDiagnostics() {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
return Diagnostics.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user