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 }