diff --git a/WORKSPACE b/WORKSPACE index e9843d37675..ca9f4e14537 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -83,7 +83,6 @@ http_archive( url = IC_233_URL, ) - # The plugin api for IntelliJ UE 2021.2. This is required to run UE-specific # integration tests. http_archive( diff --git a/base/src/META-INF/blaze-base.xml b/base/src/META-INF/blaze-base.xml index 4591042bbbc..69813037d2a 100644 --- a/base/src/META-INF/blaze-base.xml +++ b/base/src/META-INF/blaze-base.xml @@ -234,6 +234,7 @@ + @@ -571,6 +572,7 @@ + diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java index cd01e0d70eb..9e99d40ff8c 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/BuildLookupElement.java @@ -57,6 +57,10 @@ public String getLookupString() { @Nullable public abstract Icon getIcon(); + public String getLabel() { + return baseName; + } + protected String getItemText() { return baseName; } diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java index 0a5a958e6b7..0c39268620d 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/FilePathLookupElement.java @@ -24,12 +24,18 @@ public class FilePathLookupElement extends BuildLookupElement { private final String itemText; + private final Boolean isDirectory; private final NullableLazyValue icon; public FilePathLookupElement( - String fullLabel, String itemText, QuoteType quoteWrapping, NullableLazyValue icon) { + String fullLabel, + String itemText, + QuoteType quoteWrapping, + Boolean isDirectory, + NullableLazyValue icon) { super(fullLabel, quoteWrapping); this.itemText = itemText; + this.isDirectory = isDirectory; this.icon = icon; } @@ -38,6 +44,10 @@ protected String getItemText() { return itemText; } + public Boolean getIsDirectory() { + return isDirectory; + } + @Nullable @Override public Icon getIcon() { diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java index 0b9af98bfa0..8442d362085 100644 --- a/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/completion/LabelRuleLookupElement.java @@ -94,4 +94,8 @@ protected String getTypeText() { protected String getItemText() { return targetName; } + + public String getRuleType() { + return ruleType; + } } 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 8714ad71321..2e55be3bd63 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 @@ -180,7 +180,7 @@ protected Icon compute() { String fullLabel = workspacePath != null ? getFullLabel(workspacePath.relativePath()) : file.getPath(); String itemText = workspacePath != null ? getItemText(workspacePath.relativePath()) : fullLabel; - return new FilePathLookupElement(fullLabel, itemText, quoteType, icon); + return new FilePathLookupElement(fullLabel, itemText, quoteType, file.isDirectory(), icon); } private String getFullLabel(String relativePath) { diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReference.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReference.java new file mode 100644 index 00000000000..a1d31ae9221 --- /dev/null +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReference.java @@ -0,0 +1,83 @@ +package com.google.idea.blaze.base.lang.buildfile.references; + +import com.google.common.collect.ImmutableSet; +import com.google.idea.blaze.base.lang.buildfile.completion.FilePathLookupElement; +import com.google.idea.blaze.base.lang.buildfile.completion.LabelRuleLookupElement; +import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral; +import com.google.idea.blaze.base.model.primitives.Label; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.icons.AllIcons; +import java.util.ArrayList; +import java.util.List; + +public class VisibilityReference extends LabelReference { + + private static final ImmutableSet PSEUDO_VISIBILITIES = + ImmutableSet.of("__pkg__", "__subpackages__"); + + public VisibilityReference(StringLiteral element, boolean soft) { + super(element, soft); + } + + @Override + public Object[] getVariants() { + Object[] variants = super.getVariants(); + ArrayList results = new ArrayList<>(); + for (Object v : variants) { + if (v instanceof FilePathLookupElement) { + FilePathLookupElement le = ((FilePathLookupElement) v); + if (le.getIsDirectory()) { + results.add( + LookupElementBuilder.create("\"" + le.getLabel() + "/") + .withPresentableText(le.getLabel()) + .withIcon(AllIcons.Nodes.Variable)); + results.addAll(createPseudoVisibilitiesForPackage(le.getLabel())); + } + + } else if (v instanceof LabelRuleLookupElement) { + LabelRuleLookupElement le = ((LabelRuleLookupElement) v); + if (le.getRuleType().equals("package_group")) { + results.add(((LookupElement) le)); + Label lbl = Label.createIfValid(le.getLabel()); + if (lbl != null) { + String pkg = "//" + lbl.blazePackage(); + results.addAll(createPseudoVisibilitiesForPackage(pkg)); + } + } + } + } + + ArrayList globalVisibilities = new ArrayList<>(); + globalVisibilities.add("//visibility:public"); + globalVisibilities.add("//visibility:private"); + + for (String v : globalVisibilities) { + results.add( + LookupElementBuilder.create("\"" + v) + .withIcon(AllIcons.Nodes.Variable) + .withPresentableText(v)); + results.add( + LookupElementBuilder.create("'" + v) + .withIcon(AllIcons.Nodes.Variable) + .withPresentableText(v)); + } + + return results.toArray(); + } + + private List createPseudoVisibilitiesForPackage(String pkg) { + List result = new ArrayList<>(PSEUDO_VISIBILITIES.size() * 2); + for (String pv : PSEUDO_VISIBILITIES) { + result.add( + LookupElementBuilder.create("\"" + pkg + ":" + pv) + .withPresentableText(pkg + ":" + pv) + .withIcon(AllIcons.Nodes.Variable)); + result.add( + LookupElementBuilder.create("'" + pkg + ":" + pv) + .withPresentableText(pkg + ":" + pv) + .withIcon(AllIcons.Nodes.Variable)); + } + return result; + } +} diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceContributor.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceContributor.java new file mode 100644 index 00000000000..53da5cb2687 --- /dev/null +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceContributor.java @@ -0,0 +1,13 @@ +package com.google.idea.blaze.base.lang.buildfile.references; + +import com.intellij.psi.PsiReferenceContributor; +import com.intellij.psi.PsiReferenceRegistrar; +import org.jetbrains.annotations.NotNull; + +public class VisibilityReferenceContributor extends PsiReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + VisibilityReferenceProvider.PATTERN, new VisibilityReferenceProvider()); + } +} diff --git a/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceProvider.java b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceProvider.java new file mode 100644 index 00000000000..10ba3d199a5 --- /dev/null +++ b/base/src/com/google/idea/blaze/base/lang/buildfile/references/VisibilityReferenceProvider.java @@ -0,0 +1,58 @@ +package com.google.idea.blaze.base.lang.buildfile.references; + +import static com.intellij.patterns.PlatformPatterns.psiElement; + +import com.google.common.collect.ImmutableSet; +import com.google.idea.blaze.base.lang.buildfile.language.BuildFileLanguage; +import com.google.idea.blaze.base.lang.buildfile.psi.Argument; +import com.google.idea.blaze.base.lang.buildfile.psi.StringLiteral; +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PatternCondition; +import com.intellij.patterns.PatternConditionPlus; +import com.intellij.patterns.StandardPatterns; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiReference; +import com.intellij.psi.PsiReferenceProvider; +import com.intellij.psi.impl.PsiElementBase; +import com.intellij.util.PairProcessor; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +public class VisibilityReferenceProvider extends PsiReferenceProvider + implements AttributeSpecificStringLiteralReferenceProvider { + + private static final ImmutableSet VISIBILITY_STRING_TYPES = ImmutableSet.of("visibility"); + + public static final ElementPattern PATTERN = + psiElement(StringLiteral.class) + .withLanguage(BuildFileLanguage.INSTANCE) + .inside( + psiElement(Argument.Keyword.class) + .with(nameCondition(StandardPatterns.string().oneOf(VISIBILITY_STRING_TYPES)))); + + private static PatternCondition nameCondition(final ElementPattern pattern) { + return new PatternConditionPlus("_withPsiName", pattern) { + @Override + public boolean processValues( + PsiElementBase t, + ProcessingContext context, + PairProcessor processor) { + return processor.process(t.getName(), context); + } + }; + } + + @Override + public PsiReference[] getReferences(String attributeName, StringLiteral literal) { + if (!VISIBILITY_STRING_TYPES.contains(attributeName)) { + return PsiReference.EMPTY_ARRAY; + } + return new PsiReference[] {new VisibilityReference(literal, true)}; + } + + @Override + public PsiReference[] getReferencesByElement( + @NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) { + return new PsiReference[] {psiElement.getReference()}; + } +} diff --git a/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/VisibilityCompletionTest.java b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/VisibilityCompletionTest.java new file mode 100644 index 00000000000..a130b8661eb --- /dev/null +++ b/base/tests/integrationtests/com/google/idea/blaze/base/lang/buildfile/completion/VisibilityCompletionTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2023 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. + * 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 com.google.idea.blaze.base.lang.buildfile.completion; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.idea.blaze.base.lang.buildfile.BuildFileIntegrationTestCase; +import com.google.idea.blaze.base.lang.buildfile.psi.BuildFile; +import com.google.idea.blaze.base.model.primitives.WorkspacePath; +import com.intellij.openapi.editor.Editor; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class VisibilityCompletionTest extends BuildFileIntegrationTestCase { + + @Test + public void testVisibilityReferenceWithDoubleQuote() throws Throwable { + BuildFile file = createBuildFile(new WorkspacePath("BUILD"), "sh_binary(visibility = [\"/\"])"); + + Editor editor = editorTest.openFileInEditor(file); + editorTest.setCaretPosition(editor, 0, "sh_binary(visibility = [\"/".length()); + + assertThat(editorTest.getCompletionItemsAsStrings()) + .asList() + .containsExactly("\"//visibility:private", "\"//visibility:public"); + } + + @Test + public void testVisibilityReferenceWithSimpleQuote() throws Throwable { + BuildFile file = createBuildFile(new WorkspacePath("BUILD"), "sh_binary(visibility = ['/'])"); + + Editor editor = editorTest.openFileInEditor(file); + editorTest.setCaretPosition(editor, 0, "sh_binary(visibility = ['/".length()); + + assertThat(editorTest.getCompletionItemsAsStrings()) + .asList() + .containsExactly("'//visibility:private", "'//visibility:public"); + } + + @Test + public void testVisibilityReferenceWithOtherPackages() throws Throwable { + createBuildFile(new WorkspacePath("pkg/foo/BUILD"), ""); + BuildFile file = createBuildFile(new WorkspacePath("BUILD"), "sh_binary(visibility = ['/'])"); + + Editor editor = editorTest.openFileInEditor(file); + editorTest.setCaretPosition(editor, 0, "sh_binary(visibility = ['/".length()); + + assertThat(editorTest.getCompletionItemsAsStrings()) + .asList() + .containsExactly( + "'//visibility:private", + "'//visibility:public", + "'//pkg/foo:__pkg__", + "'//pkg/foo:__subpackages__"); + } + + @Test + public void testVisibilityReferenceWithPackageGroup() throws Throwable { + createBuildFile(new WorkspacePath("pkg/foo/BUILD"), "package_group(name = 'bob')"); + BuildFile file = + createBuildFile(new WorkspacePath("BUILD"), "sh_binary(visibility = ['//pkg/foo:'])"); + + Editor editor = editorTest.openFileInEditor(file); + editorTest.setCaretPosition(editor, 0, "sh_binary(visibility = ['//pkg/foo:".length()); + + assertThat(editorTest.getCompletionItemsAsStrings()) + .asList() + .containsExactly( + "'//pkg/foo:bob'", + "'//pkg/foo:__pkg__", + "'//pkg/foo:__subpackages__"); + } +} diff --git a/cpp/BUILD b/cpp/BUILD index b8c142987bd..16b83ab0b5f 100644 --- a/cpp/BUILD +++ b/cpp/BUILD @@ -57,8 +57,8 @@ optional_plugin_xml( intellij_plugin_library( name = "plugin_library", - plugin_xmls = [":non_optional_cidr"], optional_plugin_xmls = [":optional_cidr"], + plugin_xmls = [":non_optional_cidr"], visibility = PLUGIN_PACKAGES_VISIBILITY, deps = [":cpp"], ) diff --git a/sdkcompat/v233/BUILD b/sdkcompat/v233/BUILD index 8278ce5f0d1..86fec73e8e9 100644 --- a/sdkcompat/v233/BUILD +++ b/sdkcompat/v233/BUILD @@ -24,8 +24,8 @@ java_library( ]) + ["com/google/idea/sdkcompat/refactoring/safedelete/JavaSafeDeleteProcessorCompat.java"], clion = glob([ "com/google/idea/sdkcompat/cpp/**", - "com/google/idea/sdkcompat/clion/**", # For classes incompatible with Android Studio - "com/google/idea/sdkcompat/javascript/**", #api223 + "com/google/idea/sdkcompat/clion/**", # For classes incompatible with Android Studio + "com/google/idea/sdkcompat/javascript/**", #api223 ]), intellij = glob([ "com/google/idea/sdkcompat/java/**", diff --git a/third_party/go/BUILD b/third_party/go/BUILD index 25d44d98442..292314a6601 100644 --- a/third_party/go/BUILD +++ b/third_party/go/BUILD @@ -21,7 +21,7 @@ java_library( "intellij-2023.2": ["@go_2023_2//:go"], "intellij-ue-2023.2": ["@go_2023_2//:go"], "intellij-2023.3": ["@go_2023_3//:go"], - "intellij-ue-2023.3": ["@go_2023_3//:go"], + "intellij-ue-2023.3": ["@go_2023_3//:go"], "default": [], }), ) diff --git a/third_party/python/BUILD b/third_party/python/BUILD index 7a76782f4dd..bfd2a8ffdb0 100644 --- a/third_party/python/BUILD +++ b/third_party/python/BUILD @@ -21,7 +21,7 @@ java_library( "intellij-2023.2": ["@python_2023_2//:python"], "intellij-ue-2023.2": ["@python_2023_2//:python"], "intellij-2023.3": ["@python_2023_3//:python"], - "intellij-ue-2023.3": ["@python_2023_3//:python"], + "intellij-ue-2023.3": ["@python_2023_3//:python"], "clion-2021.3": ["@clion_2021_3//:python"], "clion-2022.1": ["@clion_2022_1//:python"], "clion-2022.2": ["@clion_2022_2//:python"],