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.util.text.StringUtil; 023 import com.intellij.psi.PsiElement; 024 import com.intellij.psi.PsiFile; 025 import com.intellij.psi.util.PsiTreeUtil; 026 import com.intellij.util.IncorrectOperationException; 027 import org.jetbrains.annotations.NotNull; 028 import org.jetbrains.annotations.Nullable; 029 import org.jetbrains.kotlin.JetNodeTypes; 030 import org.jetbrains.kotlin.lexer.JetModifierKeywordToken; 031 import org.jetbrains.kotlin.lexer.JetTokens; 032 import org.jetbrains.kotlin.name.FqName; 033 import org.jetbrains.kotlin.psi.addRemoveModifier.AddRemoveModifierPackage; 034 import org.jetbrains.kotlin.psi.stubs.KotlinClassStub; 035 import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes; 036 037 import java.util.ArrayList; 038 import java.util.Collections; 039 import java.util.List; 040 041 public class JetClass extends JetTypeParameterListOwnerStub<KotlinClassStub> implements JetClassOrObject { 042 043 public JetClass(@NotNull ASTNode node) { 044 super(node); 045 } 046 047 public JetClass(@NotNull KotlinClassStub stub) { 048 super(stub, JetStubElementTypes.CLASS); 049 } 050 051 @NotNull 052 @Override 053 public List<JetDeclaration> getDeclarations() { 054 JetClassBody body = getBody(); 055 if (body == null) return Collections.emptyList(); 056 057 return body.getDeclarations(); 058 } 059 060 @Override 061 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) { 062 return visitor.visitClass(this, data); 063 } 064 065 @Nullable 066 public JetParameterList getPrimaryConstructorParameterList() { 067 return getStubOrPsiChild(JetStubElementTypes.VALUE_PARAMETER_LIST); 068 } 069 070 @NotNull 071 public List<JetParameter> getPrimaryConstructorParameters() { 072 JetParameterList list = getPrimaryConstructorParameterList(); 073 if (list == null) return Collections.emptyList(); 074 return list.getParameters(); 075 } 076 077 @Override 078 @Nullable 079 public JetDelegationSpecifierList getDelegationSpecifierList() { 080 return getStubOrPsiChild(JetStubElementTypes.DELEGATION_SPECIFIER_LIST); 081 } 082 083 @Override 084 @NotNull 085 public List<JetDelegationSpecifier> getDelegationSpecifiers() { 086 JetDelegationSpecifierList list = getDelegationSpecifierList(); 087 return list != null ? list.getDelegationSpecifiers() : Collections.<JetDelegationSpecifier>emptyList(); 088 } 089 090 @Nullable 091 public JetModifierList getPrimaryConstructorModifierList() { 092 return getStubOrPsiChild(JetStubElementTypes.PRIMARY_CONSTRUCTOR_MODIFIER_LIST); 093 } 094 095 public void addPrimaryConstructorModifier(@NotNull JetModifierKeywordToken modifier) { 096 JetModifierList modifierList = getPrimaryConstructorModifierList(); 097 if (modifierList != null) { 098 AddRemoveModifierPackage.addModifier(modifierList, modifier, JetTokens.PUBLIC_KEYWORD); 099 } 100 else { 101 if (modifier == JetTokens.PUBLIC_KEYWORD) return; 102 103 JetParameterList parameterList = getPrimaryConstructorParameterList(); 104 assert parameterList != null; 105 JetModifierList newModifierList = new JetPsiFactory(getProject()).createModifierList(modifier); 106 addBefore(newModifierList, parameterList); 107 } 108 } 109 110 public void removePrimaryConstructorModifier(@NotNull JetModifierKeywordToken modifier) { 111 JetModifierList list = getPrimaryConstructorModifierList(); 112 if (list != null) { 113 PsiElement token = list.getModifier(modifier); 114 if (token != null) { 115 token.delete(); 116 } 117 } 118 } 119 120 @Override 121 @NotNull 122 public List<JetClassInitializer> getAnonymousInitializers() { 123 JetClassBody body = getBody(); 124 if (body == null) return Collections.emptyList(); 125 126 return body.getAnonymousInitializers(); 127 } 128 129 @Override 130 public boolean hasPrimaryConstructor() { 131 return getPrimaryConstructorParameterList() != null; 132 } 133 134 @Override 135 public JetObjectDeclarationName getNameAsDeclaration() { 136 return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME); 137 } 138 139 @Override 140 public JetClassBody getBody() { 141 return getStubOrPsiChild(JetStubElementTypes.CLASS_BODY); 142 } 143 144 @Nullable 145 public JetClassObject getClassObject() { 146 JetClassBody body = getBody(); 147 if (body == null) return null; 148 return body.getClassObject(); 149 } 150 151 public List<JetProperty> getProperties() { 152 JetClassBody body = getBody(); 153 if (body == null) return Collections.emptyList(); 154 155 return body.getProperties(); 156 } 157 158 public boolean isTrait() { 159 KotlinClassStub stub = getStub(); 160 if (stub != null) { 161 return stub.isTrait(); 162 } 163 164 return findChildByType(JetTokens.TRAIT_KEYWORD) != null; 165 } 166 167 public boolean isEnum() { 168 return hasModifier(JetTokens.ENUM_KEYWORD); 169 } 170 171 public boolean isAnnotation() { 172 return hasModifier(JetTokens.ANNOTATION_KEYWORD); 173 } 174 175 public boolean isInner() { 176 return hasModifier(JetTokens.INNER_KEYWORD); 177 } 178 179 @Override 180 public void delete() throws IncorrectOperationException { 181 JetPsiUtil.deleteClass(this); 182 } 183 184 @Override 185 public boolean isEquivalentTo(PsiElement another) { 186 if (super.isEquivalentTo(another)) { 187 return true; 188 } 189 if (another instanceof JetClass) { 190 String fq1 = getQualifiedName(); 191 String fq2 = ((JetClass) another).getQualifiedName(); 192 return fq1 != null && fq2 != null && fq1.equals(fq2); 193 } 194 return false; 195 } 196 197 @Nullable 198 private String getQualifiedName() { 199 KotlinClassStub stub = getStub(); 200 if (stub != null) { 201 FqName fqName = stub.getFqName(); 202 return fqName == null ? null : fqName.asString(); 203 } 204 205 List<String> parts = new ArrayList<String>(); 206 JetClassOrObject current = this; 207 while (current != null) { 208 parts.add(current.getName()); 209 current = PsiTreeUtil.getParentOfType(current, JetClassOrObject.class); 210 } 211 PsiFile file = getContainingFile(); 212 if (!(file instanceof JetFile)) return null; 213 String fileQualifiedName = ((JetFile) file).getPackageFqName().asString(); 214 if (!fileQualifiedName.isEmpty()) { 215 parts.add(fileQualifiedName); 216 } 217 Collections.reverse(parts); 218 return StringUtil.join(parts, "."); 219 } 220 221 @Override 222 public ItemPresentation getPresentation() { 223 return ItemPresentationProviders.getItemPresentation(this); 224 } 225 226 @Override 227 public boolean isTopLevel() { 228 return getContainingFile() == getParent(); 229 } 230 231 @Override 232 public boolean isLocal() { 233 KotlinClassStub stub = getStub(); 234 if (stub != null) { 235 return stub.isLocal(); 236 } 237 return JetPsiUtil.isLocal(this); 238 } 239 }