Binding trace filtering: do not calculate diagnostics if no one is going to query them
This commit is contained in:
@@ -86,13 +86,17 @@ class ControlFlowInformationProvider private constructor(
|
||||
|
||||
markUninitializedVariables()
|
||||
|
||||
markUnusedVariables()
|
||||
if (trace.wantsDiagnostics()) {
|
||||
markUnusedVariables()
|
||||
}
|
||||
|
||||
markStatements()
|
||||
|
||||
markUnusedExpressions()
|
||||
|
||||
checkIfExpressions()
|
||||
if (trace.wantsDiagnostics()) {
|
||||
checkIfExpressions()
|
||||
}
|
||||
|
||||
checkWhenExpressions()
|
||||
|
||||
|
||||
@@ -82,6 +82,11 @@ public class PseudocodeUtil {
|
||||
@Override
|
||||
public void report(@NotNull Diagnostic diagnostic) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return new ControlFlowProcessor(mockTrace).generatePseudocode(declaration);
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ public interface DiagnosticSink {
|
||||
@Override
|
||||
public void report(@NotNull Diagnostic diagnostic) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
DiagnosticSink THROW_EXCEPTION = new DiagnosticSink() {
|
||||
@@ -42,7 +47,13 @@ public interface DiagnosticSink {
|
||||
throw new IllegalStateException(diagnostic.getFactory().getName() + ": " + diagnosticText + " " + DiagnosticUtils.atLocation(psiFile, textRanges.get(0)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void report(@NotNull Diagnostic diagnostic);
|
||||
boolean wantsDiagnostics();
|
||||
}
|
||||
|
||||
@@ -37,14 +37,15 @@ public class BindingTraceContext implements BindingTrace {
|
||||
/* package */ final static boolean TRACK_WITH_STACK_TRACES = true;
|
||||
|
||||
private final MutableSlicedMap map;
|
||||
private final MutableDiagnosticsWithSuppression mutableDiagnostics;
|
||||
@Nullable private final MutableDiagnosticsWithSuppression mutableDiagnostics;
|
||||
@NotNull private final BindingTraceFilter filter;
|
||||
|
||||
private final BindingContext bindingContext = new BindingContext() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Diagnostics getDiagnostics() {
|
||||
return mutableDiagnostics;
|
||||
return mutableDiagnostics != null ? mutableDiagnostics : Diagnostics.Companion.getEMPTY();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,28 +79,45 @@ public class BindingTraceContext implements BindingTrace {
|
||||
};
|
||||
|
||||
public BindingTraceContext() {
|
||||
this(BindingTraceFilter.Companion.getACCEPT_ALL());
|
||||
}
|
||||
|
||||
public BindingTraceContext(BindingTraceFilter filter) {
|
||||
//noinspection ConstantConditions
|
||||
this(TRACK_REWRITES ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : SlicedMapImpl.create());
|
||||
this(TRACK_REWRITES ? new TrackingSlicedMap(TRACK_WITH_STACK_TRACES) : SlicedMapImpl.create(), filter);
|
||||
}
|
||||
|
||||
|
||||
private BindingTraceContext(@NotNull MutableSlicedMap map) {
|
||||
private BindingTraceContext(@NotNull MutableSlicedMap map, BindingTraceFilter filter) {
|
||||
this.map = map;
|
||||
this.mutableDiagnostics = new MutableDiagnosticsWithSuppression(bindingContext, Diagnostics.Companion.getEMPTY());
|
||||
this.mutableDiagnostics = !filter.getIgnoreDiagnostics()
|
||||
? new MutableDiagnosticsWithSuppression(bindingContext, Diagnostics.Companion.getEMPTY())
|
||||
: null;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
public static BindingTraceContext createTraceableBindingTrace() {
|
||||
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES));
|
||||
return new BindingTraceContext(new TrackingSlicedMap(TRACK_WITH_STACK_TRACES), BindingTraceFilter.Companion.getACCEPT_ALL());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void report(@NotNull Diagnostic diagnostic) {
|
||||
if (mutableDiagnostics == null) {
|
||||
return;
|
||||
}
|
||||
mutableDiagnostics.report(diagnostic);
|
||||
}
|
||||
|
||||
public void clearDiagnostics() {
|
||||
mutableDiagnostics.clear();
|
||||
if (mutableDiagnostics != null) {
|
||||
mutableDiagnostics.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return mutableDiagnostics != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2016 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.resolve
|
||||
|
||||
class BindingTraceFilter(val ignoreDiagnostics: Boolean) {
|
||||
companion object {
|
||||
val ACCEPT_ALL = BindingTraceFilter(false)
|
||||
val NO_DIAGNOSTICS = BindingTraceFilter(true)
|
||||
}
|
||||
|
||||
fun includesEverythingIn(otherFilter: BindingTraceFilter): Boolean {
|
||||
if (ignoreDiagnostics && !otherFilter.ignoreDiagnostics) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -28,12 +28,13 @@ import org.jetbrains.kotlin.util.slicedMap.*
|
||||
|
||||
open class DelegatingBindingTrace(private val parentContext: BindingContext,
|
||||
private val name: String,
|
||||
withParentDiagnostics: Boolean = true) : BindingTrace {
|
||||
withParentDiagnostics: Boolean = true,
|
||||
private val filter: BindingTraceFilter = BindingTraceFilter.ACCEPT_ALL) : BindingTrace {
|
||||
private val map = if (BindingTraceContext.TRACK_REWRITES) TrackingSlicedMap(BindingTraceContext.TRACK_WITH_STACK_TRACES) else SlicedMapImpl.create()
|
||||
private val mutableDiagnostics: MutableDiagnosticsWithSuppression
|
||||
private val mutableDiagnostics: MutableDiagnosticsWithSuppression?
|
||||
|
||||
private inner class MyBindingContext : BindingContext {
|
||||
override fun getDiagnostics(): Diagnostics = mutableDiagnostics
|
||||
override fun getDiagnostics(): Diagnostics = mutableDiagnostics ?: Diagnostics.EMPTY
|
||||
|
||||
override fun <K, V> get(slice: ReadOnlySlice<K, V>, key: K): V? {
|
||||
return this@DelegatingBindingTrace.get(slice, key)
|
||||
@@ -60,7 +61,9 @@ open class DelegatingBindingTrace(private val parentContext: BindingContext,
|
||||
private val bindingContext = MyBindingContext()
|
||||
|
||||
init {
|
||||
this.mutableDiagnostics = if (withParentDiagnostics)
|
||||
this.mutableDiagnostics = if (filter.ignoreDiagnostics)
|
||||
null
|
||||
else if (withParentDiagnostics)
|
||||
MutableDiagnosticsWithSuppression(bindingContext, parentContext.diagnostics)
|
||||
else
|
||||
MutableDiagnosticsWithSuppression(bindingContext)
|
||||
@@ -68,7 +71,11 @@ open class DelegatingBindingTrace(private val parentContext: BindingContext,
|
||||
|
||||
constructor(parentContext: BindingContext,
|
||||
debugName: String,
|
||||
resolutionSubjectForMessage: Any?) : this(parentContext, AnalyzingUtils.formDebugNameForBindingTrace(debugName, resolutionSubjectForMessage)) {
|
||||
resolutionSubjectForMessage: Any?,
|
||||
filter: BindingTraceFilter = BindingTraceFilter.ACCEPT_ALL)
|
||||
: this(parentContext,
|
||||
AnalyzingUtils.formDebugNameForBindingTrace(debugName, resolutionSubjectForMessage),
|
||||
filter = filter) {
|
||||
}
|
||||
|
||||
override fun getBindingContext(): BindingContext = bindingContext
|
||||
@@ -130,12 +137,17 @@ open class DelegatingBindingTrace(private val parentContext: BindingContext,
|
||||
|
||||
fun clear() {
|
||||
map.clear()
|
||||
mutableDiagnostics.clear()
|
||||
mutableDiagnostics?.clear()
|
||||
}
|
||||
|
||||
override fun report(diagnostic: Diagnostic) {
|
||||
if (mutableDiagnostics == null) {
|
||||
return
|
||||
}
|
||||
mutableDiagnostics.report(diagnostic)
|
||||
}
|
||||
|
||||
override fun wantsDiagnostics(): Boolean = mutableDiagnostics != null
|
||||
|
||||
override fun toString(): String = name
|
||||
}
|
||||
|
||||
@@ -91,5 +91,9 @@ public class ObservableBindingTrace implements BindingTrace {
|
||||
handlers = handlers.plus(slice, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return originalTrace.wantsDiagnostics();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,12 @@ public class TemporaryBindingTrace extends DelegatingBindingTrace {
|
||||
|
||||
@NotNull
|
||||
public static TemporaryBindingTrace create(@NotNull BindingTrace trace, String debugName) {
|
||||
return new TemporaryBindingTrace(trace, debugName);
|
||||
return create(trace, debugName, BindingTraceFilter.Companion.getACCEPT_ALL());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static TemporaryBindingTrace create(@NotNull BindingTrace trace, String debugName, BindingTraceFilter filter) {
|
||||
return new TemporaryBindingTrace(trace, debugName, filter);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -33,8 +38,8 @@ public class TemporaryBindingTrace extends DelegatingBindingTrace {
|
||||
|
||||
protected final BindingTrace trace;
|
||||
|
||||
protected TemporaryBindingTrace(@NotNull BindingTrace trace, String debugName) {
|
||||
super(trace.getBindingContext(), debugName, true);
|
||||
protected TemporaryBindingTrace(@NotNull BindingTrace trace, String debugName, BindingTraceFilter filter) {
|
||||
super(trace.getBindingContext(), debugName, true, filter);
|
||||
this.trace = trace;
|
||||
}
|
||||
|
||||
@@ -47,4 +52,9 @@ public class TemporaryBindingTrace extends DelegatingBindingTrace {
|
||||
addOwnDataTo(trace, filter, commitDiagnostics);
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return trace.wantsDiagnostics();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +94,11 @@ class CallCompleter(
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings)
|
||||
for (callChecker in callCheckers) {
|
||||
callChecker.check(resolvedCall, reportOn, callCheckerContext)
|
||||
}
|
||||
}
|
||||
|
||||
resolveHandleResultCallForCoroutineLambdaExpressions(context, resolvedCall)
|
||||
|
||||
@@ -563,7 +563,7 @@ public class CallResolver {
|
||||
if (CallResolverUtilKt.isInvokeCallOnVariable(call)) return;
|
||||
|
||||
DelegatingBindingTrace deltasTraceToCacheResolve = new DelegatingBindingTrace(
|
||||
BindingContext.EMPTY, "delta trace for caching resolve of", context.call);
|
||||
BindingContext.EMPTY, "delta trace for caching resolve of", context.call, BindingTraceFilter.Companion.getACCEPT_ALL());
|
||||
traceToResolveCall.addOwnDataTo(deltasTraceToCacheResolve);
|
||||
|
||||
context.resolutionResultsCache.record(call, results, context, tracing, deltasTraceToCacheResolve);
|
||||
|
||||
+4
-2
@@ -37,7 +37,7 @@ class MutableDiagnosticsWithSuppression @JvmOverloads constructor(
|
||||
CachedValueProvider.Result(DiagnosticsWithSuppression(bindingContext, allDiagnostics), modificationTracker)
|
||||
})
|
||||
|
||||
private fun readonlyView() = cache.value!!
|
||||
private fun readonlyView(): DiagnosticsWithSuppression = cache.value!!
|
||||
|
||||
override val modificationTracker = CompositeModificationTracker(delegateDiagnostics.modificationTracker)
|
||||
|
||||
@@ -46,7 +46,9 @@ class MutableDiagnosticsWithSuppression @JvmOverloads constructor(
|
||||
override fun noSuppression() = readonlyView().noSuppression()
|
||||
|
||||
//essential that this list is readonly
|
||||
fun getOwnDiagnostics(): List<Diagnostic> = diagnosticList
|
||||
fun getOwnDiagnostics(): List<Diagnostic> {
|
||||
return diagnosticList
|
||||
}
|
||||
|
||||
fun report(diagnostic: Diagnostic) {
|
||||
diagnosticList.add(diagnostic)
|
||||
|
||||
@@ -56,7 +56,7 @@ class FileScopeFactory(
|
||||
|
||||
fun createScopesForFile(file: KtFile, existingImports: ImportingScope? = null): FileScopes {
|
||||
val debugName = "LazyFileScope for file " + file.name
|
||||
val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve")
|
||||
val tempTrace = TemporaryBindingTrace.create(bindingTrace, "Transient trace for default imports lazy resolve", false)
|
||||
|
||||
infix fun <T> Collection<T>.concat(other: Collection<T>?) =
|
||||
if (other == null || other.isEmpty()) this else this + other
|
||||
|
||||
+2
@@ -81,5 +81,7 @@ class LockBasedLazyResolveStorageManager(private val storageManager: StorageMana
|
||||
override fun report(diagnostic: Diagnostic) {
|
||||
storageManager.compute { trace.report(diagnostic) }
|
||||
}
|
||||
|
||||
override fun wantsDiagnostics() = trace.wantsDiagnostics()
|
||||
}
|
||||
}
|
||||
|
||||
+11
-7
@@ -609,9 +609,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
trace.record(RESOLVED_CALL, call, resolvedCall);
|
||||
trace.record(CALL, expression, call);
|
||||
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -910,7 +912,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
if (KtTokens.AUGMENTED_ASSIGNMENTS.contains(operationType)
|
||||
|| operationType == KtTokens.PLUSPLUS || operationType == KtTokens.MINUSMINUS) {
|
||||
ResolvedCall<?> resolvedCall = ignoreReportsTrace.get(INDEXED_LVALUE_SET, expression);
|
||||
if (resolvedCall != null) {
|
||||
if (resolvedCall != null && trace.wantsDiagnostics()) {
|
||||
// Call must be validated with the actual, not temporary trace in order to report operator diagnostic
|
||||
// Only unary assignment expressions (++, --) and +=/... must be checked, normal assignments have the proper trace
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, trace, components.languageVersionSettings);
|
||||
@@ -979,9 +981,11 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
);
|
||||
resolvedCall.markCallAsCompleted();
|
||||
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
if (context.trace.wantsDiagnostics()) {
|
||||
CallCheckerContext callCheckerContext = new CallCheckerContext(context, components.languageVersionSettings);
|
||||
for (CallChecker checker : components.callCheckers) {
|
||||
checker.check(resolvedCall, expression, callCheckerContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user