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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user