001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.psi;
018
019 import com.intellij.lang.ASTNode;
020 import com.intellij.navigation.ItemPresentation;
021 import com.intellij.navigation.ItemPresentationProviders;
022 import com.intellij.openapi.diagnostic.Logger;
023 import com.intellij.psi.PsiElement;
024 import com.intellij.psi.tree.IElementType;
025 import com.intellij.psi.tree.TokenSet;
026 import com.intellij.psi.util.PsiTreeUtil;
027 import org.jetbrains.annotations.NotNull;
028 import org.jetbrains.annotations.Nullable;
029 import org.jetbrains.jet.JetNodeTypes;
030 import org.jetbrains.jet.lang.psi.stubs.PsiJetPropertyStub;
031 import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
032 import org.jetbrains.jet.lang.psi.typeRefHelpers.TypeRefHelpersPackage;
033 import org.jetbrains.jet.lexer.JetTokens;
034
035 import java.util.List;
036
037 import static org.jetbrains.jet.JetNodeTypes.PROPERTY_DELEGATE;
038 import static org.jetbrains.jet.lexer.JetTokens.*;
039
040 public class JetProperty extends JetTypeParameterListOwnerStub<PsiJetPropertyStub> implements JetVariableDeclaration {
041
042 private static final Logger LOG = Logger.getInstance(JetProperty.class);
043
044 public JetProperty(@NotNull ASTNode node) {
045 super(node);
046 }
047
048 public JetProperty(@NotNull PsiJetPropertyStub stub) {
049 super(stub, JetStubElementTypes.PROPERTY);
050 }
051
052 @Override
053 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
054 return visitor.visitProperty(this, data);
055 }
056
057 @Override
058 public boolean isVar() {
059 PsiJetPropertyStub stub = getStub();
060 if (stub != null) {
061 return stub.isVar();
062 }
063
064 return getNode().findChildByType(JetTokens.VAR_KEYWORD) != null;
065 }
066
067 public boolean isLocal() {
068 PsiElement parent = getParent();
069 return !(parent instanceof JetFile || parent instanceof JetClassBody);
070 }
071
072 public boolean isTopLevel() {
073 PsiJetPropertyStub stub = getStub();
074 if (stub != null) {
075 return stub.isTopLevel();
076 }
077
078 return getParent() instanceof JetFile;
079 }
080
081 @Nullable
082 @Override
083 public JetParameterList getValueParameterList() {
084 return null;
085 }
086
087 @Override
088 @Nullable
089 public JetTypeReference getReceiverTypeReference() {
090 PsiJetPropertyStub stub = getStub();
091 if (stub != null) {
092 if (!stub.hasReceiverTypeRef()) {
093 return null;
094 }
095 else {
096 return getStubOrPsiChild(JetStubElementTypes.TYPE_REFERENCE);
097 }
098 }
099 return getReceiverTypeRefByTree();
100 }
101
102 @Nullable
103 private JetTypeReference getReceiverTypeRefByTree() {
104 ASTNode node = getNode().getFirstChildNode();
105 while (node != null) {
106 IElementType tt = node.getElementType();
107 if (tt == JetTokens.COLON) break;
108
109 if (tt == JetNodeTypes.TYPE_REFERENCE) {
110 return (JetTypeReference) node.getPsi();
111 }
112 node = node.getTreeNext();
113 }
114
115 return null;
116 }
117
118 @Override
119 @Nullable
120 public JetTypeReference getTypeReference() {
121 PsiJetPropertyStub stub = getStub();
122 if (stub != null) {
123 if (!stub.hasReturnTypeRef()) {
124 return null;
125 }
126 else {
127 List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
128 int returnTypeRefPositionInPsi = stub.hasReceiverTypeRef() ? 1 : 0;
129 if (typeReferences.size() <= returnTypeRefPositionInPsi) {
130 LOG.error("Invalid stub structure built for property:\n" + getText());
131 return null;
132 }
133 return typeReferences.get(returnTypeRefPositionInPsi);
134 }
135 }
136 return TypeRefHelpersPackage.getTypeReference(this);
137 }
138
139 @Override
140 @Nullable
141 public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) {
142 return TypeRefHelpersPackage.setTypeReference(this, getNameIdentifier(), typeRef);
143 }
144
145 @NotNull
146 public List<JetPropertyAccessor> getAccessors() {
147 return getStubOrPsiChildrenAsList(JetStubElementTypes.PROPERTY_ACCESSOR);
148 }
149
150 @Nullable
151 public JetPropertyAccessor getGetter() {
152 for (JetPropertyAccessor accessor : getAccessors()) {
153 if (accessor.isGetter()) return accessor;
154 }
155
156 return null;
157 }
158
159 @Nullable
160 public JetPropertyAccessor getSetter() {
161 for (JetPropertyAccessor accessor : getAccessors()) {
162 if (accessor.isSetter()) return accessor;
163 }
164
165 return null;
166 }
167
168 public boolean hasDelegate() {
169 PsiJetPropertyStub stub = getStub();
170 if (stub != null) {
171 return stub.hasDelegate();
172 }
173 return getDelegate() != null;
174 }
175
176 @Nullable
177 public JetPropertyDelegate getDelegate() {
178 return (JetPropertyDelegate) findChildByType(PROPERTY_DELEGATE);
179 }
180
181 public boolean hasDelegateExpression() {
182 PsiJetPropertyStub stub = getStub();
183 if (stub != null) {
184 return stub.hasDelegateExpression();
185 }
186 return getDelegateExpression() != null;
187 }
188
189 @Nullable
190 public JetExpression getDelegateExpression() {
191 JetPropertyDelegate delegate = getDelegate();
192 if (delegate != null) {
193 return delegate.getExpression();
194 }
195 return null;
196 }
197
198 @Override
199 public boolean hasInitializer() {
200 PsiJetPropertyStub stub = getStub();
201 if (stub != null) {
202 return stub.hasInitializer();
203 }
204 return getInitializer() != null;
205 }
206
207 @Override
208 @Nullable
209 public JetExpression getInitializer() {
210 return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), JetExpression.class);
211 }
212
213 public boolean hasDelegateExpressionOrInitializer() {
214 return hasDelegateExpression() || hasInitializer();
215 }
216
217 @Nullable
218 public JetExpression setInitializer(@Nullable JetExpression initializer) {
219 JetExpression oldInitializer = getInitializer();
220
221 if (oldInitializer != null) {
222 if (initializer != null) {
223 return (JetExpression) oldInitializer.replace(initializer);
224 }
225 else {
226 deleteChildRange(findChildByType(EQ), oldInitializer);
227 return null;
228 }
229 }
230 else {
231 if (initializer != null) {
232 PsiElement addAfter = getTypeReference();
233 if (addAfter == null) {
234 addAfter = getNameIdentifier();
235 }
236 PsiElement eq = addAfter(new JetPsiFactory(getProject()).createEQ(), addAfter);
237 return (JetExpression) addAfter(initializer, eq);
238 }
239 else {
240 return null;
241 }
242 }
243 }
244
245 @Nullable
246 public JetExpression getDelegateExpressionOrInitializer() {
247 JetExpression expression = getDelegateExpression();
248 if (expression == null) {
249 return getInitializer();
250 }
251 return expression;
252 }
253
254 @Override
255 @NotNull
256 public ASTNode getValOrVarNode() {
257 ASTNode node = getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD));
258 assert node != null : "Val or var should always exist for property";
259 return node;
260 }
261
262 @Override
263 public ItemPresentation getPresentation() {
264 return ItemPresentationProviders.getItemPresentation(this);
265 }
266 }