Skip to content

Commit

Permalink
java: "Java X" language level for experimental features; T<any> wildc…
Browse files Browse the repository at this point in the history
…ard support
  • Loading branch information
trespasserw committed Jul 14, 2015
1 parent 270e741 commit 9f7de20
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 71 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -354,7 +354,7 @@ public static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass) {
}

private static HighlightInfo checkInterfaceMultipleInheritance(PsiClass aClass,
PsiElement place,
PsiElement place,
PsiSubstitutor derivedSubstitutor,
Map<PsiClass, PsiSubstitutor> inheritedClasses,
Set<PsiClass> visited,
Expand Down Expand Up @@ -659,7 +659,7 @@ else if (refParent instanceof PsiReferenceList) {
return null;
}

public static HighlightInfo checkReferenceTypeUsedAsTypeArgument(final PsiTypeElement typeElement) {
static HighlightInfo checkReferenceTypeUsedAsTypeArgument(PsiTypeElement typeElement, LanguageLevel level) {
final PsiType type = typeElement.getType();
if (type != PsiType.NULL && type instanceof PsiPrimitiveType ||
type instanceof PsiWildcardType && ((PsiWildcardType)type).getBound() instanceof PsiPrimitiveType) {
Expand All @@ -669,18 +669,20 @@ public static HighlightInfo checkReferenceTypeUsedAsTypeArgument(final PsiTypeEl
.getElement();
if (element == null) return null;

String description = JavaErrorMessages.message("generics.type.argument.cannot.be.of.primitive.type");
final HighlightInfo highlightInfo =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
if (level.isAtLeast(LanguageLevel.JDK_X)) return null;

String text = JavaErrorMessages.message("generics.type.argument.cannot.be.of.primitive.type");
HighlightInfo highlightInfo = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(text).create();

PsiType toConvert = type;
if (type instanceof PsiWildcardType) {
toConvert = ((PsiWildcardType)type).getBound();
}
if (toConvert instanceof PsiPrimitiveType) {
final PsiClassType boxedType = ((PsiPrimitiveType)toConvert).getBoxedType(typeElement);
if (boxedType != null) {
QuickFixAction.registerQuickFixAction(highlightInfo,
QUICK_FIX_FACTORY.createReplacePrimitiveWithBoxedTypeAction(typeElement, toConvert.getPresentableText(), ((PsiPrimitiveType)toConvert).getBoxedTypeName()));
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createReplacePrimitiveWithBoxedTypeAction(
typeElement, toConvert.getPresentableText(), ((PsiPrimitiveType)toConvert).getBoxedTypeName()));
}
}
return highlightInfo;
Expand Down Expand Up @@ -721,7 +723,7 @@ public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(@NotNull P
final PsiMember constructorOrInitializer = PsiUtil.findEnclosingConstructorOrInitializer(expr);
if (constructorOrInitializer == null) return null;
if (constructorOrInitializer.hasModifierProperty(PsiModifier.STATIC)) return null;
final PsiClass aClass = constructorOrInitializer instanceof PsiEnumConstantInitializer ?
final PsiClass aClass = constructorOrInitializer instanceof PsiEnumConstantInitializer ?
(PsiClass)constructorOrInitializer : constructorOrInitializer.getContainingClass();
if (aClass == null || !(aClass.isEnum() || aClass instanceof PsiEnumConstantInitializer)) return null;
final PsiField field = (PsiField)resolved;
Expand All @@ -747,7 +749,7 @@ public static HighlightInfo checkAccessStaticFieldFromEnumConstructor(@NotNull P

@Nullable
public static HighlightInfo checkEnumInstantiation(PsiElement expression, PsiClass aClass) {
if (aClass != null && aClass.isEnum() &&
if (aClass != null && aClass.isEnum() &&
(!(expression instanceof PsiNewExpression) ||
((PsiNewExpression)expression).getArrayDimensions().length == 0 && ((PsiNewExpression)expression).getArrayInitializer() == null)) {
String description = JavaErrorMessages.message("enum.types.cannot.be.instantiated");
Expand Down Expand Up @@ -1283,8 +1285,8 @@ private static boolean unqualifiedNestedClassReferenceAccessedViaContainingClass
final PsiElement superClass = referenceElement.resolve();
if (superClass instanceof PsiClass) {
final PsiClass superContainingClass = ((PsiClass)superClass).getContainingClass();
if (superContainingClass != null &&
InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true) &&
if (superContainingClass != null &&
InheritanceUtil.isInheritorOrSelf(containingClass, superContainingClass, true) &&
!PsiTreeUtil.isAncestor(superContainingClass, containingClass, true)) {
return true;
}
Expand All @@ -1297,7 +1299,7 @@ private static boolean unqualifiedNestedClassReferenceAccessedViaContainingClass

public static void registerVariableParameterizedTypeFixes(HighlightInfo highlightInfo,
@NotNull PsiVariable variable,
@NotNull PsiReferenceParameterList parameterList,
@NotNull PsiReferenceParameterList parameterList,
@NotNull JavaSdkVersion version) {
PsiType type = variable.getType();
if (!(type instanceof PsiClassType)) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1490,7 +1490,7 @@ public void visitResourceList(PsiResourceList resourceList) {
@Override
public void visitTypeElement(final PsiTypeElement type) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalType(type));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkReferenceTypeUsedAsTypeArgument(type, myLanguageLevel));
if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkWildcardUsage(type));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,7 +33,9 @@ public enum JavaSdkVersion {
JDK_1_7(LanguageLevel.JDK_1_7, "1.7"),
JDK_1_8(LanguageLevel.JDK_1_8, "1.8"),
JDK_1_9(LanguageLevel.JDK_1_9, "1.9");


private static final JavaSdkVersion MAX_JDK = JDK_1_9;

private final LanguageLevel myMaxLanguageLevel;
private final String myDescription;

Expand Down Expand Up @@ -75,6 +77,9 @@ public static JavaSdkVersion byDescription(@NotNull String description) throws I

@NotNull
public static JavaSdkVersion fromLanguageLevel(@NotNull LanguageLevel languageLevel) throws IllegalArgumentException {
if (languageLevel == LanguageLevel.JDK_X) {
return MAX_JDK;
}
JavaSdkVersion[] values = values();
for (int i = values.length - 1; i >= 0; i--) {
JavaSdkVersion version = values[i];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,7 +20,6 @@
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.openapi.util.Key;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand All @@ -36,21 +35,21 @@ public enum LanguageLevel {
JDK_1_6("Java 6", JavaCoreBundle.message("jdk.1.6.language.level.description")),
JDK_1_7("Java 7", JavaCoreBundle.message("jdk.1.7.language.level.description")),
JDK_1_8("Java 8", JavaCoreBundle.message("jdk.1.8.language.level.description")),
JDK_1_9("Java 9", JavaCoreBundle.message("jdk.1.9.language.level.description"));
JDK_1_9("Java 9", JavaCoreBundle.message("jdk.1.9.language.level.description")),
JDK_X("Java X", JavaCoreBundle.message("jdk.X.language.level.description"));

public static final LanguageLevel HIGHEST = JDK_1_8; // TODO! when language level 9 is really supported, update this field
public static final Key<LanguageLevel> KEY = Key.create("LANGUAGE_LEVEL");

private final String myName;
private final String myPresentableText;

LanguageLevel(@NotNull @NonNls String name, @NotNull @Nls String presentableText) {
LanguageLevel(@NotNull String name, @NotNull @Nls String presentableText) {
myName = name;
myPresentableText = presentableText;
}

@NotNull
@NonNls
public String getName() {
return myName;
}
Expand Down
4 changes: 3 additions & 1 deletion java/java-psi-api/src/messages/JavaCoreBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ jdk.1.5.language.level.description=5.0 - 'enum' keyword, generics, autoboxing et
jdk.1.6.language.level.description=6 - @Override in interfaces
jdk.1.7.language.level.description=7 - Diamonds, ARM, multi-catch etc.
jdk.1.8.language.level.description=8 - Lambdas, type annotations etc.
jdk.1.9.language.level.description=9 - Jigsaw project etc.
jdk.1.9.language.level.description=9 - JDK modularization etc.

jdk.X.language.level.description=X - Experimental features
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,8 +21,6 @@
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.java.JavaParserDefinition;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
Expand All @@ -38,7 +36,6 @@
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.SystemProperties;
import com.intellij.util.indexing.IndexingDataKeys;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -122,12 +119,6 @@ else if (ElementType.JAVA_PLAIN_COMMENT_BIT_SET.contains(tokenType)) {
public static final WhitespacesAndCommentsBinder SPECIAL_PRECEDING_COMMENT_BINDER = new PrecedingWhitespacesAndCommentsBinder(true);
public static final WhitespacesAndCommentsBinder TRAILING_COMMENT_BINDER = new TrailingWhitespacesAndCommentsBinder();

public static final boolean EXPERIMENTAL_FEATURES;
static {
Application app = ApplicationManager.getApplication();
EXPERIMENTAL_FEATURES = SystemProperties.getBooleanProperty("idea.experimental.java.features", app != null && app.isUnitTestMode());
}

private JavaParserUtil() { }

public static void setLanguageLevel(final PsiBuilder builder, final LanguageLevel level) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -102,15 +102,20 @@ private TypeInfo parseTypeInfo(PsiBuilder builder, int flags, boolean badWildcar
if (expect(builder, ElementType.PRIMITIVE_TYPE_BIT_SET)) {
typeInfo.isPrimitive = true;
}
else if (tokenType == JavaTokenType.IDENTIFIER) {
parseJavaCodeReference(builder, isSet(flags, EAT_LAST_DOT), true, false, false, false, isSet(flags, DIAMONDS), typeInfo);
}
else if ((isSet(flags, WILDCARD) || badWildcard) && tokenType == JavaTokenType.QUEST) {
builder.advanceLexer();
else if ((isSet(flags, WILDCARD) || badWildcard) && (tokenType == JavaTokenType.QUEST || isKeywordAny(builder))) {
if (tokenType == JavaTokenType.QUEST) {
builder.advanceLexer();
}
else {
dummy(builder);
}
completeWildcardType(builder, isSet(flags, WILDCARD), type);
typeInfo.marker = type;
return typeInfo;
}
else if (tokenType == JavaTokenType.IDENTIFIER) {
parseJavaCodeReference(builder, isSet(flags, EAT_LAST_DOT), true, false, false, false, isSet(flags, DIAMONDS), typeInfo);
}
else if (isSet(flags, DIAMONDS) && tokenType == JavaTokenType.GT) {
emptyElement(builder, JavaElementType.DIAMOND_TYPE);
type.done(JavaElementType.TYPE);
Expand Down Expand Up @@ -344,10 +349,8 @@ public PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) {

myParser.getDeclarationParser().parseAnnotations(builder);

if (EXPERIMENTAL_FEATURES && "any".equals(builder.getTokenText()) && getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_1_9)) {
PsiBuilder.Marker mark = builder.mark();
builder.advanceLexer();
mark.done(JavaElementType.DUMMY_ELEMENT);
if (isKeywordAny(builder)) {
dummy(builder);
}

final boolean wild = expect(builder, JavaTokenType.QUEST);
Expand All @@ -368,8 +371,7 @@ public PsiBuilder.Marker parseTypeParameter(final PsiBuilder builder) {
}

@NotNull
public PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IElementType start,
@Nullable final IElementType type, final IElementType delimiter) {
public PsiBuilder.Marker parseReferenceList(PsiBuilder builder, IElementType start, @Nullable IElementType type, IElementType delimiter) {
final PsiBuilder.Marker element = builder.mark();

if (expect(builder, start)) {
Expand All @@ -392,4 +394,14 @@ public PsiBuilder.Marker parseReferenceList(final PsiBuilder builder, final IEle
}
return element;
}

private static boolean isKeywordAny(PsiBuilder builder) {
return getLanguageLevel(builder).isAtLeast(LanguageLevel.JDK_X) && "any".equals(builder.getTokenText());
}

private static void dummy(PsiBuilder builder) {
PsiBuilder.Marker mark = builder.mark();
builder.advanceLexer();
mark.done(JavaElementType.DUMMY_ELEMENT);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -124,7 +124,8 @@ else if (PsiUtil.isJavaToken(child, JavaTokenType.ELLIPSIS)) {
type = PsiEllipsisType.createEllipsis(type, array);
}

if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST)) {
if (PsiUtil.isJavaToken(child, JavaTokenType.QUEST) ||
child instanceof ASTNode && ((ASTNode)child).getElementType() == JavaElementType.DUMMY_ELEMENT && "any".equals(child.getText())) {
assert type == null : this;
PsiElement boundKind = PsiTreeUtil.skipSiblingsForward(child, PsiComment.class, PsiWhiteSpace.class);
PsiElement boundType = PsiTreeUtil.skipSiblingsForward(boundKind, PsiComment.class, PsiWhiteSpace.class);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class C<X, any Y> { }

class Test {
void m(C<?, any> c) { }

void test() {
C<String, int> c = new C<String, int>();
m(c);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
PsiJavaFile:AnyTypeArgs.java
PsiTypeElement:T<E_SRC, any, E_DST, ?>
PsiJavaCodeReferenceElement:T<E_SRC, any, E_DST, ?>
PsiIdentifier:T('T')
PsiReferenceParameterList
PsiJavaToken:LT('<')
PsiTypeElement:E_SRC
PsiJavaCodeReferenceElement:E_SRC
PsiIdentifier:E_SRC('E_SRC')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeElement:any
PsiElement(DUMMY_ELEMENT)
PsiIdentifier:any('any')
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeElement:E_DST
PsiJavaCodeReferenceElement:E_DST
PsiIdentifier:E_DST('E_DST')
PsiReferenceParameterList
<empty list>
PsiJavaToken:COMMA(',')
PsiWhiteSpace(' ')
PsiTypeElement:?
PsiJavaToken:QUEST('?')
PsiJavaToken:GT('>')
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PsiJavaFile:AnyType.java
PsiJavaFile:AnyTypeParams.java
PsiTypeParameterList
PsiJavaToken:LT('<')
PsiTypeParameter:T
Expand Down
Loading

0 comments on commit 9f7de20

Please sign in to comment.