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