@NotNull public static PsiClass[] getPsiClasses(@NotNull PsiDirectory dir, PsiFile[] psiFiles) { FileIndexFacade index = FileIndexFacade.getInstance(dir.getProject()); VirtualFile virtualDir = dir.getVirtualFile(); boolean onlyCompiled = index.isInLibraryClasses(virtualDir) && !index.isInSourceContent(virtualDir); List<PsiClass> classes = null; for (PsiFile file : psiFiles) { if (onlyCompiled && !(file instanceof ClsFileImpl)) { continue; } if (file instanceof PsiClassOwner && file.getViewProvider().getLanguages().size() == 1) { PsiClass[] psiClasses = ((PsiClassOwner)file).getClasses(); if (psiClasses.length == 0) continue; if (classes == null) classes = new ArrayList<PsiClass>(); ContainerUtil.addAll(classes, psiClasses); } } return classes == null ? PsiClass.EMPTY_ARRAY : classes.toArray(new PsiClass[classes.size()]); }
/** * SyntaxHighlighterProvider implementation (for .class files). */ @Nullable @Override public SyntaxHighlighter create(@NotNull FileType fileType, @Nullable Project project, @Nullable VirtualFile file) { if (project != null && file != null) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (fileType == JavaClassFileType.INSTANCE && psiFile != null) { Language language = psiFile.getLanguage(); if (language != JavaLanguage.INSTANCE) { return SyntaxHighlighterFactory.getSyntaxHighlighter(language, project, file); } } if (psiFile instanceof ClsFileImpl) { LanguageLevel sourceLevel = ((ClsFileImpl)psiFile).getLanguageLevel(); return new JavaFileHighlighter(sourceLevel); } } return new JavaFileHighlighter(); }
@Nullable private Result<PsiFile> getPsiFile(ClsFileImpl file) { Project project = file.getProject(); BlazeProjectData blazeProjectData = BlazeProjectDataManager.getInstance(project).getBlazeProjectData(); if (blazeProjectData == null) { return null; } VirtualFile root = getSourceJarRoot(project, blazeProjectData, file); if (root == null) { return null; } return getSourceFileResult(file, root); }
@Override protected PsiFile createFile(@NotNull final Project project, @NotNull final VirtualFile vFile, @NotNull final FileType fileType) { final FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class); if (fileIndex.isInLibraryClasses(vFile) || !fileIndex.isInSource(vFile)) { String name = vFile.getName(); // skip inners & anonymous (todo: read actual class name from file) int dotIndex = name.lastIndexOf('.'); if (dotIndex < 0) dotIndex = name.length(); int index = name.lastIndexOf('$', dotIndex); if (index <= 0 || index == dotIndex - 1) { return new ClsFileImpl((PsiManagerImpl)PsiManager.getInstance(project), this); } } return null; }
@NotNull @Override public PsiClass[] getClasses(@NotNull PsiDirectory dir) { LOG.assertTrue(dir.isValid()); FileIndexFacade index = FileIndexFacade.getInstance(dir.getProject()); VirtualFile virtualDir = dir.getVirtualFile(); boolean onlyCompiled = index.isInLibraryClasses(virtualDir) && !index.isInSourceContent(virtualDir); List<PsiClass> classes = null; for (PsiFile file : dir.getFiles()) { if (onlyCompiled && !(file instanceof ClsFileImpl)) { continue; } if (file instanceof PsiClassOwner && file.getViewProvider().getLanguages().size() == 1) { PsiClass[] psiClasses = ((PsiClassOwner)file).getClasses(); if (psiClasses.length == 0) continue; if (classes == null) classes = new ArrayList<PsiClass>(); ContainerUtil.addAll(classes, psiClasses); } } return classes == null ? PsiClass.EMPTY_ARRAY : classes.toArray(new PsiClass[classes.size()]); }
private static void doTest(String name) { String testDir = JavaTestUtil.getJavaTestDataPath() + "/psi/cls/mirror/"; String clsPath = testDir + "pkg/" + name + ".class"; VirtualFile vFile = LocalFileSystem.getInstance().findFileByPath(clsPath); assertNotNull(clsPath, vFile); PsiFile clsFile = getPsiManager().findFile(vFile); assertNotNull(vFile.getPath(), clsFile); String expected; try { String txtPath = testDir + name + ".txt"; expected = StringUtil.trimTrailing(PlatformTestUtil.loadFileText(txtPath)); } catch (IOException e) { fail(e.getMessage()); return; } assertEquals(expected, ((ClsFileImpl)clsFile).getMirror().getText()); }
@Override protected PsiFile createFile(@NotNull Project project, @NotNull VirtualFile file, @NotNull FileType fileType) { FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class); if(!fileIndex.isInLibraryClasses(file) && fileIndex.isInSource(file) || fileIndex.isExcludedFile(file)) { return new PsiBinaryFileImpl((PsiManagerImpl) getManager(), this); } // skip inner, anonymous, missing and corrupted classes try { if(!isInnerClass(file)) { return new ClsFileImpl(this); } } catch(Exception e) { Logger.getInstance(ClassFileViewProvider.class).debug(file.getPath(), e); } return null; }
@Override protected PsiFile createFile(@NotNull final Project project, @NotNull final VirtualFile vFile, @NotNull final FileType fileType) { FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class); if (!fileIndex.isInLibraryClasses(vFile) && fileIndex.isInSource(vFile)) { return null; } // skip inners & anonymous if (isInnerClass(vFile)) return null; return new ClsFileImpl(this); }
private static void doTest(String clsPath, String txtPath) { VirtualFile file = (clsPath.contains("!/") ? StandardFileSystems.jar() : StandardFileSystems.local()).findFileByPath(clsPath); assertNotNull(clsPath, file); String expected; try { expected = StringUtil.trimTrailing(PlatformTestUtil.loadFileText(txtPath)); } catch (IOException e) { throw new RuntimeException(e); } assertEquals(expected, ClsFileImpl.decompile(file).toString()); }
private static PsiJavaFile getFile(String name) { String path = PathManagerEx.getTestDataPath() + TEST_DATA_PATH + "/pack/" + name + ".class"; VirtualFile file = LocalFileSystem.getInstance().findFileByPath(path); assertNotNull(path, file); PsiFile clsFile = PsiManager.getInstance(getProject()).findFile(file); assertTrue(String.valueOf(clsFile), clsFile instanceof ClsFileImpl); return (PsiJavaFile)clsFile; }
@Override public boolean visitFile(@NotNull VirtualFile file) { if (file.isDirectory()) { System.out.println(file.getPath()); } else if (file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$")) { PsiFile clsFile = getPsiManager().findFile(file); assertNotNull(file.getPath(), clsFile); PsiElement mirror = ((ClsFileImpl)clsFile).getMirror(); String decompiled = mirror.getText(); assertTrue(file.getPath(), decompiled.contains(file.getNameWithoutExtension())); // check that no mapped line number is on an empty line String prefix = "// "; for (String s : decompiled.split("\n")) { int pos = s.indexOf(prefix); if (pos == 0 && prefix.length() < s.length() && Character.isDigit(s.charAt(prefix.length()))) { fail("Incorrect line mapping in file " + file.getPath() + " line: " + s); } } } else if (ArchiveFileType.INSTANCE.equals(file.getFileType())) { VirtualFile jarFile = StandardFileSystems.getJarRootForLocalFile(file); if (jarFile != null) { VfsUtilCore.visitChildrenRecursively(jarFile, new MyFileVisitor()); } } return true; }
@Nullable @Override public PsiFile getFileNavigationElement(ClsFileImpl file) { return CachedValuesManager.getCachedValue( file, () -> { Result<PsiFile> result = getPsiFile(file); if (result == null) { result = notFound(file); } return result; }); }
@Nullable private Result<PsiFile> getSourceFileResult(ClsFileImpl clsFile, VirtualFile root) { // This code is adapted from JavaPsiImplementationHelperImpl#getClsFileNavigationElement PsiClass[] classes = clsFile.getClasses(); if (classes.length == 0) { return null; } String sourceFileName = ((ClsClassImpl) classes[0]).getSourceFileName(); String packageName = clsFile.getPackageName(); String relativePath = packageName.isEmpty() ? sourceFileName : packageName.replace('.', '/') + '/' + sourceFileName; VirtualFile source = root.findFileByRelativePath(relativePath); if (source != null && source.isValid()) { // Since we have an actual source jar tracked down, use that source jar as the modification // tracker. This means the result will continue to be cached unless that source jar changes. // If we didn't find a source jar, we use a modification tracker that invalidates on every // Blaze sync, which is less efficient. PsiFile psiSource = clsFile.getManager().findFile(source); if (psiSource instanceof PsiClassOwner) { return Result.create(psiSource, source); } return Result.create(null, source); } return null; }
private Result<PsiFile> notFound(ClsFileImpl file) { // A "not-found" result is null, but depends on the project sync tracker, so it will expire // after the next blaze sync. This means we'll run this check again after every sync for files // that don't have source jars, but it's not a huge deal because checking for the source jar // only takes a few microseconds. projectSyncTrackers.putIfAbsent(file.getProject(), new SimpleModificationTracker()); return Result.create(null, projectSyncTrackers.get(file.getProject())); }
/** * SyntaxHighlighterProvider implementation (for class files). */ @Nullable @Override public SyntaxHighlighter create(FileType fileType, @Nullable Project project, @Nullable VirtualFile file) { if (project != null && file != null) { PsiFile psiFile = PsiManager.getInstance(project).findFile(file); if (psiFile instanceof ClsFileImpl) { LanguageLevel sourceLevel = ((ClsFileImpl)psiFile).getSourceLanguageLevel(); return new JavaFileHighlighter(sourceLevel); } } return new JavaFileHighlighter(); }