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 017package org.jetbrains.jet.lang.psi; 018 019import com.intellij.lang.ASTNode; 020import com.intellij.navigation.ItemPresentation; 021import com.intellij.navigation.ItemPresentationProviders; 022import com.intellij.openapi.util.text.StringUtil; 023import com.intellij.psi.PsiElement; 024import com.intellij.psi.PsiFile; 025import com.intellij.psi.stubs.IStubElementType; 026import com.intellij.psi.util.PsiTreeUtil; 027import com.intellij.util.IncorrectOperationException; 028import org.jetbrains.annotations.NotNull; 029import org.jetbrains.annotations.Nullable; 030import org.jetbrains.jet.JetNodeTypes; 031import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub; 032import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes; 033import org.jetbrains.jet.lang.resolve.name.FqName; 034import org.jetbrains.jet.lexer.JetTokens; 035 036import java.util.ArrayList; 037import java.util.Collections; 038import java.util.List; 039 040public class JetClass extends JetTypeParameterListOwnerStub<PsiJetClassStub> implements JetClassOrObject { 041 042 public JetClass(@NotNull ASTNode node) { 043 super(node); 044 } 045 046 public JetClass(@NotNull PsiJetClassStub stub) { 047 super(stub, JetStubElementTypes.CLASS); 048 } 049 050 @NotNull 051 @Override 052 public List<JetDeclaration> getDeclarations() { 053 JetClassBody body = (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); 054 if (body == null) return Collections.emptyList(); 055 056 return body.getDeclarations(); 057 } 058 059 @Override 060 public void accept(@NotNull JetVisitorVoid visitor) { 061 visitor.visitClass(this); 062 } 063 064 @Override 065 public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) { 066 return visitor.visitClass(this, data); 067 } 068 069 @Nullable 070 public JetParameterList getPrimaryConstructorParameterList() { 071 return (JetParameterList) findChildByType(JetNodeTypes.VALUE_PARAMETER_LIST); 072 } 073 074 @NotNull 075 public List<JetParameter> getPrimaryConstructorParameters() { 076 JetParameterList list = getPrimaryConstructorParameterList(); 077 if (list == null) return Collections.emptyList(); 078 return list.getParameters(); 079 } 080 081 @Override 082 @Nullable 083 public JetDelegationSpecifierList getDelegationSpecifierList() { 084 return (JetDelegationSpecifierList) findChildByType(JetNodeTypes.DELEGATION_SPECIFIER_LIST); 085 } 086 087 @Override 088 @NotNull 089 public List<JetDelegationSpecifier> getDelegationSpecifiers() { 090 JetDelegationSpecifierList list = getDelegationSpecifierList(); 091 return list != null ? list.getDelegationSpecifiers() : Collections.<JetDelegationSpecifier>emptyList(); 092 } 093 094 @Nullable 095 public JetModifierList getPrimaryConstructorModifierList() { 096 return (JetModifierList) findChildByType(JetNodeTypes.PRIMARY_CONSTRUCTOR_MODIFIER_LIST); 097 } 098 099 @Override 100 @NotNull 101 public List<JetClassInitializer> getAnonymousInitializers() { 102 JetClassBody body = getBody(); 103 if (body == null) return Collections.emptyList(); 104 105 return body.getAnonymousInitializers(); 106 } 107 108 @Override 109 public boolean hasPrimaryConstructor() { 110 return getPrimaryConstructorParameterList() != null; 111 } 112 113 @Override 114 public JetObjectDeclarationName getNameAsDeclaration() { 115 return (JetObjectDeclarationName) findChildByType(JetNodeTypes.OBJECT_DECLARATION_NAME); 116 } 117 118 @Override 119 public JetClassBody getBody() { 120 return (JetClassBody) findChildByType(JetNodeTypes.CLASS_BODY); 121 } 122 123 @Nullable 124 public JetClassObject getClassObject() { 125 JetClassBody body = getBody(); 126 if (body == null) return null; 127 return body.getClassObject(); 128 } 129 130 public List<JetProperty> getProperties() { 131 JetClassBody body = getBody(); 132 if (body == null) return Collections.emptyList(); 133 134 return body.getProperties(); 135 } 136 137 public boolean isTrait() { 138 PsiJetClassStub stub = getStub(); 139 if (stub != null) { 140 return stub.isTrait(); 141 } 142 143 return findChildByType(JetTokens.TRAIT_KEYWORD) != null; 144 } 145 146 public boolean isEnum() { 147 PsiJetClassStub stub = getStub(); 148 if (stub != null) { 149 return stub.isEnumClass(); 150 } 151 152 return hasModifier(JetTokens.ENUM_KEYWORD); 153 } 154 155 public boolean isAnnotation() { 156 PsiJetClassStub stub = getStub(); 157 if (stub != null) { 158 return stub.isAnnotation(); 159 } 160 161 return hasModifier(JetTokens.ANNOTATION_KEYWORD); 162 } 163 164 public boolean isInner() { 165 PsiJetClassStub stub = getStub(); 166 if (stub != null) { 167 return stub.isInner(); 168 } 169 170 return hasModifier(JetTokens.INNER_KEYWORD); 171 } 172 173 @NotNull 174 @Override 175 public IStubElementType getElementType() { 176 return JetStubElementTypes.CLASS; 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 PsiJetClassStub 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).getNamespaceHeader().getQualifiedName(); 214 if (!fileQualifiedName.isEmpty()) { 215 parts.add(fileQualifiedName); 216 } 217 Collections.reverse(parts); 218 return StringUtil.join(parts, "."); 219 } 220 221 /** 222 * Returns the list of unqualified names that are indexed as the superclass names of this class. For the names that might be imported 223 * via an aliased import, includes both the original and the aliased name (reference resolution during inheritor search will sort this out). 224 * 225 * @return the list of possible superclass names 226 */ 227 @NotNull 228 public List<String> getSuperNames() { 229 PsiJetClassStub stub = getStub(); 230 if (stub != null) { 231 return stub.getSuperNames(); 232 } 233 234 List<JetDelegationSpecifier> specifiers = getDelegationSpecifiers(); 235 if (specifiers.size() == 0) return Collections.emptyList(); 236 List<String> result = new ArrayList<String>(); 237 for (JetDelegationSpecifier specifier : specifiers) { 238 JetUserType superType = specifier.getTypeAsUserType(); 239 if (superType != null) { 240 String referencedName = superType.getReferencedName(); 241 if (referencedName != null) { 242 addSuperName(result, referencedName); 243 } 244 } 245 } 246 return result; 247 } 248 249 private void addSuperName(List<String> result, String referencedName) { 250 result.add(referencedName); 251 if (getContainingFile() instanceof JetFile) { 252 JetImportDirective directive = ((JetFile) getContainingFile()).findImportByAlias(referencedName); 253 if (directive != null) { 254 JetExpression reference = directive.getImportedReference(); 255 while (reference instanceof JetDotQualifiedExpression) { 256 reference = ((JetDotQualifiedExpression) reference).getSelectorExpression(); 257 } 258 if (reference instanceof JetSimpleNameExpression) { 259 result.add(((JetSimpleNameExpression) reference).getReferencedName()); 260 } 261 } 262 } 263 } 264 265 @Override 266 public ItemPresentation getPresentation() { 267 return ItemPresentationProviders.getItemPresentation(this); 268 } 269}