GRECLIPSE
  1. GRECLIPSE
  2. GRECLIPSE-1423

Save operation does save the file, but the editor is left dirty

    Details

    • Type: Bug Bug
    • Status: Resolved Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.6.1.Release
    • Fix Version/s: 2.8.0.Release
    • Component/s: Editor
    • Labels:
      None
    • Number of attachments :
      0

      Description

      I have a Groovy source file in my workspace that, whenever I change it and hit Ctrl+S to save, the file is saved, but the editor is kept dirty ("*" in the editor title).

      The issue is caused by the following strange behaviour. On every save, the following lines are re-formatted:

      ModelConversionImplG(){
      	basicProfilefactories[SoloArtist.class] = {
      		return new SoloArtistBean(defaultSongLicense: it.defaultSongLicense,
      		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
      	} as BasicProfileBeanFactory;
      	basicProfilefactories[Band.class] = {
      		return new BandBean(defaultSongLicense: it.defaultSongLicense,
      		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
      	} as BasicProfileBeanFactory;
      	basicProfilefactories[Listener.class] = {
      		return new ListenerBean() } as BasicProfileBeanFactory;
      	basicProfilefactories[Club.class] = {
      		return new ClubBean(googleMapsAddress:it.googleMapsAddress)
      	} as BasicProfileBeanFactory;
      }
      

      On even saves, the code looks like that. On odd saves, it's reformatted as such:

      ModelConversionImplG(){
      	basicProfilefactories[SoloArtist.class] = {
      		return new SoloArtistBean(defaultSongLicense: it.defaultSongLicense,
      		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
      	} as BasicProfileBeanFactory;
      	basicProfilefactories[Band.class] = {
      		return new BandBean(defaultSongLicense: it.defaultSongLicense,
      		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
      	} as BasicProfileBeanFactory;
      	basicProfilefactories[Listener.class] = { return new ListenerBean() } as BasicProfileBeanFactory;
      	basicProfilefactories[Club.class] = {
      		return new ClubBean(googleMapsAddress:it.googleMapsAddress)
      	} as BasicProfileBeanFactory;
      }
      

      So, there seems to be two problems here:

      • the formatter is formatting the same code differently on every save operation, guaranteeing the same formatting on every other save
      • the editor is left dirty after the formatting operation has finished

      I have some save actions enabled but I don't know which of them are causing this. I may export the Eclipse formatter settings if you need further details.

        Activity

        Hide
        Andrew Eisenberg added a comment -

        Are there any errors in your error log?

        Show
        Andrew Eisenberg added a comment - Are there any errors in your error log?
        Hide
        Mauro Molinari added a comment -

        Sorry, I forgot to mention: no, there are no errors in the error log.

        Show
        Mauro Molinari added a comment - Sorry, I forgot to mention: no, there are no errors in the error log.
        Hide
        Andrew Eisenberg added a comment -

        I'm able to reproduce this. I am using the following code to avoid compile errors:

        ModelConversionImplG(){
        	basicProfilefactories[SoloArtist.class] = {
        		return new SoloArtistBean(defaultSongLicense: it.defaultSongLicense,
        		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
        	} as BasicProfileBeanFactory;
        	basicProfilefactories[Band.class] = {
        		return new BandBean(defaultSongLicense: it.defaultSongLicense,
        		foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate)
        	} as BasicProfileBeanFactory;
        	basicProfilefactories[Listener.class] = { return new ListenerBean() } as BasicProfileBeanFactory;
        	basicProfilefactories[Club.class] = {
        		return new ClubBean(googleMapsAddress:it.googleMapsAddress)
        	} as BasicProfileBeanFactory;
        }
        class ClubBean {
        }
        class SoloArtistBean {
        }
        class Band {
        }
        class BandBean {
        }
        class ListenerBean {
        }
        class Club {
        }
        class BasicProfileBeanFactory{
        }
        

        I am also using the following save actions (the contents of my .settings/org.eclipse.jdt.ui file):

        eclipse.preferences.version=1
        editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
        sp_cleanup.add_default_serial_version_id=true
        sp_cleanup.add_generated_serial_version_id=false
        sp_cleanup.add_missing_annotations=true
        sp_cleanup.add_missing_deprecated_annotations=true
        sp_cleanup.add_missing_methods=false
        sp_cleanup.add_missing_nls_tags=false
        sp_cleanup.add_missing_override_annotations=true
        sp_cleanup.add_missing_override_annotations_interface_methods=true
        sp_cleanup.add_serial_version_id=false
        sp_cleanup.always_use_blocks=true
        sp_cleanup.always_use_parentheses_in_expressions=false
        sp_cleanup.always_use_this_for_non_static_field_access=false
        sp_cleanup.always_use_this_for_non_static_method_access=false
        sp_cleanup.convert_to_enhanced_for_loop=false
        sp_cleanup.correct_indentation=false
        sp_cleanup.format_source_code=true
        sp_cleanup.format_source_code_changes_only=false
        sp_cleanup.make_local_variable_final=false
        sp_cleanup.make_parameters_final=false
        sp_cleanup.make_private_fields_final=true
        sp_cleanup.make_type_abstract_if_missing_method=false
        sp_cleanup.make_variable_declarations_final=true
        sp_cleanup.never_use_blocks=false
        sp_cleanup.never_use_parentheses_in_expressions=true
        sp_cleanup.on_save_use_additional_actions=true
        sp_cleanup.organize_imports=true
        sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
        sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
        sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
        sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
        sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
        sp_cleanup.remove_private_constructors=true
        sp_cleanup.remove_trailing_whitespaces=false
        sp_cleanup.remove_trailing_whitespaces_all=true
        sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
        sp_cleanup.remove_unnecessary_casts=true
        sp_cleanup.remove_unnecessary_nls_tags=false
        sp_cleanup.remove_unused_imports=false
        sp_cleanup.remove_unused_local_variables=false
        sp_cleanup.remove_unused_private_fields=true
        sp_cleanup.remove_unused_private_members=false
        sp_cleanup.remove_unused_private_methods=true
        sp_cleanup.remove_unused_private_types=true
        sp_cleanup.sort_members=false
        sp_cleanup.sort_members_all=false
        sp_cleanup.use_blocks=false
        sp_cleanup.use_blocks_only_for_return_and_throw=false
        sp_cleanup.use_parentheses_in_expressions=false
        sp_cleanup.use_this_for_non_static_field_access=false
        sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
        sp_cleanup.use_this_for_non_static_method_access=false
        sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
        

        My guess is that there is something wrong with the formatter in that it processes the same structure in different ways depending on initial whitespace.

        Show
        Andrew Eisenberg added a comment - I'm able to reproduce this. I am using the following code to avoid compile errors: ModelConversionImplG(){ basicProfilefactories[SoloArtist.class] = { return new SoloArtistBean(defaultSongLicense: it.defaultSongLicense, foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate) } as BasicProfileBeanFactory; basicProfilefactories[Band.class] = { return new BandBean(defaultSongLicense: it.defaultSongLicense, foundationDate: it.foundationDate, dissolutionDate: it.dissolutionDate) } as BasicProfileBeanFactory; basicProfilefactories[Listener.class] = { return new ListenerBean() } as BasicProfileBeanFactory; basicProfilefactories[Club.class] = { return new ClubBean(googleMapsAddress:it.googleMapsAddress) } as BasicProfileBeanFactory; } class ClubBean { } class SoloArtistBean { } class Band { } class BandBean { } class ListenerBean { } class Club { } class BasicProfileBeanFactory{ } I am also using the following save actions (the contents of my .settings/org.eclipse.jdt.ui file): eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup= true sp_cleanup.add_default_serial_version_id= true sp_cleanup.add_generated_serial_version_id= false sp_cleanup.add_missing_annotations= true sp_cleanup.add_missing_deprecated_annotations= true sp_cleanup.add_missing_methods= false sp_cleanup.add_missing_nls_tags= false sp_cleanup.add_missing_override_annotations= true sp_cleanup.add_missing_override_annotations_interface_methods= true sp_cleanup.add_serial_version_id= false sp_cleanup.always_use_blocks= true sp_cleanup.always_use_parentheses_in_expressions= false sp_cleanup.always_use_this_for_non_static_field_access= false sp_cleanup.always_use_this_for_non_static_method_access= false sp_cleanup.convert_to_enhanced_for_loop= false sp_cleanup.correct_indentation= false sp_cleanup.format_source_code= true sp_cleanup.format_source_code_changes_only= false sp_cleanup.make_local_variable_final= false sp_cleanup.make_parameters_final= false sp_cleanup.make_private_fields_final= true sp_cleanup.make_type_abstract_if_missing_method= false sp_cleanup.make_variable_declarations_final= true sp_cleanup.never_use_blocks= false sp_cleanup.never_use_parentheses_in_expressions= true sp_cleanup.on_save_use_additional_actions= true sp_cleanup.organize_imports= true sp_cleanup.qualify_static_field_accesses_with_declaring_class= false sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class= true sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class= true sp_cleanup.qualify_static_member_accesses_with_declaring_class= false sp_cleanup.qualify_static_method_accesses_with_declaring_class= false sp_cleanup.remove_private_constructors= true sp_cleanup.remove_trailing_whitespaces= false sp_cleanup.remove_trailing_whitespaces_all= true sp_cleanup.remove_trailing_whitespaces_ignore_empty= false sp_cleanup.remove_unnecessary_casts= true sp_cleanup.remove_unnecessary_nls_tags= false sp_cleanup.remove_unused_imports= false sp_cleanup.remove_unused_local_variables= false sp_cleanup.remove_unused_private_fields= true sp_cleanup.remove_unused_private_members= false sp_cleanup.remove_unused_private_methods= true sp_cleanup.remove_unused_private_types= true sp_cleanup.sort_members= false sp_cleanup.sort_members_all= false sp_cleanup.use_blocks= false sp_cleanup.use_blocks_only_for_return_and_throw= false sp_cleanup.use_parentheses_in_expressions= false sp_cleanup.use_this_for_non_static_field_access= false sp_cleanup.use_this_for_non_static_field_access_only_if_necessary= true sp_cleanup.use_this_for_non_static_method_access= false sp_cleanup.use_this_for_non_static_method_access_only_if_necessary= true My guess is that there is something wrong with the formatter in that it processes the same structure in different ways depending on initial whitespace.
        Hide
        Andrew Eisenberg added a comment -

        Narrowed it down to this:

        a = { 0 } as B
        

        Note that B is not a valid class name. If I create a B class, then CMD+S will actually save the file, but on alternate saves the formatting changes.

        Show
        Andrew Eisenberg added a comment - Narrowed it down to this: a = { 0 } as B Note that B is not a valid class name. If I create a B class, then CMD+S will actually save the file, but on alternate saves the formatting changes.
        Hide
        Andrew Eisenberg added a comment -

        From what I can see, the editor only stays dirty if there is a compile error. I dug a bit to see why this might be happening and it seems that the compile error causes an invalid piece of Java structure to be created. This causes the buffer that contains that structure to be closed. With a closed buffer, the editor thinks it has no changes.

        It's a bit of a confusing path that gets taken since because save actions are enabled the file is semantically analyzed before saving.

        I'll have a look at the formatting problem, but I my initial guess is that it is completely unrelated.

        Show
        Andrew Eisenberg added a comment - From what I can see, the editor only stays dirty if there is a compile error. I dug a bit to see why this might be happening and it seems that the compile error causes an invalid piece of Java structure to be created. This causes the buffer that contains that structure to be closed. With a closed buffer, the editor thinks it has no changes. It's a bit of a confusing path that gets taken since because save actions are enabled the file is semantically analyzed before saving. I'll have a look at the formatting problem, but I my initial guess is that it is completely unrelated.
        Hide
        Andrew Eisenberg added a comment -

        Confirmed fixed. I think this problem was related to GRECLIPSE-1519, which is now fixed as well.

        Show
        Andrew Eisenberg added a comment - Confirmed fixed. I think this problem was related to GRECLIPSE-1519 , which is now fixed as well.

          People

          • Assignee:
            Andrew Eisenberg
            Reporter:
            Mauro Molinari
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: