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 void accept(@NotNull JetVisitorVoid visitor) {
049            visitor.visitNamedFunction(this);
050        }
051    
052        @Override
053        public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
054            return visitor.visitNamedFunction(this, data);
055        }
056    
057        public boolean hasTypeParameterListBeforeFunctionName() {
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            return getEqualsToken() == null;
072        }
073    
074        @Nullable
075        public PsiElement getEqualsToken() {
076            return findChildByType(JetTokens.EQ);
077        }
078    
079        @Override
080        @Nullable
081        public JetExpression getInitializer() {
082            return PsiTreeUtil.getNextSiblingOfType(getEqualsToken(), JetExpression.class);
083        }
084    
085        /**
086        * Returns full qualified name for function "package_fqn.function_name"
087        * Not null for top level functions unless syntax errors are present.
088        * @return
089        */
090        @Nullable
091        public FqName getFqName() {
092            PsiJetFunctionStub stub = getStub();
093            if (stub != null) {
094                return stub.getTopFQName();
095            }
096    
097            PsiElement parent = getParent();
098            if (parent instanceof JetFile) {
099                // fqname is different in scripts
100                if (((JetFile) parent).getNamespaceHeader() == null) {
101                    return null;
102                }
103                JetFile jetFile = (JetFile) parent;
104                FqName fileFQN = JetPsiUtil.getFQName(jetFile);
105                Name nameAsName = getNameAsName();
106                if (nameAsName != null) {
107                    return fileFQN.child(nameAsName);
108                }
109            }
110    
111            return null;
112        }
113    
114        @NotNull
115        @Override
116        public IStubElementType getElementType() {
117            return JetStubElementTypes.FUNCTION;
118        }
119        
120        @Override
121        public ItemPresentation getPresentation() {
122            return ItemPresentationProviders.getItemPresentation(this);
123        }
124    
125        @Override
126        @Nullable
127        public JetParameterList getValueParameterList() {
128            return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST);
129        }
130    
131        @Override
132        @NotNull
133        public List<JetParameter> getValueParameters() {
134            JetParameterList list = getValueParameterList();
135            return list != null ? list.getParameters() : Collections.<JetParameter>emptyList();
136        }
137    
138        @Override
139        @Nullable
140        public JetExpression getBodyExpression() {
141            return findChildByClass(JetExpression.class);
142        }
143    
144        @Override
145        public boolean hasDeclaredReturnType() {
146            return getReturnTypeRef() != null;
147        }
148    
149        @Override
150        @Nullable
151        public JetTypeReference getReceiverTypeRef() {
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            boolean colonPassed = false;
169            PsiElement child = getFirstChild();
170            while (child != null) {
171                IElementType tt = child.getNode().getElementType();
172                if (tt == JetTokens.COLON) {
173                    colonPassed = true;
174                }
175                if (colonPassed && child instanceof JetTypeReference) {
176                    return (JetTypeReference) child;
177                }
178                child = child.getNextSibling();
179            }
180    
181            return null;
182        }
183    
184        @NotNull
185        @Override
186        public JetElement asElement() {
187            return this;
188        }
189    
190        @Override
191        public boolean isLocal() {
192            PsiElement parent = getParent();
193            return !(parent instanceof JetFile || parent instanceof JetClassBody);
194        }
195    }