Compare commits

...

3 Commits

Author SHA1 Message Date
Vladimir Dolzhenko
3c447d7fd1 Add checkCanceled on common for autocompletion and highlighting resolve path 2020-03-04 08:56:30 +01:00
Vladimir Dolzhenko
256e8bd89b Enable CancellationCheck usage for 193
Relates to #KT-36891
2020-03-04 08:56:28 +01:00
Vladimir Dolzhenko
dacd1c6ed6 Perform tryLock-and-checkCanceled on waiting lock in LockBasedStorageManager and PerFileAnalysisCache 2020-03-04 08:56:27 +01:00
15 changed files with 208 additions and 163 deletions

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.storage.ExceptionTracker
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
@@ -85,7 +86,9 @@ class MutableModuleContextImpl(
fun GlobalContext(debugName: String): GlobalContextImpl {
val tracker = ExceptionTracker()
return GlobalContextImpl(LockBasedStorageManager.createWithExceptionHandling(debugName, tracker), tracker)
return GlobalContextImpl(LockBasedStorageManager.createWithExceptionHandling(debugName, tracker) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
}, tracker)
}
fun ProjectContext(project: Project, debugName: String): ProjectContext = ProjectContextImpl(project, GlobalContext(debugName))

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Maps;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Queue;
@@ -196,6 +197,8 @@ public class BodyResolver {
Set<ConstructorDescriptor> visitedInCurrentChain = new HashSet<>();
ConstructorDescriptor currentConstructorDescriptor = constructorDescriptor;
while (true) {
ProgressManager.checkCanceled();
visitedInCurrentChain.add(currentConstructorDescriptor);
ConstructorDescriptor delegatedConstructorDescriptor = getDelegatedConstructor(currentConstructorDescriptor);
if (delegatedConstructorDescriptor == null) break;
@@ -267,6 +270,8 @@ public class BodyResolver {
@NotNull LexicalScope scopeForConstructorResolution,
@NotNull LexicalScope scopeForMemberResolution
) {
ProgressManager.checkCanceled();
LexicalScope scopeForConstructor =
primaryConstructor == null
? null
@@ -399,6 +404,8 @@ public class BodyResolver {
}
for (KtSuperTypeListEntry delegationSpecifier : ktClass.getSuperTypeListEntries()) {
ProgressManager.checkCanceled();
delegationSpecifier.accept(visitor);
}
@@ -657,6 +664,8 @@ public class BodyResolver {
@NotNull KtAnonymousInitializer anonymousInitializer,
@NotNull ClassDescriptorWithResolutionScopes classDescriptor
) {
ProgressManager.checkCanceled();
LexicalScope scopeForInitializers = classDescriptor.getScopeForInitializerResolution();
KtExpression body = anonymousInitializer.getBody();
if (body != null) {
@@ -935,6 +944,8 @@ public class BodyResolver {
// Creates wrapper scope for header resolution if necessary (see resolveSecondaryConstructorBody)
@Nullable Function1<LexicalScope, LexicalScope> headerScopeFactory
) {
ProgressManager.checkCanceled();
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace, languageVersionSettings);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace, overloadChecker);
List<KtParameter> valueParameters = function.getValueParameters();

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.resolve;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -270,6 +271,7 @@ public class ModifiersChecker {
missingSupertypesResolver
);
for (DeclarationChecker checker : declarationCheckers) {
ProgressManager.checkCanceled();
checker.check(declaration, descriptor, context);
}
OperatorModifierChecker.INSTANCE.check(declaration, descriptor, trace, languageVersionSettings);

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.lazy;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
@@ -70,6 +71,8 @@ public class ForceResolveUtil {
}
private static void doForceResolveAllContents(Object object) {
ProgressManager.checkCanceled();
if (object instanceof LazyEntity) {
LazyEntity lazyEntity = (LazyEntity) object;
lazyEntity.forceResolveAllContents();

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.types.expressions;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -303,6 +304,7 @@ public class ExpressionTypingServices {
boolean isFirstStatement = true;
for (Iterator<? extends KtElement> iterator = block.iterator(); iterator.hasNext(); ) {
ProgressManager.checkCanceled();
// Use filtering trace to keep effect system cache only for one statement
AbstractFilteringTrace traceForSingleStatement = new EffectsFilteringTrace(context.trace);

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.types.expressions;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.IndexNotReadyException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -159,6 +160,7 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
@NotNull
private KotlinTypeInfo getTypeInfo(@NotNull KtExpression expression, ExpressionTypingContext context, KtVisitor<KotlinTypeInfo, ExpressionTypingContext> visitor) {
ProgressManager.checkCanceled();
return typeInfoPerfCounter.time(() -> {
try {
KotlinTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.asJava.classes
import com.intellij.openapi.progress.ProgressManager
import com.intellij.psi.*
import com.intellij.psi.impl.light.LightMethodBuilder
import com.intellij.psi.impl.light.LightModifierList
@@ -174,6 +175,7 @@ internal class UltraLightMembersCreator(
numberOfDefaultParametersToAdd: Int = -1,
methodIndex: Int
): KtLightMethod {
ProgressManager.checkCanceled()
val isConstructor = ktFunction is KtConstructor<*>
val name =
if (isConstructor) containingClass.name

View File

@@ -29,8 +29,6 @@ import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockBasedStorageManager implements StorageManager {
private static final String PACKAGE_NAME = StringsKt.substringBeforeLast(LockBasedStorageManager.class.getCanonicalName(), ".", "");
@@ -55,7 +53,7 @@ public class LockBasedStorageManager implements StorageManager {
RuntimeException handleException(@NotNull Throwable throwable);
}
public static final StorageManager NO_LOCKS = new LockBasedStorageManager("NO_LOCKS", ExceptionHandlingStrategy.THROW, NoLock.INSTANCE) {
public static final StorageManager NO_LOCKS = new LockBasedStorageManager("NO_LOCKS", ExceptionHandlingStrategy.THROW, NoLockBlock.INSTANCE) {
@NotNull
@Override
protected <T> RecursionDetectedResult<T> recursionDetectedDefault() {
@@ -64,26 +62,38 @@ public class LockBasedStorageManager implements StorageManager {
};
@NotNull
public static LockBasedStorageManager createWithExceptionHandling(@NotNull String debugText, @NotNull ExceptionHandlingStrategy exceptionHandlingStrategy) {
return new LockBasedStorageManager(debugText, exceptionHandlingStrategy, new ReentrantLock());
public static LockBasedStorageManager createWithExceptionHandling(
@NotNull String debugText,
@NotNull ExceptionHandlingStrategy exceptionHandlingStrategy
) {
return new LockBasedStorageManager(debugText, exceptionHandlingStrategy, new SimpleLock());
}
protected final Lock lock;
@NotNull
public static LockBasedStorageManager createWithExceptionHandling(
@NotNull String debugText,
@NotNull ExceptionHandlingStrategy exceptionHandlingStrategy,
@NotNull Function0 checkCancelled
) {
return new LockBasedStorageManager(debugText, exceptionHandlingStrategy, new CancellableLock(checkCancelled));
}
private final LockBlock lockBlock;
private final ExceptionHandlingStrategy exceptionHandlingStrategy;
private final String debugText;
private LockBasedStorageManager(
@NotNull String debugText,
@NotNull ExceptionHandlingStrategy exceptionHandlingStrategy,
@NotNull Lock lock
@NotNull LockBlock lockBlock
) {
this.lock = lock;
this.lockBlock = lockBlock;
this.exceptionHandlingStrategy = exceptionHandlingStrategy;
this.debugText = debugText;
}
public LockBasedStorageManager(String debugText) {
this(debugText, ExceptionHandlingStrategy.THROW, new ReentrantLock());
this(debugText, ExceptionHandlingStrategy.THROW, new SimpleLock());
}
@Override
@@ -94,7 +104,7 @@ public class LockBasedStorageManager implements StorageManager {
public LockBasedStorageManager replaceExceptionHandling(
@NotNull String debugText, @NotNull ExceptionHandlingStrategy exceptionHandlingStrategy
) {
return new LockBasedStorageManager(debugText, exceptionHandlingStrategy, lock);
return new LockBasedStorageManager(debugText, exceptionHandlingStrategy, lockBlock);
}
@NotNull
@@ -238,17 +248,22 @@ public class LockBasedStorageManager implements StorageManager {
}
@Override
public <T> T compute(@NotNull Function0<? extends T> computable) {
lock.lock();
try {
return computable.invoke();
}
catch (Throwable throwable) {
throw exceptionHandlingStrategy.handleException(throwable);
}
finally {
lock.unlock();
}
public <T> T compute(@NotNull final Function0<? extends T> computable) {
return guarded(new Function0<T>() {
@Override
public T invoke() {
try {
return computable.invoke();
}
catch (Throwable throwable) {
throw exceptionHandlingStrategy.handleException(throwable);
}
}
});
}
protected final <T> T guarded(@NotNull Function0<? extends T> computable) {
return lockBlock.guarded(computable);
}
@NotNull
@@ -333,33 +348,34 @@ public class LockBasedStorageManager implements StorageManager {
Object _value = value;
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
storageManager.lock.lock();
try {
_value = value;
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
return storageManager.guarded(new Function0<T>() {
@Override
public T invoke() {
Object _value = value;
if (!(_value instanceof NotValue)) return WrappedValues.unescapeThrowable(_value);
if (_value == NotValue.COMPUTING) {
value = NotValue.RECURSION_WAS_DETECTED;
RecursionDetectedResult<T> result = recursionDetected(/*firstTime = */ true);
if (!result.isFallThrough()) {
return result.getValue();
if (_value == NotValue.COMPUTING) {
value = NotValue.RECURSION_WAS_DETECTED;
RecursionDetectedResult<T> result = recursionDetected(/*firstTime = */ true);
if (!result.isFallThrough()) {
return result.getValue();
}
}
}
if (_value == NotValue.RECURSION_WAS_DETECTED) {
RecursionDetectedResult<T> result = recursionDetected(/*firstTime = */ false);
if (!result.isFallThrough()) {
return result.getValue();
if (_value == NotValue.RECURSION_WAS_DETECTED) {
RecursionDetectedResult<T> result = recursionDetected(/*firstTime = */ false);
if (!result.isFallThrough()) {
return result.getValue();
}
}
}
value = NotValue.COMPUTING;
try {
T typedValue = computable.invoke();
value = NotValue.COMPUTING;
try {
T typedValue = computable.invoke();
// Don't publish computed value till post compute is finished as it may cause a race condition
// if post compute modifies value internals.
postCompute(typedValue);
// Don't publish computed value till post compute is finished as it may cause a race condition
// if post compute modifies value internals.
postCompute(typedValue);
value = typedValue;
computable = null;
@@ -372,16 +388,14 @@ public class LockBasedStorageManager implements StorageManager {
throw (RuntimeException)throwable;
}
if (value == NotValue.COMPUTING) {
// Store only if it's a genuine result, not something thrown through recursionDetected()
value = WrappedValues.escapeThrowable(throwable);
if (value == NotValue.COMPUTING) {
// Store only if it's a genuine result, not something thrown through recursionDetected()
value = WrappedValues.escapeThrowable(throwable);
}
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
}
finally {
storageManager.lock.unlock();
}
});
}
/**
@@ -498,56 +512,55 @@ public class LockBasedStorageManager implements StorageManager {
@Override
@Nullable
public V invoke(K input) {
public V invoke(final K input) {
Object value = cache.get(input);
if (value != null && value != NotValue.COMPUTING) return WrappedValues.unescapeExceptionOrNull(value);
storageManager.lock.lock();
try {
value = cache.get(input);
if (value == NotValue.COMPUTING) {
throw recursionDetected(input);
}
if (value != null) return WrappedValues.unescapeExceptionOrNull(value);
AssertionError error = null;
try {
cache.put(input, NotValue.COMPUTING);
V typedValue = compute.invoke(input);
Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue));
// This code effectively asserts that oldValue is null
// The trickery is here because below we catch all exceptions thrown here, and this is the only exception that shouldn't be stored
// A seemingly obvious way to come about this case would be to declare a special exception class, but the problem is that
// one memoized function is likely to (indirectly) call another, and if this second one throws this exception, we are screwed
if (oldValue != NotValue.COMPUTING) {
error = raceCondition(input, oldValue);
throw error;
return storageManager.guarded(new Function0<V>() {
@Override
public V invoke() {
Object value = cache.get(input);
if (value == NotValue.COMPUTING) {
throw recursionDetected(input);
}
if (value != null) return WrappedValues.unescapeExceptionOrNull(value);
return typedValue;
}
catch (Throwable throwable) {
if (ExceptionUtilsKt.isProcessCanceledException(throwable)) {
cache.remove(input);
//noinspection ConstantConditions
throw (RuntimeException)throwable;
AssertionError error = null;
try {
cache.put(input, NotValue.COMPUTING);
V typedValue = compute.invoke(input);
Object oldValue = cache.put(input, WrappedValues.escapeNull(typedValue));
// This code effectively asserts that oldValue is null
// The trickery is here because below we catch all exceptions thrown here, and this is the only exception that shouldn't be stored
// A seemingly obvious way to come about this case would be to declare a special exception class, but the problem is that
// one memoized function is likely to (indirectly) call another, and if this second one throws this exception, we are screwed
if (oldValue != NotValue.COMPUTING) {
error = raceCondition(input, oldValue);
throw error;
}
return typedValue;
}
if (throwable == error) {
catch (Throwable throwable) {
if (ExceptionUtilsKt.isProcessCanceledException(throwable)) {
cache.remove(input);
//noinspection ConstantConditions
throw (RuntimeException) throwable;
}
if (throwable == error) {
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
Object oldValue = cache.put(input, WrappedValues.escapeThrowable(throwable));
if (oldValue != NotValue.COMPUTING) {
throw raceCondition(input, oldValue);
}
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
Object oldValue = cache.put(input, WrappedValues.escapeThrowable(throwable));
if (oldValue != NotValue.COMPUTING) {
throw raceCondition(input, oldValue);
}
throw storageManager.exceptionHandlingStrategy.handleException(throwable);
}
}
finally {
storageManager.lock.unlock();
}
});
}
@NotNull

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2010-2015 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.storage;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/*package*/ class NoLock implements Lock {
public static final Lock INSTANCE = new NoLock();
private NoLock() {
}
@Override
public void lock() {
// Do nothing
}
@Override
public void unlock() {
// Do nothing
}
@Override
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException("Should not be called");
}
@Override
public boolean tryLock() {
throw new UnsupportedOperationException("Should not be called");
}
@Override
public boolean tryLock(long time, @NotNull TimeUnit unit) throws InterruptedException {
throw new UnsupportedOperationException("Should not be called");
}
@NotNull
@Override
public Condition newCondition() {
throw new UnsupportedOperationException("Should not be called");
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.storage
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
private const val CHECK_CANCELLATION_PERIOD_MS: Long = 50
interface LockBlock {
fun <T> guarded(computable: () -> T): T
}
object NoLockBlock : LockBlock {
override fun <Any> guarded(computable: () -> Any): Any {
return computable()
}
}
class SimpleLock(val lock: Any = Object()) : LockBlock {
override fun <T> guarded(computable: () -> T): T =
// Use `synchronized` as dead lock case will be handled by JVM and would be immediately visible rather with ReentrantLock
synchronized(lock) {
computable()
}
}
class CancellableLock(val lock: Lock, val checkCancelled: () -> Unit) : LockBlock {
constructor(checkCancelled: () -> Unit) : this(checkCancelled = checkCancelled, lock = ReentrantLock())
override fun <T> guarded(computable: () -> T): T {
while (!lock.tryLock(CHECK_CANCELLATION_PERIOD_MS, TimeUnit.MILLISECONDS)) {
//ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
checkCancelled()
}
try {
return computable()
} finally {
lock.unlock()
}
}
}

View File

@@ -29,6 +29,10 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.trackers.clearInBlockModifications
import org.jetbrains.kotlin.idea.caches.trackers.inBlockModifications
import org.jetbrains.kotlin.idea.project.*
import org.jetbrains.kotlin.idea.project.IdeaModuleStructureOracle
import org.jetbrains.kotlin.idea.project.findAnalyzerServices
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.*
@@ -36,6 +40,7 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.diagnostics.DiagnosticsElementsCache
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.storage.CancellableLock
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
@@ -47,6 +52,9 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone
private val resolveSession = componentProvider.get<ResolveSession>()
private val codeFragmentAnalyzer = componentProvider.get<CodeFragmentAnalyzer>()
private val bodyResolveCache = componentProvider.get<BodyResolveCache>()
private val lock = CancellableLock {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
}
private val cache = HashMap<PsiElement, AnalysisResult>()
private var fileResult: AnalysisResult? = null
@@ -56,25 +64,23 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone
val analyzableParent = KotlinResolveDataProvider.findAnalyzableParent(element)
return synchronized(this) {
ProgressIndicatorProvider.checkCanceled()
return lock.guarded {
// step 1: perform incremental analysis IF it is applicable
getIncrementalAnalysisResult()?.let { return it }
getIncrementalAnalysisResult()?.let { return@guarded it }
// cache does not contain AnalysisResult per each kt/psi element
// instead it looks up analysis for its parents - see lookUp(analyzableElement)
// step 2: return result if it is cached
lookUp(analyzableParent)?.let {
return@synchronized it
return@guarded it
}
// step 3: perform analyze of analyzableParent as nothing has been cached yet
val result = analyze(analyzableParent)
cache[analyzableParent] = result
return@synchronized result
return@guarded result
}
}

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.util.CachedValueProvider
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationList
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.CompositeBindingContext
import org.jetbrains.kotlin.storage.CancellableLock
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class ProjectResolutionFacade(
@@ -46,6 +48,10 @@ internal class ProjectResolutionFacade(
private val cachedResolverForProject: ResolverForProject<IdeaModuleInfo>
get() = globalContext.storageManager.compute { cachedValue.value }
private val analysisResultsLock = CancellableLock {
ProgressManager.checkCanceled()
}
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue(
{
val resolverForProject = cachedResolverForProject
@@ -117,7 +123,7 @@ internal class ProjectResolutionFacade(
internal fun getAnalysisResultsForElements(elements: Collection<KtElement>): AnalysisResult {
assert(elements.isNotEmpty()) { "elements collection should not be empty" }
val slruCache = synchronized(analysisResults) {
val slruCache = analysisResultsLock.guarded {
analysisResults.value!!
}
val results = elements.map {

View File

@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.idea.caches.resolve.util
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.context.GlobalContextImpl
import org.jetbrains.kotlin.idea.caches.resolve.PlatformAnalysisSettings
import org.jetbrains.kotlin.idea.project.useCompositeAnalysis
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.storage.ExceptionTracker
import org.jetbrains.kotlin.storage.LockBasedStorageManager
@@ -23,7 +23,9 @@ private fun GlobalContextImpl.contextWithCompositeExceptionTracker(debugName: St
private fun GlobalContextImpl.contextWithNewLockAndCompositeExceptionTracker(debugName: String): GlobalContextImpl {
val newExceptionTracker = CompositeExceptionTracker(this.exceptionTracker)
return GlobalContextImpl(
LockBasedStorageManager.createWithExceptionHandling(debugName, newExceptionTracker),
LockBasedStorageManager.createWithExceptionHandling(debugName, newExceptionTracker) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
},
newExceptionTracker
)
}

View File

@@ -18,6 +18,10 @@ package org.jetbrains.kotlin.idea.util.application
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressIndicatorProvider
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.impl.CancellationCheck
import com.intellij.openapi.project.Project
fun <T> runReadAction(action: () -> T): T {
@@ -43,4 +47,4 @@ fun <T> Project.executeCommand(name: String, groupId: Any? = null, command: () -
return result as T
}
fun <T> runWithCancellationCheck(block: () -> T): T = block()
fun <T> runWithCancellationCheck(block: () -> T): T = CancellationCheck.runWithCancellationCheck(block)

View File

@@ -17,6 +17,7 @@ import com.intellij.codeInspection.ex.EntryPointsManagerBase
import com.intellij.codeInspection.ex.EntryPointsManagerImpl
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiClass
@@ -201,6 +202,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return namedDeclarationVisitor(fun(declaration) {
ProgressManager.checkCanceled()
val message = declaration.describe()?.let { "$it is never used" } ?: return
if (!ProjectRootsUtil.isInProjectSource(declaration)) return
@@ -321,6 +323,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
private val KtNamedDeclaration.isObjectOrEnum: Boolean get() = this is KtObjectDeclaration || this is KtClass && isEnum()
private fun checkReference(ref: PsiReference, declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor?): Boolean {
ProgressManager.checkCanceled()
if (declaration.isAncestor(ref.element)) return true // usages inside element's declaration are not counted
if (ref.element.parent is KtValueArgumentName) return true // usage of parameter in form of named argument is not counted