diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ExtUtils.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ExtUtils.java index a699f415..1f787dbc 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ExtUtils.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ExtUtils.java @@ -13,19 +13,27 @@ import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.core.IJarEntryResource; +import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.core.JarEntryDirectory; import org.eclipse.jdt.internal.core.JarEntryFile; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; public final class ExtUtils { - - private static final String JDT_SCHEME = "jdt"; - + public static final String JDT_SCHEME = "jdt"; private static final String CONTENTS_AUTHORITY = "jarentry"; - public static String toUri(JarEntryFile jarEntryFile) { + public static String toUri(IJarEntryResource jarEntryFile) { IPackageFragmentRoot fragmentRoot = jarEntryFile.getPackageFragmentRoot(); try { return new URI(JDT_SCHEME, CONTENTS_AUTHORITY, jarEntryFile.getFullPath().toPortableString(), fragmentRoot.getHandleIdentifier(), null).toASCIIString(); @@ -35,10 +43,79 @@ public static String toUri(JarEntryFile jarEntryFile) { } } + public static boolean isJarResourceUri(URI uri) { + return uri != null && JDT_SCHEME.equals(uri.getScheme()) && CONTENTS_AUTHORITY.equals(uri.getAuthority()); + } + + public static JarEntryFile findJarEntryFile(IPackageFragmentRoot packageRoot, String path) throws JavaModelException { + String[] segments = StringUtils.split(path, "/"); + String packageName = StringUtils.join(Arrays.asList(segments).subList(0, segments.length - 1), '.'); + IPackageFragment packageFragment = packageRoot.getPackageFragment(packageName); + if (packageFragment != null && packageFragment.exists()) { + Object[] objs = packageFragment.getNonJavaResources(); + for (Object obj : objs) { + if (obj instanceof IJarEntryResource) { + IJarEntryResource child = (IJarEntryResource) obj; + if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) { + return (JarEntryFile) child; + } + } + } + } + Object[] resources = packageRoot.getNonJavaResources(); + + for (Object resource : resources) { + if (resource instanceof JarEntryFile) { + JarEntryFile file = (JarEntryFile) resource; + if (file.getFullPath().toPortableString().equals(path)) { + return file; + } + } + if (resource instanceof JarEntryDirectory) { + JarEntryDirectory directory = (JarEntryDirectory) resource; + JarEntryFile file = findFileInJar(directory, path); + if (file != null) { + return file; + } + } + } + return null; + } + + public static IJarEntryResource getJarEntryResource(URI uri) throws CoreException { + if (uri == null) { + throw new NullPointerException("Cannot get jar resource from null URI."); + } + String handleId = uri.getQuery(); + if (handleId == null) { + throw new NullPointerException("Invalid uri for a jar entry."); + } + IPackageFragmentRoot packageRoot = (IPackageFragmentRoot) JavaCore.create(handleId); + if (packageRoot == null) { + throw new CoreException(new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", handleId))); + } + return findJarEntryFile(packageRoot, uri.getPath()); + } + public static IPath removeProjectSegment(String projectElementName, IPath path) { if (projectElementName.equals(path.segment(0))) { return path.removeFirstSegments(1).makeRelative(); } return path; } + + private static JarEntryFile findFileInJar(JarEntryDirectory directory, String path) { + for (IJarEntryResource child : directory.getChildren()) { + if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) { + return (JarEntryFile) child; + } + if (child instanceof JarEntryDirectory) { + JarEntryFile file = findFileInJar((JarEntryDirectory) child, path); + if (file != null) { + return file; + } + } + } + return null; + } } diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java index 5be1940c..7058e7ff 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/JarFileContentProvider.java @@ -15,19 +15,14 @@ import java.io.InputStream; import java.net.URI; import java.nio.charset.StandardCharsets; -import java.util.Arrays; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.core.IJarEntryResource; -import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.internal.core.JarEntryDirectory; import org.eclipse.jdt.internal.core.JarEntryFile; import org.eclipse.jdt.internal.core.JarPackageFragmentRoot; import org.eclipse.jdt.ls.core.internal.IContentProvider; @@ -49,40 +44,12 @@ private String getContent(String rootId, String path, IProgressMonitor pm) { if (packageRoot == null) { throw new CoreException(new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", rootId))); } - if (packageRoot instanceof JarPackageFragmentRoot) { - Object[] resources = packageRoot.getNonJavaResources(); - - for (Object resource : resources) { - if (resource instanceof JarEntryFile) { - JarEntryFile file = (JarEntryFile) resource; - if (file.getFullPath().toPortableString().equals(path)) { - return readFileContent(file); - } - } - if (resource instanceof JarEntryDirectory) { - JarEntryDirectory directory = (JarEntryDirectory) resource; - JarEntryFile file = findFileInJar(directory, path); - if (file != null) { - return readFileContent(file); - } - } - } - // if the file exists in the java packages - String[] segments = StringUtils.split(path, "/"); - String packageName = StringUtils.join(Arrays.asList(segments).subList(0, segments.length - 1), '.'); - IPackageFragment packageFragment = packageRoot.getPackageFragment(packageName); - if (packageFragment != null && packageFragment.exists()) { - Object[] objs = packageFragment.getNonJavaResources(); - for (Object obj : objs) { - if (obj instanceof IJarEntryResource) { - IJarEntryResource child = (IJarEntryResource) obj; - if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) { - return readFileContent((JarEntryFile) child); - } - } - } + if (packageRoot instanceof JarPackageFragmentRoot) { + JarEntryFile fileEntry = ExtUtils.findJarEntryFile(packageRoot, path); + if (fileEntry != null) { + return readFileContent(fileEntry); } } @@ -92,20 +59,7 @@ private String getContent(String rootId, String path, IProgressMonitor pm) { return null; } - private static JarEntryFile findFileInJar(JarEntryDirectory directory, String path) { - for (IJarEntryResource child : directory.getChildren()) { - if (child instanceof JarEntryFile && child.getFullPath().toPortableString().equals(path)) { - return (JarEntryFile) child; - } - if (child instanceof JarEntryDirectory) { - JarEntryFile file = findFileInJar((JarEntryDirectory) child, path); - if (file != null) { - return file; - } - } - } - return null; - } + private static String readFileContent(JarEntryFile file) throws CoreException { try (InputStream stream = (file.getContents())) { diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java index 7353d02a..dea4fd38 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/PackageCommand.java @@ -25,6 +25,7 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; @@ -35,9 +36,7 @@ import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IClassFile; -import org.eclipse.jdt.core.IClasspathContainer; import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJarEntryResource; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; @@ -56,7 +55,6 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.microsoft.jdtls.ext.core.model.ContainerNode; import com.microsoft.jdtls.ext.core.model.NodeKind; import com.microsoft.jdtls.ext.core.model.PackageNode; import com.microsoft.jdtls.ext.core.model.PackageRootNode; @@ -65,15 +63,6 @@ @SuppressWarnings("deprecation") public class PackageCommand { - private static final String DEFAULT_PACKAGE_DISPLAYNAME = "(default package)"; - - private static final String REFERENCED_LIBRARIES_PATH = "REFERENCED_LIBRARIES_PATH"; - - private static final String REFERENCED_LIBRARIES_CONTAINER_NAME = "Referenced Libraries"; - - private static final ContainerNode REFERENCED_LIBRARIES_CONTAINER = new ContainerNode(REFERENCED_LIBRARIES_CONTAINER_NAME, REFERENCED_LIBRARIES_PATH, - NodeKind.CONTAINER, IClasspathEntry.CPE_CONTAINER); - private static final Gson gson = new GsonBuilder().registerTypeAdapterFactory(new CollectionTypeAdapterFactory()) .registerTypeAdapterFactory(new EnumTypeAdapterFactory()).create(); @@ -101,7 +90,7 @@ public class PackageCommand { */ public static List getChildren(List arguments, IProgressMonitor pm) throws CoreException { if (arguments == null || arguments.size() < 1) { - throw new IllegalArgumentException("Should have at least one arugment for getChildren"); + throw new IllegalArgumentException("Should have at least one argument for getChildren"); } PackageParams params = gson.fromJson(gson.toJson(arguments.get(0)), PackageParams.class); BiFunction> loader = commands.get(params.getKind()); @@ -124,68 +113,122 @@ public static List getChildren(List arguments, IProgressMon */ public static List resolvePath(List arguments, IProgressMonitor pm) throws CoreException { if (arguments == null || arguments.size() < 1) { - throw new IllegalArgumentException("Should have one arugment for resolvePath"); + throw new IllegalArgumentException("Should have one argument for resolvePath"); } String typeRootUri = (String) arguments.get(0); - List result = new ArrayList<>(); - URI uri = JDTUtils.toURI(typeRootUri); - ITypeRoot typeRoot = null; - if ("jdt".equals(uri.getScheme())) { - typeRoot = JDTUtils.resolveClassFile(uri); - } else { - typeRoot = JDTUtils.resolveCompilationUnit(uri); - } + ITypeRoot typeRoot = ExtUtils.JDT_SCHEME.equals(uri.getScheme()) ? JDTUtils.resolveClassFile(uri) : JDTUtils.resolveCompilationUnit(uri); if (typeRoot != null) { // Add project node: - IProject proj = typeRoot.getJavaProject().getProject(); - PackageNode projectNode = new PackageNode(proj.getName(), proj.getFullPath().toPortableString(), NodeKind.PROJECT); - projectNode.setUri(proj.getLocationURI().toString()); - result.add(projectNode); - + result.add(PackageNode.createNodeForProject(typeRoot)); IPackageFragment packageFragment = (IPackageFragment) typeRoot.getParent(); - String packageName = packageFragment.isDefaultPackage() ? DEFAULT_PACKAGE_DISPLAYNAME : packageFragment.getElementName(); - PackageNode packageNode = new PackageNode(packageName, packageFragment.getPath().toPortableString(), NodeKind.PACKAGE); IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) packageFragment.getParent(); - PackageNode rootNode = null; - if (typeRoot instanceof IClassFile) { - IClasspathEntry entry = pkgRoot.getRawClasspathEntry(); - // Process Referenced Variable - if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - rootNode = getNodeFromClasspathVariable(entry); - } else { - rootNode = new PackageRootNode(pkgRoot.getElementName(), pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); - } - } else { - rootNode = new PackageRootNode(ExtUtils.removeProjectSegment(typeRoot.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), - pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); - } // TODO: Let the client handle the display instead. Server side should always // provide the container node. - if (typeRoot instanceof IClassFile) { - IClasspathEntry entry = pkgRoot.getRawClasspathEntry(); - IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), typeRoot.getJavaProject()); - PackageNode containerNode = null; - if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { - containerNode = REFERENCED_LIBRARIES_CONTAINER; - } else { - containerNode = new ContainerNode(container.getDescription(), container.getPath().toPortableString(), NodeKind.CONTAINER, - entry.getEntryKind()); - } - result.add(containerNode); + boolean isClassFile = typeRoot instanceof IClassFile; + if (isClassFile) { + result.add(PackageNode.createNodeForVirtualContainer(pkgRoot)); } - result.add(rootNode); - result.add(packageNode); + result.add(PackageNode.createNodeForPackageFragmentRoot(pkgRoot)); + result.add(PackageNode.createNodeForPackageFragment(packageFragment)); PackageNode item = new TypeRootNode(typeRoot.getElementName(), typeRoot.getPath().toPortableString(), NodeKind.TYPEROOT, TypeRootNode.K_SOURCE); item.setUri(JDTUtils.toUri(typeRoot)); result.add(item); + } else if (ExtUtils.isJarResourceUri(uri)) { + IJarEntryResource resource = ExtUtils.getJarEntryResource(uri); + IPackageFragmentRoot pkgRoot = resource.getPackageFragmentRoot(); + result.add(PackageNode.createNodeForProject(pkgRoot)); + result.add(PackageNode.createNodeForVirtualContainer(resource.getPackageFragmentRoot())); + result.add(PackageNode.createNodeForPackageFragmentRoot(pkgRoot)); + if (resource.getParent() instanceof IPackageFragment) { + IPackageFragment packageFragment = (IPackageFragment) resource.getParent(); + result.add(PackageNode.createNodeForPackageFragment(packageFragment)); + } else { + int currentSize = result.size(); + // visit back from file to the top folder + Object currentNode = resource.getParent(); + while (currentNode instanceof JarEntryDirectory) { + JarEntryDirectory jarEntryDirectory = (JarEntryDirectory) currentNode; + PackageNode jarNode = getJarEntryResource(jarEntryDirectory); + if (jarNode != null) { + result.add(currentSize, jarNode); + } + currentNode = jarEntryDirectory.getParent(); + } + } + + PackageNode item = new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FILE); + item.setUri(ExtUtils.toUri(resource)); + result.add(item); + } else { + // this is not a .java/.class file + IResource resource = JDTUtils.findResource(uri, ResourcesPlugin.getWorkspace().getRoot()::findFilesForLocationURI); + if (resource != null) { + IResource parent = resource.getParent(); + IJavaElement parentJavaElement = JavaCore.create(parent); + if (parent instanceof IFolder && parentJavaElement instanceof IPackageFragment) { + IPackageFragment packageFragment = (IPackageFragment) parentJavaElement; + IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) packageFragment.getParent(); + PackageNode rootNode = null; + + rootNode = new PackageRootNode( + ExtUtils.removeProjectSegment(packageFragment.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), + pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + + result.add(PackageNode.createNodeForProject(packageFragment)); + result.add(rootNode); + result.add(PackageNode.createNodeForPackageFragment(packageFragment)); + + PackageNode item = new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FILE); + item.setUri(JDTUtils.getFileURI(resource)); + result.add(item); + } else { + return getParentAncestorNodes(resource); + } + } } return result; } + + /** + * Get the node list from bottom to top until project + * + * @param element + * @return + * @throws JavaModelException + */ + private static List getParentAncestorNodes(IResource element) throws JavaModelException { + List nodeList = new ArrayList<>(); + while (element != null) { + IJavaElement javaElement = JavaCore.create(element); + if (javaElement instanceof IPackageFragmentRoot) { + IPackageFragmentRoot pkgRoot = (IPackageFragmentRoot) javaElement; + nodeList.add(0, new PackageRootNode(element.getProjectRelativePath().toPortableString(), pkgRoot.getPath().toPortableString(), + NodeKind.PACKAGEROOT, pkgRoot.getKind())); + nodeList.add(0, PackageNode.createNodeForProject(javaElement)); + return nodeList; + } else if (javaElement instanceof IPackageFragment) { + IPackageFragment packageFragment = (IPackageFragment) javaElement; + if (packageFragment.containsJavaResources() || packageFragment.getNonJavaResources().length > 0) { + nodeList.add(0, PackageNode.createNodeForPackageFragment(packageFragment)); + } + + } else if (javaElement == null) { + PackageNode entry = PackageNode.createNodeForResource(element); + if (entry != null) { + nodeList.add(0, entry); + } + } + element = element.getParent(); + } + + return nodeList; + } + /** * Get the class path container list. */ @@ -196,12 +239,13 @@ private static List getContainers(PackageParams query, IProgressMon IClasspathEntry[] references = javaProject.getRawClasspath(); List result = Arrays.stream(references) .filter(entry -> entry.getEntryKind() != IClasspathEntry.CPE_LIBRARY && entry.getEntryKind() != IClasspathEntry.CPE_VARIABLE) - .map(entry -> getNodeFromClasspathEntry(entry, javaProject, NodeKind.CONTAINER)).filter(containerNode -> containerNode != null) + .map(entry -> PackageNode.createNodeForClasspathEntry(entry, javaProject, NodeKind.CONTAINER)) + .filter(containerNode -> containerNode != null) .collect(Collectors.toList()); boolean isReferencedLibrariesExist = Arrays.stream(references) .anyMatch(entry -> entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE); if (isReferencedLibrariesExist) { - result.add(REFERENCED_LIBRARIES_CONTAINER); + result.add(PackageNode.REFERENCED_LIBRARIES_CONTAINER); } return result; } catch (CoreException e) { @@ -211,57 +255,7 @@ private static List getContainers(PackageParams query, IProgressMon return Collections.emptyList(); } - /** - * Get the correspond node of classpath, it may be container or a package root - * - * @param classpathEntry - * classpath entry - * @param javaProject - * correspond java project - * @param nodeKind - * could be CONTAINER or PACKAGEROOT(for referenced libraries) - * @return correspond PackageNode of classpath entry - */ - private static PackageNode getNodeFromClasspathEntry(IClasspathEntry classpathEntry, IJavaProject javaProject, NodeKind nodeKind) { - try { - IClasspathEntry entry = JavaCore.getResolvedClasspathEntry(classpathEntry); - IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), javaProject); - // HACK: There is an initialization issue for the first container. - if (container == null) { - container = JavaCore.getClasspathContainer(entry.getPath(), javaProject); - } - if (container != null) { - switch (nodeKind) { - case CONTAINER: - return new ContainerNode(container.getDescription(), container.getPath().toPortableString(), nodeKind, entry.getEntryKind()); - case PACKAGEROOT: - // Use package name as package root name - String[] pathSegments = container.getPath().segments(); - return new PackageRootNode(pathSegments[pathSegments.length - 1], container.getPath().toPortableString(), nodeKind, - IPackageFragmentRoot.K_BINARY); - default: - return null; - } - } - } catch (CoreException e) { - JdtlsExtActivator.logException("Problems when convert classpath entry to package node ", e); - } - return null; - } - /** - * Get correspond node of referenced variable - * - * @param classpathEntry - * referenced cariable's classpath entry - * @return correspond package node - */ - private static PackageNode getNodeFromClasspathVariable(IClasspathEntry classpathEntry) { - IClasspathEntry entry = JavaCore.getResolvedClasspathEntry(classpathEntry); - String name = classpathEntry.getPath().toPortableString(); - String path = entry.getPath().toPortableString(); - return new PackageRootNode(name, path, NodeKind.PACKAGEROOT, IPackageFragmentRoot.K_BINARY); - } private static List getPackageFragmentRoots(PackageParams query, IProgressMonitor pm) { ArrayList children = new ArrayList<>(); @@ -292,13 +286,15 @@ private static List getPackageFragmentRoots(PackageParams query, IP } } return children; - } else if (query.getPath().equals(REFERENCED_LIBRARIES_PATH)) { + } else if (query.getPath().equals(PackageNode.REFERENCED_LIBRARIES_PATH)) { // Process referenced libraries List referLibs = Arrays.stream(references).filter(entry -> entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) - .map(classpath -> getNodeFromClasspathEntry(classpath, javaProject, NodeKind.PACKAGEROOT)).filter(entry -> entry != null) + .map(classpath -> PackageNode.createNodeForClasspathEntry(classpath, javaProject, NodeKind.PACKAGEROOT)) + .filter(entry -> entry != null) .collect(Collectors.toList()); List referVariables = Arrays.stream(references).filter(entry -> entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) - .map(classpath -> getNodeFromClasspathVariable(classpath)).filter(entry -> entry != null).collect(Collectors.toList()); + .map(classpath -> PackageNode.createNodeForClasspathVariable(classpath)).filter(entry -> entry != null) + .collect(Collectors.toList()); children.addAll(referLibs); children.addAll(referVariables); return children; @@ -338,20 +334,13 @@ private static List getRootTypes(PackageParams query, IProgressMoni throw new CoreException( new Status(IStatus.ERROR, JdtlsExtActivator.PLUGIN_ID, String.format("No package root found for %s", query.getPath()))); } - IPackageFragment packageFragment = packageRoot.getPackageFragment(DEFAULT_PACKAGE_DISPLAYNAME.equals(query.getPath()) ? "" : query.getPath()); + IPackageFragment packageFragment = packageRoot + .getPackageFragment(PackageNode.DEFAULT_PACKAGE_DISPLAYNAME.equals(query.getPath()) ? "" : query.getPath()); if (packageFragment != null) { IJavaElement[] types = packageFragment.getChildren(); Object[] nonJavaResources = packageFragment.getNonJavaResources(); - List rootTypeNodes = Arrays.stream(types).filter(typeRoot -> !typeRoot.getElementName().contains("$")).map(typeRoot -> { - PackageNode item = new TypeRootNode(typeRoot.getElementName(), typeRoot.getPath().toPortableString(), NodeKind.TYPEROOT, - typeRoot instanceof IClassFile ? TypeRootNode.K_BINARY : TypeRootNode.K_SOURCE); - if (typeRoot instanceof ICompilationUnit) { - item.setUri(JDTUtils.toURI((ICompilationUnit) typeRoot)); - } else if (typeRoot instanceof IClassFile) { - item.setUri(JDTUtils.toUri((IClassFile) typeRoot)); - } - return item; - }).collect(Collectors.toList()); + List rootTypeNodes = Arrays.stream(types).filter(typeRoot -> !typeRoot.getElementName().contains("$")) + .map(PackageNode::createNodeForTypeRoot).collect(Collectors.toList()); if (nonJavaResources.length == 0) { return rootTypeNodes; } @@ -440,10 +429,7 @@ private static List convertToPackageNode(Object[] rootContent, IPac List result = new ArrayList<>(); for (Object root : rootContent) { if (root instanceof IPackageFragment) { - IPackageFragment packageFragment = (IPackageFragment) root; - String packageName = packageFragment.isDefaultPackage() ? DEFAULT_PACKAGE_DISPLAYNAME : packageFragment.getElementName(); - PackageNode entry = new PackageNode(packageName, packageFragment.getPath().toPortableString(), NodeKind.PACKAGE); - result.add(entry); + result.add(PackageNode.createNodeForPackageFragment((IPackageFragment) root)); } else if (root instanceof IClassFile) { IClassFile classFile = (IClassFile) root; PackageNode entry = new PackageNode(classFile.getElementName(), null, NodeKind.TYPEROOT); @@ -483,7 +469,7 @@ private static PackageNode getJarEntryResource(JarEntryResource resource) { return new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FOLDER); } else if (resource instanceof JarEntryFile) { PackageNode entry = new PackageNode(resource.getName(), resource.getFullPath().toPortableString(), NodeKind.FILE); - entry.setUri(ExtUtils.toUri((JarEntryFile) resource)); + entry.setUri(ExtUtils.toUri(resource)); return entry; } return null; diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java index 1b6d5a6d..2b17d375 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/model/PackageNode.java @@ -13,12 +13,37 @@ import java.util.List; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.IClasspathContainer; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ls.core.internal.JDTUtils; + +import com.microsoft.jdtls.ext.core.ExtUtils; +import com.microsoft.jdtls.ext.core.JdtlsExtActivator; /** * Represent a PackageNode in the project view. */ public class PackageNode { + private static final String REFERENCED_LIBRARIES_CONTAINER_NAME = "Referenced Libraries"; + + public static final String REFERENCED_LIBRARIES_PATH = "REFERENCED_LIBRARIES_PATH"; + public static final String DEFAULT_PACKAGE_DISPLAYNAME = "(default package)"; + public static final ContainerNode REFERENCED_LIBRARIES_CONTAINER = new ContainerNode(REFERENCED_LIBRARIES_CONTAINER_NAME, REFERENCED_LIBRARIES_PATH, + NodeKind.CONTAINER, IClasspathEntry.CPE_CONTAINER); /** * The name of the PackageNode @@ -60,6 +85,125 @@ public PackageNode(String name, String path, NodeKind kind) { this.kind = kind; } + public static PackageNode createNodeForProject(IJavaElement javaElement) { + IProject proj = javaElement.getJavaProject().getProject(); + PackageNode projectNode = new PackageNode(proj.getName(), proj.getFullPath().toPortableString(), NodeKind.PROJECT); + projectNode.setUri(proj.getLocationURI().toString()); + return projectNode; + } + + public static PackageNode createNodeForResource(IResource resource) { + if (resource instanceof IFile) { + IFile file = (IFile) resource; + PackageNode entry = new PackageNode(file.getName(), file.getFullPath().toPortableString(), NodeKind.FILE); + entry.setUri(JDTUtils.getFileURI(file)); + return entry; + } else if (resource instanceof IFolder) { + IFolder folder = (IFolder) resource; + PackageNode entry = new PackageNode(folder.getName(), folder.getFullPath().toPortableString(), NodeKind.FOLDER); + entry.setUri(JDTUtils.getFileURI(folder)); + return entry; + } + return null; + } + + public static PackageNode createNodeForPackageFragment(IPackageFragment packageFragment) { + String packageName = packageFragment.isDefaultPackage() ? DEFAULT_PACKAGE_DISPLAYNAME : packageFragment.getElementName(); + return new PackageNode(packageName, packageFragment.getPath().toPortableString(), NodeKind.PACKAGE); + } + + public static PackageNode createNodeForVirtualContainer(IPackageFragmentRoot pkgRoot) throws JavaModelException { + IClasspathEntry entry = pkgRoot.getRawClasspathEntry(); + IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), pkgRoot.getJavaProject()); + PackageNode containerNode = null; + if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY || entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { + containerNode = REFERENCED_LIBRARIES_CONTAINER; + } else { + containerNode = new ContainerNode(container.getDescription(), container.getPath().toPortableString(), NodeKind.CONTAINER, entry.getEntryKind()); + } + return containerNode; + + } + + public static PackageNode createNodeForPackageFragmentRoot(IPackageFragmentRoot pkgRoot) throws JavaModelException { + boolean isSourcePath = pkgRoot.getKind() == IPackageFragmentRoot.K_SOURCE; + if (!isSourcePath) { + IClasspathEntry entry = pkgRoot.getRawClasspathEntry(); + // Process Referenced Variable + if (entry.getEntryKind() == IClasspathEntry.CPE_VARIABLE) { + return createNodeForClasspathVariable(entry); + } else { + return new PackageRootNode(pkgRoot.getElementName(), pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + } + } else { + return new PackageRootNode(ExtUtils.removeProjectSegment(pkgRoot.getJavaProject().getElementName(), pkgRoot.getPath()).toPortableString(), + pkgRoot.getPath().toPortableString(), NodeKind.PACKAGEROOT, pkgRoot.getKind()); + } + } + + /** + * Get the correspond node of classpath, it may be container or a package root + * + * @param classpathEntry + * classpath entry + * @param javaProject + * correspond java project + * @param nodeKind + * could be CONTAINER or PACKAGEROOT(for referenced libraries) + * @return correspond PackageNode of classpath entry + */ + public static PackageNode createNodeForClasspathEntry(IClasspathEntry classpathEntry, IJavaProject javaProject, NodeKind nodeKind) { + try { + IClasspathEntry entry = JavaCore.getResolvedClasspathEntry(classpathEntry); + IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), javaProject); + // HACK: There is an initialization issue for the first container. + if (container == null) { + container = JavaCore.getClasspathContainer(entry.getPath(), javaProject); + } + if (container != null) { + switch (nodeKind) { + case CONTAINER: + return new ContainerNode(container.getDescription(), container.getPath().toPortableString(), nodeKind, entry.getEntryKind()); + case PACKAGEROOT: + // Use package name as package root name + String[] pathSegments = container.getPath().segments(); + return new PackageRootNode(pathSegments[pathSegments.length - 1], container.getPath().toPortableString(), nodeKind, + IPackageFragmentRoot.K_BINARY); + default: + return null; + } + } + } catch (CoreException e) { + JdtlsExtActivator.logException("Problems when convert classpath entry to package node ", e); + } + return null; + } + + public static PackageNode createNodeForTypeRoot(IJavaElement typeRoot) { + PackageNode typeRootNode = new TypeRootNode(typeRoot.getElementName(), typeRoot.getPath().toPortableString(), NodeKind.TYPEROOT, + typeRoot instanceof IClassFile ? TypeRootNode.K_BINARY : TypeRootNode.K_SOURCE); + if (typeRoot instanceof ICompilationUnit) { + typeRootNode.setUri(JDTUtils.toURI((ICompilationUnit) typeRoot)); + } else if (typeRoot instanceof IClassFile) { + typeRootNode.setUri(JDTUtils.toUri((IClassFile) typeRoot)); + } + return typeRootNode; + } + + /** + * Get correspond node of referenced variable + * + * @param classpathEntry + * referenced variable's classpath entry + * @return correspond package node + */ + public static PackageNode createNodeForClasspathVariable(IClasspathEntry classpathEntry) { + IClasspathEntry entry = JavaCore.getResolvedClasspathEntry(classpathEntry); + String name = classpathEntry.getPath().toPortableString(); + String path = entry.getPath().toPortableString(); + return new PackageRootNode(name, path, NodeKind.PACKAGEROOT, IPackageFragmentRoot.K_BINARY); + } + public String getName() { return name; }