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.openapi.diagnostic.Logger; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.PsiModifiableCodeBlock; 025 import com.intellij.psi.tree.IElementType; 026 import com.intellij.psi.tree.TokenSet; 027 import com.intellij.psi.util.PsiTreeUtil; 028 import org.jetbrains.annotations.NotNull; 029 import org.jetbrains.annotations.Nullable; 030 import org.jetbrains.kotlin.JetNodeTypes; 031 import org.jetbrains.kotlin.lexer.JetTokens; 032 import org.jetbrains.kotlin.psi.stubs.KotlinPropertyStub; 033 import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; 034 import org.jetbrains.kotlin.psi.typeRefHelpers.TypeRefHelpersPackage; 035 036 import java.util.Collections; 037 import java.util.List; 038 039 import static org.jetbrains.kotlin.JetNodeTypes.PROPERTY_DELEGATE; 040 import static org.jetbrains.kotlin.lexer.JetTokens.*; 041 042 public class JetProperty extends JetTypeParameterListOwnerStub<KotlinPropertyStub> 043 implements JetVariableDeclaration, PsiModifiableCodeBlock { 044 045 private static final Logger LOG = Logger.getInstance(JetProperty.class); 046 047 public JetProperty(@NotNull ASTNode node) { 048 super(node); 049 } 050 051 public JetProperty(@NotNull KotlinPropertyStub stub) { 052 super(stub, JetStubElementTypes.PROPERTY); 053 } 054 055 @Override 056 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) { 057 return visitor.visitProperty(this, data); 058 } 059 060 @Override 061 public boolean isVar() { 062 KotlinPropertyStub stub = getStub(); 063 if (stub != null) { 064 return stub.isVar(); 065 } 066 067 return getNode().findChildByType(JetTokens.VAR_KEYWORD) != null; 068 } 069 070 public boolean isLocal() { 071 PsiElement parent = getParent(); 072 return !(parent instanceof JetFile || parent instanceof JetClassBody); 073 } 074 075 public boolean isTopLevel() { 076 KotlinPropertyStub stub = getStub(); 077 if (stub != null) { 078 return stub.isTopLevel(); 079 } 080 081 return getParent() instanceof JetFile; 082 } 083 084 @Nullable 085 @Override 086 public JetParameterList getValueParameterList() { 087 return null; 088 } 089 090 @NotNull 091 @Override 092 public List<JetParameter> getValueParameters() { 093 return Collections.emptyList(); 094 } 095 096 @Override 097 @Nullable 098 public JetTypeReference getReceiverTypeReference() { 099 KotlinPropertyStub stub = getStub(); 100 if (stub != null) { 101 if (!stub.isExtension()) { 102 return null; 103 } 104 else { 105 return getStubOrPsiChild(JetStubElementTypes.TYPE_REFERENCE); 106 } 107 } 108 return getReceiverTypeRefByTree(); 109 } 110 111 @Nullable 112 private JetTypeReference getReceiverTypeRefByTree() { 113 ASTNode node = getNode().getFirstChildNode(); 114 while (node != null) { 115 IElementType tt = node.getElementType(); 116 if (tt == JetTokens.COLON) break; 117 118 if (tt == JetNodeTypes.TYPE_REFERENCE) { 119 return (JetTypeReference) node.getPsi(); 120 } 121 node = node.getTreeNext(); 122 } 123 124 return null; 125 } 126 127 @Override 128 @Nullable 129 public JetTypeReference getTypeReference() { 130 KotlinPropertyStub stub = getStub(); 131 if (stub != null) { 132 if (!stub.hasReturnTypeRef()) { 133 return null; 134 } 135 else { 136 List<JetTypeReference> typeReferences = getStubOrPsiChildrenAsList(JetStubElementTypes.TYPE_REFERENCE); 137 int returnTypeRefPositionInPsi = stub.isExtension() ? 1 : 0; 138 if (typeReferences.size() <= returnTypeRefPositionInPsi) { 139 LOG.error("Invalid stub structure built for property:\n" + getText()); 140 return null; 141 } 142 return typeReferences.get(returnTypeRefPositionInPsi); 143 } 144 } 145 return TypeRefHelpersPackage.getTypeReference(this); 146 } 147 148 @Override 149 @Nullable 150 public JetTypeReference setTypeReference(@Nullable JetTypeReference typeRef) { 151 return TypeRefHelpersPackage.setTypeReference(this, getNameIdentifier(), typeRef); 152 } 153 154 @Nullable 155 @Override 156 public PsiElement getColon() { 157 return findChildByType(JetTokens.COLON); 158 } 159 160 @Nullable 161 public PsiElement getEqualsToken() { 162 return findChildByType(JetTokens.EQ); 163 } 164 165 @NotNull 166 public List<JetPropertyAccessor> getAccessors() { 167 return getStubOrPsiChildrenAsList(JetStubElementTypes.PROPERTY_ACCESSOR); 168 } 169 170 @Nullable 171 public JetPropertyAccessor getGetter() { 172 for (JetPropertyAccessor accessor : getAccessors()) { 173 if (accessor.isGetter()) return accessor; 174 } 175 176 return null; 177 } 178 179 @Nullable 180 public JetPropertyAccessor getSetter() { 181 for (JetPropertyAccessor accessor : getAccessors()) { 182 if (accessor.isSetter()) return accessor; 183 } 184 185 return null; 186 } 187 188 public boolean hasDelegate() { 189 KotlinPropertyStub stub = getStub(); 190 if (stub != null) { 191 return stub.hasDelegate(); 192 } 193 return getDelegate() != null; 194 } 195 196 @Nullable 197 public JetPropertyDelegate getDelegate() { 198 return (JetPropertyDelegate) findChildByType(PROPERTY_DELEGATE); 199 } 200 201 public boolean hasDelegateExpression() { 202 KotlinPropertyStub stub = getStub(); 203 if (stub != null) { 204 return stub.hasDelegateExpression(); 205 } 206 return getDelegateExpression() != null; 207 } 208 209 @Nullable 210 public JetExpression getDelegateExpression() { 211 JetPropertyDelegate delegate = getDelegate(); 212 if (delegate != null) { 213 return delegate.getExpression(); 214 } 215 return null; 216 } 217 218 @Override 219 public boolean hasInitializer() { 220 KotlinPropertyStub stub = getStub(); 221 if (stub != null) { 222 return stub.hasInitializer(); 223 } 224 return getInitializer() != null; 225 } 226 227 @Override 228 @Nullable 229 public JetExpression getInitializer() { 230 return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), JetExpression.class); 231 } 232 233 public boolean hasDelegateExpressionOrInitializer() { 234 return hasDelegateExpression() || hasInitializer(); 235 } 236 237 @Nullable 238 public JetExpression setInitializer(@Nullable JetExpression initializer) { 239 JetExpression oldInitializer = getInitializer(); 240 241 if (oldInitializer != null) { 242 if (initializer != null) { 243 return (JetExpression) oldInitializer.replace(initializer); 244 } 245 else { 246 deleteChildRange(findChildByType(EQ), oldInitializer); 247 return null; 248 } 249 } 250 else { 251 if (initializer != null) { 252 PsiElement addAfter = getTypeReference(); 253 if (addAfter == null) { 254 addAfter = getNameIdentifier(); 255 } 256 PsiElement eq = addAfter(new JetPsiFactory(getProject()).createEQ(), addAfter); 257 return (JetExpression) addAfter(initializer, eq); 258 } 259 else { 260 return null; 261 } 262 } 263 } 264 265 @Nullable 266 public JetExpression getDelegateExpressionOrInitializer() { 267 JetExpression expression = getDelegateExpression(); 268 if (expression == null) { 269 return getInitializer(); 270 } 271 return expression; 272 } 273 274 @Override 275 @NotNull 276 public PsiElement getValOrVarKeyword() { 277 PsiElement element = findChildByType(VAL_VAR_TOKEN_SET); 278 assert element != null : "Val or var should always exist for property"; 279 return element; 280 } 281 282 private static final TokenSet VAL_VAR_TOKEN_SET = TokenSet.create(JetTokens.VAL_KEYWORD, JetTokens.VAR_KEYWORD); 283 284 @Override 285 public ItemPresentation getPresentation() { 286 return ItemPresentationProviders.getItemPresentation(this); 287 } 288 289 @Override 290 public boolean shouldChangeModificationCount(PsiElement place) { 291 // Suppress Java check for out-of-block 292 return false; 293 } 294 }