Binding trace filtering: do not calculate diagnostics if no one is going to query them

This commit is contained in:
Dmitry Jemerov
2016-09-26 12:48:46 +02:00
parent b365e547c4
commit d8b0c7aaec
24 changed files with 230 additions and 89 deletions
@@ -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);
@@ -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
@@ -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()
}
}
@@ -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);
}
}
}