IDEA-144745 Some kind of incorrect saving/loading of VirtualFile flags/userdata break...
authorAleksey Zezukin <aleksey.zezukin@jetbrains.com>
Fri, 4 Sep 2015 19:31:40 +0000 (22:31 +0300)
committerAleksey Zezukin <aleksey.zezukin@jetbrains.com>
Fri, 4 Sep 2015 19:33:56 +0000 (22:33 +0300)
reverting cda5507 and a757517 to fix show-stopper bug CPP-4431

platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java
platform/platform-tests/testSrc/com/intellij/openapi/fileTypes/impl/FileTypesTest.java
platform/util-rt/src/com/intellij/openapi/util/io/FileUtilRt.java
platform/util/src/com/intellij/openapi/util/io/FileUtil.java

index f5936bd40e39d1606f05941578347daa1ed76381..5998c7e432a8191e957a1ef54977faa1e84321ad 100644 (file)
@@ -35,7 +35,6 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.*;
 import com.intellij.openapi.util.io.ByteSequence;
 import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.io.FileUtilRt;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.util.text.StringUtilRt;
 import com.intellij.openapi.vfs.*;
@@ -63,7 +62,6 @@ import org.jetbrains.annotations.TestOnly;
 
 import java.io.*;
 import java.net.URL;
-import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -81,20 +79,13 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   private static final int VERSION = 15;
   private static final Key<FileType> FILE_TYPE_KEY = Key.create("FILE_TYPE_KEY");
   // cached auto-detected file type. If the file was auto-detected as plain text or binary
-  // then the value is null and AUTO_DETECTED_* flags stored in packedFlags are used instead.
+  // then the value is null and autoDetectedAsText, autoDetectedAsBinary and autoDetectWasRun sets are used instead.
   private static final Key<FileType> DETECTED_FROM_CONTENT_FILE_TYPE_KEY = Key.create("DETECTED_FROM_CONTENT_FILE_TYPE_KEY");
   private static final int DETECT_BUFFER_SIZE = 8192; // the number of bytes to read from the file to feed to the file type detector
 
   // must be sorted
-  private static final String DEFAULT_IGNORED = "*.hprof;*.pyc;*.pyo;*.rbc;*~;.DS_Store;.git;.hg;.svn;.tox;CVS;RCS;SCCS;__pycache__;_svn;rcs;vssver.scc;vssver2.scc;";
-  static {
-    List<String> strings = StringUtil.split(DEFAULT_IGNORED, ";");
-    for (int i = 0; i < strings.size(); i++) {
-      String string = strings.get(i);
-      String prev = i==0?"":strings.get(i-1);
-      assert prev.compareTo(string) < 0 : "DEFAULT_IGNORED must be sorted, but got: '"+prev+"' >= '"+string+"'";
-    }
-  }
+  private static final String DEFAULT_IGNORED =
+    "*.hprof;*.pyc;*.pyo;*.rbc;*~;.DS_Store;.git;.hg;.svn;.tox;CVS;RCS;SCCS;__pycache__;_svn;rcs;vssver.scc;vssver2.scc;";
 
   private static boolean RE_DETECT_ASYNC = !ApplicationManager.getApplication().isUnitTestMode();
   private final Set<FileType> myDefaultTypes = new THashSet<FileType>();
@@ -137,14 +128,10 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   static final String FILE_SPEC = "filetypes";
 
   // these flags are stored in 'packedFlags' as chunks of four bits
