move some tests to the platform
authorpeter <peter@jetbrains.com>
Tue, 17 Jan 2012 18:29:33 +0000 (19:29 +0100)
committerpeter <peter@jetbrains.com>
Tue, 17 Jan 2012 18:40:31 +0000 (19:40 +0100)
24 files changed:
java/java-tests/testData/codeEditor/smartPsiElementPointers/AClass.java [new file with mode: 0644]
java/java-tests/testData/codeEditor/smartPsiElementPointers/Test.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test.ipr [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestI.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl1.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl2.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test1/test1.iml [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestI.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl1.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl3.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test2/test2.iml [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestI.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestIImpl1.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/navigation/alexProject/test3/test3.iml [new file with mode: 0644]
java/java-tests/testData/psi/libraryOrder/lib1/classes/test/A.class [new file with mode: 0644]
java/java-tests/testData/psi/libraryOrder/lib1/src/test/A.java [new file with mode: 0644]
java/java-tests/testData/psi/libraryOrder/lib2/classes/test/A.class [new file with mode: 0644]
java/java-tests/testData/psi/libraryOrder/lib2/src/test/A.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/navigation/GotoImplementationTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/LibraryOrderTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/PsiModificationTrackerTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/TreeIsCorrectAfterDiffReparseTest.java [new file with mode: 0644]

diff --git a/java/java-tests/testData/codeEditor/smartPsiElementPointers/AClass.java b/java/java-tests/testData/codeEditor/smartPsiElementPointers/AClass.java
new file mode 100644 (file)
index 0000000..777991d
--- /dev/null
@@ -0,0 +1,2 @@
+class AClass{
+}
diff --git a/java/java-tests/testData/codeEditor/smartPsiElementPointers/Test.java b/java/java-tests/testData/codeEditor/smartPsiElementPointers/Test.java
new file mode 100644 (file)
index 0000000..2645b39
--- /dev/null
@@ -0,0 +1,3 @@
+class Test {
+  AClass field;
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test.ipr b/java/java-tests/testData/codeInsight/navigation/alexProject/test.ipr
new file mode 100644 (file)
index 0000000..dded6f4
--- /dev/null
@@ -0,0 +1,264 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4" relativePaths="true">
+  <component name="AntConfiguration">
+    <defaultAnt bundledAnt="true" />
+  </component>
+  <component name="BuildJarProjectSettings">
+    <option name="BUILD_JARS_ON_MAKE" value="false" />
+  </component>
+  <component name="CodeStyleProjectProfileManger">
+    <option name="PROJECT_PROFILE" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <scopes />
+    <profiles />
+  </component>
+  <component name="CodeStyleSettingsManager">
+    <option name="PER_PROJECT_SETTINGS" />
+    <option name="USE_PER_PROJECT_SETTINGS" value="false" />
+  </component>
+  <component name="CompilerConfiguration">
+    <option name="DEFAULT_COMPILER" value="Javac" />
+    <option name="DEPLOY_AFTER_MAKE" value="0" />
+    <resourceExtensions>
+      <entry name=".+\.(properties|xml|html|dtd|tld)" />
+      <entry name=".+\.(gif|png|jpeg|jpg)" />
+    </resourceExtensions>
+    <wildcardResourcePatterns>
+      <entry name="?*.properties" />
+      <entry name="?*.xml" />
+      <entry name="?*.gif" />
+      <entry name="?*.png" />
+      <entry name="?*.jpeg" />
+      <entry name="?*.jpg" />
+      <entry name="?*.html" />
+      <entry name="?*.dtd" />
+      <entry name="?*.tld" />
+    </wildcardResourcePatterns>
+  </component>
+  <component name="DataSourceManagerImpl" />
+  <component name="DependenciesAnalyzeManager">
+    <option name="myForwardDirection" value="false" />
+  </component>
+  <component name="DependencyValidationManager" />
+  <component name="EclipseCompilerSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="true" />
+    <option name="DEPRECATION" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="EclipseEmbeddedCompilerSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="true" />
+    <option name="DEPRECATION" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="EntryPointsManager">
+    <entry_points />
+  </component>
+  <component name="ExportToHTMLSettings">
+    <option name="PRINT_LINE_NUMBERS" value="false" />
+    <option name="OPEN_IN_BROWSER" value="false" />
+    <option name="OUTPUT_DIRECTORY" />
+  </component>
+  <component name="GUI Designer component loader factory" />
+  <component name="InspectionProjectProfileManager">
+    <option name="PROJECT_PROFILE" value="Project Default" />
+    <option name="USE_PROJECT_LEVEL_SETTINGS" value="false" />
+    <scopes />
+    <profiles>
+      <profile version="1.0" is_locked="false">
+        <option name="myName" value="Project Default" />
+        <option name="myLocal" value="false" />
+      </profile>
+    </profiles>
+  </component>
+  <component name="JavacSettings">
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="DEPRECATION" value="true" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+    <option name="MAXIMUM_HEAP_SIZE" value="128" />
+  </component>
+  <component name="JavadocGenerationManager">
+    <option name="OUTPUT_DIRECTORY" />
+    <option name="OPTION_SCOPE" value="protected" />
+    <option name="OPTION_HIERARCHY" value="true" />
+    <option name="OPTION_NAVIGATOR" value="true" />
+    <option name="OPTION_INDEX" value="true" />
+    <option name="OPTION_SEPARATE_INDEX" value="true" />
+    <option name="OPTION_DOCUMENT_TAG_USE" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_AUTHOR" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_VERSION" value="false" />
+    <option name="OPTION_DOCUMENT_TAG_DEPRECATED" value="true" />
+    <option name="OPTION_DEPRECATED_LIST" value="true" />
+    <option name="OTHER_OPTIONS" value="" />
+    <option name="HEAP_SIZE" />
+    <option name="LOCALE" />
+    <option name="OPEN_IN_BROWSER" value="true" />
+  </component>
+  <component name="JikesSettings">
+    <option name="JIKES_PATH" value="" />
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="DEPRECATION" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="IS_EMACS_ERRORS_MODE" value="true" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+  </component>
+  <component name="LogConsolePreferences">
+    <option name="FILTER_ERRORS" value="false" />
+    <option name="FILTER_WARNINGS" value="false" />
+    <option name="FILTER_INFO" value="true" />
+    <option name="CUSTOM_FILTER" />
+  </component>
+  <component name="Palette2">
+    <group name="Swing">
+      <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+      </item>
+      <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
+        <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+        <initial-values>
+          <property name="text" value="Button" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="RadioButton" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="CheckBox" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+        <initial-values>
+          <property name="text" value="Label" />
+        </initial-values>
+      </item>
+      <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+          <preferred-size width="150" height="-1" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+          <preferred-size width="150" height="50" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+          <preferred-size width="200" height="200" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+      </item>
+      <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+      </item>
+      <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+          <preferred-size width="-1" height="20" />
+        </default-constraints>
+      </item>
+      <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
+        <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+      </item>
+      <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
+        <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+      </item>
+    </group>
+  </component>
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/test1/test1.iml" filepath="$PROJECT_DIR$/test1/test1.iml" />
+      <module fileurl="file://$PROJECT_DIR$/test2/test2.iml" filepath="$PROJECT_DIR$/test2/test2.iml" />
+      <module fileurl="file://$PROJECT_DIR$/test3/test3.iml" filepath="$PROJECT_DIR$/test3/test3.iml" />
+    </modules>
+  </component>
+  <component name="ProjectRootManager" version="2" assert-keyword="true" jdk-15="true" project-jdk-name="1.5" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/classes" />
+  </component>
+  <component name="ProjectRunConfigurationManager" />
+  <component name="RmicSettings">
+    <option name="IS_EANABLED" value="false" />
+    <option name="DEBUGGING_INFO" value="true" />
+    <option name="GENERATE_NO_WARNINGS" value="false" />
+    <option name="GENERATE_IIOP_STUBS" value="false" />
+    <option name="ADDITIONAL_OPTIONS_STRING" value="" />
+  </component>
+  <component name="StarteamVcsAdapter" />
+  <component name="VssVcs" />
+  <component name="libraryTable" />
+  <component name="uidesigner-configuration">
+    <option name="INSTRUMENT_CLASSES" value="true" />
+    <option name="COPY_FORMS_RUNTIME_TO_OUTPUT" value="true" />
+    <option name="DEFAULT_LAYOUT_MANAGER" value="GridLayoutManager" />
+  </component>
+  <UsedPathMacros />
+</project>
+
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestI.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestI.java
new file mode 100644 (file)
index 0000000..11b6857
--- /dev/null
@@ -0,0 +1,12 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:18 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {//jjjkjh kljh lk
+    void test(/* */);
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl1.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl1.java
new file mode 100644 (file)
index 0000000..d06b163
--- /dev/null
@@ -0,0 +1,14 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:52 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+    public void test() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl2.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test1/src/com/test/TestIImpl2.java
new file mode 100644 (file)
index 0000000..fd221c9
--- /dev/null
@@ -0,0 +1,14 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:03 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl2 implements TestI {
+    public void test() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test1/test1.iml b/java/java-tests/testData/codeInsight/navigation/alexProject/test1/test1.iml
new file mode 100644 (file)
index 0000000..9c3a0a6
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+  <component name="ModuleRootManager" />
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntryProperties />
+  </component>
+</module>
+
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestI.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestI.java
new file mode 100644 (file)
index 0000000..7b22b82
--- /dev/null
@@ -0,0 +1,11 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:11 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl1.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl1.java
new file mode 100644 (file)
index 0000000..68617fc
--- /dev/null
@@ -0,0 +1,11 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:22 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl3.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test2/src/com/test/TestIImpl3.java
new file mode 100644 (file)
index 0000000..7ae76c8
--- /dev/null
@@ -0,0 +1,11 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:28 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl3 implements TestI {
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test2/test2.iml b/java/java-tests/testData/codeInsight/navigation/alexProject/test2/test2.iml
new file mode 100644 (file)
index 0000000..9c3a0a6
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+  <component name="ModuleRootManager" />
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntryProperties />
+  </component>
+</module>
+
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestI.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestI.java
new file mode 100644 (file)
index 0000000..f3d43e0
--- /dev/null
@@ -0,0 +1,11 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:35:03 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public interface TestI {
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestIImpl1.java b/java/java-tests/testData/codeInsight/navigation/alexProject/test3/src/com/test/TestIImpl1.java
new file mode 100644 (file)
index 0000000..56e5d84
--- /dev/null
@@ -0,0 +1,11 @@
+package com.test;
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: cdr
+ * Date: Aug 14, 2006
+ * Time: 3:36:36 PM
+ * To change this template use File | Settings | File Templates.
+ */
+public class TestIImpl1 implements TestI {
+}
diff --git a/java/java-tests/testData/codeInsight/navigation/alexProject/test3/test3.iml b/java/java-tests/testData/codeInsight/navigation/alexProject/test3/test3.iml
new file mode 100644 (file)
index 0000000..9c3a0a6
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4" relativePaths="true" type="JAVA_MODULE">
+  <component name="ModuleRootManager" />
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntryProperties />
+  </component>
+</module>
+
diff --git a/java/java-tests/testData/psi/libraryOrder/lib1/classes/test/A.class b/java/java-tests/testData/psi/libraryOrder/lib1/classes/test/A.class
new file mode 100644 (file)
index 0000000..27ab007
Binary files /dev/null and b/java/java-tests/testData/psi/libraryOrder/lib1/classes/test/A.class differ
diff --git a/java/java-tests/testData/psi/libraryOrder/lib1/src/test/A.java b/java/java-tests/testData/psi/libraryOrder/lib1/src/test/A.java
new file mode 100644 (file)
index 0000000..691fe65
--- /dev/null
@@ -0,0 +1,5 @@
+package test;
+class A {
+  void methodOfClassFromLib1() {
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/psi/libraryOrder/lib2/classes/test/A.class b/java/java-tests/testData/psi/libraryOrder/lib2/classes/test/A.class
new file mode 100644 (file)
index 0000000..e1a4640
Binary files /dev/null and b/java/java-tests/testData/psi/libraryOrder/lib2/classes/test/A.class differ
diff --git a/java/java-tests/testData/psi/libraryOrder/lib2/src/test/A.java b/java/java-tests/testData/psi/libraryOrder/lib2/src/test/A.java
new file mode 100644 (file)
index 0000000..9f54891
--- /dev/null
@@ -0,0 +1,5 @@
+package test;
+class A {
+  void methodOfClassFromLib2() {
+  }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationTest.java b/java/java-tests/testSrc/com/intellij/navigation/GotoImplementationTest.java
new file mode 100644 (file)
index 0000000..b63f367
--- /dev/null
@@ -0,0 +1,92 @@
+package com.intellij.navigation;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.codeInsight.navigation.ClassImplementationsSearch;
+import com.intellij.codeInsight.navigation.MethodImplementationsSearch;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
+import com.intellij.openapi.module.impl.ModuleManagerImpl;
+import com.intellij.openapi.project.ex.ProjectManagerEx;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.util.CommonProcessors;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author cdr
+ */
+public class GotoImplementationTest extends CodeInsightTestCase {
+
+  private static Collection<PsiClass> getClassImplementations(final PsiClass psiClass) {
+    CommonProcessors.CollectProcessor<PsiClass> processor = new CommonProcessors.CollectProcessor<PsiClass>();
+    ClassImplementationsSearch.processImplementations(psiClass, processor);
+
+    return processor.getResults();
+  }
+
+  @Override
+  protected void setUpProject() throws Exception {
+    final String root = JavaTestUtil.getJavaTestDataPath() + "/codeInsight/navigation/alexProject";
+    VirtualFile vfsRoot = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(root));
+
+    VirtualFile projectFile = vfsRoot.findChild("test.ipr");
+    myProject = ProjectManagerEx.getInstanceEx().loadProject(projectFile.getPath());
+
+    simulateProjectOpen();
+    ProjectManagerEx.getInstanceEx().setCurrentTestProject(myProject);
+  }
+
+  @Override
+  protected void tearDown() throws Exception {
+    ((ModuleManagerImpl)ModuleManager.getInstance(myProject)).projectClosed();
+    super.tearDown();
+  }
+
+  public void test() throws Exception {
+
+    ModuleManager moduleManager = ModuleManager.getInstance(getProject());
+    Module[] modules = moduleManager.getModules();
+    assertEquals(3, modules.length);
+
+    Module module1 = moduleManager.findModuleByName("test1");
+    Module module2 = moduleManager.findModuleByName("test2");
+    Module module3 = moduleManager.findModuleByName("test3");
+    PsiClass test1 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module1));
+    PsiClass test2 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module2));
+    PsiClass test3 = myJavaFacade.findClass("com.test.TestI", GlobalSearchScope.moduleScope(module3));
+    HashSet<PsiClass> expectedImpls1 = new HashSet<PsiClass>(Arrays.asList(
+      myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module1)),
+      myJavaFacade.findClass("com.test.TestIImpl2", GlobalSearchScope.moduleScope(module1))
+    ));
+    assertEquals(expectedImpls1, new HashSet<PsiClass>(getClassImplementations(test1)));
+
+    PsiMethod psiMethod = test1.findMethodsByName("test", false)[0];
+    Set<PsiMethod> expectedMethodImpl1 = new HashSet<PsiMethod>(Arrays.asList(
+      myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module1)).findMethodsByName("test",false)[0],
+      myJavaFacade.findClass("com.test.TestIImpl2", GlobalSearchScope.moduleScope(module1)).findMethodsByName("test",false)[0]
+    ));
+    assertEquals(expectedMethodImpl1, new HashSet<PsiMethod>(Arrays.asList(MethodImplementationsSearch.getMethodImplementations(psiMethod))));
+
+    HashSet<PsiClass> expectedImpls2 = new HashSet<PsiClass>(Arrays.asList(
+      myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module2)),
+      myJavaFacade.findClass("com.test.TestIImpl3", GlobalSearchScope.moduleScope(module2))
+    ));
+    assertEquals(expectedImpls2, new HashSet<PsiClass>(getClassImplementations(test2)));
+
+    HashSet<PsiClass> expectedImpls3 = new HashSet<PsiClass>(Arrays.asList(
+      myJavaFacade.findClass("com.test.TestIImpl1", GlobalSearchScope.moduleScope(module3))
+    ));
+    assertEquals(expectedImpls3, new HashSet<PsiClass>(getClassImplementations(test3)));
+
+  }
+
+}
diff --git a/java/java-tests/testSrc/com/intellij/psi/LibraryOrderTest.java b/java/java-tests/testSrc/com/intellij/psi/LibraryOrderTest.java
new file mode 100644 (file)
index 0000000..1e288c2
--- /dev/null
@@ -0,0 +1,110 @@
+package com.intellij.psi;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.roots.*;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.roots.libraries.LibraryTable;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.PsiTestCase;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ *  @author dsl
+ */
+public class LibraryOrderTest extends PsiTestCase {
+
+  public void test1() {
+    setupPaths();
+    checkClassFromLib("test.A", "1");
+
+    final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
+    final OrderEntry[] order = rootModel.getOrderEntries();
+    final int length = order.length;
+    OrderEntry lib2 = order[length - 1];
+    OrderEntry lib1 = order[length - 2];
+    assertTrue(lib1 instanceof LibraryOrderEntry);
+    assertEquals("lib1", ((LibraryOrderEntry) lib1).getLibraryName());
+    assertTrue(lib2 instanceof LibraryOrderEntry);
+    assertEquals("lib2", ((LibraryOrderEntry) lib2).getLibraryName());
+
+    order[length - 1] = lib1;
+    order[length - 2] = lib2;
+    rootModel.rearrangeOrderEntries(order);
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        rootModel.commit();
+      }
+    }
+    );
+
+    checkClassFromLib("test.A", "2");
+  }
+
+  public void testNavigation() throws Exception {
+    setupPaths();
+    final JavaPsiFacade psiManager = getJavaFacade();
+    final PsiClass classA = psiManager.findClass("test.A");
+    final PsiElement navigationElement = classA.getNavigationElement();
+    assertNotNull(navigationElement);
+    assertTrue(navigationElement != classA);
+    assertEquals("A.java", navigationElement.getContainingFile().getVirtualFile().getName());
+  }
+
+  private void checkClassFromLib(String qualifiedName, String index) {
+    final PsiClass classA = (PsiClass)JavaPsiFacade.getInstance(myProject).findClass(qualifiedName).getNavigationElement();
+    assertNotNull(classA);
+    final PsiMethod[] methodsA = classA.getMethods();
+    assertEquals(1, methodsA.length);
+    assertEquals("methodOfClassFromLib" + index, methodsA[0].getName());
+  }
+
+  public void setupPaths() {
+    final String basePath = JavaTestUtil.getJavaTestDataPath() + "/psi/libraryOrder/";
+
+    final VirtualFile lib1SrcFile = refreshAndFindFile(basePath + "lib1/src");
+    final VirtualFile lib1classes = refreshAndFindFile(basePath + "lib1/classes");
+    final VirtualFile lib2SrcFile = refreshAndFindFile(basePath + "lib2/src");
+    final VirtualFile lib2classes = refreshAndFindFile(basePath + "lib2/classes");
+
+    assertTrue(lib1SrcFile != null);
+    assertTrue(lib2SrcFile != null);
+
+    final ModifiableRootModel rootModel = ModuleRootManager.getInstance(myModule).getModifiableModel();
+    final LibraryTable libraryTable = rootModel.getModuleLibraryTable();
+
+    addLibraryWithSourcePath("lib1", libraryTable, lib1SrcFile, lib1classes);
+    addLibraryWithSourcePath("lib2", libraryTable, lib2SrcFile, lib2classes);
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      @Override
+      public void run() {
+        rootModel.commit();
+      }
+    });
+    final List<VirtualFile> list = Arrays.asList(OrderEnumerator.orderEntries(myModule).getClassesRoots());
+    assertTrue(list.contains(lib1classes));
+    assertTrue(list.contains(lib2classes));
+  }
+
+  private VirtualFile refreshAndFindFile(String path) {
+    final File ioLib1Src = new File(path);
+    final VirtualFile lib1SrcFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioLib1Src);
+    return lib1SrcFile;
+  }
+
+  private void addLibraryWithSourcePath(String name, final LibraryTable libraryTable, final VirtualFile libSource,
+                                        VirtualFile libClasses) {
+    final Library lib = libraryTable.createLibrary(name);
+    final Library.ModifiableModel libModel = lib.getModifiableModel();
+    libModel.addRoot(libClasses, OrderRootType.CLASSES);
+    libModel.addRoot(libSource, OrderRootType.SOURCES);
+    libModel.commit();
+  }
+}
diff --git a/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java b/java/java-tests/testSrc/com/intellij/psi/PsiDocumentManagerImplTest.java
new file mode 100644 (file)
index 0000000..b5ff32e
--- /dev/null
@@ -0,0 +1,298 @@
+package com.intellij.psi;
+
+import com.intellij.ide.impl.ProjectUtil;
+import com.intellij.mock.MockDocument;
+import com.intellij.mock.MockPsiFile;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.impl.DocumentImpl;
+import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ex.ProjectManagerEx;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.psi.impl.PsiDocumentManagerImpl;
+import com.intellij.psi.impl.TextBlock;
+import com.intellij.psi.impl.source.PsiFileImpl;
+import com.intellij.testFramework.LeakHunter;
+import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.util.Processor;
+import com.intellij.util.concurrency.Semaphore;
+import com.intellij.util.ui.UIUtil;
+
+import java.io.File;
+import java.lang.ref.Reference;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PsiDocumentManagerImplTest extends PlatformTestCase {
+  private PsiDocumentManagerImpl getPsiDocumentManager() {
+    return (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(getProject());
+  }
+
+  public void testGetCachedPsiFile_NoFile() throws Exception {
+    final PsiFile file = getPsiDocumentManager().getCachedPsiFile(new MockDocument());
+    assertNull(file);
+  }
+
+  public void testGetPsiFile_NotRegisteredDocument() throws Exception {
+    final PsiFile file = getPsiDocumentManager().getPsiFile(new MockDocument());
+    assertNull(file);
+  }
+
+  public void testGetDocument_FirstGet() throws Exception {
+    VirtualFile vFile = createFile();
+    final PsiFile file = new MockPsiFile(vFile, getPsiManager());
+
+    final Document document = getPsiDocumentManager().getDocument(file);
+    assertNotNull(document);
+    assertSame(document, FileDocumentManager.getInstance().getDocument(vFile));
+  }
+
+  private static LightVirtualFile createFile() {
+    return new LightVirtualFile("foo.java");
+  }
+
+  public void testDocumentGced() throws Exception {
+    VirtualFile vFile = createFile();
+    PsiDocumentManagerImpl documentManager = getPsiDocumentManager();
+    long id = System.identityHashCode(documentManager.getDocument(getPsiManager().findFile(vFile)));
+
+    documentManager.commitAllDocuments();
+    UIUtil.dispatchAllInvocationEvents();
+    UIUtil.dispatchAllInvocationEvents();
+    assertEmpty(documentManager.getUncommittedDocuments());
+
+    LeakHunter.checkLeak(documentManager, DocumentImpl.class);
+    LeakHunter.checkLeak(documentManager, PsiFileImpl.class, new Processor<PsiFileImpl>() {
+      @Override
+      public boolean process(PsiFileImpl psiFile) {
+        return psiFile.getViewProvider().getVirtualFile().getFileSystem() instanceof LocalFileSystem;
+      }
+    });
+    //Class.forName("com.intellij.util.ProfilingUtil").getDeclaredMethod("forceCaptureMemorySnapshot").invoke(null);
+
+    Reference<Document> reference = vFile.getUserData(FileDocumentManagerImpl.DOCUMENT_KEY);
+    assertNotNull(reference);
+    for (int i=0;i<1000;i++) {
+      UIUtil.dispatchAllInvocationEvents();
+      if (reference.get() == null) break;
+      System.gc();
+    }
+    assertNull(documentManager.getCachedDocument(getPsiManager().findFile(vFile)));
+
+    Document newDoc = documentManager.getDocument(getPsiManager().findFile(vFile));
+    assertTrue(id != System.identityHashCode(newDoc));
+  }
+
+  public void testGetUncommittedDocuments_noDocuments() throws Exception {
+    assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+  }
+
+  public void testGetUncommittedDocuments_documentChanged_DontProcessEvents() throws Exception {
+    PsiFile file = getPsiManager().findFile(createFile());
+
+    final Document document = getPsiDocumentManager().getDocument(file);
+
+    final TextBlock block = TextBlock.get(file);
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        block.performAtomically(new Runnable() {
+          @Override
+          public void run() {
+            getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+          }
+        });
+      }
+    });
+
+
+    assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+  }
+
+  public void testGetUncommittedDocuments_documentNotRegistered() throws Exception {
+    final Document document = new MockDocument();
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+      }
+    });
+
+
+    assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+  }
+
+  public void testCommitDocument_RemovesFromUncommittedList() throws Exception {
+    PsiFile file = getPsiManager().findFile(createFile());
+
+    final Document document = getPsiDocumentManager().getDocument(file);
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+      }
+    });
+
+
+    getPsiDocumentManager().commitDocument(document);
+    assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+  }
+
+  public void testCommitAllDocument_RemovesFromUncommittedList() throws Exception {
+    PsiFile file = getPsiManager().findFile(createFile());
+
+    final Document document = getPsiDocumentManager().getDocument(file);
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+      }
+    });
+
+
+    getPsiDocumentManager().commitAllDocuments();
+    assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+  }
+
+  public void testDocumentFromAlienProjectDoesNotEndsUpInMyUncommittedList() throws Exception {
+    PsiFile file = getPsiManager().findFile(createFile());
+
+    final Document document = getPsiDocumentManager().getDocument(file);
+
+    File temp = createTempDirectory();
+    final Project alienProject = createProject(new File(temp, "alien.ipr"), DebugUtil.currentStackTrace());
+    boolean succ2 = ProjectManagerEx.getInstanceEx().openProject(alienProject);
+    assertTrue(succ2);
+
+
+    try {
+      PsiManager alienManager = PsiManager.getInstance(alienProject);
+      final String alienText = "alien";
+
+      LightVirtualFile alienVirt = new LightVirtualFile("foo.java", alienText);
+      final PsiFile alienFile = alienManager.findFile(alienVirt);
+      final PsiDocumentManagerImpl alienDocManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(alienProject);
+      final Document alienDocument = alienDocManager.getDocument(alienFile);
+      //alienDocument.putUserData(CACHED_VIEW_PROVIDER, new MockFileViewProvider(alienFile));
+      assertEquals(0, alienDocManager.getUncommittedDocuments().length);
+      assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+
+      ApplicationManager.getApplication().runWriteAction(new Runnable() {
+        public void run() {
+          getPsiDocumentManager()
+            .documentChanged(new DocumentEventImpl(alienDocument, 0, "", "", alienDocument.getModificationStamp(), false));
+          assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+          assertEquals(0, alienDocManager.getUncommittedDocuments().length);
+
+          alienDocManager.documentChanged(new DocumentEventImpl(alienDocument, 0, "", "", alienDocument.getModificationStamp(), false));
+          assertEquals(0, getPsiDocumentManager().getUncommittedDocuments().length);
+          assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+
+          getPsiDocumentManager().documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+          assertEquals(1, getPsiDocumentManager().getUncommittedDocuments().length);
+          assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+
+          alienDocManager.documentChanged(new DocumentEventImpl(document, 0, "", "", document.getModificationStamp(), false));
+          assertEquals(1, getPsiDocumentManager().getUncommittedDocuments().length);
+          assertEquals(1, alienDocManager.getUncommittedDocuments().length);
+        }
+      });
+    }
+    finally {
+      ProjectUtil.closeAndDispose(alienProject);
+    }
+  }
+
+  public void testCommitInBackground() {
+    PsiFile file = getPsiManager().findFile(createFile());
+    assertTrue(file.isPhysical());
+    final Document document = getPsiDocumentManager().getDocument(file);
+
+    final Semaphore semaphore = new Semaphore();
+    semaphore.down();
+    getPsiDocumentManager().performWhenAllCommitted(new Runnable() {
+      @Override
+      public void run() {
+        assertTrue(getPsiDocumentManager().isCommitted(document));
+        semaphore.up();
+      }
+    });
+    waitAndPump(semaphore);
+    assertTrue(getPsiDocumentManager().isCommitted(document));
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.insertString(0, "class X {}");
+      }
+    });
+
+    semaphore.down();
+    getPsiDocumentManager().performWhenAllCommitted(new Runnable() {
+      @Override
+      public void run() {
+        assertTrue(getPsiDocumentManager().isCommitted(document));
+        semaphore.up();
+      }
+    });
+    waitAndPump(semaphore);
+    assertTrue(getPsiDocumentManager().isCommitted(document));
+
+    final AtomicInteger count = new AtomicInteger();
+    final Runnable action = new Runnable() {
+      @Override
+      public void run() {
+        count.incrementAndGet();
+      }
+    };
+
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.insertString(0, "/**/");
+        boolean executed = getPsiDocumentManager().cancelAndRunWhenAllCommitted("xxx", action);
+        assertFalse(executed);
+        executed = getPsiDocumentManager().cancelAndRunWhenAllCommitted("xxx", action);
+        assertFalse(executed);
+        assertEquals(0, count.get());
+      }
+    });
+
+    while (!getPsiDocumentManager().isCommitted(document)) {
+      UIUtil.dispatchAllInvocationEvents();
+    }
+    assertTrue(getPsiDocumentManager().isCommitted(document));
+    assertEquals(1, count.get());
+
+    count.set(0);
+    ApplicationManager.getApplication().runWriteAction(new Runnable() {
+      public void run() {
+        document.insertString(0, "/**/");
+        boolean executed = getPsiDocumentManager().performWhenAllCommitted(action);
+        assertFalse(executed);
+        executed = getPsiDocumentManager().performWhenAllCommitted(action);
+        assertFalse(executed);
+        assertEquals(0, count.get());
+      }
+    });
+
+    while (!getPsiDocumentManager().isCommitted(document)) {
+      UIUtil.dispatchAllInvocationEvents();
+    }
+    assertTrue(getPsiDocumentManager().isCommitted(document));
+    assertEquals(2, count.get());
+  }
+
+  private static void waitAndPump(Semaphore semaphore) {
+    while (!semaphore.waitFor(10)) {
+      UIUtil.dispatchAllInvocationEvents();
+    }
+  }
+
+  @Override
+  protected boolean isRunInWriteAction() {
+    return false;
+  }
+}
diff --git a/java/java-tests/testSrc/com/intellij/psi/PsiModificationTrackerTest.java b/java/java-tests/testSrc/com/intellij/psi/PsiModificationTrackerTest.java
new file mode 100644 (file)
index 0000000..0dc3359
--- /dev/null
@@ -0,0 +1,137 @@
+package com.intellij.psi;
+
+import com.intellij.ide.highlighter.JavaFileType;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.SelectionModel;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.util.PsiModificationTracker;
+import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
+import com.intellij.util.Processor;
+import org.jetbrains.annotations.NonNls;
+
+import java.io.IOException;
+
+/**
+ * @author Dmitry Avdeev
+ */
+public class PsiModificationTrackerTest extends LightPlatformCodeInsightFixtureTestCase {
+  public void testAnnotationNotChanged() throws Exception {
+    doReplaceTest("@SuppressWarnings(\"zz\")\n" +
+                  "public class Foo { <selection></selection>}",
+                  "hi");
+  }
+
+  public void testAnnotationNameChanged() throws Exception {
+    doReplaceTest("@Suppr<selection>ess</selection>Warnings(\"zz\")\n" +
+                  "public class Foo { }",
+                  "hi");
+  }
+
+  public void testAnnotationParameterChanged() throws Exception {
+    doReplaceTest("@SuppressWarnings(\"<selection>zz</selection>\")\n" +
+                  "public class Foo { }",
+                  "hi");
+  }
+
+  public void testAnnotationRemoved() throws Exception {
+    doReplaceTest("<selection>@SuppressWarnings(\"zz\")</selection>\n" +
+                  "public class Foo { }",
+                  "");
+  }
+
+  public void testAnnotationWithClassRemoved() throws Exception {
+    doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" +
+                  "public </selection> class Foo { }",
+                  "");
+  }
+
+  public void testRemoveAnnotatedMethod() throws Exception {
+    doReplaceTest("public class Foo {\n" +
+                  "  <selection>  " +
+                  "   @SuppressWarnings(\"\")\n" +
+                  "    public void method() {}\n" +
+                  "</selection>" +
+                  "}",
+                  "");
+  }
+
+  public void testRenameAnnotatedMethod() throws Exception {
+    doReplaceTest("public class Foo {\n" +
+                  "   @SuppressWarnings(\"\")\n" +
+                  "    public void me<selection>th</selection>od() {}\n" +
+                  "}",
+                  "zzz");
+  }
+
+  public void testRenameAnnotatedClass() throws Exception {
+    doReplaceTest("   @SuppressWarnings(\"\")\n" +
+                  "public class F<selection>o</selection>o {\n" +
+                  "    public void method() {}\n" +
+                  "}",
+                  "zzz");
+  }
+
+  public void testRemoveAll() throws Exception {
+    doReplaceTest("<selection>@SuppressWarnings(\"zz\")\n" +
+                  "public  class Foo { }</selection>",
+                  "");
+  }
+
+  public void testRemoveFile() throws Exception {
+    doTest("<selection>@SuppressWarnings(\"zz\")\n" +
+           "public  class Foo { }</selection>",
+           new Processor<PsiFile>() {
+             @Override
+             public boolean process(PsiFile psiFile) {
+               try {
+                 final VirtualFile vFile = psiFile.getVirtualFile();
+                 assert vFile != null : psiFile;
+                 vFile.delete(this);
+               }
+               catch (IOException e) {
+                 fail(e.getMessage());
+               }
+               return false;
+             }
+           });
+  }
+
+  private void doReplaceTest(@NonNls String text, @NonNls final String with) {
+    doTest(text, new Processor<PsiFile>() {
+      @Override
+      public boolean process(PsiFile psiFile) {
+        replaceSelection(with);
+        return false;
+      }
+    });
+  }
+
+  private void doTest(@NonNls String text, Processor<PsiFile> run) {
+    PsiFile file = myFixture.configureByText(JavaFileType.INSTANCE, text);
+    PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker();
+    long count = modificationTracker.getModificationCount();
+    run.process(file);
+    assertFalse(modificationTracker.getModificationCount() == count);
+  }
+
+  private void replaceSelection(final String with) {
+    new WriteCommandAction.Simple(getProject()) {
+      @Override
+      protected void run() throws Throwable {
+        SelectionModel sel = myFixture.getEditor().getSelectionModel();
+        myFixture.getEditor().getDocument().replaceString(sel.getSelectionStart(), sel.getSelectionEnd(), with);
+        PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
+      }
+    }.execute();
+  }
+
+  public void testJavaStructureModificationChangesAfterPackageDelete() {
+    PsiFile file = myFixture.addFileToProject("/x/y/Z.java", "text");
+    PsiModificationTracker modificationTracker = PsiManager.getInstance(getProject()).getModificationTracker();
+    long count = modificationTracker.getJavaStructureModificationCount();
+
+    file.getContainingDirectory().delete();
+
+    assertEquals(count + 1, modificationTracker.getJavaStructureModificationCount());
+  }
+}
diff --git a/java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java b/java/java-tests/testSrc/com/intellij/psi/SmartPsiElementPointersTest.java
new file mode 100644 (file)
index 0000000..bd83226
--- /dev/null
@@ -0,0 +1,360 @@
+package com.intellij.psi;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.codeInsight.CodeInsightTestCase;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.event.DocumentListener;
+import com.intellij.openapi.editor.event.EditorEventMulticaster;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileTypes.StdFileTypes;
+import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.impl.source.PsiFileImpl;
+import com.intellij.psi.impl.source.tree.FileElement;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StubTree;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.testFramework.PsiTestUtil;
+import com.intellij.util.FileContentUtil;
+import gnu.trove.THashSet;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+
+@PlatformTestCase.WrapInCommand
+public class SmartPsiElementPointersTest extends CodeInsightTestCase {
+  private VirtualFile myRoot;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+
+    String root = JavaTestUtil.getJavaTestDataPath() + "/codeEditor/smartPsiElementPointers";
+    PsiTestUtil.removeAllRoots(myModule, JavaSdkImpl.getMockJdk17());
+    myRoot = PsiTestUtil.createTestProjectStructure(myProject, myModule, root, myFilesToDelete);
+  }
+
+  public void testChangeInDocument() {
+    PsiClass aClass = myJavaFacade.findClass("AClass", GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    int offset = aClass.getTextOffset();
+    document.insertString(offset, "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = pointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  // This test is unfair. If pointer would be asked for getElement() between commits it'll never restore again anyway.
+  //
+  public void testChangeInDocumentTwice() {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    int offset = aClass.getTextOffset();
+    document.insertString(offset, "/*");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+    document.insertString(offset + 2, "*/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = pointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  public void testGetElementWhenDocumentModified() {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    int offset = aClass.getTextOffset();
+    document.insertString(offset, "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    document.insertString(offset, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
+
+    PsiElement element = pointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  public void testKeepBeltWhenDocumentModified() {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    int offset = aClass.getTextOffset();
+    document.insertString(offset, "/******/");
+
+    pointer.getElement();
+
+    document.insertString(offset, "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = pointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  public void testChangeInPsi() {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    int offset = aClass.getTextOffset();
+    document.insertString(offset, "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = pointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  public void testPsiChangesWithLazyPointers() throws Exception {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    final SmartPsiElementPointer<PsiIdentifier> pointer = SmartPointerManager.getInstance(myProject).createLazyPointer(aClass.getNameIdentifier());
+    final PsiComment javadoc =
+      JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createCommentFromText("/** javadoc */", aClass);
+    aClass.getParent().addBefore(javadoc, aClass);
+
+    final PsiIdentifier elt = pointer.getElement();
+    assertNotNull(elt);
+    assertSame(elt, aClass.getNameIdentifier());
+  }
+
+  public void testTypePointer() {
+    PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    final PsiTypeElement typeElement = myJavaFacade.findClass("Test",GlobalSearchScope.allScope(getProject())).getFields()[0].getTypeElement();
+
+    SmartPsiElementPointer typePointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(typeElement);
+    SmartPsiElementPointer classPointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+
+    Document aClassDocument = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+    Document testDocument = PsiDocumentManager.getInstance(myProject).getDocument(typeElement.getContainingFile());
+
+    aClassDocument.insertString(aClass.getTextOffset(), "/**/");
+    testDocument.insertString(typeElement.getTextOffset(), "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = typePointer.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiTypeElement);
+    assertTrue(element.isValid());
+    assertEquals(classPointer.getElement(), PsiUtil.resolveClassInType(((PsiTypeElement)element).getType()));
+  }
+
+  public void testCreatePointerInBeforeDocumentChange() {
+    final PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+
+    Document document = PsiDocumentManager.getInstance(myProject).getDocument(aClass.getContainingFile());
+
+    final SmartPsiElementPointer[] pointer = new SmartPsiElementPointer[1];
+    int offset = aClass.getTextOffset();
+    DocumentListener listener = new DocumentListener() {
+      @Override
+      public void beforeDocumentChange(DocumentEvent event) {
+        pointer[0] = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+      }
+
+      @Override
+      public void documentChanged(DocumentEvent event) {
+      }
+    };
+    EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster();
+    multicaster.addDocumentListener(listener);
+    try {
+      document.insertString(offset, "/******/");
+    }
+    finally {
+      multicaster.removeDocumentListener(listener);
+    }
+
+    pointer[0].getElement();
+
+    document.insertString(0, "/**/");
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    PsiElement element = pointer[0].getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+  }
+
+  public void testCreatePointerWhenNoPsiFile() {
+    myPsiManager.startBatchFilesProcessingMode(); // to use weak refs
+
+    try {
+      final PsiClass aClass = myJavaFacade.findClass("AClass",GlobalSearchScope.allScope(getProject()));
+      assertNotNull(aClass);
+
+      VirtualFile vFile = myRoot.findChild("AClass.java");
+      assertNotNull(vFile);
+      PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(myProject);
+      Document document = FileDocumentManager.getInstance().getDocument(vFile);
+
+      final SmartPsiElementPointer pointer = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+
+      System.gc();
+      /*
+      PsiFile psiFile = myPsiManager.getFileManager().getCachedPsiFile(vFile);
+      assertNull(psiFile);
+      */
+
+      document.insertString(0, "class Foo{}\n");
+
+      PsiElement element = pointer.getElement();
+      assertEquals(aClass, element);
+
+      document.insertString(0, "/**/");
+      psiDocumentManager.commitAllDocuments();
+
+      if (aClass.isValid()) {
+        aClass.getChildren();
+      }
+
+      element = pointer.getElement();
+      assertNotNull(element);
+      assertTrue(element instanceof PsiClass);
+      assertTrue(element.isValid());
+    }
+    finally {
+      myPsiManager.finishBatchFilesProcessingMode(); // to use weak refs
+    }
+  }
+
+  public void testReplaceFile() throws IOException {
+    VirtualFile vfile = myRoot.createChildData(this, "X.java");
+    VfsUtil.saveText(vfile, "public class X { public int X; }");
+
+    PsiClass aClass = myJavaFacade.findClass("X", GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+    assertTrue(aClass.isValid());
+
+    SmartPsiElementPointer classp = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    SmartPsiElementPointer filep = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass.getContainingFile());
+
+    FileContentUtil.reparseFiles(myProject, Collections.<VirtualFile>singleton(vfile), true);
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+    assertFalse(aClass.isValid());
+
+    PsiElement element = classp.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiClass);
+    assertTrue(element.isValid());
+    assertEquals(vfile, element.getContainingFile().getVirtualFile());
+
+    element = filep.getElement();
+    assertNotNull(element);
+    assertTrue(element instanceof PsiFile);
+    assertTrue(element.isValid());
+    assertEquals(vfile, element.getContainingFile().getVirtualFile());
+  }
+
+  public void testCreatePointerDoesNotLoadPsiTree() throws IOException {
+    VirtualFile vfile = myRoot.createChildData(this, "X.java");
+    VfsUtil.saveText(vfile, "public class X { public int X; }");
+
+    PsiClass aClass = myJavaFacade.findClass("X", GlobalSearchScope.allScope(getProject()));
+    assertNotNull(aClass);
+    assertTrue(aClass.isValid());
+
+    PsiFileImpl file = (PsiFileImpl)aClass.getContainingFile();
+
+    assertTreeLoaded(file, false);
+
+    SmartPsiElementPointer p = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(aClass);
+    assertNotNull(p);
+
+    assertTreeLoaded(file, false);
+
+    assertInstanceOf(p.getElement(), PsiClass.class);
+
+    assertTreeLoaded(file, false);
+
+    PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
+    Document document = documentManager.getDocument(file);
+    document.insertString(0, "/** asdasd */");
+    documentManager.commitAllDocuments();
+
+    // loaded tree
+    assertTreeLoaded(file, true);
+
+    assertInstanceOf(p.getElement(), PsiClass.class);
+
+    assertTreeLoaded(file, true);
+  }
+
+  private static void assertTreeLoaded(PsiFileImpl file, boolean loaded) {
+    FileElement treeElement = file.getTreeElement();
+    assertEquals(loaded, treeElement != null);
+    StubTree stubTree = file.getStubTree();
+    assertEquals(loaded, stubTree == null);
+  }
+
+  public void testPointerDisambiguationAfterDupLine() throws Exception {
+    PsiJavaFile file = (PsiJavaFile)configureByText(StdFileTypes.JAVA, "class XXX{ void foo() { \n" +
+                                       " <caret>foo();\n" +
+                                       "}}");
+    PsiClass aClass = file.getClasses()[0];
+    assertNotNull(aClass);
+
+    PsiReferenceExpression ref1 = PsiTreeUtil.getParentOfType(PsiUtilBase.getElementAtCaret(getEditor()), PsiReferenceExpression.class);
+    SmartPsiElementPointer pointer1 = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(ref1);
+
+    ctrlD();
+    PsiDocumentManager.getInstance(myProject).commitAllDocuments();
+
+    Set<PsiReferenceExpression> refs = new THashSet<PsiReferenceExpression>();
+    int offset=0;
+    while (true) {
+      offset = getEditor().getDocument().getText().indexOf("foo();", offset+1);
+      if (offset == -1) break;
+      PsiReferenceExpression ref2 = PsiTreeUtil.getParentOfType(getFile().findElementAt(offset), PsiReferenceExpression.class);
+      refs.add(ref2);
+    }
+    refs.remove(ref1);
+    assertEquals(1, refs.size());
+    PsiReferenceExpression ref2 = refs.iterator().next();
+    assertNotSame(ref1, ref2);
+    SmartPsiElementPointer pointer2 = SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(ref2);
+    assertNotSame(pointer1, pointer2);
+
+    PsiElement element1 = pointer1.getElement();
+    PsiElement element2 = pointer2.getElement();
+
+    assertNotNull(element1);
+    assertNotNull(element2);
+    assertNotSame(element1, element2);
+
+    assertFalse(SmartPointerManager.getInstance(myProject).pointToTheSameElement(pointer1, pointer2));
+  }
+}
diff --git a/java/java-tests/testSrc/com/intellij/psi/TreeIsCorrectAfterDiffReparseTest.java b/java/java-tests/testSrc/com/intellij/psi/TreeIsCorrectAfterDiffReparseTest.java
new file mode 100644 (file)
index 0000000..b5e1712
--- /dev/null
@@ -0,0 +1,1097 @@
+/*
+ * @author max
+ */
+package com.intellij.psi;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.psi.impl.DebugUtil;
+import com.intellij.testFramework.LightCodeInsightTestCase;
+
+public class TreeIsCorrectAfterDiffReparseTest extends LightCodeInsightTestCase {
+
+  public void testIDEADEV41862() throws Exception {
+    String part1 = "package com.test;\n" +
+                   "\n" +
+                   "\n" +
+                   "//------------------------------------------------------------------\n" +
+                   "// Copyright (c) 1999, 2007\n" +
+                   "// WorkForce Software, Inc.\n" +
+                   "// All rights reserved.\n" +
+                   "//\n" +
+                   "// Web-site: http://www.workforcesoftware.com\n" +
+                   "// E-mail:   support@workforcesoftware.com\n" +
+                   "// Phone:    (877) 493-6723\n" +
+                   "//\n" +
+                   "// This program is protected by copyright laws and is considered\n" +
+                   "// a trade secret of WorkForce Software.  Access to this program\n" +
+                   "// and source code is granted only to licensed customers.  Under\n" +
+                   "// no circumstances may this software or source code be distributed\n" +
+                   "// without the prior written consent of WorkForce Software.\n" +
+                   "// -----------------------------------------------------------------\n" +
+                   "\n" +
+                   "import com.workforcesoftware.Data.Employee.*;\n" +
+                   "import com.workforcesoftware.Data.*;\n" +
+                   "import com.workforcesoftware.Data.assignment.Asgnmt_master;\n" +
+                   "import com.workforcesoftware.Data.assignment.Asgnmt;\n" +
+                   "import com.workforcesoftware.Data.Output.Time_sheet_output;\n" +
+                   "import com.workforcesoftware.Data.TimeSched.PayPeriodData;\n" +
+                   "import com.workforcesoftware.Data.TimeSched.TimeSchedUtils;\n" +
+                   "import com.workforcesoftware.Data.TimeSched.Schedule.Schedule_detailList;\n" +
+                   "import com.workforcesoftware.Data.TimeSched.TimeSheet.*;\n" +
+                   "import com.workforcesoftware.Data.assignment.Asgnmt_masterList;\n" +
+                   "import com.workforcesoftware.Exceptions.*;\n" +
+                   "import com.workforcesoftware.Gen.Choice.Approval_event_type;\n" +
+                   "import com.workforcesoftware.Gen.Choice.Transaction_status;\n" +
+                   "import com.workforcesoftware.Gen.Choice.Messages;\n" +
+                   "import com.workforcesoftware.Gen.Choice.Program_source;\n" +
+                   "import com.workforcesoftware.Gen.Other.DbRec.DbRecTime_sheet_output;\n" +
+                   "import com.workforcesoftware.Gen.Other.DbRec.DbRecTime_sheet;\n" +
+                   "import com.workforcesoftware.Gen.Other.List.WDateList;\n" +
+                   "import com.workforcesoftware.Gen.Policy.Right_grp;\n" +
+                   "import com.workforcesoftware.Gen.Policy.Policy_profile;\n" +
+                   "import com.workforcesoftware.Policy.*;\n" +
+                   "import com.workforcesoftware.Util.DateTime.WDate;\n" +
+                   "import com.workforcesoftware.Util.DateTime.WDateTime;\n" +
+                   "import com.workforcesoftware.Util.DB.ListWriter;\n" +
+                   "import com.workforcesoftware.Util.DB.DbRecFieldCopier;\n" +
+                   "import com.workforcesoftware.ClientRequests.TimeSched.TimeSchedUtil;\n" +
+                   "import com.workforcesoftware.ClientRequests.TimeSched.PayPeriodInfo;\n" +
+                   "import com.workforcesoftware.ClientRequests.TimeEntry.ApprovalInfo;\n" +
+                   "import com.workforcesoftware.ClientRequests.TimeEntry.BankBalanceResults;\n" +
+                   "import com.workforcesoftware.Misc.ServerErrorLogger;\n" +
+                   "import com.workforcesoftware.Misc.ServerError;\n" +
+                   "import com.workforcesoftware.AssignmentPeriod.*;\n" +
+                   "import com.workforcesoftware.AssignmentPeriod.TimeSheetState;\n" +
+                   "import com.workforcesoftware.Dictionary.DataDictionary;\n" +
+                   "\n" +
+                   "import java.sql.SQLException;\n" +
+                   "import java.util.*;\n" +
+                   "import org.log4j.Category;\n" +
+                   "\n" +
+                   "/**\n" +
+                   " * Holds definition of {@link CalcInfo}\n" +
+                   " */\n" +
+                   "class AssignmentManager {\n" +
+                   "  /**\n" +
+                   "   * Implementation of {@link TimeSheetCalculationInfo}.\n" +
+                   "   * Extracts all the required data from AllCalcDataManager, AllCalculationData, Time_sheet, etc.\n" +
+                   "   * Makes copies of all mutable data, unmodifiable lists where possible.\n" +
+                   "   */\n" +
+                   "  static class CalcInfo implements TimeSheetCalculationInfo {\n" +
+                   "    /**\n" +
+                   "     * Use the passed in AllCalculationData object - DO NOT try to get it from the passed in AllCalcDataManager because\n" +
+                   "     * the ACD object that's passed in is obtained from AssignmentManager.getAllCalcData method which handles the\n" +
+                   "     * scenario where a prior period may need to be amended automatically and if ACDM.getAllCalcData() method is called,\n" +
+                   "     * you might get an unmodifiable ACD\n" +
+                   "     * @param acdm\n" +
+                   "     * @param acd\n" +
+                   "     * @param timeSheetId\n" +
+                   "     * @param parms\n" +
+                   "     */\n" +
+                   "    CalcInfo(AllCalcDataManager acdm, AllCalculationData acd, TimeSheetIdentifier timeSheetId, TimeEntryParms parms) {\n" +
+                   "      // we'll extract all these vars separately, for readability\n" +
+                   "      final Right_grp rightGrp = parms.getRight_grp(timeSheetId);\n" +
+                   "      final AllPolicies ap = acd.getAllPolicies();\n" +
+                   "      final WDate ppEndForToday = TimeSchedUtil.getPayPeriodRangeForToday(acdm).getEnd();\n" +
+                   "\n" +
+                   "      this.acd = acd;\n" +
+                   "      this.timeSheetIdentifier = timeSheetId;\n" +
+                   "      this.approval_eventList = acd.getApproval_eventList().getUnmodifiableList();\n" +
+                   "      this.policyProfile = acd.getAsgnmtMaster().getPolicyProfilePolicy(ppEndForToday, ap);\n" +
+                   "      this.adjustmentsPaidWithTimesheet = createAdjustmentsPaidWithTimesheet(acdm, acd);\n" +
+                   "      this.bankBalanceResults = acdm.getBankDataForBankBalancePreview(ap, acd, rightGrp.getRight_grp(), acd.getPP_end());\n" +
+                   "      this.tsoListForPayPreview = Collections.unmodifiableList(acdm.getTsoListForPayPreview(acd, rightGrp.getRight_grp()));\n" +
+                   "      this.approvedDays = createApprovedDays(acd);\n" +
+                   "\n" +
+                   "      try {\n" +
+                   "        // these are fairly involved calculations, and we want to validate the pay period list,\n" +
+                   "        // so we'll do them both here together instead of upon request\n" +
+                   "        employeePeriodInfo = acdm.getEmployeePeriodInfo(timeSheetId.getPpEnd());\n" +
+                   "        payPeriodList = TimeSchedUtil.calcPayPeriodList(acdm, rightGrp.getRight_grp());\n" +
+                   "      }\n" +
+                   "      catch (Exception e) {\n" +
+                   "        throw new InternalApplicationException(\"Loading calc data for: \" + timeSheetId, e);\n" +
+                   "      }\n" +
+                   "      assertPayPeriodList();\n" +
+                   "\n" +
+                   "      AssignmentPeriodStateImpl aps = new AssignmentPeriodStateImpl(employeePeriodInfo,\n" +
+                   "          rightGrp, parms.getSystemFeature(), ap, ppEndForToday, acdm, policyProfile);\n" +
+                   "      assignmentPeriodState = aps;\n" +
+                   "      timeSheetState = new TimeSheetStateImpl(this, aps, policyProfile);\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    /**\n" +
+                   "     * Returns an ApprovalInfo object, which contains information about whether\n" +
+                   "     * employee/manager approved a timesheet.\n" +
+                   "     *\n" +
+                   "     * @see ApprovalInfo\n" +
+                   "     */\n" +
+                   "    public ApprovalInfo getApprovalInfo() { return new ApprovalInfo(acd.getTime_sheet(), approval_eventList); }\n" +
+                   "\n" +
+                   "    public Collection<DbRecTime_sheet_output> getAdjustmentsPaidWithTimesheet() {\n" +
+                   "      return adjustmentsPaidWithTimesheet;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Approval_eventList getApproval_eventList() {\n" +
+                   "      return approval_eventList;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "\n" +
+                   "    /**\n" +
+                   "     * Returns state information about a given assignment and period, encompassing\n" +
+                   "     * the cross-section of security related settings calculated from:\n" +
+                   "     * <ul>\n" +
+                   "     * <li>App_user Roles (app_user_right and right_grp tables)\n" +
+                   "     * <li>Assignment effective dates\n" +
+                   "     * <li>Employee record effective dates\n" +
+                   "     * <li>System_feature read/write privileges\n" +
+                   "     * </ul>\n" +
+                   "     *\n" +
+                   "     * @return not ever null\n" +
+                   "     */\n" +
+                   "    public AssignmentPeriodState getAssignmentPeriodState() {\n" +
+                   "      return assignmentPeriodState;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Set<WDate> getDailyApprovalDays() {\n" +
+                   "      return approvedDays;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    /**\n" +
+                   "     * Returns map to the accrual banks data, which is a read only reference\n" +
+                   "     * of the information contained there. The banks returned will be all banks attached\n" +
+                   "     * to the assignment, including aggregate banks if applicable.\n" +
+                   "     *\n" +
+                   "     * The list will not contain any banks that the current App_user's Right_grp cannot view for this assignment's\n" +
+                   "     * Policy_profile (as defined by {@link com.workforcesoftware.Gen.Policy.User_entry_rule_detail#getDisplay_bank_set()})\n" +
+                   "     */\n" +
+                   "    public List<BankBalanceResults> getBankBalanceResults() {\n" +
+                   "      return bankBalanceResults;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Approval_event getLastValidEmployeeApproveEvent() {\n" +
+                   "      return approval_eventList.getLastValidEmployeeApproveEvent();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Time_sheet_detail_splitList getTime_sheet_detail_splitList() {\n" +
+                   "      return acd.getTime_sheet().getTime_sheet_detail_splitList().getUnmodifiableList();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Time_sheet_detailList getTime_sheet_detailList() {\n" +
+                   "      return acd.getTime_sheet().getDetailList().getUnmodifiableList();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Schedule_detailList getSchedule_detailList() {\n" +
+                   "      return acd.getSchedule().getDetailList().getUnmodifiableList();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Time_sheet_exceptionList getTime_sheet_exceptionList() {\n" +
+                   "      return acd.getTime_sheet().getTime_sheet_exceptionList().getUnmodifiableList();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public List<Time_sheet_output> getTsoListForPayPreview() {\n" +
+                   "      return tsoListForPayPreview;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Approval_eventList getValidManagerApproveEvents() {\n" +
+                   "      return approval_eventList.getValidManagerApproveEvents();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public TimeSheetIdentifier getTimeSheetIdentifier() {\n" +
+                   "      return timeSheetIdentifier;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public EmployeePeriodInfo getEmployeePeriodInfo() {\n" +
+                   "      return employeePeriodInfo;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Employee_master getEmployeeMaster() {\n" +
+                   "      return new Employee_master(acd.getEmployee_master());\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Employee getEmployee() {\n" +
+                   "      return new Employee(acd.getEmployee_master().getEmployeeAsOfOrAfter(getPPEnd()));\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Asgnmt_master getAsgnmtMaster() {\n" +
+                   "      return new Asgnmt_master(acd.getAsgnmtMaster());\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Asgnmt getAsgnmt() {\n" +
+                   "      return new Asgnmt(acd.getAsgnmt());\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public WDate getPPEnd() {\n" +
+                   "      return employeePeriodInfo.getPp_end();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public WDate getPPBegin() {\n" +
+                   "      return employeePeriodInfo.getPp_begin();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public Policy_profile getPolicy_profile() {\n" +
+                   "      return policyProfile;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "\n" +
+                   "    /**\n" +
+                   "     * Return state information about the timesheet, which considers security\n" +
+                   "     * relationship between the current state (locked/closed/amended) in relation to:\n" +
+                   "     * <ul>\n" +
+                   "     * <li>App_user Roles (app_user_right and right_grp tables)\n" +
+                   "     * <li>Assignment effective dates\n" +
+                   "     * <li>Employee record effective dates\n" +
+                   "     * <li>System_feature read/write privileges\n" +
+                   "     * <li>Approval level of the timesheet\n" +
+                   "     * </ul>\n" +
+                   "     *\n" +
+                   "     * @return not ever null\n" +
+                   "     */\n" +
+                   "    public TimeSheetState getTimeSheetState() {\n" +
+                   "      return timeSheetState;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public int getVersionNumber() {\n" +
+                   "      return timeSheetIdentifier.getVersion();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public PayPeriodData getPayPeriodData() {\n" +
+                   "      return acd.getPayPeriodData();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public boolean getIsNewlyUserAmended() {\n" +
+                   "      return acd.isNewlyUserAmended();\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    public List<PayPeriodInfo> getPayPeriodList() {\n" +
+                   "      return payPeriodList;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    private static Collection<DbRecTime_sheet_output> createAdjustmentsPaidWithTimesheet(AllCalcDataManager acdm, AllCalculationData acd) {\n" +
+                   "      try { return Collections.unmodifiableCollection(acdm.getAdjustmentsPaidWithTimesheet(acd)); }\n" +
+                   "      catch (SQLException e) { throw new InternalApplicationException(\"Unexpected SQL Exception\", e); }\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    private void assertPayPeriodList() {\n" +
+                   "      //TODO - probably need to show a \"nice\" message to the user saying that the employee doesn't\n" +
+                   "      //TODO - have a viewable/editable pay period.\n" +
+                   "      if(payPeriodList.isEmpty()) {\n" +
+                   "        throw new InternalApplicationException(\"No viewable/editable pay periods found for employee \"\n" +
+                   "                + employeePeriodInfo.getEmployeeMaster().getEmployee());\n" +
+                   "      }\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    private static Set<WDate> createApprovedDays(AllCalculationData acd) {\n" +
+                   "      // calculate days approved by daily approvals\n" +
+                   "      Set<WDate> approvedDays = new HashSet<WDate>();\n" +
+                   "      for( WDate date : acd.getPayPeriodData().getActiveDates().getAllDates() ) {\n" +
+                   "        if( acd.isDayApproved(date) ) { approvedDays.add(date); }\n" +
+                   "      }\n" +
+                   "      return Collections.unmodifiableSet(approvedDays);\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    private final Collection<DbRecTime_sheet_output> adjustmentsPaidWithTimesheet;\n" +
+                   "    private final Approval_eventList approval_eventList;\n" +
+                   "    private final AssignmentPeriodState assignmentPeriodState;\n" +
+                   "    private final List<BankBalanceResults> bankBalanceResults;\n" +
+                   "    private final List<Time_sheet_output> tsoListForPayPreview;\n" +
+                   "    private final TimeSheetIdentifier timeSheetIdentifier;\n" +
+                   "    private final TimeSheetState timeSheetState;\n" +
+                   "    private final EmployeePeriodInfo employeePeriodInfo;\n" +
+                   "    private final ArrayList<PayPeriodInfo> payPeriodList;\n" +
+                   "    private final Set<WDate> approvedDays;\n" +
+                   "    private final Policy_profile policyProfile;\n" +
+                   "    private final AllCalculationData acd;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  AssignmentManager(GeneratedId assignmentId, Set<TimeSheetIdentifier> timeSheetIdentifiers, TimeEntryParmsPerAssignment parms) {\n" +
+                   "    this.asgnmtMaster = getAggregateOrSingleAssignmentMaster(assignmentId);\n" +
+                   "    setClassFields(parms, timeSheetIdentifiers);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Obtains the single or aggregate assignment master for the given assignmentId.  If the given assignmentId is not a\n" +
+                   "   * single or aggregate assignment, fetches the aggregate associated with the given assignmentId and returns that.\n" +
+                   "   *\n" +
+                   "   * @param assignmentId Id of the assigment to load.\n" +
+                   "   * @return the single or aggregate assignment master for the given assignmentId.\n" +
+                   "   */\n" +
+                   "  private static Asgnmt_master getAggregateOrSingleAssignmentMaster(GeneratedId assignmentId) {\n" +
+                   "    Asgnmt_master am = Asgnmt_master.load(assignmentId);\n" +
+                   "    if(am.isAggregate() || am.isSingle()) {\n" +
+                   "      return am;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    //If it's not a single or aggregate, we need to load the aggregate and load that.\n" +
+                   "    return Asgnmt_master.load(am.getAggregate_asgnmt());\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  AggregateTimeEntryTransactionResults load() {\n" +
+                   "    return loadImpl();\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Reverts any changes that have not been committed to the database on this AssignmentManager\n" +
+                   "   */\n" +
+                   "  void revert() {\n" +
+                   "    updatedAllCalcDataManager = null;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * @return Return initial transaction results from originalAllCalcData, which must be set before calling this.\n" +
+                   "   */\n" +
+                   "  private AggregateTimeEntryTransactionResults loadImpl() {\n" +
+                   "    AggregateTimeEntryTransactionResults aggregateResults = (AggregateTimeEntryTransactionResults) parms.getTimeEntryResultsFactory().newInstance();\n" +
+                   "    for (TimeSheetIdentifier timeSheetId : getTimeSheetIdentifiers()) {\n" +
+                   "      AllCalculationData acd = getOriginalAllCalcData(timeSheetId);\n" +
+                   "      // Make sure system_record_id's are assigned - TimeEntryManager and client do not function correctly without\n" +
+                   "      assignSystemRecordIds(acd);\n" +
+                   "      CalcInfo calcInfo = new CalcInfo(getOriginalAllCalcDataManager(timeSheetId.getAsgnmt()), acd, timeSheetId, parms);\n" +
+                   "      //todo-ute-nazim do we really need to perform TimeSheetDiff for the initial load ?\n" +
+                   "      TimeEntryTransactionResults singleTimeSheetResults =\n" +
+                   "              new TimeSheetDiff(timeSheetId, acd, calcInfo, TimeSheetCounters.getEmptyCounters(), NewToOldIdMap.EMPTY,\n" +
+                   "                                Collections.EMPTY_LIST, new StatusMapsForTimesheetAndSchedule(), true, parms, null);\n" +
+                   "      aggregateResults.add(singleTimeSheetResults);\n" +
+                   "    }\n" +
+                   "    return aggregateResults;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Assign system_record_id's for time_sheet, time_sheet_detail's and time_sheet_exception's\n" +
+                   "   * @param acd\n" +
+                   "   */\n" +
+                   "  private void assignSystemRecordIds(AllCalculationData acd) {\n" +
+                   "    assignSystemRecordId(acd.getTime_sheet());\n" +
+                   "    assignSystemRecordIds(acd.getTime_sheet().getTime_sheet_detailList());\n" +
+                   "    assignSystemRecordIds(acd.getTime_sheet().getTime_sheet_exceptionList());\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * todo: store the event.getComment()\n" +
+                   "   * @param event\n" +
+                   "   */\n" +
+                   "  AggregateTimeEntryTransactionResults amend(TransactionApprovalEvent event) {\n" +
+                   "    TimeSheetIdentifier singleTimeSheetId = event.getTimeSheetIdentifier();\n" +
+                   "    //TODO: Shouldn't this call createOriginalAllCalcDataManagerIfNeeded?  Seems like we needlessly reload the original\n" +
+                   "    //TODO: ACDM.  This is because a timesheet which was prepared for amendment couldn't have been modified before it\n" +
+                   "    //TODO: was amended.\n" +
+                   "    invalidateAllCalcDataManagers();\n" +
+                   "\n" +
+                   "    // Create the amended ACD and put into the ACDM cache\n" +
+                   "    EmployeePeriodInfo epInfo = null;\n" +
+                   "    try {\n" +
+                   "      AllCalcDataManager acdm = getOriginalAllCalcDataManager(singleTimeSheetId.getAsgnmt());\n" +
+                   "      epInfo = acdm.getEmployeePeriodInfo(singleTimeSheetId.getPpEnd());\n" +
+                   "      AllCalculationData amendedAllCalcData = acdm.createAmendedAllCalcData(epInfo, parms.getApp_user(), WDateTime.now());\n" +
+                   "      // No need to hook this up to approval change logic, since it is an in-memory change so far.\n" +
+                   "      //Recalculate the amended ACD object so that timesheet exceptions that are on the closed version (if any)\n" +
+                   "      // get created on the amended timesheet as well\n" +
+                   "      amendedAllCalcData.recalc(acdm);\n" +
+                   "    }\n" +
+                   "    catch (SQLException e) {\n" +
+                   "      throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+                   "    }\n" +
+                   "    catch (MultipleRowDbRecException e) {\n" +
+                   "      throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+                   "    } catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"amending time sheet for \" + singleTimeSheetId, e);\n" +
+                   "    }\n" +
+                   "    return loadImpl();\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  TimeSheetTransactionApplier applyTransaction(TimeSheetIdentifier id, TimeEntryTransaction trans) {\n" +
+                   "    AllCalcDataManager updatedAcdm = getUpdatedAllCalcDataManager(id.getAsgnmt());\n" +
+                   "    AllCalculationData acd = getAllCalcData(updatedAcdm, id);\n" +
+                   "    return new TimeSheetTransactionApplier(trans, updatedAcdm, acd, parms, id);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private void recalc(TimeSheetIdentifier timeSheetId, Approval_event_type approvalEventType) {\n" +
+                   "    AllCalcDataManager updatedAcdm = getUpdatedAllCalcDataManager(timeSheetId.getAsgnmt());\n" +
+                   "    AllCalculationData acd = getAllCalcData(updatedAcdm, timeSheetId);\n" +
+                   "    try {\n" +
+                   "      if (approvalEventType == Approval_event_type.SAVE_SCHEDULE) {\n" +
+                   "        // if we're saving a change to the schedule, the timesheet might need to be re-initialized.\n" +
+                   "        acd.reinitTimeSheet(updatedAcdm, true);\n" +
+                   "      }\n" +
+                   "      acd.recalc(updatedAcdm);\n" +
+                   "    }\n" +
+                   "    catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"calculate for \" + timeSheetId, e);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Save one timesheet to a ListWriter using AllCalculationData.\n" +
+                   "   * @param timeSheetId\n" +
+                   "   * @param saveEvent\n" +
+                   "   * @throws Exception\n" +
+                   "   */\n" +
+                   "  void save(TimeSheetIdentifier timeSheetId, Approval_event_type saveEvent) throws Exception {\n" +
+                   "    GeneratedId asgnmtId = timeSheetId.getAsgnmt();\n" +
+                   "    AllCalcDataManager acdMgr = getUpdatedAllCalcDataManager(asgnmtId);\n" +
+                   "    AllCalculationData acd = getAllCalcData(acdMgr, timeSheetId);\n" +
+                   "\n" +
+                   "    // TODO: it'd be nice if we were able to retry a save if it failed because of unrelated changes (to accomodate for\n" +
+                   "    // concurrent save operations on other component timesheets besides the one that the user is trying to save)\n" +
+                   "    final ListWriter lw = new ListWriter();\n" +
+                   "    acd.saveAfterApplyingApprovalEvent(acdMgr, saveEvent, lw);\n" +
+                   "\n" +
+                   "    //The exceptions must be generated after the ACD has performed approval related operations.\n" +
+                   "    // Loading the original ACD to get the timesheet object before the approval. This will be used to determine\n" +
+                   "    // timesheet's approval level before this save event.\n" +
+                   "    AllCalculationData originalAcd = getAllCalcData(getOriginalAllCalcDataManager(asgnmtId), timeSheetId);\n" +
+                   "    acdMgr.generateExceptionNotifications(acd, originalAcd.getTime_sheet(), acd.getTime_sheet(), lw);\n" +
+                   "    lw.writeLists();\n" +
+                   "\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * If time sheets were saved and written to the database successfully, update internal data\n" +
+                   "   * to reflect what's in the database as the new \"original\" data.\n" +
+                   "   */\n" +
+                   "  void postSave() {\n" +
+                   "    originalAllCalcDataManager = updatedAllCalcDataManager;\n" +
+                   "    updatedAllCalcDataManager = null;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Returns true if the given timesheet contains exceptions that should prevent save.\n" +
+                   "   * @param timeSheetId time sheet ID\n" +
+                   "   * @return true if exceptions exist that should prevent save, false otherwise.\n" +
+                   "   */\n" +
+                   "  boolean hasExceptionsPreventingSave(TimeSheetIdentifier timeSheetId) {\n" +
+                   "    AllCalculationData acd = getUpdatedAllCalcData(timeSheetId);\n" +
+                   "    try {\n" +
+                   "      return acd.getTime_sheet().getTime_sheet_exceptionList().getDisallow_timesheet_save(acd.getAllPolicies());\n" +
+                   "    }\n" +
+                   "    catch (PolicyLookupRequiredException e) {\n" +
+                   "      throw new InternalApplicationException(\"Policy error on timesheet \" + timeSheetId);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Returns true if the given timesheet contains exceptions that should prevent submit.\n" +
+                   "   * @param timeSheetId time sheet ID\n" +
+                   "   * @return true if exceptions exist that should prevent submit, false otherwise.\n" +
+                   "   */\n" +
+                   "  boolean hasExceptionsPreventingSubmit(TimeSheetIdentifier timeSheetId) {\n" +
+                   "    AllCalculationData acd = getUpdatedAllCalcData(timeSheetId);\n" +
+                   "    try {\n" +
+                   "      return acd.getTime_sheet().getTime_sheet_exceptionList().getDisallow_timesheet_submit(acd.getAllPolicies());\n" +
+                   "    }\n" +
+                   "    catch (PolicyLookupRequiredException e) {\n" +
+                   "      throw new InternalApplicationException(\"Policy error on timesheet \" + timeSheetId);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Compute {@link TimeEntryTransactionResults} changes to be returned in client.\n" +
+                   "   * @param timeSheetId\n" +
+                   "   * @param trans transaction which client just sent\n" +
+                   "   * @param applyResults results (errors) of applying the transaction\n" +
+                   "   * @param timeSheetSavedStatus a status to be added representing the save results - SAVED or ERROR, or null if none.\n" +
+                   "   * @param transactionSuccessful value for {@link TimeEntryTransactionResults#getTransactionWasSuccessful}.\n" +
+                   "   */\n" +
+                   "  TimeSheetDiff getDiff(TimeSheetIdentifier timeSheetId, TimeEntryTransaction trans,\n" +
+                   "                        TimeSheetTransactionApplier applyResults, TransactionStatus timeSheetSavedStatus,\n" +
+                   "                        boolean transactionSuccessful)\n" +
+                   "  {\n" +
+                   "    AllCalcDataManager acdm = getLatestAllCalcDataManager(timeSheetId.getAsgnmt());\n" +
+                   "    AllCalculationData acd = getAllCalcData(acdm, timeSheetId);\n" +
+                   "    NewToOldIdMap newToOldIdMap = applyResults.getNewToOldIdMap();\n" +
+                   "    StatusMapsForTimesheetAndSchedule timeSheetRowStatusMap = applyResults.getTimeEntryRowErrorMap();\n" +
+                   "\n" +
+                   "    if (cat.isDebugEnabled()) {\n" +
+                   "      ObjectDumper.debug(cat, \"TimeSheetDiff getDiff before\", timeSheetRowStatusMap, null, true);\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    List<TransactionStatus> timeSheetStatuses = new ArrayList<TransactionStatus>(applyResults.getTimeSheetErrors());\n" +
+                   "    TimeSheetCounters counters = new TimeSheetCounters(trans, timeSheetId, newToOldIdMap);\n" +
+                   "    if (timeSheetSavedStatus != null) {\n" +
+                   "      timeSheetStatuses.add(timeSheetSavedStatus);\n" +
+                   "      if (timeSheetSavedStatus.getTransaction_status() == Transaction_status.SAVED ||\n" +
+                   "              timeSheetSavedStatus.getTransaction_status() == Transaction_status.ERROR) {\n" +
+                   "        // if we saved or there is an error mark every TimeEntryRow in the transaction as such.\n" +
+                   "        // get all row id's from the transaction (new id's - not temp id's)\n" +
+                   "        Collection transTimeSheetRowIds = applyResults.getTransactionTimeSheetRowIds();\n" +
+                   "        Collection transScheduleRowIds = applyResults.getTransactionScheduleRowIds();\n" +
+                   "        timeSheetRowStatusMap = new StatusMapsForTimesheetAndSchedule(transTimeSheetRowIds, transScheduleRowIds, timeSheetSavedStatus);\n" +
+                   "        timeSheetRowStatusMap.addAll(applyResults.getTimeEntryRowErrorMap());\n" +
+                   "      }\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    if (cat.isDebugEnabled()) {\n" +
+                   "      ObjectDumper.debug(cat, \"TimeSheetDiff getDiff after\", timeSheetRowStatusMap, null, true);\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    CalcInfo calcInfo = new CalcInfo(acdm, acd, timeSheetId, parms);\n" +
+                   "    return new TimeSheetDiff(timeSheetId, acd, calcInfo, counters, newToOldIdMap, timeSheetStatuses,\n" +
+                   "                             timeSheetRowStatusMap, transactionSuccessful, parms, trans);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  TimeSheetCalculationInfo getCalculationInfo(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+                   "    validate(timeSheetIdentifier);\n" +
+                   "    final AllCalcDataManager acdm = getLatestAllCalcDataManager(timeSheetIdentifier.getAsgnmt());\n" +
+                   "    return new CalcInfo(acdm, getAllCalcData(acdm, timeSheetIdentifier), timeSheetIdentifier, parms);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Return the calculation info without auto-amending\n" +
+                   "   * @param acdm\n" +
+                   "   * @param timeSheetIdentifier\n" +
+                   "   * @return\n" +
+                   "   */\n" +
+                   "  private TimeSheetCalculationInfo getCalculationInfo(AllCalcDataManager acdm, TimeSheetIdentifier timeSheetIdentifier) {\n" +
+                   "    validate(timeSheetIdentifier);\n" +
+                   "    try {\n" +
+                   "      return new CalcInfo(acdm, acdm.getAllCalcData(timeSheetIdentifier.getPpEnd(), timeSheetIdentifier.getVersion()), timeSheetIdentifier, parms);\n" +
+                   "    } catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"Error creating CalcInfo \", e); \n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private void invalidateAllCalcDataManagers() {\n" +
+                   "    originalAllCalcDataManager = null;\n" +
+                   "    updatedAllCalcDataManager = null;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private void createUpdatedAllCalcDataManager(Set<TimeSheetIdentifier> timeSheetIds) {\n" +
+                   "    AllCalcDataManager origAcdMgr = getOriginalAllCalcDataManager(asgnmtMaster.getAsgnmt());\n" +
+                   "    try {\n" +
+                   "      WDateList dateList = new WDateList();\n" +
+                   "      for(TimeSheetIdentifier id : timeSheetIds) {\n" +
+                   "        dateList.add(id.getPpEnd());\n" +
+                   "      }\n" +
+                   "      updatedAllCalcDataManager = origAcdMgr.copyForUpdate(dateList);\n" +
+                   "    } catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"Cloning for \" + timeSheetIds, e);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private void validate(TimeSheetIdentifier timeSheetId) throws IllegalArgumentException {\n" +
+                   "    if (!timeSheetIdentifiers.contains(timeSheetId)) {\n" +
+                   "      throw new IllegalArgumentException(\"Invalid time sheet specified: \" + timeSheetId\n" +
+                   "        + \". not in \" + timeSheetIdentifiers);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Obtains the original AllCalcDataManager for the given assignment Id.  The assignment id must be given because in a\n" +
+                   "   * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+                   "   * to the aggregate assignment.\n" +
+                   "   *\n" +
+                   "   * @param asgnmtId The id of the assignment to load.\n" +
+                   "   * @return the original AllCalcDataManager for the given assignment Id\n" +
+                   "   */\n" +
+                   "  private AllCalcDataManager getOriginalAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+                   "    if(originalAllCalcDataManager == null) {\n" +
+                   "      originalAllCalcDataManager = createOriginalAllCalcDataManager();\n" +
+                   "      updatedAllCalcDataManager = null;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    if(asgnmtId.equals(originalAllCalcDataManager.getAsgnmtId())) {\n" +
+                   "      return originalAllCalcDataManager;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    return originalAllCalcDataManager.getAllCalcDataManager(asgnmtId);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private AllCalcDataManager createOriginalAllCalcDataManager() {\n" +
+                   "    AllPolicies allPolicies = PolicyManager.getInstance().getAllPolicies();\n" +
+                   "    try {\n" +
+                   "      return AllCalcDataManager.createForAsgnmt(asgnmtMaster, allPolicies);\n" +
+                   "    }\n" +
+                   "    catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"Failed to load ACDM for assignment with id:\"+asgnmtMaster.getAsgnmt(), e);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Obtains the updated AllCalcDataManager for the given assignment Id.  The assignment id must be given because in a\n" +
+                   "   * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+                   "   * to the aggregate assignment.\n" +
+                   "   *\n" +
+                   "   * @param asgnmtId The id of the assignment to load.\n" +
+                   "   * @return the updated AllCalcDataManager for the given assignment Id\n" +
+                   "   */\n" +
+                   "  private AllCalcDataManager getUpdatedAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+                   "    if(updatedAllCalcDataManager == null) {\n" +
+                   "      throw new InternalApplicationException(\"Attempted to use the updated all calc data manager before it was created.\");\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    if(asgnmtId.equals(updatedAllCalcDataManager.getAsgnmtId())) {\n" +
+                   "      return updatedAllCalcDataManager;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    return updatedAllCalcDataManager.getAllCalcDataManager(asgnmtId);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Obtains the updated AllCalcDataManager for the given assignment Id, if present.  If not present, returns the\n" +
+                   "   * original ACDM instead.  The assignment id must be given because in a\n" +
+                   "   * multiple assignment environment, a specific component needs to be requested, as originalAllCalcDataManager refers\n" +
+                   "   * to the aggregate assignment.\n" +
+                   "   *\n" +
+                   "   * @param asgnmtId The id of the assignment to load.\n" +
+                   "   * @return  he updated AllCalcDataManager for the given assignment Id, if present.  If not present, returns the\n" +
+                   "   * original ACDM instead.\n" +
+                   "   */\n" +
+                   "  AllCalcDataManager getLatestAllCalcDataManager(GeneratedId asgnmtId) {\n" +
+                   "    if (updatedAllCalcDataManager != null) {\n" +
+                   "      return getUpdatedAllCalcDataManager(asgnmtId);\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    return getOriginalAllCalcDataManager(asgnmtId);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  //todo-ute: the method name is misleading as it may also create a new amended ACD if period is amendable by system on user's behalf\n" +
+                   "  private AllCalculationData getAllCalcData(AllCalcDataManager mgr, TimeSheetIdentifier id) {\n" +
+                   "    try {\n" +
+                   "      EmployeePeriodInfo epInfo = mgr.getEmployeePeriodInfo(id.getPpEnd());\n" +
+                   "      if (epInfo == null) {\n" +
+                   "        final PolicyID asgnmtPolicyProfile = mgr.getAsgnmtMaster().getPolicy_profile(id.getPpEnd());\n" +
+                   "        final PolicyID policyProfileId = (asgnmtPolicyProfile == null) ? PolicyID.EMPTY_POLICYID : asgnmtPolicyProfile;\n" +
+                   "        throw new InvalidPayPeriodException(\"EmployeePeriodInfo could not be obtained for employee \" +\n" +
+                   "            id.getEmployee() + \" and assignment \" + id.getAsgnmt() + \" and period end - \" + id.getPpEnd() + \". \" +\n" +
+                   "            \"Possibly because the employee is not active on that date or there are not enough initialized policy profile \" +\n" +
+                   "            \"periods for policy profile \" + policyProfileId );\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      TimeSheetCalculationInfo calcInfo = this.getCalculationInfo(mgr, id);\n" +
+                   "      AssignmentPeriodState asgnmtPeriodState = calcInfo.getAssignmentPeriodState();\n" +
+                   "      TimeSheetState timesheetState = calcInfo.getTimeSheetState();\n" +
+                   "      //If requesting EDIT_VERSION, check to see if one exists or that period is amendable by the logged in user\n" +
+                   "      if (id.getVersion() == EmployeePeriodVersionInfo.EDIT_VERSION && !epInfo.hasEditVersion()\n" +
+                   "          && !isPeriodAmendable(epInfo, mgr, asgnmtPeriodState, timesheetState) ) {\n" +
+                   "        throw new InternalApplicationException(\"An editable timesheet could not be obtained for employee \" +\n" +
+                   "            id.getEmployee() + \" and period end - \" + id.getPpEnd());\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      //Check to see if an editable ACD is in ACD manager's cache - if one exists, use it\n" +
+                   "      //An empty unmodifiable ACD for a prior period might be in cache if an ACD for prior timesheet is requested and\n" +
+                   "      //if that's the case, we want to still be able to create an amended ACD\n" +
+                   "      final AllCalculationData acd = mgr.getAllCalcData(id.getPpEnd(),id.getVersion(),AllCalculationData.FETCH_CACHED_ONLY);\n" +
+                   "      if (acd != null && !acd.isUnmodifiable()) {\n" +
+                   "        return acd;\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      //Create an amended ACD only if the period is amendable and the logged in user can amend it\n" +
+                   "      if (isAmendableBySystemForUser(epInfo, mgr, asgnmtPeriodState)) {\n" +
+                   "        final AllCalculationData amendedAllCalcData = mgr.createAmendedAllCalcData(epInfo, parms.getApp_user(), WDateTime.now());\n" +
+                   "        // No need to hook this up to approval change logic, since it is an in-memory change so far.\n" +
+                   "        //Recalculate the amended ACD so that timesheet exceptions (if any) get created on the amended timesheet\n" +
+                   "        amendedAllCalcData.recalc(mgr);\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      //By this time, the ACD mgr's ACD cache will have the amended ACD if one's created in this method\n" +
+                   "      //and we can retrieve the cached amended ACD or the ACD from the database\n" +
+                   "      return mgr.getAllCalcData(id.getPpEnd(), id.getVersion());\n" +
+                   "    } catch(InvalidPayPeriodException e) {\n" +
+                   "      //Rethrow InvalidPeriodExceptions--don't wrap them.  We want them to be typed as InvalidPeriodExceptions.\n" +
+                   "      throw e;\n" +
+                   "    } catch (Exception e) {\n" +
+                   "      throw new InternalApplicationException(\"Timesheet could not be obtained for employee \" +\n" +
+                   "            id.getEmployee() + \", assignment \" + id.getAsgnmt()+ \", period end \" + id.getPpEnd() +  \" and version \" + id.getVersion() + \".\", e);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * A period is amendable if one of the following is true:\n" +
+                   "   * <pre>\n" +
+                   "   * - {@link #isAmendableBySystemForUser(EmployeePeriodInfo, AllCalcDataManager, AssignmentPeriodState)\n" +
+                   "   *    amendable by system on users's behalf}\n" +
+                   "   * - {@link TimeSheetState#isAmendable() amendable directly by user} generally by clicking \"Amend\" button on\n" +
+                   "   *   prior active period with one or more closed timesheets\n" +
+                   "   * </pre>\n" +
+                   "   */\n" +
+                   "  private static boolean isPeriodAmendable(EmployeePeriodInfo epInfo, AllCalcDataManager mgr,\n" +
+                   "                                           AssignmentPeriodState asgnmtPeriodState, TimeSheetState timesheetState)\n" +
+                   "          throws SQLException, MultipleRowDbRecException {\n" +
+                   "    return timesheetState.isAmendable() || isAmendableBySystemForUser(epInfo, mgr, asgnmtPeriodState);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * A period is amendable by system on user's behalf (not the same as AUTO_AMEND or SYS_AMEND which are also created by\n" +
+                   "   * system) if user has amend rights for the specified period as of today and if specified period is a priod period\n" +
+                   "   * with no timesheet or it's a prior period timesheet with just system amended but not user amended\n" +
+                   "   * @param epInfo\n" +
+                   "   * @param mgr\n" +
+                   "   * @param asgnmtPeriodState\n" +
+                   "   * @return\n" +
+                   "   * @throws PolicyLookupException\n" +
+                   "   * @throws MultipleRowDbRecException\n" +
+                   "   * @throws SQLException\n" +
+                   "   * @see AssignmentPeriodState#isPeriodAmendable() \n" +
+                   "   * @see Approval_event_type#SYS_AMEND\n" +
+                   "   * @see Approval_event_type#AMEND\n" +
+                   "   */\n" +
+                   "  private static boolean isAmendableBySystemForUser(EmployeePeriodInfo epInfo, AllCalcDataManager mgr,\n" +
+                   "                                                    AssignmentPeriodState asgnmtPeriodState)\n" +
+                   "      throws MultipleRowDbRecException, SQLException {\n" +
+                   "    return asgnmtPeriodState.isPeriodAmendable() &&  // TODO: this doesn't match the javadoc?\n" +
+                   "        ( mgr.isPriorModifiablePeriodWithNoTimesheet(epInfo) || epInfo.isPriorPeriodWithSysAmendVersionOnly() );\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private AllCalculationData getOriginalAllCalcData(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+                   "    return getAllCalcData(getOriginalAllCalcDataManager(timeSheetIdentifier.getAsgnmt()), timeSheetIdentifier);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private AllCalculationData getUpdatedAllCalcData(TimeSheetIdentifier timeSheetIdentifier) {\n" +
+                   "    return getAllCalcData(getUpdatedAllCalcDataManager(timeSheetIdentifier.getAsgnmt()), timeSheetIdentifier);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "\n" +
+                   "  private Set<TimeSheetIdentifier> getTimeSheetIdentifiers() {\n" +
+                   "    return timeSheetIdentifiers;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Returns the pay period end for the period containing date provided, relative\n" +
+                   "   * to the defined periods for this assignment.\n" +
+                   "   *\n" +
+                   "   * @param aDateInUnknownPeriod any date we want to know the period for\n" +
+                   "   * @return never null\n" +
+                   "   */\n" +
+                   "  WDate getPpEndForDate(GeneratedId asgnmtId, WDate aDateInUnknownPeriod) {\n" +
+                   "    return TimeSchedUtils.getPpEndForDate(getOriginalAllCalcDataManager(asgnmtId), aDateInUnknownPeriod);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Assign system_record_id's to any DbRec objecs in the collection which lack them.\n" +
+                   "   * @param dbRecList List of DbRec objects on which to check the system_record_id.  Records in list will be modified.\n" +
+                   "   */\n" +
+                   "  static private void assignSystemRecordIds(ListWrapBase dbRecList) {\n" +
+                   "    for (Iterator iterator = dbRecList.getCollection().iterator(); iterator.hasNext();) {\n" +
+                   "      DbRec dbRec = (DbRec) iterator.next();\n" +
+                   "      assignSystemRecordId(dbRec);\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Assign system_record_id to a DbRec object, if it is not set or contains a temporary id.\n" +
+                   "   * @param dbRec DbRec objects on which to check/change the system_record_id.\n" +
+                   "   */\n" +
+                   "  static private void assignSystemRecordId(DbRec dbRec) {\n" +
+                   "    if (dbRec.getSystem_record_id() == null || dbRec.getSystem_record_id().requiresPermanentId()) {\n" +
+                   "      dbRec.setSystem_record_id(SystemId.getNewID());\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Removes the last approval event (employee approval) from approval event list from the AllCalculationData object of\n" +
+                   "   * {@link #updatedAllCalcDataManager}\n" +
+                   "   * @param timeSheetId  - Used to get the {@link AllCalculationData} object from {@link #updatedAllCalcDataManager}\n" +
+                   "   */\n" +
+                   "  void undoEmployeeApproval(TimeSheetIdentifier timeSheetId) {\n" +
+                   "    final AllCalculationData updatedAllCalcData = getUpdatedAllCalcData(timeSheetId);\n" +
+                   "    updatedAllCalcData.getApproval_eventList().removeLastApprovalEvent();\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Update the current object to be able to be used for other timesheets for this assignment\n" +
+                   "   * @param parms\n" +
+                   "   * @param timeSheetIdentifiers\n" +
+                   "   */\n" +
+                   "  public void update(TimeEntryParmsPerAssignment parms, Set<TimeSheetIdentifier> timeSheetIdentifiers) {\n" +
+                   "    setClassFields(parms, timeSheetIdentifiers);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  private void setClassFields(TimeEntryParmsPerAssignment parms, Set<TimeSheetIdentifier> timeSheetIdentifiers) {\n" +
+                   "    this.parms = parms;\n" +
+                   "    this.timeSheetIdentifiers = TimeEntryParmsPerAssignment.TIMESHEET_IDENTIFIER_TREESET_FACTORY.newInstance();\n" +
+                   "    this.timeSheetIdentifiers.addAll(timeSheetIdentifiers);\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Recalculates and Saves timesheets (if saveData == true) for timesheet ids in {@link #parms} that belong to this\n" +
+                   "   * assignment\n" +
+                   "   *\n" +
+                   "   * @param trans\n" +
+                   "   * @return AggregateTimeEntryTransactionResults for all saved timesheets\n" +
+                   "   * @throws Exception in case of fatal error during timesheet recalc & save e.g. errors while store data in DB etc.\n" +
+                   "   * This precludes ConcurrentUserModification exception. Any exception thrown from this method, eventually gets\n" +
+                   "   * escalated as transaction exception\n" +
+                   "   */\n" +
+                   "  public TimeEntryTransactionResults recalcAndSaveTimesheets(TimeEntryTransaction trans, boolean saveData) throws Exception {\n" +
+                   "    // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+                   "    AllCalcDataManager tempAcdMgr = null;\n" +
+                   "    AggregateTimeEntryTransactionResults results = (AggregateTimeEntryTransactionResults) parms.getTimeEntryResultsFactory().newInstance();\n" +
+                   "    Set<TimeSheetIdentifier> timeSheetIds = getAffectedTimeSheetIdentifiers(trans, parms);\n" +
+                   "    int retryCount = 0;\n" +
+                   "    boolean canRetryConcurrentModification = true;\n" +
+                   "    if (timeSheetIds.isEmpty()) {\n" +
+                   "      return results;\n" +
+                   "    }\n" +
+                   "\n" +
+                   "    assert timeSheetIdentifiers.containsAll(timeSheetIds) : \"Attempted to recalculate a timesheet identifier not managed by this AssignmentManager.\";\n" +
+                   "    createUpdatedAllCalcDataManager(timeSheetIds);\n" +
+                   "\n" +
+                   "    TransactionStatus timeSheetSaveStatus = null;\n" +
+                   "    Map<TimeSheetIdentifier, TimeSheetTransactionApplier> applyResultsMap = new HashMap<TimeSheetIdentifier, TimeSheetTransactionApplier>();\n" +
+                   "    for (TimeSheetIdentifier timeSheetId : timeSheetIds) {\n" +
+                   "      TimeSheetTransactionApplier applyResults = applyTransaction(timeSheetId, trans);\n" +
+                   "      if(applyResults.getApprovalEventType() != Approval_event_type.SAVE_SCHEDULE) {\n" +
+                   "        applyResultsMap.put(timeSheetId, applyResults);\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      recalc(timeSheetId, applyResults.getApprovalEventType());\n" +
+                   "\n" +
+                   "      boolean isWithdrawal =\n" +
+                   "              (trans.findTransactionApprovalEvent(timeSheetId, Approval_event_type.WITHDRAWAL) != null);\n" +
+                   "      if (!isWithdrawal) {\n" +
+                   "        // There are 3 conditions identified in the following if statement that can prevent an \"action\" on the\n" +
+                   "        // current timesheet. The first is an exception that prevents save. In this case, we should never allow a\n" +
+                   "        // save of the timesheet to occur. The second condition is an exception that prevents submit. In this\n" +
+                   "        // condition, we should only allow a save if the user is not attempting to submit (apply an APPROVAL event).\n" +
+                   "        // The third case is errors that occur while applying transactions to the timesheet. An example of when this\n" +
+                   "        // may occur is if the same time sheet detail row is modified by 2 users. In all of these cases we prevent\n" +
+                   "        // the save operation from executing.\n" +
+                   "        // In the next condition where we check if an error has occurred, we remove the last approval event from the\n" +
+                   "        // timesheet if we did not save AND it was a submit (APPROVAL) event. Transactions only allow 1 event to be applied\n" +
+                   "        // to the timesheet. The transaction explicitly excludes SAVE_TIME_SHEET and SAVE_SCHEDULE events from being applied.\n" +
+                   "        // It relies on these events being applied only by the save operation itself. As a result, a maximum of 2 events may\n" +
+                   "        // be added to the timesheet as a result of the transaction (the event on the transaction if it was not a save event)\n" +
+                   "        // and the SAVE_TIME_SHEET or SAVE_SCHEDULE event added during the save operation.\n" +
+                   "\n" +
+                   "        if (hasSubmitEvent(trans, timeSheetId) &&\n" +
+                   "                hasExceptionsPreventingSubmit(timeSheetId)) {\n" +
+                   "          timeSheetSaveStatus = getHighestPriorityError(timeSheetSaveStatus, Messages.EXCEPTIONS_PREVENT_SUBMIT);\n" +
+                   "        }\n" +
+                   "\n" +
+                   "        if (hasExceptionsPreventingSave(timeSheetId)) {\n" +
+                   "          timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+                   "                  Messages.EXCEPTIONS_PREVENT_SAVE.getLabel());\n" +
+                   "        }\n" +
+                   "      }\n" +
+                   "\n" +
+                   "      if (applyResults.hasErrors()) {\n" +
+                   "        timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+                   "                  Messages.TIME_SHEET_EXCEPTION_JAVA_EXCEPTION .getLabel());\n" +
+                   "      }\n" +
+                   "    }\n" +
+                   "\n" +
+                   "\n" +
+                   "    boolean errorPreventsAction = (timeSheetSaveStatus != null);\n" +
+                   "\n" +
+                   "\n" +
+                   "    Approval_event lastOriginalApprovalEvent = null;\n" +
+                   "    for (TimeSheetIdentifier timeSheetId : timeSheetIds) {\n" +
+                   "      TimeSheetTransactionApplier applyResults = applyResultsMap.get(timeSheetId);\n" +
+                   "      try {\n" +
+                   "        while (saveData && canRetryConcurrentModification) {\n" +
+                   "          if (errorPreventsAction) {\n" +
+                   "            // If the changes were not saved due to errors, and this operation (transaction) was an employee timesheet submission,\n" +
+                   "            // remove the approval event from the unsaved ACD.\n" +
+                   "            // NOTE: We do not have to concern ourselves with removing SAVE_TIME_SHEET or SAVE_SCHEDULE events here as these events\n" +
+                   "            // are explicitly EXCLUDED in the TimeSheetTransactionApplier (not applied) and are applied by the save operation (which\n" +
+                   "            // has not executed if we made it here.\n" +
+                   "            if (hasSubmitEvent(trans, timeSheetId)) {\n" +
+                   "              undoEmployeeApproval(timeSheetId);\n" +
+                   "            }\n" +
+                   "          } else {\n" +
+                   "            save(timeSheetId, applyResults.getApprovalEventType());\n" +
+                   "            timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.SAVED,\n" +
+                   "                    Messages.TIME_SHEET_SAVED.getLabel());\n" +
+                   "            postSave();\n" +
+                   "          }\n" +
+                   "          // All operations completed, so retries are no longer necessary\n" +
+                   "          canRetryConcurrentModification = false;\n" +
+                   "        }\n" +
+                   "      } catch (ConcurrentUserModificationException ex) {\n" +
+                   "        // Store the old AcdMgr, when a concurrent mod error due to another user modifying a time sheet occurs we want\n" +
+                   "        // to receive the same new approval events to ensure that the user is forced to reload the time sheet to continue.\n" +
+                   "        // TODO-13285: Remove the tempAcdMgr and make merging concurrently modified time sheets possible,\n" +
+                   "        // TODO-13285: requires considering multiple edge cases for the user interface\n" +
+                   "        if (tempAcdMgr == null) {\n" +
+                   "          tempAcdMgr = getOriginalAllCalcDataManager(asgnmtMaster.getAsgnmt());\n" +
+                   "        }\n" +
+                   "\n" +
+                   "        if (retryCount == MAX_RETRIES) {\n" +
+                   "          // return the acdMgr to its previous state, this ensures the user must reload the time sheet\n" +
+                   "          // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+                   "          originalAllCalcDataManager = tempAcdMgr;\n" +
+                   "          GeneratedId errorId = ServerErrorLogger.singleton.log(new ServerError(\"Exception saving time sheet\", ex,\n" +
+                   "                  Program_source.SERVER_REQUEST, parms.getApp_user().getLogin_id()));\n" +
+                   "          cat.error(\"Unable to save time sheet.  debug_error_log id:\" + errorId, ex);\n" +
+                   "          //Use timeSheetSaveStatus to send concurrent error message to user.\n" +
+                   "          errorPreventsAction = true;\n" +
+                   "          timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+                   "                  Messages.TIME_SHEET_EXCEPTION_CONCURRENT_USER.getLabel());\n" +
+                   "          // We have retried saving and have hit the MAX_RETRIES threshold, so stop retrying.\n" +
+                   "          canRetryConcurrentModification = false;\n" +
+                   "        } else {\n" +
+                   "          // On the first retry, we need to capture the last (most recent) approval event that existed on this timesheet prior to applying\n" +
+                   "          // any transactions because when we reload the \"original\" ACD to attempt to reapply the transactions we will lose track\n" +
+                   "          // of this (we'll pull in approval events for transactions that were saved in other sessions/processes). This is necessary to\n" +
+                   "          // allow more than 1 retry\n" +
+                   "          if (lastOriginalApprovalEvent == null) {\n" +
+                   "            lastOriginalApprovalEvent = getAllCalcData(getOriginalAllCalcDataManager(timeSheetId.getAsgnmt()), timeSheetId).getApproval_eventList().getLastApprovalEvent();\n" +
+                   "          }\n" +
+                   "          retryCount++;\n" +
+                   "          // attempt to reapply the transaction\n" +
+                   "          try {\n" +
+                   "            applyResults = attemptTimeSheetTransactionReapply(trans, timeSheetId, lastOriginalApprovalEvent);\n" +
+                   "          } catch (ConcurrentUserModificationException cume) {\n" +
+                   "            // return the acdMgr to its previous state, this ensures the user must reload the time sheet\n" +
+                   "            // TODO-13285: Remove this code and implement merging concurrently modified time sheets\n" +
+                   "            originalAllCalcDataManager = tempAcdMgr;\n" +
+                   "            // if we were unable to reapply transactions, no further retries are necessary (because it will just keep failing)\n" +
+                   "            // subsequent retries only succeed if we were able to reapply the new transactions successfully and still received\n" +
+                   "            // another ConcurrentUserModificationException (a second change occurred while applying transactions)\n" +
+                   "            canRetryConcurrentModification = false;\n" +
+                   "            errorPreventsAction = true;\n" +
+                   "            timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+                   "                    Messages.TIME_SHEET_EXCEPTION_CONCURRENT_USER.getLabel());\n" +
+                   "          }\n" +
+                   "        }\n" +
+                   "      }\n" +
+                   "      results.add(getDiff(timeSheetId, trans, applyResults, timeSheetSaveStatus, !errorPreventsAction));\n" +
+                   "    }\n" +
+                   "    return results;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  ";
+
+    String part2 = "\n" +
+                   "  private TransactionStatus getHighestPriorityError(TransactionStatus existingStatus, Message newError) {\n" +
+                   "    if(existingStatus == null) {\n" +
+                   "      return newError;\n" +
+                   "    }\n" +
+                   "    TransactionStatus timeSheetSaveStatus = new TransactionStatusImpl(Transaction_status.ERROR,\n" +
+                   "            );\n" +
+                   "    return timeSheetSaveStatus;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Returns true if the given TimeEntryTransaction has a submit event for the given time sheet.\n" +
+                   "   * @param trans TimeEntryTransaction to search\n" +
+                   "   * @param timeSheetId time sheet to search\n" +
+                   "   * @return true if a submit event exists\n" +
+                   "   */\n" +
+                   "  private static boolean hasSubmitEvent(TimeEntryTransaction trans, TimeSheetIdentifier timeSheetId) {\n" +
+                   "    return trans.findTransactionApprovalEvent(timeSheetId, Approval_event_type.APPROVAL) != null;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Resolves modifications that impact only non-\"input\" values on the timesheet to prevent them\n" +
+                   "   * from causing ConcurrentUserModificationExceptions on subsequent attempts at saving the data\n" +
+                   "   * @param trans time entry transaction to resolve\n" +
+                   "   * @param id time sheet ID\n" +
+                   "   * @param lastApprovalEvent the most recent approval event on the timesheet prior to any transactions\n" +
+                   "   * @return TimeSheetTransactionApplier if transactions were reapplied\n" +
+                   "   * @throws Exception on error loading the acd\n" +
+                   "   */\n" +
+                   "  private TimeSheetTransactionApplier attemptTimeSheetTransactionReapply(final TimeEntryTransaction trans, final TimeSheetIdentifier id, Approval_event lastApprovalEvent) throws Exception {\n" +
+                   "    // Clean out the ACDM cache to force reloads of the data from the database\n" +
+                   "    invalidateAllCalcDataManagers();\n" +
+                   "    AllCalculationData originalAcd = getAllCalcData(getOriginalAllCalcDataManager(id.getAsgnmt()), id);\n" +
+                   "    // Get any new approval events that exist in the database\n" +
+                   "    Approval_eventList newApprovalEvents = originalAcd.getApproval_eventList().getApprovalsSince(lastApprovalEvent);\n" +
+                   "    // Check if a \"concurrent save\" is possible given the events that have occurred\n" +
+                   "    if (newApprovalEvents.canConcurrentSave()) {\n" +
+                   "      //TODO:FIX\n" +
+                   "      //createUpdatedAllCalcDataManager(listOfAllIdsHere);\n" +
+                   "      TimeSheetTransactionApplier applyResults = applyTransaction(id, trans); // reapply transactions\n" +
+                   "      recalc(id, applyResults.getApprovalEventType()); // recalculate\n" +
+                   "      DbRecTime_sheet originalTimeSheet = originalAcd.getTime_sheet();\n" +
+                   "      DbRecTime_sheet updatedTimeSheet = getAllCalcData(getUpdatedAllCalcDataManager(id.getAsgnmt()), id).getTime_sheet();\n" +
+                   "      // Copy the system fields from the original time sheet to the updated time sheet because\n" +
+                   "      // we have determined at this point that the concurrent save is okay based on the difference\n" +
+                   "      // between these 2 time sheets. Copying these fields over will allow the save to complete\n" +
+                   "      // without causing a ConcurrentUserModificationException by making the update counter match.\n" +
+                   "      DbRecFieldCopier copier = new DbRecFieldCopier(DataDictionary.getCltnOfSystemFieldNames());\n" +
+                   "      copier.copyFields(originalTimeSheet, updatedTimeSheet);\n" +
+                   "      return applyResults;\n" +
+                   "    } else {\n" +
+                   "      // Otherwise, throw the exception\n" +
+                   "      throw new ConcurrentUserModificationException(\"Unable to save time sheet for assignment \" + originalAcd.getAsgnmtId() + \"due to concurrent changes.\");\n" +
+                   "    }\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Returns a set of AssignmentManagers that are affected by changes in the given transaction and managed by this\n" +
+                   "   * TimeEntryManager.\n" +
+                   "   *\n" +
+                   "   * @return a set of AssignmentManagers that are affected by changes in the given transaction and managed by this\n" +
+                   "   * TimeEntryManager.\n" +
+                   "   */\n" +
+                   "  public Set<TimeSheetIdentifier> getAffectedTimeSheetIdentifiers(TimeEntryTransaction transaction, TimeEntryParmsPerAssignment parms) {\n" +
+                   "    Set<TimeSheetIdentifier> affectedTimeSheetIds = new HashSet<TimeSheetIdentifier>();\n" +
+                   "    for(GeneratedId assignmentId : getAssignmentIds()) {\n" +
+                   "      for(TimeSheetIdentifier timeSheetId : parms.getTimeSheetIdentifiersForAssignment(assignmentId)) {\n" +
+                   "        if(!transaction.obtainAllRows(timeSheetId).isEmpty()) {\n" +
+                   "          affectedTimeSheetIds.add(timeSheetId);\n" +
+                   "        }\n" +
+                   "      }\n" +
+                   "    }\n" +
+                   "    return affectedTimeSheetIds;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Obtains all assignment id's that are managed by this AssignmentManager.\n" +
+                   "   *\n" +
+                   "   * @return all assignment id's that are managed by this AssignmentManager.\n" +
+                   "   */\n" +
+                   "  public Set<GeneratedId> getAssignmentIds() {\n" +
+                   "    Set<GeneratedId> assignmentIds = new HashSet<GeneratedId>();\n" +
+                   "    Asgnmt_masterList amList = asgnmtMaster.getCompAsgnmtMasters();\n" +
+                   "    for(Asgnmt_master am : amList) {\n" +
+                   "      assignmentIds.add(am.getAsgnmt());\n" +
+                   "    }\n" +
+                   "    return assignmentIds;\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  public GeneratedId getEmployee() {\n" +
+                   "    return asgnmtMaster.getEmployee();\n" +
+                   "  }\n" +
+                   "\n" +
+                   "  /** Single or aggregate assignment master associated with this manager */\n" +
+                   "  private final Asgnmt_master asgnmtMaster;\n" +
+                   "\n" +
+                   "  private TimeEntryParmsPerAssignment parms;\n" +
+                   "\n" +
+                   "  /** Set of {@link TimeSheetIdentifier}'s which are managed by this object.\n" +
+                   "   * Composed of all the identifiers in the TimeEntryParms for this assignment and related components.\n" +
+                   "   */\n" +
+                   "  private Set<TimeSheetIdentifier> timeSheetIdentifiers;\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Original Single or Aggregate ACDM, as loaded from the database.  ACD's in here are not modified.\n" +
+                   "   * This ACDM is lazily loaded, and should always be obtained from {@link #getOriginalAllCalcDataManager(GeneratedId)}.\n" +
+                   "   *\n" +
+                   "   * Null means that the ACDM has not yet been loaded from the database, and any attempts to use it should first\n" +
+                   "   * initialize it.  Note:  The meaning of null is different than updatedAllCalcDataManager's null meaning.\n" +
+                   "   */\n" +
+                   "  private AllCalcDataManager originalAllCalcDataManager = null;\n" +
+                   "\n" +
+                   "  /**\n" +
+                   "   * Updated Single or Aggregate ACDM--a shallow copy of originalAllCalcDataManager.  ACD's in here are modified by\n" +
+                   "   * TimeEntryTransactions.  This ACDM is NOT lazily loaded--null means no changes present, and non-null means the\n" +
+                   "   * updated ACDM has been explicitly created.\n" +
+                   "   *\n" +
+                   "   * Null means that no changes have been made to the ACDM or data, and any attempts to use it should either throw a\n" +
+                   "   * descriptive error, or explicitly create the updatedAllCalcDataManager.\n" +
+                   "   * Note:  The meaning of null is different than originalAllCalcDataManager's null meaning.\n" +
+                   "   */\n" +
+                   "  private AllCalcDataManager updatedAllCalcDataManager = null;\n" +
+                   "\n" +
+                   "  private static final int MAX_RETRIES = 2;\n" +
+                   "\n" +
+                   "  private static final Category cat=Category.getInstance(AssignmentManager.class.getName());\n" +
+                   "}";
+    configureFromFileText("Foo.java", part1 + part2);
+
+    final PsiDocumentManager docManager = PsiDocumentManager.getInstance(ourProject);
+    final Document doc = docManager.getDocument(myFile);
+    doc.insertString(part1.length(), "/**");
+
+    boolean old = DebugUtil.CHECK;
+    DebugUtil.CHECK = true;
+    try {
+      docManager.commitAllDocuments();
+    }
+    finally {
+      DebugUtil.CHECK = old;
+    }
+  }
+}