Cleanup (warnings; formatting)

GitOrigin-RevId: fa3874b1b3a0789415fbffd52e5262c15c8f8592
This commit is contained in:
Roman Shevchenko
2022-11-06 10:38:51 +00:00
committed by intellij-monorepo-bot
parent 13a81937cd
commit 4a6f9bd7d8
3 changed files with 136 additions and 220 deletions
@@ -1,4 +1,4 @@
// Copyright 2000-2020 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.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.fileEditor.impl;
import com.intellij.openapi.application.ApplicationManager;
@@ -29,13 +29,13 @@ import java.util.Map;
public abstract class FileDocumentManagerBase extends FileDocumentManager {
public static final Key<Document> HARD_REF_TO_DOCUMENT_KEY = Key.create("HARD_REF_TO_DOCUMENT_KEY");
public static final Key<Boolean> TRACK_NON_PHYSICAL = Key.create("TRACK_NON_PHYSICAL");
private static final Key<VirtualFile> FILE_KEY = Key.create("FILE_KEY");
private static final Key<Boolean> BIG_FILE_PREVIEW = Key.create("BIG_FILE_PREVIEW");
private static final Object lock = new Object();
@Override
@Nullable
public Document getDocument(@NotNull VirtualFile file) {
public @Nullable Document getDocument(@NotNull VirtualFile file) {
ApplicationManager.getApplication().assertReadAccessAllowed();
DocumentEx document = (DocumentEx)getCachedDocument(file);
if (document == null) {
@@ -47,7 +47,7 @@ public abstract class FileDocumentManagerBase extends FileDocumentManager {
CharSequence text = loadText(file, tooLarge);
synchronized (lock) {
document = (DocumentEx)getCachedDocument(file);
if (document != null) return document; // Double checking
if (document != null) return document; // double-checking
document = (DocumentEx)createDocument(text, file);
document.setModificationStamp(file.getModificationStamp());
@@ -78,8 +78,7 @@ public abstract class FileDocumentManagerBase extends FileDocumentManager {
document.putUserData(BIG_FILE_PREVIEW, tooLarge ? Boolean.TRUE : null);
}
@NotNull
private CharSequence loadText(@NotNull VirtualFile file, boolean tooLarge) {
private @NotNull CharSequence loadText(@NotNull VirtualFile file, boolean tooLarge) {
if (file instanceof LightVirtualFile) {
FileViewProvider vp = findCachedPsiInAnyProject(file);
if (vp != null) {
@@ -90,24 +89,26 @@ public abstract class FileDocumentManagerBase extends FileDocumentManager {
return tooLarge ? LoadTextUtil.loadText(file, getPreviewCharCount(file)) : LoadTextUtil.loadText(file);
}
@NotNull
protected abstract Document createDocument(@NotNull CharSequence text, @NotNull VirtualFile file);
protected abstract @NotNull Document createDocument(@NotNull CharSequence text, @NotNull VirtualFile file);
@Override
@Nullable
public Document getCachedDocument(@NotNull VirtualFile file) {
public @Nullable Document getCachedDocument(@NotNull VirtualFile file) {
Document hard = file.getUserData(HARD_REF_TO_DOCUMENT_KEY);
return hard != null ? hard : getDocumentFromCache(file);
}
// store file<->document association with hard references to avoid undesired gc.
// works for non-physical ViewProviders only to avoid memleaks.
// please do not use under the penalty of severe memory leaks and wild PSI inconsistencies.
/**
* Storing file<->document association with hard references to avoid undesired GCs.
* Works for non-physical ViewProviders only, to avoid memory leaks.
* Please do not use under the penalty of severe memory leaks and wild PSI inconsistencies.
*/
@ApiStatus.Internal
public static void registerDocument(@NotNull Document document, @NotNull VirtualFile virtualFile) {
if (!(virtualFile instanceof LightVirtualFile) &&
!(virtualFile.getFileSystem() instanceof NonPhysicalFileSystem)) {
throw new IllegalArgumentException("Hard-coding file<->document association is permitted for non-physical files only (see FileViewProvider.isPhysical()) to avoid memleaks. virtualFile="+virtualFile);
throw new IllegalArgumentException(
"Hard-coding file<->document association is permitted for non-physical files only (see FileViewProvider.isPhysical())" +
" to avoid memory leaks. virtualFile=" + virtualFile);
}
synchronized (lock) {
document.putUserData(FILE_KEY, virtualFile);
@@ -116,10 +117,8 @@ public abstract class FileDocumentManagerBase extends FileDocumentManager {
}
@Override
@Nullable
public VirtualFile getFile(@NotNull Document document) {
if (document instanceof FrozenDocument) return null;
return document.getUserData(FILE_KEY);
public @Nullable VirtualFile getFile(@NotNull Document document) {
return document instanceof FrozenDocument ? null : document.getUserData(FILE_KEY);
}
@Override
@@ -16,8 +16,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.Strings;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.*;
@@ -48,16 +46,15 @@ public final class LoadTextUtil {
private LoadTextUtil() { }
@NotNull
private static ConvertResult convertLineSeparatorsToSlashN(@NotNull CharBuffer buffer) {
private static @NotNull ConvertResult convertLineSeparatorsToSlashN(@NotNull CharBuffer buffer) {
int dst = 0;
char prev = ' ';
int crCount = 0;
int lfCount = 0;
int crlfCount = 0;
final int length = buffer.length();
final char[] bufferArray = CharArrayUtil.fromSequenceWithoutCopying(buffer);
int length = buffer.length();
char[] bufferArray = CharArrayUtil.fromSequenceWithoutCopying(buffer);
for (int src = 0; src < length; src++) {
char c = bufferArray != null ? bufferArray[src]:buffer.charAt(src);
@@ -92,8 +89,7 @@ public final class LoadTextUtil {
private static final char UNDEFINED_CHAR = 0xFDFF;
@NotNull
private static ConvertResult convertLineSeparatorsToSlashN(byte @NotNull [] charsAsBytes, int startOffset, int endOffset) {
private static @NotNull ConvertResult convertLineSeparatorsToSlashN(byte @NotNull [] charsAsBytes, int startOffset, int endOffset) {
int lineBreak = findLineBreakOrWideChar(charsAsBytes, startOffset, endOffset);
if (!BitUtil.isSet(lineBreak, CR) && !BitUtil.isSet(lineBreak, WIDE)) {
// optimisation: if there is no CR in the file, no line separator conversion is necessary. we can re-use the passed byte buffer inplace
@@ -141,8 +137,7 @@ public final class LoadTextUtil {
return new ConvertResult(sequence, crCount, lfCount, crlfCount);
}
@NotNull
private static ConvertResult convertWideCharacters(byte @NotNull [] charsAsBytes, int startOffset, int endOffset) {
private static @NotNull ConvertResult convertWideCharacters(byte @NotNull [] charsAsBytes, int startOffset, int endOffset) {
// convert \r\n to \n, \r to \n, wide char to UNDEFINED_CHAR
char prev = ' ';
int crCount = 0;
@@ -183,6 +178,7 @@ public final class LoadTextUtil {
private static final int CR = 1;
private static final int LF = 2;
private static final int WIDE = 4;
@MagicConstant(flags = {CR, LF, WIDE})
private static int findLineBreakOrWideChar(byte @NotNull [] ints, int start, int end) {
int flags = 0;
@@ -195,10 +191,12 @@ public final class LoadTextUtil {
return flags;
}
// private fake charsets for files which have one-byte-for-ascii-characters encoding but contain seven bits characters only. used for optimization since we don't have to encode-decode bytes here.
// Private fake charsets for files having one-byte-for-ascii-characters encoding but containing only 7-bit characters.
// Used for optimization since we don't have to encode-decode bytes here.
private static final Charset INTERNAL_SEVEN_BIT_UTF8 = new SevenBitCharset(StandardCharsets.UTF_8);
private static final Charset INTERNAL_SEVEN_BIT_ISO_8859_1 = new SevenBitCharset(StandardCharsets.ISO_8859_1);
private static final Charset INTERNAL_SEVEN_BIT_WIN_1251 = new SevenBitCharset(CharsetToolkit.WIN_1251_CHARSET);
private static class SevenBitCharset extends Charset {
private final Charset myBaseCharset;
@@ -238,13 +236,12 @@ public final class LoadTextUtil {
}
}
// guess from file type or content
@NotNull
private static DetectResult detectHardCharset(@NotNull VirtualFile virtualFile,
// guess from a file type or a content
private static @NotNull DetectResult detectHardCharset(@NotNull VirtualFile virtualFile,
byte @NotNull [] internalBuffer,
int length,
@NotNull FileType fileType) {
String charsetName = fileType.getCharset(virtualFile, internalBuffer); // todo aaaaah
String charsetName = fileType.getCharset(virtualFile, internalBuffer); // todo[cdr]
Charset charset = charsetName == null ? null : CharsetToolkit.forName(charsetName);
DetectResult detectResult = guessFromContent(virtualFile, internalBuffer, length);
Charset hardCodedCharset = charset == null ? detectResult.hardCodedCharset : charset;
@@ -260,24 +257,21 @@ public final class LoadTextUtil {
return new DetectResult(result, guessed, detectedBOM);
}
@NotNull
public static Charset detectCharsetAndSetBOM(@NotNull VirtualFile virtualFile, byte @NotNull [] content, @NotNull FileType fileType) {
public static @NotNull Charset detectCharsetAndSetBOM(@NotNull VirtualFile virtualFile, byte @NotNull [] content, @NotNull FileType fileType) {
Charset internalCharset = detectInternalCharsetAndSetBOM(virtualFile, content, content.length, true, fileType).hardCodedCharset;
return internalCharset instanceof SevenBitCharset ? ((SevenBitCharset)internalCharset).myBaseCharset : internalCharset;
}
@NotNull
private static Charset getDefaultCharsetFromEncodingManager(@NotNull VirtualFile virtualFile) {
private static @NotNull Charset getDefaultCharsetFromEncodingManager(@NotNull VirtualFile virtualFile) {
Charset specifiedExplicitly = EncodingRegistry.getInstance().getEncoding(virtualFile, true);
return ObjectUtils.notNull(specifiedExplicitly, EncodingRegistry.getInstance().getDefaultCharset());
}
@NotNull
private static DetectResult detectInternalCharsetAndSetBOM(@NotNull VirtualFile file,
byte @NotNull [] internalBuffer,
int length,
boolean saveBOM,
@NotNull FileType fileType) {
private static @NotNull DetectResult detectInternalCharsetAndSetBOM(@NotNull VirtualFile file,
byte @NotNull [] internalBuffer,
int length,
boolean saveBOM,
@NotNull FileType fileType) {
DetectResult info = detectHardCharset(file, internalBuffer, length, fileType);
Charset charset;
@@ -314,19 +308,17 @@ public final class LoadTextUtil {
}
@NotNull
public static DetectResult guessFromContent(@NotNull VirtualFile virtualFile, byte @NotNull [] content) {
public static @NotNull DetectResult guessFromContent(@NotNull VirtualFile virtualFile, byte @NotNull [] content) {
return guessFromContent(virtualFile, content, content.length);
}
private static final boolean GUESS_UTF = Boolean.parseBoolean(System.getProperty("idea.guess.utf.encoding", "true"));
@NotNull
private static DetectResult guessFromContent(@NotNull VirtualFile virtualFile, byte @NotNull [] content, int length) {
private static @NotNull DetectResult guessFromContent(@NotNull VirtualFile virtualFile, byte @NotNull [] content, int length) {
AutoDetectionReason detectedFromBytes = null;
try {
DetectResult info;
if (GUESS_UTF) {
info = guessFromBytes(content, 0, length, getDefaultCharsetFromEncodingManager(virtualFile));
info = guessFromBytes(content, length, getDefaultCharsetFromEncodingManager(virtualFile));
if (info.BOM != null) {
detectedFromBytes = AutoDetectionReason.FROM_BOM;
}
@@ -344,11 +336,8 @@ public final class LoadTextUtil {
}
}
@NotNull
private static DetectResult guessFromBytes(byte @NotNull [] content,
int startOffset, int endOffset,
@NotNull Charset defaultCharset) {
if (startOffset == endOffset) {
private static @NotNull DetectResult guessFromBytes(byte @NotNull [] content, int endOffset, @NotNull Charset defaultCharset) {
if (endOffset == 0) {
return new DetectResult(null, CharsetToolkit.GuessedEncoding.SEVEN_BIT, null);
}
CharsetToolkit toolkit = new CharsetToolkit(content, defaultCharset, true);
@@ -357,46 +346,14 @@ public final class LoadTextUtil {
byte[] bom = ObjectUtils.notNull(CharsetToolkit.getMandatoryBom(charset), CharsetToolkit.UTF8_BOM);
return new DetectResult(charset, null, bom);
}
CharsetToolkit.GuessedEncoding guessed = toolkit.guessFromContent(startOffset, endOffset);
CharsetToolkit.GuessedEncoding guessed = toolkit.guessFromContent(0, endOffset);
if (guessed == CharsetToolkit.GuessedEncoding.VALID_UTF8) {
return new DetectResult(StandardCharsets.UTF_8, CharsetToolkit.GuessedEncoding.VALID_UTF8, null); //UTF detected, ignore all directives
}
return new DetectResult(null, guessed, null);
}
/**
* Tries to detect text in the {@code bytes} and call the {@code fileTextProcessor} with the text (if detected) or with null if not
*/
public static String getTextFromBytesOrNull(byte @NotNull [] bytes, int startOffset, int endOffset) {
Charset defaultCharset = EncodingManager.getInstance().getDefaultCharset();
DetectResult info = guessFromBytes(bytes, startOffset, endOffset, defaultCharset);
Charset charset;
if (info.hardCodedCharset != null) {
charset = info.hardCodedCharset;
}
else {
switch (info.guessed) {
case SEVEN_BIT:
charset = StandardCharsets.US_ASCII;
break;
case VALID_UTF8:
charset = StandardCharsets.UTF_8;
break;
case INVALID_UTF8:
case BINARY:
// the charset was not detected so the file is likely binary
return null;
default:
throw new IllegalStateException(String.valueOf(info.guessed));
}
}
byte[] bom = info.BOM;
ConvertResult result = convertBytes(bytes, Math.min(startOffset + (bom == null ? 0 : bom.length), endOffset), endOffset, charset);
return result.text.toString();
}
@NotNull
private static Pair.NonNull<Charset,byte[]> getOverriddenCharsetByBOM(byte @NotNull [] content, @NotNull Charset charset) {
private static @NotNull Pair.NonNull<Charset, byte[]> getOverriddenCharsetByBOM(byte @NotNull [] content, @NotNull Charset charset) {
if (charset.name().contains(CharsetToolkit.UTF8) && CharsetToolkit.hasUTF8Bom(content)) {
return Pair.createNonNull(charset, CharsetToolkit.UTF8_BOM);
}
@@ -420,16 +377,7 @@ public final class LoadTextUtil {
}
/**
* Overwrites file with text and sets modification stamp and time stamp to the specified values.
* <p/>
* Normally you should not use this method.
*
* @param requestor any object to control who called this method. Note that
* it is considered to be an external change if {@code requestor} is {@code null}.
* See {@link VirtualFileEvent#getRequestor}
* @param newModificationStamp new modification stamp or -1 if no special value should be set @return {@code Writer}
* @throws IOException if an I/O error occurs
* @see VirtualFile#getModificationStamp()
* Normally, one should not use this method.
*/
public static void write(@Nullable Project project,
@NotNull VirtualFile virtualFile,
@@ -443,24 +391,22 @@ public final class LoadTextUtil {
if (!charset.equals(existing)) {
virtualFile.setCharset(charset);
}
setDetectedFromBytesFlagBack(virtualFile, buffer);
restoreDetectedFromContentFlag(virtualFile, buffer);
try (OutputStream stream = virtualFile.getOutputStream(requestor, newModificationStamp, -1)) {
stream.write(buffer);
}
}
@NotNull
public static Pair.NonNull<Charset, byte[]> charsetForWriting(@Nullable Project project,
@NotNull VirtualFile virtualFile,
@NotNull String text,
@NotNull Charset existing) {
public static @NotNull Pair.NonNull<Charset, byte[]> charsetForWriting(@Nullable Project project,
@NotNull VirtualFile virtualFile,
@NotNull String text,
@NotNull Charset existing) {
Charset specified = extractCharsetFromFileContent(project, virtualFile, text);
Pair.NonNull<Charset, byte[]> chosen = chooseMostlyHarmlessCharset(existing, specified, text);
Charset charset = chosen.first;
// in case of "UTF-16", OutputStreamWriter sometimes adds BOM on it's own.
// see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6800103
// in the case of "UTF-16", OutputStreamWriter sometimes adds BOM on its own (see JDK-6800103)
byte[] bom = virtualFile.getBOM();
Charset fromBom = bom == null ? null : CharsetToolkit.guessFromBOM(bom);
if (fromBom != null && !fromBom.equals(charset)) {
@@ -469,18 +415,17 @@ public final class LoadTextUtil {
return chosen;
}
private static void setDetectedFromBytesFlagBack(@NotNull VirtualFile virtualFile, byte @NotNull [] content) {
private static void restoreDetectedFromContentFlag(@NotNull VirtualFile virtualFile, byte @NotNull [] content) {
if (virtualFile.getBOM() == null) {
guessFromContent(virtualFile, content);
}
else {
// prevent file to be reloaded in other encoding after save with BOM
// prevent file to be reloaded in another encoding after save with BOM
setCharsetAutoDetectionReason(virtualFile, AutoDetectionReason.FROM_BOM);
}
}
@NotNull
public static Pair.NonNull<Charset, byte[]> chooseMostlyHarmlessCharset(@NotNull Charset existing, @NotNull Charset specified, @NotNull String text) {
public static @NotNull Pair.NonNull<Charset, byte[]> chooseMostlyHarmlessCharset(@NotNull Charset existing, @NotNull Charset specified, @NotNull String text) {
try {
if (specified.equals(existing)) {
return Pair.createNonNull(specified, text.getBytes(existing));
@@ -494,7 +439,7 @@ public final class LoadTextUtil {
if (out != null) {
return Pair.createNonNull(existing, out); //otherwise stick to the old encoding if it's ok
}
return Pair.createNonNull(specified, text.getBytes(specified)); //if both are bad there is no difference
return Pair.createNonNull(specified, text.getBytes(specified)); //if both are bad, there is no difference
}
catch (RuntimeException e) {
Charset defaultCharset = Charset.defaultCharset();
@@ -517,21 +462,18 @@ public final class LoadTextUtil {
}
}
@NotNull
public static Charset extractCharsetFromFileContent(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull CharSequence text) {
public static @NotNull Charset extractCharsetFromFileContent(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull CharSequence text) {
return ObjectUtils.notNull(charsetFromContentOrNull(project, virtualFile, text), virtualFile.getCharset());
}
@Nullable("returns null if cannot determine from content")
public static Charset charsetFromContentOrNull(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull CharSequence text) {
public static @Nullable("returns null if cannot determine from content") Charset charsetFromContentOrNull(@Nullable Project project, @NotNull VirtualFile virtualFile, @NotNull CharSequence text) {
return CharsetUtil.extractCharsetFromFileContent(project, virtualFile, virtualFile.getFileType(), text);
}
@NotNull
public static CharSequence loadText(@NotNull final VirtualFile file) {
public static @NotNull CharSequence loadText(@NotNull VirtualFile file) {
FileType type = file.getFileType();
if (type.isBinary()) {
final BinaryFileDecompiler decompiler = BinaryFileTypeDecompilers.getInstance().forFileType(type);
BinaryFileDecompiler decompiler = BinaryFileTypeDecompilers.getInstance().forFileType(type);
if (decompiler != null) {
CharSequence text = decompiler.decompile(file);
try {
@@ -550,19 +492,13 @@ public final class LoadTextUtil {
}
/**
* Loads content of given virtual file. If limit is {@value UNLIMITED} then full CharSequence will be returned. Else CharSequence
* will be truncated by limit if it has bigger length.
* @param file Virtual file for content loading
* @param limit Maximum characters count or {@value UNLIMITED}
* @throws IllegalArgumentException for binary files
* @return Full or truncated CharSequence with file content
*/
@NotNull
public static CharSequence loadText(@NotNull final VirtualFile file, int limit) {
public static @NotNull CharSequence loadText(@NotNull VirtualFile file, int limit) {
FileType type = file.getFileType();
if (type.isBinary()) throw new IllegalArgumentException(
"Attempt to load truncated text for binary file: " + file.getPresentableUrl() + ". File type: " + type.getName()
);
if (type.isBinary()) {
throw new IllegalArgumentException("Attempt to load truncated text for binary file: " + file.getPresentableUrl() + ". File type: " + type.getName());
}
if (file instanceof LightVirtualFile) {
return limitCharSequence(((LightVirtualFile)file).getContent(), limit);
@@ -572,38 +508,32 @@ public final class LoadTextUtil {
throw new AssertionError("'" + file.getPresentableUrl() + "' is a directory");
}
try {
byte[] bytes = limit == UNLIMITED ? file.contentsToByteArray() :
FileUtil.loadFirstAndClose(file.getInputStream(), limit);
byte[] bytes = limit == UNLIMITED ? file.contentsToByteArray() : FileUtil.loadFirstAndClose(file.getInputStream(), limit);
return getTextByBinaryPresentation(bytes, file);
}
catch (IOException e) {
LOG.debug(e);
return Strings.EMPTY_CHAR_SEQUENCE;
}
}
@NotNull
private static CharSequence limitCharSequence(@NotNull CharSequence sequence, int limit) {
private static @NotNull CharSequence limitCharSequence(@NotNull CharSequence sequence, int limit) {
return limit == UNLIMITED ? sequence : sequence.subSequence(0, Math.min(limit, sequence.length()));
}
@NotNull
public static CharSequence getTextByBinaryPresentation(final byte @NotNull [] bytes, @NotNull VirtualFile virtualFile) {
public static @NotNull CharSequence getTextByBinaryPresentation(byte @NotNull [] bytes, @NotNull VirtualFile virtualFile) {
return getTextByBinaryPresentation(bytes, virtualFile, true, true);
}
@NotNull
public static CharSequence getTextByBinaryPresentation(byte @NotNull [] bytes,
@NotNull VirtualFile virtualFile,
boolean saveDetectedSeparators,
boolean saveBOM) {
public static @NotNull CharSequence getTextByBinaryPresentation(byte @NotNull [] bytes,
@NotNull VirtualFile virtualFile,
boolean saveDetectedSeparators,
boolean saveBOM) {
DetectResult info = detectInternalCharsetAndSetBOM(virtualFile, bytes, bytes.length, saveBOM, virtualFile.getFileType());
ConvertResult result = convertBytesAndSetSeparator(bytes, bytes.length, virtualFile, saveDetectedSeparators, info, info.hardCodedCharset);
return result.text;
}
@NotNull
static Set<String> detectAllLineSeparators(@NotNull VirtualFile virtualFile) {
static @NotNull Set<String> detectAllLineSeparators(@NotNull VirtualFile virtualFile) {
byte[] bytes;
try {
bytes = virtualFile.contentsToByteArray();
@@ -618,8 +548,7 @@ public final class LoadTextUtil {
}
// written in push way to make sure no-one stores the CharSequence because it came from thread-local byte buffers which will be overwritten soon
@NotNull
public static FileType processTextFromBinaryPresentationOrNull(@NotNull ByteSequence bytes,
public static @NotNull FileType processTextFromBinaryPresentationOrNull(@NotNull ByteSequence bytes,
@NotNull VirtualFile virtualFile,
boolean saveDetectedSeparators,
boolean saveBOM,
@@ -631,7 +560,7 @@ public final class LoadTextUtil {
CharsetToolkit.GuessedEncoding guessed = detectResult.guessed;
CharSequence toProcess;
if (internalCharset == null || guessed == CharsetToolkit.GuessedEncoding.BINARY || guessed == CharsetToolkit.GuessedEncoding.INVALID_UTF8) {
// the charset was not detected so the file is likely binary
// the charset was not detected, so the file is likely binary
toProcess = null;
}
else {
@@ -641,13 +570,12 @@ public final class LoadTextUtil {
return fileTextProcessor.fun(toProcess);
}
@NotNull
private static ConvertResult convertBytesAndSetSeparator(byte @NotNull [] bytes,
int length,
@NotNull VirtualFile virtualFile,
boolean saveDetectedSeparators,
@NotNull DetectResult info,
@NotNull Charset internalCharset) {
private static @NotNull ConvertResult convertBytesAndSetSeparator(byte @NotNull [] bytes,
int length,
@NotNull VirtualFile virtualFile,
boolean saveDetectedSeparators,
@NotNull DetectResult info,
@NotNull Charset internalCharset) {
byte[] bom = info.BOM;
int BOMEndOffset = Math.min(length, bom == null ? 0 : bom.length);
ConvertResult result = convertBytes(bytes, BOMEndOffset, length, internalCharset);
@@ -668,34 +596,29 @@ public final class LoadTextUtil {
* @param checkFile if the line separator was not detected before, try to detect it
* @return the detected line separator or null
*/
@Nullable
public static String detectLineSeparator(@NotNull VirtualFile file, boolean checkFile) {
public static @Nullable String detectLineSeparator(@NotNull VirtualFile file, boolean checkFile) {
String lineSeparator = file.getDetectedLineSeparator();
if (lineSeparator == null && checkFile) {
try {
getTextByBinaryPresentation(file.contentsToByteArray(), file);
lineSeparator = file.getDetectedLineSeparator();
}
catch (IOException e) {
// null will be returned
}
catch (IOException ignored) { }
}
return lineSeparator;
}
@NotNull
public static CharSequence getTextByBinaryPresentation(byte @NotNull [] bytes, @NotNull Charset charset) {
public static @NotNull CharSequence getTextByBinaryPresentation(byte @NotNull [] bytes, @NotNull Charset charset) {
Pair.NonNull<Charset, byte[]> pair = getOverriddenCharsetByBOM(bytes, charset);
byte[] bom = pair.getSecond();
final ConvertResult result = convertBytes(bytes, Math.min(bom.length, bytes.length), bytes.length, pair.first);
ConvertResult result = convertBytes(bytes, Math.min(bom.length, bytes.length), bytes.length, pair.first);
return result.text;
}
@NotNull
private static ConvertResult convertBytes(byte @NotNull [] bytes,
final int startOffset, int endOffset,
@NotNull Charset internalCharset) {
private static @NotNull ConvertResult convertBytes(byte @NotNull [] bytes,
int startOffset, int endOffset,
@NotNull Charset internalCharset) {
assert startOffset >= 0 && startOffset <= endOffset && endOffset <= bytes.length: startOffset + "," + endOffset+": "+bytes.length;
if (internalCharset instanceof SevenBitCharset || internalCharset == StandardCharsets.US_ASCII) {
// optimisation: skip byte-to-char conversion for ascii chars
@@ -716,7 +639,7 @@ public final class LoadTextUtil {
}
private static class ConvertResult {
@NotNull private final CharSequence text;
private final @NotNull CharSequence text;
private final int CR_count;
private final int LF_count;
private final int CRLF_count;
@@ -753,8 +676,8 @@ public final class LoadTextUtil {
}
private static final Key<AutoDetectionReason> CHARSET_WAS_DETECTED_FROM_BYTES = Key.create("CHARSET_WAS_DETECTED_FROM_BYTES");
@Nullable("null if was not detected, otherwise the reason it was")
public static AutoDetectionReason getCharsetAutoDetectionReason(@NotNull VirtualFile virtualFile) {
public static @Nullable("null if was not detected, otherwise the reason it was") AutoDetectionReason getCharsetAutoDetectionReason(@NotNull VirtualFile virtualFile) {
return virtualFile.getUserData(CHARSET_WAS_DETECTED_FROM_BYTES);
}
@@ -15,6 +15,7 @@ import com.intellij.openapi.editor.Document;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.fileEditor.FileDocumentManagerListener;
import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeEvent;
import com.intellij.openapi.fileTypes.FileTypeListener;
import com.intellij.openapi.fileTypes.FileTypeManager;
@@ -73,7 +74,7 @@ public final class PsiVFSListener implements BulkFileListener {
public void runActivity(@NotNull Project project) {
MessageBusConnection connection = project.getMessageBus().connect();
ExtensionPoint<KeyedLazyInstance<LanguageSubstitutor>> point = LanguageSubstitutors.getInstance().getPoint();
ExtensionPoint<@NotNull KeyedLazyInstance<LanguageSubstitutor>> point = LanguageSubstitutors.getInstance().getPoint();
if (point != null) {
point.addChangeListener(() -> {
if (project.isDisposed()) {
@@ -114,9 +115,6 @@ public final class PsiVFSListener implements BulkFileListener {
}
}
/**
* This code is implemented as static method (and not static constructor, as it was done before) to prevent installing listeners in Upsource
*/
private static void installGlobalListener() {
if (!ourGlobalListenerInstalled.compareAndSet(false, true)) {
return;
@@ -135,10 +133,9 @@ public final class PsiVFSListener implements BulkFileListener {
@Override
public void after(@NotNull List<? extends @NotNull VFileEvent> events) {
Project[] projects = ProjectUtilCore.getOpenProjects();
// let PushedFilePropertiesUpdater process all pending vfs events and update file properties before we issue PSI events
// let PushedFilePropertiesUpdater process all pending VFS events and update file properties before we issue PSI events
for (Project project : projects) {
PushedFilePropertiesUpdater updater = PushedFilePropertiesUpdater.getInstance(project);
// false in upsource
if (updater instanceof PushedFilePropertiesUpdaterImpl) {
((PushedFilePropertiesUpdaterImpl)updater).processAfterVfsChanges(events);
}
@@ -150,8 +147,7 @@ public final class PsiVFSListener implements BulkFileListener {
});
}
@Nullable
private PsiDirectory getCachedDirectory(VirtualFile parent) {
private @Nullable PsiDirectory getCachedDirectory(VirtualFile parent) {
return parent == null ? null : myFileManager.getCachedDirectory(parent);
}
@@ -176,10 +172,10 @@ public final class PsiVFSListener implements BulkFileListener {
}
private void beforeFileDeletion(@NotNull VFileDeleteEvent event) {
final VirtualFile vFile = event.getFile();
VirtualFile vFile = event.getFile();
VirtualFile parent = vFile.getParent();
final PsiDirectory parentDir = getCachedDirectory(parent);
PsiDirectory parentDir = getCachedDirectory(parent);
if (parentDir == null) return; // do not notify listeners if parent directory was never accessed via PSI
ApplicationManager.getApplication().runWriteAction(
@@ -195,7 +191,7 @@ public final class PsiVFSListener implements BulkFileListener {
);
}
// optimization: call myFileManager.removeInvalidFilesAndDirs() once for group of delete events, instead of once for each event
// optimization: call myFileManager.removeInvalidFilesAndDirs() once for a group of deletion events, instead of once for each event
private void filesDeleted(@NotNull List<? extends VFileEvent> events) {
boolean needToRemoveInvalidFilesAndDirs = false;
for (VFileEvent event : events) {
@@ -203,14 +199,14 @@ public final class PsiVFSListener implements BulkFileListener {
VirtualFile vFile = de.getFile();
VirtualFile parent = vFile.getParent();
final PsiFile psiFile = myFileManager.getCachedPsiFileInner(vFile);
PsiFile psiFile = myFileManager.getCachedPsiFileInner(vFile);
PsiElement element;
if (psiFile != null) {
myFileManager.setViewProvider(vFile, null);
element = psiFile;
}
else {
final PsiDirectory psiDir = myFileManager.getCachedDirectory(vFile);
PsiDirectory psiDir = myFileManager.getCachedDirectory(vFile);
if (psiDir != null) {
needToRemoveInvalidFilesAndDirs = true;
element = psiDir;
@@ -223,7 +219,7 @@ public final class PsiVFSListener implements BulkFileListener {
element = null;
}
}
final PsiDirectory parentDir = getCachedDirectory(parent);
PsiDirectory parentDir = getCachedDirectory(parent);
if (element != null && parentDir != null) {
ApplicationManager.getApplication().runWriteAction((ExternalChangeAction)() -> {
PsiTreeChangeEventImpl treeEvent = new PsiTreeChangeEventImpl(myManager);
@@ -242,14 +238,14 @@ public final class PsiVFSListener implements BulkFileListener {
DebugUtil.performPsiModification(why, ()-> myFileManager.setViewProvider(vFile, null));
}
private void beforePropertyChange(@NotNull final VFilePropertyChangeEvent event) {
final VirtualFile vFile = event.getFile();
final String propertyName = event.getPropertyName();
private void beforePropertyChange(@NotNull VFilePropertyChangeEvent event) {
VirtualFile vFile = event.getFile();
String propertyName = event.getPropertyName();
final FileViewProvider viewProvider = myFileManager.findCachedViewProvider(vFile);
FileViewProvider viewProvider = myFileManager.findCachedViewProvider(vFile);
VirtualFile parent = vFile.getParent();
final PsiDirectory parentDir = viewProvider != null && parent != null ? myFileManager.findDirectory(parent) : getCachedDirectory(parent);
PsiDirectory parentDir = viewProvider != null && parent != null ? myFileManager.findDirectory(parent) : getCachedDirectory(parent);
if (parent != null && parentDir == null) return; // do not notifyListeners event if parent directory was never accessed via PSI
ApplicationManager.getApplication().runWriteAction(
@@ -258,7 +254,7 @@ public final class PsiVFSListener implements BulkFileListener {
treeEvent.setParent(parentDir);
if (VirtualFile.PROP_NAME.equals(propertyName)) {
final String newName = (String)event.getNewValue();
String newName = (String)event.getNewValue();
if (parentDir == null) return;
@@ -284,7 +280,7 @@ public final class PsiVFSListener implements BulkFileListener {
}
}
else {
final FileViewProvider viewProvider1 = myFileManager.findViewProvider(vFile);
FileViewProvider viewProvider1 = myFileManager.findViewProvider(vFile);
PsiFile psiFile = viewProvider1.getPsi(viewProvider1.getBaseLanguage());
PsiFile psiFile1 = createFileCopyWithNewName(vFile, newName);
@@ -339,18 +335,18 @@ public final class PsiVFSListener implements BulkFileListener {
return false;
}
private void propertyChanged(@NotNull final VFilePropertyChangeEvent event) {
final String propertyName = event.getPropertyName();
final VirtualFile vFile = event.getFile();
private void propertyChanged(@NotNull VFilePropertyChangeEvent event) {
String propertyName = event.getPropertyName();
VirtualFile vFile = event.getFile();
FileViewProvider oldFileViewProvider = myFileManager.findCachedViewProvider(vFile);
PsiFile oldPsiFile = myFileManager.getCachedPsiFile(vFile);
VirtualFile parent = vFile.getParent();
final PsiDirectory parentDir = oldPsiFile != null && parent != null ? myFileManager.findDirectory(parent) : getCachedDirectory(parent);
PsiDirectory parentDir = oldPsiFile != null && parent != null ? myFileManager.findDirectory(parent) : getCachedDirectory(parent);
if (oldFileViewProvider != null // there is no need to rebuild if there were no PSI in the first place
&& FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(event.getRequestor())) {
if (oldFileViewProvider != null && FileContentUtilCore.FORCE_RELOAD_REQUESTOR.equals(event.getRequestor())) {
// there is no need to rebuild if there were no PSI in the first place
myFileManager.forceReload(vFile);
return;
}
@@ -401,8 +397,8 @@ public final class PsiVFSListener implements BulkFileListener {
}
}
else {
final FileViewProvider fileViewProvider = myFileManager.createFileViewProvider(vFile, true);
final PsiFile newPsiFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage());
FileViewProvider fileViewProvider = myFileManager.createFileViewProvider(vFile, true);
PsiFile newPsiFile = fileViewProvider.getPsi(fileViewProvider.getBaseLanguage());
if (oldPsiFile != null) {
if (newPsiFile == null) {
clearViewProvider(vFile, "PSI renamed");
@@ -493,7 +489,7 @@ public final class PsiVFSListener implements BulkFileListener {
});
}
// optimization: call myFileManager.removeInvalidFilesAndDirs() once for group of move events, instead of once for each event
// optimization: call myFileManager.removeInvalidFilesAndDirs() once for a group of move events, instead of once for each event
private void filesMoved(@NotNull List<? extends VFileEvent> events) {
List<PsiElement> oldElements = new ArrayList<>(events.size());
List<PsiDirectory> oldParentDirs = new ArrayList<>(events.size());
@@ -503,7 +499,7 @@ public final class PsiVFSListener implements BulkFileListener {
for (VFileEvent e : events) {
VFileMoveEvent event = (VFileMoveEvent)e;
final VirtualFile vFile = event.getFile();
VirtualFile vFile = event.getFile();
PsiDirectory oldParentDir = myFileManager.findDirectory(event.getOldParent());
PsiDirectory newParentDir = myFileManager.findDirectory(event.getNewParent());
@@ -515,7 +511,7 @@ public final class PsiVFSListener implements BulkFileListener {
if (oldProject != null && oldProject != myProject) {
// file moved between projects, remove all associations to the old project
myFileManager.removeFilesAndDirsRecursively(vFile);
// avoid crash in filePointer.getElement()
// avoiding crashes in filePointer.getElement()
PsiCopyPasteManager.getInstance().fileMovedOutsideProject(vFile);
oldElement = null;
oldParentDir = null;
@@ -530,15 +526,15 @@ public final class PsiVFSListener implements BulkFileListener {
for (int i = 0; i < events.size(); i++) {
VFileMoveEvent event = (VFileMoveEvent)events.get(i);
final VirtualFile vFile = event.getFile();
VirtualFile vFile = event.getFile();
final PsiDirectory oldParentDir = oldParentDirs.get(i);
final PsiDirectory newParentDir = newParentDirs.get(i);
PsiDirectory oldParentDir = oldParentDirs.get(i);
PsiDirectory newParentDir = newParentDirs.get(i);
if (oldParentDir == null && newParentDir == null) continue;
final PsiElement oldElement = oldElements.get(i);
final PsiElement newElement;
final FileViewProvider newViewProvider;
PsiElement oldElement = oldElements.get(i);
PsiElement newElement;
FileViewProvider newViewProvider;
if (vFile.isDirectory()) {
newElement = myFileManager.findDirectory(vFile);
newViewProvider = null;
@@ -592,14 +588,14 @@ public final class PsiVFSListener implements BulkFileListener {
}
}
@Nullable
private PsiFile createFileCopyWithNewName(VirtualFile vFile, String name) {
private @Nullable PsiFile createFileCopyWithNewName(VirtualFile vFile, String name) {
// TODO[ik] remove this. Event handling and generation must be in view providers mechanism since we
// need to track changes in _all_ psi views (e.g. namespace changes in XML)
var typeManager = FileTypeManager.getInstance();
if (typeManager.isFileIgnored(name)) return null;
var fileType = typeManager.getFileTypeByFileName(name);
return PsiFileFactory.getInstance(myManager.getProject()).createFileFromText(name, fileType, "", vFile.getModificationStamp(), true, false);
FileTypeManager instance = FileTypeManager.getInstance();
if (instance.isFileIgnored(name)) return null;
FileType fileTypeByFileName = instance.getFileTypeByFileName(name);
return PsiFileFactory.getInstance(myManager.getProject()).createFileFromText(
name, fileTypeByFileName, "", vFile.getModificationStamp(), true, false);
}
private static final class MyModuleRootListener implements ModuleRootListener {
@@ -613,7 +609,7 @@ public final class PsiVFSListener implements BulkFileListener {
}
@Override
public void beforeRootsChange(@NotNull final ModuleRootEvent event) {
public void beforeRootsChange(@NotNull ModuleRootEvent event) {
if (event.isCausedByFileTypesChange()) return;
ApplicationManager.getApplication().runWriteAction(
(ExternalChangeAction)() -> {
@@ -628,7 +624,7 @@ public final class PsiVFSListener implements BulkFileListener {
}
@Override
public void rootsChanged(@NotNull final ModuleRootEvent event) {
public void rootsChanged(@NotNull ModuleRootEvent event) {
fileManager.dispatchPendingEvents();
if (event.isCausedByFileTypesChange()) return;
@@ -750,13 +746,12 @@ public final class PsiVFSListener implements BulkFileListener {
myReportedUnloadedPsiChange = false;
}
// group same type events together and call fireForGrouped() for each batch
// grouping events of the same type together and calling fireForGrouped() for each batch
private void groupAndFire(@NotNull List<? extends VFileEvent> events) {
StreamEx.of(events)
// group several VFileDeleteEvents together, several VFileMoveEvents together, place all other events into one-element lists
.groupRuns((event1, event2) ->
event1 instanceof VFileDeleteEvent && event2 instanceof VFileDeleteEvent
|| event1 instanceof VFileMoveEvent && event2 instanceof VFileMoveEvent)
.groupRuns((e1, e2) -> e1 instanceof VFileDeleteEvent && e2 instanceof VFileDeleteEvent ||
e1 instanceof VFileMoveEvent && e2 instanceof VFileMoveEvent)
.forEach(this::fireForGrouped);
}
@@ -772,15 +767,15 @@ public final class PsiVFSListener implements BulkFileListener {
assert subList.size() == 1;
if (event instanceof VFileCopyEvent) {
VFileCopyEvent ce = (VFileCopyEvent)event;
final VirtualFile copy = ce.getNewParent().findChild(ce.getNewChildName());
VirtualFile copy = ce.getNewParent().findChild(ce.getNewChildName());
if (copy != null) {
fileCreated(copy); // no need to group creation
fileCreated(copy); // no need to group file creation events
}
}
else if (event instanceof VFileCreateEvent) {
VirtualFile file = event.getFile();
if (file != null) {
fileCreated(file); // no need to group creation
fileCreated(file); // no need to group file creation events
}
}
else if (event instanceof VFilePropertyChangeEvent) {
@@ -789,4 +784,3 @@ public final class PsiVFSListener implements BulkFileListener {
}
}
}