Fix severe freezes because of long lint checks on large files (KT-13071)

- Run lint analyze under indicator with write action priority. Otherwise ProgressManager.checkCanceled() checks doesn't work
 - Move ProgressManager.checkCanceled() up or they are not called in large files without lint warnings

 #KT-13071 Fixed
This commit is contained in:
Nikolay Krasko
2016-09-16 18:17:17 +03:00
committed by Nikolay Krasko
parent 131e77927a
commit d96863da93
2 changed files with 12 additions and 9 deletions
@@ -30,6 +30,7 @@ import com.intellij.openapi.keymap.KeymapManager;
import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*; import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
@@ -150,11 +151,16 @@ public class AndroidLintExternalAnnotator extends ExternalAnnotator<State, State
} }
List<VirtualFile> files = Collections.singletonList(mainFile); List<VirtualFile> files = Collections.singletonList(mainFile);
LintRequest request = new IntellijLintRequest(client, project, files, final LintRequest request = new IntellijLintRequest(
Collections.singletonList(state.getModule()), true /* incremental */); client, project, files, Collections.singletonList(state.getModule()), true /* incremental */);
request.setScope(scope); request.setScope(scope);
lint.analyze(request); ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(new Runnable() {
@Override
public void run() {
lint.analyze(request);
}
});
} }
finally { finally {
Disposer.dispose(client); Disposer.dispose(client);
@@ -18,7 +18,6 @@ package org.jetbrains.uast.check
import com.android.tools.klint.detector.api.Issue import com.android.tools.klint.detector.api.Issue
import com.android.tools.klint.detector.api.JavaContext import com.android.tools.klint.detector.api.JavaContext
import com.android.tools.klint.detector.api.Location import com.android.tools.klint.detector.api.Location
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
@@ -84,9 +83,9 @@ object UastChecker {
val visitor = object : AbstractUastVisitor() { val visitor = object : AbstractUastVisitor() {
override fun visitCallExpression(node: UCallExpression): Boolean { override fun visitCallExpression(node: UCallExpression): Boolean {
ProgressManager.checkCanceled()
if (applicableFunctionNames.isNotEmpty()) { if (applicableFunctionNames.isNotEmpty()) {
if (node.kind == FUNCTION_CALL && node.functionName in applicableFunctionNames) { if (node.kind == FUNCTION_CALL && node.functionName in applicableFunctionNames) {
ProgressManager.checkCanceled()
scanner.visitCall(context, node) scanner.visitCall(context, node)
} }
} }
@@ -95,7 +94,6 @@ object UastChecker {
if (node.kind == CONSTRUCTOR_CALL) { if (node.kind == CONSTRUCTOR_CALL) {
node.resolve(context)?.let { constructor -> node.resolve(context)?.let { constructor ->
if (constructor.getContainingClass()?.fqName in applicableConstructorTypes) { if (constructor.getContainingClass()?.fqName in applicableConstructorTypes) {
ProgressManager.checkCanceled()
scanner.visitConstructor(context, node, constructor) scanner.visitConstructor(context, node, constructor)
} }
} }
@@ -106,9 +104,9 @@ object UastChecker {
} }
override fun visitClass(node: UClass): Boolean { override fun visitClass(node: UClass): Boolean {
ProgressManager.checkCanceled()
if (applicableSuperClasses.isNotEmpty()) { if (applicableSuperClasses.isNotEmpty()) {
if (applicableSuperClasses.any { node.isSubclassOf(it) }) { if (applicableSuperClasses.any { node.isSubclassOf(it) }) {
ProgressManager.checkCanceled()
scanner.visitClass(context, node) scanner.visitClass(context, node)
} }
} }
@@ -117,9 +115,8 @@ object UastChecker {
} }
override fun visitQualifiedExpression(node: UQualifiedExpression): Boolean { override fun visitQualifiedExpression(node: UQualifiedExpression): Boolean {
ProgressManager.checkCanceled()
if (appliesToResourcesRefs && node.receiver is UQualifiedExpression) { if (appliesToResourcesRefs && node.receiver is UQualifiedExpression) {
ProgressManager.checkCanceled()
val parentQualifiedExpr = node.receiver as UQualifiedExpression val parentQualifiedExpr = node.receiver as UQualifiedExpression
val resourceName = node.selector val resourceName = node.selector
val resourceType = parentQualifiedExpr.selector val resourceType = parentQualifiedExpr.selector