Skip to content

Commit

Permalink
[bazelbuild#6664] Completion of FilePath and targets from external re…
Browse files Browse the repository at this point in the history
…positories
  • Loading branch information
mtoader committed Sep 8, 2024
1 parent 44b468e commit b3eb5be
Show file tree
Hide file tree
Showing 16 changed files with 473 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -32,16 +32,10 @@
public class LabelRuleLookupElement extends BuildLookupElement {

public static BuildLookupElement[] collectAllRules(
BuildFile file,
String originalString,
String packagePrefix,
@Nullable String excluded,
QuoteType quoteType) {
if (packagePrefix.startsWith("//") || originalString.startsWith(":")) {
packagePrefix += ":";
}
BuildFile file, String originalLabel, @Nullable String excluded, QuoteType quoteType) {

String ruleFragment = LabelUtils.getRuleComponent(originalLabel);

String ruleFragment = LabelUtils.getRuleComponent(originalString);
List<BuildLookupElement> lookups = Lists.newArrayList();
for (FuncallExpression target : file.findChildrenByClass(FuncallExpression.class)) {
String targetName = target.getName();
Expand All @@ -54,30 +48,33 @@ public static BuildLookupElement[] collectAllRules(
if (ruleType == null) {
continue;
}
String lookupPrefix =
originalLabel.substring(0, originalLabel.length() - ruleFragment.length());

lookups.add(
new LabelRuleLookupElement(packagePrefix, target, targetName, ruleType, quoteType));
new LabelRuleLookupElement(lookupPrefix, target, targetName, ruleType, quoteType));
}
return lookups.isEmpty()
? BuildLookupElement.EMPTY_ARRAY
: lookups.toArray(new BuildLookupElement[lookups.size()]);
: lookups.toArray(BuildLookupElement.EMPTY_ARRAY);
}

private final FuncallExpression target;
private final String targetName;
private final String ruleType;

private LabelRuleLookupElement(
String packagePrefix,
String namePrefix,
FuncallExpression target,
String targetName,
String ruleType,
QuoteType quoteType) {
super(packagePrefix + targetName, quoteType);
super(namePrefix + targetName, quoteType);
this.target = target;
this.targetName = targetName;
this.ruleType = ruleType;

assert (packagePrefix.isEmpty() || packagePrefix.endsWith(":"));
assert (namePrefix.isEmpty() || namePrefix.endsWith(":"));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -25,6 +25,7 @@
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.TargetName;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.model.primitives.WorkspaceRoot;
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;
Expand Down Expand Up @@ -116,16 +117,37 @@ public PsiFileSystemItem resolveFile(File file) {

@Nullable
public File resolvePackage(@Nullable WorkspacePath packagePath) {
return resolveWorkspaceRelativePath(packagePath != null ? packagePath.relativePath() : null);
return resolvePackageInWorkspace(packagePath, null);
}

@Nullable
private File resolveWorkspaceRelativePath(@Nullable String relativePath) {
WorkspacePathResolver pathResolver = getWorkspacePathResolver();
if (pathResolver == null || relativePath == null) {
public File resolvePackageInWorkspace(
@Nullable WorkspacePath packagePath, @Nullable String externalWorkspace) {
return resolveWorkspaceRelativePath(
packagePath != null ? packagePath.relativePath() : null, externalWorkspace);
}

@Nullable
private File resolveWorkspaceRelativePath(
@Nullable String relativePath, @Nullable String workspace) {
if (relativePath == null) {
return null;
}
return pathResolver.resolveToFile(relativePath);

if (workspace == null) {
WorkspacePathResolver pathResolver = getWorkspacePathResolver();
if (pathResolver == null) {
return null;
}
return pathResolver.resolveToFile(relativePath);
}

WorkspaceRoot workspaceRoot = WorkspaceHelper.getExternalWorkspace(project, workspace);
if (workspaceRoot != null) {
return workspaceRoot.absolutePathFor(relativePath).toFile();
}

return null;
}

@Nullable
Expand All @@ -145,14 +167,14 @@ public BuildLookupElement[] resolvePackageLookupElements(FileLookupData lookupDa
// ignore invalid labels containing './', '../', etc.
return BuildLookupElement.EMPTY_ARRAY;
}
File file = resolveWorkspaceRelativePath(relativePath);
File file = resolveWorkspaceRelativePath(relativePath, lookupData.externalWorkspace);

FileOperationProvider provider = FileOperationProvider.getInstance();
String pathFragment = "";
if (file == null || (!provider.isDirectory(file) && !relativePath.endsWith("/"))) {
// we might be partway through a file name. Try the parent directory
relativePath = PathUtil.getParentPath(relativePath);
file = resolveWorkspaceRelativePath(relativePath);
file = resolveWorkspaceRelativePath(relativePath, lookupData.externalWorkspace);
pathFragment =
StringUtil.trimStart(lookupData.filePathFragment.substring(relativePath.length()), "/");
}
Expand Down Expand Up @@ -217,14 +239,17 @@ private BuildLookupElement lookupForFile(VirtualFile file, FileLookupData lookup
}

@Nullable
public BuildFile resolveBlazePackage(String workspaceRelativePath) {
public BuildFile resolveBlazePackage(
String workspaceRelativePath, @Nullable String externalWorkspace) {
workspaceRelativePath = StringUtil.trimStart(workspaceRelativePath, "//");
return resolveBlazePackage(WorkspacePath.createIfValid(workspaceRelativePath));
return resolveBlazePackage(
WorkspacePath.createIfValid(workspaceRelativePath), externalWorkspace);
}

@Nullable
public BuildFile resolveBlazePackage(@Nullable WorkspacePath path) {
return findBuildFile(resolvePackage(path));
public BuildFile resolveBlazePackage(
@Nullable WorkspacePath path, @Nullable String externalWorkspace) {
return findBuildFile(resolvePackageInWorkspace(path, externalWorkspace));
}

@Nullable
Expand Down Expand Up @@ -253,12 +278,16 @@ public BuildFile findBuildFile(@Nullable File packageDirectory) {
*/
@Nullable
public File resolveParentDirectory(@Nullable Label label) {
return label != null ? resolveParentDirectory(label.blazePackage(), label.targetName()) : null;
return label != null
? resolveParentDirectory(
label.externalWorkspaceName(), label.blazePackage(), label.targetName())
: null;
}

@Nullable
private File resolveParentDirectory(WorkspacePath packagePath, TargetName targetName) {
File packageFile = resolvePackage(packagePath);
private File resolveParentDirectory(
String workspaceName, WorkspacePath packagePath, TargetName targetName) {
File packageFile = resolvePackageInWorkspace(packagePath, workspaceName);
if (packageFile == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,7 +39,8 @@

/** The data relevant to finding file lookups. */
public class FileLookupData {
private static final ImmutableSet<String> BUILDFILE_NAMES = ImmutableSet.of("BUILD", "BUILD.bazel");
private static final ImmutableSet<String> BUILDFILE_NAMES =
ImmutableSet.of("BUILD", "BUILD.bazel");

/** The type of path string format */
public enum PathFormat {
Expand Down Expand Up @@ -70,7 +71,9 @@ public static FileLookupData nonLocalFileLookup(
return null;
}
// handle the single '/' case by calling twice.
String relativePath = StringUtil.trimStart(StringUtil.trimStart(originalLabel, "/"), "/");
String relativePath =
StringUtil.trimStart(
StringUtil.trimStart(LabelUtils.getPackagePathComponent(originalLabel), "/"), "/");
if (relativePath.startsWith("/")) {
return null;
}
Expand Down Expand Up @@ -119,6 +122,7 @@ public static FileLookupData packageLocalFileLookup(
private final BuildFile containingFile;
@Nullable private final String containingPackage;
public final String filePathFragment;
@Nullable public final String externalWorkspace;
public final PathFormat pathFormat;
private final QuoteType quoteType;
@Nullable private final VirtualFileFilter fileFilter;
Expand All @@ -139,6 +143,7 @@ protected FileLookupData(
this.filePathFragment = filePathFragment;
this.pathFormat = pathFormat;
this.quoteType = quoteType;
this.externalWorkspace = LabelUtils.getExternalWorkspaceComponent(originalLabel);

assert (pathFormat != PathFormat.PackageLocal
|| (containingPackage != null && containingFile != null));
Expand Down Expand Up @@ -187,6 +192,9 @@ private String getFullLabel(String relativePath) {
if (pathFormat != PathFormat.PackageLocal) {
if (pathFormat == PathFormat.NonLocal) {
relativePath = "//" + relativePath;
if (externalWorkspace != null) {
relativePath = "@" + externalWorkspace + relativePath;
}
}
return relativePath;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -98,15 +98,21 @@ public Object[] getVariants() {
private BuildLookupElement[] getRuleLookups(String labelString) {
if (labelString.endsWith("/")
|| (labelString.startsWith("/") && !labelString.contains(":"))
|| (labelString.startsWith("@") && !labelString.contains(":"))
|| skylarkExtensionReference(myElement)) {
return BuildLookupElement.EMPTY_ARRAY;
}

String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
String externalWorkspace = LabelUtils.getExternalWorkspaceComponent(labelString);

BuildFile referencedBuildFile =
LabelUtils.getReferencedBuildFile(myElement.getContainingFile(), packagePrefix);
LabelUtils.getReferencedBuildFile(
myElement.getContainingFile(), externalWorkspace, packagePrefix);
if (referencedBuildFile == null) {
return BuildLookupElement.EMPTY_ARRAY;
}

String self = null;
if (referencedBuildFile == myElement.getContainingFile()) {
FuncallExpression funcall =
Expand All @@ -116,11 +122,11 @@ private BuildLookupElement[] getRuleLookups(String labelString) {
}
}
return LabelRuleLookupElement.collectAllRules(
referencedBuildFile, labelString, packagePrefix, self, myElement.getQuoteType());
referencedBuildFile, labelString, self, myElement.getQuoteType());
}

private BuildLookupElement[] getFileLookups(String labelString) {
if (labelString.startsWith("//") || labelString.equals("/")) {
if (labelString.startsWith("//") || labelString.equals("/") || labelString.startsWith("@")) {
return getNonLocalFileLookups(labelString);
}
return getPackageLocalFileLookups(labelString);
Expand Down Expand Up @@ -151,6 +157,7 @@ private BuildLookupElement[] getSkylarkExtensionLookups(String labelString) {
return BuildLookupElement.EMPTY_ARRAY;
}
String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
String externalWorkspace = LabelUtils.getExternalWorkspaceComponent(labelString);
BuildFile parentFile = myElement.getContainingFile();
if (parentFile == null) {
return BuildLookupElement.EMPTY_ARRAY;
Expand All @@ -160,7 +167,8 @@ private BuildLookupElement[] getSkylarkExtensionLookups(String labelString) {
return BuildLookupElement.EMPTY_ARRAY;
}
BuildFile referencedBuildFile =
LabelUtils.getReferencedBuildFile(containingPackage.buildFile, packagePrefix);
LabelUtils.getReferencedBuildFile(
containingPackage.buildFile, externalWorkspace, packagePrefix);

// Directories before the colon are already covered.
// We're only concerned with package-local directories.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,9 +24,11 @@
import com.google.idea.blaze.base.model.primitives.TargetName;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.intellij.codeInsight.completion.CompletionUtilCore;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PathUtil;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/** Utility methods for working with blaze labels. */
Expand Down Expand Up @@ -119,18 +121,28 @@ public static Label createLabelFromString(
/** The blaze file referenced by the label. */
@Nullable
public static BuildFile getReferencedBuildFile(
@Nullable BuildFile containingFile, String packagePathComponent) {
@Nullable BuildFile containingFile,
@Nullable String externalWorkspaceComponent,
String packagePathComponent) {
if (containingFile == null) {
return null;
}
if (!packagePathComponent.startsWith("//")) {
return containingFile;
}
return BuildReferenceManager.getInstance(containingFile.getProject())
.resolveBlazePackage(packagePathComponent);
.resolveBlazePackage(packagePathComponent, externalWorkspaceComponent);
}

@Nonnull
public static String getRuleComponent(String labelString) {
if (labelString.startsWith("@")) {
int colonIndex = labelString.indexOf('/');
if (colonIndex == -1) {
return "";
}
labelString = labelString.substring(colonIndex + 1);
}
if (labelString.startsWith("/")) {
int colonIndex = labelString.indexOf(':');
return colonIndex == -1 ? "" : labelString.substring(colonIndex + 1);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -62,9 +62,11 @@ public TextRange getRangeInElement() {
@Nullable
@Override
public BuildFile resolve() {
WorkspacePath workspacePath = getWorkspacePath(myElement.getStringContents());
String labelString = myElement.getStringContents();
WorkspacePath workspacePath = getWorkspacePath(labelString);
String externalWorkspace = LabelUtils.getExternalWorkspaceComponent(labelString);
return BuildReferenceManager.getInstance(myElement.getProject())
.resolveBlazePackage(workspacePath);
.resolveBlazePackage(workspacePath, externalWorkspace);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
* Copyright 2024 The Bazel Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -109,12 +109,12 @@ private BuildLookupElement[] getRuleLookups(String labelString) {
}
String packagePrefix = LabelUtils.getPackagePathComponent(labelString);
BuildFile referencedBuildFile =
BuildReferenceManager.getInstance(getProject()).resolveBlazePackage(packagePrefix);
BuildReferenceManager.getInstance(getProject()).resolveBlazePackage(packagePrefix, null);
if (referencedBuildFile == null) {
return BuildLookupElement.EMPTY_ARRAY;
}
return LabelRuleLookupElement.collectAllRules(
referencedBuildFile, labelString, packagePrefix, null, QuoteType.NoQuotes);
referencedBuildFile, labelString, null, QuoteType.NoQuotes);
}

private BuildLookupElement[] getFileLookups(String labelString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ public static Path getExternalSourceRoot(BlazeProjectData projectData) {
return Paths.get(projectData.getBlazeInfo().getOutputBase().getAbsolutePath(), "external").normalize();
}

/** resolve workspace root for a named external repository. needs context since the same name can mean something different in different workspaces. */
@Nullable
private static synchronized WorkspaceRoot resolveExternalWorkspaceRoot(
Project project, String workspaceName, @Nullable BuildFile buildFile) {
Expand Down
Loading

0 comments on commit b3eb5be

Please sign in to comment.