synchronize everything on SmartPointerTracker
authorpeter <peter@jetbrains.com>
Fri, 11 Nov 2016 08:19:50 +0000 (09:19 +0100)
committerpeter <peter@jetbrains.com>
Fri, 11 Nov 2016 17:06:38 +0000 (18:06 +0100)
platform/core-impl/src/com/intellij/psi/impl/smartPointers/AnchorElementInfo.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/MarkerCache.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/SelfElementInfo.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java
platform/core-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerTracker.java

index bccbd390e0e4d611087656ed4d287bb3e8df9a94..db1f92bc4598e508e307bb2b5d2e5aca8f321bf9 100644 (file)
@@ -127,19 +127,20 @@ class AnchorElementInfo extends SelfElementInfo {
 
   private void switchToTree() {
     PsiElement element = restoreElement();
-    if (element != null) {
-      PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
-      if (anchor == null) anchor = element;
-      myType = AnchorTypeInfo.obtainInfo(anchor, myType.getFileLanguage());
-      setRange(anchor.getTextRange());
-      MarkerCache cache = myManager.getMarkerCache(getVirtualFile());
-      if (cache != null) {
-        cache.rangeChanged();
-      }
-      myStubElementTypeAndId = pack(-1, null);
+    SmartPointerTracker tracker = myManager.getTracker(getVirtualFile());
+    if (element != null && tracker != null) {
+      tracker.switchStubToAst(this, element);
     }
   }
 
+  void switchToTreeRange(@NotNull PsiElement element) {
+    PsiElement anchor = AnchorElementInfoFactory.getAnchor(element);
+    if (anchor == null) anchor = element;
+    myType = AnchorTypeInfo.obtainInfo(anchor, myType.getFileLanguage());
+    setRange(anchor.getTextRange());
+    myStubElementTypeAndId = pack(-1, null);
+  }
+
   @Override
   public Segment getRange() {
     if (getStubId() != -1) {
index 13cd778ce7b3da8528b57aee9f70d8f9d816b720..018bd8c12e86cdd8bcdaf34ecd64a9cb46b76a06 100644 (file)
@@ -49,7 +49,7 @@ class MarkerCache {
     }
   };
   private final SmartPointerTracker myPointers;
-  private volatile UpdatedRanges myUpdatedRanges;
+  private UpdatedRanges myUpdatedRanges;
 
   MarkerCache(SmartPointerTracker pointers) {
     myPointers = pointers;
@@ -62,25 +62,19 @@ class MarkerCache {
     UpdatedRanges cache = myUpdatedRanges;
     if (cache != null && cache.myEventCount == eventCount) return cache;
 
-    //noinspection SynchronizeOnThis
-    synchronized (this) {
-      cache = myUpdatedRanges;
-      if (cache != null && cache.myEventCount == eventCount) return cache;
-
-      UpdatedRanges answer;
-      if (cache != null && cache.myEventCount < eventCount) {
-        // apply only the new events
-        answer = applyEvents(events.subList(cache.myEventCount, eventCount), cache);
-      }
-      else {
-        List<SelfElementInfo> infos = myPointers.getSortedInfos();
-        ManualRangeMarker[] markers = createMarkers(infos);
-        answer = applyEvents(events, new UpdatedRanges(0, frozen, infos, markers));
-      }
-
-      myUpdatedRanges = answer;
-      return answer;
+    UpdatedRanges answer;
+    if (cache != null && cache.myEventCount < eventCount) {
+      // apply only the new events
+      answer = applyEvents(events.subList(cache.myEventCount, eventCount), cache);
     }
+    else {
+      List<SelfElementInfo> infos = myPointers.getSortedInfos();
+      ManualRangeMarker[] markers = createMarkers(infos);
+      answer = applyEvents(events, new UpdatedRanges(0, frozen, infos, markers));
+    }
+
+    myUpdatedRanges = answer;
+    return answer;
   }
 
   @NotNull
@@ -143,7 +137,7 @@ class MarkerCache {
     return new UpdatedRanges(struct.myEventCount + events.size(), frozen, struct.mySortedInfos, resultMarkers);
   }
 
-  synchronized void updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
+  boolean updateMarkers(@NotNull FrozenDocument frozen, @NotNull List<DocumentEvent> events) {
     UpdatedRanges updated = getUpdatedMarkers(frozen, events);
 
     boolean sorted = true;
@@ -155,11 +149,8 @@ class MarkerCache {
       }
     }
 
-    if (!sorted) {
-      myPointers.markUnsorted();
-    }
-
     myUpdatedRanges = null;
+    return sorted;
   }
 
   @Nullable
@@ -172,7 +163,6 @@ class MarkerCache {
 
   void rangeChanged() {
     myUpdatedRanges = null;
-    myPointers.markUnsorted();
   }
 
   private static class UpdatedRanges {
index b938aa482afa7b67971dbfd770029053a07ec469..662060905a75c428cc65d64a020f1e6194c89ef7 100644 (file)
@@ -274,9 +274,9 @@ public class SelfElementInfo extends SmartPointerElementInfo {
         PsiDocumentManagerBase documentManager = myManager.getPsiDocumentManager();
         List<DocumentEvent> events = documentManager.getEventsSinceCommit(document);
         if (!events.isEmpty()) {
-          MarkerCache markerCache = myManager.getMarkerCache(getVirtualFile());
-          if (markerCache != null) {
-            return markerCache.getUpdatedRange(this, (FrozenDocument)documentManager.getLastCommittedDocument(document), events);
+          SmartPointerTracker tracker = myManager.getTracker(getVirtualFile());
+          if (tracker != null) {
+            return tracker.getUpdatedRange(this, (FrozenDocument)documentManager.getLastCommittedDocument(document), events);
           }
         }
       }
index 6567f3647b4366487a41f73ea650369a7221d772..0398a4aae1d4c20fa256513f9d76cf5db910253c 100644 (file)
@@ -23,13 +23,14 @@ import com.intellij.openapi.editor.event.DocumentEvent;
 import com.intellij.openapi.editor.impl.FrozenDocument;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.ProperTextRange;
+import com.intellij.openapi.util.TextRange;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.PsiDocumentManagerBase;
 import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.reference.SoftReference;
-import com.intellij.util.Processor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
@@ -50,17 +51,8 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
   }
 
   public void fastenBelts(@NotNull VirtualFile file) {
-    SmartPointerTracker.processQueue();
-    SmartPointerTracker pointers = getPointers(file);
-    if (pointers != null) {
-      pointers.processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
-        @Override
-        public boolean process(SmartPsiElementPointerImpl pointer) {
-          pointer.getElementInfo().fastenBelt();
-          return true;
-        }
-      });
-    }
+    SmartPointerTracker pointers = getTracker(file);
+    if (pointers != null) pointers.fastenBelts();
   }
 
   private static final Key<Reference<SmartPsiElementPointerImpl>> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY");
@@ -138,14 +130,11 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
 
     SmartPointerTracker.PointerReference reference = new SmartPointerTracker.PointerReference(pointer, containingFile, POINTERS_KEY);
     while (true) {
-      SmartPointerTracker pointers = getPointers(containingFile);
+      SmartPointerTracker pointers = getTracker(containingFile);
       if (pointers == null) {
         pointers = containingFile.putUserDataIfAbsent(POINTERS_KEY, new SmartPointerTracker());
       }
-      if (pointers.addReference(reference)) {
-        if (((SelfElementInfo)info).hasRange()) {
-          pointers.markerCache.rangeChanged();
-        }
+      if (pointers.addReference(reference, pointer)) {
         break;
       }
     }
@@ -169,7 +158,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
 
       if (containingFile == null) return;
       VirtualFile vFile = containingFile.getViewProvider().getVirtualFile();
-      SmartPointerTracker pointers = getPointers(vFile);
+      SmartPointerTracker pointers = getTracker(vFile);
       SmartPointerTracker.PointerReference reference = ((SmartPsiElementPointerImpl)pointer).pointerReference;
       if (pointers != null && reference != null) {
         pointers.removeReference(reference);
@@ -178,20 +167,14 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
   }
 
   @Nullable
-  private SmartPointerTracker getPointers(@NotNull VirtualFile containingFile) {
+  SmartPointerTracker getTracker(@NotNull VirtualFile containingFile) {
     return containingFile.getUserData(POINTERS_KEY);
   }
 
-  @Nullable
-  MarkerCache getMarkerCache(@NotNull VirtualFile file) {
-    SmartPointerTracker pointers = getPointers(file);
-    return pointers == null ? null : pointers.markerCache;
-  }
-
   @TestOnly
   public int getPointersNumber(@NotNull PsiFile containingFile) {
     VirtualFile file = containingFile.getViewProvider().getVirtualFile();
-    SmartPointerTracker pointers = getPointers(file);
+    SmartPointerTracker pointers = getTracker(file);
     return pointers == null ? 0 : pointers.getSize();
   }
 
@@ -202,39 +185,15 @@ public class SmartPointerManagerImpl extends SmartPointerManager {
 
   public void updatePointers(Document document, FrozenDocument frozen, List<DocumentEvent> events) {
     VirtualFile file = FileDocumentManager.getInstance().getFile(document);
-    SmartPointerTracker list = file == null ? null : getPointers(file);
-    if (list == null) return;
-
-    list.markerCache.updateMarkers(frozen, events);
+    SmartPointerTracker list = file == null ? null : getTracker(file);
+    if (list != null) list.updateMarkers(frozen, events);
   }
 
   public void updatePointerTargetsAfterReparse(@NotNull VirtualFile file) {
-    SmartPointerTracker list = getPointers(file);
-    if (list == null) return;
-
-    list.processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
-      @Override
-      public boolean process(SmartPsiElementPointerImpl pointer) {
-        if (!(pointer instanceof SmartPsiFileRangePointerImpl)) {
-          updatePointerTarget(pointer, pointer.getPsiRange());
-        }
-        return true;
-      }
-    });
+    SmartPointerTracker list = getTracker(file);
+    if (list != null) list.updatePointerTargetsAfterReparse();
   }
 
-  // after reparse and its complex tree diff, the element might have "moved" to other range
-  // but if an element of the same type can still be found at the old range, let's point there
-  private static <E extends PsiElement> void updatePointerTarget(@NotNull SmartPsiElementPointerImpl<E> pointer, @Nullable Segment pointerRange) {
-    E cachedElement = pointer.getCachedElement();
-    if (cachedElement == null || cachedElement.isValid() && pointerRange != null && pointerRange.equals(cachedElement.getTextRange())) {
-      return;
-    }
-
-    pointer.cacheElement(pointer.doRestoreElement());
-  }
-
-
   Project getProject() {
     return myProject;
   }
index 5f2fe64062728b189a253000674a489bd1c72351..c552dd4f875de604e7a45e2dc538b518d7d7a50f 100644 (file)
 package com.intellij.psi.impl.smartPointers;
 
 import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.impl.FrozenDocument;
 import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.LowMemoryWatcher;
+import com.intellij.openapi.util.Segment;
 import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
 import com.intellij.util.CommonProcessors;
 import com.intellij.util.Processor;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.annotations.TestOnly;
 
 import java.lang.ref.ReferenceQueue;
@@ -35,7 +40,7 @@ class SmartPointerTracker {
   private int nextAvailableIndex;
   private int size;
   private PointerReference[] references = new PointerReference[10];
-  final MarkerCache markerCache = new MarkerCache(this);
+  private final MarkerCache markerCache = new MarkerCache(this);
   private boolean mySorted;
 
   static {
@@ -47,7 +52,7 @@ class SmartPointerTracker {
     }, ApplicationManager.getApplication());
   }
 
-  synchronized boolean addReference(@NotNull PointerReference reference) {
+  synchronized boolean addReference(@NotNull PointerReference reference, @NotNull SmartPsiElementPointerImpl pointer) {
     if (!isActual(reference.file, reference.key)) {
       // this pointer list has been removed by another thread; clients should get/create an up-to-date list and try adding to it
       return false;
@@ -62,6 +67,9 @@ class SmartPointerTracker {
     storePointerReference(references, nextAvailableIndex++, reference);
     size++;
     mySorted = false;
+    if (((SelfElementInfo)pointer.getElementInfo()).hasRange()) {
+      markerCache.rangeChanged();
+    }
     return true;
   }
 
@@ -104,7 +112,7 @@ class SmartPointerTracker {
     }
   }
 
-  synchronized void processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
+  private void processAlivePointers(@NotNull Processor<SmartPsiElementPointerImpl> processor) {
     for (int i = 0; i < nextAvailableIndex; i++) {
       PointerReference ref = references[i];
       if (ref == null) continue;
@@ -144,6 +152,58 @@ class SmartPointerTracker {
     }
   }
 
+  synchronized void updateMarkers(FrozenDocument frozen, List<DocumentEvent> events) {
+    boolean stillSorted = markerCache.updateMarkers(frozen, events);
+    if (!stillSorted) {
+      mySorted = false;
+    }
+  }
+
+  @Nullable
+  synchronized Segment getUpdatedRange(SelfElementInfo info, FrozenDocument document, List<DocumentEvent> events) {
+    return markerCache.getUpdatedRange(info, document, events);
+  }
+
+  synchronized void switchStubToAst(AnchorElementInfo info, PsiElement element) {
+    info.switchToTreeRange(element);
+    markerCache.rangeChanged();
+    mySorted = false;
+  }
+
+  synchronized void fastenBelts() {
+    processQueue();
+    processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+      @Override
+      public boolean process(SmartPsiElementPointerImpl pointer) {
+        pointer.getElementInfo().fastenBelt();
+        return true;
+      }
+    });
+  }
+
+  synchronized void updatePointerTargetsAfterReparse() {
+    processAlivePointers(new Processor<SmartPsiElementPointerImpl>() {
+      @Override
+      public boolean process(SmartPsiElementPointerImpl pointer) {
+        if (!(pointer instanceof SmartPsiFileRangePointerImpl)) {
+          updatePointerTarget(pointer, pointer.getPsiRange());
+        }
+        return true;
+      }
+    });
+  }
+
+  // after reparse and its complex tree diff, the element might have "moved" to other range
+  // but if an element of the same type can still be found at the old range, let's point there
+  private static <E extends PsiElement> void updatePointerTarget(@NotNull SmartPsiElementPointerImpl<E> pointer, @Nullable Segment pointerRange) {
+    E cachedElement = pointer.getCachedElement();
+    if (cachedElement == null || cachedElement.isValid() && pointerRange != null && pointerRange.equals(cachedElement.getTextRange())) {
+      return;
+    }
+
+    pointer.cacheElement(pointer.doRestoreElement());
+  }
+
   private static void storePointerReference(PointerReference[] references, int index, PointerReference ref) {
     references[index] = ref;
     ref.index = index;
@@ -171,10 +231,6 @@ class SmartPointerTracker {
     return size;
   }
 
-  synchronized void markUnsorted() {
-    mySorted = false;
-  }
-
   static class PointerReference extends WeakReference<SmartPsiElementPointerImpl> {
     @NotNull private final VirtualFile file;
     @NotNull private final Key<SmartPointerTracker> key;