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