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 true;
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        @Nullable
081        @IfNotParsed // "function" with no "fun" keyword is created by parser for "{...}" on top-level or in class body
082        public PsiElement getFunKeyword() {
083            return findChildByType(JetTokens.FUN_KEYWORD);
084        }
085    
086        @Override
087        @Nullable
088        public PsiElement getEqualsToken() {
089            return findChildByType(JetTokens.EQ);
090        }
091    
092        @Override
093        @Nullable
094        public JetExpression getInitializer() {
095            return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class);
096        }
097    
098        @Override
099        public boolean hasInitializer() {
100            return getInitializer() != null;
101        }
102    
103        @Override
104        public ItemPresentation getPresentation() {
105            return ItemPresentationProviders.getItemPresentation(this);
106        }
107    
108        @Override
109        @Nullable
110        public JetParameterList getValueParameterList() {
111            return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST);
112        }
113    
114        @Override
115        @NotNull
116        public List<JetParameter> getValueParameters() {
117            JetParameterList list = getValueParameterList();
118            return list != null ? list.getParameters() : Collections.<JetParameter>emptyList();
119        }
120    
121        @Override
122        @Nullable
123        public JetExpression getBodyExpression() {
124            return findChildByClass(JetExpression.class);
125        }
126    
127        @Override
128        public boolean hasBody() {
129            KotlinFunctionStub stub = getStub();
130            if (stub != null) {
131                return stub.hasBody();
132            }
133            return getBodyExpression() != null;
134        }
135    
136        @Override
137        public boolean hasDeclaredReturnType() {
138            return getTypeReference() != null;
139        }
140    
141        @Override
142        @Nullable
143        public JetTypeReference getReceiverTypeReference() {
144            KotlinFunctionStub stub = getStub();
145            if (stub != null) {
146                if (!stub.isExtension()) {
147                    return null;
148                }
149                List<JetTypeReference> childTypeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
150                if (!childTypeReferences.isEmpty()) {
151                    return childTypeReferences.get(0);
152                }
153                else {
154                    return null;
155                }
156            }
157            return getReceiverTypeRefByTree();
158        }
159    
160        @Nullable
161        private JetTypeReference getReceiverTypeRefByTree() {
162            PsiElement child = getFirstChild();
163            while (child != null) {
164                IElementType tt = child.getNode().getElementType();
165                if (tt == JetTokens.LPAR || tt == JetTokens.COLON) break;
166                if (child instanceof JetTypeReference) {
167                    return (JetTypeReference) child;
168                }
169                child = child.getNextSibling();
170            }
171    
172            return null;
173        }
174    
175        @Override
176        @Nullable
177        public JetTypeReference getTypeReference() {
178            KotlinFunctionStub stub = getStub();
179            if (stub != null) {
180                List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE);
181                int returnTypeIndex = stub.isExtension() ? 1 : 0;
182                if (returnTypeIndex >= typeReferences.size()) {
183                    return null;
184                }
185                return typeReferences.get(returnTypeIndex);
186            }
187            return TypeRefHelpersPackage.getTypeReference(this);
188        }
189    
190        @Override
191        @Nullable
192        public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) {
193            return TypeRefHelpersPackage.setTypeReference(this, getValueParameterList(), typeRef);
194        }
195    
196        @Nullable
197        @Override
198        public PsiElement getColon() {
199            return findChildByType(JetTokens.COLON);
200        }
201    
202        @Override
203        public boolean isLocal() {
204            PsiElement parent = getParent();
205            return !(parent instanceof JetFile || parent instanceof JetClassBody);
206        }
207    
208        public boolean isTopLevel() {
209            KotlinFunctionStub stub = getStub();
210            if (stub != null) {
211                return stub.isTopLevel();
212            }
213    
214            return getParent() instanceof JetFile;
215        }
216    
217        @Override
218        public boolean shouldChangeModificationCount(PsiElement place) {
219            // Suppress Java check for out-of-block
220            return false;
221        }
222    }