diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java index d653923ed41..f31707afa27 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManager.java @@ -26,6 +26,7 @@ import com.google.idea.blaze.base.model.primitives.TargetName; import com.google.idea.blaze.base.model.primitives.WorkspacePath; import com.google.idea.blaze.base.settings.Blaze; +import com.google.idea.blaze.base.sync.projectview.ImportRoots; import com.google.idea.blaze.base.sync.workspace.WorkspaceHelper; import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver; import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverProvider; @@ -53,8 +54,13 @@ public static BuildReferenceManager getInstance(Project project) { private final Project project; + private IgnoredDirectories ignoredDirectories; + public BuildReferenceManager(Project project) { this.project = project; + if (ImportRoots.forProjectSafe(project) != null) { + this.ignoredDirectories = new IgnoredDirectories(ImportRoots.forProjectSafe(project)); + } } /** Finds the PSI element associated with the given label. */ @@ -158,6 +164,7 @@ public BuildLookupElement[] resolvePackageLookupElements(FileLookupData lookupDa if (vf == null || !vf.isDirectory()) { return BuildLookupElement.EMPTY_ARRAY; } + BuildLookupElement[] uniqueLookup = new BuildLookupElement[1]; while (true) { VirtualFile[] children = vf.getChildren(); @@ -167,7 +174,9 @@ public BuildLookupElement[] resolvePackageLookupElements(FileLookupData lookupDa List validChildren = Lists.newArrayListWithCapacity(children.length); for (VirtualFile child : children) { ProgressManager.checkCanceled(); - if (child.getName().startsWith(pathFragment) && lookupData.acceptFile(project, child)) { + if (child.getName().startsWith(pathFragment) + && lookupData.acceptFile(project, child) + && (ignoredDirectories == null || !ignoredDirectories.shouldIgnore(child))) { validChildren.add(child); } } @@ -256,4 +265,21 @@ private File resolveParentDirectory(WorkspacePath packagePath, TargetName target String rulePathParent = PathUtil.getParentPath(targetName.toString()); return new File(packageFile, rulePathParent); } + + private class IgnoredDirectories { + private ImportRoots importRoots; + + public IgnoredDirectories(ImportRoots importRoots) { + this.importRoots = importRoots; + } + + public Boolean shouldIgnore(VirtualFile vf) { + for (WorkspacePath excludeDirectory : importRoots.excludeDirectories()) { + if (vf.getName().startsWith(excludeDirectory.relativePath())) { + return true; + } + } + return false; + } + } } diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java index 2e55be3bd63..328ce19e210 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/FileLookupData.java @@ -123,7 +123,7 @@ public static FileLookupData packageLocalFileLookup( private final QuoteType quoteType; @Nullable private final VirtualFileFilter fileFilter; - private FileLookupData( + protected FileLookupData( String originalLabel, @Nullable BuildFile containingFile, @Nullable String containingPackage, diff --git a/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java index aa53076cb5e..2fe960db465 100644 --- a/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java +++ b/base/src/com/google/idea/blaze/base/model/primitives/WorkspaceRoot.java @@ -46,12 +46,17 @@ public static WorkspaceRoot fromImportSettings(BlazeImportSettings blazeSettings /** * Tries to load the import settings for the given project and get the workspace root directory. *
- * Unlike {@link #fromProject}, it will silently return null if this is not a blaze project. + * Unlike {@link #fromProject}, it will silently return null if this is not a blaze project of if + * the project is not properly initialized (eg. in tests). */ @Nullable public static WorkspaceRoot fromProjectSafe(Project project) { - BlazeImportSettings importSettings = - BlazeImportSettingsManager.getInstance(project).getImportSettings(); + BlazeImportSettingsManager manager = BlazeImportSettingsManager.getInstance(project); + if (manager == null) { + return null; + } + + BlazeImportSettings importSettings = manager.getImportSettings(); return importSettings != null ? fromImportSettings(importSettings) : null; } diff --git a/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java b/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java index 993e861d1a6..592d42270d3 100644 --- a/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java +++ b/base/src/com/google/idea/blaze/base/sync/projectview/ImportRoots.java @@ -55,10 +55,20 @@ public final class ImportRoots { @Nullable public static ImportRoots forProjectSafe(Project project) { WorkspaceRoot root = WorkspaceRoot.fromProjectSafe(project); - ProjectViewSet projectViewSet = ProjectViewManager.getInstance(project).getProjectViewSet(); - if (root == null || projectViewSet == null) { + if (root == null) { return null; } + + ProjectViewManager manager = ProjectViewManager.getInstance(project); + if (manager == null) { + return null; + } + + ProjectViewSet projectViewSet = manager.getProjectViewSet(); + if (projectViewSet == null) { + return null; + } + return ImportRoots.builder(root, Blaze.getBuildSystemName(project)).add(projectViewSet).build(); } diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManagerTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManagerTest.java new file mode 100644 index 00000000000..43262e06877 --- /dev/null +++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/references/BuildReferenceManagerTest.java @@ -0,0 +1,83 @@ +package com.google.idea.blaze.base.lang.buildfile.references; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.base.Joiner; +import com.google.idea.blaze.base.MockProjectViewManager; +import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase; +import com.google.idea.blaze.base.lang.buildfile.completion.BuildLookupElement; +import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile; +import com.google.idea.blaze.base.model.primitives.Label; +import com.google.idea.blaze.base.model.primitives.WorkspacePath; +import com.google.idea.blaze.base.projectview.ProjectViewSet; +import com.google.idea.blaze.base.projectview.parser.ProjectViewParser; +import com.google.idea.blaze.base.scope.BlazeContext; +import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolverImpl; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Arrays; +import java.util.List; + +@RunWith(JUnit4.class) +public class BuildReferenceManagerTest extends BuildFileIntegrationTestCase { + private MockProjectViewManager projectViewManager; + + @Test + public void testResolvePackageLookupElementsIgnoresIgnoredDirectories() { + projectViewManager = new MockProjectViewManager(getProject()); + setProjectView("directories:", " .", "derive_targets_from_directories: true"); + + workspace.createDirectory(new WorkspacePath(".ijwb")); + workspace.createDirectory(new WorkspacePath("src")); + workspace.createDirectory(new WorkspacePath("src/go")); + workspace.createFile(new WorkspacePath("src/go/BUILD.bazel"), ""); + workspace.createFile(new WorkspacePath("src/go/main.go"), "package main\n"); + BuildFile topTelevelBuildFile = createBuildFile(new WorkspacePath("BUILD.bazel"), ""); + + BuildReferenceManager manager = new BuildReferenceManager(getProject()); + FileLookupData nonLocalLookupData = + FileLookupData.nonLocalFileLookup( + "//", topTelevelBuildFile, QuoteType.NoQuotes, FileLookupData.PathFormat.NonLocal); + assertThat(nonLocalLookupData).isNotNull(); + List results = + Arrays.stream(manager.resolvePackageLookupElements(nonLocalLookupData)) + .map(BuildLookupElement::getLookupString) + .toList(); + assertThat(results).containsAllIn(new String[] {"//src/go"}); + assertThat(results).containsNoneIn(new String[] {".ijwb"}); + + String originalLabel = "//:"; + Label packageLabel = topTelevelBuildFile.getPackageLabel(); + assertThat(packageLabel).isNotNull(); + String basePackagePath = packageLabel.blazePackage().relativePath(); + String filePath = basePackagePath + "/" + LabelUtils.getRuleComponent(originalLabel); + FileLookupData localLookupData = + new FileLookupData( + originalLabel, + topTelevelBuildFile, + basePackagePath, + filePath, + FileLookupData.PathFormat.PackageLocal, + QuoteType.NoQuotes, + null); + List otherResults = + Arrays.stream(manager.resolvePackageLookupElements(localLookupData)) + .map(BuildLookupElement::getLookupString) + .toList(); + assertThat(otherResults).containsAllIn(new String[] {"//:src"}); + assertThat(otherResults).containsNoneIn(new String[] {":.ijwb"}); + } + + protected void setProjectView(String... contents) { + BlazeContext context = BlazeContext.create(); + ProjectViewParser projectViewParser = + new ProjectViewParser(context, new WorkspacePathResolverImpl(workspaceRoot)); + projectViewParser.parseProjectView(Joiner.on("\n").join(contents)); + + ProjectViewSet result = projectViewParser.getResult(); + assertThat(result.getProjectViewFiles()).isNotEmpty(); + projectViewManager.setProjectView(result); + } +}