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.lexer.JetTokens;
033
034 import java.util.List;
035
036 import static org.jetbrains.jet.JetNodeTypes.PROPERTY_ACCESSOR;
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 JetCallableDeclaration {
042
043 private static final Logger LOG = Logger.getInstance(JetProperty.class);
044
045 public JetProperty(@NotNull ASTNode node) {
046 super(node);
047 }
048
049 public JetProperty(@NotNull PsiJetPropertyStub stub) {
050 super(stub, JetStubElementTypes.PROPERTY);
051 }
052
053 @Override
054 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
055 return visitor.visitProperty(this, data);
056 }
057
058 @Override
059 public boolean isVar() {
060 PsiJetPropertyStub stub = getStub();
061 if (stub != null) {
062 return stub.isVar();
063 }
064
065 return getNode().findChildByType(JetTokens.VAR_KEYWORD) != null;
066 }
067
068 public boolean isLocal() {
069 PsiElement parent = getParent();
070 return !(parent instanceof JetFile || parent instanceof JetClassBody);
071 }
072
073 public boolean isTopLevel() {
074 PsiJetPropertyStub stub = getStub();
075 if (stub != null) {
076 return stub.isTopLevel();
077 }
078
079 return getParent() instanceof JetFile;
080 }
081
082 @Nullable
083 @Override
084 public JetParameterList getValueParameterList() {
085 return null;
086 }
087
088 @Override
089 @Nullable
090 public JetTypeReference getReceiverTypeRef() {
091 PsiJetPropertyStub stub = getStub();
092 if (stub != null) {
093 if (!stub.hasReceiverTypeRef()) {
094 return null;
095 }
096 else {
097 return getStubOrPsiChild(JetStubElementTypes.TYPE_REFERENCE);
098 }
099 }
100 return getReceiverTypeRefByTree();
101 }
102
103 @Nullable
104 private JetTypeReference getReceiverTypeRefByTree() {
105 ASTNode node = getNode().getFirstChildNode();
106 while (node != null) {
107 IElementType tt = node.getElementType();
108 if (tt == JetTokens.COLON) break;
109
110 if (tt == JetNodeTypes.TYPE_REFERENCE) {
111 return (JetTypeReference) node.getPsi();
112 }
113 node = node.getTreeNext();
114 }
115
116 return null;
117 }
118
119 @Nullable
120 @Override
121 public JetTypeReference getReturnTypeRef() {
122 return getTypeRef();
123 }
124
125 @Override
126 @Nullable
127 public JetTypeReference getTypeRef() {
128 PsiJetPropertyStub stub = getStub();
129 if (stub != null) {
130 if (!stub.hasReturnTypeRef()) {
131 return null;
132 }
133 else {
134 List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
135 int returnTypeRefPositionInPsi = stub.hasReceiverTypeRef() ? 1 : 0;
136 if (typeReferences.size() <= returnTypeRefPositionInPsi) {
137 LOG.error("Invalid stub structure built for property:\n" + getText());
138 return null;
139 }
140 return typeReferences.get(returnTypeRefPositionInPsi);
141 }
142 }
143 return getTypeRefByTree();
144 }
145
146 @Nullable
147 private JetTypeReference getTypeRefByTree() {
148 ASTNode node = getNode().getFirstChildNode();
149 boolean passedColon = false;
150 while (node != null) {
151 IElementType tt = node.getElementType();
152 if (tt == JetTokens.COLON) {
153 passedColon = true;
154 }
155 else if (tt == JetNodeTypes.TYPE_REFERENCE && passedColon) {
156 return (JetTypeReference) node.getPsi();
157 }
158 node = node.getTreeNext();
159 }
160
161 return null;
162 }
163
164 @NotNull
165 public List<JetPropertyAccessor> getAccessors() {
166 return getStubOrPsiChildrenAsList(JetStubElementTypes.PROPERTY_ACCESSOR);
167 }
168
169 @Nullable
170 public JetPropertyAccessor getGetter() {
171 for (JetPropertyAccessor accessor : getAccessors()) {
172 if (accessor.isGetter()) return accessor;
173 }
174
175 return null;
176 }
177
178 @Nullable
179 public JetPropertyAccessor getSetter() {
180 for (JetPropertyAccessor accessor : getAccessors()) {
181 if (accessor.isSetter()) return accessor;
182 }
183
184 return null;
185 }
186
187 public boolean hasDelegate() {
188 PsiJetPropertyStub stub = getStub();
189 if (stub != null) {
190 return stub.hasDelegate();
191 }
192 return getDelegate() != null;
193 }
194
195 @Nullable
196 public JetPropertyDelegate getDelegate() {
197 return (JetPropertyDelegate) findChildByType(PROPERTY_DELEGATE);
198 }
199
200 public boolean hasDelegateExpression() {
201 PsiJetPropertyStub stub = getStub();
202 if (stub != null) {
203 return stub.hasDelegateExpression();
204 }
205 return getDelegateExpression() != null;
206 }
207
208 @Nullable
209 public JetExpression getDelegateExpression() {
210 JetPropertyDelegate delegate = getDelegate();
211 if (delegate != null) {
212 return delegate.getExpression();
213 }
214 return null;
215 }
216
217 @Override
218 public boolean hasInitializer() {
219 PsiJetPropertyStub stub = getStub();
220 if (stub != null) {
221 return stub.hasInitializer();
222 }
223 return getInitializer() != null;
224 }
225
226 @Override
227 @Nullable
228 public JetExpression getInitializer() {
229 return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), JetExpression.class);
230 }
231
232 public boolean hasDelegateExpressionOrInitializer() {
233 return hasDelegateExpression() || hasInitializer();
234 }
235
236 @Nullable
237 public JetExpression getDelegateExpressionOrInitializer() {
238 JetExpression expression = getDelegateExpression();
239 if (expression == null) {
240 return getInitializer();
241 }
242 return expression;
243 }
244
245 @Override
246 @NotNull
247 public ASTNode getValOrVarNode() {
248 ASTNode node = getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD));
249 assert node != null : "Val or var should always exist for property";
250 return node;
251 }
252
253 @Override
254 public ItemPresentation getPresentation() {
255 return ItemPresentationProviders.getItemPresentation(this);
256 }
257 }