-  private static final byte AUTO_DETECTED_AS_TEXT_MASK = 1<<0;     // set if the file was auto-detected as text
-  private static final byte AUTO_DETECTED_AS_BINARY_MASK = 1<<1;   // set if the file was auto-detected as binary
-
-  // set if auto-detection was performed for this file.
-  // if some detector returned some custom file type, it's stored in DETECTED_FROM_CONTENT_FILE_TYPE_KEY file key.
-  // otherwise if auto-detected as text or binary, the result is stored in AUTO_DETECTED_AS_TEXT_MASK|AUTO_DETECTED_AS_BINARY_MASK bits
-  private static final byte AUTO_DETECT_WAS_RUN_MASK = 1<<2;
-  private static final byte ATTRIBUTES_WERE_LOADED_MASK = 1<<3;    // set if AUTO_* bits above were loaded from the file persistent attributes and saved to packedFlags
+  private static final int AUTO_DETECTED_AS_TEXT_MASK = 1;     // set if the file was auto-detected as text
+  private static final int AUTO_DETECTED_AS_BINARY_MASK = 2;   // set if the file was auto-detected as binary
+  private static final int AUTO_DETECT_WAS_RUN_MASK = 4;       // set if auto-detection was performed for this file
+  private static final int ATTRIBUTES_WERE_LOADED_MASK = 8;    // set if AUTO_* bits above were loaded from the file persistent attributes
   private final ConcurrentPackedBitsArray packedFlags = new ConcurrentPackedBitsArray(4);
 
   private final AtomicInteger counterAutoDetect = new AtomicInteger();
@@ -323,7 +310,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     return toLog;
   }
 
-  private static void log(String message) {
+  private static void log(@SuppressWarnings("UnusedParameters") String message) {
     System.out.println(message);
   }
 
@@ -359,26 +346,17 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
         log("F: Redetect file: " + file.getName() + "; shouldRedetect: " + shouldRedetect);
       }
       if (shouldRedetect) {
-        int id = ((VirtualFileWithId)file).getId();
-        long flags = packedFlags.get(id);
-        FileType before = fromCachedFlags(file, flags);
+        int id = file instanceof VirtualFileWithId ? ((VirtualFileWithId)file).getId() : -1;
+        FileType before = getAutoDetectedType(file, id);
 
+        int flags = ATTRIBUTES_WERE_LOADED_MASK;
+        packedFlags.set(id, flags);
         if (toLog()) {
           log("F: reDetect("+file.getName()+") prepare to redetect. flags: "+flags);
         }
 
-        FileType after = getOrDetectByFile(file);
-
-        if (after == null) {
-          after = detectFromContentAndCache(file);
-        }
-        else {
-          // back to standard file type
-          // detected by conventional methods, no need to run detect-from-content
-          file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null);
-          flags = 0;
-          packedFlags.set(id, flags);
-        }
+        file.putUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY, null);
+        FileType after = getFileTypeByFile(file); // may be back to standard file type
         if (toLog()) {
           log("F: After redetect file: " + file.getName() + "; before: " + before.getName() + "; after: " + after.getName()+"; now getFileType()="+file.getFileType().getName());
         }
@@ -463,17 +441,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   @Override
   @NotNull
   public FileType getFileTypeByFile(@NotNull VirtualFile file) {
-    FileType fileType = getOrDetectByFile(file);
-
-    if (fileType == null) {
-      fileType = file instanceof StubVirtualFile ? UnknownFileType.INSTANCE : getOrDetectFromContent(file);
-    }
-
-    return fileType;
-  }
-
-  @Nullable // null means all conventional detect methods returned UnknownFileType.INSTANCE, have to detect from content
-  private FileType getOrDetectByFile(@NotNull VirtualFile file) {
     FileType fileType = file.getUserData(FILE_TYPE_KEY);
     if (fileType != null) return fileType;
 
@@ -498,7 +465,12 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
       }
       return fileType;
     }
-    return null;
+
+    if (!(file instanceof StubVirtualFile)) {
+      fileType = getOrDetectFromContent(file);
+    }
+
+    return fileType;
   }
 
   @NotNull
@@ -509,28 +481,32 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
       if (id < 0) return UnknownFileType.INSTANCE;
 
       long flags = packedFlags.get(id);
+      boolean autoDetectWasRun = (flags & AUTO_DETECT_WAS_RUN_MASK) != 0;
+      if (autoDetectWasRun) {
+        FileType type = getAutoDetectedType(file, id);
+        if (toLog()) {
+          log("F: autodetected getFileType("+file.getName()+") = "+type.getName()+"; packedFlags.get(id):"+flags);
+        }
+        return type;
+      }
       if ((flags & ATTRIBUTES_WERE_LOADED_MASK) == 0) {
         flags = readFlagsFromCache(file);
-        flags = BitUtil.set(flags, ATTRIBUTES_WERE_LOADED_MASK, true);
-
         packedFlags.set(id, flags);
         if (toLog()) {
           log("F: readFlagsFromCache("+file.getName()+") = "+flags);
         }
       }
