Skip to content

[perf] optimize EDT SdkRunConfig.getState #8149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions flutter-idea/src/io/flutter/run/MainFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
package io.flutter.run;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.BaseProjectDirectories;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
Expand Down Expand Up @@ -79,11 +79,15 @@ public boolean hasFlutterImports() {
* If there is an error, {@link Result#canLaunch} will return false and the error is available via {@link Result#getError}
*/
@NotNull
public static MainFile.Result verify(@Nullable String path, Project project) {
public static MainFile.Result verify(@Nullable String path, @Nullable Project project) {
if (!ApplicationManager.getApplication().isReadAccessAllowed()) {
throw new IllegalStateException("need read access");
}

if (project == null) {
return error("Project is not set.");
}

if (StringUtil.isEmptyOrSpaces(path)) {
return error(FlutterBundle.message("entrypoint.not.set"));
}
Expand Down Expand Up @@ -123,7 +127,7 @@ public static MainFile.Result verify(@Nullable String path, Project project) {
private static VirtualFile findAppDir(@Nullable VirtualFile file, @NotNull Project project) {
if (WorkspaceCache.getInstance(project).isBazel()) {
final Workspace workspace = WorkspaceCache.getInstance(project).get();
assert(workspace != null);
assert (workspace != null);
return workspace.getRoot();
}

Expand All @@ -134,7 +138,7 @@ private static VirtualFile findAppDir(@Nullable VirtualFile file, @NotNull Proje
}

private static boolean isAppDir(@NotNull VirtualFile dir, @NotNull Project project) {
assert(!WorkspaceCache.getInstance(project).isBazel());
assert (!WorkspaceCache.getInstance(project).isBazel());
return dir.isDirectory() && (
dir.findChild(PubRoot.PUBSPEC_YAML) != null ||
dir.findChild(PubRoot.DOT_DART_TOOL) != null ||
Expand All @@ -143,7 +147,10 @@ private static boolean isAppDir(@NotNull VirtualFile dir, @NotNull Project proje
}

private static boolean inProject(@Nullable VirtualFile file, @NotNull Project project) {
return file != null && ProjectRootManager.getInstance(project).getFileIndex().isInContent(file);
// Do a speedy check for containment over accessing the file index (which we did historically)
// but is very slow and unacceptably blocks the UI thread.
// See: https://github.com/flutter/flutter-intellij/issues/8089
return file != null && BaseProjectDirectories.getInstance(project).contains(file);
}

/**
Expand Down
30 changes: 21 additions & 9 deletions flutter-idea/src/io/flutter/run/SdkRunConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,10 @@ public LaunchState getState(@NotNull Executor executor, @NotNull ExecutionEnviro
final MainFile mainFile = MainFile.verify(launchFields.getFilePath(), env.getProject()).get();
final Project project = env.getProject();
final RunMode mode = RunMode.fromEnv(env);
final Module module = ModuleUtilCore.findModuleForFile(mainFile.getFile(), env.getProject());

final LaunchState.CreateAppCallback createAppCallback = (@Nullable FlutterDevice device) -> {
if (device == null) return null;
if (mainFile == null) return null;

final GeneralCommandLine command = getCommand(env, device);

Expand Down Expand Up @@ -190,20 +191,23 @@ public LaunchState getState(@NotNull Executor executor, @NotNull ExecutionEnviro
}
}

var module = ModuleUtilCore.findModuleForFile(mainFile.getFile(), env.getProject());
if (module == null) return null;

return getFlutterApp(env, device, project, module, mode, command);
};

final LaunchState launcher = new LaunchState(env, mainFile.getAppDir(), mainFile.getFile(), this, createAppCallback);
addConsoleFilters(launcher, env, mainFile, module);
addConsoleFilters(launcher, env, mainFile, null /* look up the module in an async read context */);
return launcher;
}

static @NotNull FlutterApp getFlutterApp(@NotNull ExecutionEnvironment env,
@NotNull FlutterDevice device,
Project project,
Module module,
RunMode mode,
GeneralCommandLine command) throws ExecutionException {
@NotNull FlutterDevice device,
Project project,
Module module,
RunMode mode,
GeneralCommandLine command) throws ExecutionException {
final FlutterApp app = FlutterApp.start(env, project, module, mode, device, command,
StringUtil.capitalize(mode.mode()) + "App",
"StopApp");
Expand All @@ -224,20 +228,28 @@ public void flutterSdkRemoved() {
protected void addConsoleFilters(@NotNull LaunchState launcher,
@NotNull ExecutionEnvironment env,
@NotNull MainFile mainFile,
// If unspecified, we'll try and find it in a non-blocking read context.
@Nullable Module module) {
// Creating console filters is expensive so we want to make sure we are not blocking.
// See: https://github.com/flutter/flutter-intellij/issues/8089
ReadAction.nonBlocking(() -> {
// Make a copy of the module reference, since we may update it in this lambda.
var moduleReference = module;
// If no module was passed in, try and find one.
if (moduleReference == null) {
moduleReference = ModuleUtilCore.findModuleForFile(mainFile.getFile(), env.getProject());
}

// Set up additional console filters.
final TextConsoleBuilder builder = launcher.getConsoleBuilder();
if (builder == null) return null;
// file:, package:, and dart: references
builder.addFilter(new DartConsoleFilter(env.getProject(), mainFile.getFile()));
//// links often found when running tests
//builder.addFilter(new DartRelativePathsConsoleFilter(env.getProject(), mainFile.getAppDir().getPath()));
if (module != null) {
if (moduleReference != null) {
// various flutter run links
builder.addFilter(new FlutterConsoleFilter(module));
builder.addFilter(new FlutterConsoleFilter(moduleReference));
}
// general urls
builder.addFilter(new UrlFilter());
Expand Down