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