From 8ad2ec468aa120e8bac2185e1d1f581347889683 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Jan 2015 13:16:26 +0100 Subject: [PATCH 01/10] generate equals/hashCode: provide apache/guava templates; allow to choose between them; --- .../EqualsHashCodeTemplatesManager.java | 60 +++++++++++++++++-- .../generation/apacheEqualsBuilder.vm | 23 +++++++ .../generation/apacheEqualsBuilder3.vm | 23 +++++++ .../generation/apacheHashCodeBuilder.vm | 12 ++++ .../generation/apacheHashCodeBuilder3.vm | 12 ++++ .../generation/commonEqualsMacros.vm | 24 ++++++++ .../codeInsight/generation/defaultEquals.vm | 28 +-------- .../codeInsight/generation/guavaEquals.vm | 29 +++++++++ .../codeInsight/generation/guavaHashCode.vm | 14 +++++ .../generation/ui/GenerateEqualsWizard.java | 25 +++++++- .../generate/velocity/VelocityFactory.java | 5 ++ 11 files changed, 220 insertions(+), 35 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java index c852e93a3db5..1338616ad535 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java @@ -20,11 +20,16 @@ import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.java.generate.exception.TemplateResourceException; import org.jetbrains.java.generate.template.TemplateResource; import org.jetbrains.java.generate.template.TemplatesManager; import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; @State( name = "EqualsHashCodeTemplates", @@ -36,6 +41,15 @@ import java.io.IOException; public class EqualsHashCodeTemplatesManager extends TemplatesManager { private static final String DEFAULT_EQUALS = "/com/intellij/codeInsight/generation/defaultEquals.vm"; private static final String DEFAULT_HASH_CODE = "/com/intellij/codeInsight/generation/defaultHashCode.vm"; + private static final String APACHE3_EQUALS = "/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm"; + private static final String APACHE3_HASH_CODE = "/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm"; + private static final String APACHE_EQUALS = "/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm"; + private static final String APACHE_HASH_CODE = "/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm"; + private static final String GUAVA_EQUALS = "/com/intellij/codeInsight/generation/guavaEquals.vm"; + private static final String GUAVA_HASH_CODE = "/com/intellij/codeInsight/generation/guavaHashCode.vm"; + + private static final String EQUALS_SUFFIX = "equals"; + private static final String HASH_CODE_SUFFIX = "hashCode"; public static EqualsHashCodeTemplatesManager getInstance() { @@ -46,8 +60,17 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { public TemplateResource[] getDefaultTemplates() { try { return new TemplateResource[] { - new TemplateResource("Default equals", readFile(DEFAULT_EQUALS), true), - new TemplateResource("Default hashCode", readFile(DEFAULT_HASH_CODE), true), + new TemplateResource("IntelliJ Default equals", readFile(DEFAULT_EQUALS), true), + new TemplateResource("IntelliJ Default hashCode", readFile(DEFAULT_HASH_CODE), true), + + new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang) equals", readFile(APACHE_EQUALS), true), + new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang) hashCode", readFile(APACHE_HASH_CODE), true), + + new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang 3) equals", readFile(APACHE3_EQUALS), true), + new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang 3) hashCode", readFile(APACHE3_HASH_CODE), true), + + new TemplateResource("Objects.equal and hashCode (Guava) equals", readFile(GUAVA_EQUALS), true), + new TemplateResource("Objects.equal and hashCode (Guava) hashCode", readFile(GUAVA_HASH_CODE), true), }; } catch (IOException e) { @@ -60,14 +83,27 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { } public TemplateResource getDefaultEqualsTemplate() { - return getDefaultEqualsTemplate("equals", "hashCode"); + return getDefaultTemplate(EQUALS_SUFFIX, HASH_CODE_SUFFIX); } public TemplateResource getDefaultHashcodeTemplate() { - return getDefaultEqualsTemplate("hashCode", "equals"); + return getDefaultTemplate(HASH_CODE_SUFFIX, EQUALS_SUFFIX); } - private TemplateResource getDefaultEqualsTemplate(String selfSuffix, String oppositeSuffix) { + public String[] getTemplateNames() { + final Set names = new LinkedHashSet(); + for (TemplateResource resource : getAllTemplates()) { + names.add(getTemplateBaseName(resource)); + } + return ArrayUtil.toStringArray(names); + } + + @NotNull + private String getTemplateBaseName(TemplateResource resource) { + return StringUtil.trimEnd(StringUtil.trimEnd(resource.getFileName(), EQUALS_SUFFIX), HASH_CODE_SUFFIX).trim(); + } + + private TemplateResource getDefaultTemplate(String selfSuffix, String oppositeSuffix) { final TemplateResource defaultTemplate = getDefaultTemplate(); final String fileName = defaultTemplate.getFileName(); if (fileName.endsWith(selfSuffix)) { @@ -82,4 +118,18 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { assert false : selfSuffix + " template for " + fileName + " not found"; return null; } + + public void setDefaultTemplate(String name) { + Set fullNames = ContainerUtil.newHashSet(name + " " + EQUALS_SUFFIX, name + " " + HASH_CODE_SUFFIX); + for (TemplateResource resource : getAllTemplates()) { + if (fullNames.contains(resource.getFileName())) { + setDefaultTemplate(resource); + break; + } + } + } + + public String getDefaultTemplateBaseName() { + return getTemplateBaseName(getDefaultTemplate()); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm new file mode 100644 index 000000000000..0fb13fc8b06f --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm @@ -0,0 +1,23 @@ +#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +public boolean equals(## +#if ($settings.generateFinalParameters) + final ## +#end +Object $paramName){ + if(this == $paramName) return true; + + #addInstanceOfToText() + + #addClassInstance() + + return new org.apache.commons.lang.builder.EqualsBuilder() + #if($superHasEquals) + .appendSuper(super.equals($paramName)) + #end + #foreach($field in $members) + #if (!$field.static) + .append($field.name, ${classInstanceName}.$field.name) + #end + #end + .isEquals(); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm new file mode 100644 index 000000000000..fd509e5e7498 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm @@ -0,0 +1,23 @@ +#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +public boolean equals(## +#if ($settings.generateFinalParameters) + final ## +#end +Object $paramName){ + if(this == $paramName) return true; + + #addInstanceOfToText() + + #addClassInstance() + + return new org.apache.commons.lang3.builder.EqualsBuilder() + #if($superHasEquals) + .appendSuper(super.equals($paramName)) + #end + #foreach($field in $members) + #if (!$field.static) + .append($field.name, ${classInstanceName}.$field.name) + #end + #end + .isEquals(); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm new file mode 100644 index 000000000000..ae5f73ced6ad --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm @@ -0,0 +1,12 @@ +public int hashCode() { + return new org.apache.commons.lang.builder.HashCodeBuilder(17, 37) + #if($superHasHashCode) + .appendSuper(super.hashCode()) + #end + #foreach($field in $members) + #if (!$field.static) + .append($field.name) + #end + #end + .toHashCode(); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm new file mode 100644 index 000000000000..fa9919c94809 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm @@ -0,0 +1,12 @@ +public int hashCode() { + return new org.apache.commons.lang3.builder.HashCodeBuilder(17, 37) + #if($superHasHashCode) + .appendSuper(super.hashCode()) + #end + #foreach($field in $members) + #if (!$field.static) + .append($field.name) + #end + #end + .toHashCode(); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm b/java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm new file mode 100644 index 000000000000..8b8137f19a4e --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm @@ -0,0 +1,24 @@ +#set($classInstanceName = $helper.getUniqueLocalVarName($instanceName, $members, $settings)) +#set($paramName = $helper.getUniqueLocalVarName($baseParamName, $members, $settings)) +#macro(addClassInstance) + #if ($settings.generateFinalLocals) + final ## + #end + $classname $classInstanceName = ($classname)$paramName; +#end +## +#macro(addEqualsPrologue) +if(this == $paramName) return true; + #addInstanceOfToText() + #if ($superHasEquals) + if(!super.equals($paramName)) return false; + #end +#end +## +#macro(addInstanceOfToText) + #if ($checkParameterWithInstanceof) + if(!($paramName instanceof $classname)) return false; + #else + if($paramName == null || getClass() != ${paramName}.getClass()) return false; + #end +#end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm index 5c0ba0820672..b1ed5e54f040 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm @@ -1,5 +1,4 @@ -#set($classInstanceName = $helper.getUniqueLocalVarName($instanceName, $members, $settings)) -#set($paramName = $helper.getUniqueLocalVarName($baseParamName, $members, $settings)) +#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## @@ -32,31 +31,6 @@ Object $paramName){ return true; } ## -#macro(addClassInstance) - #if ($settings.generateFinalLocals) - final ## - #end - $classname $classInstanceName = ($classname)$paramName; -#end -## -#macro(addEqualsPrologue) - if(this == $paramName) return true; - #if (!$superHasEquals) - #addInstanceOfToText() - #else - #addInstanceOfToText() - if(!super.equals($paramName)) return false; - #end -#end -## -#macro(addInstanceOfToText) - #if ($checkParameterWithInstanceof) - if(!($paramName instanceof $classname)) return false; - #else - if($paramName == null || getClass() != ${paramName}.getClass()) return false; - #end -#end -## #macro(addPrimitiveFieldComparison $field) if($field.name != ${classInstanceName}.$field.name) return false; #end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm new file mode 100644 index 000000000000..3f5b280fdc25 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm @@ -0,0 +1,29 @@ +#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +public boolean equals(## +#if ($settings.generateFinalParameters) + final ## +#end +Object $paramName){ + #addEqualsPrologue() + #addClassInstance() + return ## + #set($i = 0) + #foreach($field in $members) + #if (!$field.static) + #if ($i > 0) + && + #end + #set($i = $i + 1) + #if ($field.array) + #if ($field.nestedArray) +java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## + #else +java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## + #end + #else +com.google.common.base.Objects.equal($field.name, ${classInstanceName}.$field.name)## + #end + #end + #end + ; +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm new file mode 100644 index 000000000000..6f381f0c6b02 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm @@ -0,0 +1,14 @@ +public int hashCode() { + return com.google.common.base.Objects.hashCode(## + #set($i = 0) + #foreach($member in $members) + #if (!$member.static) + #if ($i > 0) + , ## + #end + $member.name ## + #set($i = $i + 1) + #end + #end + ); +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java index 1a80bc93a0eb..26677c86f572 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java @@ -18,12 +18,14 @@ package com.intellij.codeInsight.generation.ui; import com.intellij.codeInsight.CodeInsightBundle; import com.intellij.codeInsight.CodeInsightSettings; import com.intellij.codeInsight.NullableNotNullManager; +import com.intellij.codeInsight.generation.EqualsHashCodeTemplatesManager; import com.intellij.codeInsight.generation.GenerateEqualsHelper; import com.intellij.ide.wizard.StepAdapter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JavaVersionService; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.psi.*; import com.intellij.refactoring.classMembers.AbstractMemberInfoModel; @@ -38,9 +40,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.java.generate.psi.PsiAdapter; import javax.swing.*; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; +import java.util.List; /** * @author dsl @@ -247,7 +251,7 @@ public class GenerateEqualsWizard extends AbstractGenerateEqualsWizard Date: Mon, 12 Jan 2015 16:56:05 +0100 Subject: [PATCH 02/10] generate equals/hashCode: ui to configure additional templates --- .../EqualsHashCodeTemplatesManager.java | 47 +++- .../ui/EqualsHashCodeTemplatesPanel.java | 204 ++++++++++++++++++ .../generation/ui/GenerateEqualsWizard.java | 41 +++- 3 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/ui/EqualsHashCodeTemplatesPanel.java diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java index 1338616ad535..2bdcd287fa72 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java @@ -19,6 +19,7 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; +import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; @@ -28,8 +29,7 @@ import org.jetbrains.java.generate.template.TemplateResource; import org.jetbrains.java.generate.template.TemplatesManager; import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; +import java.util.*; @State( name = "EqualsHashCodeTemplates", @@ -83,11 +83,19 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { } public TemplateResource getDefaultEqualsTemplate() { - return getDefaultTemplate(EQUALS_SUFFIX, HASH_CODE_SUFFIX); + return getEqualsTemplate(getDefaultTemplate()); } public TemplateResource getDefaultHashcodeTemplate() { - return getDefaultTemplate(HASH_CODE_SUFFIX, EQUALS_SUFFIX); + return getHashcodeTemplate(getDefaultTemplate()); + } + + public TemplateResource getEqualsTemplate(TemplateResource template) { + return getDefaultTemplate(EQUALS_SUFFIX, HASH_CODE_SUFFIX, template); + } + + public TemplateResource getHashcodeTemplate(TemplateResource template) { + return getDefaultTemplate(HASH_CODE_SUFFIX, EQUALS_SUFFIX, template); } public String[] getTemplateNames() { @@ -99,12 +107,11 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { } @NotNull - private String getTemplateBaseName(TemplateResource resource) { + public static String getTemplateBaseName(TemplateResource resource) { return StringUtil.trimEnd(StringUtil.trimEnd(resource.getFileName(), EQUALS_SUFFIX), HASH_CODE_SUFFIX).trim(); } - private TemplateResource getDefaultTemplate(String selfSuffix, String oppositeSuffix) { - final TemplateResource defaultTemplate = getDefaultTemplate(); + private TemplateResource getDefaultTemplate(String selfSuffix, String oppositeSuffix, TemplateResource defaultTemplate) { final String fileName = defaultTemplate.getFileName(); if (fileName.endsWith(selfSuffix)) { return defaultTemplate; @@ -132,4 +139,30 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { public String getDefaultTemplateBaseName() { return getTemplateBaseName(getDefaultTemplate()); } + + public static String toEqualsName(String name) { + return name + " " + EQUALS_SUFFIX; + } + + public static String toHashCodeName(String name) { + return name + " " + HASH_CODE_SUFFIX; + } + + public Collection> getTemplateCouples() { + final LinkedHashMap> resources = new LinkedHashMap>(); + for (TemplateResource resource : getAllTemplates()) { + final String baseName = getTemplateBaseName(resource); + TemplateResource eq = toEqualsName(baseName).equals(resource.getFileName()) ? resource : null; + TemplateResource hc = toHashCodeName(baseName).equals(resource.getFileName()) ? resource : null; + final Couple couple = resources.get(baseName); + if (couple != null) { + resources.put(baseName, Couple.of(couple.first != null ? couple.first : eq, + couple.second != null ? couple.second : hc)); + } + else { + resources.put(baseName, Couple.of(eq, hc)); + } + } + return resources.values(); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/ui/EqualsHashCodeTemplatesPanel.java b/java/java-impl/src/com/intellij/codeInsight/generation/ui/EqualsHashCodeTemplatesPanel.java new file mode 100644 index 000000000000..144c8da3586e --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/ui/EqualsHashCodeTemplatesPanel.java @@ -0,0 +1,204 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.generation.ui; + +import com.intellij.codeInsight.generation.EqualsHashCodeTemplatesManager; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.NamedItemsListEditor; +import com.intellij.openapi.ui.Namer; +import com.intellij.openapi.ui.Splitter; +import com.intellij.openapi.util.Cloner; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.Factory; +import com.intellij.ui.TitledSeparator; +import gnu.trove.Equality; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.java.generate.template.TemplateResource; +import org.jetbrains.java.generate.view.GenerateTemplateConfigurable; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class EqualsHashCodeTemplatesPanel extends NamedItemsListEditor> { + private static final Namer> NAMER = new Namer>() { + + @Override + public String getName(Couple couple) { + return EqualsHashCodeTemplatesManager.getTemplateBaseName(couple.first); + } + + @Override + public boolean canRename(Couple item) { + return !item.first.isDefault(); + } + + @Override + public void setName(Couple couple, String name) { + couple.first.setFileName(EqualsHashCodeTemplatesManager.toEqualsName(name)); + couple.second.setFileName(EqualsHashCodeTemplatesManager.toHashCodeName(name)); + } + }; + + private static final Factory> FACTORY = new Factory>() { + @Override + public Couple create() { + return Couple.of(new TemplateResource(), new TemplateResource()); + } + }; + + private static final Cloner> CLONER = new Cloner>() { + @Override + public Couple cloneOf(Couple couple) { + if (couple.first.isDefault()) return couple; + return copyOf(couple); + } + + @Override + public Couple copyOf(Couple couple) { + return Couple.of(copyOf(couple.first), copyOf(couple.second)); + } + + @NotNull + private TemplateResource copyOf(TemplateResource resource) { + TemplateResource result = new TemplateResource(); + result.setFileName(resource.getFileName()); + result.setTemplate(resource.getTemplate()); + return result; + } + }; + + private static final Equality> COMPARER = new Equality>() { + @Override + public boolean equals(Couple o1, Couple o2) { + return equals(o1.first, o2.first) && equals(o1.second, o2.second); + } + + private boolean equals(TemplateResource r1, TemplateResource r2) { + return Comparing.equal(r1.getTemplate(), r2.getTemplate()) && Comparing.equal(r1.getFileName(), r2.getFileName()); + } + }; + private final Project myProject; + private final EqualsHashCodeTemplatesManager myManager; + + public EqualsHashCodeTemplatesPanel(Project project, EqualsHashCodeTemplatesManager manager) { + super(NAMER, FACTORY, CLONER, COMPARER, new ArrayList>(manager.getTemplateCouples())); + myProject = project; + myManager = manager; + } + + @Nls + public String getDisplayName() { + return "Templates"; + } + + @Override + protected String subjDisplayName() { + return "template"; + } + + @Nullable + @NonNls + public String getHelpTopic() { + return null; + } + + @Override + public boolean isModified() { + return super.isModified() || !Comparing.equal(myManager.getDefaultTemplate(), getSelectedItem().first); + } + + @Override + protected boolean canDelete(Couple item) { + return !item.first.isDefault(); + } + + @Override + protected UnnamedConfigurable createConfigurable(Couple item) { + final GenerateTemplateConfigurable equalsConfigurable = new GenerateTemplateConfigurable(item.first, myProject); + final GenerateTemplateConfigurable hashCodeConfigurable = new GenerateTemplateConfigurable(item.second, myProject); + return new UnnamedConfigurable() { + @Nullable + @Override + public JComponent createComponent() { + final Splitter splitter = new Splitter(true); + + final JPanel eqPanel = new JPanel(new BorderLayout()); + eqPanel.add(new TitledSeparator("Equals Template:"), BorderLayout.NORTH); + final JComponent eqPane = equalsConfigurable.createComponent(); + eqPane.setPreferredSize(new Dimension(300, 200)); + eqPanel.add(eqPane, BorderLayout.CENTER); + splitter.setFirstComponent(eqPanel); + + final JPanel hcPanel = new JPanel(new BorderLayout()); + hcPanel.add(new TitledSeparator("HashCode Template:"), BorderLayout.NORTH); + final JComponent hcPane = hashCodeConfigurable.createComponent(); + hcPane.setPreferredSize(new Dimension(300, 200)); + hcPanel.add(hcPane, BorderLayout.CENTER); + splitter.setSecondComponent(hcPanel); + + return splitter; + } + + @Override + public boolean isModified() { + return equalsConfigurable.isModified() || hashCodeConfigurable.isModified(); + } + + @Override + public void apply() throws ConfigurationException { + equalsConfigurable.apply(); + hashCodeConfigurable.apply(); + } + + @Override + public void reset() { + equalsConfigurable.reset(); + hashCodeConfigurable.reset(); + } + + @Override + public void disposeUIResources() { + equalsConfigurable.disposeUIResources(); + hashCodeConfigurable.disposeUIResources(); + } + }; + } + + @Override + public void apply() throws ConfigurationException { + super.apply(); + List resources = new ArrayList(); + for (Couple resource : getItems()) { + resources.add(resource.first); + resources.add(resource.second); + } + myManager.setTemplates(resources); + + final Couple selection = getSelectedItem(); + if (selection != null) { + myManager.setDefaultTemplate(selection.first); + } + } +} + diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java index 26677c86f572..5261839f25ad 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/ui/GenerateEqualsWizard.java @@ -22,10 +22,12 @@ import com.intellij.codeInsight.generation.EqualsHashCodeTemplatesManager; import com.intellij.codeInsight.generation.GenerateEqualsHelper; import com.intellij.ide.wizard.StepAdapter; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.JavaSdkVersion; import com.intellij.openapi.projectRoots.JavaVersionService; import com.intellij.openapi.ui.ComboBox; +import com.intellij.openapi.ui.ComponentWithBrowseButton; import com.intellij.openapi.ui.VerticalFlowLayout; import com.intellij.psi.*; import com.intellij.refactoring.classMembers.AbstractMemberInfoModel; @@ -251,7 +253,7 @@ public class GenerateEqualsWizard extends AbstractGenerateEqualsWizard comboBoxWithBrowseButton = new ComponentWithBrowseButton(comboBox, + new MyEditTemplatesListener(project, myPanel, comboBox)); final EqualsHashCodeTemplatesManager manager = EqualsHashCodeTemplatesManager.getInstance(); comboBox.setModel(new DefaultComboBoxModel(manager.getTemplateNames())); comboBox.setSelectedItem(manager.getDefaultTemplateBaseName()); @@ -358,11 +367,7 @@ public class GenerateEqualsWizard extends AbstractGenerateEqualsWizard Date: Mon, 12 Jan 2015 17:25:52 +0100 Subject: [PATCH 03/10] generate equals/hashCode: tests for apache/guava templates --- .../EqualsHashCodeTemplatesManager.java | 24 +++--- ...entTypesSuperEqualsAndHashCodeApache3.java | 78 +++++++++++++++++++ ...erentTypesSuperEqualsAndHashCodeGuava.java | 59 ++++++++++++++ ...entTypesSuperEqualsAndHashCodeApache3.java | 31 ++++++++ ...erentTypesSuperEqualsAndHashCodeGuava.java | 31 ++++++++ .../codeInsight/GenerateEquals15Test.java | 19 +++++ 6 files changed, 233 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeApache3.java create mode 100644 java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java create mode 100644 java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeApache3.java create mode 100644 java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeGuava.java diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java index 2bdcd287fa72..ffa8c2f6d725 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java @@ -23,6 +23,7 @@ import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.java.generate.exception.TemplateResourceException; import org.jetbrains.java.generate.template.TemplateResource; @@ -51,6 +52,11 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { private static final String EQUALS_SUFFIX = "equals"; private static final String HASH_CODE_SUFFIX = "hashCode"; + @NonNls public static final String INTELLI_J_DEFAULT = "IntelliJ Default"; + @NonNls public static final String EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG = "Equals/HashCodeBuilder (Apache commons-lang)"; + @NonNls public static final String EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG_3 = "Equals/HashCodeBuilder (Apache commons-lang 3)"; + @NonNls public static final String OBJECTS_EQUAL_AND_HASH_CODE_GUAVA = "Objects.equal and hashCode (Guava)"; + public static EqualsHashCodeTemplatesManager getInstance() { return ServiceManager.getService(EqualsHashCodeTemplatesManager.class); @@ -60,17 +66,17 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { public TemplateResource[] getDefaultTemplates() { try { return new TemplateResource[] { - new TemplateResource("IntelliJ Default equals", readFile(DEFAULT_EQUALS), true), - new TemplateResource("IntelliJ Default hashCode", readFile(DEFAULT_HASH_CODE), true), + new TemplateResource(toEqualsName(INTELLI_J_DEFAULT), readFile(DEFAULT_EQUALS), true), + new TemplateResource(toHashCodeName(INTELLI_J_DEFAULT), readFile(DEFAULT_HASH_CODE), true), - new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang) equals", readFile(APACHE_EQUALS), true), - new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang) hashCode", readFile(APACHE_HASH_CODE), true), + new TemplateResource(toEqualsName(EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG), readFile(APACHE_EQUALS), true), + new TemplateResource(toHashCodeName(EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG), readFile(APACHE_HASH_CODE), true), - new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang 3) equals", readFile(APACHE3_EQUALS), true), - new TemplateResource("Equals/HashCodeBuilder (Apache commons-lang 3) hashCode", readFile(APACHE3_HASH_CODE), true), + new TemplateResource(toEqualsName(EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG_3), readFile(APACHE3_EQUALS), true), + new TemplateResource(toHashCodeName(EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG_3), readFile(APACHE3_HASH_CODE), true), - new TemplateResource("Objects.equal and hashCode (Guava) equals", readFile(GUAVA_EQUALS), true), - new TemplateResource("Objects.equal and hashCode (Guava) hashCode", readFile(GUAVA_HASH_CODE), true), + new TemplateResource(toEqualsName(OBJECTS_EQUAL_AND_HASH_CODE_GUAVA), readFile(GUAVA_EQUALS), true), + new TemplateResource(toHashCodeName(OBJECTS_EQUAL_AND_HASH_CODE_GUAVA), readFile(GUAVA_HASH_CODE), true), }; } catch (IOException e) { @@ -127,7 +133,7 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { } public void setDefaultTemplate(String name) { - Set fullNames = ContainerUtil.newHashSet(name + " " + EQUALS_SUFFIX, name + " " + HASH_CODE_SUFFIX); + Set fullNames = ContainerUtil.newHashSet(toEqualsName(name), toHashCodeName(name)); for (TemplateResource resource : getAllTemplates()) { if (fullNames.contains(resource.getFileName())) { setDefaultTemplate(resource); diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeApache3.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeApache3.java new file mode 100644 index 000000000000..0cec1ef81118 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeApache3.java @@ -0,0 +1,78 @@ +class B { + @Override + public boolean equals(Object obj) { + return obj != null; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} +class A extends B { + Object[] a1; + Object[][] a2; + String[] a3; + String[][] a4; + int[] a5; + int[][] a6; + + byte a7; + short a8; + int a9; + long a10; + float a11; + double a12; + + Object a13; + String a14; + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + final A a = (A) o; + + return new org.apache.commons.lang3.builder.EqualsBuilder() + .appendSuper(super.equals(o)) + .append(a10, a.a10) + .append(a11, a.a11) + .append(a12, a.a12) + .append(a7, a.a7) + .append(a8, a.a8) + .append(a9, a.a9) + .append(a1, a.a1) + .append(a13, a.a13) + .append(a14, a.a14) + .append(a2, a.a2) + .append(a3, a.a3) + .append(a4, a.a4) + .append(a5, a.a5) + .append(a6, a.a6) + .isEquals(); + } + + @Override + public int hashCode() { + return new org.apache.commons.lang3.builder.HashCodeBuilder(17, 37) + .appendSuper(super.hashCode()) + .append(a1) + .append(a2) + .append(a3) + .append(a4) + .append(a5) + .append(a6) + .append(a7) + .append(a8) + .append(a9) + .append(a10) + .append(a11) + .append(a12) + .append(a13) + .append(a14) + .toHashCode(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java new file mode 100644 index 000000000000..b55764404950 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java @@ -0,0 +1,59 @@ +import java.util.Arrays; + +class B { + @Override + public boolean equals(Object obj) { + return obj != null; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} +class A extends B { + Object[] a1; + Object[][] a2; + String[] a3; + String[][] a4; + int[] a5; + int[][] a6; + + byte a7; + short a8; + int a9; + long a10; + float a11; + double a12; + + Object a13; + String a14; + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + final A a = (A) o; + return com.google.common.base.Objects.equal(a10, a.a10) && + com.google.common.base.Objects.equal(a11, a.a11) && + com.google.common.base.Objects.equal(a12, a.a12) && + com.google.common.base.Objects.equal(a7, a.a7) && + com.google.common.base.Objects.equal(a8, a.a8) && + com.google.common.base.Objects.equal(a9, a.a9) && + Arrays.equals(a1, a.a1) && + com.google.common.base.Objects.equal(a13, a.a13) && + com.google.common.base.Objects.equal(a14, a.a14) && + Arrays.deepEquals(a2, a.a2) && + Arrays.equals(a3, a.a3) && + Arrays.deepEquals(a4, a.a4) && + Arrays.equals(a5, a.a5) && + Arrays.deepEquals(a6, a.a6); + } + + @Override + public int hashCode() { + return com.google.common.base.Objects.hashCode(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeApache3.java b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeApache3.java new file mode 100644 index 000000000000..b123e793ba14 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeApache3.java @@ -0,0 +1,31 @@ +class B { + @Override + public boolean equals(Object obj) { + return obj != null; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} +class A extends B { + Object[] a1; + Object[][] a2; + String[] a3; + String[][] a4; + int[] a5; + int[][] a6; + + byte a7; + short a8; + int a9; + long a10; + float a11; + double a12; + + Object a13; + String a14; + + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeGuava.java b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeGuava.java new file mode 100644 index 000000000000..b123e793ba14 --- /dev/null +++ b/java/java-tests/testData/codeInsight/generateEquals/beforeDifferentTypesSuperEqualsAndHashCodeGuava.java @@ -0,0 +1,31 @@ +class B { + @Override + public boolean equals(Object obj) { + return obj != null; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} +class A extends B { + Object[] a1; + Object[][] a2; + String[] a3; + String[][] a4; + int[] a5; + int[][] a6; + + byte a7; + short a8; + int a9; + long a10; + float a11; + double a12; + + Object a13; + String a14; + + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java index 992f237c435e..68cd47604a9a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/GenerateEquals15Test.java @@ -1,5 +1,6 @@ package com.intellij.codeInsight; +import com.intellij.codeInsight.generation.EqualsHashCodeTemplatesManager; import com.intellij.psi.PsiField; import com.intellij.util.Function; @@ -37,4 +38,22 @@ public class GenerateEquals15Test extends GenerateEqualsTestCase { doTest(Function.ID, Function.ID, Function.ID, true); } + public void testDifferentTypesSuperEqualsAndHashCodeApache3() throws Exception { + doTestWithTemplate(EqualsHashCodeTemplatesManager.EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG_3); + } + + public void testDifferentTypesSuperEqualsAndHashCodeGuava() throws Exception { + doTestWithTemplate(EqualsHashCodeTemplatesManager.OBJECTS_EQUAL_AND_HASH_CODE_GUAVA); + } + + private void doTestWithTemplate(String templateName) throws Exception { + try { + EqualsHashCodeTemplatesManager.getInstance().setDefaultTemplate(templateName); + doTest(Function.ID, Function.ID, Function.ID, true); + } + finally { + EqualsHashCodeTemplatesManager.getInstance().setDefaultTemplate(EqualsHashCodeTemplatesManager.INTELLI_J_DEFAULT); + } + } + } \ No newline at end of file From aab113eeab979a6f4c07e33ccb4c245fbd683bc5 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Jan 2015 17:37:39 +0100 Subject: [PATCH 04/10] generate equals/hashCode: template for java.util.Objects; treat super.hashCode --- .../EqualsHashCodeTemplatesManager.java | 6 ++++ .../codeInsight/generation/guavaHashCode.vm | 4 +++ .../codeInsight/generation/objectsEquals.vm | 29 +++++++++++++++++++ .../codeInsight/generation/objectsHashCode.vm | 18 ++++++++++++ ...erentTypesSuperEqualsAndHashCodeGuava.java | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java index ffa8c2f6d725..0f25e54cfa1c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/EqualsHashCodeTemplatesManager.java @@ -48,6 +48,8 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { private static final String APACHE_HASH_CODE = "/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm"; private static final String GUAVA_EQUALS = "/com/intellij/codeInsight/generation/guavaEquals.vm"; private static final String GUAVA_HASH_CODE = "/com/intellij/codeInsight/generation/guavaHashCode.vm"; + private static final String OBJECTS_EQUALS = "/com/intellij/codeInsight/generation/objectsEquals.vm"; + private static final String OBJECTS_HASH_CODE = "/com/intellij/codeInsight/generation/objectsHashCode.vm"; private static final String EQUALS_SUFFIX = "equals"; private static final String HASH_CODE_SUFFIX = "hashCode"; @@ -56,6 +58,7 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { @NonNls public static final String EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG = "Equals/HashCodeBuilder (Apache commons-lang)"; @NonNls public static final String EQUALS_HASH_CODE_BUILDER_APACHE_COMMONS_LANG_3 = "Equals/HashCodeBuilder (Apache commons-lang 3)"; @NonNls public static final String OBJECTS_EQUAL_AND_HASH_CODE_GUAVA = "Objects.equal and hashCode (Guava)"; + @NonNls public static final String JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE = "java.util.Objects.equals and hashCode (java 7+)"; public static EqualsHashCodeTemplatesManager getInstance() { @@ -77,6 +80,9 @@ public class EqualsHashCodeTemplatesManager extends TemplatesManager { new TemplateResource(toEqualsName(OBJECTS_EQUAL_AND_HASH_CODE_GUAVA), readFile(GUAVA_EQUALS), true), new TemplateResource(toHashCodeName(OBJECTS_EQUAL_AND_HASH_CODE_GUAVA), readFile(GUAVA_HASH_CODE), true), + + new TemplateResource(toEqualsName(JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE), readFile(OBJECTS_EQUALS), true), + new TemplateResource(toHashCodeName(JAVA_UTIL_OBJECTS_EQUALS_AND_HASH_CODE), readFile(OBJECTS_HASH_CODE), true) }; } catch (IOException e) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm index 6f381f0c6b02..ff5bfcec7fb0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaHashCode.vm @@ -1,6 +1,10 @@ public int hashCode() { return com.google.common.base.Objects.hashCode(## #set($i = 0) + #if($superHasHashCode) + super.hashCode() ## + #set($i = 1) + #end #foreach($member in $members) #if (!$member.static) #if ($i > 0) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm new file mode 100644 index 000000000000..08b7723c9d17 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm @@ -0,0 +1,29 @@ +#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +public boolean equals(## +#if ($settings.generateFinalParameters) + final ## +#end +Object $paramName){ + #addEqualsPrologue() + #addClassInstance() + return ## + #set($i = 0) + #foreach($field in $members) + #if (!$field.static) + #if ($i > 0) + && + #end + #set($i = $i + 1) + #if ($field.array) + #if ($field.nestedArray) +java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## + #else +java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## + #end + #else +java.util.Objects.equals($field.name, ${classInstanceName}.$field.name)## + #end + #end + #end + ; +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm new file mode 100644 index 000000000000..dfe06020b040 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsHashCode.vm @@ -0,0 +1,18 @@ +public int hashCode() { + return java.util.Objects.hash(## + #set($i = 0) + #if($superHasHashCode) + super.hashCode() ## + #set($i = 1) + #end + #foreach($member in $members) + #if (!$member.static) + #if ($i > 0) + , ## + #end + $member.name ## + #set($i = $i + 1) + #end + #end + ); +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java index b55764404950..1c500e9da141 100644 --- a/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java +++ b/java/java-tests/testData/codeInsight/generateEquals/afterDifferentTypesSuperEqualsAndHashCodeGuava.java @@ -54,6 +54,6 @@ class A extends B { @Override public int hashCode() { - return com.google.common.base.Objects.hashCode(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); + return com.google.common.base.Objects.hashCode(super.hashCode(), a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14); } } \ No newline at end of file From 958d48c84d8145dacfb62de95b05faf59a2e60f3 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Jan 2015 17:49:55 +0100 Subject: [PATCH 05/10] generate equals/hashCode: catch exceptions from invalid templates --- .../generation/GenerateEqualsHelper.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java index 42adc40a11dd..106733b899a1 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateEqualsHelper.java @@ -159,8 +159,16 @@ public class GenerateEqualsHelper implements Runnable { .velocityGenerateCode(myClass, equalsFields, myNonNullSet, new HashMap(), contextMap, EqualsHashCodeTemplatesManager.getInstance().getDefaultEqualsTemplate().getTemplate(), 0, false); buffer.append(methodText); - PsiMethod result = myFactory.createMethodFromText(buffer.toString(), myClass); - final PsiParameter parameter = result.getParameterList().getParameters()[0]; + PsiMethod result; + try { + result = myFactory.createMethodFromText(buffer.toString(), myClass); + } + catch (IncorrectOperationException e) { + return null; + } + final PsiParameter[] parameters = result.getParameterList().getParameters(); + if (parameters.length != 1) return null; + final PsiParameter parameter = parameters[0]; PsiUtil.setModifierProperty(parameter, PsiModifier.FINAL, styleSettings.GENERATE_FINAL_PARAMETERS); PsiMethod method = (PsiMethod)myCodeStyleManager.reformat(result); @@ -190,7 +198,13 @@ public class GenerateEqualsHelper implements Runnable { .velocityGenerateCode(myClass, Arrays.asList(myHashCodeFields), myNonNullSet, new HashMap(), contextMap, EqualsHashCodeTemplatesManager.getInstance().getDefaultHashcodeTemplate().getTemplate(), 0, false); buffer.append(methodText); - PsiMethod hashCode = myFactory.createMethodFromText(buffer.toString(), null); + PsiMethod hashCode; + try { + hashCode = myFactory.createMethodFromText(buffer.toString(), null); + } + catch (IncorrectOperationException e) { + return null; + } hashCode = (PsiMethod)myJavaCodeStyleManager.shortenClassReferences(hashCode); return (PsiMethod)myCodeStyleManager.reformat(hashCode); } From 15919a000d2946fd59c4fa9976276c70515b552e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Jan 2015 18:00:30 +0100 Subject: [PATCH 06/10] generate equals/hashCode: remove checks for static fields as statics are already excluded from $members --- .../generation/apacheEqualsBuilder.vm | 4 +--- .../generation/apacheEqualsBuilder3.vm | 4 +--- .../generation/apacheHashCodeBuilder.vm | 2 -- .../generation/apacheHashCodeBuilder3.vm | 2 -- .../codeInsight/generation/defaultEquals.vm | 22 +++++++++---------- .../codeInsight/generation/guavaEquals.vm | 20 ++++++++--------- .../codeInsight/generation/objectsEquals.vm | 20 ++++++++--------- 7 files changed, 30 insertions(+), 44 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm index 0fb13fc8b06f..06f267ef3098 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm @@ -15,9 +15,7 @@ Object $paramName){ .appendSuper(super.equals($paramName)) #end #foreach($field in $members) - #if (!$field.static) - .append($field.name, ${classInstanceName}.$field.name) - #end + .append($field.name, ${classInstanceName}.$field.name) #end .isEquals(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm index fd509e5e7498..ce36e031f0f8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm @@ -15,9 +15,7 @@ Object $paramName){ .appendSuper(super.equals($paramName)) #end #foreach($field in $members) - #if (!$field.static) - .append($field.name, ${classInstanceName}.$field.name) - #end + .append($field.name, ${classInstanceName}.$field.name) #end .isEquals(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm index ae5f73ced6ad..db93847c6d3b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder.vm @@ -4,9 +4,7 @@ public int hashCode() { .appendSuper(super.hashCode()) #end #foreach($field in $members) - #if (!$field.static) .append($field.name) - #end #end .toHashCode(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm index fa9919c94809..ecb288dc146a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheHashCodeBuilder3.vm @@ -4,9 +4,7 @@ public int hashCode() { .appendSuper(super.hashCode()) #end #foreach($field in $members) - #if (!$field.static) .append($field.name) - #end #end .toHashCode(); } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm index b1ed5e54f040..055d18416e0a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm @@ -10,20 +10,18 @@ Object $paramName){ #addClassInstance() #foreach($field in $members) - #if (!$field.static) - #if ($field.array) - #addArrayEquals($field) - #elseif ($field.primitive) - #if ($field.double || $field.float) - #addDoubleFieldComparison($field) - #else - #addPrimitiveFieldComparison($field) - #end - #elseif ($field.enum) + #if ($field.array) + #addArrayEquals($field) + #elseif ($field.primitive) + #if ($field.double || $field.float) + #addDoubleFieldComparison($field) + #else #addPrimitiveFieldComparison($field) - #else - #addFieldComparison($field) #end + #elseif ($field.enum) + #addPrimitiveFieldComparison($field) + #else + #addFieldComparison($field) #end #end #end diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm index 3f5b280fdc25..eff56c357293 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm @@ -9,20 +9,18 @@ Object $paramName){ return ## #set($i = 0) #foreach($field in $members) - #if (!$field.static) - #if ($i > 0) - && - #end - #set($i = $i + 1) - #if ($field.array) - #if ($field.nestedArray) + #if ($i > 0) + && + #end + #set($i = $i + 1) + #if ($field.array) + #if ($field.nestedArray) java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## - #else -java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## - #end #else -com.google.common.base.Objects.equal($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## #end + #else +com.google.common.base.Objects.equal($field.name, ${classInstanceName}.$field.name)## #end #end ; diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm index 08b7723c9d17..0bf3e43d2982 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm @@ -9,20 +9,18 @@ Object $paramName){ return ## #set($i = 0) #foreach($field in $members) - #if (!$field.static) - #if ($i > 0) - && - #end - #set($i = $i + 1) - #if ($field.array) - #if ($field.nestedArray) + #if ($i > 0) + && + #end + #set($i = $i + 1) + #if ($field.array) + #if ($field.nestedArray) java.util.Arrays.deepEquals($field.name, ${classInstanceName}.$field.name)## - #else -java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## - #end #else -java.util.Objects.equals($field.name, ${classInstanceName}.$field.name)## +java.util.Arrays.equals($field.name, ${classInstanceName}.$field.name)## #end + #else +java.util.Objects.equals($field.name, ${classInstanceName}.$field.name)## #end #end ; From 268171ca99715bfcb0f97fb92464a6fdbee35a6e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 12 Jan 2015 18:07:59 +0100 Subject: [PATCH 07/10] generate equals/hashCode: use special loader to include by short name --- .../VelocityIncludesClassLoader.java | 28 +++++++++++++++++++ .../generation/apacheEqualsBuilder.vm | 2 +- .../generation/apacheEqualsBuilder3.vm | 2 +- .../codeInsight/generation/defaultEquals.vm | 2 +- ...{commonEqualsMacros.vm => equalsHelper.vm} | 0 .../codeInsight/generation/guavaEquals.vm | 2 +- .../codeInsight/generation/objectsEquals.vm | 2 +- .../generate/velocity/VelocityFactory.java | 3 +- 8 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/generation/VelocityIncludesClassLoader.java rename java/java-impl/src/com/intellij/codeInsight/generation/{commonEqualsMacros.vm => equalsHelper.vm} (100%) diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/VelocityIncludesClassLoader.java b/java/java-impl/src/com/intellij/codeInsight/generation/VelocityIncludesClassLoader.java new file mode 100644 index 000000000000..0266e86d3d36 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/generation/VelocityIncludesClassLoader.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.generation; + +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; + +import java.io.InputStream; + +public class VelocityIncludesClassLoader extends ClasspathResourceLoader { + @Override + public InputStream getResourceStream(String name) throws ResourceNotFoundException { + return super.getResourceStream("com/intellij/codeInsight/generation/" + name); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm index 06f267ef3098..690a223c5d00 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder.vm @@ -1,4 +1,4 @@ -#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +#parse("equalsHelper.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm index ce36e031f0f8..dd3fecd94f80 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/apacheEqualsBuilder3.vm @@ -1,4 +1,4 @@ -#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +#parse("equalsHelper.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm index 055d18416e0a..94c6c93d4065 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/defaultEquals.vm @@ -1,4 +1,4 @@ -#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +#parse("equalsHelper.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm b/java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm similarity index 100% rename from java/java-impl/src/com/intellij/codeInsight/generation/commonEqualsMacros.vm rename to java/java-impl/src/com/intellij/codeInsight/generation/equalsHelper.vm diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm index eff56c357293..213cabdd032d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/guavaEquals.vm @@ -1,4 +1,4 @@ -#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +#parse("equalsHelper.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm index 0bf3e43d2982..878a1f7656bd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm +++ b/java/java-impl/src/com/intellij/codeInsight/generation/objectsEquals.vm @@ -1,4 +1,4 @@ -#parse("com/intellij/codeInsight/generation/commonEqualsMacros.vm") +#parse("equalsHelper.vm") public boolean equals(## #if ($settings.generateFinalParameters) final ## diff --git a/plugins/generate-tostring/src/org/jetbrains/java/generate/velocity/VelocityFactory.java b/plugins/generate-tostring/src/org/jetbrains/java/generate/velocity/VelocityFactory.java index c45775d0555a..faaa80907a8e 100644 --- a/plugins/generate-tostring/src/org/jetbrains/java/generate/velocity/VelocityFactory.java +++ b/plugins/generate-tostring/src/org/jetbrains/java/generate/velocity/VelocityFactory.java @@ -15,6 +15,7 @@ */ package org.jetbrains.java.generate.velocity; +import com.intellij.codeInsight.generation.VelocityIncludesClassLoader; import org.apache.commons.collections.ExtendedProperties; import org.apache.velocity.app.Velocity; import org.apache.velocity.app.VelocityEngine; @@ -51,7 +52,7 @@ public class VelocityFactory { prop.addProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, SimpleLog4JLogSystem.class.getName()); prop.addProperty("runtime.log.logsystem.log4j.category", "GenerateToString"); prop.addProperty(RuntimeConstants.RESOURCE_LOADER, "includes"); - prop.addProperty("includes.resource.loader.class", ClasspathResourceLoader.class.getName()); + prop.addProperty("includes.resource.loader.class", VelocityIncludesClassLoader.class.getName()); VelocityEngine velocity = new VelocityEngine(); velocity.setExtendedProperties(prop); velocity.init(); From d38083b6e02cb59c756e670e87655c7e6e8398ec Mon Sep 17 00:00:00 2001 From: Dennis Ushakov Date: Mon, 12 Jan 2015 20:11:50 +0300 Subject: [PATCH 08/10] fix spaces stripping tests --- .../EditorSettingsManager.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorSettingsManager.java b/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorSettingsManager.java index 0e4c06929f68..8e3f7db77a60 100644 --- a/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorSettingsManager.java +++ b/plugins/editorconfig/src/org/editorconfig/configmanagement/EditorSettingsManager.java @@ -74,17 +74,13 @@ public class EditorSettingsManager extends FileDocumentManagerAdapter { private void applyConfigValueToUserData(VirtualFile file, Key userDataKey, String editorConfigKey, String configValue, Map configMap) { - if (configValue.isEmpty()) { - file.putUserData(userDataKey, null); - } - else { - final T data = configMap.get(configValue); - if (data == null) { - Utils.invalidConfigMessage(myProject, configValue, editorConfigKey, file.getCanonicalPath()); - } - else { - file.putUserData(userDataKey, data); - } + if (configValue.isEmpty()) return; + + final T data = configMap.get(configValue); + if (data == null) { + Utils.invalidConfigMessage(myProject, configValue, editorConfigKey, file.getCanonicalPath()); + } else { + file.putUserData(userDataKey, data); } } } From dad60f7b9cc270c097f7d056b6257d40521a3fc5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 12 Jan 2015 17:58:11 +0100 Subject: [PATCH 09/10] fail launcher generator on error --- build/scripts/utils.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant index 29a081c309a7..71b39fa46d96 100644 --- a/build/scripts/utils.gant +++ b/build/scripts/utils.gant @@ -852,7 +852,7 @@ binding.setVariable("buildWinLauncher", { String ch, String inputPath, String ou launcherProperties = launcherPropertiesTemp } - ant.java(classname: "com.pme.launcher.LauncherGeneratorMain", fork: "true") { + ant.java(classname: "com.pme.launcher.LauncherGeneratorMain", fork: "true", failonerror: "true") { sysproperty(key: "java.awt.headless", value: "true") arg(value: inputPath) arg(value: appInfo) From 398323f36a68a0f0f551e4888d01751bf1cc037d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 12 Jan 2015 18:01:07 +0100 Subject: [PATCH 10/10] another race condition with accessing SrcFileAnnotator.myFile after it has been disposed (https://ea.jetbrains.com/browser/ea_reports/772151) --- .../com/intellij/coverage/SrcFileAnnotator.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java index 595585998fde..3be1079fffc3 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java +++ b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java @@ -1,5 +1,17 @@ /* - * Copyright (c) 2000-2006 JetBrains s.r.o. All Rights Reserved. + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package com.intellij.coverage; @@ -287,7 +299,8 @@ public class SrcFileAnnotator implements Disposable { // let's find old content in local history and build mapping from old lines to new one // local history doesn't index libraries, so let's distinguish libraries content with other one final ProjectFileIndex projectFileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - final VirtualFile file = getVirtualFile(); + final VirtualFile file = psiFile.getVirtualFile(); + LOG.assertTrue(file != null); final long fileTimeStamp = file.getTimeStamp(); final long coverageTimeStamp = suite.getLastCoverageTimeStamp();