[vfs][refactoring] more helper methods to CaseSensitivity enum

GitOrigin-RevId: 37bcb5c411f85db3cc69b289e9e2b8bd0cb12e5b
This commit is contained in:
Ruslan Cheremin
2025-07-27 15:22:38 +00:00
committed by intellij-monorepo-bot
parent 48e5349bbe
commit 4232396663
9 changed files with 119 additions and 46 deletions
@@ -192,11 +192,7 @@ public abstract class CompilerReferenceServiceBase<Reader extends CompilerRefere
if (basePath != null) {
File file = new File(basePath);
FileAttributes.CaseSensitivity sensitivity = FileSystemUtil.readParentCaseSensitivity(file);
return switch (sensitivity) {
case UNKNOWN -> SystemInfo.isFileSystemCaseSensitive;
case SENSITIVE -> true;
case INSENSITIVE -> false;
};
return sensitivity.toBooleanWithDefault(SystemInfo.isFileSystemCaseSensitive);
}
}
}
@@ -1,8 +1,9 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.util.projectWizard.importSources.util;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileSystemUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
@@ -78,11 +79,8 @@ public abstract class CommonSourceRootDetectionUtil<F> {
@Override
protected boolean isCaseSensitive(@NotNull File file) {
return switch (FileSystemUtil.readParentCaseSensitivity(file)) {
case SENSITIVE -> true;
case INSENSITIVE -> false;
case UNKNOWN -> SystemInfo.isFileSystemCaseSensitive;
};
FileAttributes.CaseSensitivity sensitivity = FileSystemUtil.readParentCaseSensitivity(file);
return sensitivity.toBooleanWithDefault(SystemInfo.isFileSystemCaseSensitive);
}
@Override
@@ -1,8 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.vfs.newvfs;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileAttributes.CaseSensitivity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.newvfs.events.ChildInfo;
import com.intellij.openapi.vfs.newvfs.persistent.FSRecords;
@@ -93,8 +92,8 @@ public final class ChildInfoImpl implements ChildInfo {
var isSpecial = attributes.isSpecial();
var isHidden = attributes.isHidden();
var sensitivity = attributes.areChildrenCaseSensitive();
var isCaseSensitive = sensitivity == CaseSensitivity.SENSITIVE;
var isCaseSensitivityKnown = sensitivity != CaseSensitivity.UNKNOWN;
var isCaseSensitive = sensitivity.isSensitive();
var isCaseSensitivityKnown = sensitivity.isKnown();
return PersistentFSImpl.fileAttributesToFlags(isDirectory, isWritable, isSymLink, isSpecial, isHidden, isCaseSensitivityKnown, isCaseSensitive);
}
@@ -237,7 +237,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
*/
@ApiStatus.Internal
public void setCaseSensitivityFlag(@NotNull CaseSensitivity newSensitivity) {
if (newSensitivity == CaseSensitivity.UNKNOWN) {
//TODO RC: use newSensitivity: boolean, instead of CaseSensitivity -- this way the absence of UNKNOWN is definitive
if (newSensitivity.isUnknown()) {
throw new IllegalArgumentException("invalid argument for " + this + ": " + newSensitivity);
}
@@ -246,7 +247,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
VfsData vfsData = getVfsData();
VfsData.Segment segment = vfsData.getSegment(getId(), false);
int newFlags = VfsDataFlags.CHILDREN_CASE_SENSITIVITY_CACHED |
(newSensitivity == CaseSensitivity.SENSITIVE ? VfsDataFlags.CHILDREN_CASE_SENSITIVE : 0);
(newSensitivity.isSensitive() ? VfsDataFlags.CHILDREN_CASE_SENSITIVE : 0);
segment.setFlags(getId(), VfsDataFlags.CHILDREN_CASE_SENSITIVE | VfsDataFlags.CHILDREN_CASE_SENSITIVITY_CACHED, newFlags);
//children are sorted by name => case-sensitivity change requires re-sorting:
@@ -321,8 +322,8 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
(PersistentFS.isSpecialFile(attributes) ? VfsDataFlags.IS_SPECIAL_FLAG : 0) |
(PersistentFS.isWritable(attributes) ? VfsDataFlags.IS_WRITABLE_FLAG : 0) |
(PersistentFS.isHidden(attributes) ? VfsDataFlags.IS_HIDDEN_FLAG : 0) |
(sensitivity != CaseSensitivity.UNKNOWN ? VfsDataFlags.CHILDREN_CASE_SENSITIVITY_CACHED : 0) |
(sensitivity == CaseSensitivity.SENSITIVE ? VfsDataFlags.CHILDREN_CASE_SENSITIVE : 0) |
(sensitivity.isKnown() ? VfsDataFlags.CHILDREN_CASE_SENSITIVITY_CACHED : 0) |
(sensitivity.isSensitive() ? VfsDataFlags.CHILDREN_CASE_SENSITIVE : 0) |
(PersistentFS.isOfflineByDefault(attributes) ? VfsDataFlags.IS_OFFLINE : 0);
int relevantFlagsMask = VfsDataFlags.IS_SYMLINK_FLAG |
VfsDataFlags.IS_SPECIAL_FLAG |
@@ -376,7 +377,7 @@ public class VirtualDirectoryImpl extends VirtualFileSystemEntry {
// fire event asynchronously to avoid deadlocks with possibly currently held VFP/Refresh queue locks
RefreshQueue.getInstance().processEvents(/*async: */ true, List.of(caseSensitivityEvent));
}
else if (getChildrenCaseSensitivity() == CaseSensitivity.UNKNOWN) {
else if (getChildrenCaseSensitivity().isUnknown()) {
// Fallback: cache 'default' case sensitivity when we failed to read it from the disk, to avoid freezes on
// constant attempts to re-read -- but do not save the new value in persistence:
CaseSensitivity defaultCaseSensitivity = CaseSensitivity.fromBoolean(getFileSystem().isCaseSensitive());
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.vfs.newvfs.persistent;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileAttributes.CaseSensitivity;
import com.intellij.openapi.vfs.DiskQueryRelay;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.ManagingFS;
@@ -80,17 +80,15 @@ public abstract class PersistentFS extends ManagingFS {
public static boolean isHidden(@Attributes int attributes) { return isSet(attributes, Flags.IS_HIDDEN); }
public static boolean isOfflineByDefault(@Attributes int attributes) { return isSet(attributes, Flags.OFFLINE_BY_DEFAULT); }
public static @NotNull FileAttributes.CaseSensitivity areChildrenCaseSensitive(@Attributes int attributes) {
public static @NotNull CaseSensitivity areChildrenCaseSensitive(@Attributes int attributes) {
if (!isDirectory(attributes)) {
throw new IllegalArgumentException(
"CHILDREN_CASE_SENSITIVE flag defined for directories only but got file: 0b" + Integer.toBinaryString(attributes));
}
if (!isSet(attributes, Flags.CHILDREN_CASE_SENSITIVITY_CACHED)) {
return FileAttributes.CaseSensitivity.UNKNOWN;
return CaseSensitivity.UNKNOWN;
}
return isSet(attributes, Flags.CHILDREN_CASE_SENSITIVE)
? FileAttributes.CaseSensitivity.SENSITIVE
: FileAttributes.CaseSensitivity.INSENSITIVE;
return CaseSensitivity.fromBoolean(isSet(attributes, Flags.CHILDREN_CASE_SENSITIVE));
}
public abstract int storeUnlinkedContent(byte @NotNull [] bytes);
@@ -2245,7 +2245,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
@ApiStatus.Internal
public VFilePropertyChangeEvent determineCaseSensitivityAndPrepareUpdate(@NotNull VirtualFile parent,
@NotNull String childName) {
if (((VirtualDirectoryImpl)parent).getChildrenCaseSensitivity() != CaseSensitivity.UNKNOWN) {
if (((VirtualDirectoryImpl)parent).getChildrenCaseSensitivity().isKnown()) {
//do not update case-sensitivity once determined: assume folder case-sensitivity is constant through the run
// time of an app -- which is, strictly speaking, incorrect, but we don't want to process those cases so far
return null;
@@ -2276,7 +2276,7 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
@ApiStatus.Internal
public VFilePropertyChangeEvent prepareCaseSensitivityUpdateIfNeeded(@NotNull VirtualFile dir,
@NotNull CaseSensitivity actualCaseSensitivity) {
if (actualCaseSensitivity == CaseSensitivity.UNKNOWN) {
if (actualCaseSensitivity.isUnknown()) {
return null;
}
@@ -2607,9 +2607,10 @@ public final class PersistentFSImpl extends PersistentFS implements Disposable {
static @Attributes int fileAttributesToFlags(@NotNull FileAttributes attributes) {
CaseSensitivity sensitivity = attributes.areChildrenCaseSensitive();
boolean isCaseSensitive = sensitivity == CaseSensitivity.SENSITIVE;
return fileAttributesToFlags(attributes.isDirectory(), attributes.isWritable(), attributes.isSymLink(), attributes.isSpecial(),
attributes.isHidden(), sensitivity != CaseSensitivity.UNKNOWN, isCaseSensitive);
return fileAttributesToFlags(
attributes.isDirectory(), attributes.isWritable(), attributes.isSymLink(), attributes.isSpecial(), attributes.isHidden(),
sensitivity.isKnown(), sensitivity.isSensitive()
);
}
public static @Attributes int fileAttributesToFlags(boolean isDirectory,
+8
View File
@@ -27,6 +27,14 @@ c:com.intellij.openapi.util.UserDataHolderBase
- java.util.concurrent.atomic.AtomicReference
- com.intellij.openapi.util.UserDataHolderEx
- *:isCopyableDataEqual(com.intellij.openapi.util.UserDataHolderBase):Z
e:com.intellij.openapi.util.io.FileAttributes$CaseSensitivity
- java.lang.Enum
- *:isInsensitive():Z
- *:isKnown():Z
- *:isSensitive():Z
- *:isUnknown():Z
- *:toBooleanOrFail():Z
- *:toBooleanWithDefault(Z):Z
f:com.intellij.openapi.util.io.NioFiles
- *s:copyRecursively(java.nio.file.Path,java.nio.file.Path):V
- *s:copyRecursively(java.nio.file.Path,java.nio.file.Path,java.util.function.Consumer):V
@@ -2,6 +2,7 @@
package com.intellij.openapi.util.io;
import com.intellij.openapi.util.SystemInfo;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,6 +28,50 @@ public final class FileAttributes {
/** Case sensitivity is not specified - either because not yet known or not applicable (to non-directories) */
UNKNOWN;
@ApiStatus.Experimental
public boolean isSensitive() {
return this == SENSITIVE;
}
@ApiStatus.Experimental
public boolean isInsensitive() {
return this == INSENSITIVE;
}
@ApiStatus.Experimental
public boolean isUnknown() {
return this == UNKNOWN;
}
@ApiStatus.Experimental
public boolean isKnown() {
return this != UNKNOWN;
}
@ApiStatus.Experimental
public boolean toBooleanWithDefault(boolean defaultIfUnknown) {
//@formatter:off
switch (this){
case SENSITIVE: return true;
case INSENSITIVE: return false;
case UNKNOWN: return defaultIfUnknown;
}
//@formatter:on
throw new AssertionError(this + " is unrecognized");
}
@ApiStatus.Experimental
public boolean toBooleanOrFail() {
//@formatter:off
switch (this){
case SENSITIVE: return true;
case INSENSITIVE: return false;
case UNKNOWN: throw new IllegalStateException("case sensitivity is UNKNOWN");
}
//@formatter:on
throw new AssertionError(this + " is unrecognized");
}
public static CaseSensitivity fromBoolean(boolean isCaseSensitive) {
return isCaseSensitive ? SENSITIVE : INSENSITIVE;
}
@@ -44,7 +89,7 @@ public final class FileAttributes {
* <p>Bits 0-2: modifiers ({@link #SYM_LINK}, {@link #HIDDEN}, {@link #READ_ONLY})</p>
* <p>Bits 3-4: {@link Type Type} (00=unknown, 01={@link Type#FILE FILE}, 10={@link Type#DIRECTORY DIRECTORY}, 11={@link Type#SPECIAL SPECIAL})</p>
* <p>Bits 5-7: {@link CaseSensitivity CaseSensitivity} (00={@link CaseSensitivity#UNKNOWN UNKNOWN},
* 01={@link CaseSensitivity#SENSITIVE SENSITIVE}, 10={@link CaseSensitivity#INSENSITIVE INSENSITIVE})</p>
* 01={@link CaseSensitivity#SENSITIVE SENSITIVE}, 10={@link CaseSensitivity#INSENSITIVE INSENSITIVE})</p>
*/
private final byte flags;
@@ -60,7 +105,13 @@ public final class FileAttributes {
*/
public final long lastModified;
public FileAttributes(boolean isDirectory, boolean isSpecial, boolean isSymlink, boolean isHidden, long length, long lastModified, boolean isWritable) {
public FileAttributes(boolean isDirectory,
boolean isSpecial,
boolean isSymlink,
boolean isHidden,
long length,
long lastModified,
boolean isWritable) {
this(isDirectory, isSpecial, isSymlink, isHidden, length, lastModified, isWritable, CaseSensitivity.UNKNOWN);
}
@@ -72,7 +123,13 @@ public final class FileAttributes {
* When {@code isDirectory == false}, the caseSensitivity argument is ignored
* (set to {@link CaseSensitivity#UNKNOWN}), because case sensitivity is configured on a directory level.
*/
public FileAttributes(boolean isDirectory, boolean isSpecial, boolean isSymlink, boolean isHidden, long length, long lastModified, boolean isWritable,
public FileAttributes(boolean isDirectory,
boolean isSpecial,
boolean isSymlink,
boolean isHidden,
long length,
long lastModified,
boolean isWritable,
@NotNull CaseSensitivity caseSensitivity) {
this(flags(isDirectory, isSpecial, isSymlink, isHidden, isWritable, caseSensitivity), length, lastModified);
}
@@ -90,7 +147,12 @@ public final class FileAttributes {
this.lastModified = lastModified;
}
private static byte flags(boolean isDirectory, boolean isSpecial, boolean isSymlink, boolean isHidden, boolean isWritable, CaseSensitivity sensitivity) {
private static byte flags(boolean isDirectory,
boolean isSpecial,
boolean isSymlink,
boolean isHidden,
boolean isWritable,
CaseSensitivity sensitivity) {
byte flags = 0;
if (isSymlink) flags |= SYM_LINK;
if (isHidden) flags |= HIDDEN;
@@ -102,7 +164,7 @@ public final class FileAttributes {
}
private static byte packSensitivityIntoFlags(CaseSensitivity sensitivity, byte flags) {
int sensitivity_flags = sensitivity == CaseSensitivity.UNKNOWN ? 0 : sensitivity == CaseSensitivity.SENSITIVE ? 1 : 2;
int sensitivity_flags = sensitivity.isUnknown() ? 0 : sensitivity.isSensitive() ? 1 : 2;
flags |= sensitivity_flags << CASE_SENSITIVITY_SHIFT;
return flags;
}
@@ -134,10 +196,14 @@ public final class FileAttributes {
public @Nullable("`null` means an unknown type, typically a broken symlink") Type getType() {
int type = (flags >> TYPE_SHIFT) & 0b11;
switch (type) {
case 0b00: return null;
case 0b01: return Type.FILE;
case 0b10: return Type.DIRECTORY;
case 0b11: return Type.SPECIAL;
case 0b00:
return null;
case 0b01:
return Type.FILE;
case 0b10:
return Type.DIRECTORY;
case 0b11:
return Type.SPECIAL;
}
throw new IllegalStateException("Invalid type flags: " + Integer.toBinaryString(flags));
}
@@ -148,9 +214,12 @@ public final class FileAttributes {
}
int sensitivity_flags = (flags >> CASE_SENSITIVITY_SHIFT) & 0b11;
switch (sensitivity_flags) {
case 0b00: return CaseSensitivity.UNKNOWN;
case 0b01: return CaseSensitivity.SENSITIVE;
case 0b10: return CaseSensitivity.INSENSITIVE;
case 0b00:
return CaseSensitivity.UNKNOWN;
case 0b01:
return CaseSensitivity.SENSITIVE;
case 0b10:
return CaseSensitivity.INSENSITIVE;
}
throw new IllegalStateException("Invalid sensitivity flags: " + Integer.toBinaryString(sensitivity_flags));
}
@@ -231,11 +300,14 @@ public final class FileAttributes {
else {
try {
isWritable = isDirectory || Files.isWritable(path);
} catch (SecurityException ignored) { }
}
catch (SecurityException ignored) {
}
}
long lastModified = attrs.lastModifiedTime().toMillis();
//MAYBE RC: request case-sensitivity from FileSystemUtil.readParentCaseSensitivity() if it is unknown?
CaseSensitivity caseSensitivity = (isDirectory && attrs instanceof CaseSensitivityAttribute) ?
((CaseSensitivityAttribute)attrs).getCaseSensitivity() :
CaseSensitivity.UNKNOWN;
@@ -129,7 +129,7 @@ public final class FileSystemUtil {
@ApiStatus.Internal
public static @NotNull FileAttributes.CaseSensitivity readParentCaseSensitivity(@NotNull java.io.File anyChild) {
FileAttributes.CaseSensitivity detected = readCaseSensitivityByNativeAPI(anyChild);
if (detected != com.intellij.openapi.util.io.FileAttributes.CaseSensitivity.UNKNOWN) return detected;
if (detected.isKnown()) return detected;
// native queries failed, fallback to the Java I/O:
return readParentCaseSensitivityByJavaIO(anyChild);
}