diff --git a/json/src/com/intellij/json/psi/impl/JsonTreeChangePreprocessor.java b/json/src/com/intellij/json/psi/impl/JsonTreeChangePreprocessor.java index 0bbf04bd99e4..0b54775e8d6b 100644 --- a/json/src/com/intellij/json/psi/impl/JsonTreeChangePreprocessor.java +++ b/json/src/com/intellij/json/psi/impl/JsonTreeChangePreprocessor.java @@ -17,34 +17,24 @@ package com.intellij.json.psi.impl; import com.intellij.json.JsonLanguage; import com.intellij.json.psi.JsonFile; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiTreeChangeEventImpl; import com.intellij.psi.impl.PsiTreeChangePreprocessorBase; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class JsonTreeChangePreprocessor extends PsiTreeChangePreprocessorBase { - public JsonTreeChangePreprocessor(@NotNull Project project) { - super(project); + public JsonTreeChangePreprocessor(@NotNull PsiManager psiManager) { + super(psiManager); } @Override - public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { - if (event.getFile() instanceof JsonFile) { - super.treeChanged(event); - } + protected boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event) { + return event.getFile() instanceof JsonFile; } @Override - protected boolean isInsideCodeBlock(@Nullable PsiElement element) { - if (element instanceof PsiFileSystemItem) { - return false; - } - if (element == null || element.getParent() == null) { - return true; - } - return !(element.getLanguage() instanceof JsonLanguage); + protected boolean isOutOfCodeBlock(@NotNull PsiElement element) { + return element.getLanguage() instanceof JsonLanguage; } } \ No newline at end of file diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/PsiManagerImpl.java index 81c9a77b9b36..2105773c5d44 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiManagerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiManagerImpl.java @@ -40,7 +40,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import java.util.Collections; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -86,7 +85,6 @@ public class PsiManagerImpl extends PsiManagerEx { myFileManager = isProjectDefault ? new EmptyFileManager(this) : new FileManagerImpl(this, fileDocumentManager, fileIndex); myTreeChangePreprocessors.add((PsiTreeChangePreprocessor)modificationTracker); - Collections.addAll(myTreeChangePreprocessors, Extensions.getExtensions(PsiTreeChangePreprocessor.EP_NAME, myProject)); Disposer.register(project, new Disposable() { @Override @@ -361,6 +359,9 @@ public class PsiManagerImpl extends PsiManagerEx { for (PsiTreeChangePreprocessor preprocessor : myTreeChangePreprocessors) { preprocessor.treeChanged(event); } + for (PsiTreeChangePreprocessor preprocessor : Extensions.getExtensions(PsiTreeChangePreprocessor.EP_NAME, myProject)) { + preprocessor.treeChanged(event); + } for (PsiTreeChangeListener listener : myTreeChangeListeners) { try { diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java index ceba43ce3027..53ffc786daeb 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiModificationTrackerImpl.java @@ -29,6 +29,9 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.atomic.AtomicLong; +import static com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED; +import static com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGED; + /** * @author mike * Date: Jul 18, 2002 @@ -88,12 +91,17 @@ public class PsiModificationTrackerImpl implements PsiModificationTracker, PsiTr return; } + PsiTreeChangeEventImpl.PsiEventType code = event.getCode(); + boolean outOfCodeBlock = + code == PROPERTY_CHANGED ? event.getPropertyName() == PsiTreeChangeEvent.PROP_UNLOADED_PSI : + code == CHILD_MOVED ? event.getOldParent() instanceof PsiDirectory || event.getNewParent() instanceof PsiDirectory : + event.getParent() instanceof PsiDirectory; + myModificationCount.getAndIncrement(); - if (event.getParent() instanceof PsiDirectory - || event.getOldParent() instanceof PsiDirectory /* move events */) { + if (outOfCodeBlock) { + myJavaStructureModificationCount.getAndIncrement(); myOutOfCodeBlockModificationCount.getAndIncrement(); } - fireEvent(); } diff --git a/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java b/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java index d55eb8b7defe..6c377695c022 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java +++ b/platform/core-impl/src/com/intellij/psi/impl/PsiTreeChangePreprocessorBase.java @@ -16,84 +16,111 @@ package com.intellij.psi.impl; -import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileSystemItem; import com.intellij.psi.PsiManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public abstract class PsiTreeChangePreprocessorBase implements PsiTreeChangePreprocessor { - @NotNull private final Project myProject; - public PsiTreeChangePreprocessorBase(@NotNull Project project) { - myProject = project; + protected final PsiManager myPsiManager; + + public PsiTreeChangePreprocessorBase(@NotNull PsiManager psiManager) { + myPsiManager = psiManager; } - @NotNull - protected Project getProject() { - return myProject; + protected abstract boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event); + + /** + * Shall return true if and only if the element is considered to be "out of code block" + * (the exact meaning is language- or technology-specific); otherwise false. + * + * @see PsiModificationTrackerImpl#getOutOfCodeBlockModificationCount() + */ + protected abstract boolean isOutOfCodeBlock(@NotNull PsiElement element); + + protected boolean isOutOfCodeBlock(@NotNull PsiFileSystemItem file) { + return true; + } + + protected boolean isOutOfCodeBlockInvalid(@NotNull PsiElement element) { + return false; + } + + private boolean outOfCodeBlock(@Nullable PsiElement element) { + if (element == null) return false; + if (element instanceof PsiDirectory) return false; // handled by PsiModificationTrackerImpl#treeChanged() + if (!element.isValid()) return !(element instanceof PsiFileSystemItem) && isOutOfCodeBlockInvalid(element); + if (element instanceof PsiFileSystemItem) return isOutOfCodeBlock((PsiFileSystemItem)element); + return isOutOfCodeBlock(element); } @Override - public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { + public final void treeChanged(@NotNull PsiTreeChangeEventImpl event) { if (!PsiModificationTrackerImpl.canAffectPsi(event)) { return; } + if (!acceptsEvent(event)) { + return; + } + onTreeChanged(event); + } - boolean changedInsideCodeBlock = false; + protected void onTreeChanged(@NotNull PsiTreeChangeEventImpl event) { + boolean outOfCodeBlock; switch (event.getCode()) { - case BEFORE_CHILDREN_CHANGE: - if (event.getParent() instanceof PsiFile) { - changedInsideCodeBlock = true; - break; // May be caused by fake PSI event from PomTransaction. A real event will anyway follow. - } + case BEFORE_PROPERTY_CHANGE: + case BEFORE_CHILD_MOVEMENT: + case BEFORE_CHILD_ADDITION: + case BEFORE_CHILD_REMOVAL: + case BEFORE_CHILD_REPLACEMENT: + outOfCodeBlock = false; + break; + case BEFORE_CHILDREN_CHANGE: case CHILDREN_CHANGED: if (event.isGenericChange()) { return; } - changedInsideCodeBlock = isInsideCodeBlock(event.getParent()); + outOfCodeBlock = outOfCodeBlock(event.getParent()); break; - case BEFORE_CHILD_ADDITION: - case BEFORE_CHILD_REMOVAL: case CHILD_ADDED: case CHILD_REMOVED: - case BEFORE_CHILD_REPLACEMENT: - case CHILD_REPLACED : - changedInsideCodeBlock = isInsideCodeBlock(event.getParent()) && - isInsideCodeBlock(event.getChild()) && - isInsideCodeBlock(event.getOldChild()) && - isInsideCodeBlock(event.getNewChild()); + case CHILD_REPLACED: + outOfCodeBlock = outOfCodeBlock(event.getParent()) || + outOfCodeBlock(event.getChild()) || + outOfCodeBlock(event.getOldChild()) || + outOfCodeBlock(event.getNewChild()); break; - case BEFORE_PROPERTY_CHANGE: case PROPERTY_CHANGED: - changedInsideCodeBlock = false; + outOfCodeBlock = true; break; - case BEFORE_CHILD_MOVEMENT: case CHILD_MOVED: - changedInsideCodeBlock = isInsideCodeBlock(event.getOldParent()) && - isInsideCodeBlock(event.getNewParent()) && - isInsideCodeBlock(event.getChild()); + outOfCodeBlock = outOfCodeBlock(event.getOldParent()) || + outOfCodeBlock(event.getNewParent()) || + outOfCodeBlock(event.getChild()); + break; + default: + outOfCodeBlock = true; break; } - if (!changedInsideCodeBlock) { - processOutOfCodeBlockModification(event); + if (outOfCodeBlock) { + onOutOfCodeBlockModification(event); + doIncOutOfCodeBlockCounter(); } } - @NotNull - private PsiModificationTrackerImpl getModificationTracker() { - return (PsiModificationTrackerImpl)PsiManager.getInstance(myProject).getModificationTracker(); + protected void onOutOfCodeBlockModification(@NotNull PsiTreeChangeEventImpl event) { } - protected void processOutOfCodeBlockModification(final PsiTreeChangeEventImpl event) { - getModificationTracker().incOutOfCodeBlockModificationCounter(); + protected void doIncOutOfCodeBlockCounter() { + ((PsiModificationTrackerImpl)myPsiManager.getModificationTracker()).incOutOfCodeBlockModificationCounter(); } - - protected abstract boolean isInsideCodeBlock(PsiElement element); } diff --git a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java index af27e00d87dd..1a572abaf96a 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java +++ b/plugins/yaml/src/org/jetbrains/yaml/psi/YAMLPsiManager.java @@ -1,10 +1,9 @@ package org.jetbrains.yaml.psi; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiTreeChangeEventImpl; import com.intellij.psi.impl.PsiTreeChangePreprocessorBase; import org.jetbrains.annotations.NotNull; @@ -13,41 +12,33 @@ import org.jetbrains.annotations.NotNull; * @author oleg */ final class YAMLPsiManager extends PsiTreeChangePreprocessorBase { - public YAMLPsiManager(@NotNull Project project) { - super(project); + public YAMLPsiManager(@NotNull PsiManager psiManager) { + super(psiManager); } @Override - protected boolean isInsideCodeBlock(PsiElement element) { - if (element instanceof PsiFileSystemItem) { - return false; - } - - if (element == null || element.getParent() == null) { - return true; - } + protected boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event) { + return event.getFile() instanceof YAMLFile; + } + @Override + protected boolean isOutOfCodeBlock(@NotNull PsiElement element) { while (true) { if (element instanceof YAMLFile) { - return false; + return true; } if (element instanceof PsiFile || element instanceof PsiDirectory) { - return true; + return false; } PsiElement parent = element.getParent(); if (!(parent instanceof YAMLFile || parent instanceof YAMLKeyValue || parent instanceof YAMLCompoundValue || parent instanceof YAMLDocument)) { - return true; + return false; } element = parent; } } - @Override - public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { - if (!(event.getFile() instanceof YAMLFile)) return; - super.treeChanged(event); - } } diff --git a/python/src/com/jetbrains/python/PythonPsiManager.java b/python/src/com/jetbrains/python/PythonPsiManager.java index 70f4cae36871..32be517f1062 100644 --- a/python/src/com/jetbrains/python/PythonPsiManager.java +++ b/python/src/com/jetbrains/python/PythonPsiManager.java @@ -15,11 +15,10 @@ */ package com.jetbrains.python; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiTreeChangeEventImpl; import com.intellij.psi.impl.PsiTreeChangePreprocessorBase; import com.jetbrains.python.psi.PyFile; @@ -27,34 +26,27 @@ import com.jetbrains.python.psi.PyFunction; import org.jetbrains.annotations.NotNull; public class PythonPsiManager extends PsiTreeChangePreprocessorBase { - public PythonPsiManager(@NotNull Project project) { - super(project); + public PythonPsiManager(@NotNull PsiManager psiManager) { + super(psiManager); } - public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { - if (event.getFile() instanceof PyFile) { - super.treeChanged(event); - } + @Override + protected boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event) { + return event.getFile() instanceof PyFile; } - protected boolean isInsideCodeBlock(PsiElement element) { - if (element instanceof PsiFileSystemItem) { - return false; - } - - if (element == null || !element.isValid() || element.getParent() == null) return true; - + protected boolean isOutOfCodeBlock(@NotNull PsiElement element) { while (true) { if (element instanceof PyFile) { - return false; + return true; } if (element instanceof PsiFile || element instanceof PsiDirectory || element == null) { - return true; + return false; } PsiElement pparent = element.getParent(); if (pparent instanceof PyFunction) { - final PyFunction pyFunction = (PyFunction)pparent; - return !(element == pyFunction.getParameterList() || element == pyFunction.getNameIdentifier()); + PyFunction pyFunction = (PyFunction)pparent; + return element == pyFunction.getParameterList() || element == pyFunction.getNameIdentifier(); } element = pparent; } diff --git a/xml/xml-psi-impl/src/com/intellij/xml/XmlPsiTreeChangePreprocessor.java b/xml/xml-psi-impl/src/com/intellij/xml/XmlPsiTreeChangePreprocessor.java index 7bb9bcc71360..379d773c5d3d 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/XmlPsiTreeChangePreprocessor.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/XmlPsiTreeChangePreprocessor.java @@ -1,36 +1,28 @@ package com.intellij.xml; import com.intellij.lang.xml.XMLLanguage; -import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFileSystemItem; +import com.intellij.psi.PsiManager; import com.intellij.psi.impl.PsiTreeChangeEventImpl; import com.intellij.psi.impl.PsiTreeChangePreprocessorBase; import com.intellij.psi.xml.XmlFile; import org.jetbrains.annotations.NotNull; public class XmlPsiTreeChangePreprocessor extends PsiTreeChangePreprocessorBase { - public XmlPsiTreeChangePreprocessor(@NotNull Project project) { - super(project); + public XmlPsiTreeChangePreprocessor(@NotNull PsiManager psiManager) { + super(psiManager); } @Override - protected boolean isInsideCodeBlock(PsiElement element) { - if (element instanceof PsiFileSystemItem) { - return false; - } + protected boolean acceptsEvent(@NotNull PsiTreeChangeEventImpl event) { + return event.getFile() instanceof XmlFile; + } - if (element == null || element.getParent() == null) return true; - - final boolean isXml = element.getLanguage() instanceof XMLLanguage; + @Override + protected boolean isOutOfCodeBlock(@NotNull PsiElement element) { // any xml element isn't inside a "code block" // cause we display even attributes and tag values in structure view - return !isXml; + return element.getLanguage() instanceof XMLLanguage; } - @Override - public void treeChanged(@NotNull PsiTreeChangeEventImpl event) { - if (!(event.getFile() instanceof XmlFile)) return; - super.treeChanged(event); - } }