Skip to content
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

Lookup *.proto files in additional libraries #856

Open
wants to merge 2 commits 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package com.intellij.protobuf.lang.resolve;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.AdditionalLibraryRootsProvider;
import com.intellij.openapi.roots.SyntheticLibrary;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.GlobalSearchScopesCore;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

public class AdditionalLibrariesFileResolveProvider implements FileResolveProvider {
@NotNull
@Override
public Collection<ChildEntry> getChildEntries(@NotNull String path, @NotNull Project project) {
VirtualFile pathFile = findFile(path, project);
if (pathFile == null || !pathFile.isDirectory()) {
return Collections.emptyList();
}
VirtualFile[] children = pathFile.getChildren();
if (children == null) {
return Collections.emptyList();
}

Set<ChildEntry> results = new HashSet<>();

for (VirtualFile child : children) {
if (PROTO_AND_DIRECTORY_FILTER.accept(child)) {
results.add(new ChildEntry(child.getName(), child.isDirectory()));
}
}
return results;
}

@Nullable
@Override
public VirtualFile findFile(@NotNull String path, @NotNull Project project) {
for (AdditionalLibraryRootsProvider provider : AdditionalLibraryRootsProvider.EP_NAME.getExtensionList()) {
for (SyntheticLibrary library : provider.getAdditionalProjectLibraries(project)) {
for (VirtualFile sourceRoot : library.getSourceRoots()) {
if (sourceRoot.isDirectory()) {
VirtualFile pbFile = sourceRoot.findFileByRelativePath(path);
if (pbFile != null) {
return pbFile;
}
}
if (sourceRoot.getPath().endsWith(path)) {
return sourceRoot;
}
}
}
}
return null;
}

@Nullable
@Override
public VirtualFile getDescriptorFile(@NotNull Project project) {
return null;
}

@NotNull
@Override
public GlobalSearchScope getSearchScope(@NotNull Project project) {
VirtualFile[] roots = AdditionalLibraryRootsProvider.EP_NAME.getExtensionList().stream()
.map(provider -> provider.getAdditionalProjectLibraries(project))
.flatMap(Collection::stream)
.map(SyntheticLibrary::getSourceRoots)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.toArray(VirtualFile[]::new);
return GlobalSearchScopesCore.directoriesScope(project, /* withSubDirectories= */ true, roots);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.intellij.protobuf.lang.resolve;

import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.AdditionalLibraryRootsProvider;
import com.intellij.openapi.roots.SyntheticLibrary;
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.protobuf.fixtures.PbCodeInsightFixtureTestCase;
import com.intellij.protobuf.lang.resolve.FileResolveProvider.ChildEntry;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
* Unit tests for {@link AdditionalLibrariesFileResolveProvider}.
*/
public class AdditionalLibrariesFileResolveProviderTest extends PbCodeInsightFixtureTestCase {

private File tempDir = null;

@Override
public void setUp() throws Exception {
super.setUp();
tempDir = FileUtil.createTempDirectory(getName(), UUID.randomUUID().toString(), false);
WriteAction.run(() -> ProjectRootManagerEx.getInstanceEx(getProject()).makeRootsChange(
() -> AdditionalLibraryRootsProvider.EP_NAME.getPoint().registerExtension(new AdditionalLibraryRootsProvider() {
@NotNull
@Override
public Collection<SyntheticLibrary> getAdditionalProjectLibraries(@NotNull Project project) {
List<VirtualFile> roots = Collections.singletonList(VfsUtil.findFile(tempDir.toPath(), true));
return Collections.singletonList(SyntheticLibrary.newImmutableLibrary(roots));
}
}, getTestRootDisposable()), false, true));
}

@Override
public void tearDown() throws Exception {
FileUtil.delete(tempDir);
super.tearDown();
}

public void testFindFilePrefersFirstListedPath() throws Exception {
FileUtil.writeToFile(new File(tempDir, "com/foo/dir/foo.proto"), "// foo");

VirtualFileManager.getInstance().syncRefresh();

FileResolveProvider resolver = new AdditionalLibrariesFileResolveProvider();
VirtualFile foo = resolver.findFile("com/foo/dir/foo.proto", getProject());

assertNotNull(foo);

assertEquals("// foo", VfsUtil.loadText(foo));
}

public void testGetChildEntries() throws Exception {
FileUtil.writeToFile(new File(tempDir, "com/foo/dir/foo.proto"), "// foo");
FileUtil.writeToFile(new File(tempDir, "com/foo/dir/bar.proto"), "// bar");

VirtualFileManager.getInstance().syncRefresh();

FileResolveProvider resolver = new AdditionalLibrariesFileResolveProvider();
assertContainsElements(
resolver.getChildEntries("", getProject()),
ChildEntry.directory("com"));
assertContainsElements(
resolver.getChildEntries("com", getProject()), ChildEntry.directory("foo"));
assertContainsElements(
resolver.getChildEntries("com/", getProject()), ChildEntry.directory("foo"));
assertContainsElements(
resolver.getChildEntries("com/foo", getProject()), ChildEntry.directory("dir"));
assertContainsElements(
resolver.getChildEntries("com/foo/dir", getProject()),
ChildEntry.file("foo.proto"),
ChildEntry.file("bar.proto"));
assertContainsElements(
resolver.getChildEntries("com/foo/dir/", getProject()),
ChildEntry.file("foo.proto"),
ChildEntry.file("bar.proto"));
}
}
1 change: 1 addition & 0 deletions protobuf/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
<!-- SettingsFileResolveProvider is listed first so that manually-configured descriptor paths always win. -->
<fileResolveProvider id="settings" order="FIRST"
implementation="com.intellij.protobuf.ide.settings.SettingsFileResolveProvider"/>
<fileResolveProvider implementation="com.intellij.protobuf.lang.resolve.AdditionalLibrariesFileResolveProvider"/>
<projectSettingsConfigurator id="default" order="LAST"
implementation="com.intellij.protobuf.ide.settings.DefaultConfigurator"/>

Expand Down