Skip to content

Commit

Permalink
Lookup *.proto files in additional libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
fkorotkov committed Feb 16, 2022
1 parent 139f305 commit 2c78cea
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 0 deletions.
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,85 @@
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.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");


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");


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

0 comments on commit 2c78cea

Please sign in to comment.