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.codegen; 018 019 import com.intellij.openapi.application.ApplicationManager; 020 import com.intellij.openapi.progress.ProcessCanceledException; 021 import com.intellij.openapi.vfs.VirtualFile; 022 import com.intellij.util.SmartList; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.annotations.Nullable; 025 import org.jetbrains.kotlin.codegen.context.PackageContext; 026 import org.jetbrains.kotlin.codegen.state.GenerationState; 027 import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; 028 import org.jetbrains.kotlin.diagnostics.DiagnosticUtils; 029 import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; 030 import org.jetbrains.kotlin.load.kotlin.PackageParts; 031 import org.jetbrains.kotlin.name.FqName; 032 import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus; 033 import org.jetbrains.kotlin.psi.*; 034 import org.jetbrains.kotlin.resolve.BindingContext; 035 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; 036 import org.jetbrains.org.objectweb.asm.Type; 037 038 import java.util.Collection; 039 040 public class PackageCodegen { 041 private final GenerationState state; 042 private final Collection<KtFile> files; 043 private final PackageFragmentDescriptor packageFragment; 044 private final PackageParts packageParts; 045 046 public PackageCodegen( 047 @NotNull GenerationState state, 048 @NotNull Collection<KtFile> files, 049 @NotNull FqName packageFqName 050 ) { 051 this.state = state; 052 this.files = files; 053 this.packageFragment = getOnlyPackageFragment(packageFqName); 054 packageParts = new PackageParts(packageFqName.asString()); 055 } 056 057 public void generate(@NotNull CompilationErrorHandler errorHandler) { 058 for (KtFile file : files) { 059 ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); 060 try { 061 generateFile(file); 062 } 063 catch (ProcessCanceledException e) { 064 throw e; 065 } 066 catch (Throwable e) { 067 VirtualFile vFile = file.getVirtualFile(); 068 errorHandler.reportException(e, vFile == null ? "no file" : vFile.getUrl()); 069 DiagnosticUtils.throwIfRunningOnServer(e); 070 if (ApplicationManager.getApplication().isInternal()) { 071 //noinspection CallToPrintStackTrace 072 e.printStackTrace(); 073 } 074 } 075 } 076 } 077 078 @Nullable 079 private ClassBuilder generateFile(@NotNull KtFile file) { 080 JvmFileClassInfo fileClassInfo = state.getFileClassesProvider().getFileClassInfo(file); 081 082 if (fileClassInfo.getWithJvmMultifileClass()) { 083 return null; 084 } 085 086 Type fileClassType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(fileClassInfo.getFileClassFqName()); 087 PackageContext packagePartContext = state.getRootContext().intoPackagePart(packageFragment, fileClassType, file); 088 089 boolean generatePackagePart = false; 090 091 for (KtDeclaration declaration : file.getDeclarations()) { 092 if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) { 093 generatePackagePart = true; 094 } 095 else if (declaration instanceof KtClassOrObject) { 096 KtClassOrObject classOrObject = (KtClassOrObject) declaration; 097 if (state.getGenerateDeclaredClassFilter().shouldGenerateClass(classOrObject)) { 098 generateClassOrObject(classOrObject, packagePartContext); 099 } 100 } 101 else if (declaration instanceof KtScript) { 102 KtScript script = (KtScript) declaration; 103 104 if (state.getGenerateDeclaredClassFilter().shouldGenerateScript(script)) { 105 ScriptCodegen.createScriptCodegen(script, state, packagePartContext).generate(); 106 } 107 } 108 } 109 110 if (!generatePackagePart || !state.getGenerateDeclaredClassFilter().shouldGeneratePackagePart(file)) return null; 111 112 String name = fileClassType.getInternalName(); 113 packageParts.getParts().add(name.substring(name.lastIndexOf('/') + 1)); 114 115 ClassBuilder builder = state.getFactory().newVisitor(JvmDeclarationOriginKt.PackagePart(file, packageFragment), fileClassType, file); 116 117 new PackagePartCodegen(builder, file, fileClassType, packagePartContext, state).generate(); 118 119 return builder; 120 } 121 122 @Nullable 123 private PackageFragmentDescriptor getOnlyPackageFragment(@NotNull FqName expectedPackageFqName) { 124 SmartList<PackageFragmentDescriptor> fragments = new SmartList<PackageFragmentDescriptor>(); 125 for (KtFile file : files) { 126 PackageFragmentDescriptor fragment = state.getBindingContext().get(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file); 127 assert fragment != null : "package fragment is null for " + file + "\n" + file.getText(); 128 129 assert expectedPackageFqName.equals(fragment.getFqName()) : 130 "expected package fq name: " + expectedPackageFqName + ", actual: " + fragment.getFqName(); 131 132 if (!fragments.contains(fragment)) { 133 fragments.add(fragment); 134 } 135 } 136 if (fragments.size() > 1) { 137 throw new IllegalStateException("More than one package fragment, files: " + files + " | fragments: " + fragments); 138 } 139 140 if (fragments.isEmpty()) { 141 return null; 142 } 143 return fragments.get(0); 144 } 145 146 public void generateClassOrObject(@NotNull KtClassOrObject classOrObject, @NotNull PackageContext packagePartContext) { 147 MemberCodegen.genClassOrObject(packagePartContext, classOrObject, state, null); 148 } 149 150 public PackageParts getPackageParts() { 151 return packageParts; 152 } 153 154 public Collection<KtFile> getFiles() { 155 return files; 156 } 157 158 public PackageFragmentDescriptor getPackageFragment() { 159 return packageFragment; 160 } 161 }