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 017package org.jetbrains.jet.cli.jvm.compiler; 018 019import com.intellij.codeInsight.ExternalAnnotationsManager; 020import com.intellij.core.CoreApplicationEnvironment; 021import com.intellij.core.CoreJavaFileManager; 022import com.intellij.core.JavaCoreApplicationEnvironment; 023import com.intellij.core.JavaCoreProjectEnvironment; 024import com.intellij.lang.java.JavaParserDefinition; 025import com.intellij.mock.MockApplication; 026import com.intellij.mock.MockProject; 027import com.intellij.openapi.Disposable; 028import com.intellij.openapi.components.ServiceManager; 029import com.intellij.openapi.extensions.Extensions; 030import com.intellij.openapi.fileTypes.PlainTextFileType; 031import com.intellij.openapi.project.Project; 032import com.intellij.openapi.vfs.VirtualFile; 033import com.intellij.psi.PsiElementFinder; 034import com.intellij.psi.PsiFile; 035import com.intellij.psi.PsiManager; 036import com.intellij.psi.impl.compiled.ClsCustomNavigationPolicy; 037import com.intellij.psi.impl.file.impl.JavaFileManager; 038import org.jetbrains.annotations.NotNull; 039import org.jetbrains.jet.CompilerModeProvider; 040import org.jetbrains.jet.OperationModeProvider; 041import org.jetbrains.jet.asJava.JavaElementFinder; 042import org.jetbrains.jet.asJava.LightClassGenerationSupport; 043import org.jetbrains.jet.cli.common.CLIConfigurationKeys; 044import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation; 045import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity; 046import org.jetbrains.jet.cli.common.messages.MessageCollector; 047import org.jetbrains.jet.cli.jvm.JVMConfigurationKeys; 048import org.jetbrains.jet.config.CommonConfigurationKeys; 049import org.jetbrains.jet.config.CompilerConfiguration; 050import org.jetbrains.jet.lang.parsing.JetParserDefinition; 051import org.jetbrains.jet.lang.parsing.JetScriptDefinitionProvider; 052import org.jetbrains.jet.lang.psi.JetFile; 053import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; 054import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 055import org.jetbrains.jet.plugin.JetFileType; 056import org.jetbrains.jet.utils.PathUtil; 057 058import java.io.File; 059import java.util.ArrayList; 060import java.util.List; 061 062import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.ERROR; 063import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.WARNING; 064 065public class JetCoreEnvironment { 066 067 private final JavaCoreApplicationEnvironment applicationEnvironment; 068 private final JavaCoreProjectEnvironment projectEnvironment; 069 private final List<JetFile> sourceFiles = new ArrayList<JetFile>(); 070 071 private final CoreExternalAnnotationsManager annotationsManager; 072 073 private final CompilerConfiguration configuration; 074 075 public JetCoreEnvironment(Disposable parentDisposable, @NotNull CompilerConfiguration configuration) { 076 this.configuration = configuration.copy(); 077 this.configuration.setReadOnly(true); 078 079 this.applicationEnvironment = new JavaCoreApplicationEnvironment(parentDisposable); 080 081 // ability to get text from annotations xml files 082 applicationEnvironment.registerFileType(PlainTextFileType.INSTANCE, "xml"); 083 084 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kt"); 085 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "kts"); 086 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "ktm"); 087 applicationEnvironment.registerFileType(JetFileType.INSTANCE, JetParserDefinition.KTSCRIPT_FILE_SUFFIX); // should be renamed to kts 088 applicationEnvironment.registerFileType(JetFileType.INSTANCE, "jet"); 089 applicationEnvironment.registerParserDefinition(new JavaParserDefinition()); 090 applicationEnvironment.registerParserDefinition(new JetParserDefinition()); 091 092 applicationEnvironment.getApplication().registerService(OperationModeProvider.class, new CompilerModeProvider()); 093 094 projectEnvironment = new JavaCoreProjectEnvironment(parentDisposable, applicationEnvironment); 095 096 MockProject project = projectEnvironment.getProject(); 097 project.registerService(JetScriptDefinitionProvider.class, new JetScriptDefinitionProvider()); 098 project.registerService(JetFilesProvider.class, new CliJetFilesProvider(this)); 099 project.registerService(CoreJavaFileManager.class, (CoreJavaFileManager) ServiceManager.getService(project, JavaFileManager.class)); 100 101 CliLightClassGenerationSupport cliLightClassGenerationSupport = new CliLightClassGenerationSupport(); 102 project.registerService(LightClassGenerationSupport.class, cliLightClassGenerationSupport); 103 project.registerService(CliLightClassGenerationSupport.class, cliLightClassGenerationSupport); 104 105 Extensions.getArea(project) 106 .getExtensionPoint(PsiElementFinder.EP_NAME) 107 .registerExtension(new JavaElementFinder(project, cliLightClassGenerationSupport)); 108 109 // This extension point should be registered in JavaCoreApplicationEnvironment 110 CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), ClsCustomNavigationPolicy.EP_NAME, 111 ClsCustomNavigationPolicy.class); 112 113 annotationsManager = new CoreExternalAnnotationsManager(project.getComponent(PsiManager.class)); 114 project.registerService(ExternalAnnotationsManager.class, annotationsManager); 115 116 for (File path : configuration.getList(JVMConfigurationKeys.CLASSPATH_KEY)) { 117 addToClasspath(path); 118 } 119 for (File path : configuration.getList(JVMConfigurationKeys.ANNOTATIONS_PATH_KEY)) { 120 addExternalAnnotationsRoot(path); 121 } 122 for (String path : configuration.getList(CommonConfigurationKeys.SOURCE_ROOTS_KEY)) { 123 addSources(path); 124 } 125 126 JetScriptDefinitionProvider.getInstance(project).addScriptDefinitions(configuration.getList(CommonConfigurationKeys.SCRIPT_DEFINITIONS_KEY)); 127 128 KotlinBuiltIns.initialize(project, KotlinBuiltIns.InitializationMode.SINGLE_THREADED); 129 } 130 131 public CompilerConfiguration getConfiguration() { 132 return configuration; 133 } 134 135 @NotNull 136 public MockApplication getApplication() { 137 return applicationEnvironment.getApplication(); 138 } 139 140 @NotNull 141 public Project getProject() { 142 return projectEnvironment.getProject(); 143 } 144 145 private void addExternalAnnotationsRoot(File path) { 146 if (!path.exists()) { 147 report(WARNING, "Annotations path entry points to a non-existent location: " + path); 148 return; 149 } 150 annotationsManager.addExternalAnnotationsRoot(PathUtil.jarFileOrDirectoryToVirtualFile(path)); 151 } 152 153 private void addSources(File file) { 154 if (file.isDirectory()) { 155 File[] files = file.listFiles(); 156 if (files != null) { 157 for (File child : files) { 158 addSources(child); 159 } 160 } 161 } 162 else { 163 VirtualFile fileByPath = applicationEnvironment.getLocalFileSystem().findFileByPath(file.getAbsolutePath()); 164 if (fileByPath != null) { 165 PsiFile psiFile = PsiManager.getInstance(getProject()).findFile(fileByPath); 166 if (psiFile instanceof JetFile) { 167 sourceFiles.add((JetFile) psiFile); 168 } 169 } 170 } 171 } 172 173 private void addSources(String path) { 174 if (path == null) { 175 return; 176 } 177 178 VirtualFile vFile = applicationEnvironment.getLocalFileSystem().findFileByPath(path); 179 if (vFile == null) { 180 report(ERROR, "Source file or directory not found: " + path); 181 return; 182 } 183 if (!vFile.isDirectory() && vFile.getFileType() != JetFileType.INSTANCE) { 184 report(ERROR, "Source entry is not a Kotlin file: " + path); 185 return; 186 } 187 188 addSources(new File(path)); 189 } 190 191 private void addToClasspath(File path) { 192 if (path.isFile()) { 193 VirtualFile jarFile = applicationEnvironment.getJarFileSystem().findFileByPath(path + "!/"); 194 if (jarFile == null) { 195 report(WARNING, "Classpath entry points to a file that is not a JAR archive: " + path); 196 return; 197 } 198 projectEnvironment.addJarToClassPath(path); 199 } 200 else { 201 VirtualFile root = applicationEnvironment.getLocalFileSystem().findFileByPath(path.getAbsolutePath()); 202 if (root == null) { 203 report(WARNING, "Classpath entry points to a non-existent location: " + path); 204 return; 205 } 206 projectEnvironment.addSourcesToClasspath(root); 207 } 208 } 209 210 public List<JetFile> getSourceFiles() { 211 return sourceFiles; 212 } 213 214 private void report(@NotNull CompilerMessageSeverity severity, @NotNull String message) { 215 MessageCollector messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY); 216 if (messageCollector != null) { 217 messageCollector.report(severity, message, CompilerMessageLocation.NO_LOCATION); 218 } 219 else { 220 throw new CompileEnvironmentException(message); 221 } 222 } 223}