001    /*
002     * Copyright 2010-2015 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.kotlin.psi;
018    
019    import com.intellij.lang.ASTNode;
020    import com.intellij.navigation.ItemPresentation;
021    import com.intellij.navigation.ItemPresentationProviders;
022    import com.intellij.psi.PsiElement;
023    import com.intellij.psi.PsiModifiableCodeBlock;
024    import com.intellij.psi.tree.IElementType;
025    import com.intellij.psi.util.PsiTreeUtil;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.kotlin.lexer.JetTokens;
029    import org.jetbrains.kotlin.psi.stubs.KotlinFunctionStub;
030    import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes;
031    import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage;
032    
033    import java.util.Collections;
034    import java.util.List;
035    
036    public class JetNamedFunction extends JetTypeParameterListOwnerStub<KotlinFunctionStub>
037            implements JetFunction, JetWithExpressionInitializer, PsiModifiableCodeBlock {
038        public JetNamedFunction(@NotNull ASTNode node) {
039            super(node);
040        }
041    
042        public JetNamedFunction(@NotNull KotlinFunctionStub stub) {
043            super(stub, JetStubElementTypes.FUNCTION);
044        }
045    
046        @Override
047        public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
048            return visitor.visitNamedFunction(this, data);
049        }
050    
051        public boolean hasTypeParameterListBeforeFunctionName() {
052            KotlinFunctionStub stub = getStub();
053            if (stub != null) {
054                return stub.hasTypeParameterListBeforeFunctionName();
055            }
056            return hasTypeParameterListBeforeFunctionNameByTree();
057        }
058    
059        private boolean hasTypeParameterListBeforeFunctionNameByTree() {
060            JetTypeParameterList typeParameterList = getTypeParameterList();
061            if (typeParameterList == null) {
062                return false;
063            }
064            PsiElement nameIdentifier = getNameIdentifier();
065            if (nameIdentifier == null) {
066                return false;
067            }
068            return nameIdentifier.getTextOffset() > typeParameterList.getTextOffset();
069        }
070    
071        @Override
072        public boolean hasBlockBody() {
073            KotlinFunctionStub stub = getStub();
074            if (stub != null) {
075                return stub.hasBlockBody();
076            }
077            return getEqualsToken() == null;
078        }
079    
080        @Override
081        @Nullable
082        public PsiElement getEqualsToken() {
083            return findChildByType(JetTokens.EQ);
084        }
085    
086        @Override
087        @Nullable
088        public JetExpression getInitializer() {
089            return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class);
090        }
091    
092        @Override
093        public boolean hasInitializer() {
094            return getInitializer() != null;
095        }
096    
097        @Override
098        public ItemPresentation getPresentation() {
099            return ItemPresentationProviders.getItemPresentation(this);
100        }
101    
102        @Override
103        @Nullable
104        public JetParameterList getValueParameterList() {
105            return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST);
106        }
107    
108        @Override
109        @NotNull
110        public List<JetParameter> getValueParameters() {
111            JetParameterList list = getValueParameterList();
112            return list != null ? list.getParameters() : Collections.<JetParameter>emptyList();
113        }
114    
115        @Override
116        @Nullable
117        public JetExpression getBodyExpression() {
118            return findChildByClass(JetExpression.class);
119        }
120    
121        @Override
122        public boolean hasBody() {
123            KotlinFunctionStub stub = getStub();
124            if (stub != null) {
125                return stub.hasBody();
126            }
127            return getBodyExpression() != null;
128        }
129    
130        @Override
131        public boolean hasDeclaredReturnType() {
132            return getTypeReference() != null;
133        }
134    
135        @Override
136        @Nullable
137        public JetTypeReference getReceiverTypeReference() {
138            KotlinFunctionStub stub = getStub();
139            if (stub != null) {
140                if (!stub.isExtension()) {
141                    return null;
142                }
143                List<JetTypeReference> childTypeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
144                if (!childTypeReferences.isEmpty()) {
145                    return childTypeReferences.get(0);
146                }
147                else {
148                    return null;
149                }
150            }
151            return getReceiverTypeRefByTree();
152        }
153    
154        @Nullable
155        private JetTypeReference getReceiverTypeRefByTree() {
156            PsiElement child = getFirstChild();
157            while (child != null) {
158                IElementType tt = child.getNode().getElementType();
159                if (tt == JetTokens.LPAR || tt == JetTokens.COLON) break;
160                if (child instanceof JetTypeReference) {
161                    return (JetTypeReference) child;
162                }
163                child = child.getNextSibling();
164            }
165    
166            return null;
167        }
168    
169        @Override
170        @Nullable
171        public JetTypeReference getTypeReference() {
172            KotlinFunctionStub stub = getStub();
173            if (stub != null) {
174                List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
175                int returnTypeIndex = stub.isExtension() ? 1 : 0;
176                if (returnTypeIndex >= typeReferences.size()) {
177                    return null;
178                }
179                return typeReferences.get(returnTypeIndex);
180            }
181            return TypeRefHelpersPackage.getTypeReference(this);
182        }
183    
184        @Override
185        @Nullable
186        public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) {
187            return TypeRefHelpersPackage.setTypeReference(this, getValueParameterList(), typeRef);
188        }
189    
190        @Nullable
191        @Override
192        public PsiElement getColon() {
193            return findChildByType(JetTokens.COLON);
194        }
195    
196        @Override
197        public boolean isLocal() {
198            PsiElement parent = getParent();
199            return !(parent instanceof JetFile || parent instanceof JetClassBody);
200        }
201    
202        @Override
203        public boolean shouldChangeModificationCount(PsiElement place) {
204            // Suppress Java check for out-of-block
205            return false;
206        }
207    }