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.extapi.psi.PsiFileBase;
020    import com.intellij.lang.ASTNode;
021    import com.intellij.lang.FileASTNode;
022    import com.intellij.openapi.fileTypes.FileType;
023    import com.intellij.psi.FileViewProvider;
024    import com.intellij.psi.PsiClass;
025    import com.intellij.psi.PsiClassOwner;
026    import com.intellij.psi.PsiElementVisitor;
027    import com.intellij.psi.stubs.StubElement;
028    import com.intellij.psi.util.PsiTreeUtil;
029    import org.jetbrains.annotations.NotNull;
030    import org.jetbrains.annotations.Nullable;
031    import org.jetbrains.jet.JetNodeTypes;
032    import org.jetbrains.jet.lang.psi.stubs.KotlinFileStub;
033    import org.jetbrains.jet.lang.psi.stubs.elements.JetPlaceHolderStubElementType;
034    import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes;
035    import org.jetbrains.jet.lang.resolve.name.FqName;
036    import org.jetbrains.jet.plugin.JetFileType;
037    import org.jetbrains.jet.plugin.JetLanguage;
038    
039    import java.util.Arrays;
040    import java.util.Collections;
041    import java.util.List;
042    
043    public class JetFile extends PsiFileBase implements JetDeclarationContainer, JetAnnotated, JetElement, PsiClassOwner {
044    
045        private final boolean isCompiled;
046    
047        public JetFile(FileViewProvider viewProvider, boolean compiled) {
048            super(viewProvider, JetLanguage.INSTANCE);
049            this.isCompiled = compiled;
050        }
051    
052        @Override
053        public FileASTNode getNode() {
054            return super.getNode();
055        }
056    
057        public boolean isCompiled() {
058            return isCompiled;
059        }
060    
061        @Override
062        @NotNull
063        public FileType getFileType() {
064            return JetFileType.INSTANCE;
065        }
066    
067        @Override
068        public String toString() {
069            return "JetFile: " + getName();
070        }
071    
072        @NotNull
073        @Override
074        public List<JetDeclaration> getDeclarations() {
075            KotlinFileStub stub = getStub();
076            if (stub != null) {
077                return Arrays.asList(stub.getChildrenByType(JetStubElementTypes.DECLARATION_TYPES, JetDeclaration.ARRAY_FACTORY));
078            }
079            return PsiTreeUtil.getChildrenOfTypeAsList(this, JetDeclaration.class);
080        }
081    
082        @Nullable
083        public JetImportList getImportList() {
084            return findChildByTypeOrClass(JetStubElementTypes.IMPORT_LIST, JetImportList.class);
085        }
086    
087        @Nullable
088        public JetFileAnnotationList getFileAnnotationList() {
089            return findChildByTypeOrClass(JetStubElementTypes.FILE_ANNOTATION_LIST, JetFileAnnotationList.class);
090        }
091    
092        @Nullable
093        public <T extends JetElementImplStub<? extends StubElement<?>>> T findChildByTypeOrClass(
094                @NotNull JetPlaceHolderStubElementType<T> elementType,
095                @NotNull Class<T> elementClass
096        ) {
097            KotlinFileStub stub = getStub();
098            if (stub != null) {
099                StubElement<T> importListStub = stub.findChildStubByType(elementType);
100                return importListStub != null ? importListStub.getPsi() : null;
101            }
102            return findChildByClass(elementClass);
103        }
104    
105        @NotNull
106        public List<JetImportDirective> getImportDirectives() {
107            JetImportList importList = getImportList();
108            return importList != null ? importList.getImports() : Collections.<JetImportDirective>emptyList();
109        }
110    
111        @Nullable
112        public JetImportDirective findImportByAlias(@NotNull String name) {
113            for (JetImportDirective directive : getImportDirectives()) {
114                if (name.equals(directive.getAliasName())) {
115                    return directive;
116                }
117            }
118            return null;
119        }
120    
121        // scripts have no package directive, all other files must have package directives
122        @Nullable
123        public JetPackageDirective getPackageDirective() {
124            KotlinFileStub stub = getStub();
125            if (stub != null) {
126                StubElement<JetPackageDirective> packageDirectiveStub = stub.findChildStubByType(JetStubElementTypes.PACKAGE_DIRECTIVE);
127                return packageDirectiveStub != null ? packageDirectiveStub.getPsi() : null;
128            }
129            ASTNode ast = getNode().findChildByType(JetNodeTypes.PACKAGE_DIRECTIVE);
130            return ast != null ? (JetPackageDirective) ast.getPsi() : null;
131        }
132    
133        @Deprecated // getPackageFqName should be used instead
134        @Override
135        @NotNull
136        public String getPackageName() {
137            return getPackageFqName().asString();
138        }
139    
140        @NotNull
141        public FqName getPackageFqName() {
142            KotlinFileStub stub = getStub();
143            if (stub != null) {
144                return stub.getPackageFqName();
145            }
146            return getPackageFqNameByTree();
147        }
148    
149        @NotNull
150        public FqName getPackageFqNameByTree() {
151            JetPackageDirective packageDirective = getPackageDirective();
152            if (packageDirective == null) {
153                return FqName.ROOT;
154            }
155            return packageDirective.getFqName();
156        }
157    
158        @Override
159        @Nullable
160        public KotlinFileStub getStub() {
161            return (KotlinFileStub) super.getStub();
162        }
163    
164        @NotNull
165        @Override
166        public PsiClass[] getClasses() {
167            return PsiClass.EMPTY_ARRAY;
168        }
169    
170        @Override
171        public void setPackageName(String packageName) { }
172    
173        // SCRIPT: find script in file
174        @Nullable
175        public JetScript getScript() {
176            return PsiTreeUtil.getChildOfType(this, JetScript.class);
177        }
178    
179        public boolean isScript() {
180            KotlinFileStub stub = getStub();
181            if (stub != null) {
182                return stub.isScript();
183            }
184            return isScriptByTree();
185        }
186    
187        public boolean isScriptByTree() {
188            return getScript() != null;
189        }
190    
191        @NotNull
192        @Override
193        public String getName() {
194            return super.getName(); // TODO
195        }
196    
197        @Override
198        public void accept(@NotNull PsiElementVisitor visitor) {
199            if (visitor instanceof JetVisitor) {
200                accept((JetVisitor) visitor, null);
201            }
202            else {
203                visitor.visitFile(this);
204            }
205        }
206    
207        @NotNull
208        @Override
209        public JetFile getContainingJetFile() {
210            return this;
211        }
212    
213        @Override
214        public <D> void acceptChildren(@NotNull JetTreeVisitor<D> visitor, D data) {
215            JetPsiUtil.visitChildren(this, visitor, data);
216        }
217    
218        @Override
219        public <R, D> R accept(@NotNull JetVisitor<R, D> visitor, D data) {
220            return visitor.visitJetFile(this, data);
221        }
222    
223        @NotNull
224        @Override
225        public List<JetAnnotation> getAnnotations() {
226            JetFileAnnotationList fileAnnotationList = getFileAnnotationList();
227            if (fileAnnotationList == null) return Collections.emptyList();
228    
229            return fileAnnotationList.getAnnotations();
230        }
231    
232        @NotNull
233        @Override
234        public List<JetAnnotationEntry> getAnnotationEntries() {
235            JetFileAnnotationList fileAnnotationList = getFileAnnotationList();
236            if (fileAnnotationList == null) return Collections.emptyList();
237    
238            return fileAnnotationList.getAnnotationEntries();
239        }
240    }