Java type annotations: receiver parameter PSI

This commit is contained in:
Roman Shevchenko
2013-02-19 21:12:06 +01:00
parent a7474d109b
commit caf9bd61ff
11 changed files with 213 additions and 89 deletions
@@ -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 {
}
@@ -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<PsiParameterStub, PsiParameter> {
public JavaParameterElementType() {
super("PARAMETER");
}
public abstract class JavaParameterElementType extends JavaStubElementType<PsiParameterStub, PsiParameter> {
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<PsiParameterSt
}
@Override
public PsiParameter createPsi(@NotNull final ASTNode node) {
return new PsiParameterImpl(node);
public PsiParameter createPsi(@NotNull ASTNode node) {
boolean receiver = node.getElementType() == JavaElementType.RECEIVER_PARAMETER;
return receiver ? new PsiReceiverParameterImpl(node) : new PsiParameterImpl(node);
}
@Override
public PsiParameterStub createStub(final LighterAST tree,
final LighterASTNode node,
final StubElement parentStub) {
final TypeInfo typeInfo = TypeInfo.create(tree, node, parentStub);
final LighterASTNode id = LightTreeUtil.requiredChildOfType(tree, node, JavaTokenType.IDENTIFIER);
final String name = RecordUtil.intern(tree.getCharTable(), id);
public PsiParameterStub createStub(LighterAST tree, LighterASTNode node, StubElement parentStub) {
TypeInfo typeInfo = TypeInfo.create(tree, node, parentStub);
LighterASTNode id = LightTreeUtil.requiredChildOfType(tree, node, ID_TYPES);
String name = RecordUtil.intern(tree.getCharTable(), id);
return new PsiParameterStubImpl(parentStub, name, typeInfo, typeInfo.isEllipsis);
}
@Override
public void serialize(final PsiParameterStub stub, final StubOutputStream dataStream) throws IOException {
public void serialize(PsiParameterStub stub, StubOutputStream dataStream) throws IOException {
dataStream.writeName(stub.getName());
TypeInfo.writeTYPE(dataStream, stub.getType(false));
dataStream.writeBoolean(stub.isParameterTypeEllipsis());
}
@Override
public PsiParameterStub deserialize(final StubInputStream dataStream, final StubElement parentStub) throws IOException {
public PsiParameterStub deserialize(StubInputStream dataStream, StubElement parentStub) throws IOException {
StringRef name = dataStream.readName();
TypeInfo type = TypeInfo.readTYPE(dataStream, parentStub);
boolean isEll = dataStream.readBoolean();
return new PsiParameterStubImpl(parentStub, name, type, isEll);
boolean isEllipsis = dataStream.readBoolean();
return new PsiParameterStubImpl(parentStub, name, type, isEllipsis);
}
@Override
public void indexStub(final PsiParameterStub stub, final IndexSink sink) {
public void indexStub(PsiParameterStub stub, IndexSink sink) {
}
}
@@ -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.
@@ -17,11 +17,12 @@ package com.intellij.psi.impl.java.stubs;
import com.intellij.lang.ASTNode;
import com.intellij.psi.impl.source.JavaFileElementType;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.java.*;
import com.intellij.psi.tree.IStubFileElementType;
import org.jetbrains.annotations.NotNull;
/*
/**
* @author max
*/
public interface JavaStubElementTypes {
@@ -29,13 +30,27 @@ public interface JavaStubElementTypes {
JavaAnnotationElementType ANNOTATION = new JavaAnnotationElementType();
JavaAnnotationParameterListType ANNOTATION_PARAMETER_LIST = new JavaAnnotationParameterListType();
JavaNameValuePairType NAME_VALUE_PAIR = new JavaNameValuePairType();
JavaParameterElementType PARAMETER = new JavaParameterElementType();
JavaParameterListElementType PARAMETER_LIST = new JavaParameterListElementType();
JavaTypeParameterElementType TYPE_PARAMETER = new JavaTypeParameterElementType();
JavaTypeParameterListElementType TYPE_PARAMETER_LIST = new JavaTypeParameterListElementType();
JavaClassInitializerElementType CLASS_INITIALIZER = new JavaClassInitializerElementType();
JavaImportListElementType IMPORT_LIST = new JavaImportListElementType();
JavaParameterElementType PARAMETER = new JavaParameterElementType("PARAMETER") {
@NotNull
@Override
public ASTNode createCompositeNode() {
return new ParameterElement(JavaElementType.PARAMETER);
}
};
JavaParameterElementType RECEIVER_PARAMETER = new JavaParameterElementType("RECEIVER") {
@NotNull
@Override
public ASTNode createCompositeNode() {
return new ParameterElement(JavaElementType.RECEIVER_PARAMETER);
}
};
JavaClassElementType CLASS = new JavaClassElementType("CLASS") {
@NotNull
@Override
@@ -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.
@@ -13,10 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* @author max
*/
package com.intellij.psi.impl.java.stubs;
import com.intellij.psi.PsiParameter;
@@ -24,8 +20,20 @@ import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.stubs.NamedStub;
import org.jetbrains.annotations.NotNull;
/**
* @author max
*/
public interface PsiParameterStub extends NamedStub<PsiParameter> {
@NotNull
@Override
String getName();
boolean isParameterTypeEllipsis();
@NotNull TypeInfo getType(boolean doResolve);
@NotNull
TypeInfo getType(boolean doResolve);
PsiModifierListStub getModList();
boolean isReceiver();
}
@@ -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
@@ -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<PsiParameter> 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<PsiParameter> 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<PsiParameter> implements PsiP
return null;
}
@NotNull
@Override
public String getName() {
return StringRef.toString(myName);
@@ -91,11 +97,6 @@ public class PsiParameterStubImpl extends StubBase<PsiParameter> 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)) + ']';
}
}
@@ -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<PsiParameterStub> implements PsiParameter {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiParameterImpl");
private volatile PatchedSoftReference<PsiType> 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<PsiParameterStub> 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<PsiParameterStub> imple
@Override
@NotNull
public PsiType getType() {
final PsiParameterStub stub = getStub();
PsiParameterStub stub = getStub();
if (stub != null) {
PatchedSoftReference<PsiType> cachedType = myCachedType;
if (cachedType != null) {
@@ -106,8 +123,9 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> 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<PsiType>(type);
return type;
}
@@ -119,19 +137,22 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> 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<PsiParameterStub> 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<PsiParameterStub> 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
@@ -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";
}
}
@@ -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;
@@ -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{
}
}
}
@@ -42,6 +42,17 @@ public class LightTreeUtil {
return null;
}
@Nullable
public static LighterASTNode firstChildOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull TokenSet types) {
List<LighterASTNode> 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<LighterASTNode> getChildrenOfType(@NotNull LighterAST tree, @NotNull LighterASTNode node, @NotNull IElementType type) {
List<LighterASTNode> result = null;