Binding trace filtering: do not calculate diagnostics if no one is going to query them
This commit is contained in:
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
||||
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
|
||||
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
@@ -67,7 +68,8 @@ class GenerationState @JvmOverloads constructor(
|
||||
// partial compilation. Module chunks are treated as a single module.
|
||||
// TODO: get rid of it with the proper module infrastructure
|
||||
val outDirectory: File? = null,
|
||||
private val onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING
|
||||
private val onIndependentPartCompilationEnd: GenerationStateEventCallback = GenerationStateEventCallback.DO_NOTHING,
|
||||
wantsDiagnostics: Boolean = true
|
||||
) {
|
||||
abstract class GenerateClassFilter {
|
||||
abstract fun shouldAnnotateClass(processingClassOrObject: KtClassOrObject): Boolean
|
||||
@@ -129,7 +131,8 @@ class GenerationState @JvmOverloads constructor(
|
||||
|
||||
val moduleName: String = moduleName ?: JvmCodegenUtil.getModuleName(module)
|
||||
val classBuilderMode: ClassBuilderMode = builderFactory.classBuilderMode
|
||||
val bindingTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "trace in GenerationState")
|
||||
val bindingTrace: BindingTrace = DelegatingBindingTrace(bindingContext, "trace in GenerationState",
|
||||
filter = if (wantsDiagnostics) BindingTraceFilter.ACCEPT_ALL else BindingTraceFilter.NO_DIAGNOSTICS)
|
||||
val bindingContext: BindingContext = bindingTrace.bindingContext
|
||||
val typeMapper: KotlinTypeMapper = KotlinTypeMapper(
|
||||
this.bindingContext, classBuilderMode, fileClassesProvider, incrementalCacheForThisTarget,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -99,7 +99,8 @@ abstract class LightClassDataProvider<T : WithFileStubAndExtraDiagnostics>(
|
||||
context.bindingContext,
|
||||
files.toMutableList(),
|
||||
CompilerConfiguration.EMPTY,
|
||||
generateClassFilter
|
||||
generateClassFilter,
|
||||
wantsDiagnostics = false
|
||||
)
|
||||
state.beforeCompile()
|
||||
|
||||
|
||||
@@ -196,6 +196,11 @@ public class KotlinTestUtils {
|
||||
throw new IllegalStateException("Unresolved: " + diagnostic.getPsiElement().getText());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
public static BindingTrace DUMMY_EXCEPTION_ON_ERROR_TRACE = new BindingTrace() {
|
||||
@@ -276,6 +281,11 @@ public class KotlinTestUtils {
|
||||
throw new IllegalStateException(DefaultErrorMessages.render(diagnostic));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wantsDiagnostics() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// We suspect sequences of eight consecutive hexadecimal digits to be a package part hash code
|
||||
|
||||
@@ -16,8 +16,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.lazy
|
||||
|
||||
enum class BodyResolveMode {
|
||||
FULL,
|
||||
PARTIAL,
|
||||
PARTIAL_FOR_COMPLETION
|
||||
import org.jetbrains.kotlin.resolve.BindingTraceFilter
|
||||
|
||||
open class BodyResolveMode {
|
||||
open val bindingTraceFilter: BindingTraceFilter = BindingTraceFilter.ACCEPT_ALL
|
||||
|
||||
companion object {
|
||||
@JvmField val FULL = BodyResolveMode()
|
||||
|
||||
@JvmField val PARTIAL = object : BodyResolveMode() {
|
||||
override val bindingTraceFilter: BindingTraceFilter
|
||||
get() = BindingTraceFilter.NO_DIAGNOSTICS
|
||||
}
|
||||
|
||||
@JvmField val PARTIAL_WITH_DIAGNOSTICS = BodyResolveMode()
|
||||
|
||||
@JvmField val PARTIAL_FOR_COMPLETION = BodyResolveMode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,10 +83,11 @@ class ResolveElementCache(
|
||||
},
|
||||
false)
|
||||
|
||||
private class CachedPartialResolve(val bindingContext: BindingContext, file: KtFile) {
|
||||
private class CachedPartialResolve(val bindingContext: BindingContext, file: KtFile, val filter: BindingTraceFilter) {
|
||||
private val modificationStamp: Long? = modificationStamp(file)
|
||||
|
||||
fun isUpToDate(file: KtFile) = modificationStamp == modificationStamp(file)
|
||||
fun isUpToDate(file: KtFile, newFilter: BindingTraceFilter) =
|
||||
modificationStamp == modificationStamp(file) && filter.includesEverythingIn(newFilter)
|
||||
|
||||
private fun modificationStamp(file: KtFile): Long? {
|
||||
return if (!file.isPhysical) // for non-physical file we don't get MODIFICATION_COUNT increased and must reset data on any modification of the file
|
||||
@@ -117,7 +118,7 @@ class ResolveElementCache(
|
||||
= getElementsAdditionalResolve(function, null, BodyResolveMode.FULL)
|
||||
|
||||
fun resolvePrimaryConstructorParametersDefaultValues(ktClass: KtClass): BindingContext {
|
||||
return constructorAdditionalResolve(resolveSession, ktClass, ktClass.getContainingKtFile()).bindingContext
|
||||
return constructorAdditionalResolve(resolveSession, ktClass, ktClass.getContainingKtFile(), BindingTraceFilter.NO_DIAGNOSTICS).bindingContext
|
||||
}
|
||||
|
||||
@Deprecated("Use getElementsAdditionalResolve")
|
||||
@@ -149,7 +150,16 @@ class ResolveElementCache(
|
||||
return bindingContext
|
||||
}
|
||||
|
||||
BodyResolveMode.PARTIAL -> {
|
||||
BodyResolveMode.PARTIAL_FOR_COMPLETION -> {
|
||||
if (resolveElement !is KtDeclaration) {
|
||||
return getElementsAdditionalResolve(resolveElement, null, BodyResolveMode.FULL)
|
||||
}
|
||||
|
||||
// not cached
|
||||
return performElementAdditionalResolve(resolveElement, contextElements, bodyResolveMode).first
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (resolveElement !is KtDeclaration) {
|
||||
return getElementsAdditionalResolve(resolveElement, null, BodyResolveMode.FULL)
|
||||
}
|
||||
@@ -158,18 +168,18 @@ class ResolveElementCache(
|
||||
val statementsToResolve = contextElements!!.map { PartialBodyResolveFilter.findStatementToResolve(it, resolveElement) }.distinct()
|
||||
val partialResolveMap = partialBodyResolveCache.value
|
||||
val cachedResults = statementsToResolve.map { partialResolveMap[it ?: resolveElement] }
|
||||
if (cachedResults.all { it != null && it.isUpToDate(file) }) { // partial resolve is already cached for these statements
|
||||
if (cachedResults.all { it != null && it.isUpToDate(file, bodyResolveMode.bindingTraceFilter) }) { // partial resolve is already cached for these statements
|
||||
return CompositeBindingContext.create(cachedResults.map { it!!.bindingContext }.distinct())
|
||||
}
|
||||
|
||||
val (bindingContext, statementFilter) = performElementAdditionalResolve(resolveElement, contextElements, BodyResolveMode.PARTIAL)
|
||||
val (bindingContext, statementFilter) = performElementAdditionalResolve(resolveElement, contextElements, bodyResolveMode)
|
||||
|
||||
if (statementFilter == StatementFilter.NONE) { // partial resolve is not supported for the given declaration - full resolve performed instead
|
||||
fullResolveMap[resolveElement] = CachedFullResolve(bindingContext, resolveElement)
|
||||
return bindingContext
|
||||
}
|
||||
|
||||
val resolveToCache = CachedPartialResolve(bindingContext, file)
|
||||
val resolveToCache = CachedPartialResolve(bindingContext, file, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
for (statement in (statementFilter as PartialBodyResolveFilter).allStatementsToResolve) {
|
||||
if (!partialResolveMap.containsKey(statement) && bindingContext[BindingContext.PROCESSED, statement] == true) {
|
||||
@@ -182,15 +192,6 @@ class ResolveElementCache(
|
||||
|
||||
return bindingContext
|
||||
}
|
||||
|
||||
BodyResolveMode.PARTIAL_FOR_COMPLETION -> {
|
||||
if (resolveElement !is KtDeclaration) {
|
||||
return getElementsAdditionalResolve(resolveElement, null, BodyResolveMode.FULL)
|
||||
}
|
||||
|
||||
// not cached
|
||||
return performElementAdditionalResolve(resolveElement, contextElements, bodyResolveMode).first
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,17 +312,17 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
val trace: BindingTrace = when (resolveElement) {
|
||||
is KtNamedFunction -> functionAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
|
||||
is KtNamedFunction -> functionAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtAnonymousInitializer -> initializerAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
|
||||
is KtAnonymousInitializer -> initializerAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtSecondaryConstructor -> secondaryConstructorAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
|
||||
is KtSecondaryConstructor -> secondaryConstructorAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtProperty -> propertyAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter())
|
||||
is KtProperty -> propertyAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtSuperTypeList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as KtClassOrObject, file)
|
||||
is KtSuperTypeList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as KtClassOrObject, file, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtInitializerList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as KtEnumEntry, file)
|
||||
is KtInitializerList -> delegationSpecifierAdditionalResolve(resolveSession, resolveElement, resolveElement.getParent() as KtEnumEntry, file, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtImportList -> {
|
||||
val resolver = resolveSession.fileScopeProvider.getImportResolver(resolveElement.getContainingKtFile())
|
||||
@@ -341,9 +342,9 @@ class ResolveElementCache(
|
||||
|
||||
is KtAnnotationEntry -> annotationAdditionalResolve(resolveSession, resolveElement)
|
||||
|
||||
is KtClass -> constructorAdditionalResolve(resolveSession, resolveElement, file)
|
||||
is KtClass -> constructorAdditionalResolve(resolveSession, resolveElement, file, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtTypeAlias -> typealiasAdditionalResolve(resolveSession, resolveElement)
|
||||
is KtTypeAlias -> typealiasAdditionalResolve(resolveSession, resolveElement, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
is KtTypeParameter -> typeParameterAdditionalResolve(resolveSession, resolveElement)
|
||||
|
||||
@@ -353,7 +354,7 @@ class ResolveElementCache(
|
||||
|
||||
else -> {
|
||||
if (resolveElement.getParentOfType<KtPackageDirective>(true) != null) {
|
||||
packageRefAdditionalResolve(resolveSession, resolveElement)
|
||||
packageRefAdditionalResolve(resolveSession, resolveElement, bodyResolveMode.bindingTraceFilter)
|
||||
}
|
||||
else {
|
||||
error("Invalid type of the topmost parent: $resolveElement\n${resolveElement.getElementTextWithContext()}")
|
||||
@@ -368,8 +369,9 @@ class ResolveElementCache(
|
||||
return Pair(trace.bindingContext, statementFilterUsed)
|
||||
}
|
||||
|
||||
private fun packageRefAdditionalResolve(resolveSession: ResolveSession, ktElement: KtElement): BindingTrace {
|
||||
val trace = createDelegatingTrace(ktElement)
|
||||
private fun packageRefAdditionalResolve(resolveSession: ResolveSession, ktElement: KtElement,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(ktElement, bindingTraceFilter)
|
||||
|
||||
if (ktElement is KtSimpleNameExpression) {
|
||||
val header = ktElement.getParentOfType<KtPackageDirective>(true)!!
|
||||
@@ -398,7 +400,7 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun codeFragmentAdditionalResolve(codeFragment: KtCodeFragment, bodyResolveMode: BodyResolveMode): BindingTrace {
|
||||
val trace = createDelegatingTrace(codeFragment)
|
||||
val trace = createDelegatingTrace(codeFragment, bodyResolveMode.bindingTraceFilter)
|
||||
|
||||
val contextResolveMode = if (bodyResolveMode == BodyResolveMode.PARTIAL)
|
||||
BodyResolveMode.PARTIAL_FOR_COMPLETION
|
||||
@@ -456,8 +458,9 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun delegationSpecifierAdditionalResolve(resolveSession: ResolveSession, ktElement: KtElement,
|
||||
classOrObject: KtClassOrObject, file: KtFile): BindingTrace {
|
||||
val trace = createDelegatingTrace(ktElement)
|
||||
classOrObject: KtClassOrObject, file: KtFile,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(ktElement, bindingTraceFilter)
|
||||
val descriptor = resolveSession.resolveToDescriptor(classOrObject) as LazyClassDescriptor
|
||||
|
||||
// Activate resolving of supertypes
|
||||
@@ -475,8 +478,10 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun propertyAdditionalResolve(resolveSession: ResolveSession, property: KtProperty,
|
||||
file: KtFile, statementFilter: StatementFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(property)
|
||||
file: KtFile,
|
||||
statementFilter: StatementFilter,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(property, bindingTraceFilter)
|
||||
|
||||
val bodyResolver = createBodyResolver(resolveSession, trace, file, statementFilter)
|
||||
val descriptor = resolveSession.resolveToDescriptor(property) as PropertyDescriptor
|
||||
@@ -501,8 +506,9 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun functionAdditionalResolve(resolveSession: ResolveSession, namedFunction: KtNamedFunction, file: KtFile,
|
||||
statementFilter: StatementFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(namedFunction)
|
||||
statementFilter: StatementFilter,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(namedFunction, bindingTraceFilter)
|
||||
|
||||
val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(namedFunction)
|
||||
val functionDescriptor = resolveSession.resolveToDescriptor(namedFunction) as FunctionDescriptor
|
||||
@@ -517,8 +523,9 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun secondaryConstructorAdditionalResolve(resolveSession: ResolveSession, constructor: KtSecondaryConstructor,
|
||||
file: KtFile, statementFilter: StatementFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(constructor)
|
||||
file: KtFile, statementFilter: StatementFilter,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(constructor, bindingTraceFilter)
|
||||
|
||||
val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(constructor)
|
||||
val constructorDescriptor = resolveSession.resolveToDescriptor(constructor) as ClassConstructorDescriptor
|
||||
@@ -532,8 +539,8 @@ class ResolveElementCache(
|
||||
return trace
|
||||
}
|
||||
|
||||
private fun constructorAdditionalResolve(resolveSession: ResolveSession, klass: KtClass, file: KtFile): BindingTrace {
|
||||
val trace = createDelegatingTrace(klass)
|
||||
private fun constructorAdditionalResolve(resolveSession: ResolveSession, klass: KtClass, file: KtFile, filter : BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(klass, filter)
|
||||
val scope = resolveSession.declarationScopeProvider.getResolutionScopeForDeclaration(klass)
|
||||
|
||||
val classDescriptor = resolveSession.resolveToDescriptor(klass) as ClassDescriptor
|
||||
@@ -547,8 +554,9 @@ class ResolveElementCache(
|
||||
return trace
|
||||
}
|
||||
|
||||
private fun typealiasAdditionalResolve(resolveSession: ResolveSession, typeAlias: KtTypeAlias): BindingTrace {
|
||||
val trace = createDelegatingTrace(typeAlias)
|
||||
private fun typealiasAdditionalResolve(resolveSession: ResolveSession, typeAlias: KtTypeAlias,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(typeAlias, bindingTraceFilter)
|
||||
val typeAliasDescriptor = resolveSession.resolveToDescriptor(typeAlias)
|
||||
ForceResolveUtil.forceResolveAllContents(typeAliasDescriptor)
|
||||
forceResolveAnnotationsInside(typeAlias)
|
||||
@@ -556,8 +564,9 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
private fun initializerAdditionalResolve(resolveSession: ResolveSession, anonymousInitializer: KtAnonymousInitializer,
|
||||
file: KtFile, statementFilter: StatementFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(anonymousInitializer)
|
||||
file: KtFile, statementFilter: StatementFilter,
|
||||
bindingTraceFilter: BindingTraceFilter): BindingTrace {
|
||||
val trace = createDelegatingTrace(anonymousInitializer, bindingTraceFilter)
|
||||
|
||||
val classOrObjectDescriptor = resolveSession.resolveToDescriptor(anonymousInitializer.containingDeclaration) as LazyClassDescriptor
|
||||
|
||||
@@ -595,9 +604,9 @@ class ResolveElementCache(
|
||||
}
|
||||
|
||||
// All additional resolve should be done to separate trace
|
||||
private fun createDelegatingTrace(resolveElement: KtElement): BindingTrace {
|
||||
private fun createDelegatingTrace(resolveElement: KtElement, filter: BindingTraceFilter): BindingTrace {
|
||||
return resolveSession.storageManager.createSafeTrace(
|
||||
DelegatingBindingTrace(resolveSession.bindingContext, "trace to resolve element", resolveElement))
|
||||
DelegatingBindingTrace(resolveSession.bindingContext, "trace to resolve element", resolveElement, filter))
|
||||
}
|
||||
|
||||
private class BodyResolveContextForLazy(
|
||||
|
||||
@@ -70,7 +70,7 @@ abstract class AbstractKtReference<T : KtElement>(element: T)
|
||||
override fun isSoft(): Boolean = false
|
||||
|
||||
private fun resolveToPsiElements(): Collection<PsiElement> {
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
return resolveToPsiElements(bindingContext, getTargetDescriptors(bindingContext))
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ abstract class KotlinIntentionActionFactoryWithDelegate<E : KtElement, D : Any>
|
||||
if (!diagnosticElement.isValid || !element.isValid) return@factory null
|
||||
|
||||
val currentDiagnostic =
|
||||
element.analyze(BodyResolveMode.PARTIAL)
|
||||
element.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
.diagnostics
|
||||
.forElement(diagnosticElement)
|
||||
.firstOrNull { DefaultErrorMessages.render(it) == diagnosticMessage } ?: return@factory null
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ class CreateTypeParameterFromUsageFix(
|
||||
}
|
||||
}
|
||||
is KtCallElement -> {
|
||||
if (it.analyze(BodyResolveMode.PARTIAL).diagnostics.forElement(it.calleeExpression!!).any {
|
||||
if (it.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS).diagnostics.forElement(it.calleeExpression!!).any {
|
||||
it.factory in Errors.TYPE_INFERENCE_ERRORS
|
||||
}) {
|
||||
callsToExplicateArguments += it
|
||||
|
||||
@@ -303,7 +303,7 @@ class KotlinInlineValHandler : InlineActionHandler() {
|
||||
resolutionFacade: ResolutionFacade
|
||||
): Boolean {
|
||||
val functionLiteral = lambdaExpression.functionLiteral
|
||||
val context = resolutionFacade.analyze(lambdaExpression, BodyResolveMode.PARTIAL)
|
||||
val context = resolutionFacade.analyze(lambdaExpression, BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
return context.diagnostics.any { diagnostic ->
|
||||
val factory = diagnostic.factory
|
||||
val element = diagnostic.psiElement
|
||||
|
||||
@@ -784,7 +784,7 @@ fun getQualifiedTypeArgumentList(initializer: KtExpression): KtTypeArgumentList?
|
||||
}
|
||||
|
||||
fun addTypeArgumentsIfNeeded(expression: KtExpression, typeArgumentList: KtTypeArgumentList) {
|
||||
val context = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
val context = expression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS)
|
||||
val call = expression.getCallWithAssert(context)
|
||||
val callElement = call.callElement as? KtCallExpression ?: return
|
||||
if (call.typeArgumentList != null) return
|
||||
|
||||
Reference in New Issue
Block a user