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.stubs.IStubElementType;
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.jet.JetNodeTypes;
029    import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub;
030    import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
031    import org.jetbrains.jet.lang.resolve.name.FqName;
032    import org.jetbrains.jet.lang.resolve.name.Name;
033    import org.jetbrains.jet.lexer.JetTokens;
034    
035    import java.util.Collections;
036    import java.util.List;
037    
038    public class JetNamedFunction extends JetTypeParameterListOwnerStub<PsiJetFunctionStub> implements JetFunction, JetWithExpressionInitializer {
039        public JetNamedFunction(@NotNull ASTNode node) {
040            super(node);
041        }
042    
043        public JetNamedFunction(@NotNull PsiJetFunctionStub stub) {
044            super(stub, JetStubElementTypes.FUNCTION);
045        }
046    
047        @Override
048        public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
049            return visitor.visitNamedFunction(this, data);
050        }
051    
052        public boolean hasTypeParameterListBeforeFunctionName() {
053            JetTypeParameterList typeParameterList = getTypeParameterList();
054            if (typeParameterList == null) {
055                return false;
056            }
057            PsiElement nameIdentifier = getNameIdentifier();
058            if (nameIdentifier == null) {
059                return false;
060            }
061            return nameIdentifier.getTextOffset() > typeParameterList.getTextOffset();
062        }
063    
064        @Override
065        public boolean hasBlockBody() {
066            return getEqualsToken() == null;
067        }
068    
069        @Nullable
070        public PsiElement getEqualsToken() {
071            return findChildByType(JetTokens.EQ);
072        }
073    
074        @Override
075        @Nullable
076        public JetExpression getInitializer() {
077            return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class);
078        }
079    
080        /**
081        * Returns full qualified name for function "package_fqn.function_name"
082        * Not null for top level functions unless syntax errors are present.
083        * @return
084        */
085        @Nullable
086        public FqName getFqName() {
087            PsiJetFunctionStub stub = getStub();
088            if (stub != null) {
089                return stub.getTopFQName();
090            }
091    
092            PsiElement parent = getParent();
093            if (parent instanceof JetFile) {
094                // fqname is different in scripts
095                if (((JetFile) parent).getPackageDirective() == null) {
096                    return null;
097                }
098                JetFile jetFile = (JetFile) parent;
099                FqName fileFQN = JetPsiUtil.getFQName(jetFile);
100                Name nameAsName = getNameAsName();
101                if (nameAsName != null) {
102                    return fileFQN.child(nameAsName);
103                }
104            }
105    
106            return null;
107        }
108    
109        @NotNull
110        @Override
111        public IStubElementType getElementType() {
112            return JetStubElementTypes.FUNCTION;
113        }
114        
115        @Override
116        public ItemPresentation getPresentation() {
117            return ItemPresentationProviders.getItemPresentation(this);
118        }
119    
120        @Override
121        @Nullable
122        public JetParameterList getValueParameterList() {
123            return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
124        }
125    
126        @Override
127        @NotNull
128        public List<JetParameter> getValueParameters() {
129            JetParameterList list = getValueParameterList();
130            return list != null ? list.getParameters() : Collections.<JetParameter>emptyList();
131        }
132    
133        @Override
134        @Nullable
135        public JetExpression getBodyExpression() {
136            return findChildByClass(JetExpression.class);
137        }
138    
139        @Override
140        public boolean hasDeclaredReturnType() {
141            return getReturnTypeRef() != null;
142        }
143    
144        @Override
145        @Nullable
146        public JetTypeReference getReceiverTypeRef() {
147            PsiElement child = getFirstChild();
148            while (child != null) {
149                IElementType tt = child.getNode().getElementType();
150                if (tt == JetTokens.LPAR || tt == JetTokens.COLON) break;
151                if (child instanceof JetTypeReference) {
152                    return (JetTypeReference) child;
153                }
154                child = child.getNextSibling();
155            }
156    
157            return null;
158        }
159    
160        @Override
161        @Nullable
162        public JetTypeReference getReturnTypeRef() {
163            boolean colonPassed = false;
164            PsiElement child = getFirstChild();
165            while (child != null) {
166                IElementType tt = child.getNode().getElementType();
167                if (tt == JetTokens.COLON) {
168                    colonPassed = true;
169                }
170                if (colonPassed && child instanceof JetTypeReference) {
171                    return (JetTypeReference) child;
172                }
173                child = child.getNextSibling();
174            }
175    
176            return null;
177        }
178    
179        @NotNull
180        @Override
181        public JetElement asElement() {
182            return this;
183        }
184    
185        @Override
186        public boolean isLocal() {
187            PsiElement parent = getParent();
188            return !(parent instanceof JetFile || parent instanceof JetClassBody);
189        }
190    }