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:
Andrey Breslav
2013-04-01 13:09:22 +04:00
parent d57003dece
commit ffeb73beb5
3 changed files with 68 additions and 27 deletions
@@ -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);
@@ -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
@@ -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