diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java index f710b325f74..75d09c4829e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/lang/KotlinBuiltIns.java @@ -58,25 +58,26 @@ public class KotlinBuiltIns { public static final Name UNIT_ALIAS = Name.identifier("Unit"); public static final JetScope STUB = JetScope.EMPTY; + public static final String BUILT_INS_DIR = "jet"; private static final String BUILT_INS_PACKAGE_NAME_STRING = "jet"; private static final Name BUILT_INS_PACKAGE_NAME = Name.identifier(BUILT_INS_PACKAGE_NAME_STRING); public static final FqName BUILT_INS_PACKAGE_FQ_NAME = FqName.topLevel(BUILT_INS_PACKAGE_NAME); private static final List LIBRARY_FILES = Arrays.asList( - "jet/Library.jet", - "jet/Numbers.jet", - "jet/Ranges.jet", - "jet/Iterables.jet", - "jet/Iterators.jet", - "jet/Arrays.jet", - "jet/Enum.jet", - "jet/Collections.jet", - "jet/Any.jet", - "jet/ExtensionFunctions.jet", - "jet/Functions.jet", - "jet/Nothing.jet", - "jet/Tuples.jet", - "jet/Unit.jet" + BUILT_INS_DIR + "/Library.jet", + BUILT_INS_DIR + "/Numbers.jet", + BUILT_INS_DIR + "/Ranges.jet", + BUILT_INS_DIR + "/Iterables.jet", + BUILT_INS_DIR + "/Iterators.jet", + BUILT_INS_DIR + "/Arrays.jet", + BUILT_INS_DIR + "/Enum.jet", + BUILT_INS_DIR + "/Collections.jet", + BUILT_INS_DIR + "/Any.jet", + BUILT_INS_DIR + "/ExtensionFunctions.jet", + BUILT_INS_DIR + "/Functions.jet", + BUILT_INS_DIR + "/Nothing.jet", + BUILT_INS_DIR + "/Tuples.jet", + BUILT_INS_DIR + "/Unit.jet" ); private static final Map ALIASES = ImmutableMap.builder() @@ -294,22 +295,11 @@ public class KotlinBuiltIns { return getBuiltInsPackage().getQualifiedName(); } - @NotNull - public Collection getAllBuiltInClasses() { - // TODO: used once, but incorrectly in JetShortNamesCache - return getBuiltInsScope().getAllDescriptors(); - } - @NotNull public JetScope getBuiltInsScope() { return getBuiltInsPackage().getMemberScope(); } - public boolean isStandardClass(@NotNull FqName fqName) { - // TODO: this seems to be wrong for ranges, and will certainly be wrong upon renaming jet -> kotlin - return getBuiltInsPackageFqName().equals(fqName.parent()); - } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // GET CLASS diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightClass.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightClass.java index eaa6a5e2ae0..e2c7296de29 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightClass.java +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/JetLightClass.java @@ -21,9 +21,12 @@ package org.jetbrains.jet.asJava; import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.SystemInfo; import com.intellij.psi.*; import com.intellij.psi.impl.PsiClassImplUtil; import com.intellij.psi.impl.java.stubs.PsiClassStub; @@ -50,13 +53,14 @@ import org.jetbrains.jet.lang.resolve.java.JetFilesProvider; import org.jetbrains.jet.lang.resolve.java.JetJavaMirrorMarker; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.name.FqName; -import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.plugin.JetLanguage; import javax.swing.*; import java.util.Collections; public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMarker { + private static final Logger LOG = Logger.getInstance(JetLightClass.class); + static class JetBadWrapperException extends RuntimeException { private final String context; @@ -92,8 +96,11 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa } @Nullable - public static JetLightClass create(PsiManager manager, JetFile file, FqName qualifiedName) { - return KotlinBuiltIns.getInstance().isStandardClass(qualifiedName) ? null : new JetLightClass(manager, file, qualifiedName); + public static JetLightClass create(@NotNull PsiManager manager, @NotNull JetFile file, @NotNull FqName qualifiedName) { + if (LightClassUtil.belongsToKotlinBuiltIns(file)) { + return null; + } + return new JetLightClass(manager, file, qualifiedName); } @Override @@ -167,6 +174,12 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa } private PsiJavaFileStub calcStub() { + if (LightClassUtil.belongsToKotlinBuiltIns(file)) { + // We may not fail later due to some luck, but generating JetLightClasses for built-ins is a bad idea anyways + // If it fails later, there will be an exception logged + logErrorWithOSInfo(null); + } + final PsiJavaFileStubImpl answer = new PsiJavaFileStubImpl(JetPsiUtil.getFQName(file).getFqName(), true); final Project project = getProject(); @@ -205,15 +218,32 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa throw new IllegalStateException("failed to analyze: " + context.getError(), context.getError()); } - final GenerationState state = new GenerationState(project, builderFactory, context, Collections.singletonList(file)); - final GenerationStrategy strategy = new LightClassGenerationStrategy(this, stubStack, answer); + try { + GenerationState state = new GenerationState(project, builderFactory, context, Collections.singletonList(file)); + GenerationStrategy strategy = new LightClassGenerationStrategy(this, stubStack, answer); - strategy.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); - state.getFactory().files(); + strategy.compileCorrectFiles(state, CompilationErrorHandler.THROW_EXCEPTION); + state.getFactory().files(); + } + catch (ProcessCanceledException e) { + throw e; + } + catch (RuntimeException e) { + logErrorWithOSInfo(e); + throw e; + } return answer; } + private void logErrorWithOSInfo(@Nullable Throwable cause) { + LOG.error( + "Could not generate JetLightClass for " + qualifiedName + " declared in " + file.getVirtualFile().getPath() + "\n" + + "built-ins dir URL is " + LightClassUtil.getBuiltInsDirResourceUrl() + "\n" + + "System: " + SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION + " Java Runtime: " + SystemInfo.JAVA_RUNTIME_VERSION, + cause); + } + @Override public boolean isEquivalentTo(PsiElement another) { return another instanceof PsiClass && Comparing.equal(((PsiClass)another).getQualifiedName(), getQualifiedName()); diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java new file mode 100644 index 00000000000..39da4d1a9ba --- /dev/null +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/LightClassUtil.java @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.asJava; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetFile; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; +import org.jetbrains.jet.utils.KotlinVfsUtil; + +import java.net.MalformedURLException; +import java.net.URL; + +public class LightClassUtil { + private static final Logger LOG = Logger.getInstance(JetLightClass.class); + private static final String DEFINITION_OF_ANY = "Any.jet"; + + /** + * Checks whether the given file is loaded from the location where Kotlin's built-in classes are defined. + * As of today, this is compiler/frontend/src/jet directory and files such as Any.jet, Nothing.jet etc. + * + * Used to skip JetLightClass creation for built-ins, because built-in classes have no Java counterparts + */ + public static boolean belongsToKotlinBuiltIns(@NotNull JetFile file) { + try { + String jetVfsPathUrl = KotlinVfsUtil.convertFromUrl(getBuiltInsDirResourceUrl()); + VirtualFile virtualFile = file.getVirtualFile(); + if (virtualFile != null) { + VirtualFile parent = virtualFile.getParent(); + if (parent != null) { + String fileDirVfsUrl = parent.getUrl() + "/" + DEFINITION_OF_ANY; + if (jetVfsPathUrl.equals(fileDirVfsUrl)) { + return true; + } + } + } + } + catch (MalformedURLException e) { + LOG.error(e); + } + // We deliberately return false on error: who knows what weird URLs we might come across out there + // it would be a pity if no light classes would be created in such cases + return false; + } + + @NotNull + public static URL getBuiltInsDirResourceUrl() { + String pathToAny = "/" + KotlinBuiltIns.BUILT_INS_DIR + "/" + DEFINITION_OF_ANY; + URL url = KotlinBuiltIns.class.getResource(pathToAny); + if (url == null) { + throw new IllegalStateException("Built-ins not found in the classpath: " + pathToAny); + } + return url; + } + + private LightClassUtil() {} +} diff --git a/compiler/util/src/org/jetbrains/jet/utils/KotlinVfsUtil.java b/compiler/util/src/org/jetbrains/jet/utils/KotlinVfsUtil.java new file mode 100644 index 00000000000..cc0e565ba17 --- /dev/null +++ b/compiler/util/src/org/jetbrains/jet/utils/KotlinVfsUtil.java @@ -0,0 +1,59 @@ +/* + * Copyright 2010-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.utils; + +import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.io.URLUtil; +import org.jetbrains.annotations.NotNull; + +import java.net.MalformedURLException; +import java.net.URL; + +/* + * This code is essentially copied from IntelliJ IDEA's VfsUtil, and slightly restructured + */ +public class KotlinVfsUtil { + private static final String FILE = "file"; + private static final String JAR = "jar"; + private static final String PROTOCOL_DELIMITER = ":"; + + @NotNull + public static String convertFromUrl(@NotNull URL url) throws MalformedURLException { + String protocol = url.getProtocol(); + String path = url.getPath(); + if (JAR.equals(protocol)) { + if (StringUtil.startsWithConcatenationOf(path, FILE, PROTOCOL_DELIMITER)) { + URL subURL = new URL(path); + path = subURL.getPath(); + } + else { + throw new MalformedURLException("Can't parse url: " + url.toExternalForm()); + } + } + if (SystemInfo.isWindows || SystemInfo.isOS2) { + while (path.length() > 0 && path.charAt(0) == '/') { + path = path.substring(1, path.length()); + } + } + + path = URLUtil.unescapePercentSequences(path); + return protocol + "://" + path; + } + + private KotlinVfsUtil() {} +}