diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
index fbb90cdaf9cd..7089cc697eb7 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java
@@ -7,6 +7,10 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixActionRegistrarImpl;
import com.intellij.codeInsight.intention.QuickFixFactory;
+import com.intellij.lang.jvm.JvmEnumField;
+import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute;
+import com.intellij.lang.jvm.annotation.JvmAnnotationAttributeValue;
+import com.intellij.lang.jvm.annotation.JvmAnnotationEnumFieldValue;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
@@ -22,6 +26,7 @@ import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.PsiImplUtil;
+import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.SuperMethodsSearch;
@@ -32,12 +37,15 @@ import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
+import static com.intellij.util.ObjectUtils.tryCast;
+
public class GenericsHighlightUtil {
private static final Logger LOG = Logger.getInstance(GenericsHighlightUtil.class);
@@ -1548,4 +1556,50 @@ public class GenericsHighlightUtil {
}
return null;
}
+
+ @Nullable
+ @Contract(value = "null -> null", pure = true)
+ static HighlightingFeature extractHighlightingFeature(@Nullable final PsiAnnotation annotation) {
+ if (annotation == null) return null;
+ if (!CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE.equals(annotation.getQualifiedName())) return null;
+
+ final JvmAnnotationAttribute feature = annotation.findAttribute("feature");
+ if (feature == null) return null;
+
+ final JvmAnnotationAttributeValue attributeValue = feature.getAttributeValue();
+ if (attributeValue == null) return null;
+
+ final JvmAnnotationEnumFieldValue annotationEnumFieldValue = tryCast(attributeValue, JvmAnnotationEnumFieldValue.class);
+ if (annotationEnumFieldValue == null) return null;
+
+ final JvmEnumField field = annotationEnumFieldValue.getField();
+ if (field == null) return null;
+
+ return HighlightingFeature.convertFromPreviewFeature(field.getName());
+ }
+
+ public static HighlightInfo checkTypePreviewFeatureAnnotation(@NotNull final PsiTypeElement type,
+ @NotNull final LanguageLevel level) {
+ final PsiClass clazz = PsiTypesUtil.getPsiClass(type.getType());
+
+ final PsiAnnotation annotation = getPreviewFeatureAnnotation(clazz);
+ if (annotation == null) return null;
+
+ final HighlightingFeature feature = extractHighlightingFeature(annotation);
+ if (feature == null) return null;
+
+ return HighlightUtil.checkFeature(type, feature, level, type.getContainingFile());
+ }
+
+ @Nullable
+ @Contract(value = "null -> null", pure = true)
+ private static PsiAnnotation getPreviewFeatureAnnotation(@Nullable final PsiClass clazz) {
+ if (clazz == null) return null;
+ final PsiAnnotation annotation = clazz.getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE);
+ if (annotation != null) return annotation;
+
+ final PsiPackage psiPackage = JavaResolveUtil.getContainingPackage(clazz);
+ if (psiPackage == null) return null;
+ return psiPackage.getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE);
+ }
}
\ No newline at end of file
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java
index e041b05c8217..7af37992e1c8 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java
@@ -860,6 +860,26 @@ public class HighlightClassUtil {
return checkCreateInnerClassFromStaticContext(expression, qualifier, aClass);
}
+ /**
+ * This method validates that the language level of the project where a new expression accesses
+ * the constructor that is annotated with {@link CommonClassNames#JDK_INTERNAL_PREVIEW_FEATURE} is sufficient
+ *
+ * @param expression the expression to examine
+ * @param level the current language level
+ * @return an instance of HighlightInfo with a quickfix to set the appropriate language level
+ * if the current language level is not sufficient or null
+ */
+ static HighlightInfo checkConstructorPreviewFeature(@NotNull final PsiNewExpression expression,
+ @NotNull final LanguageLevel level) {
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) return null;
+
+ final HighlightingFeature feature = GenericsHighlightUtil.extractHighlightingFeature(method.getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE));
+ if (feature == null) return null;
+
+ return HighlightUtil.checkFeature(expression, feature, level, expression.getContainingFile());
+ }
+
public static HighlightInfo checkCreateInnerClassFromStaticContext(@NotNull PsiElement element,
@Nullable PsiExpression qualifier,
@Nullable PsiClass aClass) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
index 75371eb41cd4..11ea420d1208 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
@@ -55,6 +55,8 @@ import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Stream;
+import static com.intellij.util.ObjectUtils.tryCast;
+
public class HighlightMethodUtil {
private static final QuickFixFactory QUICK_FIX_FACTORY = QuickFixFactory.getInstance();
private static final Logger LOG = Logger.getInstance(HighlightMethodUtil.class);
@@ -1285,7 +1287,7 @@ public class HighlightMethodUtil {
if (!JavaPsiConstructorUtil.isConstructorCall(methodCall)) return null;
PsiElement codeBlock = methodCall.getParent().getParent();
if (codeBlock instanceof PsiCodeBlock) {
- PsiMethod ctor = ObjectUtils.tryCast(codeBlock.getParent(), PsiMethod.class);
+ PsiMethod ctor = tryCast(codeBlock.getParent(), PsiMethod.class);
if (ctor != null && ctor.isConstructor()) {
if (JavaPsiRecordUtil.isCompactConstructor(ctor) ||
JavaPsiRecordUtil.isExplicitCanonicalConstructor(ctor)) {
@@ -1317,6 +1319,27 @@ public class HighlightMethodUtil {
return null;
}
+ /**
+ * This method validates that the language level of the project where a call expression accesses
+ * the method that is annotated with {@link CommonClassNames#JDK_INTERNAL_PREVIEW_FEATURE} is sufficient
+ *
+ * @param methodCallExpression the expression to examine
+ * @param level the current language level
+ * @return an instance of HighlightInfo with a quickfix to set the appropriate language level
+ * if the current language level is not sufficient or null
+ */
+ static HighlightInfo checkMethodCallPreviewFeatureAnnotation(@NotNull final PsiMethodCallExpression methodCallExpression,
+ @NotNull final LanguageLevel level) {
+ final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
+ final PsiElement targetMethod = methodExpression.resolve();
+ if (!(targetMethod instanceof PsiJvmModifiersOwner)) return null;
+
+ final PsiAnnotation annotation = ((PsiJvmModifiersOwner)targetMethod).getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE);
+ final HighlightingFeature feature = GenericsHighlightUtil.extractHighlightingFeature(annotation);
+ if (feature == null) return null;
+
+ return HighlightUtil.checkFeature(methodCallExpression, feature, level, methodCallExpression.getContainingFile());
+ }
static HighlightInfo checkConstructorCallsBaseClassConstructor(@NotNull PsiMethod constructor,
@Nullable RefCountHolder refCountHolder,
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
index e02efb254839..4e0c4382db99 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
@@ -1592,6 +1592,38 @@ public class HighlightUtil {
return null;
}
+ public static HighlightInfo checkFieldPreviewFeatureAnnotation(@NotNull final PsiReferenceExpression expression,
+ @NotNull final PsiField field,
+ @NotNull final LanguageLevel level) {
+ final HighlightingFeature feature = GenericsHighlightUtil.extractHighlightingFeature(field.getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE));
+ if (feature == null) return null;
+
+ return checkFeature(expression, feature, level, expression.getContainingFile());
+ }
+
+ public static HighlightInfo checkPackagePreviewFeatureAnnotation(@NotNull final PsiImportStatement statement,
+ @NotNull final LanguageLevel level) {
+ final PsiElement resolve = statement.resolve();
+ final PsiPackage psiPackage;
+ if (resolve instanceof PsiPackage) {
+ psiPackage = (PsiPackage)resolve;
+ }
+ else if (resolve instanceof PsiClass) {
+ psiPackage = JavaResolveUtil.getContainingPackage((PsiClass)resolve);
+ }
+ else {
+ return null;
+ }
+
+ if (psiPackage == null) return null;
+
+ final PsiAnnotation annotation = psiPackage.getAnnotation(CommonClassNames.JDK_INTERNAL_PREVIEW_FEATURE);
+ final HighlightingFeature feature = GenericsHighlightUtil.extractHighlightingFeature(annotation);
+ if (feature == null) return null;
+
+ return checkFeature(statement, feature, level, statement.getContainingFile());
+ }
+
private enum SelectorKind { INT, ENUM, STRING }
private static SelectorKind getSwitchSelectorKind(@NotNull PsiType type) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
index b4a1a2c0905c..70250ad56adc 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java
@@ -760,6 +760,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses,myFile));
}
+ if (!myHolder.hasErrorResults()) {
+ myHolder.add(HighlightUtil.checkPackagePreviewFeatureAnnotation(statement, myLanguageLevel));
+ }
}
@Override
@@ -990,6 +993,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkSuperAbstractMethodDirectCall(expression));
if (!myHolder.hasErrorResults()) visitExpression(expression);
+ if (!myHolder.hasErrorResults()) myHolder.add(HighlightMethodUtil.checkMethodCallPreviewFeatureAnnotation(expression, myLanguageLevel));
}
@Override
@@ -1081,6 +1085,8 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) registerConstructorCall(expression);
if (!myHolder.hasErrorResults()) visitExpression(expression);
+
+ if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkConstructorPreviewFeature(expression, myLanguageLevel));
}
@Override
@@ -1399,6 +1405,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults() && resolved instanceof PsiField) {
try {
myHolder.add(HighlightUtil.checkIllegalForwardReferenceToField(expression, (PsiField)resolved));
+ if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkFieldPreviewFeatureAnnotation(expression, (PsiField)resolved, myLanguageLevel));
}
catch (IndexNotReadyException ignored) { }
}
@@ -1806,6 +1813,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalType(type));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type));
+ if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypePreviewFeatureAnnotation(type, myLanguageLevel));
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingFeature.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingFeature.java
index 8f77b73447ed..609132bf1245 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingFeature.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightingFeature.java
@@ -7,6 +7,7 @@ import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.PropertyKey;
public enum HighlightingFeature {
@@ -89,4 +90,18 @@ public enum HighlightingFeature {
LanguageLevel getStandardLevel() {
return level.isPreview() ? null : level;
}
+
+ @Nullable
+ public static HighlightingFeature convertFromPreviewFeature(@NotNull final String feature) {
+ switch (feature) {
+ case "PATTERN_MATCHING_IN_INSTANCEOF":
+ return PATTERNS;
+ case "TEXT_BLOCKS":
+ return TEXT_BLOCKS;
+ case "RECORDS":
+ return RECORDS;
+ default:
+ return null;
+ }
+ }
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java
index aa114f84b724..412c4b4b514f 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java
@@ -300,4 +300,9 @@ public class JavaResolveUtil {
return PsiResolveHelper.SERVICE.getInstance(project)
.resolveConstructor(PsiTypesUtil.getClassType(superClassWhichTheSuperCallMustResolveTo), expressionList, place).getElement();
}
+
+ public static PsiPackage getContainingPackage(@NotNull PsiClass psiClass) {
+ PsiDirectory directory = psiClass.getContainingFile().getContainingDirectory();
+ return directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory);
+ }
}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallConstructorWithPreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallConstructorWithPreviewFeature.java
new file mode 100644
index 000000000000..2218481f2e98
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallConstructorWithPreviewFeature.java
@@ -0,0 +1,20 @@
+import jdk.internal.PreviewFeature;
+import jdk.internal.PreviewFeature.Feature;
+
+class Main {
+ @PreviewFeature(feature=Feature.PATTERN_MATCHING_IN_INSTANCEOF)
+ Main(){}
+ @PreviewFeature(feature=Feature.RECORDS)
+ Main(long i){}
+ @PreviewFeature(feature=Feature.TEXT_BLOCKS)
+ Main(String s){}
+ Main(int i){}
+
+ static {
+ new Main();
+ new Main(42l);
+ new Main("42");
+ new Main(42);
+ }
+
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallMethodsWithPreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallMethodsWithPreviewFeature.java
new file mode 100644
index 000000000000..f6398c56d47f
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/CallMethodsWithPreviewFeature.java
@@ -0,0 +1,20 @@
+import jdk.internal.PreviewFeature;
+import jdk.internal.PreviewFeature.Feature;
+
+class Main {
+ static {
+ requirePatternMatching();
+ Main.requireTextBlocks();
+ new Main().requireRecords();
+ }
+
+ @PreviewFeature(feature=Feature.PATTERN_MATCHING_IN_INSTANCEOF)
+ static void requirePatternMatching(){}
+
+ @PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.TEXT_BLOCKS)
+ static void requireTextBlocks(){}
+
+ @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS)
+ void requireRecords(){}
+
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/FieldsWithPreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/FieldsWithPreviewFeature.java
new file mode 100644
index 000000000000..f0900ba2fb3a
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/FieldsWithPreviewFeature.java
@@ -0,0 +1,22 @@
+import jdk.internal.PreviewFeature;
+import jdk.internal.PreviewFeature.Feature;
+
+class Main {
+ @PreviewFeature(feature=Feature.PATTERN_MATCHING_IN_INSTANCEOF)
+ static String instanceOf;
+ @PreviewFeature(feature=Feature.RECORDS)
+ static long records;
+ @PreviewFeature(feature=Feature.TEXT_BLOCKS)
+ String textBlocks;
+ int i;
+ org.myorg.preview.FromPreview preview;
+
+ static {
+ String s = new Main().textBlocks;
+ String o = Main.instanceOf;
+ long l = records;
+ int k = new Main().i;
+ org.myorg.preview.FromPreview local = null;
+ }
+
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/ImportWithPreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/ImportWithPreviewFeature.java
new file mode 100644
index 000000000000..322aec36102d
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/ImportWithPreviewFeature.java
@@ -0,0 +1,3 @@
+import org.myorg.preview.FromPreview;
+
+class Main { }
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/PreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/PreviewFeature.java
new file mode 100644
index 000000000000..e1e1ac37ab3a
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/PreviewFeature.java
@@ -0,0 +1,26 @@
+package jdk.internal;
+
+import java.lang.annotation.*;
+
+@Target({ElementType.METHOD,
+ ElementType.CONSTRUCTOR,
+ ElementType.FIELD,
+ ElementType.PACKAGE,
+ ElementType.TYPE})
+@Retention(RetentionPolicy.CLASS)
+public @interface PreviewFeature {
+ /**
+ * Name of the preview feature the annotated API is associated
+ * with.
+ */
+ public Feature feature();
+
+ public boolean essentialAPI() default false;
+
+ public enum Feature {
+ PATTERN_MATCHING_IN_INSTANCEOF,
+ TEXT_BLOCKS,
+ RECORDS,
+ ;
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/TypeWithPreviewFeature.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/TypeWithPreviewFeature.java
new file mode 100644
index 000000000000..6077bf3cf6a9
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/TypeWithPreviewFeature.java
@@ -0,0 +1,17 @@
+import jdk.internal.PreviewFeature;
+import jdk.internal.PreviewFeature.Feature;
+
+class Main {
+ @PreviewFeature(feature=Feature.PATTERN_MATCHING_IN_INSTANCEOF)
+ class InstanceOf{}
+ @PreviewFeature(feature=Feature.RECORDS)
+ class Records{}
+ @PreviewFeature(feature=Feature.TEXT_BLOCKS)
+ class TextBlocks{}
+ class Empty{}
+
+ private void f(InstanceOf o, Empty e) {}
+ private void f(Empty e, Records r) {}
+ private void f(TextBlocks e, Records r) {}
+ private void f(org.myorg.preview.FromPreview p) {}
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/FromPreview.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/FromPreview.java
new file mode 100644
index 000000000000..23889c67d448
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/FromPreview.java
@@ -0,0 +1,3 @@
+package org.myorg.preview;
+
+public interface FromPreview {}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/package-info.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/package-info.java
new file mode 100644
index 000000000000..96aa0cab3435
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/previewfeature/packagepreview/package-info.java
@@ -0,0 +1,2 @@
+@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.PATTERN_MATCHING_IN_INSTANCEOF)
+package org.myorg.preview;
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/previewfeature/PreviewFeatureAnnotationTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/previewfeature/PreviewFeatureAnnotationTest.java
new file mode 100644
index 000000000000..4ac57e48e07f
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/previewfeature/PreviewFeatureAnnotationTest.java
@@ -0,0 +1,50 @@
+// 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.
+package com.intellij.java.codeInsight.daemon.previewfeature;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class PreviewFeatureAnnotationTest extends LightJavaCodeInsightFixtureTestCase {
+ @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/previewfeature";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final String previewFeatureAnnotation = BASE_PATH + "/PreviewFeature.java";
+ final String packagePreview = BASE_PATH + "/" + "packagepreview/package-info.java";
+ final String interfaceInPreviewPackage = BASE_PATH + "/" + "packagepreview/FromPreview.java";
+ myFixture.configureByFile(previewFeatureAnnotation);
+ myFixture.configureByFile(packagePreview);
+ myFixture.configureByFile(interfaceInPreviewPackage);
+ }
+
+ @Override
+ protected @NotNull LightProjectDescriptor getProjectDescriptor() {
+ return JAVA_8;
+ }
+
+ public void testCallMethodsWithPreviewFeature() { doTest(); }
+ public void testCallConstructorWithPreviewFeature() { doTest(); }
+ public void testTypeWithPreviewFeature() { doTest(); }
+ public void testFieldsWithPreviewFeature() { doTest(); }
+ public void testImportWithPreviewFeature() { doTest();}
+
+ private void doTest() {
+ String filePath = BASE_PATH + "/" + getTestName(false) + ".java";
+ myFixture.configureByFile(filePath);
+ myFixture.checkHighlighting();
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return JavaTestUtil.getJavaTestDataPath();
+ }
+
+ //@Override
+ //protected String getBasePath() {
+ // return BASE_PATH;
+ //}
+}
diff --git a/platform/core-api/src/com/intellij/psi/CommonClassNames.java b/platform/core-api/src/com/intellij/psi/CommonClassNames.java
index dbed2e1d289b..f777684d044f 100644
--- a/platform/core-api/src/com/intellij/psi/CommonClassNames.java
+++ b/platform/core-api/src/com/intellij/psi/CommonClassNames.java
@@ -115,6 +115,8 @@ public interface CommonClassNames {
String JAVA_UTIL_FUNCTION_BI_FUNCTION = "java.util.function.BiFunction";
String JAVA_UTIL_FUNCTION_SUPPLIER = "java.util.function.Supplier";
+ String JDK_INTERNAL_PREVIEW_FEATURE = "jdk.internal.PreviewFeature";
+
String JAVA_LANG_INVOKE_MH_POLYMORPHIC = "java.lang.invoke.MethodHandle.PolymorphicSignature";
String CLASS_FILE_EXTENSION = ".class";