Prohibit creation of JetLightClass on built-ins

If we allow JetLightClass to be created on built-in types, a normal codegen
would be launched, with a mapping from Kotlin to Java types enabled, every time
IDE requests built-in classes. Codegen would then try to make something
meaningless, e.g. create a class for a primitive type (since our jet.Boolean is
mapped to primitive boolean). This would result in different exceptions when
navigating to built-in library from IDE.

Add a helpful error message to ClassFileFactory if we ever again produce
classes for primitive types.
This commit is contained in:
Alexander Udalov
2012-09-11 16:03:33 +04:00
parent 4eea0cafb9
commit bb92655ecd
11 changed files with 129 additions and 39 deletions
@@ -17,6 +17,7 @@
package org.jetbrains.jet.codegen;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.asm4.Type;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStateAware;
import org.jetbrains.jet.codegen.state.JetTypeMapperMode;
@@ -112,8 +113,11 @@ public final class ClassFileFactory extends GenerationStateAware {
}
public ClassBuilder forClassImplementation(ClassDescriptor aClass) {
return newVisitor(
state.getTypeMapper().mapType(aClass.getDefaultType(), JetTypeMapperMode.IMPL).getInternalName() + ".class");
Type type = state.getTypeMapper().mapType(aClass.getDefaultType(), JetTypeMapperMode.IMPL);
if (CodegenUtil.isPrimitive(type)) {
throw new IllegalStateException("Codegen for primitive type is not possible: " + aClass);
}
return newVisitor(type.getInternalName() + ".class");
}
public ClassBuilder forNamespacepart(String name) {
@@ -542,4 +542,13 @@ public class JetStandardClasses {
public static Collection<DeclarationDescriptor> getAllStandardClasses() {
return STANDARD_CLASSES.getAllDescriptors();
}
public static boolean isStandardClass(@NotNull FqName fqName) {
for (DeclarationDescriptor descriptor : getAllStandardClasses()) {
if (DescriptorUtils.getFQName(descriptor).equals(fqName.toUnsafe())) {
return true;
}
}
return false;
}
}
@@ -118,7 +118,10 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
if (packageName != null && qualifiedName.getFqName().startsWith(packageName.getFqName())) {
if (qualifiedName.equals(QualifiedNamesUtil.combine(packageName, Name.identifier(JvmAbi.PACKAGE_CLASS))) &&
NamespaceCodegen.shouldGenerateNSClass(Arrays.asList(file))) {
answer.add(new JetLightClass(psiManager, file, qualifiedName));
JetLightClass lightClass = JetLightClass.create(psiManager, file, qualifiedName);
if (lightClass != null) {
answer.add(lightClass);
}
}
else {
for (JetDeclaration declaration : file.getDeclarations()) {
@@ -137,7 +140,10 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
FqName fqn = QualifiedNamesUtil.combine(containerFqn, Name.identifier(localName));
if (qualifiedName.equals(fqn)) {
if (!(declaration instanceof JetEnumEntry)) {
answer.add(new JetLightClass(psiManager, file, qualifiedName));
JetLightClass lightClass = JetLightClass.create(psiManager, file, qualifiedName);
if (lightClass != null) {
answer.add(lightClass);
}
}
}
else if (QualifiedNamesUtil.isSubpackageOf(qualifiedName, fqn)) {
@@ -231,12 +237,20 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
for (JetFile file : filesInScope) {
if (packageFQN.equals(JetPsiUtil.getFQName(file))) {
answer.add(new JetLightClass(psiManager, file, QualifiedNamesUtil.combine(packageFQN, Name.identifier(JvmAbi.PACKAGE_CLASS))));
JetLightClass lightClass = JetLightClass
.create(psiManager, file, QualifiedNamesUtil.combine(packageFQN, Name.identifier(JvmAbi.PACKAGE_CLASS)));
if (lightClass != null) {
answer.add(lightClass);
}
for (JetDeclaration declaration : file.getDeclarations()) {
if (declaration instanceof JetClassOrObject) {
String localName = getLocalName(declaration);
if (localName != null) {
answer.add(new JetLightClass(psiManager, file, QualifiedNamesUtil.combine(packageFQN, Name.identifier(localName))));
JetLightClass aClass = JetLightClass.create(psiManager, file,
QualifiedNamesUtil.combine(packageFQN, Name.identifier(localName)));
if (aClass != null) {
answer.add(aClass);
}
}
}
}
@@ -21,7 +21,6 @@ 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.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
@@ -36,8 +35,12 @@ import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.*;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.analyzer.AnalyzeExhaust;
import org.jetbrains.jet.codegen.*;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.GenerationStrategy;
import org.jetbrains.jet.lang.BuiltinsScopeExtensionMode;
@@ -49,6 +52,7 @@ import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
import org.jetbrains.jet.lang.resolve.java.JetFilesProvider;
import org.jetbrains.jet.lang.resolve.java.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
import org.jetbrains.jet.plugin.JetLanguage;
import javax.swing.*;
@@ -61,20 +65,28 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
private final FqName qualifiedName;
private PsiClass delegate;
public JetLightClass(PsiManager manager, JetFile file, FqName qualifiedName) {
private JetLightClass(PsiManager manager, JetFile file, FqName qualifiedName) {
super(manager, JetLanguage.INSTANCE);
this.file = file;
this.qualifiedName = qualifiedName;
}
@Nullable
public static JetLightClass create(PsiManager manager, JetFile file, FqName qualifiedName) {
return JetStandardClasses.isStandardClass(qualifiedName) ? null : new JetLightClass(manager, file, qualifiedName);
}
@Override
public String getName() {
return qualifiedName.shortName().getName();
}
@NotNull
@Override
public PsiElement copy() {
return new JetLightClass(getManager(), file, qualifiedName);
JetLightClass result = create(getManager(), file, qualifiedName);
assert result != null;
return result;
}
@NotNull
@@ -233,13 +245,20 @@ public class JetLightClass extends AbstractLightClass implements JetJavaMirrorMa
return true;
}
@Nullable
public static JetLightClass wrapDelegate(JetClass jetClass) {
return new JetLightClass(jetClass.getManager(), (JetFile) jetClass.getContainingFile(), JetPsiUtil.getFQName(jetClass));
if (jetClass == null) return null;
return create(jetClass.getManager(), (JetFile) jetClass.getContainingFile(), JetPsiUtil.getFQName(jetClass));
}
@Nullable
public static PsiMethod wrapMethod(JetFunction function) {
JetClass containingClass = PsiTreeUtil.getParentOfType(function, JetClass.class);
JetLightClass wrapper = wrapDelegate(containingClass);
if (wrapper == null) {
return null;
}
for (PsiMethod method : wrapper.getMethods()) {
if (method instanceof PsiCompiledElement && ((PsiCompiledElement) method).getMirror() == function) {
return method;
@@ -82,8 +82,11 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
return null;
}
}
final PsiClass lightClass = JetLightClass.wrapDelegate((JetClass) element).getDelegate();
final PsiElement[] children = lightClass.getChildren();
JetLightClass lightClass = JetLightClass.wrapDelegate((JetClass) element);
if (lightClass == null) {
return null;
}
final PsiElement[] children = lightClass.getDelegate().getChildren();
return children.length > 0 ? children[0] : null;
}
@@ -251,7 +254,11 @@ public class JetLineMarkerProvider implements LineMarkerProvider {
if (!element.hasModifier(JetTokens.OPEN_KEYWORD)) {
return;
}
PsiClass inheritor = ClassInheritorsSearch.search(JetLightClass.wrapDelegate(element), false).findFirst();
JetLightClass lightClass = JetLightClass.wrapDelegate(element);
if (lightClass == null) {
return;
}
PsiClass inheritor = ClassInheritorsSearch.search(lightClass, false).findFirst();
if (inheritor != null) {
final PsiElement nameIdentifier = element.getNameIdentifier();
PsiElement anchor = nameIdentifier != null ? nameIdentifier : element;
@@ -68,24 +68,25 @@ public class JetJUnitConfigurationProducer extends RuntimeConfigurationProducer
if (owner instanceof JetClass) {
JetLightClass delegate = JetLightClass.wrapDelegate((JetClass) owner);
for (PsiMethod method : delegate.getMethods()) {
if (method.getNavigationElement() == function) {
Location<PsiMethod> methodLocation = PsiLocation.fromPsiElement(method);
if (JUnitUtil.isTestMethod(methodLocation, false)) {
RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(context.getProject(), context);
final JUnitConfiguration configuration = (JUnitConfiguration) settings.getConfiguration();
if (delegate != null) {
for (PsiMethod method : delegate.getMethods()) {
if (method.getNavigationElement() == function) {
Location<PsiMethod> methodLocation = PsiLocation.fromPsiElement(method);
if (JUnitUtil.isTestMethod(methodLocation, false)) {
RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(context.getProject(), context);
final JUnitConfiguration configuration = (JUnitConfiguration) settings.getConfiguration();
final Module originalModule = configuration.getConfigurationModule().getModule();
configuration.beMethodConfiguration(methodLocation);
configuration.restoreOriginalModule(originalModule);
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location);
final Module originalModule = configuration.getConfigurationModule().getModule();
configuration.beMethodConfiguration(methodLocation);
configuration.restoreOriginalModule(originalModule);
JavaRunConfigurationExtensionManager.getInstance().extendCreatedConfiguration(configuration, location);
return settings;
return settings;
}
break;
}
break;
}
}
}
}
@@ -99,7 +100,7 @@ public class JetJUnitConfigurationProducer extends RuntimeConfigurationProducer
myElement = jetClass;
PsiClass delegate = JetLightClass.wrapDelegate(jetClass);
if (JUnitUtil.isTestClass(delegate)) {
if (delegate != null && JUnitUtil.isTestClass(delegate)) {
RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(context.getProject(), context);
final JUnitConfiguration configuration = (JUnitConfiguration) settings.getConfiguration();
@@ -42,12 +42,14 @@ public class KotlinDefinitionsSearcher extends QueryExecutorBase<PsiElement, Psi
}
});
Query<PsiClass> query = ClassInheritorsSearch.search(psiClass, true);
query.forEach(new Processor<PsiClass>() {
@Override
public boolean process(final PsiClass clazz) {
return consumer.process(clazz);
}
});
if (psiClass != null) {
query.forEach(new Processor<PsiClass>() {
@Override
public boolean process(final PsiClass clazz) {
return consumer.process(clazz);
}
});
}
}
}
}
@@ -82,7 +82,10 @@ public class KotlinDirectInheritorsSearcher extends QueryExecutorBase<PsiClass,
}
if (qualifiedName.equals(resolvedFQName)) {
consumer.process(JetLightClass.wrapDelegate((JetClass) candidate));
JetLightClass lightClass = JetLightClass.wrapDelegate((JetClass) candidate);
if (lightClass != null) {
consumer.process(lightClass);
}
}
}
}
@@ -40,8 +40,10 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
if (element instanceof JetClass) {
String className = ((JetClass) element).getName();
if (className != null) {
queryParameters.getOptimizer().searchWord(className, queryParameters.getScope(),
true, JetLightClass.wrapDelegate((JetClass) element));
JetLightClass lightClass = JetLightClass.wrapDelegate((JetClass) element);
if (lightClass != null) {
queryParameters.getOptimizer().searchWord(className, queryParameters.getScope(), true, lightClass);
}
}
}
else if (element instanceof JetFunction) {
@@ -55,8 +57,10 @@ public class KotlinReferencesSearcher extends QueryExecutorBase<PsiReference, Re
}
});
if (method != null) {
queryParameters.getOptimizer().searchWord(name, queryParameters.getScope(),
true, JetLightClass.wrapMethod((JetFunction) element));
PsiMethod target = JetLightClass.wrapMethod((JetFunction) element);
if (target != null) {
queryParameters.getOptimizer().searchWord(name, queryParameters.getScope(), true, target);
}
}
}
@@ -0,0 +1,3 @@
class A {
val x: <caret>Int = 42
}
@@ -21,6 +21,12 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.testFramework.LightProjectDescriptor;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.asJava.JetLightClass;
import org.jetbrains.jet.lang.psi.JetClass;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.plugin.JetLightProjectDescriptor;
import org.jetbrains.jet.plugin.PluginTestCaseBase;
@@ -74,4 +80,22 @@ public class JetJavaFacadeTest extends LightCodeInsightFixtureTestCase {
assertEquals("java.io.PrintStream", methods[0].getReturnType().getCanonicalText());
}
public void testLightClassIsNotCreatedForBuiltins() throws Exception {
myFixture.configureByFile(getTestName(true) + ".kt");
PsiReference reference = myFixture.getFile().findReferenceAt(myFixture.getCaretOffset());
assert reference != null;
PsiElement element = reference.resolve();
assertInstanceOf(element, JetClass.class);
JetClass aClass = (JetClass) element;
JetLightClass createdByWrapDelegate = JetLightClass.wrapDelegate(aClass);
assertNull(createdByWrapDelegate);
JetLightClass createdByFactory = JetLightClass.create(element.getManager(),
(JetFile) element.getContainingFile(),
JetPsiUtil.getFQName(aClass));
assertNull(createdByFactory);
}
}