diff --git a/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java new file mode 100644 index 000000000000..f3851a9fe54e --- /dev/null +++ b/java/java-psi-api/src/com/intellij/psi/PsiReceiverParameter.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2013 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.psi; + +/** + * Represents a receiver parameter of a Java method (Java 8). + * + * @since 12.1 + */ +public interface PsiReceiverParameter extends PsiParameter { +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaParameterElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaParameterElementType.java index a38b94c3179c..f9ebdd67b767 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaParameterElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/JavaParameterElementType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -24,12 +24,14 @@ import com.intellij.psi.impl.cache.RecordUtil; import com.intellij.psi.impl.cache.TypeInfo; import com.intellij.psi.impl.java.stubs.impl.PsiParameterStubImpl; import com.intellij.psi.impl.source.PsiParameterImpl; +import com.intellij.psi.impl.source.PsiReceiverParameterImpl; +import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.LightTreeUtil; -import com.intellij.psi.impl.source.tree.java.ParameterElement; import com.intellij.psi.stubs.IndexSink; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubInputStream; import com.intellij.psi.stubs.StubOutputStream; +import com.intellij.psi.tree.TokenSet; import com.intellij.util.io.StringRef; import org.jetbrains.annotations.NotNull; @@ -38,15 +40,11 @@ import java.io.IOException; /** * @author max */ -public class JavaParameterElementType extends JavaStubElementType { - public JavaParameterElementType() { - super("PARAMETER"); - } +public abstract class JavaParameterElementType extends JavaStubElementType { + public static final TokenSet ID_TYPES = TokenSet.create(JavaTokenType.IDENTIFIER, JavaTokenType.THIS_KEYWORD); - @NotNull - @Override - public ASTNode createCompositeNode() { - return new ParameterElement(); + public JavaParameterElementType(@NotNull String id) { + super(id); } @Override @@ -55,36 +53,35 @@ public class JavaParameterElementType extends JavaStubElementType { + @NotNull + @Override + String getName(); + boolean isParameterTypeEllipsis(); - @NotNull TypeInfo getType(boolean doResolve); + + @NotNull + TypeInfo getType(boolean doResolve); + PsiModifierListStub getModList(); + + boolean isReceiver(); } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/SourceStubPsiFactory.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/SourceStubPsiFactory.java index 1b5a5f763bfd..d64f7afff81e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/SourceStubPsiFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/SourceStubPsiFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -86,7 +86,7 @@ public class SourceStubPsiFactory extends StubPsiFactory { @Override public PsiParameter createParameter(PsiParameterStub stub) { - return new PsiParameterImpl(stub); + return stub.isReceiver() ? new PsiReceiverParameterImpl(stub) : new PsiParameterImpl(stub); } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterStubImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterStubImpl.java index 9e732a209201..2c66a4028e80 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterStubImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/impl/PsiParameterStubImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.java.stubs.impl; +import com.intellij.psi.PsiKeyword; import com.intellij.psi.PsiParameter; import com.intellij.psi.impl.cache.TypeInfo; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; @@ -35,11 +36,11 @@ public class PsiParameterStubImpl extends StubBase implements PsiP private final TypeInfo myType; private final boolean myIsEllipsis; - public PsiParameterStubImpl(final StubElement parent, final String name, @NotNull TypeInfo type, final boolean isEllipsis) { + public PsiParameterStubImpl(StubElement parent, @NotNull String name, @NotNull TypeInfo type, boolean isEllipsis) { this(parent, StringRef.fromString(name), type, isEllipsis); } - public PsiParameterStubImpl(final StubElement parent, final StringRef name, @NotNull TypeInfo type, final boolean isEllipsis) { + public PsiParameterStubImpl(StubElement parent, @NotNull StringRef name, @NotNull TypeInfo type, boolean isEllipsis) { super(parent, JavaStubElementTypes.PARAMETER); myName = name; myType = type; @@ -51,11 +52,15 @@ public class PsiParameterStubImpl extends StubBase implements PsiP return myIsEllipsis; } + @Override + public boolean isReceiver() { + return PsiKeyword.THIS.equals(getName()); + } + @Override @NotNull public TypeInfo getType(boolean doResolve) { - if (!doResolve) return myType; - return PsiFieldStubImpl.addApplicableTypeAnnotationsFromChildModifierList(this, myType); + return doResolve ? PsiFieldStubImpl.addApplicableTypeAnnotationsFromChildModifierList(this, myType) : myType; } @Override @@ -68,6 +73,7 @@ public class PsiParameterStubImpl extends StubBase implements PsiP return null; } + @NotNull @Override public String getName() { return StringRef.toString(myName); @@ -91,11 +97,6 @@ public class PsiParameterStubImpl extends StubBase implements PsiP @Override public String toString() { - StringBuilder builder = new StringBuilder(); - builder. - append("PsiParameterStub["). - append(myName).append(':').append(TypeInfo.createTypeText(getType(false))). - append(']'); - return builder.toString(); + return "PsiParameterStub[" + myName + ':' + TypeInfo.createTypeText(getType(false)) + ']'; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index 89717007ca90..446f4ce06f6d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -26,11 +26,12 @@ import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.cache.TypeInfo; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiParameterStub; -import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.tree.JavaSharedImplUtil; import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.stubs.IStubElementType; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.ui.RowIcon; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PatchedSoftReference; @@ -42,10 +43,15 @@ import java.util.Arrays; public class PsiParameterImpl extends JavaStubPsiElement implements PsiParameter { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiParameterImpl"); + private volatile PatchedSoftReference myCachedType = null; public PsiParameterImpl(@NotNull PsiParameterStub stub) { - super(stub, JavaStubElementTypes.PARAMETER); + this(stub, JavaStubElementTypes.PARAMETER); + } + + protected PsiParameterImpl(@NotNull PsiParameterStub stub, @NotNull IStubElementType type) { + super(stub, type); } public PsiParameterImpl(@NotNull ASTNode node) { @@ -69,23 +75,34 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override @NotNull public final String getName() { - final PsiParameterStub stub = getStub(); + PsiParameterStub stub = getStub(); if (stub != null) { return stub.getName(); } - return getNameIdentifier().getText(); + + return getParameterIdentifier().getText(); } @Override - public PsiElement setName(@NotNull String name) throws IncorrectOperationException { - PsiImplUtil.setName(getNameIdentifier(), name); + public final PsiElement setName(@NotNull String name) throws IncorrectOperationException { + if (this instanceof PsiReceiverParameter) { + throw new IncorrectOperationException("Cannot rename receiver parameter"); + } + + PsiImplUtil.setName(getParameterIdentifier(), name); return this; } @Override - @NotNull public final PsiIdentifier getNameIdentifier() { - return (PsiIdentifier)getNode().findChildByRoleAsPsiElement(ChildRole.NAME); + return PsiTreeUtil.getChildOfType(this, PsiIdentifier.class); + } + + @NotNull + private PsiElement getParameterIdentifier() { + PsiJavaToken identifier = PsiTreeUtil.getChildOfAnyType(this, PsiIdentifier.class, PsiKeyword.class); + assert identifier != null : this; + return identifier; } @Override @@ -97,7 +114,7 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override @NotNull public PsiType getType() { - final PsiParameterStub stub = getStub(); + PsiParameterStub stub = getStub(); if (stub != null) { PatchedSoftReference cachedType = myCachedType; if (cachedType != null) { @@ -106,8 +123,9 @@ public class PsiParameterImpl extends JavaStubPsiElement imple } String typeText = TypeInfo.createTypeText(stub.getType(true)); + assert typeText != null : stub; try { - final PsiType type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); + PsiType type = JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); myCachedType = new PatchedSoftReference(type); return type; } @@ -119,19 +137,22 @@ public class PsiParameterImpl extends JavaStubPsiElement imple myCachedType = null; - final PsiTypeElement typeElement = getTypeElement(); - if (typeElement == null && isLambdaParameter()) { + PsiTypeElement typeElement = getTypeElement(); + if (typeElement == null) { + assert isLambdaParameter() : this; return LambdaUtil.getLambdaParameterType(this); } - - return JavaSharedImplUtil.getType(typeElement, getNameIdentifier(), this); + else { + return JavaSharedImplUtil.getType(typeElement, getParameterIdentifier(), this); + } } @Override public PsiType getTypeNoResolve() { - final PsiParameterStub stub = getStub(); + PsiParameterStub stub = getStub(); if (stub != null) { String typeText = TypeInfo.createTypeText(stub.getType(false)); + assert typeText != null : stub; try { return JavaPsiFacade.getInstance(getProject()).getParserFacade().createTypeFromText(typeText, this); } @@ -142,11 +163,13 @@ public class PsiParameterImpl extends JavaStubPsiElement imple } final PsiTypeElement typeElement = getTypeElement(); - if (typeElement == null && isLambdaParameter()) { + if (typeElement == null) { + assert isLambdaParameter() : this; return new PsiLambdaParameterType(this); } - - return JavaSharedImplUtil.getTypeNoResolve(typeElement, getNameIdentifier(), this); + else { + return JavaSharedImplUtil.getTypeNoResolve(typeElement, getParameterIdentifier(), this); + } } private boolean isLambdaParameter() { @@ -156,13 +179,15 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override public PsiTypeElement getTypeElement() { - return (PsiTypeElement)getNode().findChildByRoleAsPsiElement(ChildRole.TYPE); + return PsiTreeUtil.getChildOfType(this, PsiTypeElement.class); } @Override @NotNull public PsiModifierList getModifierList() { - return getStubOrPsiChild(JavaStubElementTypes.MODIFIER_LIST); + PsiModifierList modifierList = getStubOrPsiChild(JavaStubElementTypes.MODIFIER_LIST); + assert modifierList != null : this; + return modifierList; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java new file mode 100644 index 000000000000..9bf940bf7f7d --- /dev/null +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiReceiverParameterImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2013 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.psi.impl.source; + +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiReceiverParameter; +import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; +import com.intellij.psi.impl.java.stubs.PsiParameterStub; +import org.jetbrains.annotations.NotNull; + +public class PsiReceiverParameterImpl extends PsiParameterImpl implements PsiReceiverParameter { + public PsiReceiverParameterImpl(@NotNull PsiParameterStub stub) { + super(stub, JavaStubElementTypes.RECEIVER_PARAMETER); + } + + public PsiReceiverParameterImpl(@NotNull ASTNode node) { + super(node); + } + + @Override + public String toString() { + return "PsiReceiverParameter"; + } +} diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index a24e5f5f8b05..3ffd29fc03bc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -76,6 +76,7 @@ public interface JavaElementType { IElementType ANNOTATION_METHOD = JavaStubElementTypes.ANNOTATION_METHOD; IElementType CLASS_INITIALIZER = JavaStubElementTypes.CLASS_INITIALIZER; IElementType PARAMETER = JavaStubElementTypes.PARAMETER; + IElementType RECEIVER_PARAMETER = JavaStubElementTypes.RECEIVER_PARAMETER; IElementType PARAMETER_LIST = JavaStubElementTypes.PARAMETER_LIST; IElementType EXTENDS_BOUND_LIST = JavaStubElementTypes.EXTENDS_BOUND_LIST; IElementType THROWS_LIST = JavaStubElementTypes.THROWS_LIST; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterElement.java index 0d3aeac52c66..7a3d42fd9b48 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ParameterElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -18,50 +18,49 @@ package com.intellij.psi.impl.source.tree.java; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.JavaTokenType; +import com.intellij.psi.impl.java.stubs.JavaParameterElementType; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.CompositeElement; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; +import org.jetbrains.annotations.NotNull; -public class ParameterElement extends CompositeElement{ +public class ParameterElement extends CompositeElement { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.ParameterElement"); - public ParameterElement() { - super(JavaElementType.PARAMETER); - } - - protected ParameterElement(IElementType type) { + public ParameterElement(@NotNull IElementType type) { super(type); } @Override public int getTextOffset() { - return findChildByRole(ChildRole.NAME).getStartOffset(); + ASTNode node = findChildByType(JavaParameterElementType.ID_TYPES); + return node != null ? node.getStartOffset() : getStartOffset(); } @Override - public ASTNode findChildByRole(int role){ + public ASTNode findChildByRole(int role) { LOG.assertTrue(ChildRole.isUnique(role)); - switch(role){ - default: - return null; - - case ChildRole.MODIFIER_LIST: - return findChildByType(JavaElementType.MODIFIER_LIST); - - case ChildRole.NAME: - return findChildByType(JavaTokenType.IDENTIFIER); - - case ChildRole.TYPE: - return findChildByType(JavaElementType.TYPE); + if (role == ChildRole.MODIFIER_LIST) { + return findChildByType(JavaElementType.MODIFIER_LIST); + } + else if (role == ChildRole.NAME) { + return findChildByType(JavaTokenType.IDENTIFIER); + } + else if (role == ChildRole.TYPE) { + return findChildByType(JavaElementType.TYPE); + } + else { + return null; } } @Override public int getChildRole(ASTNode child) { LOG.assertTrue(child.getTreeParent() == this); + IElementType i = child.getElementType(); if (i == JavaElementType.MODIFIER_LIST) { return ChildRole.MODIFIER_LIST; @@ -77,4 +76,3 @@ public class ParameterElement extends CompositeElement{ } } } - diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LightTreeUtil.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LightTreeUtil.java index a42c0bc4328f..4002b1646ac8 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LightTreeUtil.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LightTreeUtil.java @@ -42,6 +42,17 @@ public class LightTreeUtil { return null; } + @Nullable + public static LighterASTNode firstChildOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull TokenSet types) { + List children = tree.getChildren(node); + for (int i = 0, size = children.size(); i < size; ++i) { + LighterASTNode child = children.get(i); + if (types.contains(child.getTokenType())) return child; + } + + return null; + } + @NotNull public static LighterASTNode requiredChildOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull IElementType type) { LighterASTNode child = firstChildOfType(tree, node, type); @@ -49,6 +60,13 @@ public class LightTreeUtil { return child; } + @NotNull + public static LighterASTNode requiredChildOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull TokenSet types) { + LighterASTNode child = firstChildOfType(tree, node, types); + assert child != null : "Required child " + types + " not found in " + node.getTokenType() + ": " + tree.getChildren(node); + return child; + } + @NotNull public static List getChildrenOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull IElementType type) { List result = null;