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 = getBody();
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 getStubOrPsiChild(JetStubElementTypes.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 getStubOrPsiChild(JetStubElementTypes.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 getStubOrPsiChild(JetStubElementTypes.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 getStubOrPsiChild(JetStubElementTypes.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            return hasModifier(JetTokens.ENUM_KEYWORD);
142        }
143    
144        public boolean isAnnotation() {
145            return hasModifier(JetTokens.ANNOTATION_KEYWORD);
146        }
147    
148        public boolean isInner() {
149            return hasModifier(JetTokens.INNER_KEYWORD);
150        }
151    
152        @Override
153        public void delete() throws IncorrectOperationException {
154            JetPsiUtil.deleteClass(this);
155        }
156    
157        @Override
158        public boolean isEquivalentTo(PsiElement another) {
159            if (super.isEquivalentTo(another)) {
160                return true;
161            }
162            if (another instanceof JetClass) {
163                String fq1 = getQualifiedName();
164                String fq2 = ((JetClass) another).getQualifiedName();
165                return fq1 != null && fq2 != null && fq1.equals(fq2);
166            }
167            return false;
168        }
169    
170        @Nullable
171        private String getQualifiedName() {
172            PsiJetClassStub stub = getStub();
173            if (stub != null) {
174                FqName fqName = stub.getFqName();
175                return fqName == null ? null : fqName.asString();
176            }
177    
178            List<String> parts = new ArrayList<String>();
179            JetClassOrObject current = this;
180            while (current != null) {
181                parts.add(current.getName());
182                current = PsiTreeUtil.getParentOfType(current, JetClassOrObject.class);
183            }
184            PsiFile file = getContainingFile();
185            if (!(file instanceof JetFile)) return null;
186            String fileQualifiedName = ((JetFile) file).getPackageFqName().asString();
187            if (!fileQualifiedName.isEmpty()) {
188                parts.add(fileQualifiedName);
189            }
190            Collections.reverse(parts);
191            return StringUtil.join(parts, ".");
192        }
193    
194        @Override
195        public ItemPresentation getPresentation() {
196            return ItemPresentationProviders.getItemPresentation(this);
197        }
198    
199        @Override
200        public boolean isTopLevel() {
201            return getContainingFile() == getParent();
202        }
203    
204        @Override
205        public boolean isLocal() {
206            PsiJetClassStub stub = getStub();
207            if (stub != null) {
208                return stub.isLocal();
209            }
210            return JetPsiUtil.isLocal(this);
211        }
212    }