diff --git a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceBase.java b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceBase.java index 55db5f2c9464..a55da6b70186 100644 --- a/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceBase.java +++ b/java/compiler/impl/src/com/intellij/compiler/backwardRefs/CompilerReferenceServiceBase.java @@ -192,11 +192,7 @@ public abstract class CompilerReferenceServiceBase SystemInfo.isFileSystemCaseSensitive; - case SENSITIVE -> true; - case INSENSITIVE -> false; - }; + return sensitivity.toBooleanWithDefault(SystemInfo.isFileSystemCaseSensitive); } } } diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/util/CommonSourceRootDetectionUtil.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/util/CommonSourceRootDetectionUtil.java index 10d752fc45b9..c663711066f0 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/util/CommonSourceRootDetectionUtil.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/util/CommonSourceRootDetectionUtil.java @@ -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 { @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 diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/ChildInfoImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/ChildInfoImpl.java index 9cd14301fb8b..0784f2f66f22 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/ChildInfoImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/ChildInfoImpl.java @@ -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); } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java index 9256e08a66af..5caf8924eb5a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VirtualDirectoryImpl.java @@ -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()); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java index 6e8ffbe34e21..ba10fae698a4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFS.java @@ -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); diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java index 42d3fb517439..0f4abc7d91a6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java @@ -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, diff --git a/platform/util/api-dump-experimental.txt b/platform/util/api-dump-experimental.txt index e00e8ad745d7..27d2ee872e64 100644 --- a/platform/util/api-dump-experimental.txt +++ b/platform/util/api-dump-experimental.txt @@ -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 diff --git a/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java b/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java index 4a7a5ac12d74..992b110c5112 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileAttributes.java @@ -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 { *

Bits 0-2: modifiers ({@link #SYM_LINK}, {@link #HIDDEN}, {@link #READ_ONLY})

*

Bits 3-4: {@link Type Type} (00=unknown, 01={@link Type#FILE FILE}, 10={@link Type#DIRECTORY DIRECTORY}, 11={@link Type#SPECIAL SPECIAL})

*

Bits 5-7: {@link CaseSensitivity CaseSensitivity} (00={@link CaseSensitivity#UNKNOWN UNKNOWN}, - * 01={@link CaseSensitivity#SENSITIVE SENSITIVE}, 10={@link CaseSensitivity#INSENSITIVE INSENSITIVE})

+ * 01={@link CaseSensitivity#SENSITIVE SENSITIVE}, 10={@link CaseSensitivity#INSENSITIVE INSENSITIVE})

*/ 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; diff --git a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java index ea5de82612f6..0ccd6adf7e67 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileSystemUtil.java @@ -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); }