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