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