mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
Java: basic support for Valhalla Value Classes (IDEA-364548)
GitOrigin-RevId: 93b0394866aae35772ccc90e7de822af8a94c6ce
This commit is contained in:
committed by
intellij-monorepo-bot
parent
36b258bc98
commit
2b32d9bb56
@@ -351,7 +351,8 @@ public final class HighlightClassUtil {
|
||||
return PsiKeyword.VAR.equals(typeName) && JavaFeature.LVTI.isSufficient(level) ||
|
||||
PsiKeyword.YIELD.equals(typeName) && JavaFeature.SWITCH_EXPRESSION.isSufficient(level) ||
|
||||
PsiKeyword.RECORD.equals(typeName) && JavaFeature.RECORDS.isSufficient(level) ||
|
||||
(PsiKeyword.SEALED.equals(typeName) || PsiKeyword.PERMITS.equals(typeName)) && JavaFeature.SEALED_CLASSES.isSufficient(level);
|
||||
(PsiKeyword.SEALED.equals(typeName) || PsiKeyword.PERMITS.equals(typeName)) && JavaFeature.SEALED_CLASSES.isSufficient(level) ||
|
||||
PsiKeyword.VALUE.equals(typeName) && JavaFeature.VALHALLA_VALUE_CLASSES.isSufficient(level);
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkClassAndPackageConflict(@NotNull PsiClass aClass) {
|
||||
@@ -588,15 +589,20 @@ public final class HighlightClassUtil {
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkCannotInheritFromFinal(@NotNull PsiClass superClass, @NotNull PsiElement elementToHighlight) {
|
||||
HighlightInfo.Builder errorResult = null;
|
||||
if (superClass.hasModifierProperty(PsiModifier.FINAL) || superClass.isEnum()) {
|
||||
String message = JavaErrorBundle.message("inheritance.from.final.class", HighlightUtil.formatClass(superClass),
|
||||
superClass.isEnum() ? PsiKeyword.ENUM : PsiKeyword.FINAL);
|
||||
errorResult = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message);
|
||||
int choice;
|
||||
if (superClass.isEnum()) choice = 2;
|
||||
else if (superClass.isRecord()) choice = 3;
|
||||
else if (superClass.isValueClass()) choice = 4;
|
||||
else choice = 1;
|
||||
String message = JavaErrorBundle.message("inheritance.from.final.class", HighlightUtil.formatClass(superClass), choice);
|
||||
HighlightInfo.Builder errorResult =
|
||||
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message);
|
||||
ChangeModifierRequest removeFinal = MemberRequestsKt.modifierRequest(JvmModifier.FINAL, false);
|
||||
QuickFixAction.registerQuickFixActions(errorResult, null, JvmElementActionFactories.createModifierActions(superClass, removeFinal));
|
||||
return errorResult;
|
||||
}
|
||||
return errorResult;
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkAnonymousInheritFinal(@NotNull PsiNewExpression expression) {
|
||||
@@ -1107,12 +1113,21 @@ public final class HighlightClassUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
static HighlightInfo.Builder checkExtendsProhibitedClass(@NotNull PsiClass superClass, @NotNull PsiClass psiClass, @NotNull PsiElement elementToHighlight) {
|
||||
static HighlightInfo.Builder checkExtendsProhibitedClass(@NotNull PsiClass superClass,
|
||||
@NotNull PsiClass psiClass,
|
||||
@NotNull PsiElement elementToHighlight) {
|
||||
String qualifiedName = superClass.getQualifiedName();
|
||||
if (CommonClassNames.JAVA_LANG_ENUM.equals(qualifiedName) && !psiClass.isEnum() || CommonClassNames.JAVA_LANG_RECORD.equals(qualifiedName) && !psiClass.isRecord()) {
|
||||
if (CommonClassNames.JAVA_LANG_ENUM.equals(qualifiedName) && !psiClass.isEnum() ||
|
||||
CommonClassNames.JAVA_LANG_RECORD.equals(qualifiedName) && !psiClass.isRecord()) {
|
||||
String message = JavaErrorBundle.message("classes.extends.prohibited.super", qualifiedName);
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message);
|
||||
}
|
||||
else if (!(!psiClass.isValueClass() ||
|
||||
superClass.isValueClass() ||
|
||||
CommonClassNames.JAVA_LANG_OBJECT.equals(superClass.getQualifiedName()))) {
|
||||
String message = JavaErrorBundle.message("value.class.can.only.inherit");
|
||||
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(elementToHighlight).descriptionAndTooltip(message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,17 +119,19 @@ public final class HighlightUtil {
|
||||
PsiModifier.STATIC, Set.of(),
|
||||
PsiModifier.TRANSIENT, Set.of(),
|
||||
PsiModifier.VOLATILE, Set.of(PsiModifier.FINAL));
|
||||
private static final Map<String, Set<String>> ourClassIncompatibleModifiers = Map.of(
|
||||
PsiModifier.ABSTRACT, Set.of(PsiModifier.FINAL),
|
||||
PsiModifier.FINAL, Set.of(PsiModifier.ABSTRACT, PsiModifier.SEALED, PsiModifier.NON_SEALED),
|
||||
PsiModifier.PACKAGE_LOCAL, Set.of(PsiModifier.PRIVATE, PsiModifier.PUBLIC, PsiModifier.PROTECTED),
|
||||
PsiModifier.PRIVATE, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PROTECTED),
|
||||
PsiModifier.PUBLIC, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PRIVATE, PsiModifier.PROTECTED),
|
||||
PsiModifier.PROTECTED, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PRIVATE),
|
||||
PsiModifier.STRICTFP, Set.of(),
|
||||
PsiModifier.STATIC, Set.of(),
|
||||
PsiModifier.SEALED, Set.of(PsiModifier.FINAL, PsiModifier.NON_SEALED),
|
||||
PsiModifier.NON_SEALED, Set.of(PsiModifier.FINAL, PsiModifier.SEALED));
|
||||
private static final Map<String, Set<String>> ourClassIncompatibleModifiers = Map.ofEntries(
|
||||
Map.entry(PsiModifier.ABSTRACT, Set.of(PsiModifier.FINAL)),
|
||||
Map.entry(PsiModifier.FINAL, Set.of(PsiModifier.ABSTRACT, PsiModifier.SEALED, PsiModifier.NON_SEALED)),
|
||||
Map.entry(PsiModifier.PACKAGE_LOCAL, Set.of(PsiModifier.PRIVATE, PsiModifier.PUBLIC, PsiModifier.PROTECTED)),
|
||||
Map.entry(PsiModifier.PRIVATE, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PROTECTED)),
|
||||
Map.entry(PsiModifier.PUBLIC, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PRIVATE, PsiModifier.PROTECTED)),
|
||||
Map.entry(PsiModifier.PROTECTED, Set.of(PsiModifier.PACKAGE_LOCAL, PsiModifier.PUBLIC, PsiModifier.PRIVATE)),
|
||||
Map.entry(PsiModifier.STRICTFP, Set.of()),
|
||||
Map.entry(PsiModifier.STATIC, Set.of()),
|
||||
Map.entry(PsiModifier.SEALED, Set.of(PsiModifier.FINAL, PsiModifier.NON_SEALED)),
|
||||
Map.entry(PsiModifier.NON_SEALED, Set.of(PsiModifier.FINAL, PsiModifier.SEALED)),
|
||||
Map.entry(PsiModifier.VALUE, Set.of())
|
||||
);
|
||||
private static final Map<String, Set<String>> ourClassInitializerIncompatibleModifiers = Map.of(PsiModifier.STATIC, Set.of());
|
||||
private static final Map<String, Set<String>> ourModuleIncompatibleModifiers = Map.of(PsiModifier.OPEN, Set.of());
|
||||
private static final Map<String, Set<String>> ourRequiresIncompatibleModifiers = Map.of(
|
||||
@@ -1181,10 +1183,10 @@ public final class HighlightUtil {
|
||||
|
||||
if (aClass.isEnum()) {
|
||||
isAllowed &=
|
||||
!(PsiModifier.FINAL.equals(modifier) || PsiModifier.ABSTRACT.equals(modifier) || PsiModifier.SEALED.equals(modifier));
|
||||
!PsiModifier.FINAL.equals(modifier) && !PsiModifier.ABSTRACT.equals(modifier) && !PsiModifier.SEALED.equals(modifier)
|
||||
&& !PsiModifier.VALUE.equals(modifier);
|
||||
}
|
||||
|
||||
if (aClass.isRecord()) {
|
||||
else if (aClass.isRecord()) {
|
||||
isAllowed &= !PsiModifier.ABSTRACT.equals(modifier);
|
||||
}
|
||||
|
||||
@@ -1222,10 +1224,12 @@ public final class HighlightUtil {
|
||||
}
|
||||
else if (PsiModifier.PROTECTED.equals(modifier) ||
|
||||
PsiModifier.TRANSIENT.equals(modifier) ||
|
||||
PsiModifier.SYNCHRONIZED.equals(modifier) ||
|
||||
PsiModifier.FINAL.equals(modifier)) {
|
||||
isAllowed &= !isInterface;
|
||||
}
|
||||
else if (PsiModifier.SYNCHRONIZED.equals(modifier)) {
|
||||
isAllowed &= !isInterface && (containingClass == null || !containingClass.isValueClass());
|
||||
}
|
||||
|
||||
if (containingClass != null && (containingClass.isInterface() || containingClass.isRecord())) {
|
||||
isAllowed &= !PsiModifier.NATIVE.equals(modifier);
|
||||
@@ -1242,7 +1246,7 @@ public final class HighlightUtil {
|
||||
}
|
||||
else if (modifierOwner instanceof PsiField) {
|
||||
if (PsiModifier.PRIVATE.equals(modifier) || PsiModifier.PROTECTED.equals(modifier) || PsiModifier.TRANSIENT.equals(modifier) ||
|
||||
PsiModifier.STRICTFP.equals(modifier) || PsiModifier.SYNCHRONIZED.equals(modifier)) {
|
||||
PsiModifier.STRICTFP.equals(modifier)) {
|
||||
isAllowed = modifierOwnerParent instanceof PsiClass psiClass && !psiClass.isInterface();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ public final class JavaHighlightErrorFilter extends HighlightErrorFilter {
|
||||
}
|
||||
else if (description.equals(JavaPsiBundle.message("expected.class.or.interface"))) {
|
||||
String text = element.getText();
|
||||
if ((text.equals(PsiKeyword.SEALED) || text.equals(PsiKeyword.NON_SEALED)) &&
|
||||
if ((text.equals(PsiKeyword.SEALED) || text.equals(PsiKeyword.NON_SEALED) || text.equals(PsiKeyword.VALUE)) &&
|
||||
PsiTreeUtil.skipWhitespacesAndCommentsForward(element) instanceof PsiClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ feature.statements.before.super=Statements before super()
|
||||
feature.module.import.declarations=Module Import Declarations
|
||||
feature.package.import.shadow.module.import=Import-on-demand over module import
|
||||
feature.package.transitive.dependency.on.java.base=Transitive dependency on java.base module
|
||||
feature.valhalla.value.classes=Valhalla value classes
|
||||
|
||||
else.without.if='else' without 'if'
|
||||
enum.constant.context=Enum constant ''{0}'' in ''{1}''
|
||||
|
||||
@@ -121,6 +121,7 @@ public enum JavaFeature {
|
||||
MODULE_IMPORT_DECLARATIONS(LanguageLevel.JDK_23_PREVIEW, "feature.module.import.declarations"),
|
||||
PACKAGE_IMPORTS_SHADOW_MODULE_IMPORTS(LanguageLevel.JDK_24_PREVIEW, "feature.package.import.shadow.module.import"),
|
||||
TRANSITIVE_DEPENDENCY_ON_JAVA_BASE(LanguageLevel.JDK_24_PREVIEW, "feature.package.transitive.dependency.on.java.base"),
|
||||
VALHALLA_VALUE_CLASSES(LanguageLevel.JDK_X, "feature.valhalla.value.classes"),
|
||||
;
|
||||
|
||||
private final @NotNull LanguageLevel myLevel;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -151,6 +151,7 @@ public interface JavaTokenType extends TokenType {
|
||||
IElementType YIELD_KEYWORD = new IJavaElementType("YIELD");
|
||||
IElementType RECORD_KEYWORD = new IJavaElementType("RECORD");
|
||||
|
||||
IElementType VALUE_KEYWORD = new IJavaElementType("VALUE_KEYWORD");
|
||||
IElementType SEALED_KEYWORD = new IJavaElementType("SEALED");
|
||||
IElementType NON_SEALED_KEYWORD = new IKeywordElementType("NON_SEALED");
|
||||
IElementType PERMITS_KEYWORD = new IJavaElementType("PERMITS");
|
||||
@@ -299,6 +300,7 @@ public interface JavaTokenType extends TokenType {
|
||||
YIELD_KEYWORD,
|
||||
RECORD_KEYWORD,
|
||||
|
||||
VALUE_KEYWORD,
|
||||
SEALED_KEYWORD,
|
||||
NON_SEALED_KEYWORD,
|
||||
PERMITS_KEYWORD,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
@@ -62,24 +62,24 @@ public interface PsiKeyword extends PsiJavaToken {
|
||||
@NlsSafe String FALSE = "false";
|
||||
@NlsSafe String NULL = "null";
|
||||
|
||||
@NlsSafe String OPEN = "open";
|
||||
@NlsSafe String MODULE = "module";
|
||||
@NlsSafe String REQUIRES = "requires";
|
||||
@NlsSafe String EXPORTS = "exports";
|
||||
@NlsSafe String OPENS = "opens";
|
||||
@NlsSafe String USES = "uses";
|
||||
@NlsSafe String PROVIDES = "provides";
|
||||
@NlsSafe String TRANSITIVE = "transitive";
|
||||
@NlsSafe String TO = "to";
|
||||
@NlsSafe String WITH = "with";
|
||||
|
||||
@NlsSafe String VAR = "var";
|
||||
@NlsSafe String YIELD = "yield";
|
||||
|
||||
@NlsSafe String RECORD = "record";
|
||||
|
||||
@NlsSafe String SEALED = "sealed";
|
||||
@NlsSafe String PERMITS = "permits";
|
||||
@NlsSafe String NON_SEALED = "non-sealed";
|
||||
|
||||
// soft keywords:
|
||||
@NlsSafe String EXPORTS = "exports";
|
||||
@NlsSafe String MODULE = "module";
|
||||
@NlsSafe String OPEN = "open";
|
||||
@NlsSafe String OPENS = "opens";
|
||||
@NlsSafe String PERMITS = "permits";
|
||||
@NlsSafe String PROVIDES = "provides";
|
||||
@NlsSafe String RECORD = "record";
|
||||
@NlsSafe String REQUIRES = "requires";
|
||||
@NlsSafe String SEALED = "sealed";
|
||||
@NlsSafe String TO = "to";
|
||||
@NlsSafe String TRANSITIVE = "transitive";
|
||||
@NlsSafe String USES = "uses";
|
||||
@NlsSafe String VALUE = "value";
|
||||
@NlsSafe String VAR = "var";
|
||||
@NlsSafe String WHEN = "when";
|
||||
@NlsSafe String WITH = "with";
|
||||
@NlsSafe String YIELD = "yield";
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
@@ -27,13 +27,16 @@ public interface PsiModifier {
|
||||
String SEALED = "sealed";
|
||||
//WARNING: it may not be reported for compiled classes.
|
||||
String NON_SEALED = "non-sealed";
|
||||
String VALUE = "value";
|
||||
|
||||
String[] MODIFIERS = {
|
||||
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT, OPEN, TRANSITIVE, SEALED, NON_SEALED
|
||||
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT, OPEN, TRANSITIVE,
|
||||
SEALED, NON_SEALED, VALUE
|
||||
};
|
||||
|
||||
@MagicConstant(stringValues = {
|
||||
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT, OPEN, TRANSITIVE, PACKAGE_LOCAL, SEALED, NON_SEALED
|
||||
PUBLIC, PROTECTED, PRIVATE, STATIC, ABSTRACT, FINAL, NATIVE, SYNCHRONIZED, STRICTFP, TRANSIENT, VOLATILE, DEFAULT, OPEN, TRANSITIVE,
|
||||
PACKAGE_LOCAL, SEALED, NON_SEALED, VALUE
|
||||
})
|
||||
@interface ModifierConstant { }
|
||||
}
|
||||
@@ -437,6 +437,12 @@ public class BasicDeclarationParser {
|
||||
PsiKeyword.SEALED.equals(builder.getTokenText());
|
||||
}
|
||||
|
||||
private static boolean isValueToken(PsiBuilder builder, IElementType tokenType) {
|
||||
return JavaFeature.VALHALLA_VALUE_CLASSES.isSufficient(getLanguageLevel(builder)) &&
|
||||
tokenType == JavaTokenType.IDENTIFIER &&
|
||||
PsiKeyword.VALUE.equals(builder.getTokenText());
|
||||
}
|
||||
|
||||
static boolean isNonSealedToken(PsiBuilder builder, IElementType tokenType) {
|
||||
if (!JavaFeature.SEALED_CLASSES.isSufficient(getLanguageLevel(builder)) ||
|
||||
tokenType != JavaTokenType.IDENTIFIER ||
|
||||
@@ -458,14 +464,18 @@ public class BasicDeclarationParser {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Pair<PsiBuilder.Marker, Boolean> parseModifierList(final PsiBuilder builder, final TokenSet modifiers) {
|
||||
public Pair<PsiBuilder.Marker, Boolean> parseModifierList(PsiBuilder builder, TokenSet modifiers) {
|
||||
final PsiBuilder.Marker modList = builder.mark();
|
||||
boolean isEmpty = true;
|
||||
|
||||
while (true) {
|
||||
IElementType tokenType = builder.getTokenType();
|
||||
if (tokenType == null) break;
|
||||
if (isSealedToken(builder, tokenType)) {
|
||||
if (isValueToken(builder, tokenType)) {
|
||||
builder.remapCurrentToken(JavaTokenType.VALUE_KEYWORD);
|
||||
tokenType = JavaTokenType.VALUE_KEYWORD;
|
||||
}
|
||||
else if (isSealedToken(builder, tokenType)) {
|
||||
builder.remapCurrentToken(JavaTokenType.SEALED_KEYWORD);
|
||||
tokenType = JavaTokenType.SEALED_KEYWORD;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public interface BasicElementTypes extends JavaTokenType, JavaDocTokenType, Basi
|
||||
VOLATILE_KEYWORD, WHILE_KEYWORD,
|
||||
OPEN_KEYWORD, MODULE_KEYWORD, REQUIRES_KEYWORD, EXPORTS_KEYWORD, OPENS_KEYWORD, USES_KEYWORD, PROVIDES_KEYWORD,
|
||||
TRANSITIVE_KEYWORD, TO_KEYWORD, WITH_KEYWORD, VAR_KEYWORD, YIELD_KEYWORD, RECORD_KEYWORD, SEALED_KEYWORD, PERMITS_KEYWORD,
|
||||
NON_SEALED_KEYWORD, WHEN_KEYWORD
|
||||
NON_SEALED_KEYWORD, WHEN_KEYWORD, VALUE_KEYWORD
|
||||
);
|
||||
|
||||
TokenSet BASIC_LITERAL_BIT_SET = TokenSet.create(TRUE_KEYWORD, FALSE_KEYWORD, NULL_KEYWORD);
|
||||
@@ -45,7 +45,8 @@ public interface BasicElementTypes extends JavaTokenType, JavaDocTokenType, Basi
|
||||
|
||||
TokenSet BASIC_MODIFIER_BIT_SET = TokenSet.create(
|
||||
PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, STATIC_KEYWORD, ABSTRACT_KEYWORD, FINAL_KEYWORD, NATIVE_KEYWORD,
|
||||
SYNCHRONIZED_KEYWORD, STRICTFP_KEYWORD, TRANSIENT_KEYWORD, VOLATILE_KEYWORD, DEFAULT_KEYWORD, SEALED_KEYWORD, NON_SEALED_KEYWORD);
|
||||
SYNCHRONIZED_KEYWORD, STRICTFP_KEYWORD, TRANSIENT_KEYWORD, VOLATILE_KEYWORD, DEFAULT_KEYWORD, SEALED_KEYWORD, NON_SEALED_KEYWORD,
|
||||
VALUE_KEYWORD);
|
||||
|
||||
TokenSet BASIC_PRIMITIVE_TYPE_BIT_SET = TokenSet.create(
|
||||
BOOLEAN_KEYWORD, BYTE_KEYWORD, SHORT_KEYWORD, INT_KEYWORD, LONG_KEYWORD, CHAR_KEYWORD, FLOAT_KEYWORD, DOUBLE_KEYWORD, VOID_KEYWORD);
|
||||
|
||||
@@ -80,6 +80,8 @@ public abstract class AbstractBasicClassParsingTest extends AbstractBasicJavaPar
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
public void testValueClass() { doTest(true); }
|
||||
|
||||
public void testSealedInterface() { doTest(true); }
|
||||
public void testSealedClassOldLanguageLevel() {
|
||||
setLanguageLevel(LanguageLevel.JDK_1_8);
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
// Copyright 2000-2020 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.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.valuebased;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.codeInspection.dataFlow.CommonDataflow;
|
||||
import com.intellij.codeInspection.dataFlow.TypeConstraint;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.pom.java.JavaFeature;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
@@ -16,7 +17,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class SynchronizeOnValueBasedClassInspection extends LocalInspectionTool {
|
||||
private static final @NonNls String ANNOTATION_NAME = "jdk.internal.ValueBased";
|
||||
private static final @NonNls String JDK_INTERNAL_VALUE_BASED = "jdk.internal.ValueBased";
|
||||
|
||||
@Override
|
||||
public @NotNull String getID() {
|
||||
@@ -24,50 +25,48 @@ public final class SynchronizeOnValueBasedClassInspection extends LocalInspectio
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
|
||||
boolean isOnTheFly) {
|
||||
public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!PsiUtil.getLanguageLevel(holder.getFile()).isAtLeast(LanguageLevel.JDK_16)) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitSynchronizedStatement(@NotNull final PsiSynchronizedStatement statement) {
|
||||
public void visitSynchronizedStatement(@NotNull PsiSynchronizedStatement statement) {
|
||||
final PsiExpression monitor = statement.getLockExpression();
|
||||
if (monitor == null) return;
|
||||
|
||||
final PsiType monitorType = monitor.getType();
|
||||
if (monitorType == null) return;
|
||||
|
||||
if (!isValueBasedClass(monitorType)) {
|
||||
if (!isValueBasedClass(PsiUtil.resolveClassInClassTypeOnly(monitorType))) {
|
||||
final TypeConstraint constraint = TypeConstraint.fromDfType(CommonDataflow.getDfType(monitor));
|
||||
final PsiType inferredType = constraint.getPsiType(statement.getProject());
|
||||
|
||||
if (monitorType.equals(inferredType)) return;
|
||||
|
||||
if (!isValueBasedClass(inferredType)) return;
|
||||
if (monitorType.equals(inferredType) || !isValueBasedClass(PsiUtil.resolveClassInClassTypeOnly(inferredType))) return;
|
||||
}
|
||||
|
||||
holder.registerProblem(monitor, JavaBundle.message("inspection.value.based.warnings.synchronization"));
|
||||
ProblemHighlightType highlightType = JavaFeature.VALHALLA_VALUE_CLASSES.isSufficient(PsiUtil.getLanguageLevel(monitor))
|
||||
? ProblemHighlightType.GENERIC_ERROR
|
||||
: ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
|
||||
holder.registerProblem(monitor, JavaBundle.message("inspection.value.based.warnings.synchronization"), highlightType);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A class is considered a value-based class when it is annotated with <code>jdk.internal.ValueBased</code>.
|
||||
* A class is considered a value-based class when it is annotated with <code>jdk.internal.ValueBased</code> or has the Valhalla
|
||||
* {@code value} modifier.
|
||||
* Wherever the annotation is applied to an abstract class or interface, it is also applied to all subclasses in the JDK,
|
||||
* so all such subclasses are considered value-based classes
|
||||
* so all such subclasses are considered value-based classes.
|
||||
*
|
||||
* @param type type to decide if it's of a value-based class
|
||||
* @return true when the argument is of a value-based class
|
||||
* @param aClass the class to check if it is a value-based class
|
||||
* @return true when the argument is a value-based class
|
||||
*/
|
||||
@Contract(value = "null -> false", pure = true)
|
||||
private static boolean isValueBasedClass(PsiType type) {
|
||||
final PsiClass classType = PsiTypesUtil.getPsiClass(type);
|
||||
if (classType == null) return false;
|
||||
|
||||
if (classType.hasAnnotation(ANNOTATION_NAME)) return true;
|
||||
|
||||
return ContainerUtil.or(type.getSuperTypes(), superType -> isValueBasedClass(superType));
|
||||
private static boolean isValueBasedClass(PsiClass aClass) {
|
||||
if (aClass == null) return false;
|
||||
return aClass.isValueClass() ||
|
||||
aClass.hasAnnotation(JDK_INTERNAL_VALUE_BASED) ||
|
||||
ContainerUtil.or(aClass.getSupers(), c -> isValueBasedClass(c));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi;
|
||||
|
||||
import com.intellij.lang.jvm.JvmClass;
|
||||
@@ -72,6 +72,15 @@ public interface PsiClass
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the class is a Valhalla value class.
|
||||
*
|
||||
* @return true if the class is a value class, false otherwise.
|
||||
*/
|
||||
default boolean isValueClass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of classes that this class or interface extends.
|
||||
*
|
||||
|
||||
@@ -59,22 +59,23 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
private static final @NotNull Map<CharSequence, JavaFeature> SOFT_KEYWORDS = CollectionFactory.createCharSequenceMap(true);
|
||||
|
||||
static {
|
||||
SOFT_KEYWORDS.put(VAR, JavaFeature.LVTI);
|
||||
SOFT_KEYWORDS.put(RECORD, JavaFeature.RECORDS);
|
||||
SOFT_KEYWORDS.put(YIELD, JavaFeature.SWITCH_EXPRESSION);
|
||||
SOFT_KEYWORDS.put(SEALED, JavaFeature.SEALED_CLASSES);
|
||||
SOFT_KEYWORDS.put(PERMITS, JavaFeature.SEALED_CLASSES);
|
||||
SOFT_KEYWORDS.put(WHEN, JavaFeature.PATTERN_GUARDS_AND_RECORD_PATTERNS);
|
||||
SOFT_KEYWORDS.put(OPEN, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(MODULE, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(REQUIRES, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(EXPORTS, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(MODULE, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(OPEN, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(OPENS, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(USES, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(PERMITS, JavaFeature.SEALED_CLASSES);
|
||||
SOFT_KEYWORDS.put(PROVIDES, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(TRANSITIVE, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(RECORD, JavaFeature.RECORDS);
|
||||
SOFT_KEYWORDS.put(REQUIRES, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(SEALED, JavaFeature.SEALED_CLASSES);
|
||||
SOFT_KEYWORDS.put(TO, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(TRANSITIVE, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(USES, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(VAR, JavaFeature.LVTI);
|
||||
SOFT_KEYWORDS.put(VALUE, JavaFeature.VALHALLA_VALUE_CLASSES);
|
||||
SOFT_KEYWORDS.put(WHEN, JavaFeature.PATTERN_GUARDS_AND_RECORD_PATTERNS);
|
||||
SOFT_KEYWORDS.put(WITH, JavaFeature.MODULES);
|
||||
SOFT_KEYWORDS.put(YIELD, JavaFeature.SWITCH_EXPRESSION);
|
||||
}
|
||||
|
||||
private PsiUtil() {}
|
||||
|
||||
@@ -115,7 +115,8 @@ duplicate.class.in.other.file=Duplicate class found in the file ''{0}''
|
||||
duplicate.class=Duplicate class: ''{0}''
|
||||
duplicate.reference.in.list=Duplicate reference to ''{0}'' in ''{1}'' list
|
||||
public.class.should.be.named.after.file=Class ''{0}'' is public, should be declared in a file named ''{0}.java''
|
||||
inheritance.from.final.class=Cannot inherit from {1} ''{0}''
|
||||
inheritance.from.final.class=Cannot inherit from {1, choice, 1#final class|2#enum|3#record|4#non-abstract value class} ''{0}''
|
||||
value.class.can.only.inherit=Value classes may only extend abstract value classes or 'java.lang.Object'
|
||||
package.name.file.path.mismatch=Package name ''{0}'' does not correspond to the file path ''{1}''
|
||||
missing.package.statement=Missing package statement: ''{0}''
|
||||
missing.package.statement.package.name.invalid=Missing package statement but package name ''{0}'' which corresponds to the file path is invalid
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2020 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.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.impl.cache;
|
||||
|
||||
import com.intellij.psi.JavaTokenType;
|
||||
@@ -33,6 +33,7 @@ public final class ModifierFlags {
|
||||
public static final int TRANSITIVE_MASK = 0x4000;
|
||||
public static final int SEALED_MASK = 0x8000;
|
||||
public static final int NON_SEALED_MASK = 0x10000;
|
||||
public static final int VALUE_MASK = 0x20000;
|
||||
|
||||
public static final Object2IntMap<String> NAME_TO_MODIFIER_FLAG_MAP = new Object2IntOpenHashMap<>();
|
||||
public static final Int2ObjectMap<String> MODIFIER_FLAG_TO_NAME_MAP = new Int2ObjectOpenHashMap<>();
|
||||
@@ -55,6 +56,7 @@ public final class ModifierFlags {
|
||||
NAME_TO_MODIFIER_FLAG_MAP.put(PsiModifier.TRANSITIVE, TRANSITIVE_MASK);
|
||||
NAME_TO_MODIFIER_FLAG_MAP.put(PsiModifier.SEALED, SEALED_MASK);
|
||||
NAME_TO_MODIFIER_FLAG_MAP.put(PsiModifier.NON_SEALED, NON_SEALED_MASK);
|
||||
NAME_TO_MODIFIER_FLAG_MAP.put(PsiModifier.VALUE, VALUE_MASK);
|
||||
|
||||
for (String name : NAME_TO_MODIFIER_FLAG_MAP.keySet()) {
|
||||
MODIFIER_FLAG_TO_NAME_MAP.put(NAME_TO_MODIFIER_FLAG_MAP.getInt(name), name);
|
||||
@@ -76,6 +78,7 @@ public final class ModifierFlags {
|
||||
KEYWORD_TO_MODIFIER_FLAG_MAP.put(JavaTokenType.TRANSITIVE_KEYWORD, TRANSITIVE_MASK);
|
||||
KEYWORD_TO_MODIFIER_FLAG_MAP.put(JavaTokenType.SEALED_KEYWORD, SEALED_MASK);
|
||||
KEYWORD_TO_MODIFIER_FLAG_MAP.put(JavaTokenType.NON_SEALED_KEYWORD, NON_SEALED_MASK);
|
||||
KEYWORD_TO_MODIFIER_FLAG_MAP.put(JavaTokenType.VALUE_KEYWORD, VALUE_MASK);
|
||||
}
|
||||
|
||||
public static boolean hasModifierProperty(String name, int mask) {
|
||||
|
||||
@@ -26,6 +26,13 @@ public final class RecordUtil {
|
||||
|
||||
private RecordUtil() { }
|
||||
|
||||
public static boolean hasValueModifier(@NotNull LighterAST tree, @NotNull LighterASTNode modList) {
|
||||
for (LighterASTNode child : tree.getChildren(modList)) {
|
||||
if (child.getTokenType() == JavaTokenType.VALUE_KEYWORD) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isDeprecatedByAnnotation(@NotNull LighterAST tree, @NotNull LighterASTNode modList) {
|
||||
for (final LighterASTNode child : tree.getChildren(modList)) {
|
||||
if (child.getTokenType() == JavaElementType.ANNOTATION) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.impl.compiled;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -93,7 +93,7 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
|
||||
boolean isRecord = isSet(flags, Opcodes.ACC_RECORD);
|
||||
short stubFlags = PsiClassStubImpl.packFlags(
|
||||
isDeprecated, isInterface, isEnum, false, false, isAnnotationType, false, false, myAnonymousInner, myLocalClassInner, false,
|
||||
isRecord, false);
|
||||
isRecord, false, false/*asm doesn't know about value classes yet*/);
|
||||
myResult =
|
||||
new PsiClassStubImpl<>(JavaStubElementTypes.CLASS, myParent, fqn == null ? TypeInfo.SimpleTypeInfo.NULL : fqn, shortName, null,
|
||||
stubFlags);
|
||||
|
||||
@@ -56,11 +56,12 @@ public abstract class JavaClassElementType extends JavaStubElementType<PsiClassS
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PsiClassStub<PsiClass> createStub(final @NotNull LighterAST tree, final @NotNull LighterASTNode node, final @NotNull StubElement<?> parentStub) {
|
||||
public @NotNull PsiClassStub<PsiClass> createStub(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull StubElement<?> parentStub) {
|
||||
boolean isDeprecatedByComment = false;
|
||||
boolean isInterface = false;
|
||||
boolean isEnum = false;
|
||||
boolean isRecord = false;
|
||||
boolean isValueClass = false;
|
||||
boolean isEnumConst = false;
|
||||
boolean isAnonymous = false;
|
||||
boolean isAnnotation = false;
|
||||
@@ -91,6 +92,7 @@ public abstract class JavaClassElementType extends JavaStubElementType<PsiClassS
|
||||
}
|
||||
else if (type == JavaElementType.MODIFIER_LIST) {
|
||||
hasDeprecatedAnnotation = RecordUtil.isDeprecatedByAnnotation(tree, child);
|
||||
isValueClass = RecordUtil.hasValueModifier(tree, child);
|
||||
}
|
||||
else if (type == JavaTokenType.AT) {
|
||||
isAnnotation = true;
|
||||
@@ -139,7 +141,8 @@ public abstract class JavaClassElementType extends JavaStubElementType<PsiClassS
|
||||
|
||||
boolean isImplicit = node.getTokenType() == JavaElementType.IMPLICIT_CLASS;
|
||||
final short flags = PsiClassStubImpl.packFlags(isDeprecatedByComment, isInterface, isEnum, isEnumConst, isAnonymous, isAnnotation,
|
||||
isInQualifiedNew, hasDeprecatedAnnotation, false, false, hasDocComment, isRecord, isImplicit);
|
||||
isInQualifiedNew, hasDeprecatedAnnotation, false, false, hasDocComment, isRecord,
|
||||
isImplicit, isValueClass);
|
||||
final JavaClassElementType type = typeForClass(isAnonymous, isEnumConst, isImplicit);
|
||||
return new PsiClassStubImpl<>(type, parentStub, qualifiedName, name, baseRef, flags);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.psi.impl.java.stubs;
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
@@ -23,6 +23,10 @@ public interface PsiClassStub<T extends PsiClass> extends PsiMemberStub<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isValueClass() {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isEnumConstantInitializer();
|
||||
|
||||
boolean isAnonymous();
|
||||
|
||||
@@ -27,6 +27,7 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
private static final int HAS_DOC_COMMENT = 0x400;
|
||||
private static final int RECORD = 0x800;
|
||||
private static final int IMPLICIT = 0x1000;
|
||||
private static final int VALUE_CLASS = 0x2000;
|
||||
|
||||
private final @NotNull TypeInfo myTypeInfo;
|
||||
private final String myQualifiedName;
|
||||
@@ -36,20 +37,20 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
private String mySourceFileName;
|
||||
|
||||
public PsiClassStubImpl(@NotNull JavaClassElementType type,
|
||||
final StubElement parent,
|
||||
final @Nullable String qualifiedName,
|
||||
final @Nullable String name,
|
||||
final @Nullable String baseRefText,
|
||||
final short flags) {
|
||||
StubElement parent,
|
||||
@Nullable String qualifiedName,
|
||||
@Nullable String name,
|
||||
@Nullable String baseRefText,
|
||||
short flags) {
|
||||
this(type, parent, TypeInfo.fromString(qualifiedName), name, baseRefText, flags);
|
||||
}
|
||||
|
||||
public PsiClassStubImpl(@NotNull JavaClassElementType type,
|
||||
final StubElement parent,
|
||||
final @NotNull TypeInfo typeInfo,
|
||||
final @Nullable String name,
|
||||
final @Nullable String baseRefText,
|
||||
final short flags) {
|
||||
StubElement parent,
|
||||
@NotNull TypeInfo typeInfo,
|
||||
@Nullable String name,
|
||||
@Nullable String baseRefText,
|
||||
short flags) {
|
||||
super(parent, type);
|
||||
myTypeInfo = typeInfo;
|
||||
myQualifiedName = typeInfo.text();
|
||||
@@ -111,16 +112,21 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
return BitUtil.isSet(myFlags, IMPLICIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueClass() {
|
||||
return BitUtil.isSet(myFlags, VALUE_CLASS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnumConstantInitializer() {
|
||||
return isEnumConstInitializer(myFlags);
|
||||
}
|
||||
|
||||
public static boolean isEnumConstInitializer(final short flags) {
|
||||
public static boolean isEnumConstInitializer(short flags) {
|
||||
return BitUtil.isSet(flags, ENUM_CONSTANT_INITIALIZER);
|
||||
}
|
||||
|
||||
public static boolean isImplicit(final short flags) {
|
||||
public static boolean isImplicit(short flags) {
|
||||
return BitUtil.isSet(flags, IMPLICIT);
|
||||
}
|
||||
|
||||
@@ -129,7 +135,7 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
return isAnonymous(myFlags);
|
||||
}
|
||||
|
||||
public static boolean isAnonymous(final short flags) {
|
||||
public static boolean isAnonymous(short flags) {
|
||||
return BitUtil.isSet(flags, ANONYMOUS);
|
||||
}
|
||||
|
||||
@@ -184,6 +190,7 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
localClassInner,
|
||||
hasDocComment,
|
||||
false,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
@@ -199,7 +206,8 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
boolean localClassInner,
|
||||
boolean hasDocComment,
|
||||
boolean isRecord,
|
||||
boolean isImplicit) {
|
||||
boolean isImplicit,
|
||||
boolean isValueClass) {
|
||||
short flags = 0;
|
||||
if (isDeprecated) flags |= DEPRECATED;
|
||||
if (isInterface) flags |= INTERFACE;
|
||||
@@ -214,6 +222,7 @@ public class PsiClassStubImpl<T extends PsiClass> extends StubBase<T> implements
|
||||
if (hasDocComment) flags |= HAS_DOC_COMMENT;
|
||||
if (isRecord) flags |= RECORD;
|
||||
if (isImplicit) flags |= IMPLICIT;
|
||||
if (isValueClass) flags |= VALUE_CLASS;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
@@ -454,6 +454,16 @@ public class PsiClassImpl extends JavaStubPsiElement<PsiClassStub<?>> implements
|
||||
return keyword != null && keyword.getElementType() == JavaTokenType.RECORD_KEYWORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValueClass() {
|
||||
PsiClassStub<?> stub = getGreenStub();
|
||||
if (stub != null) {
|
||||
return stub.isValueClass();
|
||||
}
|
||||
|
||||
return hasModifierProperty(PsiKeyword.VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(@NotNull PsiElementVisitor visitor){
|
||||
if (visitor instanceof JavaElementVisitor) {
|
||||
|
||||
@@ -48,6 +48,7 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
|
||||
NAME_TO_KEYWORD_TYPE_MAP.put(TRANSITIVE, JavaTokenType.TRANSITIVE_KEYWORD);
|
||||
NAME_TO_KEYWORD_TYPE_MAP.put(SEALED, JavaTokenType.SEALED_KEYWORD);
|
||||
NAME_TO_KEYWORD_TYPE_MAP.put(NON_SEALED, JavaTokenType.NON_SEALED_KEYWORD);
|
||||
NAME_TO_KEYWORD_TYPE_MAP.put(VALUE, JavaTokenType.VALUE_KEYWORD);
|
||||
|
||||
KEYWORD_TYPE_TO_NAME_MAP = new HashMap<>();
|
||||
for (String name : NAME_TO_KEYWORD_TYPE_MAP.keySet()) {
|
||||
@@ -120,6 +121,11 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
|
||||
implicitModifiers.add(STATIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (explicitModifiers.contains(VALUE) && !explicitModifiers.contains(ABSTRACT)) {
|
||||
implicitModifiers.add(FINAL);
|
||||
}
|
||||
}
|
||||
if (((PsiClass)parent).isRecord()) {
|
||||
if (!(grandParent instanceof PsiFile)) {
|
||||
implicitModifiers.add(STATIC);
|
||||
@@ -173,8 +179,13 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
|
||||
}
|
||||
else {
|
||||
PsiClass aClass = ((PsiField)parent).getContainingClass();
|
||||
if (aClass != null && aClass.isInterface()) {
|
||||
Collections.addAll(implicitModifiers, PUBLIC, STATIC, FINAL);
|
||||
if (aClass != null) {
|
||||
if (aClass.isInterface()) {
|
||||
Collections.addAll(implicitModifiers, PUBLIC, STATIC, FINAL);
|
||||
}
|
||||
else if (aClass.isValueClass()) {
|
||||
implicitModifiers.add(FINAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
final class X {
|
||||
X(int i) {}
|
||||
}
|
||||
class A extends <error descr="Cannot inherit from final 'X'">X</error> {
|
||||
class A extends <error descr="Cannot inherit from final class 'X'">X</error> {
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
// inherit from final
|
||||
public class a extends <error descr="Cannot inherit from final 'ff'">ff</error> {
|
||||
public class a extends <error descr="Cannot inherit from final class 'ff'">ff</error> {
|
||||
|
||||
void f() {
|
||||
Object o = new <error descr="Cannot inherit from final 'ff'">ff</error>() { void gg(){} };
|
||||
Object o = new <error descr="Cannot inherit from final class 'ff'">ff</error>() { void gg(){} };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Main {
|
||||
public static void main(String[] args) {
|
||||
final class First{}
|
||||
class Second extends <error descr="Cannot inherit from final 'First'">First</error>{}
|
||||
class Second extends <error descr="Cannot inherit from final class 'First'">First</error>{}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ class ClassWithComponents2<error descr="Record header declared for non-record">(
|
||||
<error descr="Modifier 'abstract' not allowed here">abstract</error> record AbstractRecord() {}
|
||||
record ExtendsObject() <error descr="'extends' not allowed on record">extends</error> Object {}
|
||||
record PermitsObject() <error descr="'permits' not allowed on record">permits</error> Object {}
|
||||
class ExtendsRecord extends <error descr="Cannot inherit from final 'NoComponents'">NoComponents</error> {}
|
||||
class ExtendsRecord extends <error descr="Cannot inherit from record 'NoComponents'">NoComponents</error> {}
|
||||
abstract class ExtendsJLR extends <error descr="Classes cannot directly extend 'java.lang.Record'">Record</error> {}
|
||||
class AnonymousExtendsJLR {
|
||||
Record r = new <error descr="Classes cannot directly extend 'java.lang.Record'">Record</error>() {
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
value class One {
|
||||
|
||||
<error descr="Variable 'value' might not have been initialized">private int value</error>;
|
||||
|
||||
<error descr="Modifier 'synchronized' not allowed here">synchronized</error> void x() {}
|
||||
}
|
||||
value class Two extends <error descr="Cannot inherit from non-abstract value class 'One'">One</error> {}
|
||||
value class Three extends <error descr="Value classes may only extend abstract value classes or 'java.lang.Object'">java.util.ArrayList</error> {}
|
||||
abstract value class Four {}
|
||||
value class Five extends Four {}
|
||||
class Six extends Four {} // it's valid to extend a value class with an identity class
|
||||
<error descr="Modifier 'value' not allowed here">value</error> interface Seven {}
|
||||
<error descr="Modifier 'value' not allowed here">value</error> enum Eight {}
|
||||
value record Nine(int no) {}
|
||||
<error descr="Illegal combination of modifiers 'sealed' and 'final'">sealed</error> value class Ten {}
|
||||
<error descr="Modifier 'non-sealed' not allowed on classes that do not have a sealed superclass">non-sealed</error> value class Eleven {}
|
||||
abstract sealed value class Twelve {}
|
||||
value class Thirteen extends Twelve {
|
||||
void x() {
|
||||
synchronized (this) {
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@ class Main {
|
||||
final ComplexVBHierarchy localVb = new ComplexVBHierarchy();
|
||||
final Object objectVb = new ComplexVBHierarchy();
|
||||
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">objectVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">objectVb</warning>) {}
|
||||
synchronized (ComplexVBHierarchy.class) {}
|
||||
f(vb);
|
||||
g(vb);
|
||||
}
|
||||
|
||||
void f(ComplexVBHierarchy vb) {
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
}
|
||||
|
||||
void g(Object vb) {
|
||||
|
||||
@@ -6,9 +6,9 @@ class AC extends AbstractValueBased {
|
||||
{
|
||||
final AC localAc = new AC();
|
||||
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">ac</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">objectAc</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">localAc</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">ac</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">objectAc</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">localAc</warning>) {}
|
||||
synchronized (AC.class) {}
|
||||
|
||||
synchronized (new Object()) {}
|
||||
@@ -18,7 +18,7 @@ class AC extends AbstractValueBased {
|
||||
}
|
||||
|
||||
void f(AC ac) {
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">ac</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">ac</warning>) {}
|
||||
}
|
||||
|
||||
void g(Object ac) {
|
||||
|
||||
@@ -6,9 +6,9 @@ class IVB implements IValueBased {
|
||||
final IVB localVb = new IVB();
|
||||
final Object objectVb = new IVB();
|
||||
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">objectVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">objectVb</warning>) {}
|
||||
synchronized (IValueBased.class) {}
|
||||
synchronized (IVB.class) {}
|
||||
f(vb);
|
||||
@@ -16,7 +16,7 @@ class IVB implements IValueBased {
|
||||
}
|
||||
|
||||
void f(IVB vb) {
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
}
|
||||
|
||||
void g(Object vb) {
|
||||
|
||||
@@ -6,16 +6,16 @@ class Main {
|
||||
final OpenValueBased localVb = new OpenValueBased();
|
||||
final Object objectVb = new OpenValueBased();
|
||||
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">objectVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">localVb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">objectVb</warning>) {}
|
||||
synchronized (OpenValueBased.class) {}
|
||||
f(vb);
|
||||
g(vb);
|
||||
}
|
||||
|
||||
void f(OpenValueBased vb) {
|
||||
synchronized (<warning descr="Attempt to synchronize on an instance of a value-based class">vb</warning>) {}
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">vb</warning>) {}
|
||||
}
|
||||
|
||||
void g(Object vb) {
|
||||
@@ -26,4 +26,8 @@ class Main {
|
||||
void h(OpenValueBased vb) {
|
||||
synchronized (vb) {}
|
||||
}
|
||||
|
||||
void i(Integer i) {
|
||||
synchronized (<warning descr="Synchronization on instance of value-based class">i</warning>) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package jdk.internal;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value={TYPE})
|
||||
public @interface ValueBased { }
|
||||
@@ -2,7 +2,7 @@ import java.util.Optional;
|
||||
|
||||
class AAA {
|
||||
static final class A {}
|
||||
static class B extends <error descr="Cannot inherit from final 'AAA.A'">A</error> {}
|
||||
static class B extends <error descr="Cannot inherit from final class 'AAA.A'">A</error> {}
|
||||
static class C extends B {}
|
||||
static class D extends B {}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
value class One {
|
||||
|
||||
value class Two {
|
||||
value class Three {}
|
||||
}
|
||||
}
|
||||
value interface I {}
|
||||
value record R() {}
|
||||
value enum E {}
|
||||
@@ -0,0 +1,109 @@
|
||||
PsiJavaFile:ValueClass.java
|
||||
PsiImportList
|
||||
<empty list>
|
||||
PsiClass:One
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:class('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:One('One')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace('\n\n ')
|
||||
PsiClass:Two
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:class('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:Two('Two')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiClass:Three
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:class('class')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:Three('Three')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n ')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiClass:I
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:interface('interface')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:I('I')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiClass:R
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:record('record')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:R('R')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiRecordHeader
|
||||
PsiJavaToken:LPARENTH('(')
|
||||
PsiJavaToken:RPARENTH(')')
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiClass:E
|
||||
PsiModifierList:value
|
||||
PsiKeyword:value('value')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiKeyword:enum('enum')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiIdentifier:E('E')
|
||||
PsiTypeParameterList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiReferenceList
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PsiJavaToken:LBRACE('{')
|
||||
PsiJavaToken:RBRACE('}')
|
||||
@@ -0,0 +1,109 @@
|
||||
java.FILE
|
||||
IMPORT_LIST
|
||||
<empty list>
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
CLASS_KEYWORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
WHITE_SPACE
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
CLASS_KEYWORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
WHITE_SPACE
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
CLASS_KEYWORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
RBRACE
|
||||
WHITE_SPACE
|
||||
RBRACE
|
||||
WHITE_SPACE
|
||||
RBRACE
|
||||
WHITE_SPACE
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
INTERFACE_KEYWORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
RBRACE
|
||||
WHITE_SPACE
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
RECORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
RECORD_HEADER
|
||||
LPARENTH
|
||||
RPARENTH
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
RBRACE
|
||||
WHITE_SPACE
|
||||
CLASS
|
||||
MODIFIER_LIST
|
||||
VALUE_KEYWORD
|
||||
WHITE_SPACE
|
||||
ENUM_KEYWORD
|
||||
WHITE_SPACE
|
||||
IDENTIFIER
|
||||
TYPE_PARAMETER_LIST
|
||||
<empty list>
|
||||
EXTENDS_LIST
|
||||
<empty list>
|
||||
IMPLEMENTS_LIST
|
||||
<empty list>
|
||||
WHITE_SPACE
|
||||
LBRACE
|
||||
RBRACE
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInsight.daemon;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class ValueClassHighlightingTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
|
||||
public void testValueClass() { doTest(); }
|
||||
|
||||
protected void doTest() {
|
||||
myFixture.configureByFile(getTestName(false) + ".java");
|
||||
myFixture.checkHighlighting();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
|
||||
return JAVA_X;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return JavaTestUtil.getRelativeJavaTestDataPath() + "/codeInsight/daemonCodeAnalyzer/valueClass";
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInsight.daemon.valuebased;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.valuebased.SynchronizeOnValueBasedClassInspection;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SynchronizeOnValueBasedClassHighlightTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
public class SynchronizeOnValueBasedClassInspectionTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
static final @NonNls String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/valuebased";
|
||||
|
||||
@Override
|
||||
@@ -37,4 +39,9 @@ public class SynchronizeOnValueBasedClassHighlightTest extends LightJavaCodeInsi
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
|
||||
return JAVA_21_ANNOTATED;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2020 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.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.siyeh.ig.numeric;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
@@ -18,5 +18,5 @@ public class CachedNumberConstructorCallInspectionTest extends LightJavaInspecti
|
||||
public void testSimple() { doStatementTest("new /*Number constructor call with primitive argument*/Integer/**/(1);"); }
|
||||
public void testStringArgument() { doStatementTest("new /*Number constructor call with primitive argument*/Byte/**/(\"1\");"); }
|
||||
public void testNoWarn() { doStatementTest("Long.valueOf(1L);"); }
|
||||
public void testNoAssertionError() { doStatementTest("Integer i = new /*!Cannot inherit from final 'java.lang.Integer'*/Integer/*!*/(new String/*!'(' or '[' expected*//*!',' or ')' expected*/{/*!*//*!*/}/*!';' expected*//*!Unexpected token*/)/*!*//*!*/;"); }
|
||||
public void testNoAssertionError() { doStatementTest("Integer i = new /*!Cannot inherit from final class 'java.lang.Integer'*/Integer/*!*/(new String/*!'(' or '[' expected*//*!',' or ')' expected*/{/*!*//*!*/}/*!';' expected*//*!Unexpected token*/)/*!*//*!*/;"); }
|
||||
}
|
||||
|
||||
@@ -826,7 +826,7 @@ inspection.unresolved.module.dependencies.problem.descriptor=Unresolved module d
|
||||
inspection.auto.add.module.requirements.quickfix=Fill in module dependencies
|
||||
inspection.value.based.warnings=Value-based warnings
|
||||
inspection.preview.feature=Preview Feature warning
|
||||
inspection.value.based.warnings.synchronization=Attempt to synchronize on an instance of a value-based class
|
||||
inspection.value.based.warnings.synchronization=Synchronization on instance of value-based class
|
||||
inspection.variable.assigned.to.itself.display.name=Variable is assigned to itself
|
||||
inspection.wrapper.type.may.be.primitive.fix.name=Convert wrapper type to primitive
|
||||
inspection.wrapper.type.may.be.primitive.name=Type may be primitive
|
||||
|
||||
Reference in New Issue
Block a user