-      boolean autoDetectWasRun = (flags & AUTO_DETECT_WAS_RUN_MASK) != 0;
-      if (autoDetectWasRun) {
-        FileType type = fromCachedFlags(file, flags);
-        if (toLog()) {
-          log("F: autodetected getFileType("+file.getName()+") = "+type.getName()+"; packedFlags.get(id):"+flags+"; DETECTED_FROM_CONTENT_FILE_TYPE_KEY: "+file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY));
-        }
-        return type;
+      boolean wasDetectedAsText = BitUtil.isSet(flags, AUTO_DETECTED_AS_TEXT_MASK);
+      boolean wasDetectedAsBinary = BitUtil.isSet(flags, AUTO_DETECTED_AS_BINARY_MASK);
+      boolean wasAutoDetectRun = BitUtil.isSet(flags, AUTO_DETECT_WAS_RUN_MASK);
+      if (wasAutoDetectRun && (wasDetectedAsText || wasDetectedAsBinary)) {
+        return wasDetectedAsText ? FileTypes.PLAIN_TEXT : UnknownFileType.INSTANCE;
       }
     }
     FileType fileType = file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY);
     // run autodetection
     if (fileType == null) {
-      fileType = detectFromContentAndCache(file);
+      fileType = detectFromContent(file);
     }
 
     if (toLog()) {
@@ -541,8 +517,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   }
 
   private volatile FileAttribute autoDetectedAttribute;
-  // read auto-detection flags from the persistent FS file attributes. If file attributes are absent, return 0 for flags
-  // returns three bits value for AUTO_DETECTED_AS_TEXT_MASK, AUTO_DETECTED_AS_BINARY_MASK and AUTO_DETECT_WAS_RUN_MASK bits
   protected byte readFlagsFromCache(@NotNull VirtualFile file) {
     DataInputStream stream = autoDetectedAttribute.readAttribute(file);
     boolean wasAutoDetectRun = false;
@@ -560,18 +534,17 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     }
     catch (IOException ignored) {
     }
-    status = BitUtil.set(status, AUTO_DETECT_WAS_RUN_MASK, wasAutoDetectRun);
+    status = (byte)BitUtil.set(status, AUTO_DETECT_WAS_RUN_MASK, wasAutoDetectRun);
+    status = (byte)BitUtil.set(status, ATTRIBUTES_WERE_LOADED_MASK, true);
 
-    return (byte)(status & (AUTO_DETECTED_AS_TEXT_MASK | AUTO_DETECTED_AS_BINARY_MASK | AUTO_DETECT_WAS_RUN_MASK));
+    return status;
   }
 
