mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-30 10:20:15 +07:00
attach JDK Annotations automatically on JDK creation to fix IDEA-211771
GitOrigin-RevId: 975cffd646b68abb31a61eb6ac50de264c428cdc
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d5e8ba9e13
commit
5910039653
@@ -7,6 +7,7 @@ import com.intellij.codeInsight.ExternalAnnotationsManager;
|
||||
import com.intellij.codeInsight.daemon.GroupNames;
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.ide.util.treeView.AbstractTreeNode;
|
||||
import com.intellij.openapi.application.TransactionGuard;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.util.ProgressIndicatorBase;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -16,7 +17,6 @@ import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
|
||||
import com.intellij.openapi.roots.JdkUtils;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
@@ -52,7 +52,7 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MagicConstantInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
private static final Key<Boolean> NO_ANNOTATIONS_FOUND = Key.create("REPORTED_NO_ANNOTATIONS_FOUND");
|
||||
private static final Key<Boolean> ANNOTATIONS_BEING_ATTACHED = Key.create("REPORTED_NO_ANNOTATIONS_FOUND");
|
||||
|
||||
private static final CallMapper<AllowedValues> SPECIAL_CASES = new CallMapper<AllowedValues>()
|
||||
.register(CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_CALENDAR, "get").parameterTypes("int"),
|
||||
@@ -103,7 +103,12 @@ public class MagicConstantInspection extends AbstractBaseJavaLocalInspectionTool
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitJavaFile(PsiJavaFile file) {
|
||||
checkAnnotationsJarAttached(file, holder);
|
||||
if (!(file.getViewProvider() instanceof InjectedFileViewProvider)) {
|
||||
Runnable fix = getAttachAnnotationsJarFix(file.getProject());
|
||||
if (fix != null) {
|
||||
fix.run(); // try to attach automatically
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,55 +183,35 @@ public class MagicConstantInspection extends AbstractBaseJavaLocalInspectionTool
|
||||
@Override
|
||||
public void cleanup(@NotNull Project project) {
|
||||
super.cleanup(project);
|
||||
project.putUserData(NO_ANNOTATIONS_FOUND, null);
|
||||
project.putUserData(ANNOTATIONS_BEING_ATTACHED, null);
|
||||
}
|
||||
|
||||
private static void checkAnnotationsJarAttached(@NotNull PsiFile file, @NotNull ProblemsHolder holder) {
|
||||
if (file.getViewProvider() instanceof InjectedFileViewProvider) return;
|
||||
// returns fix to apply if our own JB "jdkAnnotations" are not attached to the current jdk
|
||||
public static Runnable getAttachAnnotationsJarFix(Project project) {
|
||||
final Boolean found = project.getUserData(ANNOTATIONS_BEING_ATTACHED);
|
||||
if (found != null) return null;
|
||||
|
||||
final Project project = file.getProject();
|
||||
if (!holder.isOnTheFly()) {
|
||||
final Boolean found = project.getUserData(NO_ANNOTATIONS_FOUND);
|
||||
if (found != null) return;
|
||||
}
|
||||
|
||||
PsiClass event = JavaPsiFacade.getInstance(project).findClass("java.awt.event.InputEvent", GlobalSearchScope.allScope(project));
|
||||
if (event == null) return; // no jdk to attach
|
||||
PsiMethod[] methods = event.findMethodsByName("getModifiers", false);
|
||||
if (methods.length != 1) return; // no jdk to attach
|
||||
PsiClass awtInputEvent = JavaPsiFacade.getInstance(project).findClass("java.awt.event.InputEvent", GlobalSearchScope.allScope(project));
|
||||
if (awtInputEvent == null) return null;
|
||||
PsiMethod[] methods = awtInputEvent.findMethodsByName("getModifiers", false);
|
||||
if (methods.length != 1) return null;
|
||||
PsiMethod getModifiers = methods[0];
|
||||
PsiAnnotation annotation = ExternalAnnotationsManager.getInstance(project).findExternalAnnotation(getModifiers, MagicConstant.class.getName());
|
||||
if (annotation != null) return;
|
||||
Sdk jdk = JdkUtils.getJdkForElement(getModifiers);
|
||||
if (jdk == null) return; // no jdk to attach
|
||||
if (jdk == null) return null;
|
||||
PsiAnnotation annotation = ExternalAnnotationsManager.getInstance(project).findExternalAnnotation(getModifiers, MagicConstant.class.getName());
|
||||
return annotation == null ? () -> attachAnnotationsLaterTo(project, jdk) : null;
|
||||
}
|
||||
|
||||
if (!holder.isOnTheFly()) {
|
||||
project.putUserData(NO_ANNOTATIONS_FOUND, Boolean.TRUE);
|
||||
}
|
||||
|
||||
final Sdk finalJdk = jdk;
|
||||
|
||||
String path = finalJdk.getHomePath();
|
||||
String text = "No IDEA annotations attached to the JDK " + finalJdk.getName() + (path == null ? "" : " (" + FileUtil.toSystemDependentName(path) + ")")
|
||||
+", some issues will not be found";
|
||||
holder.registerProblem(file, text, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, new LocalQuickFix() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Attach annotations";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiElement getElementToMakeWritable(@NotNull PsiFile file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
SdkModificator modificator = finalJdk.getSdkModificator();
|
||||
JavaSdkImpl.attachJdkAnnotations(modificator);
|
||||
modificator.commitChanges();
|
||||
private static void attachAnnotationsLaterTo(@NotNull Project project, @NotNull Sdk sdk) {
|
||||
project.putUserData(ANNOTATIONS_BEING_ATTACHED, Boolean.TRUE);
|
||||
TransactionGuard.submitTransaction(project, () -> {
|
||||
SdkModificator modificator = sdk.getSdkModificator();
|
||||
boolean success = JavaSdkImpl.attachIDEAAnnotationsToJdk(modificator);
|
||||
// daemon will restart automatically
|
||||
modificator.commitChanges();
|
||||
// avoid endless loop on JDK misconfigration
|
||||
if (success) {
|
||||
project.putUserData(ANNOTATIONS_BEING_ATTACHED, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -416,7 +401,6 @@ public class MagicConstantInspection extends AbstractBaseJavaLocalInspectionTool
|
||||
|
||||
@Nullable
|
||||
static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, @Nullable PsiType type, @Nullable Set<? super PsiClass> visited) {
|
||||
|
||||
PsiManager manager = element.getManager();
|
||||
for (PsiAnnotation annotation : getAllAnnotations(element)) {
|
||||
if (type != null && MagicConstant.class.getName().equals(annotation.getQualifiedName())) {
|
||||
|
||||
@@ -263,29 +263,12 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
}
|
||||
|
||||
public static void attachJdkAnnotations(@NotNull SdkModificator modificator) {
|
||||
LocalFileSystem lfs = LocalFileSystem.getInstance();
|
||||
attachIDEAAnnotationsToJdk(modificator);
|
||||
}
|
||||
|
||||
public static boolean attachIDEAAnnotationsToJdk(@NotNull SdkModificator modificator) {
|
||||
List<String> pathsChecked = new ArrayList<>();
|
||||
|
||||
// community idea under idea
|
||||
String path = FileUtil.toSystemIndependentName(PathManager.getCommunityHomePath()) + "/java/jdkAnnotations";
|
||||
VirtualFile root = lfs.findFileByPath(path);
|
||||
pathsChecked.add(path);
|
||||
|
||||
if (root == null) { // build
|
||||
String javaPluginClassesRootPath = PathManager.getJarPathForClass(JavaSdkImpl.class);
|
||||
LOG.assertTrue(javaPluginClassesRootPath != null);
|
||||
File javaPluginClassesRoot = new File(javaPluginClassesRootPath);
|
||||
if (javaPluginClassesRoot.isFile()) {
|
||||
String annotationsJarPath = FileUtil.toSystemIndependentName(new File(javaPluginClassesRoot.getParentFile(), "jdkAnnotations.jar").getAbsolutePath());
|
||||
root = VirtualFileManager.getInstance().findFileByUrl("jar://" + annotationsJarPath + "!/");
|
||||
pathsChecked.add(annotationsJarPath);
|
||||
}
|
||||
if (root == null) {
|
||||
String url = "jar://" + FileUtil.toSystemIndependentName(PathManager.getHomePath()) + "/lib/jdkAnnotations.jar!/";
|
||||
root = VirtualFileManager.getInstance().findFileByUrl(url);
|
||||
pathsChecked.add(FileUtil.toSystemIndependentName(PathManager.getHomePath()) + "/lib/jdkAnnotations.jar");
|
||||
}
|
||||
}
|
||||
VirtualFile root = internalJdkAnnotationsPath(pathsChecked);
|
||||
|
||||
if (root == null) {
|
||||
StringBuilder msg = new StringBuilder("Paths checked:\n");
|
||||
@@ -294,12 +277,39 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
msg.append(p).append("; ").append(f.exists()).append("; ").append(Arrays.toString(f.getParentFile().list())).append('\n');
|
||||
}
|
||||
LOG.error("JDK annotations not found", msg.toString());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
OrderRootType annoType = AnnotationOrderRootType.getInstance();
|
||||
modificator.removeRoot(root, annoType);
|
||||
if (modificator.getRoots(annoType).length != 0) {
|
||||
modificator.removeRoot(root, annoType);
|
||||
}
|
||||
modificator.addRoot(root, annoType);
|
||||
return true;
|
||||
}
|
||||
|
||||
static VirtualFile internalJdkAnnotationsPath(@NotNull List<? super String> pathsChecked) {
|
||||
String javaPluginClassesRootPath = PathManager.getJarPathForClass(JavaSdkImpl.class);
|
||||
LOG.assertTrue(javaPluginClassesRootPath != null);
|
||||
File javaPluginClassesRoot = new File(javaPluginClassesRootPath);
|
||||
VirtualFile root = null;
|
||||
if (javaPluginClassesRoot.isFile()) {
|
||||
String annotationsJarPath = FileUtil.toSystemIndependentName(new File(javaPluginClassesRoot.getParentFile(), "jdkAnnotations.jar").getAbsolutePath());
|
||||
root = VirtualFileManager.getInstance().findFileByUrl("jar://" + annotationsJarPath + "!/");
|
||||
pathsChecked.add(annotationsJarPath);
|
||||
}
|
||||
if (root == null) {
|
||||
String url = "jar://" + FileUtil.toSystemIndependentName(PathManager.getHomePath()) + "/lib/jdkAnnotations.jar!/";
|
||||
root = VirtualFileManager.getInstance().findFileByUrl(url);
|
||||
pathsChecked.add(url);
|
||||
}
|
||||
if (root == null) {
|
||||
// community idea under idea
|
||||
String path = FileUtil.toSystemIndependentName(PathManager.getCommunityHomePath()) + "/java/jdkAnnotations";
|
||||
root = LocalFileSystem.getInstance().findFileByPath(path);
|
||||
pathsChecked.add(path);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -348,6 +358,8 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
addClasses(jdkHomeFile, sdkModificator, isJre);
|
||||
addSources(jdkHomeFile, sdkModificator);
|
||||
addDocs(jdkHomeFile, sdkModificator, null);
|
||||
attachJdkAnnotations(sdkModificator);
|
||||
|
||||
sdkModificator.commitChanges();
|
||||
|
||||
return jdk;
|
||||
@@ -370,7 +382,7 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
@Override public void setVersionString(String versionString) { throw new UnsupportedOperationException(); }
|
||||
@Override public SdkAdditionalData getSdkAdditionalData() { throw new UnsupportedOperationException(); }
|
||||
@Override public void setSdkAdditionalData(SdkAdditionalData data) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NotNull VirtualFile[] getRoots(@NotNull OrderRootType rootType) { throw new UnsupportedOperationException(); }
|
||||
@Override public @NotNull VirtualFile[] getRoots(@NotNull OrderRootType rootType) { return roots.get(rootType).toArray(VirtualFile.EMPTY_ARRAY); }
|
||||
@Override public void removeRoot(@NotNull VirtualFile root, @NotNull OrderRootType rootType) { throw new UnsupportedOperationException(); }
|
||||
@Override public void removeRoots(@NotNull OrderRootType rootType) { throw new UnsupportedOperationException(); }
|
||||
@Override public void removeAllRoots() { throw new UnsupportedOperationException(); }
|
||||
@@ -385,6 +397,7 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
|
||||
addClasses(jdkHomeFile, sdkModificator, isJre);
|
||||
addSources(jdkHomeFile, sdkModificator);
|
||||
attachJdkAnnotations(sdkModificator);
|
||||
|
||||
return new MockSdk(jdkName, homePath, jdkName, roots, this);
|
||||
}
|
||||
@@ -403,8 +416,8 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
private static List<String> readModulesFromReleaseFile(File jrtBaseDir) {
|
||||
File releaseFile = new File(jrtBaseDir, "release");
|
||||
if (releaseFile.isFile()) {
|
||||
Properties p = new Properties();
|
||||
try (FileInputStream stream = new FileInputStream(releaseFile)) {
|
||||
Properties p = new Properties();
|
||||
p.load(stream);
|
||||
String modules = p.getProperty("MODULES");
|
||||
if (modules != null) {
|
||||
@@ -419,20 +432,20 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<String> findClasses(@NotNull File file, boolean isJre) {
|
||||
private static List<String> findClasses(@NotNull File jdkHome, boolean isJre) {
|
||||
List<String> result = ContainerUtil.newArrayList();
|
||||
|
||||
if (JdkUtil.isExplodedModularRuntime(file.getPath())) {
|
||||
File[] exploded = new File(file, "modules").listFiles();
|
||||
if (JdkUtil.isExplodedModularRuntime(jdkHome.getPath())) {
|
||||
File[] exploded = new File(jdkHome, "modules").listFiles();
|
||||
if (exploded != null) {
|
||||
for (File root : exploded) {
|
||||
result.add(VfsUtil.getUrlForLibraryRoot(root));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (JdkUtil.isModularRuntime(file)) {
|
||||
String jrtBaseUrl = JrtFileSystem.PROTOCOL_PREFIX + getPath(file) + JrtFileSystem.SEPARATOR;
|
||||
List<String> modules = readModulesFromReleaseFile(file);
|
||||
else if (JdkUtil.isModularRuntime(jdkHome)) {
|
||||
String jrtBaseUrl = JrtFileSystem.PROTOCOL_PREFIX + getPath(jdkHome) + JrtFileSystem.SEPARATOR;
|
||||
List<String> modules = readModulesFromReleaseFile(jdkHome);
|
||||
if (modules != null) {
|
||||
for (String module : modules) {
|
||||
result.add(jrtBaseUrl + module);
|
||||
@@ -448,7 +461,7 @@ public class JavaSdkImpl extends JavaSdk {
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (File root : JavaSdkUtil.getJdkClassesRoots(file, isJre)) {
|
||||
for (File root : JavaSdkUtil.getJdkClassesRoots(jdkHome, isJre)) {
|
||||
result.add(VfsUtil.getUrlForLibraryRoot(root));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ public class Example {
|
||||
@NotNull Class x = <warning descr="'null' is assigned to a variable that is annotated with @NotNull">ClassUtils.primitiveToWrapper(null)</warning>;
|
||||
}
|
||||
|
||||
void writeBytes(@Nullable byte[] bytes) throws IOException {
|
||||
new FilterOutputStream(null).write(<warning descr="Argument 'bytes' might be null">bytes</warning>);
|
||||
void writeBytes(@Nullable byte[] bytes, FilterOutputStream stream) throws IOException {
|
||||
stream.write(<warning descr="Argument 'bytes' might be null">bytes</warning>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class Main {
|
||||
@@ -14,6 +16,7 @@ class Main {
|
||||
newMethod();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Object[] newMethod() {
|
||||
return myScheduledUpdates.keySet().toArray(new Object[myScheduledUpdates.keySet().size()]);
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ public class ParameterInfoTest extends AbstractParameterInfoTestCase {
|
||||
public void testInferredWithVarargs() {
|
||||
myFixture.configureByText(JavaFileType.INSTANCE,
|
||||
"import java.util.*; class C { void m(Object objects[], List<Object> list) { Collections.addAll(<caret>list, objects);} }");
|
||||
assertEquals("<html>Collection<? super Object> collection, @NotNull Object... ts</html>", parameterPresentation(-1));
|
||||
assertEquals("<html>@NotNull Collection<? super Object> collection,</html><html> @NotNull Object... ts</html>", parameterPresentation(-1));
|
||||
}
|
||||
|
||||
private void checkHighlighted(int lineIndex) {
|
||||
@@ -450,7 +450,7 @@ public class ParameterInfoTest extends AbstractParameterInfoTestCase {
|
||||
"-\n" +
|
||||
"<html><b>double v</b></html>\n" +
|
||||
"-\n" +
|
||||
"<html><b>char[] chars</b></html>\n" +
|
||||
"<html><b>@NotNull char[] chars</b></html>\n" +
|
||||
"-\n" +
|
||||
"<html><b>@Nullable String s</b></html>\n" +
|
||||
"-\n" +
|
||||
|
||||
@@ -615,7 +615,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
checkHintContents("<html><b>String</b> <i>a default value. </i></html>");
|
||||
showParameterInfo();
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><font color=a8a8a8>@NotNull String key</font></html>\n" +
|
||||
checkHintContents("<html><font color=a8a8a8>@NonNls @NotNull String key</font></html>\n" +
|
||||
"-\n" +
|
||||
"[<html>@NotNull String key, <b>String def</b></html>]");
|
||||
}
|
||||
@@ -627,14 +627,14 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
complete("setProperty");
|
||||
waitForAllAsyncStuff();
|
||||
checkResultWithInlays("class C { void m() { System.setProperty(<HINT text=\"key:\"/><caret>, <Hint text=\"value:\"/>) } }");
|
||||
checkHintContents("<html><b>@NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
checkHintContents("<html><b>@NonNls @NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
next();
|
||||
waitForAllAsyncStuff();
|
||||
checkResultWithInlays("class C { void m() { System.setProperty(<Hint text=\"key:\"/>, <HINT text=\"value:\"/><caret>) } }");
|
||||
checkHintContents("<html><b>String</b> <i>the value of the system property. </i></html>");
|
||||
checkHintContents("<html><b>@NonNls @NotNull String</b> <i>the value of the system property. </i></html>");
|
||||
showParameterInfo();
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html>@NotNull String key, <b>String value</b></html>");
|
||||
checkHintContents("<html>@NonNls @NotNull String key, <b>@NonNls @NotNull String value</b></html>");
|
||||
}
|
||||
|
||||
public void testUpInEditor() {
|
||||
@@ -646,7 +646,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
checkHintContents("<html><b>@NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
showParameterInfo();
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><b>@NotNull String key</b></html>\n" +
|
||||
checkHintContents("<html><b>@NonNls @NotNull String key</b></html>\n" +
|
||||
"-\n" +
|
||||
"[<html><b>@NotNull String key</b>, String def</html>]");
|
||||
up();
|
||||
@@ -664,7 +664,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
checkHintContents("<html><b>@NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
showParameterInfo();
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><b>@NotNull String key</b></html>\n" +
|
||||
checkHintContents("<html><b>@NonNls @NotNull String key</b></html>\n" +
|
||||
"-\n" +
|
||||
"[<html><b>@NotNull String key</b>, String def</html>]");
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN);
|
||||
@@ -693,7 +693,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
configureJava("class C { void m() { System.getPro<caret> } }");
|
||||
complete("getProperty(String key)");
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><b>@NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
checkHintContents("<html><b>@NonNls @NotNull String</b> <i>the name of the system property. </i></html>");
|
||||
}
|
||||
|
||||
public void testSwitchIsPossibleForManuallyEnteredUnmatchedMethodCall() {
|
||||
@@ -730,7 +730,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
complete("getProperty(String key, String def)");
|
||||
waitForAllAsyncStuff();
|
||||
showParameterInfo();
|
||||
checkHintContents("<html><b>@NotNull String key</b></html>\n" +
|
||||
checkHintContents("<html><b>@NonNls @NotNull String key</b></html>\n" +
|
||||
"-\n" +
|
||||
"[<html><b>@NotNull String key</b>, String def</html>]");
|
||||
escape();
|
||||
@@ -748,7 +748,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
complete("getProperty(String key, String def)");
|
||||
checkResultWithInlays("class C { void m() { System.getProperty(<caret>) } }");
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><b>@NotNull String key</b></html>\n" +
|
||||
checkHintContents("<html><b>@NonNls @NotNull String key</b></html>\n" +
|
||||
"-\n" +
|
||||
"[<html><b>@NotNull String key</b>, String def</html>]");
|
||||
}
|
||||
@@ -879,7 +879,7 @@ public class CompletionHintsTest extends AbstractParameterInfoTestCase {
|
||||
complete("format(String format, Object... args)");
|
||||
checkResultWithInlays("class C { void m() { String.format(<HINT text=\"format:\"/><caret><Hint text=\",args:\"/>) } }");
|
||||
waitForAllAsyncStuff();
|
||||
checkHintContents("<html><b>String</b> <i> A format string </i></html>");
|
||||
checkHintContents("<html><b>@NotNull String</b> <i> A format string </i></html>");
|
||||
}
|
||||
|
||||
public void testBasicScenarioForConstructor() {
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.intellij.java.codeInsight.daemon.quickFix;
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.i18n.I18nInspection;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -44,6 +46,12 @@ public class I18nQuickFixTest extends LightQuickFixParameterizedTestCase {
|
||||
myMustBeAvailableAfterInvoke = Comparing.strEqual(testName, "SystemCall.java");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runSingle() throws Throwable {
|
||||
VfsGuardian.guard(FileUtil.toSystemIndependentName(PathManager.getCommunityHomePath()), getTestRootDisposable());
|
||||
super.runSingle();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldBeAvailableAfterExecution() {
|
||||
return myMustBeAvailableAfterInvoke;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Disposer;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.VirtualFileEvent;
|
||||
import com.intellij.openapi.vfs.VirtualFileListener;
|
||||
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||
import gnu.trove.THashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
class VfsGuardian {
|
||||
private static final Logger LOG = Logger.getInstance(VfsGuardian.class);
|
||||
/**
|
||||
* Listens for changes in files under {@code root} and reverts them back when {@code parent} gets disposed
|
||||
*/
|
||||
static void guard(@NotNull String root, @NotNull Disposable parent) {
|
||||
Map<VirtualFile, byte[]> oldContent = new THashMap<>();
|
||||
VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileListener() {
|
||||
@Override
|
||||
public void beforeContentsChange(@NotNull VirtualFileEvent event) {
|
||||
VirtualFile file = event.getFile();
|
||||
if (file.getPath().startsWith(root)) {
|
||||
try {
|
||||
byte[] old = file.contentsToByteArray();
|
||||
oldContent.put(file, old);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, parent);
|
||||
Disposer.register(parent, () -> {
|
||||
for (Map.Entry<VirtualFile, byte[]> entry : oldContent.entrySet()) {
|
||||
VirtualFile file = entry.getKey();
|
||||
byte[] content = entry.getValue();
|
||||
try {
|
||||
LOG.warn("Restoring "+file+" ...");
|
||||
WriteAction.run(() -> file.setBinaryContent(content));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import com.intellij.codeInsight.daemon.GutterMark;
|
||||
import com.intellij.codeInspection.bytecodeAnalysis.BytecodeAnalysisConverter;
|
||||
import com.intellij.codeInspection.bytecodeAnalysis.ClassDataIndexer;
|
||||
import com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis;
|
||||
import com.intellij.codeInspection.dataFlow.JavaMethodContractUtil;
|
||||
import com.intellij.java.testutil.MavenDependencyUtil;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
@@ -31,7 +32,6 @@ import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
import one.util.streamex.EntryStream;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.java.decompiler.IdeaDecompiler;
|
||||
@@ -46,7 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author lambdamix
|
||||
*/
|
||||
public class BytecodeAnalysisIntegrationTest extends LightCodeInsightFixtureTestCase {
|
||||
private static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = Contract.class.getName();
|
||||
private static final String ORG_JETBRAINS_ANNOTATIONS_CONTRACT = JavaMethodContractUtil.ORG_JETBRAINS_ANNOTATIONS_CONTRACT;
|
||||
private static final String INFERRED_TEST_METHOD =
|
||||
"org.apache.velocity.util.ExceptionUtils java.lang.Throwable createWithCause(java.lang.Class, java.lang.String, java.lang.Throwable)";
|
||||
private static final String EXTERNAL_TEST_METHOD = "java.lang.String String(java.lang.String)";
|
||||
@@ -69,6 +69,9 @@ public class BytecodeAnalysisIntegrationTest extends LightCodeInsightFixtureTest
|
||||
}
|
||||
Sdk sdk = model.getSdk();
|
||||
if (sdk != null) {
|
||||
// first, remove bundled JDK Annotations because they are too thorough - can't infer them automatically yet
|
||||
sdk = PsiTestUtil.modifyJdkRoots(sdk, modificator -> modificator.removeRoots(AnnotationOrderRootType.getInstance()));
|
||||
|
||||
sdk = PsiTestUtil.addRootsToJdk(sdk, AnnotationOrderRootType.getInstance(), annotationsRoot);
|
||||
model.setSdk(sdk);
|
||||
}
|
||||
@@ -129,57 +132,59 @@ public class BytecodeAnalysisIntegrationTest extends LightCodeInsightFixtureTest
|
||||
protected void visitSubPackage(PsiPackage aPackage, PsiClass[] classes) {
|
||||
for (PsiClass aClass : classes) {
|
||||
for (PsiMethod method : aClass.getMethods()) {
|
||||
checkMethodAnnotations(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMethodAnnotations(PsiMethod method) {
|
||||
if (ProjectBytecodeAnalysis.getInstance(getProject()).getKey(method, digest) == null) return;
|
||||
String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
|
||||
if (INFERRED_TEST_METHOD.equals(methodKey)) return;
|
||||
|
||||
String externalNotNullMethodAnnotation = findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
String inferredNotNullMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
if (!externalNotNullMethodAnnotation.equals(inferredNotNullMethodAnnotation)) {
|
||||
diffs.add(methodKey + ": " + externalNotNullMethodAnnotation + " != " + inferredNotNullMethodAnnotation + "\n");
|
||||
}
|
||||
String externalNullableMethodAnnotation = findExternalAnnotation(method, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
String inferredNullableMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
if (!externalNullableMethodAnnotation.equals(inferredNullableMethodAnnotation)) {
|
||||
diffs.add(methodKey + ": " + externalNullableMethodAnnotation + " != " + inferredNullableMethodAnnotation + "\n");
|
||||
}
|
||||
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
|
||||
String externalNotNull = findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
String inferredNotNull = findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
if (!externalNotNull.equals(inferredNotNull)) {
|
||||
diffs.add(parameterKey + ": " + externalNotNull + " != " + inferredNotNull + "\n");
|
||||
}
|
||||
String externalNullable = findExternalAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
String inferredNullable = findInferredAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
if (!externalNullable.equals(inferredNullable)) {
|
||||
diffs.add(parameterKey + ": " + externalNullable + " != " + inferredNullable + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!EXTERNAL_TEST_METHOD.equals(methodKey)) {
|
||||
PsiAnnotation externalContractAnnotation = findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
PsiAnnotation inferredContractAnnotation = findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
String externalContractAnnotationText = externalContractAnnotation == null ? "-" : externalContractAnnotation.getText();
|
||||
String inferredContractAnnotationText = inferredContractAnnotation == null ? "-" : inferredContractAnnotation.getText();
|
||||
if (!externalContractAnnotationText.equals(inferredContractAnnotationText)) {
|
||||
diffs.add(methodKey + ": " + externalContractAnnotationText + " != " + inferredContractAnnotationText + "\n");
|
||||
checkMethodAnnotations(method, digest, diffs);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
rootPackage.accept(visitor);
|
||||
System.err.println(ClassDataIndexer.ourIndexSizeStatistics);
|
||||
if (!diffs.isEmpty()) {
|
||||
System.err.println(ClassDataIndexer.ourIndexSizeStatistics);
|
||||
}
|
||||
assertEmpty(diffs);
|
||||
}
|
||||
|
||||
private void checkMethodAnnotations(PsiMethod method, MessageDigest digest, List<? super String> diffs) {
|
||||
if (ProjectBytecodeAnalysis.getInstance(getProject()).getKey(method, digest) == null) return;
|
||||
String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
|
||||
if (INFERRED_TEST_METHOD.equals(methodKey)) return;
|
||||
|
||||
String externalNotNullMethodAnnotation = findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
String inferredNotNullMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
if (!externalNotNullMethodAnnotation.equals(inferredNotNullMethodAnnotation)) {
|
||||
diffs.add(methodKey + ": " + externalNotNullMethodAnnotation + " != " + inferredNotNullMethodAnnotation + "\n");
|
||||
}
|
||||
String externalNullableMethodAnnotation = findExternalAnnotation(method, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
String inferredNullableMethodAnnotation = findInferredAnnotation(method, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
if (!externalNullableMethodAnnotation.equals(inferredNullableMethodAnnotation)) {
|
||||
diffs.add(methodKey + ": " + externalNullableMethodAnnotation + " != " + inferredNullableMethodAnnotation + "\n");
|
||||
}
|
||||
|
||||
for (PsiParameter parameter : method.getParameterList().getParameters()) {
|
||||
String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
|
||||
String externalNotNull = findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
String inferredNotNull = findInferredAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "-" : "@NotNull";
|
||||
if (!externalNotNull.equals(inferredNotNull)) {
|
||||
diffs.add(parameterKey + ": " + externalNotNull + " != " + inferredNotNull + "\n");
|
||||
}
|
||||
String externalNullable = findExternalAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
String inferredNullable = findInferredAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "-" : "@Nullable";
|
||||
if (!externalNullable.equals(inferredNullable)) {
|
||||
diffs.add(parameterKey + ": " + externalNullable + " != " + inferredNullable + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!EXTERNAL_TEST_METHOD.equals(methodKey)) {
|
||||
PsiAnnotation externalContractAnnotation = findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
PsiAnnotation inferredContractAnnotation = findInferredAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
|
||||
String externalContractAnnotationText = externalContractAnnotation == null ? "-" : externalContractAnnotation.getText();
|
||||
String inferredContractAnnotationText = inferredContractAnnotation == null ? "-" : inferredContractAnnotation.getText();
|
||||
if (!externalContractAnnotationText.equals(inferredContractAnnotationText)) {
|
||||
diffs.add(methodKey + ": " + externalContractAnnotationText + " != " + inferredContractAnnotationText + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void _testExportInferredAnnotations() {
|
||||
PsiPackage rootPackage = JavaPsiFacade.getInstance(getProject()).findPackage("");
|
||||
assertNotNull(rootPackage);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
// Copyright 2000-2017 JetBrains s.r.o.
|
||||
// Use of this source code is governed by the Apache 2.0 license that can be
|
||||
// found in the LICENSE file.
|
||||
package com.intellij.java.openapi.projectRoots;
|
||||
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import org.jdom.Element;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ProjectJdkTest extends PlatformTestCase {
|
||||
public void testDoesntCrashOnJdkRootDisappearance() throws Exception {
|
||||
VirtualFile nDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDir("nroot", true));
|
||||
String nUrl = nDir.getUrl();
|
||||
ProjectJdkImpl jdk = WriteCommandAction.runWriteCommandAction(getProject(), (ThrowableComputable<ProjectJdkImpl, Exception>)()->{
|
||||
ProjectJdkImpl myJdk = (ProjectJdkImpl)ProjectJdkTable.getInstance().createSdk("my", JavaSdk.getInstance());
|
||||
Element element = JDOMUtil.load("<jdk version=\"2\">\n" +
|
||||
" <name value=\"1.8\" />\n" +
|
||||
" <type value=\"JavaSDK\" />\n" +
|
||||
" <version value=\"java version "1.8.0_152-ea"\" />\n" +
|
||||
" <homePath value=\"I:/Java/jdk1.8\" />\n" +
|
||||
" <roots>\n" +
|
||||
" <classPath>\n" +
|
||||
" <root type=\"composite\">\n" +
|
||||
" <root url=\"" + nUrl + "\" type=\"simple\" />\n" +
|
||||
" </root>\n" +
|
||||
" </classPath>\n" +
|
||||
" </roots>\n" +
|
||||
" <additional />\n" +
|
||||
" </jdk>\n"
|
||||
);
|
||||
myJdk.readExternal(element);
|
||||
return myJdk;
|
||||
});
|
||||
|
||||
try {
|
||||
List<String> urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertOrderedEquals(urls, nUrl);
|
||||
|
||||
delete(nDir);
|
||||
assertFalse(nDir.isValid());
|
||||
|
||||
urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertEmpty(urls);
|
||||
}
|
||||
finally {
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), ()->ProjectJdkTable.getInstance().removeJdk(jdk));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.openapi.projectRoots.impl;
|
||||
|
||||
import com.intellij.codeInspection.magicConstant.MagicConstantInspection;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable;
|
||||
import com.intellij.openapi.projectRoots.SdkType;
|
||||
import com.intellij.openapi.roots.AnnotationOrderRootType;
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.ThrowableComputable;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jdom.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ProjectJdkTest extends PlatformTestCase {
|
||||
public void testDoesntCrashOnJdkRootDisappearance() throws Exception {
|
||||
VirtualFile nDir = ObjectUtils.assertNotNull(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(createTempDir("nroot", true)));
|
||||
String nUrl = nDir.getUrl();
|
||||
ProjectJdkImpl jdk = WriteCommandAction.runWriteCommandAction(getProject(), (ThrowableComputable<ProjectJdkImpl, Exception>)()->{
|
||||
ProjectJdkImpl myJdk = (ProjectJdkImpl)ProjectJdkTable.getInstance().createSdk("my", JavaSdk.getInstance());
|
||||
@Language("XML")
|
||||
String s = "<jdk version=\"2\">\n" +
|
||||
" <name value=\"1.8\" />\n" +
|
||||
" <type value=\"JavaSDK\" />\n" +
|
||||
" <version value=\"java version "1.8.0_152-ea"\" />\n" +
|
||||
" <homePath value=\"I:/Java/jdk1.8\" />\n" +
|
||||
" <roots>\n" +
|
||||
" <classPath>\n" +
|
||||
" <root type=\"composite\">\n" +
|
||||
" <root url=\"" + nUrl + "\" type=\"simple\" />\n" +
|
||||
" </root>\n" +
|
||||
" </classPath>\n" +
|
||||
" </roots>\n" +
|
||||
" <additional />\n" +
|
||||
"</jdk>\n";
|
||||
Element element = JDOMUtil.load(s);
|
||||
myJdk.readExternal(element);
|
||||
return myJdk;
|
||||
});
|
||||
|
||||
try {
|
||||
List<String> urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertOrderedEquals(urls, nUrl);
|
||||
|
||||
delete(nDir);
|
||||
assertFalse(nDir.isValid());
|
||||
|
||||
urls = Arrays.stream(jdk.getRoots(OrderRootType.CLASSES)).peek(v -> assertTrue(v.isValid())).map(VirtualFile::getUrl).collect(Collectors.toList());
|
||||
assertEmpty(urls);
|
||||
}
|
||||
finally {
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), ()->ProjectJdkTable.getInstance().removeJdk(jdk));
|
||||
}
|
||||
}
|
||||
|
||||
public void testJdkAnnotationsAttachedAutomaticallyOnJDKCreation() throws Exception {
|
||||
ProjectJdkImpl jdk = WriteCommandAction.runWriteCommandAction(getProject(), (ThrowableComputable<ProjectJdkImpl, Exception>)()->
|
||||
(ProjectJdkImpl)ProjectJdkTable.getInstance().createSdk("my", JavaSdk.getInstance()));
|
||||
((SdkType)jdk.getSdkType()).setupSdkPaths(jdk);
|
||||
|
||||
try {
|
||||
Runnable fix = MagicConstantInspection.getAttachAnnotationsJarFix(getProject());
|
||||
assertNull(fix);
|
||||
|
||||
List<VirtualFile> annotations = Arrays.asList(jdk.getRoots(AnnotationOrderRootType.getInstance()));
|
||||
|
||||
assertNotEmpty(annotations);
|
||||
|
||||
VirtualFile internalAnnotationsPath = JavaSdkImpl.internalJdkAnnotationsPath(new ArrayList<>());
|
||||
assertContainsElements(annotations, internalAnnotationsPath);
|
||||
}
|
||||
finally {
|
||||
WriteCommandAction.runWriteCommandAction(getProject(), ()->ProjectJdkTable.getInstance().removeJdk(jdk));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,21 @@
|
||||
package com.intellij.testFramework;
|
||||
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.AnnotationOrderRootType;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
public class SdkEqualityTest extends LightPlatformTestCase {
|
||||
public void testSdkEquality() {
|
||||
Sdk jdk8 = IdeaTestUtil.getMockJdk(LanguageLevel.JDK_1_8.toJavaVersion());
|
||||
Sdk jdk8_copy = IdeaTestUtil.getMockJdk(LanguageLevel.JDK_1_8.toJavaVersion());
|
||||
Sdk jdk8_annotated = PsiTestUtil.addJdkAnnotations(jdk8);
|
||||
|
||||
String someRandomStrangePath = FileUtil.toSystemIndependentName(PlatformTestUtil.getCommunityPath()) + "/java/jdkAnnotations/javax";
|
||||
VirtualFile root = LocalFileSystem.getInstance().findFileByPath(someRandomStrangePath);
|
||||
Sdk jdk8_annotated = PsiTestUtil.addRootsToJdk(jdk8, AnnotationOrderRootType.getInstance(), root);
|
||||
|
||||
Sdk jdk11 = IdeaTestUtil.getMockJdk(LanguageLevel.JDK_11.toJavaVersion());
|
||||
assertTrue(areSdkEqual(jdk8, jdk8));
|
||||
assertTrue(areSdkEqual(jdk8, jdk8_copy));
|
||||
|
||||
@@ -496,6 +496,16 @@ public class PsiTestUtil {
|
||||
public static Sdk addRootsToJdk(@NotNull Sdk sdk,
|
||||
@NotNull OrderRootType rootType,
|
||||
@NotNull VirtualFile... roots) {
|
||||
return modifyJdkRoots(sdk, sdkModificator -> {
|
||||
for (VirtualFile root : roots) {
|
||||
sdkModificator.addRoot(root, rootType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Contract(pure=true)
|
||||
public static Sdk modifyJdkRoots(@NotNull Sdk sdk, Consumer<? super SdkModificator> modifier) {
|
||||
Sdk clone;
|
||||
try {
|
||||
clone = (Sdk)sdk.clone();
|
||||
@@ -504,9 +514,7 @@ public class PsiTestUtil {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
SdkModificator sdkModificator = clone.getSdkModificator();
|
||||
for (VirtualFile root : roots) {
|
||||
sdkModificator.addRoot(root, rootType);
|
||||
}
|
||||
modifier.accept(sdkModificator);
|
||||
sdkModificator.commitChanges();
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -70,12 +70,6 @@ object IdeaGuiTestUtil{
|
||||
if (foundJdk == null) {
|
||||
ApplicationManager.getApplication().runWriteAction { ProjectJdkTable.getInstance().addJdk(newJdk) }
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().runWriteAction {
|
||||
val modificator = newJdk.sdkModificator
|
||||
JavaSdkImpl.attachJdkAnnotations(modificator)
|
||||
modificator.commitChanges()
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw IllegalStateException("The resolved path '" + path.path + "' was not found")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Test1 {
|
||||
void foo(){}
|
||||
{
|
||||
@@ -5,7 +7,7 @@ class Test1 {
|
||||
String str1 = "effectively final string";
|
||||
Comparable<String> a = new Comparable<String>() {
|
||||
@Override
|
||||
public int compareTo(String o) {
|
||||
public int compareTo(@NotNull String o) {
|
||||
System.out.println(str1);
|
||||
new Runnable() {
|
||||
@Override
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Test1 {
|
||||
void foo(){}
|
||||
{
|
||||
Comparable<String> a = new Comparable<String>() {
|
||||
@Override
|
||||
public int compareTo(String o) {
|
||||
public int compareTo(@NotNull String o) {
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Test1<U> {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Comparable<? extends Integer> c = new Comparable<Integer>() {
|
||||
@Override
|
||||
public int compareTo(Integer o) {
|
||||
public int compareTo(@NotNull Integer o) {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
class Foo implements Comparable<Foo> {
|
||||
|
||||
def Foo next() {
|
||||
@@ -9,7 +11,7 @@ class Foo implements Comparable<Foo> {
|
||||
}
|
||||
|
||||
@Override
|
||||
int compareTo(Foo o) {
|
||||
int compareTo(@NotNull Foo o) {
|
||||
<selection>return 0</selection>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import org.jetbrains.annotations.NotNull
|
||||
|
||||
class Foo implements Comparable<Foo> {
|
||||
def next() {return this}
|
||||
def previous() {return this}
|
||||
|
||||
@Override
|
||||
int compareTo(Foo o) {
|
||||
int compareTo(@NotNull Foo o) {
|
||||
<selection>return 0</selection>
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user