georgii-ustinov/252/IDEA-168035

This MR duplicates the https://code.jetbrains.team/p/ij/repositories/ultimate/reviews/173952/timeline, but fixes the conflicts community/java/java-tests/testSrc/com/intellij/codeInsight/daemon/impl/quickfix/AnnotateMethodInGeneratedFilesTest.java

Merge-request: IJ-MR-175150
Merged-by: Georgii Ustinov <georgii.ustinov@jetbrains.com>

GitOrigin-RevId: 69f1417a59be188fab171f8d7bfdbd57d40eddc7
This commit is contained in:
Georgii Ustinov
2025-09-10 15:01:55 +00:00
committed by intellij-monorepo-bot
parent 773f837fff
commit dd035bc29f
47 changed files with 1032 additions and 11 deletions

View File

@@ -1,10 +1,10 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.formatter.java
import com.intellij.codeInsight.AnnotationUtil
import com.intellij.codeInsight.DumbAwareAnnotationUtil
import com.intellij.lang.ASTNode
import com.intellij.openapi.roots.LanguageLevelProjectExtension
import com.intellij.pom.java.LanguageLevel
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.PsiAnnotation
import com.intellij.psi.PsiKeyword
import com.intellij.psi.PsiModifierListOwner
@@ -13,11 +13,14 @@ import com.intellij.psi.formatter.FormatterUtil
import com.intellij.psi.formatter.java.JavaFormatterAnnotationUtil.isFieldWithAnnotations
import com.intellij.psi.impl.source.tree.JavaElementType
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.psi.util.PsiUtil
internal object JavaFormatterAnnotationUtil {
private val KNOWN_TYPE_ANNOTATIONS: Set<String> = setOf(
"org.jetbrains.annotations.NotNull",
"org.jetbrains.annotations.Nullable"
AnnotationUtil.NOT_NULL,
AnnotationUtil.NULLABLE,
AnnotationUtil.J_SPECIFY_NON_NULL,
AnnotationUtil.J_SPECIFY_NULLABLE,
)
/**
@@ -31,8 +34,7 @@ internal object JavaFormatterAnnotationUtil {
fun isTypeAnnotation(annotation: ASTNode): Boolean {
val node = annotation.psi as? PsiAnnotation ?: return false
val languageLevel = LanguageLevelProjectExtension.getInstance(node.project).languageLevel
if (languageLevel.isLessThan(LanguageLevel.JDK_1_8)) return false
if (!PsiUtil.isAvailable(JavaFeature.TYPE_ANNOTATIONS, node)) return false
val next = PsiTreeUtil.skipSiblingsForward(node, PsiWhiteSpace::class.java, PsiAnnotation::class.java)
if (next is PsiKeyword) return false

View File

@@ -26,6 +26,9 @@ public class AnnotationUtil {
public static final String NOT_NULL = "org.jetbrains.annotations.NotNull";
public static final String NOT_NULL_BY_DEFAULT = "org.jetbrains.annotations.NotNullByDefault";
public static final String J_SPECIFY_NON_NULL = "org.jspecify.annotations.NonNull";
public static final String J_SPECIFY_NULLABLE = "org.jspecify.annotations.Nullable";
public static final String NON_NLS = "org.jetbrains.annotations.NonNls";
public static final String NLS = "org.jetbrains.annotations.Nls";

View File

@@ -5,10 +5,12 @@ import com.intellij.codeInsight.DumbAwareAnnotationUtil.KNOWN_ANNOTATIONS
import com.intellij.codeInsight.DumbAwareAnnotationUtil.hasAnnotation
import com.intellij.openapi.util.NlsSafe
import com.intellij.openapi.util.text.StringUtil
import com.intellij.pom.java.JavaFeature
import com.intellij.psi.*
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.PsiUtil
/**
* Utility which helps to detect annotation in `Dumb mode`.
@@ -16,10 +18,24 @@ import com.intellij.psi.util.PsiModificationTracker
object DumbAwareAnnotationUtil {
private const val JAVA_LANG_PACKAGE = "java.lang"
/**
* Represents a list of fully qualified names for annotations that are treated as a type annotations.
*/
private val KNOWN_ANNOTATIONS = setOf(
AnnotationUtil.NOT_NULL,
AnnotationUtil.NULLABLE,
AnnotationUtil.NON_NLS
AnnotationUtil.NON_NLS,
AnnotationUtil.J_SPECIFY_NON_NULL,
AnnotationUtil.J_SPECIFY_NULLABLE
)
/**
* Represents a mapping from a fully qualified name of a module to a set of fully qualified names of annotations
* that are treated as type annotations and located in this module
*/
private val KNOWN_MODULE_TO_ANNOTATIONS_MAP = mapOf(
"org.jetbrains.annotations" to setOf(AnnotationUtil.NOT_NULL, AnnotationUtil.NULLABLE, AnnotationUtil.NON_NLS),
"org.jspecify" to setOf(AnnotationUtil.J_SPECIFY_NON_NULL, AnnotationUtil.J_SPECIFY_NULLABLE)
)
/**
@@ -57,12 +73,12 @@ object DumbAwareAnnotationUtil {
* Formats the given fully qualified name (FQN) by trimming whitespace around each segment.
*/
@JvmStatic
fun getFormattedReferenceFqn(referenceText: @NlsSafe String) = referenceText.split(".").joinToString(separator = ".") { pathPart -> pathPart.trim() }
fun getFormattedReferenceFqn(referenceText: @NlsSafe String): String = referenceText.split(".").joinToString(separator = ".") { pathPart -> pathPart.trim() }
private fun getImportedKnownAnnotations(file: PsiJavaFile): Set<String> = CachedValuesManager.getCachedValue(file) {
val importList = file.importList
?: return@getCachedValue CachedValueProvider.Result(emptySet(), PsiModificationTracker.MODIFICATION_COUNT)
val filteredAnnotations = KNOWN_ANNOTATIONS.filter { isAnnotationInImportList(it, importList) }
val filteredAnnotations = KNOWN_ANNOTATIONS.filter { isAnnotationInImportList(it, importList) || isAnnotationInModuleImportList(it, importList) }
.mapNotNull { fqn -> fqn.split(".").lastOrNull() }
.toSet()
CachedValueProvider.Result.create(filteredAnnotations, PsiModificationTracker.MODIFICATION_COUNT)
@@ -77,6 +93,16 @@ object DumbAwareAnnotationUtil {
}
}
private fun isAnnotationInModuleImportList(annotationFqn: String, moduleList: PsiImportList): Boolean {
if (!PsiUtil.isAvailable(JavaFeature.MODULE_IMPORT_DECLARATIONS, moduleList)) return false
return moduleList.importModuleStatements.any { statement: PsiImportModuleStatement ->
val referenceName = statement.referenceName ?: return@any false
val formattedReferenceName = getFormattedReferenceFqn(referenceName)
if (formattedReferenceName !in KNOWN_MODULE_TO_ANNOTATIONS_MAP) return@any false
annotationFqn in KNOWN_MODULE_TO_ANNOTATIONS_MAP.getValue(formattedReferenceName)
}
}
private fun getAnnotationImportInfo(annotationFqn: String): AnnotationImportInfo {
val packageName = StringUtil.getPackageName(annotationFqn)
val className = StringUtil.getShortName(annotationFqn)

View File

@@ -0,0 +1,18 @@
package org.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.List;
@Target({ElementType.TYPE_USE})
@interface CustomAnno {}
public class Formatter {
@CustomAnno String getCustomString() {
return null;
}
@CustomAnno <T, V> List<T> getCustomList() {
return null;
}
}

View File

@@ -0,0 +1,21 @@
package org.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.List;
@Target({ElementType.TYPE_USE})
@interface CustomAnno {
}
public class Formatter {
@CustomAnno
String getCustomString() {
return null;
}
@CustomAnno
<T, V> List<T> getCustomList() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package org.example;
public class Formatter {
@org.jspecify.annotations.NonNull
<T, V> List<T> getNotNullList() {
return List.of();
}
@org.jspecify.annotations.Nullable
<T, V> List<T> getNullableList() {
return null;
}
@org.jspecify.annotations.NonNull
String getNotNullName() {
return "";
}
@org.jspecify.annotations.Nullable
String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,19 @@
package org.example;
public class Formatter {
@org.jspecify.annotations.NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@org.jspecify.annotations.Nullable <T, V> List<T> getNullableList() {
return null;
}
@org.jspecify.annotations.NonNull String getNotNullName() {
return "";
}
@org.jspecify.annotations.Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package org.example;
import org.jspecify.annotations.*;
import java.util.List;
public class Formatter {
@NonNull @org.jspecify.annotations.Nullable
<T, V> List<T> getNotNullList() {
return List.of();
}
@NonNull @org.jspecify.annotations.Nullable
String getNotNullName() {
return "";
}
}

View File

@@ -0,0 +1,15 @@
package org.example;
import org.jspecify.annotations.*;
import java.util.List;
public class Formatter {
@NonNull @org.jspecify.annotations.Nullable <T, V> List<T> getNotNullList() {
return List.of();
}
@NonNull @org.jspecify.annotations.Nullable String getNotNullName() {
return "";
}
}

View File

@@ -0,0 +1,26 @@
package org.example;
import org.jspecify.annotations.*;
import java.util.List;
public class Formatter {
@NonNull
<T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable
<T, V> List<T> getNullableList() {
return null;
}
@NonNull
String getNotNullName() {
return "";
}
@Nullable
String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package org.example;
import org.jspecify.annotations.*;
import java.util.List;
public class Formatter {
@NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable <T, V> List<T> getNullableList() {
return null;
}
@NonNull String getNotNullName() {
return "";
}
@Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,27 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull
@Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NonNull
String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,27 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull
@Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NonNull
String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,14 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull String getNotNullName() {
return "";
}
@Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable <T, V> List<T> getNullableList() {
return null;
}
}

View File

@@ -0,0 +1,16 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable <T, V> List<T> getNullableList() {
return null;
}
}

View File

@@ -0,0 +1,14 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull String getNotNullName() {
return "";
}
@Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,24 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull
String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,29 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull
String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,17 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@Nullable @NonNull String getCustomString() {
return null;
}
@Nullable @NonNull <T, V> List<T> getCustomList() {
return null;
}
}

View File

@@ -0,0 +1,17 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@Nullable @NonNull String getCustomString() {
return null;
}
@Nullable @NonNull <T, V> List<T> getCustomList() {
return null;
}
}

View File

@@ -0,0 +1,27 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull
@org.jspecify.annotations.Nullable
String breakLineBetweenAnnotations() {
return "";
}
@org.jspecify.annotations.Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@org.jspecify.annotations.Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@org.jspecify.annotations.Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,22 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull @org.jspecify.annotations.Nullable String breakLineBetweenAnnotations() {
return "";
}
@org.jspecify.annotations.Nullable @NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@org.jspecify.annotations.Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@org.jspecify.annotations.Nullable @NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,29 @@
package org.example;
import org.jspecify.annotations.Nullable;
import module org.jspecify;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package org.example;
import org.jspecify.annotations.Nullable;
import module org.jspecify;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable @NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package org.example;
import module org .
jspecify;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,22 @@
package org.example;
import module org .
jspecify;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable @NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,21 @@
package org.example;
import module org.jspecify;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable @NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,20 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull
@Nullable
<T, V> List<T> getStrangeList() {
return List.of();
}
@NonNull
@Nullable
String getNotNullName() {
return "";
}
}

View File

@@ -0,0 +1,16 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull @Nullable <T, V> List<T> getStrangeList() {
return List.of();
}
@NonNull @Nullable String getNotNullName() {
return "";
}
}

View File

@@ -0,0 +1,28 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull
<T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable
<T, V> List<T> getNullableList() {
return null;
}
@NonNull
String getNotNullName() {
return "";
}
@Nullable
String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,24 @@
package org.example;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import java.util.List;
public class Formatter {
@NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@Nullable <T, V> List<T> getNullableList() {
return null;
}
@NonNull String getNotNullName() {
return "";
}
@Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,24 @@
package org.example;
public class Formatter {
@ org . jspecify .annotations . NonNull
<T, V> List<T> getNotNullList() {
return List.of();
}
@org. jspecify. annotations .
Nullable
<T, V> List<T> getNullableList() {
return null;
}
@ org. jspecify . annotations. NonNull
String getNotNullName() {
return "";
}
@ org . jspecify . annotations . Nullable
String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,19 @@
package org.example;
public class Formatter {
@org.jspecify.annotations.NonNull <T, V> List<T> getNotNullList() {
return List.of();
}
@org.jspecify.annotations.Nullable <T, V> List<T> getNullableList() {
return null;
}
@org.jspecify.annotations.NonNull String getNotNullName() {
return "";
}
@org.jspecify.annotations.Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,20 @@
package org.example
import
org . jspecify . annotations. NonNull;
import org. jspecify . annotations.
Nullable;
import org . jspecify .
annotations .*;
public class Formatter {
@NonNull
String getNotNullName() {
return "";
}
@Nullable
String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,15 @@
package org.example
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.jspecify.annotations.*;
public class Formatter {
@NonNull String getNotNullName() {
return "";
}
@Nullable String getNullableName() {
return null;
}
}

View File

@@ -0,0 +1,23 @@
package org.example;
import module org.jspecify.annotations;
public class Formatter {
@NonNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,28 @@
package org.example;
import module org.jspecify.annotations;
public class Formatter {
@NonNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NonNull
String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable
<T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NonNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,26 @@
package org.example;
import module org.jetbrains.annotations;
public class Formatter {
@NotNull
@Nullable
String breakLineBetweenAnnotations() {
return "";
}
@Nullable
@NotNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable
@NotNull
<T> String breakLineMixed() {
return null;
}
}

View File

@@ -0,0 +1,21 @@
package org.example;
import module org.jetbrains.annotations;
public class Formatter {
@NotNull @Nullable String breakLineBetweenAnnotations() {
return "";
}
@Nullable @NotNull String breakLineBetweenTypeAndAnnotations() {
return null;
}
@Nullable <T> String breakLineBetweenTypeParameterAndAnnotation() {
return null;
}
@Nullable @NotNull <T> String breakLineMixed() {
return null;
}
}

View File

@@ -8,7 +8,9 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.GeneratedSourcesFilter;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiClass;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -38,6 +40,7 @@ public class AnnotateMethodInGeneratedFilesTest extends LightJavaCodeInsightFixt
}
public void testAnnotateOverriddenMethod() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.getModule(), LanguageLevel.JDK_1_6);
doTest("Annotate overriding methods");
}

View File

@@ -14,12 +14,14 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.JavaModuleExternalPaths;
import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.UsefulTestCase;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.*;
@@ -70,6 +72,7 @@ public class ExternalAnnotationsTest extends UsefulTestCase {
public void testAddedAnnotationInCodeWhenAlreadyPresent() {
myFixture.configureByFile("src/withAnnotation/Foo.java");
IdeaTestUtil.setModuleLanguageLevel(myFixture.getModule(), LanguageLevel.JDK_1_8);
PsiMethod method = PsiTreeUtil.getParentOfType(myFixture.getElementAtCaret(), PsiMethod.class, false);
assertNotNull(method);
ActionContext context = myFixture.getActionContext();

View File

@@ -0,0 +1,102 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.psi.formatter.java
import com.intellij.JavaTestUtil
import com.intellij.application.options.CodeStyle
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.pom.java.LanguageLevel
import com.intellij.psi.codeStyle.CodeStyleManager
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings.WRAP_ALWAYS
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import com.intellij.testFramework.fixtures.MavenDependencyUtil
class JSpecifyTypeAnnotationFormatterTest : LightJavaCodeInsightFixtureTestCase() {
private val commonSettings: CommonCodeStyleSettings
get() = CodeStyle.getSettings(project).getCommonSettings(JavaLanguage.INSTANCE)
override fun getTestDataPath() = "${JavaTestUtil.getJavaTestDataPath()}/psi/formatter/java/jSpecifyTypeAnnotation/"
override fun setUp() {
super.setUp()
commonSettings.KEEP_LINE_BREAKS = false
commonSettings.METHOD_ANNOTATION_WRAP = WRAP_ALWAYS
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_8)
ModuleRootModificationUtil.updateModel(module) { model ->
MavenDependencyUtil.addFromMaven(model, "org.jspecify:jspecify:1.0.0")
}
}
fun testKnownAnnotationBeforeType() = doTest()
fun testKnownAnnotationBeforeTypeParameterList() = doTest()
fun testCustomAnnotation() = doTest()
fun testManyKnownAnnotations() = doTest()
fun testPreserveWrappingSingleAnnotation() = doTest()
fun testPreserveWrappingManyAnnotations() = doTest()
fun testFullyQualifiedName() = doTest()
fun testImportOnDemand() = doTest()
fun testImportMix() = doTest()
fun testSpacesInImportList() = doTest()
fun testSpacesInFqnAnnotations() = doTest()
fun testKeepLineBreaks() {
commonSettings.KEEP_LINE_BREAKS = true
doTest()
}
fun testLowLanguageLevel() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_7)
doTest()
}
fun testModuleImport() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}
fun testModuleImportWithSpaces() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}
fun testModuleImportMixedWithPackageImport() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}
fun testModuleImportMixedWithFqn() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}
fun testLowLanguageLevelForModuleImport() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_24)
doTest()
}
fun testUnknownModuleImport() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}
private fun doTest() {
val testName = getTestName(false)
myFixture.configureByFile("$testName.java")
WriteCommandAction.runWriteCommandAction(project) { CodeStyleManager.getInstance(project).reformatText(file, 0, editor.document.textLength) }
myFixture.checkResultByFile("${testName}_after.java")
}
}

View File

@@ -24,7 +24,7 @@ class TypeAnnotationFormatterTest : LightJavaCodeInsightFixtureTestCase() {
super.setUp()
commonSettings.KEEP_LINE_BREAKS = false
commonSettings.METHOD_ANNOTATION_WRAP = WRAP_ALWAYS
IdeaTestUtil.setProjectLanguageLevel(myFixture.project, LanguageLevel.JDK_1_8)
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_8)
ModuleRootModificationUtil.updateModel(module, DefaultLightProjectDescriptor::addJetBrainsAnnotations)
}
@@ -56,7 +56,12 @@ class TypeAnnotationFormatterTest : LightJavaCodeInsightFixtureTestCase() {
}
fun testLowLanguageLevel() {
IdeaTestUtil.setProjectLanguageLevel(myFixture.project, LanguageLevel.JDK_1_7)
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_1_7)
doTest()
}
fun testModuleImport() {
IdeaTestUtil.setModuleLanguageLevel(myFixture.module, LanguageLevel.JDK_25)
doTest()
}