-  // store auto-detection flags to the persistent FS file attributes
-  // writes AUTO_DETECTED_AS_TEXT_MASK, AUTO_DETECTED_AS_BINARY_MASK bits only
   protected void writeFlagsToCache(@NotNull VirtualFile file, int flags) {
     DataOutputStream stream = autoDetectedAttribute.writeAttribute(file);
     try {
       try {
-        stream.writeByte(flags & (AUTO_DETECTED_AS_TEXT_MASK | AUTO_DETECTED_AS_BINARY_MASK));
+        stream.writeByte(flags);
       }
       finally {
         stream.close();
@@ -593,7 +566,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   }
 
   @NotNull
-  private static FileType fromCachedFlags(@NotNull VirtualFile file, long flags) {
+  private FileType getAutoDetectedType(@NotNull VirtualFile file, int id) {
+    long flags = packedFlags.get(id);
     return BitUtil.isSet(flags, AUTO_DETECTED_AS_TEXT_MASK) ? FileTypes.PLAIN_TEXT :
            BitUtil.isSet(flags, AUTO_DETECTED_AS_BINARY_MASK) ? UnknownFileType.INSTANCE :
            ObjectUtils.notNull(file.getUserData(DETECTED_FROM_CONTENT_FILE_TYPE_KEY), FileTypes.PLAIN_TEXT);
@@ -615,8 +589,9 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     writeFlagsToCache(file, flags);
     if (file instanceof VirtualFileWithId) {
       int id = Math.abs(((VirtualFileWithId)file).getId());
-      flags = BitUtil.set(flags, AUTO_DETECT_WAS_RUN_MASK, true);
-      flags = BitUtil.set(flags, ATTRIBUTES_WERE_LOADED_MASK, true);
+      flags = AUTO_DETECT_WAS_RUN_MASK | ATTRIBUTES_WERE_LOADED_MASK;
+      flags = BitUtil.set(flags, AUTO_DETECTED_AS_TEXT_MASK, wasAutodetectedAsText);
+      flags = BitUtil.set(flags, AUTO_DETECTED_AS_BINARY_MASK, wasAutodetectedAsBinary);
       packedFlags.set(id, flags);
       if (toLog()) {
         log("F: cacheAutoDetectedFileType("+file.getName()+") = "+flags);
@@ -653,37 +628,15 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     return file.getFileSystem() instanceof FileSystemInterface && !SingleRootFileViewProvider.isTooLargeForContentLoading(file);
   }
 
-  private static boolean processFirstBytes(@NotNull final InputStream stream, final int length, @NotNull Processor<ByteSequence> processor) throws IOException {
-    final byte[] bytes = FileUtilRt.getThreadLocalBuffer();
-    assert bytes.length >= length : "Cannot process more than " + bytes.length + " in one call, requested:" + length;
-
-    int n = stream.read(bytes, 0, length);
-    if (n <= 0) {
-      // maybe locked because someone else is writing to it
-      // repeat inside read action to guarantee all writes are finished
-      n = ApplicationManager.getApplication().runReadAction(new ThrowableComputable<Integer, IOException>() {
-        @Override
-        public Integer compute() throws IOException {
-          return stream.read(bytes, 0, length);
-        }
-      });
-      if (n <= 0) {
-        return false;
-      }
-    }
-
-    return processor.process(new ByteSequence(bytes, 0, n));
-  }
-
   @NotNull
-  private FileType detectFromContentAndCache(@NotNull final VirtualFile file) {
+  private FileType detectFromContent(@NotNull final VirtualFile file) {
     long start = System.currentTimeMillis();
     try {
       final InputStream inputStream = ((FileSystemInterface)file.getFileSystem()).getInputStream(file);
       final Ref<FileType> result = new Ref<FileType>(UnknownFileType.INSTANCE);
-      boolean r = false;
+      boolean r;
       try {
-        r = processFirstBytes(inputStream, DETECT_BUFFER_SIZE, new Processor<ByteSequence>() {
+        r = FileUtil.processFirstBytes(inputStream, DETECT_BUFFER_SIZE, new Processor<ByteSequence>() {
           @Override
           public boolean process(ByteSequence byteSequence) {
             boolean isText = guessIfText(file, byteSequence);
@@ -720,23 +673,23 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
         });
       }
       finally {
-        if (toLog()) {
-          byte[] buffer = new byte[50];
-          InputStream newStream = ((FileSystemInterface)file.getFileSystem()).getInputStream(file);
-          int n = newStream.read(buffer, 0, buffer.length);
-          log("F: Redetect run for file: " + file.getName() + "; result: "+result.get().getName()+"; processor ret: "+r+"; stream: "+streamInfo(inputStream)+"; newStream: "+streamInfo(newStream)+"; read: "+n+"; buffer: "+Arrays.toString(buffer));
-          newStream.close();
-          try {
-            InputStream in = ReflectionUtil.getField(newStream.getClass(), newStream, InputStream.class, "in");
-            String path = ReflectionUtil.getField(in.getClass(), in, String.class, "path");
-            log("F: inputStream.in: " + in + "("+in.getClass()+"; in.path: "+path+"; path.exists "+new File(path).exists()+"; canRead: "+new File(path).canRead());
-          }
-          catch (Exception ignored) {
-          }
-        }
         inputStream.close();
       }
       FileType fileType = result.get();
+      if (toLog()) {
+        byte[] buffer = new byte[50];
+        InputStream newStream = ((FileSystemInterface)file.getFileSystem()).getInputStream(file);
+        int n = newStream.read(buffer, 0, buffer.length);
+        newStream.close();
+        log("F: Redetect run for file: " + file.getName() + "; result: "+fileType.getName()+"; processor ret: "+r+"; stream: "+inputStream+"; newStream: "+newStream+"; read: "+n+"; buffer: "+Arrays.toString(buffer));
+        try {
+          InputStream in = ReflectionUtil.getField(newStream.getClass(), newStream, InputStream.class, "in");
+          String path = ReflectionUtil.getField(in.getClass(), in, String.class, "path");
+          log("F: inputStream.in: " + in + "("+in.getClass()+"; in.path: "+path+"; path.exists "+new File(path).exists()+"; canRead: "+new File(path).canRead());
+        }
+        catch (Exception ignored) {
+        }
+      }
 
       if (LOG.isDebugEnabled()) {
         LOG.debug(file + "; type=" + fileType.getDescription() + "; " + counterAutoDetect);
@@ -754,27 +707,6 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     }
   }
 
-  // for diagnostics
-  private static Object streamInfo(InputStream stream) throws IOException {
-    if (stream instanceof BufferedInputStream) {
-      InputStream in = ReflectionUtil.getField(stream.getClass(), stream, InputStream.class, "in");
-      byte[] buf = ReflectionUtil.getField(stream.getClass(), stream, byte[].class, "buf");
-      int count = ReflectionUtil.getField(stream.getClass(), stream, int.class, "count");
-      int pos = ReflectionUtil.getField(stream.getClass(), stream, int.class, "pos");
-
-      return "BufferedInputStream(buf="+(buf == null ? null : Arrays.toString(Arrays.copyOf(buf, count))) + ", count="+count+ ", pos="+pos+", in="+streamInfo(in)+")";
-    }
-    if (stream instanceof FileInputStream) {
-      String path = ReflectionUtil.getField(stream.getClass(), stream, String.class, "path");
-      FileChannel channel = ReflectionUtil.getField(stream.getClass(), stream, FileChannel.class, "channel");
-      boolean closed = ReflectionUtil.getField(stream.getClass(), stream, boolean.class, "closed");
-      int available = stream.available();
-      File file = new File(path);
-      return "FileInputStream(path="+path+ ", available="+available+ ", closed="+closed+ ", channel="+channel+", channel.size="+(channel==null?null:channel.size())+", file.exists=" + file.exists()+", file.content='"+FileUtil.loadFile(file)+"')";
-    }
-    return stream;
-  }
-
   private static boolean guessIfText(@NotNull VirtualFile file, @NotNull ByteSequence byteSequence) {
     byte[] bytes = byteSequence.getBytes();
     Trinity<Charset, CharsetToolkit.GuessedEncoding, byte[]> guessed = LoadTextUtil.guessFromContent(file, bytes, byteSequence.getLength());
@@ -795,7 +727,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
       return ((FileTypeIdentifiableByVirtualFile)type).isMyFileType(file);
     }
 
-    return getFileTypeByFileName(file.getNameSequence()) == type;
+    return getFileTypeByFileName(file.getName()) == type;
   }
 
   @Override
@@ -1084,7 +1016,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
     }
   }
 
-  @NotNull
+  @Nullable
   @Override
   public Element getState() {
     Element state = new Element("state");
@@ -1399,11 +1331,8 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements Persistent
   @Nullable
   public FileType getKnownFileTypeOrAssociate(@NotNull VirtualFile file) {
     FileType type = file.getFileType();
-    if (type == UnknownFileType.INSTANCE) {
-      type = FileTypeChooser.associateFileType(file.getName());
-    }
-
-    return type;
+    if (type != UnknownFileType.INSTANCE) return type;
+    return FileTypeChooser.getKnownFileTypeOrAssociate(file.getName());
   }
 
   @Override
index 59ae57a54d96df6c60b766485be763fe0b301930..bbd0136c0f7c7cddddb06265006e87ec93463e45 100644 (file)
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.CharsetToolkit;
 import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.PsiManagerEx;
@@ -96,7 +97,7 @@ public class FileTypesTest extends PlatformTestCase {
     checkNotIgnored("ax.cxx");
     checkNotIgnored("ab.cd");
     checkNotIgnored("ab.c__d");
-    checkNotIgnored("xxxx");
+    checkNotIgnored("xx" + "xx");
     checkNotIgnored("xx");
     assertTrue(myFileTypeManager.isIgnoredFilesListEqualToCurrent(pattern2 + ";" + pattern1));
     assertFalse(myFileTypeManager.isIgnoredFilesListEqualToCurrent(pattern2 + ";" + "ab.c*d"));
@@ -111,8 +112,8 @@ public class FileTypesTest extends PlatformTestCase {
     });
     final String[] names = new String[100];
     for (int i = 0; i < names.length; i++) {
-      String name = String.valueOf(i % 10 * 10 + i * 100 + i + 1);
-      names[i] = name + name + name + name;
+      String name = String.valueOf((i%10)*10 + (i*100) + i + 1);
+      names[i] = (name + name + name + name);
     }
     PlatformTestUtil.startPerformanceTest("ignore perf", 700, new ThrowableRunnable() {
       @Override
@@ -172,7 +173,7 @@ public class FileTypesTest extends PlatformTestCase {
     File file = createTempFile(".svn", "");
     VirtualFile vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
     assertTrue(FileTypeManager.getInstance().isFileIgnored(vFile));
-    delete(vFile);
+    vFile.delete(this);
 
     file = createTempFile("a.txt", "");
     vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
@@ -234,7 +235,7 @@ public class FileTypesTest extends PlatformTestCase {
     assertTrue(psi instanceof PsiBinaryFile);
     assertEquals(FileTypes.UNKNOWN, virtualFile.getFileType());
 
-    setBinaryContent(virtualFile, "xxxxxxx".getBytes(CharsetToolkit.UTF8_CHARSET));
+    virtualFile.setBinaryContent("xxxxxxx".getBytes(CharsetToolkit.UTF8_CHARSET));
     assertEquals(FileTypes.PLAIN_TEXT, virtualFile.getFileType());
     PsiFile after = getPsiManager().findFile(virtualFile);
     assertNotSame(psi, after);
@@ -246,8 +247,8 @@ public class FileTypesTest extends PlatformTestCase {
   public void testAutoDetectTextFileFromContents() throws IOException {
     File dir = createTempDirectory();
     VirtualFile vDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(dir);
-    VirtualFile vFile = createChildData(vDir, "test.xxxxxxxx");
-    setFileText(vFile, "text");
+    VirtualFile vFile = vDir.createChildData(this, "test.xxxxxxxx");
+    VfsUtil.saveText(vFile, "text");
     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
 
     assertEquals(PlainTextFileType.INSTANCE, vFile.getFileType()); // type autodetected during indexing
@@ -331,12 +332,12 @@ public class FileTypesTest extends PlatformTestCase {
       assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof PlainTextFileType);
 
       log("T: ------ TYPE:IDEA_MODULE");
-      setFileText(vFile,  "TYPE:IDEA_MODULE");
+      VfsUtil.saveText(vFile, "TYPE:IDEA_MODULE");
       ensureRedetected(vFile, detectorCalled);
       assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ModuleFileType);
 
       log("T: ------ TYPE:IDEA_PROJECT");
-      setFileText(vFile, "TYPE:IDEA_PROJECT");
+      VfsUtil.saveText(vFile, "TYPE:IDEA_PROJECT");
       ensureRedetected(vFile, detectorCalled);
       assertTrue(vFile.getFileType().toString(), vFile.getFileType() instanceof ProjectFileType);
       log("T: ------");
@@ -368,16 +369,10 @@ public class FileTypesTest extends PlatformTestCase {
   }
 
   public void testReassignedPredefinedFileType() throws Exception {
-    final FileType perlFileType = myFileTypeManager.getFileTypeByFileName("foo.pl");
+    FileType perlFileType = myFileTypeManager.getFileTypeByFileName("foo.pl");
     assertEquals("Perl", perlFileType.getName());
     assertEquals(PlainTextFileType.INSTANCE, myFileTypeManager.getFileTypeByFileName("foo.cgi"));
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.associatePattern(perlFileType, "*.cgi");
-      }
-    });
-
+    myFileTypeManager.associatePattern(perlFileType, "*.cgi");
     assertEquals(perlFileType, myFileTypeManager.getFileTypeByFileName("foo.cgi"));
 
     Element element = myFileTypeManager.getState();
@@ -385,13 +380,7 @@ public class FileTypesTest extends PlatformTestCase {
     myFileTypeManager.initComponent();
     assertEquals(perlFileType, myFileTypeManager.getFileTypeByFileName("foo.cgi"));
 
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.removeAssociatedExtension(perlFileType, "*.cgi");
-      }
-    });
-
+    myFileTypeManager.removeAssociatedExtension(perlFileType, "*.cgi");
     myFileTypeManager.clearForTests();
     myFileTypeManager.initStandardFileTypes();
     myFileTypeManager.initComponent();
@@ -421,13 +410,7 @@ public class FileTypesTest extends PlatformTestCase {
 
   // for IDEA-114804 File types mapped to text are not remapped when corresponding plugin is installed
   public void testRemappingToInstalledPluginExtension() throws WriteExternalException, InvalidDataException {
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.associatePattern(PlainTextFileType.INSTANCE, "*.fromPlugin");
-      }
-    });
-
+    myFileTypeManager.associatePattern(PlainTextFileType.INSTANCE, "*.fromPlugin");
     Element element = myFileTypeManager.getState();
     String s = JDOMUtil.writeElement(element);
     log(s);
@@ -504,13 +487,7 @@ public class FileTypesTest extends PlatformTestCase {
       myFileTypeManager.loadState(element);
       myFileTypeManager.initComponent();
 
-      ApplicationManager.getApplication().runWriteAction(new Runnable() {
-        @Override
-        public void run() {
-          myFileTypeManager.associatePattern(typeFromPlugin, "*.foo");
-        }
-      });
-
+      myFileTypeManager.associatePattern(typeFromPlugin, "*.foo");
 
       element = myFileTypeManager.getState();
       log(JDOMUtil.writeElement(element));
@@ -567,39 +544,17 @@ public class FileTypesTest extends PlatformTestCase {
   }
 
   public void testDefaultFileType() throws Exception {
-    final FileType idl = myFileTypeManager.findFileTypeByName("IDL");
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.associatePattern(idl, "*.xxx");
-      }
-    });
-
+    FileType idl = myFileTypeManager.findFileTypeByName("IDL");
+    myFileTypeManager.associatePattern(idl, "*.xxx");
     Element element = myFileTypeManager.getState();
     log(JDOMUtil.writeElement(element));
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.removeAssociatedExtension(idl, "xxx");
-      }
-    });
-
+    myFileTypeManager.removeAssociatedExtension(idl, "xxx");
     myFileTypeManager.clearForTests();
     myFileTypeManager.initStandardFileTypes();
     myFileTypeManager.loadState(element);
     myFileTypeManager.initComponent();
     FileType extensions = myFileTypeManager.getFileTypeByExtension("xxx");
     assertEquals("IDL", extensions.getName());
-    ApplicationManager.getApplication().runWriteAction(new Runnable() {
-      @Override
-      public void run() {
-        myFileTypeManager.removeAssociatedExtension(idl, "xxx");
-      }
-    });
-  }
-
-  @Override
-  protected boolean isRunInWriteAction() {
-    return false;
+    myFileTypeManager.removeAssociatedExtension(idl, "xxx");
   }
 }
index 8a48ba176218b4cc55a3b2ba192bcde0f7596b3f..8b76f8008cd1de1c033795d88083963c8237fb61 100644 (file)
@@ -617,7 +617,13 @@ public class FileUtilRt {
   @NotNull
   public static byte[] loadBytes(@NotNull InputStream stream) throws IOException {
     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-    copy(stream, buffer);
+    final byte[] bytes = BUFFER.get();
+    while (true) {
+      int n = stream.read(bytes, 0, bytes.length);
+      if (n <= 0) break;
+      buffer.write(bytes, 0, n);
+    }
+    buffer.close();
     return buffer.toByteArray();
   }
 
@@ -672,7 +678,7 @@ public class FileUtilRt {
   /**
    * Warning! this method is _not_ symlinks-aware. Consider using com.intellij.openapi.util.io.FileUtil.delete()
    * @param file file or directory to delete
-   * @return true if the file did not exist or was successfully deleted
+   * @return true if the file did not exist or was successfully deleted 
    */
   public static boolean delete(@NotNull File file) {
     if (NIOReflect.IS_AVAILABLE) {
@@ -690,7 +696,7 @@ public class FileUtilRt {
           Files.deleteIfExists(file);
           return FileVisitResult.CONTINUE;
         }
-
+      
         @Override
         public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
           Files.deleteIfExists(dir);
@@ -714,7 +720,7 @@ public class FileUtilRt {
     }
     return !file.exists();
   }
-
+  
   private static boolean deleteRecursively(@NotNull File file) {
     File[] files = file.listFiles();
     if (files != null) {
@@ -837,7 +843,7 @@ public class FileUtilRt {
       }
     }
     else {
-      final byte[] buffer = getThreadLocalBuffer();
+      final byte[] buffer = BUFFER.get();
       while (true) {
         int read = inputStream.read(buffer);
         if (read < 0) break;
@@ -846,12 +852,6 @@ public class FileUtilRt {
     }
   }
 
-  @NotNull
-  public static byte[] getThreadLocalBuffer() {
-    return BUFFER.get();
-  }
-
-
   public static int getUserFileSizeLimit() {
     try {
       return Integer.parseInt(System.getProperty("idea.max.intellisense.filesize")) * KILOBYTE;
index 5a1b2106ac444f95c672adf67e273b8f25daebac..d980bf0eac7d7c5cb4075bdc9a0e2e3c88bd43b4 100644 (file)
@@ -30,10 +30,7 @@ import com.intellij.util.text.FilePathHashingStrategy;
 import com.intellij.util.text.StringFactory;
 import gnu.trove.TObjectHashingStrategy;
 import org.intellij.lang.annotations.RegExp;
-import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.annotations.TestOnly;
+import org.jetbrains.annotations.*;
 
 import java.io.*;
 import java.lang.reflect.Method;
@@ -235,10 +232,27 @@ public class FileUtil extends FileUtilRt {
     return bytes;
   }
 
+  public static boolean processFirstBytes(@NotNull InputStream stream, int length, @NotNull Processor<ByteSequence> processor)
+    throws IOException {
+    final byte[] bytes = BUFFER.get();
+    assert bytes.length >= length : "Cannot process more than " + bytes.length + " in one call, requested:" + length;
+
+    int n = stream.read(bytes, 0, length);
+    if (n <= 0) return false;
+
+    return processor.process(new ByteSequence(bytes, 0, n));
+  }
+
   @NotNull
   public static byte[] loadFirst(@NotNull InputStream stream, int maxLength) throws IOException {
     ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-    copy(stream, maxLength, buffer);
+    final byte[] bytes = BUFFER.get();
+    while (maxLength > 0) {
+      int n = stream.read(bytes, 0, Math.min(maxLength, bytes.length));
+      if (n <= 0) break;
+      buffer.write(bytes, 0, n);
+      maxLength -= n;
+    }
     buffer.close();
     return buffer.toByteArray();
   }
@@ -294,7 +308,7 @@ public class FileUtil extends FileUtilRt {
 
   @NotNull
   public static byte[] adaptiveLoadBytes(@NotNull InputStream stream) throws IOException {
-    byte[] bytes = getThreadLocalBuffer();
+    byte[] bytes = new byte[4096];
     List<byte[]> buffers = null;
     int count = 0;
     int total = 0;
@@ -518,7 +532,7 @@ public class FileUtil extends FileUtilRt {
   }
 
   public static void copy(@NotNull InputStream inputStream, int maxSize, @NotNull OutputStream outputStream) throws IOException {
-    final byte[] buffer = getThreadLocalBuffer();
+    final byte[] buffer = BUFFER.get();
     int toRead = maxSize;
     while (toRead > 0) {
       int read = inputStream.read(buffer, 0, Math.min(buffer.length, toRead));