diff --git a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java index 71d6899249a1..198726115763 100644 --- a/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java +++ b/java/java-impl/src/com/intellij/lang/java/parser/ReferenceParser.java @@ -25,10 +25,10 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import static com.intellij.BitUtil.isSet; import static com.intellij.lang.PsiBuilderUtil.expect; import static com.intellij.lang.PsiBuilderUtil.nextTokenType; import static com.intellij.lang.java.parser.JavaParserUtil.*; -import static com.intellij.lang.java.parser.JavaParserUtil.emptyElement; public class ReferenceParser { @@ -147,10 +147,6 @@ public class ReferenceParser { return typeInfo; } - private static boolean isSet(final int mask, final int flag) { - return (mask & flag) != 0; - } - @NotNull private static PsiBuilder.Marker parseWildcardType(final PsiBuilder builder) { final PsiBuilder.Marker type = builder.mark(); diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java b/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java index 12e62429979d..95bb4aedd329 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiElementFactoryImpl.java @@ -559,16 +559,24 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps @NotNull public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, final PsiElement context, final boolean isPhysical) { - return createTypeCodeFragment(text, context, false, isPhysical, false); + return createTypeCodeFragment(text, context, isPhysical, 0); } + @NotNull + public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, final PsiElement context, final boolean isPhysical, final int flags) { + final PsiTypeCodeFragmentImpl result = new PsiTypeCodeFragmentImpl(myManager.getProject(), isPhysical, "fragment.java", text, flags); + result.setContext(context); + return result; + } @NotNull public PsiTypeCodeFragment createTypeCodeFragment(@NotNull final String text, final PsiElement context, final boolean isVoidValid, final boolean isPhysical) { - return createTypeCodeFragment(text, context, true, isPhysical, false); + int flags = 0; + if (isVoidValid) flags |= ALLOW_VOID; + return createTypeCodeFragment(text, context, isPhysical, flags); } @NotNull @@ -577,12 +585,10 @@ public class PsiElementFactoryImpl extends PsiJavaParserFacadeImpl implements Ps final boolean isVoidValid, final boolean isPhysical, final boolean allowEllipsis) { - final PsiTypeCodeFragmentImpl result = new PsiTypeCodeFragmentImpl(myManager.getProject(), isPhysical, allowEllipsis, "fragment.java", text); - result.setContext(context); - if (isVoidValid) { - result.putUserData(PsiUtil.VALID_VOID_TYPE_IN_CODE_FRAGMENT, Boolean.TRUE); - } - return result; + int flags = 0; + if (isVoidValid) flags |= ALLOW_VOID; + if (allowEllipsis) flags |= ALLOW_ELLIPSIS; + return createTypeCodeFragment(text, context, isPhysical, flags); } @NotNull diff --git a/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeCodeFragmentImpl.java b/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeCodeFragmentImpl.java index 38633eec4b4e..d96859a418d8 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeCodeFragmentImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/PsiTypeCodeFragmentImpl.java @@ -15,61 +15,70 @@ */ package com.intellij.psi.impl.source; +import com.intellij.BitUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import static com.intellij.BitUtil.isSet; + /** * @author dsl */ public class PsiTypeCodeFragmentImpl extends PsiCodeFragmentImpl implements PsiTypeCodeFragment { private final boolean myAllowEllipsis; + private final boolean myAllowDisjunction; - public PsiTypeCodeFragmentImpl(Project manager, - boolean isPhysical, - boolean allowEllipsis, - @NonNls String name, - CharSequence text) { - super(manager, JavaElementType.TYPE_TEXT, isPhysical, name, text); - myAllowEllipsis = allowEllipsis; + public PsiTypeCodeFragmentImpl(final Project project, + final boolean isPhysical, + final @NonNls String name, + final CharSequence text, + final int flags) { + super(project, JavaElementType.TYPE_TEXT, isPhysical, name, text); + + myAllowEllipsis = BitUtil.isSet(flags, PsiElementFactory.ALLOW_ELLIPSIS); + myAllowDisjunction = BitUtil.isSet(flags, PsiElementFactory.ALLOW_DISJUNCTION); + + if (isSet(flags, PsiElementFactory.ALLOW_VOID)) { + putUserData(PsiUtil.VALID_VOID_TYPE_IN_CODE_FRAGMENT, Boolean.TRUE); + } } @NotNull - public PsiType getType() - throws TypeSyntaxException, NoTypeException { - class SyntaxError extends RuntimeException {} + public PsiType getType() throws TypeSyntaxException, NoTypeException { + class MyTypeSyntaxException extends RuntimeException { + MyTypeSyntaxException(final String message) { super(message); } + } + try { accept(new PsiRecursiveElementWalkingVisitor() { - @Override public void visitErrorElement(PsiErrorElement element) { - throw new SyntaxError(); + @Override + public void visitErrorElement(PsiErrorElement element) { + throw new MyTypeSyntaxException(element.getErrorDescription()); } }); } - catch(SyntaxError e) { - throw new TypeSyntaxException(); + catch (MyTypeSyntaxException e) { + throw new TypeSyntaxException(e.getMessage()); } - PsiElement child = getFirstChild(); - while (child != null && !(child instanceof PsiTypeElement)) { - child = child.getNextSibling(); - } - PsiTypeElement typeElement = (PsiTypeElement)child; + + final PsiTypeElement typeElement = PsiTreeUtil.getChildOfType(this, PsiTypeElement.class); if (typeElement == null) { - throw new NoTypeException(); + throw new NoTypeException("No type found in '" + getText() + "'"); } - PsiType type = typeElement.getType(); - PsiElement sibling = typeElement.getNextSibling(); - while (sibling instanceof PsiWhiteSpace) { - sibling = sibling.getNextSibling(); + + final PsiType type = typeElement.getType(); + if (type instanceof PsiEllipsisType && !myAllowEllipsis) { + throw new TypeSyntaxException("Ellipsis not allowed: " + type); } - if (sibling instanceof PsiJavaToken && "...".equals(sibling.getText())) { - if (myAllowEllipsis) return new PsiEllipsisType(type); - else throw new TypeSyntaxException(); - } else { - return type; + else if (type instanceof PsiDisjunctionType && !myAllowDisjunction) { + throw new TypeSyntaxException("Disjunction not allowed: " + type); } + return type; } public boolean isVoidValid() { diff --git a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 3a6026e33880..9060dfdc225e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -38,8 +38,6 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.Constructor; -import static com.intellij.lang.PsiBuilderUtil.expect; - public interface JavaElementType { class JavaCompositeElementType extends IJavaElementType implements ICompositeElementType { private final Constructor myConstructor; @@ -238,8 +236,8 @@ public interface JavaElementType { return JavaParserUtil.parseFragment(chameleon, new JavaParserUtil.ParserWrapper() { public void parse(final PsiBuilder builder) { - ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.WILDCARD); - expect(builder, JavaTokenType.ELLIPSIS); // todo[r.sh] parse ellipsis and fix PsiTypeCodeFragmentImpl.getType() + ReferenceParser.parseType(builder, ReferenceParser.EAT_LAST_DOT | ReferenceParser.ELLIPSIS | + ReferenceParser.WILDCARD | ReferenceParser.DISJUNCTIONS); } }); } diff --git a/java/openapi/src/com/intellij/psi/PsiElementFactory.java b/java/openapi/src/com/intellij/psi/PsiElementFactory.java index d74a242b882b..15589b5f0345 100644 --- a/java/openapi/src/com/intellij/psi/PsiElementFactory.java +++ b/java/openapi/src/com/intellij/psi/PsiElementFactory.java @@ -287,10 +287,10 @@ public interface PsiElementFactory extends PsiJavaParserFacade { @NotNull PsiReferenceExpression createReferenceExpression(@NotNull PsiPackage aPackage) throws IncorrectOperationException; /** - * Creates a Java idenitifier with the specified text. + * Creates a Java identifier with the specified text. * * @param text the text of the identifier to create. - * @return the idenitifier instance. + * @return the identifier instance. * @throws IncorrectOperationException if text is not a valid Java identifier. */ @NotNull PsiIdentifier createIdentifier(@NotNull @NonNls String text) throws IncorrectOperationException; @@ -371,6 +371,19 @@ public interface PsiElementFactory extends PsiJavaParserFacade { @NotNull JavaCodeFragment createCodeBlockCodeFragment(@NotNull String text, PsiElement context, boolean isPhysical); + /** + * Flag for {@linkplain #createTypeCodeFragment(String, PsiElement, boolean, int)} - allows void type. + */ + int ALLOW_VOID = 0x01; + /** + * Flag for {@linkplain #createTypeCodeFragment(String, PsiElement, boolean, int)} - allows type with ellipsis. + */ + int ALLOW_ELLIPSIS = 0x02; + /** + * Flag for {@linkplain #createTypeCodeFragment(String, PsiElement, boolean, int)} - allows disjunctive type. + */ + int ALLOW_DISJUNCTION = 0x02; + /** * Creates a Java type code fragment from the text of the name of a Java type (the name * of a primitive type, array type or class), with void and ellipsis @@ -386,35 +399,31 @@ public interface PsiElementFactory extends PsiJavaParserFacade { /** * Creates a Java type code fragment from the text of the name of a Java type (the name - * of a primitive type, array type or class), with void optionally treated - * as a valid type, and ellipsis not treated as a valid type. + * of a primitive type, array type or class).
+ * {@code void}, ellipsis and disjunctive types are optionally treated as valid ones. * - * @param text the text of the Java type to create. - * @param context the context for resolving references from the code fragment. - * @param isVoidValid whether void is a valid type for the fragment. - * @param isPhysical whether the code fragment is created as a physical element - * (see {@link PsiElement#isPhysical()}). + * @param text the text of the Java type to create. + * @param context the context for resolving references from the code fragment. + * @param isPhysical whether the code fragment is created as a physical element + * (see {@link PsiElement#isPhysical()}). + * @param flags types allowed to present in text. * @return the created code fragment. */ + @NotNull PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, PsiElement context, boolean isPhysical, int flags); + + /** + * @deprecated use {@link #createTypeCodeFragment(String, PsiElement, boolean, int)} (todo[r.sh] to remove in IDEA 11). + */ @NotNull PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, PsiElement context, boolean isVoidValid, boolean isPhysical); /** - * Creates a Java type code fragment from the text of the name of a Java type (the name - * of a primitive type, array type or class), with void optionally treated - * as a valid type, and ellipsis not treated as a valid type. - * - * @param text the text of the Java type to create. - * @param context the context for resolving references from the code fragment. - * @param isVoidValid whether void is a valid type for the fragment. - * @param isPhysical whether the code fragment is created as a physical element - * (see {@link PsiElement#isPhysical()}). - * @param allowEllipsis whether {@link PsiEllipsisType} is a valid type for the element. - * @return the created code fragment. + * @deprecated use {@link #createTypeCodeFragment(String, PsiElement, boolean, int)} (todo[r.sh] to remove in IDEA 11). */ @NotNull PsiTypeCodeFragment createTypeCodeFragment(@NotNull String text, - PsiElement context, - boolean isVoidValid, - boolean isPhysical, boolean allowEllipsis); + PsiElement context, + boolean isVoidValid, + boolean isPhysical, + boolean allowEllipsis); /** * Returns a synthetic Java class containing methods which are defined on Java arrays. diff --git a/java/openapi/src/com/intellij/psi/PsiTypeCodeFragment.java b/java/openapi/src/com/intellij/psi/PsiTypeCodeFragment.java index bec5c949135c..81589dac65d5 100644 --- a/java/openapi/src/com/intellij/psi/PsiTypeCodeFragment.java +++ b/java/openapi/src/com/intellij/psi/PsiTypeCodeFragment.java @@ -43,9 +43,15 @@ public interface PsiTypeCodeFragment extends JavaCodeFragment { */ boolean isVoidValid(); - class IncorrectTypeException extends Exception {} + class IncorrectTypeException extends Exception { + public IncorrectTypeException(final String message) { super(message); } + } - class TypeSyntaxException extends IncorrectTypeException {} + class TypeSyntaxException extends IncorrectTypeException { + public TypeSyntaxException(final String message) { super(message); } + } - class NoTypeException extends IncorrectTypeException {} + class NoTypeException extends IncorrectTypeException { + public NoTypeException(final String message) { super(message); } + } } diff --git a/platform/util/src/com/intellij/BitUtil.java b/platform/util/src/com/intellij/BitUtil.java new file mode 100644 index 000000000000..bab83c8d082f --- /dev/null +++ b/platform/util/src/com/intellij/BitUtil.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2011 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij; + +public class BitUtil { + private BitUtil() { } + + public static boolean isSet(final int mask, final int flag) { + return (mask & flag) != 0; + } +}