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    }