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