mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
composite stub index
GitOrigin-RevId: cbbd49521d0a322f6b5678668ca53b3ce24660d2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
40466bc42f
commit
5e4e1a1515
@@ -6,21 +6,24 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.compiled.ClassFileDecompilers;
|
||||
import com.intellij.psi.stubs.BinaryFileStubBuilder;
|
||||
import com.intellij.psi.stubs.PsiFileStub;
|
||||
import com.intellij.psi.stubs.StubElement;
|
||||
import com.intellij.psi.stubs.Stub;
|
||||
import com.intellij.util.cls.ClsFormatException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileContent;
|
||||
import com.intellij.util.indexing.InvertedIndex;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.intellij.psi.compiled.ClassFileDecompilers.Full;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
*/
|
||||
public class ClassFileStubBuilder implements BinaryFileStubBuilder {
|
||||
public class ClassFileStubBuilder implements BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<ClassFileDecompilers.Decompiler> {
|
||||
private static final Logger LOG = Logger.getInstance(ClassFileStubBuilder.class);
|
||||
|
||||
public static final int STUB_VERSION = 23;
|
||||
@@ -30,41 +33,47 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StubElement buildStubTree(@NotNull FileContent fileContent) {
|
||||
VirtualFile file = fileContent.getFile();
|
||||
byte[] content = fileContent.getContent();
|
||||
public ClassFileDecompilers.Decompiler getSubBuilder(@NotNull FileContent fileContent) {
|
||||
return setContentAndCompute(fileContent, () -> ClassFileDecompilers.find(fileContent.getFile()));
|
||||
}
|
||||
|
||||
try {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSubBuilderVersion(@Nullable ClassFileDecompilers.Decompiler decompiler) {
|
||||
if (decompiler == null) return "default";
|
||||
int version = decompiler instanceof Full ? ((Full)decompiler).getStubBuilder().getStubVersion() : 0;
|
||||
return decompiler.getClass().getName() + ":" + version;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Stub buildStubTree(@NotNull FileContent fileContent, @Nullable ClassFileDecompilers.Decompiler decompiler) {
|
||||
return setContentAndCompute(fileContent, () -> {
|
||||
VirtualFile file = fileContent.getFile();
|
||||
try {
|
||||
file.setPreloadedContentHint(content);
|
||||
ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.find(file);
|
||||
if (decompiler instanceof Full) {
|
||||
return ((Full)decompiler).getStubBuilder().buildFileStub(fileContent);
|
||||
return ((Full) decompiler).getStubBuilder().buildFileStub(fileContent);
|
||||
}
|
||||
}
|
||||
catch (ClsFormatException e) {
|
||||
} catch (ClsFormatException e) {
|
||||
if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e);
|
||||
else LOG.info(file.getPath() + ": " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
PsiFileStub<?> stub = ClsFileImpl.buildFileStub(file, content);
|
||||
PsiFileStub<?> stub = ClsFileImpl.buildFileStub(file, fileContent.getContent());
|
||||
if (stub == null && fileContent.getFileName().indexOf('$') < 0) {
|
||||
LOG.info("No stub built for the file " + fileContent);
|
||||
}
|
||||
return stub;
|
||||
}
|
||||
catch (ClsFormatException e) {
|
||||
} catch (ClsFormatException e) {
|
||||
if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e);
|
||||
else LOG.info(file.getPath() + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
file.setPreloadedContentHint(null);
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private static final Comparator<Object> CLASS_NAME_COMPARATOR = Comparator.comparing(o -> o.getClass().getName());
|
||||
@@ -73,14 +82,25 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder {
|
||||
public int getStubVersion() {
|
||||
int version = STUB_VERSION;
|
||||
|
||||
List<ClassFileDecompilers.Decompiler> decompilers = ContainerUtil.newArrayList(ClassFileDecompilers.EP_NAME.getExtensions());
|
||||
decompilers.sort(CLASS_NAME_COMPARATOR);
|
||||
for (ClassFileDecompilers.Decompiler decompiler : decompilers) {
|
||||
if (decompiler instanceof Full) {
|
||||
version = version * 31 + ((Full)decompiler).getStubBuilder().getStubVersion() + decompiler.getClass().getName().hashCode();
|
||||
if (!InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED) {
|
||||
List<ClassFileDecompilers.Decompiler> decompilers = ContainerUtil.newArrayList(ClassFileDecompilers.EP_NAME.getExtensions());
|
||||
decompilers.sort(CLASS_NAME_COMPARATOR);
|
||||
for (ClassFileDecompilers.Decompiler decompiler : decompilers) {
|
||||
if (decompiler instanceof Full) {
|
||||
version = version * 31 + ((Full)decompiler).getStubBuilder().getStubVersion() + decompiler.getClass().getName().hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
private static <T> T setContentAndCompute(@NotNull FileContent content, @NotNull Supplier<T> computation) {
|
||||
try {
|
||||
content.getFile().setPreloadedContentHint(content.getContent());
|
||||
return computation.get();
|
||||
} finally {
|
||||
content.getFile().setPreloadedContentHint(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,4 +31,21 @@ public interface BinaryFileStubBuilder {
|
||||
Stub buildStubTree(@NotNull FileContent fileContent);
|
||||
|
||||
int getStubVersion();
|
||||
|
||||
interface CompositeBinaryFileStubBuilder<SubBuilder> extends BinaryFileStubBuilder {
|
||||
@Nullable
|
||||
SubBuilder getSubBuilder(@NotNull FileContent fileContent);
|
||||
|
||||
@NotNull
|
||||
String getSubBuilderVersion(@Nullable SubBuilder subBuilder);
|
||||
|
||||
@Nullable
|
||||
Stub buildStubTree(@NotNull FileContent fileContent, @Nullable SubBuilder builder);
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
default Stub buildStubTree(@NotNull FileContent fileContent) {
|
||||
return buildStubTree(fileContent, getSubBuilder(fileContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.psi.stubs;
|
||||
|
||||
import com.intellij.diagnostic.PluginException;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.templateLanguages.TemplateLanguage;
|
||||
import com.intellij.psi.tree.IStubFileElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
class StubBuilderType {
|
||||
private static final Logger LOG = Logger.getInstance(StubBuilderType.class);
|
||||
private final IStubFileElementType myElementType;
|
||||
private final BinaryFileStubBuilder myBinaryFileStubBuilder;
|
||||
private final Object myBinarySubBuilder;
|
||||
|
||||
StubBuilderType(@NotNull IStubFileElementType elementType) {
|
||||
myElementType = elementType;
|
||||
myBinaryFileStubBuilder = null;
|
||||
myBinarySubBuilder = null;
|
||||
}
|
||||
|
||||
StubBuilderType(@NotNull BinaryFileStubBuilder binaryFileStubBuilder) {
|
||||
myElementType = null;
|
||||
myBinaryFileStubBuilder = binaryFileStubBuilder;
|
||||
myBinarySubBuilder = null;
|
||||
}
|
||||
|
||||
StubBuilderType(@NotNull BinaryFileStubBuilder.CompositeBinaryFileStubBuilder binaryFileStubBuilder,
|
||||
@Nullable Object binarySubBuilder) {
|
||||
myElementType = null;
|
||||
myBinaryFileStubBuilder = binaryFileStubBuilder;
|
||||
myBinarySubBuilder = binarySubBuilder;
|
||||
}
|
||||
|
||||
BinaryFileStubBuilder getBinaryFileStubBuilder() {
|
||||
return myBinaryFileStubBuilder;
|
||||
}
|
||||
|
||||
String getVersion() {
|
||||
if (myElementType != null) {
|
||||
if (myElementType.getLanguage() instanceof TemplateLanguage &&
|
||||
myElementType.getStubVersion() < IStubFileElementType.getTemplateStubVersion()) {
|
||||
PluginException.logPluginError(LOG, myElementType.getLanguage() + " stub version should call super.getStubVersion()",
|
||||
null, myElementType.getClass());
|
||||
}
|
||||
return myElementType.getClass().getName() + ":" + myElementType.getStubVersion();
|
||||
} else {
|
||||
assert myBinaryFileStubBuilder != null;
|
||||
String baseVersion = myBinaryFileStubBuilder.getClass().getName() + ":" + myBinaryFileStubBuilder.getStubVersion();
|
||||
if (myBinaryFileStubBuilder instanceof BinaryFileStubBuilder.CompositeBinaryFileStubBuilder) {
|
||||
return baseVersion + ":" + ((BinaryFileStubBuilder.CompositeBinaryFileStubBuilder)myBinaryFileStubBuilder).getSubBuilderVersion(myBinarySubBuilder);
|
||||
} else {
|
||||
return baseVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
StubBuilderType type = (StubBuilderType)o;
|
||||
return Objects.equals(myElementType, type.myElementType) &&
|
||||
Objects.equals(myBinaryFileStubBuilder, type.myBinaryFileStubBuilder) &&
|
||||
Objects.equals(myBinarySubBuilder, type.myBinarySubBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(myElementType, myBinaryFileStubBuilder, myBinarySubBuilder);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,11 @@
|
||||
package com.intellij.psi.stubs;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageParserDefinitions;
|
||||
import com.intellij.lang.ParserDefinition;
|
||||
import com.intellij.lang.TreeBackedLighterAST;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
@@ -27,10 +30,12 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.StubBuilder;
|
||||
import com.intellij.psi.impl.source.PsiFileImpl;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import com.intellij.psi.tree.IStubFileElementType;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.indexing.FileContent;
|
||||
import com.intellij.util.indexing.IndexedFile;
|
||||
import com.intellij.util.indexing.IndexingDataKeys;
|
||||
import com.intellij.util.indexing.PsiDependentFileContent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,8 +49,49 @@ public class StubTreeBuilder {
|
||||
|
||||
private StubTreeBuilder() { }
|
||||
|
||||
static boolean requiresContentToFindBuilder(@NotNull FileType fileType) {
|
||||
final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType);
|
||||
return builder instanceof BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<?>;
|
||||
}
|
||||
|
||||
static StubBuilderType getStubBuilderType(@NotNull IndexedFile file, boolean toBuild) {
|
||||
FileType fileType = file.getFileType();
|
||||
final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType);
|
||||
if (builder != null) {
|
||||
if (builder instanceof BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<?>) {
|
||||
Object subBuilder = ((BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<?>)builder).getSubBuilder((FileContent) file);
|
||||
return new StubBuilderType((BinaryFileStubBuilder.CompositeBinaryFileStubBuilder)builder, subBuilder);
|
||||
} else {
|
||||
return new StubBuilderType(builder);
|
||||
}
|
||||
}
|
||||
|
||||
if (fileType instanceof LanguageFileType) {
|
||||
final Language l = ((LanguageFileType)fileType).getLanguage();
|
||||
final ParserDefinition parserDefinition = LanguageParserDefinitions.INSTANCE.forLanguage(l);
|
||||
if (parserDefinition == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final IFileElementType elementType = parserDefinition.getFileNodeType();
|
||||
if (!(elementType instanceof IStubFileElementType)) return null;
|
||||
boolean shouldBuildStubFor = ((IStubFileElementType)elementType).shouldBuildStubFor(file.getFile());
|
||||
if (toBuild && !shouldBuildStubFor) return null;
|
||||
return new StubBuilderType((IStubFileElementType)elementType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Stub buildStubTree(final FileContent inputData) {
|
||||
public static Stub buildStubTree(@NotNull FileContent inputData) {
|
||||
StubBuilderType type = getStubBuilderType(inputData, false);
|
||||
if (type == null) return null;
|
||||
return buildStubTree(inputData, type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Stub buildStubTree(@NotNull FileContent inputData, @NotNull StubBuilderType stubBuilderType) {
|
||||
Stub data = inputData.getUserData(stubElementKey);
|
||||
if (data != null) return data;
|
||||
|
||||
@@ -54,9 +100,7 @@ public class StubTreeBuilder {
|
||||
data = inputData.getUserData(stubElementKey);
|
||||
if (data != null) return data;
|
||||
|
||||
final FileType fileType = inputData.getFileType();
|
||||
|
||||
final BinaryFileStubBuilder builder = BinaryFileStubBuilders.INSTANCE.forFileType(fileType);
|
||||
final BinaryFileStubBuilder builder = stubBuilderType.getBinaryFileStubBuilder();
|
||||
if (builder != null) {
|
||||
data = builder.buildStubTree(inputData);
|
||||
if (data instanceof PsiFileStubImpl && !((PsiFileStubImpl)data).rootsAreSet()) {
|
||||
|
||||
@@ -24,9 +24,7 @@ import com.intellij.util.indexing.impl.DebugAssertions;
|
||||
import com.intellij.util.indexing.impl.IndexStorage;
|
||||
import com.intellij.util.indexing.impl.InputDataDiffBuilder;
|
||||
import com.intellij.util.indexing.impl.forward.EmptyForwardIndex;
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import com.intellij.util.io.PersistentHashMapValueStorage;
|
||||
import com.intellij.util.io.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -41,7 +39,7 @@ import java.util.Map;
|
||||
public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<SerializedStubTree>
|
||||
implements CustomImplementationFileBasedIndexExtension<Integer, SerializedStubTree> {
|
||||
static final Logger LOG = Logger.getInstance(StubUpdatingIndex.class);
|
||||
private static final int VERSION = 43 + (PersistentHashMapValueStorage.COMPRESSION_ENABLED ? 1 : 0);
|
||||
private static final int VERSION = 43 + (PersistentHashMapValueStorage.COMPRESSION_ENABLED ? 1 : 0) + (InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED ? 1 : 0);
|
||||
|
||||
// todo remove once we don't need this for stub-ast mismatch debug info
|
||||
private static final FileAttribute INDEXED_STAMP = new FileAttribute("stubIndexStamp", 3, true);
|
||||
@@ -86,10 +84,33 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
@NotNull
|
||||
@Override
|
||||
public SingleEntryIndexer<SerializedStubTree> getIndexer() {
|
||||
return new SingleEntryIndexer<SerializedStubTree>(false) {
|
||||
return new SingleEntryCompositeIndexer<SerializedStubTree, StubBuilderType, String>(false) {
|
||||
@Override
|
||||
public boolean requiresContentForSubIndexerEvaluation(@NotNull IndexedFile file) {
|
||||
return StubTreeBuilder.requiresContentToFindBuilder(file.getFileType());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StubBuilderType calculateSubIndexer(@NotNull IndexedFile file) {
|
||||
return StubTreeBuilder.getStubBuilderType(file, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSubIndexerVersion(@NotNull StubBuilderType type) {
|
||||
return type.getVersion();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public KeyDescriptor<String> getSubIndexerVersionDescriptor() {
|
||||
return EnumeratorStringDescriptor.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SerializedStubTree computeValue(@NotNull final FileContent inputData) {
|
||||
public SerializedStubTree computeValue(@NotNull final FileContent inputData, @NotNull StubBuilderType type) {
|
||||
return ReadAction.compute(() -> {
|
||||
SerializedStubTree serializedStubTree = null;
|
||||
|
||||
@@ -109,7 +130,7 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
}
|
||||
|
||||
if (serializedStubTree == null) {
|
||||
Stub rootStub = StubTreeBuilder.buildStubTree(inputData);
|
||||
Stub rootStub = StubTreeBuilder.buildStubTree(inputData, type);
|
||||
if (rootStub != null) {
|
||||
serializedStubTree = new SerializedStubTree(rootStub, SerializationManagerEx.getInstanceEx(), SerializedStubTree.IDE_USED_EXTERNALIZER);
|
||||
if (DebugAssertions.DEBUG) {
|
||||
@@ -256,13 +277,25 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
|
||||
private static class MyIndex extends VfsAwareMapReduceIndex<Integer, SerializedStubTree, FileContent> {
|
||||
private StubIndexImpl myStubIndex;
|
||||
private final StubVersionMap myStubVersionMap = new StubVersionMap();
|
||||
@Nullable
|
||||
private final StubVersionMap myStubVersionMap = InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED ? null : new StubVersionMap();
|
||||
|
||||
MyIndex(@NotNull FileBasedIndexExtension<Integer, SerializedStubTree> extension, @NotNull IndexStorage<Integer, SerializedStubTree> storage)
|
||||
throws StorageException, IOException {
|
||||
super(extension, storage, new EmptyForwardIndex(), new StubUpdatingForwardIndexAccessor(), null, null);
|
||||
((StubUpdatingForwardIndexAccessor)getForwardIndexAccessor()).setIndex(this);
|
||||
checkNameStorage();
|
||||
|
||||
if (InvertedIndex.ARE_COMPOSITE_INDEXERS_ENABLED) {
|
||||
// load stub serializers before usage
|
||||
for (Language language : Language.getRegisteredLanguages()) {
|
||||
ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(language);
|
||||
if (definition != null) {
|
||||
definition.getFileNodeType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -334,7 +367,9 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
if (stubIndex != null) {
|
||||
stubIndex.clearAllIndices();
|
||||
}
|
||||
myStubVersionMap.clear();
|
||||
if (myStubVersionMap != null) {
|
||||
myStubVersionMap.clear();
|
||||
}
|
||||
super.doClear();
|
||||
}
|
||||
|
||||
@@ -358,6 +393,8 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
@Override
|
||||
public void setIndexedStateForFile(int fileId, @NotNull IndexedFile file) {
|
||||
super.setIndexedStateForFile(fileId, file);
|
||||
|
||||
if (myStubVersionMap == null) return;
|
||||
try {
|
||||
myStubVersionMap.persistIndexedState(fileId, file.getFile());
|
||||
} catch (IOException e) {
|
||||
@@ -371,6 +408,7 @@ public class StubUpdatingIndex extends SingleEntryFileBasedIndexExtension<Serial
|
||||
boolean indexedStateForFile = super.isIndexedStateForFile(fileId, file);
|
||||
if (!indexedStateForFile) return false;
|
||||
|
||||
if (myStubVersionMap == null) return true;
|
||||
try {
|
||||
return myStubVersionMap.isIndexed(fileId, file.getFile());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user