2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.jetbrains.java.decompiler;
18 import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory;
19 import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
20 import com.intellij.debugger.PositionManager;
21 import com.intellij.openapi.application.PluginPathManager;
22 import com.intellij.openapi.fileTypes.StdFileTypes;
23 import com.intellij.openapi.util.SystemInfo;
24 import com.intellij.openapi.util.registry.Registry;
25 import com.intellij.openapi.util.registry.RegistryValue;
26 import com.intellij.openapi.vfs.StandardFileSystems;
27 import com.intellij.openapi.vfs.VfsUtilCore;
28 import com.intellij.openapi.vfs.VirtualFile;
29 import com.intellij.openapi.vfs.VirtualFileVisitor;
30 import com.intellij.pom.Navigatable;
31 import com.intellij.psi.PsiElement;
32 import com.intellij.psi.PsiFile;
33 import com.intellij.psi.impl.compiled.ClsFileImpl;
34 import com.intellij.testFramework.PlatformTestUtil;
35 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
36 import com.intellij.util.containers.ContainerUtil;
37 import org.jetbrains.annotations.NotNull;
41 public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase {
43 protected void setUp() throws Exception {
45 myFixture.setTestDataPath(PluginPathManager.getPluginHomePath("java-decompiler") + "/plugin/testData");
48 public void testSimple() {
49 String path = PlatformTestUtil.getRtJarPath() + "!/java/lang/String.class";
50 VirtualFile file = StandardFileSystems.jar().findFileByPath(path);
51 assertNotNull(path, file);
53 String decompiled = new IdeaDecompiler().getText(file).toString();
54 assertTrue(decompiled, decompiled.startsWith(IdeaDecompiler.BANNER + "package java.lang;\n"));
55 assertTrue(decompiled, decompiled.contains("public final class String"));
56 assertTrue(decompiled, decompiled.contains("@deprecated"));
57 assertTrue(decompiled, decompiled.contains("private static class CaseInsensitiveComparator"));
58 assertFalse(decompiled, decompiled.contains("{ /* compiled code */ }"));
59 assertFalse(decompiled, decompiled.contains("synthetic"));
62 public void testStubCompatibility() {
63 String path = PlatformTestUtil.getRtJarPath() + "!/java";
64 VirtualFile dir = StandardFileSystems.jar().findFileByPath(path);
65 assertNotNull(path, dir);
66 doTestStubCompatibility(dir);
69 private void doTestStubCompatibility(VirtualFile root) {
70 VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
72 public boolean visitFile(@NotNull VirtualFile file) {
73 if (file.isDirectory()) {
74 System.out.println(file.getPath());
76 else if (file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$") && !skip(file)) {
77 PsiFile clsFile = getPsiManager().findFile(file);
78 assertNotNull(file.getPath(), clsFile);
79 PsiElement mirror = ((ClsFileImpl)clsFile).getMirror();
80 String decompiled = mirror.getText();
81 assertTrue(file.getPath(), decompiled.contains(file.getNameWithoutExtension()));
86 private boolean skip(VirtualFile file) {
87 if (!SystemInfo.isJavaVersionAtLeast("1.8")) return false;
88 String path = file.getPath();
89 int p = path.indexOf("!/");
90 return p > 0 && knowProblems.contains(path.substring(p + 2));
93 // todo[r.sh] drop when IDEA-129734 get fixed
94 private final Set<String> knowProblems = ContainerUtil.newHashSet(
95 "java/lang/reflect/AnnotatedElement.class", "java/util/stream/Nodes.class", "java/util/stream/FindOps.class",
96 "java/util/stream/Collectors.class", "java/util/stream/DistinctOps.class", "java/util/stream/IntPipeline.class",
97 "java/util/stream/LongPipeline.class", "java/util/stream/DoublePipeline.class"
102 public void testNavigation() {
103 myFixture.openFileInEditor(getTestFile("Navigation.class"));
104 doTestNavigation(11, 14, 14, 10); // to "m2()"
105 doTestNavigation(15, 21, 14, 17); // to "int i"
106 doTestNavigation(16, 28, 15, 13); // to "int r"
109 public void testHighlighting() {
110 myFixture.openFileInEditor(getTestFile("Navigation.class"));
111 IdentifierHighlighterPassFactory.doWithHighlightingEnabled(new Runnable() {
113 myFixture.getEditor().getCaretModel().moveToOffset(offset(11, 14)); // m2(): usage, declaration
114 assertEquals(2, myFixture.doHighlighting().size());
115 myFixture.getEditor().getCaretModel().moveToOffset(offset(15, 21)); // int i: usage, declaration
116 assertEquals(2, myFixture.doHighlighting().size());
117 myFixture.getEditor().getCaretModel().moveToOffset(offset(16, 28)); // int r: usage, declaration
118 assertEquals(2, myFixture.doHighlighting().size());
119 myFixture.getEditor().getCaretModel().moveToOffset(offset(19, 24)); // throws: declaration, m4() call
120 assertEquals(2, myFixture.doHighlighting().size());
125 private VirtualFile getTestFile(String name) {
126 String path = myFixture.getTestDataPath() + "/" + name;
127 VirtualFile file = StandardFileSystems.local().refreshAndFindFileByPath(path);
128 assertNotNull(path, file);
132 private void doTestNavigation(int line, int column, int expectedLine, int expectedColumn) {
133 PsiElement target = GotoDeclarationAction.findTargetElement(getProject(), myFixture.getEditor(), offset(line, column));
134 assertTrue(String.valueOf(target), target instanceof Navigatable);
135 ((Navigatable)target).navigate(true);
136 int expected = offset(expectedLine, expectedColumn);
137 assertEquals(expected, myFixture.getCaretOffset());
140 private int offset(int line, int column) {
141 return myFixture.getEditor().getDocument().getLineStartOffset(line - 1) + column - 1;
144 public void testLineNumberMapping() {
145 RegistryValue value = Registry.get("decompiler.use.line.mapping");
146 boolean old = value.asBoolean();
148 value.setValue(true);
150 VirtualFile file = getTestFile("LineNumbers.class");
151 assertNull(file.getUserData(PositionManager.LINE_NUMBERS_MAPPING_KEY));
153 new IdeaDecompiler().getText(file);
155 int[] mapping = file.getUserData(PositionManager.LINE_NUMBERS_MAPPING_KEY);
156 assertNotNull(mapping);
157 assertEquals(20, mapping.length);