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.hasReceiverTypeRef()) { 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.hasReceiverTypeRef() ? 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 @NotNull 161 public List<JetPropertyAccessor> getAccessors() { 162 return getStubOrPsiChildrenAsList(JetStubElementTypes.PROPERTY_ACCESSOR); 163 } 164 165 @Nullable 166 public JetPropertyAccessor getGetter() { 167 for (JetPropertyAccessor accessor : getAccessors()) { 168 if (accessor.isGetter()) return accessor; 169 } 170 171 return null; 172 } 173 174 @Nullable 175 public JetPropertyAccessor getSetter() { 176 for (JetPropertyAccessor accessor : getAccessors()) { 177 if (accessor.isSetter()) return accessor; 178 } 179 180 return null; 181 } 182 183 public boolean hasDelegate() { 184 KotlinPropertyStub stub = getStub(); 185 if (stub != null) { 186 return stub.hasDelegate(); 187 } 188 return getDelegate() != null; 189 } 190 191 @Nullable 192 public JetPropertyDelegate getDelegate() { 193 return (JetPropertyDelegate) findChildByType(PROPERTY_DELEGATE); 194 } 195 196 public boolean hasDelegateExpression() { 197 KotlinPropertyStub stub = getStub(); 198 if (stub != null) { 199 return stub.hasDelegateExpression(); 200 } 201 return getDelegateExpression() != null; 202 } 203 204 @Nullable 205 public JetExpression getDelegateExpression() { 206 JetPropertyDelegate delegate = getDelegate(); 207 if (delegate != null) { 208 return delegate.getExpression(); 209 } 210 return null; 211 } 212 213 @Override 214 public boolean hasInitializer() { 215 KotlinPropertyStub stub = getStub(); 216 if (stub != null) { 217 return stub.hasInitializer(); 218 } 219 return getInitializer() != null; 220 } 221 222 @Override 223 @Nullable 224 public JetExpression getInitializer() { 225 return PsiTreeUtil.getNextSiblingOfType(findChildByType(EQ), JetExpression.class); 226 } 227 228 public boolean hasDelegateExpressionOrInitializer() { 229 return hasDelegateExpression() || hasInitializer(); 230 } 231 232 @Nullable 233 public JetExpression setInitializer(@Nullable JetExpression initializer) { 234 JetExpression oldInitializer = getInitializer(); 235 236 if (oldInitializer != null) { 237 if (initializer != null) { 238 return (JetExpression) oldInitializer.replace(initializer); 239 } 240 else { 241 deleteChildRange(findChildByType(EQ), oldInitializer); 242 return null; 243 } 244 } 245 else { 246 if (initializer != null) { 247 PsiElement addAfter = getTypeReference(); 248 if (addAfter == null) { 249 addAfter = getNameIdentifier(); 250 } 251 PsiElement eq = addAfter(new JetPsiFactory(getProject()).createEQ(), addAfter); 252 return (JetExpression) addAfter(initializer, eq); 253 } 254 else { 255 return null; 256 } 257 } 258 } 259 260 @Nullable 261 public JetExpression getDelegateExpressionOrInitializer() { 262 JetExpression expression = getDelegateExpression(); 263 if (expression == null) { 264 return getInitializer(); 265 } 266 return expression; 267 } 268 269 @Override 270 @NotNull 271 public ASTNode getValOrVarNode() { 272 ASTNode node = getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD)); 273 assert node != null : "Val or var should always exist for property"; 274 return node; 275 } 276 277 @Override 278 public ItemPresentation getPresentation() { 279 return ItemPresentationProviders.getItemPresentation(this); 280 } 281 282 @Override 283 public boolean shouldChangeModificationCount(PsiElement place) { 284 // Suppress Java check for out-of-block 285 return false; 286 } 287 }