From d8b0c7aaec21cac9cb665d04413d40c379994db7 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 26 Sep 2016 12:48:46 +0200 Subject: [PATCH] Binding trace filtering: do not calculate diagnostics if no one is going to query them --- .../kotlin/codegen/state/GenerationState.kt | 7 +- .../cfg/ControlFlowInformationProvider.kt | 8 +- .../kotlin/cfg/pseudocode/PseudocodeUtil.java | 5 + .../kotlin/diagnostics/DiagnosticSink.java | 11 +++ .../kotlin/resolve/BindingTraceContext.java | 32 ++++-- .../kotlin/resolve/BindingTraceFilter.kt | 31 ++++++ .../kotlin/resolve/DelegatingBindingTrace.kt | 24 +++-- .../resolve/ObservableBindingTrace.java | 6 +- .../kotlin/resolve/TemporaryBindingTrace.java | 16 ++- .../kotlin/resolve/calls/CallCompleter.kt | 8 +- .../kotlin/resolve/calls/CallResolver.java | 2 +- .../MutableDiagnosticsWithSuppression.kt | 6 +- .../kotlin/resolve/lazy/FileScopeFactory.kt | 2 +- .../LockBasedLazyResolveStorageManager.kt | 2 + .../BasicExpressionTypingVisitor.java | 18 ++-- .../asJava/builder/LightClassDataProvider.kt | 3 +- .../kotlin/test/KotlinTestUtils.java | 10 ++ .../kotlin/resolve/lazy/BodyResolveMode.kt | 21 +++- .../idea/project/ResolveElementCache.kt | 97 ++++++++++--------- .../kotlin/idea/references/KtReference.kt | 2 +- ...otlinIntentionActionFactoryWithDelegate.kt | 2 +- .../CreateTypeParameterFromUsageFix.kt | 2 +- .../inline/KotlinInlineValHandler.kt | 2 +- .../idea/refactoring/kotlinRefactoringUtil.kt | 2 +- 24 files changed, 230 insertions(+), 89 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceFilter.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index fe974c52dc6..7c647e6bb5d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -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, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index deb53e970d5..ebb5ca63a01 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -86,13 +86,17 @@ class ControlFlowInformationProvider private constructor( markUninitializedVariables() - markUnusedVariables() + if (trace.wantsDiagnostics()) { + markUnusedVariables() + } markStatements() markUnusedExpressions() - checkIfExpressions() + if (trace.wantsDiagnostics()) { + checkIfExpressions() + } checkWhenExpressions() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java index e9fc6f86124..eca8b70a581 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java index 44c3f7d3d71..073a1e0b58d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/DiagnosticSink.java @@ -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(); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java index ddb3c3dc1aa..a4653acda65 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceContext.java @@ -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 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceFilter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceFilter.kt new file mode 100644 index 00000000000..bc9a9713f45 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingTraceFilter.kt @@ -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 + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt index f2101b875ac..e36444fcea2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatingBindingTrace.kt @@ -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 get(slice: ReadOnlySlice, 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 } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java index 0c0d2b19a4b..27ecd8a7359 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ObservableBindingTrace.java @@ -91,5 +91,9 @@ public class ObservableBindingTrace implements BindingTrace { handlers = handlers.plus(slice, handler); return this; } - + + @Override + public boolean wantsDiagnostics() { + return originalTrace.wantsDiagnostics(); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java index 994e68f8287..23df6ed01e8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TemporaryBindingTrace.java @@ -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(); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index f3e8704f7d2..a6873e46da1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -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) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 73bfb7a9ad7..e8cb54df785 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt index 12b64f4ed9f..1db5dec54b2 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/diagnostics/MutableDiagnosticsWithSuppression.kt @@ -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 = diagnosticList + fun getOwnDiagnostics(): List { + return diagnosticList + } fun report(diagnostic: Diagnostic) { diagnosticList.add(diagnostic) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt index 94228159996..93f8ba45134 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/FileScopeFactory.kt @@ -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 Collection.concat(other: Collection?) = if (other == null || other.isEmpty()) this else this + other diff --git a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt index c93b8ae3de3..d4fc6674744 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/storage/LockBasedLazyResolveStorageManager.kt @@ -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() } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index 4694688f947..2b7c4d4baec 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -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); + } } } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt index 1bbb83f2e11..298e7e0c3eb 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/builder/LightClassDataProvider.kt @@ -99,7 +99,8 @@ abstract class LightClassDataProvider( context.bindingContext, files.toMutableList(), CompilerConfiguration.EMPTY, - generateClassFilter + generateClassFilter, + wantsDiagnostics = false ) state.beforeCompile() diff --git a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java index ba9c88b845a..90622f8c135 100644 --- a/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java +++ b/compiler/tests-common/org/jetbrains/kotlin/test/KotlinTestUtils.java @@ -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 diff --git a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt index d67337bec75..f59b607fe83 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/resolve/lazy/BodyResolveMode.kt @@ -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() + } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 6f2701bbfcf..7d5b2d505fe 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -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(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(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( diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/KtReference.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/KtReference.kt index 96f5abaf105..29cf34f8924 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/KtReference.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/KtReference.kt @@ -70,7 +70,7 @@ abstract class AbstractKtReference(element: T) override fun isSoft(): Boolean = false private fun resolveToPsiElements(): Collection { - val bindingContext = expression.analyze(BodyResolveMode.PARTIAL) + val bindingContext = expression.analyze(BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS) return resolveToPsiElements(bindingContext, getTargetDescriptors(bindingContext)) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinIntentionActionFactoryWithDelegate.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinIntentionActionFactoryWithDelegate.kt index 78b14bce8f8..0cd63de8f83 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinIntentionActionFactoryWithDelegate.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinIntentionActionFactoryWithDelegate.kt @@ -76,7 +76,7 @@ abstract class KotlinIntentionActionFactoryWithDelegate 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 diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeParameter/CreateTypeParameterFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeParameter/CreateTypeParameterFromUsageFix.kt index 81f3fb148cf..0f3223417bf 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeParameter/CreateTypeParameterFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createTypeParameter/CreateTypeParameterFromUsageFix.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt index 232e901760e..48691e74345 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/inline/KotlinInlineValHandler.kt @@ -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 diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt index 18879baeec5..07f266775ca 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt @@ -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