EA-43573 - assert: KotlinJavaFileStubProvider$.generate
The problem was that KotlinJavaFileStubProvider instances remembered information that changed between their invocation: e.g. when a package gets renamed the qualified name in a java file stub does not get updated
This commit is contained in:
@@ -115,7 +115,7 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
|
||||
Collection<JetFile> filesForPackage = lightClassGenerationSupport.findFilesForPackage(qualifiedName, scope);
|
||||
|
||||
if (!filesForPackage.isEmpty() && NamespaceCodegen.shouldGenerateNSClass(filesForPackage)) {
|
||||
KotlinLightClassForPackage lightClass = KotlinLightClassForPackage.create(psiManager, qualifiedName, filesForPackage);
|
||||
KotlinLightClassForPackage lightClass = KotlinLightClassForPackage.create(psiManager, qualifiedName, scope, filesForPackage);
|
||||
if (lightClass != null) {
|
||||
answer.add(lightClass);
|
||||
|
||||
|
||||
+49
-21
@@ -28,6 +28,7 @@ import com.intellij.psi.impl.PsiManagerImpl;
|
||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
|
||||
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.stubs.PsiClassHolderFileStub;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
@@ -55,13 +56,28 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
|
||||
@NotNull
|
||||
public static KotlinJavaFileStubProvider createForPackageClass(
|
||||
@NotNull Project project,
|
||||
@NotNull final Project project,
|
||||
@NotNull final FqName packageFqName,
|
||||
@NotNull final Collection<JetFile> files
|
||||
@NotNull final GlobalSearchScope searchScope
|
||||
) {
|
||||
return new KotlinJavaFileStubProvider(project, packageFqName, files, new StubGenerationStrategy.NoDeclaredClasses() {
|
||||
return new KotlinJavaFileStubProvider(project, new StubGenerationStrategy.NoDeclaredClasses() {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public void generate(GenerationState state) {
|
||||
public Collection<JetFile> getFiles() {
|
||||
// Don't memoize this, it can be called again after an out-of-code-block modification occurs,
|
||||
// and the set of files changes
|
||||
return LightClassGenerationSupport.getInstance(project).findFilesForPackage(packageFqName, searchScope);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FqName getPackageFqName() {
|
||||
return packageFqName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
|
||||
NamespaceCodegen codegen = state.getFactory().forNamespace(packageFqName, files);
|
||||
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
|
||||
state.getFactory().files();
|
||||
@@ -73,16 +89,29 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
public static KotlinJavaFileStubProvider createForDeclaredTopLevelClass(
|
||||
@NotNull final JetClassOrObject classOrObject
|
||||
) {
|
||||
JetFile file = (JetFile) classOrObject.getContainingFile();
|
||||
assert classOrObject.getParent() == file : "Not a top-level class: " + classOrObject.getText();
|
||||
return new KotlinJavaFileStubProvider(classOrObject.getProject(), new StubGenerationStrategy.WithDeclaredClasses() {
|
||||
private JetFile getFile() {
|
||||
JetFile file = (JetFile) classOrObject.getContainingFile();
|
||||
assert classOrObject.getParent() == file : "Not a top-level class: " + classOrObject.getText();
|
||||
return file;
|
||||
}
|
||||
|
||||
final FqName packageFqName = JetPsiUtil.getFQName(file);
|
||||
|
||||
return new KotlinJavaFileStubProvider(classOrObject.getProject(), packageFqName, Collections.singletonList(file), new StubGenerationStrategy.WithDeclaredClasses() {
|
||||
@NotNull
|
||||
@Override
|
||||
public void generate(GenerationState state) {
|
||||
public Collection<JetFile> getFiles() {
|
||||
return Collections.singletonList(getFile());
|
||||
}
|
||||
|
||||
NamespaceCodegen namespaceCodegen = state.getFactory().forNamespace(packageFqName, state.getFiles());
|
||||
@NotNull
|
||||
@Override
|
||||
public FqName getPackageFqName() {
|
||||
return JetPsiUtil.getFQName(getFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
|
||||
FqName packageFqName = getPackageFqName();
|
||||
NamespaceCodegen namespaceCodegen = state.getFactory().forNamespace(packageFqName, files);
|
||||
NamespaceDescriptor namespaceDescriptor =
|
||||
state.getBindingContext().get(BindingContext.FQNAME_TO_NAMESPACE_DESCRIPTOR, packageFqName);
|
||||
assert namespaceDescriptor != null : "No package descriptor for " + packageFqName + " for class " + classOrObject.getText();
|
||||
@@ -95,19 +124,13 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
|
||||
private static final Logger LOG = Logger.getInstance(KotlinJavaFileStubProvider.class);
|
||||
|
||||
private final Collection<JetFile> files;
|
||||
private final FqName packageFqName;
|
||||
private final Project project;
|
||||
private final StubGenerationStrategy stubGenerationStrategy;
|
||||
|
||||
private KotlinJavaFileStubProvider(
|
||||
@NotNull Project project,
|
||||
@NotNull FqName packageFqName,
|
||||
@NotNull Collection<JetFile> files,
|
||||
@NotNull StubGenerationStrategy stubGenerationStrategy
|
||||
) {
|
||||
this.files = files;
|
||||
this.packageFqName = packageFqName;
|
||||
this.project = project;
|
||||
this.stubGenerationStrategy = stubGenerationStrategy;
|
||||
}
|
||||
@@ -115,6 +138,9 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<PsiJavaFileStub> compute() {
|
||||
FqName packageFqName = stubGenerationStrategy.getPackageFqName();
|
||||
Collection<JetFile> files = stubGenerationStrategy.getFiles();
|
||||
|
||||
checkForBuiltIns(packageFqName, files);
|
||||
|
||||
LightClassConstructionContext context = LightClassGenerationSupport.getInstance(project).analyzeRelevantCode(files);
|
||||
@@ -124,7 +150,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
throw new IllegalStateException("failed to analyze: " + error, error);
|
||||
}
|
||||
|
||||
PsiJavaFileStub javaFileStub = createJavaFileStub(getRepresentativeVirtualFile(files));
|
||||
PsiJavaFileStub javaFileStub = createJavaFileStub(packageFqName, getRepresentativeVirtualFile(files));
|
||||
try {
|
||||
Stack<StubElement> stubStack = new Stack<StubElement>();
|
||||
stubStack.push(javaFileStub);
|
||||
@@ -140,7 +166,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
/*generateDeclaredClasses=*/stubGenerationStrategy.generateDeclaredClasses());
|
||||
state.beforeCompile();
|
||||
|
||||
stubGenerationStrategy.generate(state);
|
||||
stubGenerationStrategy.generate(state, files);
|
||||
|
||||
StubElement pop = stubStack.pop();
|
||||
if (pop != javaFileStub) {
|
||||
@@ -160,7 +186,7 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiJavaFileStub createJavaFileStub(VirtualFile virtualFile) {
|
||||
private PsiJavaFileStub createJavaFileStub(@NotNull final FqName packageFqName, @NotNull VirtualFile virtualFile) {
|
||||
PsiManager manager = PsiManager.getInstance(project);
|
||||
|
||||
final PsiJavaFileStubImpl javaFileStub = new PsiJavaFileStubImpl(packageFqName.getFqName(), true);
|
||||
@@ -214,8 +240,10 @@ public class KotlinJavaFileStubProvider implements CachedValueProvider<PsiJavaFi
|
||||
}
|
||||
|
||||
private interface StubGenerationStrategy {
|
||||
@NotNull Collection<JetFile> getFiles();
|
||||
@NotNull FqName getPackageFqName();
|
||||
boolean generateDeclaredClasses();
|
||||
void generate(GenerationState state);
|
||||
void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files);
|
||||
|
||||
abstract class NoDeclaredClasses implements StubGenerationStrategy {
|
||||
@Override
|
||||
|
||||
+18
-5
@@ -24,6 +24,7 @@ import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValue;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -38,27 +39,39 @@ import java.util.Collection;
|
||||
|
||||
public class KotlinLightClassForPackage extends KotlinLightClassForPackageBase implements KotlinLightClass, JetJavaMirrorMarker {
|
||||
@Nullable
|
||||
public static KotlinLightClassForPackage create(@NotNull PsiManager manager, @NotNull FqName qualifiedName, @NotNull Collection<JetFile> files) {
|
||||
public static KotlinLightClassForPackage create(
|
||||
@NotNull PsiManager manager,
|
||||
@NotNull FqName qualifiedName,
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull Collection<JetFile> files // this is redundant, but computing it multiple times is costly
|
||||
) {
|
||||
for (JetFile file : files) {
|
||||
if (LightClassUtil.belongsToKotlinBuiltIns(file)) return null;
|
||||
}
|
||||
return new KotlinLightClassForPackage(manager, qualifiedName, files);
|
||||
return new KotlinLightClassForPackage(manager, qualifiedName, searchScope, files);
|
||||
}
|
||||
|
||||
private final FqName packageFqName;
|
||||
private final FqName packageClassFqName; // derived from packageFqName
|
||||
private final GlobalSearchScope searchScope;
|
||||
private final Collection<JetFile> files;
|
||||
private final int hashCode;
|
||||
private final CachedValue<PsiJavaFileStub> javaFileStub;
|
||||
|
||||
private KotlinLightClassForPackage(@NotNull PsiManager manager, @NotNull FqName packageFqName, @NotNull Collection<JetFile> files) {
|
||||
private KotlinLightClassForPackage(
|
||||
@NotNull PsiManager manager,
|
||||
@NotNull FqName packageFqName,
|
||||
@NotNull GlobalSearchScope searchScope,
|
||||
@NotNull Collection<JetFile> files
|
||||
) {
|
||||
super(manager);
|
||||
this.packageFqName = packageFqName;
|
||||
this.packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName);
|
||||
this.searchScope = searchScope;
|
||||
assert !files.isEmpty() : "No files for package " + packageFqName;
|
||||
this.files = Sets.newHashSet(files); // needed for hashCode
|
||||
this.hashCode = computeHashCode();
|
||||
KotlinJavaFileStubProvider stubProvider = KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, files);
|
||||
KotlinJavaFileStubProvider stubProvider = KotlinJavaFileStubProvider.createForPackageClass(getProject(), packageFqName, searchScope);
|
||||
this.javaFileStub = CachedValuesManager.getManager(getProject()).createCachedValue(stubProvider, /*trackValue = */false);
|
||||
}
|
||||
|
||||
@@ -95,7 +108,7 @@ public class KotlinLightClassForPackage extends KotlinLightClassForPackageBase i
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement copy() {
|
||||
return new KotlinLightClassForPackage(getManager(), packageFqName, files);
|
||||
return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user