下面列出了怎么用com.intellij.psi.impl.source.PsiFileImpl的API类实例代码及写法,或者点击链接到github查看源代码。
@Nullable
@Override
protected PsiFile createFile(@NotNull Language lang) {
if (lang == myTemplateDataLanguage) {
PsiFileImpl file = (PsiFileImpl) LanguageParserDefinitions.INSTANCE.forLanguage(lang).createFile(this);
file.setContentElementType(TEMPLATE_DATA);
return file;
} else if (lang == FluidLanguage.INSTANCE) {
return LanguageParserDefinitions.INSTANCE.forLanguage(lang).createFile(this);
} else {
return null;
}
}
@Override
protected PsiFile createFile(@NotNull Language lang) {
ParserDefinition parserDefinition = getDefinition(lang);
if (parserDefinition == null) {
return null;
}
if (lang.is(TEMPLATE_DATA_LANGUAGE)) {
PsiFileImpl file = (PsiFileImpl) parserDefinition.createFile(this);
file.setContentElementType(TEMPLATE_DATA_ELEMENT_TYPE);
return file;
} else if (lang.isKindOf(BASE_LANGUAGE)) {
return parserDefinition.createFile(this);
} else {
return null;
}
}
public void testUsageViewDoesNotHoldPsiFilesOrDocuments() throws Exception {
PsiFile psiFile = createFile("X.java", "public class X{} //iuggjhfg");
Usage[] usages = new Usage[100];
for (int i = 0; i < usages.length; i++) {
usages[i] = createUsage(psiFile,i);
}
UsageView usageView = UsageViewManager.getInstance(getProject()).createUsageView(UsageTarget.EMPTY_ARRAY, usages, new UsageViewPresentation(), null);
Disposer.register(getTestRootDisposable(), usageView);
((EncodingManagerImpl)EncodingManager.getInstance()).clearDocumentQueue();
FileDocumentManager.getInstance().saveAllDocuments();
UIUtil.dispatchAllInvocationEvents();
LeakHunter.checkLeak(usageView, PsiFileImpl.class);
LeakHunter.checkLeak(usageView, Document.class);
}
private static void diagnoseInvalidRange(@Nonnull PsiElement scope, PsiFile file, FileViewProvider viewProvider, CharSequence buffer, TextRange range) {
String msg = "Range for element: '" + scope + "' = " + range + " is out of file '" + file + "' range: " + file.getTextRange();
msg += "; file contents length: " + buffer.length();
msg += "\n file provider: " + viewProvider;
Document document = viewProvider.getDocument();
if (document != null) {
msg += "\n committed=" + PsiDocumentManager.getInstance(file.getProject()).isCommitted(document);
}
for (Language language : viewProvider.getLanguages()) {
final PsiFile root = viewProvider.getPsi(language);
msg += "\n root " +
language +
" length=" +
root.getTextLength() +
(root instanceof PsiFileImpl ? "; contentsLoaded=" + ((PsiFileImpl)root).isContentsLoaded() : "");
}
LOG.error(msg);
}
private void reparseParallelTrees(PsiFile changedFile, PsiToDocumentSynchronizer synchronizer) {
List<PsiFile> allFiles = changedFile.getViewProvider().getAllFiles();
if (allFiles.size() <= 1) {
return;
}
CharSequence newText = changedFile.getNode().getChars();
for (final PsiFile file : allFiles) {
FileElement fileElement = file == changedFile ? null : ((PsiFileImpl)file).getTreeElement();
Runnable changeAction = fileElement == null ? null : reparseFile(file, fileElement, newText);
if (changeAction == null) continue;
synchronizer.setIgnorePsiEvents(true);
try {
CodeStyleManager.getInstance(file.getProject()).performActionWithFormatterDisabled(changeAction);
}
finally {
synchronizer.setIgnorePsiEvents(false);
}
}
}
/**
* Ensures this element is AST-based. This is an expensive operation that might take significant time and allocate lots of objects,
* so it should be to be avoided if possible.
*
* @return an AST node corresponding to this element. If the element is currently operating via stubs,
* this causes AST to be loaded for the whole file and all stub-based PSI elements in this file (including the current one)
* to be switched from stub to AST. So, after this call {@link #getStub()} will return null.
*/
@Override
@Nonnull
public ASTNode getNode() {
if (mySubstrateRef instanceof SubstrateRef.StubRef) {
ApplicationManager.getApplication().assertReadAccessAllowed();
PsiFileImpl file = (PsiFileImpl)getContainingFile();
if (!file.isValid()) throw new PsiInvalidElementAccessException(file);
FileElement treeElement = file.getTreeElement();
if (treeElement != null && mySubstrateRef instanceof SubstrateRef.StubRef) {
return notBoundInExistingAst(file, treeElement);
}
treeElement = file.calcTreeElement();
if (mySubstrateRef instanceof SubstrateRef.StubRef) {
return failedToBindStubToAst(file, treeElement);
}
}
return mySubstrateRef.getNode();
}
private ASTNode failedToBindStubToAst(@Nonnull PsiFileImpl file, @Nonnull final FileElement fileElement) {
VirtualFile vFile = file.getVirtualFile();
StubTree stubTree = file.getStubTree();
final String stubString = stubTree != null ? ((PsiFileStubImpl)stubTree.getRoot()).printTree() : null;
final String astString = RecursionManager.doPreventingRecursion("failedToBindStubToAst", true, () -> DebugUtil.treeToString(fileElement, true));
@NonNls final String message =
"Failed to bind stub to AST for element " + getClass() + " in " + (vFile == null ? "<unknown file>" : vFile.getPath()) + "\nFile:\n" + file + "@" + System.identityHashCode(file);
final String creationTraces = ourTraceStubAstBinding ? dumpCreationTraces(fileElement) : null;
List<Attachment> attachments = new ArrayList<>();
if (stubString != null) {
attachments.add(new Attachment("stubTree.txt", stubString));
}
if (astString != null) {
attachments.add(new Attachment("ast.txt", astString));
}
if (creationTraces != null) {
attachments.add(new Attachment("creationTraces.txt", creationTraces));
}
throw new RuntimeExceptionWithAttachments(message, attachments.toArray(Attachment.EMPTY_ARRAY));
}
@Override
protected PsiFile getPsiInner(@Nonnull final Language target) {
PsiFileImpl file = myRoots.get(target);
if (file == null) {
if (!shouldCreatePsi()) return null;
if (target != getBaseLanguage() && !getLanguages().contains(target)) {
return null;
}
file = createPsiFileImpl(target);
if (file == null) return null;
if (myOriginal != null) {
final PsiFile originalFile = myOriginal.getPsi(target);
if (originalFile != null) {
file.setOriginalFile(originalFile);
}
}
file = ConcurrencyUtil.cacheOrGet(myRoots, target, file);
}
return file;
}
/**
* Order is deterministic. First element matches {@link FileViewProvider#getStubBindingRoot()}
*/
@Nonnull
public static List<Pair<IStubFileElementType, PsiFile>> getStubbedRoots(@Nonnull FileViewProvider viewProvider) {
final List<Trinity<Language, IStubFileElementType, PsiFile>> roots = new SmartList<>();
final PsiFile stubBindingRoot = viewProvider.getStubBindingRoot();
for (Language language : viewProvider.getLanguages()) {
final PsiFile file = viewProvider.getPsi(language);
if (file instanceof PsiFileImpl) {
final IElementType type = ((PsiFileImpl)file).getElementTypeForStubBuilder();
if (type != null) {
roots.add(Trinity.create(language, (IStubFileElementType)type, file));
}
}
}
ContainerUtil.sort(roots, (o1, o2) -> {
if (o1.third == stubBindingRoot) return o2.third == stubBindingRoot ? 0 : -1;
else if (o2.third == stubBindingRoot) return 1;
else return StringUtil.compare(o1.first.getID(), o2.first.getID(), false);
});
return ContainerUtil.map(roots, trinity -> Pair.create(trinity.second, trinity.third));
}
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
public void reparseFileFromText(@Nonnull PsiFileImpl file) {
ApplicationManager.getApplication().assertIsDispatchThread();
if (isCommitInProgress()) throw new IllegalStateException("Re-entrant commit is not allowed");
FileElement node = file.calcTreeElement();
CharSequence text = node.getChars();
ourIsFullReparseInProgress = true;
try {
WriteAction.run(() -> {
ProgressIndicator indicator = ProgressIndicatorProvider.getGlobalProgressIndicator();
if (indicator == null) indicator = new EmptyProgressIndicator();
DiffLog log = BlockSupportImpl.makeFullParse(file, node, text, indicator, text).log;
log.doActualPsiChange(file);
file.getViewProvider().contentsSynchronized();
});
}
finally {
ourIsFullReparseInProgress = false;
}
}
@Nonnull
static ReparseResult reparse(@Nonnull final PsiFile file,
@Nonnull FileASTNode oldFileNode,
@Nonnull TextRange changedPsiRange,
@Nonnull final CharSequence newFileText,
@Nonnull final ProgressIndicator indicator,
@Nonnull CharSequence lastCommittedText) {
PsiFileImpl fileImpl = (PsiFileImpl)file;
final Couple<ASTNode> reparseableRoots = findReparseableRoots(fileImpl, oldFileNode, changedPsiRange, newFileText);
if (reparseableRoots == null) {
return makeFullParse(fileImpl, oldFileNode, newFileText, indicator, lastCommittedText);
}
ASTNode oldRoot = reparseableRoots.first;
ASTNode newRoot = reparseableRoots.second;
DiffLog diffLog = mergeTrees(fileImpl, oldRoot, newRoot, indicator, lastCommittedText);
return new ReparseResult(diffLog, oldRoot, newRoot);
}
private static boolean isReplaceWholeNode(@Nonnull PsiFileImpl fileImpl, @Nonnull ASTNode newRoot) throws ReparsedSuccessfullyException {
final Boolean data = fileImpl.getUserData(DO_NOT_REPARSE_INCREMENTALLY);
if (data != null) fileImpl.putUserData(DO_NOT_REPARSE_INCREMENTALLY, null);
boolean explicitlyMarkedDeep = Boolean.TRUE.equals(data);
if (explicitlyMarkedDeep || isTooDeep(fileImpl)) {
return true;
}
final ASTNode childNode = newRoot.getFirstChildNode(); // maybe reparsed in PsiBuilderImpl and have thrown exception here
boolean childTooDeep = isTooDeep(childNode);
if (childTooDeep) {
childNode.putUserData(TREE_DEPTH_LIMIT_EXCEEDED, null);
fileImpl.putUserData(TREE_DEPTH_LIMIT_EXCEEDED, Boolean.TRUE);
}
return childTooDeep;
}
@Nullable
private static SmartPointerElementInfo createAnchorInfo(@Nonnull PsiElement element, @Nonnull PsiFile containingFile) {
if (element instanceof StubBasedPsiElement && containingFile instanceof PsiFileImpl) {
IStubFileElementType stubType = ((PsiFileImpl)containingFile).getElementTypeForStubBuilder();
if (stubType != null && stubType.shouldBuildStubFor(containingFile.getViewProvider().getVirtualFile())) {
StubBasedPsiElement stubPsi = (StubBasedPsiElement)element;
int stubId = PsiAnchor.calcStubIndex(stubPsi);
if (stubId != -1) {
return new AnchorElementInfo(element, (PsiFileImpl)containingFile, stubId, stubPsi.getElementType());
}
}
}
Pair<Identikit.ByAnchor, PsiElement> pair = Identikit.withAnchor(element, LanguageUtil.getRootLanguage(containingFile));
if (pair != null) {
return new AnchorElementInfo(pair.second, containingFile, pair.first);
}
return null;
}
@Nonnull
public final AstSpine getStubbedSpine() {
AstSpine result = myStubbedSpine;
if (result == null) {
PsiFileImpl file = (PsiFileImpl)getPsi();
IStubFileElementType type = file.getElementTypeForStubBuilder();
if (type == null) return AstSpine.EMPTY_SPINE;
result = RecursionManager.doPreventingRecursion(file, false, () -> new AstSpine(calcStubbedDescendants(type.getBuilder())));
if (result == null) {
throw new StackOverflowPreventedException("Endless recursion prevented");
}
myStubbedSpine = result;
}
return result;
}
static OffsetsInFile toInjectedIfAny(PsiFile originalFile, OffsetsInFile hostCopyOffsets) {
CompletionAssertions.assertHostInfo(hostCopyOffsets.getFile(), hostCopyOffsets.getOffsets());
int hostStartOffset = hostCopyOffsets.getOffsets().getOffset(CompletionInitializationContext.START_OFFSET);
OffsetsInFile translatedOffsets = hostCopyOffsets.toInjectedIfAny(hostStartOffset);
if (translatedOffsets != hostCopyOffsets) {
PsiFile injected = translatedOffsets.getFile();
if (originalFile != injected && injected instanceof PsiFileImpl && InjectedLanguageManager.getInstance(originalFile.getProject()).isInjectedFragment(originalFile)) {
((PsiFileImpl)injected).setOriginalFile(originalFile);
}
DocumentWindow documentWindow = InjectedLanguageUtil.getDocumentWindow(injected);
CompletionAssertions.assertInjectedOffsets(hostStartOffset, injected, documentWindow);
if (injected.getTextRange().contains(translatedOffsets.getOffsets().getOffset(CompletionInitializationContext.START_OFFSET))) {
return translatedOffsets;
}
}
return hostCopyOffsets;
}
private void diagnoseLengthMismatch(VirtualFile vFile, boolean wasIndexedAlready, @Nullable Document document, boolean saved, @Nullable PsiFile cachedPsi) {
String message = "Outdated stub in index: " +
vFile +
" " +
getIndexingStampInfo(vFile) +
", doc=" +
document +
", docSaved=" +
saved +
", wasIndexedAlready=" +
wasIndexedAlready +
", queried at " +
vFile.getTimeStamp();
message += "\ndoc length=" + (document == null ? -1 : document.getTextLength()) + "\nfile length=" + vFile.getLength();
if (cachedPsi != null) {
message += "\ncached PSI " + cachedPsi.getClass();
if (cachedPsi instanceof PsiFileImpl && ((PsiFileImpl)cachedPsi).isContentsLoaded()) {
message += "\nPSI length=" + cachedPsi.getTextLength();
}
List<Project> projects = ContainerUtil.findAll(ProjectManager.getInstance().getOpenProjects(), p -> PsiManagerEx.getInstanceEx(p).getFileManager().findCachedViewProvider(vFile) != null);
message += "\nprojects with file: " + (LOG.isDebugEnabled() ? projects.toString() : projects.size());
}
processError(vFile, message, new Exception());
}
@Nullable
private PsiFileSystemItem doResolve(@Nonnull final FileIncludeInfo info, @Nonnull final PsiFile context) {
if (info instanceof FileIncludeInfoImpl) {
String id = ((FileIncludeInfoImpl)info).providerId;
FileIncludeProvider provider = id == null ? null : myProviderMap.get(id);
final PsiFileSystemItem resolvedByProvider = provider == null ? null : provider.resolveIncludedFile(info, context);
if (resolvedByProvider != null) {
return resolvedByProvider;
}
}
PsiFileImpl psiFile = (PsiFileImpl)myPsiFileFactory.createFileFromText("dummy.txt", PlainTextFileType.INSTANCE, info.path);
psiFile.setOriginalFile(context);
return new FileReferenceSet(psiFile) {
@Override
protected boolean useIncludingFileAsContext() {
return false;
}
}.resolve();
}
private long collectAndCheckHighlighting(@NotNull ExpectedHighlightingDataWrapper data) {
Project project = myFixture.getProject();
EdtTestUtil.runInEdtAndWait(() -> {
PsiDocumentManager.getInstance(project).commitAllDocuments();
});
PsiFileImpl file = (PsiFileImpl)this.getHostFile();
FileElement hardRefToFileElement = file.calcTreeElement();
if (!DumbService.isDumb(project)) {
ServiceManager.getService(project, CacheManager.class).getFilesWithWord("XXX", (short)2, GlobalSearchScope.allScope(project), true);
}
long start = System.currentTimeMillis();
Disposable disposable = Disposer.newDisposable();
List<HighlightInfo> infos;
try {
infos = myFixture.doHighlighting();
this.removeDuplicatedRangesForInjected(infos);
} finally {
Disposer.dispose(disposable);
}
long elapsed = System.currentTimeMillis() - start;
data.checkResultWrapper(file, infos, file.getText());
hardRefToFileElement.hashCode();
return elapsed;
}
@Nullable
protected PsiFile createFile(@NotNull Language lang) {
ParserDefinition parser = LanguageParserDefinitions.INSTANCE.forLanguage(lang);
if (parser == null) {
return null;
} else if (lang == XMLLanguage.INSTANCE || lang == HTMLLanguage.INSTANCE) {
PsiFileImpl file = (PsiFileImpl) parser.createFile(this);
file.setContentElementType(templateDataElement);
return file;
} else {
return lang == this.getBaseLanguage() ? parser.createFile(this) : null;
}
}
public boolean parseRequirejsConfig() {
VirtualFile mainJsVirtualFile = findPathInWebDir(settings.configFilePath);
if (null == mainJsVirtualFile) {
this.showErrorConfigNotification("Config file not found. File " + settings.publicPath + '/' + settings.configFilePath + " not found in project");
LOG.debug("Config not found");
return false;
} else {
PsiFile mainJs = PsiManager.getInstance(project).findFile(mainJsVirtualFile);
if (mainJs instanceof JSFileImpl || mainJs instanceof XmlFileImpl) {
Map<String, VirtualFile> allConfigPaths;
packageConfig.clear();
requireMap.clear();
requirePaths.clear();
if (((PsiFileImpl) mainJs).getTreeElement() == null) {
parseMainJsFile(((PsiFileImpl) mainJs).calcTreeElement());
} else {
parseMainJsFile(((PsiFileImpl) mainJs).getTreeElement());
}
} else {
this.showErrorConfigNotification("Config file wrong format");
LOG.debug("Config file wrong format");
return false;
}
}
return true;
}
private long collectAndCheckHighlighting(@Nonnull ExpectedHighlightingData data) {
final Project project = getProject();
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiFileImpl file = (PsiFileImpl)getHostFile();
FileElement hardRefToFileElement = file.calcTreeElement();//to load text
//to initialize caches
if (!DumbService.isDumb(project)) {
CacheManager.getInstance(project).getFilesWithWord(XXX, UsageSearchContext.IN_COMMENTS, GlobalSearchScope.allScope(project), true);
}
List<HighlightInfo> infos;
final long start = System.currentTimeMillis();
try {
((PsiManagerImpl)PsiManager.getInstance(project)).setAssertOnFileLoadingFilter(myJavaFilesFilter, myTestRootDisposable);
// ProfilingUtil.startCPUProfiling();
infos = doHighlighting();
removeDuplicatedRangesForInjected(infos);
// ProfilingUtil.captureCPUSnapshot("testing");
}
finally {
((PsiManagerImpl)PsiManager.getInstance(project)).setAssertOnFileLoadingFilter(VirtualFileFilter.NONE, myTestRootDisposable);
}
final long elapsed = System.currentTimeMillis() - start;
data.checkResult(infos, file.getText());
hardRefToFileElement.hashCode(); // use it so gc won't collect it
return elapsed;
}
@Nonnull
private static List<StubbedSpine> getAllSpines(PsiFile psiFile) {
if (!(psiFile instanceof PsiFileImpl) && psiFile instanceof PsiFileWithStubSupport) {
return Collections.singletonList(((PsiFileWithStubSupport)psiFile).getStubbedSpine());
}
return ContainerUtil.map(StubTreeBuilder.getStubbedRoots(psiFile.getViewProvider()), t -> ((PsiFileImpl)t.second).getStubbedSpine());
}
private <Psi extends PsiElement> boolean checkType(@Nonnull Class<Psi> requiredClass, PsiFile psiFile, PsiElement psiElement) {
if (requiredClass.isInstance(psiElement)) return true;
StubTree stubTree = ((PsiFileWithStubSupport)psiFile).getStubTree();
if (stubTree == null && psiFile instanceof PsiFileImpl) stubTree = ((PsiFileImpl)psiFile).calcStubTree();
inconsistencyDetected(stubTree, (PsiFileWithStubSupport)psiFile);
return false;
}
private void startTransaction(@Nonnull PomTransaction transaction) {
final PsiDocumentManagerBase manager = (PsiDocumentManagerBase)PsiDocumentManager.getInstance(myProject);
final PsiToDocumentSynchronizer synchronizer = manager.getSynchronizer();
final PsiElement changeScope = transaction.getChangeScope();
final PsiFile containingFileByTree = getContainingFileByTree(changeScope);
if (containingFileByTree != null && !(containingFileByTree instanceof DummyHolder) && !manager.isCommitInProgress()) {
PsiUtilCore.ensureValid(containingFileByTree);
}
boolean physical = changeScope.isPhysical();
if (synchronizer.toProcessPsiEvent()) {
// fail-fast to prevent any psi modifications that would cause psi/document text mismatch
// PsiToDocumentSynchronizer assertions happen inside event processing and are logged by PsiManagerImpl.fireEvent instead of being rethrown
// so it's important to throw something outside event processing
if (isDocumentUncommitted(containingFileByTree)) {
throw new IllegalStateException("Attempt to modify PSI for non-committed Document!");
}
CommandProcessor commandProcessor = CommandProcessor.getInstance();
if (physical && !commandProcessor.isUndoTransparentActionInProgress() && commandProcessor.getCurrentCommand() == null) {
throw new IncorrectOperationException(
"Must not change PSI outside command or undo-transparent action. See com.intellij.openapi.command.WriteCommandAction or com.intellij.openapi.command.CommandProcessor");
}
}
if (containingFileByTree != null) {
((SmartPointerManagerImpl)SmartPointerManager.getInstance(myProject)).fastenBelts(containingFileByTree.getViewProvider().getVirtualFile());
if (containingFileByTree instanceof PsiFileImpl) {
((PsiFileImpl)containingFileByTree).beforeAstChange();
}
}
BlockSupportImpl.sendBeforeChildrenChangeEvent((PsiManagerImpl)PsiManager.getInstance(myProject), changeScope, true);
Document document = containingFileByTree == null ? null : physical ? manager.getDocument(containingFileByTree) : manager.getCachedDocument(containingFileByTree);
if (document != null) {
synchronizer.startTransaction(myProject, document, changeScope);
}
}
@SuppressWarnings({"NonConstantStringShouldBeStringBuffer", "StringConcatenationInLoop"})
private ASTNode notBoundInExistingAst(@Nonnull PsiFileImpl file, @Nonnull FileElement treeElement) {
String message = "file=" + file + "; tree=" + treeElement;
PsiElement each = this;
while (each != null) {
message += "\n each of class " + each.getClass() + "; valid=" + each.isValid();
if (each instanceof StubBasedPsiElementBase) {
message += "; ref=" + ((StubBasedPsiElementBase<?>)each).mySubstrateRef;
each = ((StubBasedPsiElementBase<?>)each).getParentByStub();
}
else {
if (each instanceof PsiFile) {
message += "; same file=" + (each == file) + "; current tree= " + file.getTreeElement() + "; stubTree=" + file.getStubTree() + "; physical=" + file.isPhysical();
}
break;
}
}
StubElement<?> eachStub = getStub();
while (eachStub != null) {
message += "\n each stub " + (eachStub instanceof PsiFileStubImpl ? ((PsiFileStubImpl<?>)eachStub).getDiagnostics() : eachStub);
eachStub = eachStub.getParentStub();
}
if (ourTraceStubAstBinding) {
message += dumpCreationTraces(treeElement);
}
throw new AssertionError(message);
}
@Nonnull
@Override
public final List<FileElement> getKnownTreeRoots() {
List<FileElement> files = new ArrayList<>(myRoots.size());
for (PsiFile file : myRoots.values()) {
final FileElement treeElement = ((PsiFileImpl)file).getTreeElement();
if (treeElement != null) {
files.add(treeElement);
}
}
return files;
}
@Override
public void contentsSynchronized() {
Set<Language> languages = getLanguages();
for (Iterator<Map.Entry<Language, PsiFileImpl>> iterator = myRoots.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<Language, PsiFileImpl> entry = iterator.next();
if (!languages.contains(entry.getKey())) {
PsiFileImpl file = entry.getValue();
iterator.remove();
file.markInvalidated();
}
}
super.contentsSynchronized();
}
private PsiTreeChangeEventImpl createChildrenChangeEvent(PsiFile file, boolean generic) {
PsiTreeChangeEventImpl event = new PsiTreeChangeEventImpl(myManager);
event.setParent(file);
event.setFile(file);
event.setGenericChange(generic);
if (file instanceof PsiFileImpl && ((PsiFileImpl)file).isContentsLoaded()) {
event.setOffset(0);
event.setOldLength(file.getTextLength());
}
return event;
}
private static StubTree getOrCalcStubTree(PsiFile stubBindingRoot) {
StubTree result = null;
if (stubBindingRoot instanceof PsiFileWithStubSupport) {
result = ((PsiFileWithStubSupport)stubBindingRoot).getStubTree();
if (result == null && stubBindingRoot instanceof PsiFileImpl) {
result = ((PsiFileImpl)stubBindingRoot).calcStubTree();
}
}
return result;
}
public static void checkStubTextConsistency(@Nonnull PsiFile file) throws StubTextInconsistencyException {
PsiUtilCore.ensureValid(file);
FileViewProvider viewProvider = file.getViewProvider();
if (viewProvider instanceof FreeThreadedFileViewProvider || viewProvider.getVirtualFile() instanceof LightVirtualFile) return;
PsiFile bindingRoot = viewProvider.getStubBindingRoot();
if (!(bindingRoot instanceof PsiFileImpl)) return;
IStubFileElementType fileElementType = ((PsiFileImpl)bindingRoot).getElementTypeForStubBuilder();
if (fileElementType == null || !fileElementType.shouldBuildStubFor(viewProvider.getVirtualFile())) return;
List<PsiFileStub> fromText = restoreStubsFromText(viewProvider);
List<PsiFileStub> fromPsi = ContainerUtil.map(StubTreeBuilder.getStubbedRoots(viewProvider), p -> ((PsiFileImpl)p.getSecond()).calcStubTree().getRoot());
if (fromPsi.size() != fromText.size()) {
throw new StubTextInconsistencyException(
"Inconsistent stub roots: " + "PSI says it's " + ContainerUtil.map(fromPsi, s -> s.getType()) + " but re-parsing the text gives " + ContainerUtil.map(fromText, s -> s.getType()), file,
fromText, fromPsi);
}
for (int i = 0; i < fromPsi.size(); i++) {
PsiFileStub psiStub = fromPsi.get(i);
if (!DebugUtil.stubTreeToString(psiStub).equals(DebugUtil.stubTreeToString(fromText.get(i)))) {
throw new StubTextInconsistencyException("Stub is inconsistent with text in " + file.getLanguage(), file, fromText, fromPsi);
}
}
}