From a34dfe8ade0721a91e86fc98a6a54ba1ad2508f9 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Sun, 20 Jan 2013 10:25:11 +0100 Subject: [PATCH 01/18] DevKit: * support AppCode 1.6 and 2.0) (cherry picked from commit ca2b8ed) * allow specifying idea.platform.prefix in Plugin run configuration. --- .../configurations/ParametersList.java | 5 +-- .../src/com/intellij/util/PlatformUtils.java | 4 +- .../src/run/PluginRunConfiguration.java | 44 +++++++++++-------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java index 1c22a7e51613..503d217ba1f7 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java @@ -47,10 +47,7 @@ public class ParametersList implements Cloneable { } public boolean hasProperty(@NonNls final String name) { - for (@NonNls String parameter : myParameters) { - if (parameter.startsWith("-D" + name + '=')) return true; - } - return false; + return getPropertyValue(name) != null; } @Nullable diff --git a/platform/platform-api/src/com/intellij/util/PlatformUtils.java b/platform/platform-api/src/com/intellij/util/PlatformUtils.java index 79b69414162f..ad6840591f15 100644 --- a/platform/platform-api/src/com/intellij/util/PlatformUtils.java +++ b/platform/platform-api/src/com/intellij/util/PlatformUtils.java @@ -23,6 +23,8 @@ import org.jetbrains.annotations.Nullable; * @author Konstantin Bulenkov */ public class PlatformUtils { + public static final String PLATFORM_PREFIX_KEY = "idea.platform.prefix"; + public static final String IDEA_PREFIX = "idea"; public static final String COMMUNITY_PREFIX = "Idea"; public static final String APPCODE_PREFIX = "AppCode"; @@ -40,7 +42,7 @@ public class PlatformUtils { } public static String getPlatformPrefix(String defaultPrefix) { - return System.getProperty("idea.platform.prefix", defaultPrefix); + return System.getProperty(PLATFORM_PREFIX_KEY, defaultPrefix); } public static boolean isIdea() { diff --git a/plugins/devkit/src/run/PluginRunConfiguration.java b/plugins/devkit/src/run/PluginRunConfiguration.java index 597eb02ccda3..e71ee7e155e6 100644 --- a/plugins/devkit/src/run/PluginRunConfiguration.java +++ b/plugins/devkit/src/run/PluginRunConfiguration.java @@ -33,6 +33,7 @@ import com.intellij.openapi.projectRoots.SdkModificator; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PlatformUtils; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -144,25 +145,30 @@ public class PluginRunConfiguration extends RunConfigurationBase implements Modu } } - String buildNumber = IdeaJdk.getBuildNumber(usedIdeaJdk.getHomePath()); - if (buildNumber != null) { - if (buildNumber.startsWith("IC")) { - vm.defineProperty("idea.platform.prefix", "Idea"); - } - else if (buildNumber.startsWith("PY")) { - vm.defineProperty("idea.platform.prefix", "Python"); - } - else if (buildNumber.startsWith("RM")) { - vm.defineProperty("idea.platform.prefix", "Ruby"); - } - else if (buildNumber.startsWith("PS")) { - vm.defineProperty("idea.platform.prefix", "PhpStorm"); - } - else if (buildNumber.startsWith("WS")) { - vm.defineProperty("idea.platform.prefix", "WebStorm"); - } - else if (buildNumber.startsWith("OC")) { - vm.defineProperty("idea.platform.prefix", "AppCode"); + if (!vm.hasProperty(PlatformUtils.PLATFORM_PREFIX_KEY)) { + String buildNumber = IdeaJdk.getBuildNumber(usedIdeaJdk.getHomePath()); + if (buildNumber != null) { + String prefix = null; + + if (buildNumber.startsWith("IC")) { + prefix = PlatformUtils.COMMUNITY_PREFIX; + } + else if (buildNumber.startsWith("PY")) { + prefix = PlatformUtils.PYCHARM_PREFIX; + } + else if (buildNumber.startsWith("RM")) { + prefix = PlatformUtils.RUBY_PREFIX; + } + else if (buildNumber.startsWith("PS")) { + prefix = PlatformUtils.PHP_PREFIX; + } + else if (buildNumber.startsWith("WS")) { + prefix = PlatformUtils.WEB_PREFIX; + } + else if (buildNumber.startsWith("OC")) { + prefix = buildNumber.contains("121") ? "CIDR" : PlatformUtils.APPCODE_PREFIX; + } + if (prefix != null) vm.defineProperty(PlatformUtils.PLATFORM_PREFIX_KEY, prefix); } } From 505a556c3525fe5a74b28e0ba02fcf10559c61d8 Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Sun, 20 Jan 2013 10:25:11 +0100 Subject: [PATCH 02/18] DevKit: clarification: IntelliJ IDEA SDK -> IntelliJ Platform SDK --- .../resources/fileTemplates/j2ee/Action.java.html | 2 +- .../j2ee/ApplicationComponent.java.html | 2 +- .../fileTemplates/j2ee/ModuleComponent.java.html | 2 +- .../fileTemplates/j2ee/ProjectComponent.java.html | 2 +- .../resources/fileTemplates/j2ee/plugin.xml.html | 2 +- plugins/devkit/src/DevKitBundle.properties | 12 +++++------- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/plugins/devkit/resources/fileTemplates/j2ee/Action.java.html b/plugins/devkit/resources/fileTemplates/j2ee/Action.java.html index 77a42a6d68b4..dfdcdc190f38 100644 --- a/plugins/devkit/resources/fileTemplates/j2ee/Action.java.html +++ b/plugins/devkit/resources/fileTemplates/j2ee/Action.java.html @@ -3,7 +3,7 @@
This is a built-in template used each time you create - a new IntelliJ IDEA action. + a new IntelliJ Platform action.
diff --git a/plugins/devkit/resources/fileTemplates/j2ee/ApplicationComponent.java.html b/plugins/devkit/resources/fileTemplates/j2ee/ApplicationComponent.java.html index 70dcf44bc50d..999447a6446d 100644 --- a/plugins/devkit/resources/fileTemplates/j2ee/ApplicationComponent.java.html +++ b/plugins/devkit/resources/fileTemplates/j2ee/ApplicationComponent.java.html @@ -3,7 +3,7 @@
This is a built-in template used each time you create - a new IntelliJ IDEA application component. + a new IntelliJ Platform application component.
diff --git a/plugins/devkit/resources/fileTemplates/j2ee/ModuleComponent.java.html b/plugins/devkit/resources/fileTemplates/j2ee/ModuleComponent.java.html index 1929e4054837..79bcdabfec27 100644 --- a/plugins/devkit/resources/fileTemplates/j2ee/ModuleComponent.java.html +++ b/plugins/devkit/resources/fileTemplates/j2ee/ModuleComponent.java.html @@ -3,7 +3,7 @@
This is a built-in template used each time you create - a new IntelliJ IDEA module component. + a new IntelliJ Platform module component.
diff --git a/plugins/devkit/resources/fileTemplates/j2ee/ProjectComponent.java.html b/plugins/devkit/resources/fileTemplates/j2ee/ProjectComponent.java.html index b42f0ac6c94a..b07885752ce0 100644 --- a/plugins/devkit/resources/fileTemplates/j2ee/ProjectComponent.java.html +++ b/plugins/devkit/resources/fileTemplates/j2ee/ProjectComponent.java.html @@ -3,7 +3,7 @@
This is a built-in template used each time you create - a new IntelliJ IDEA project component. + a new IntelliJ Platform project component.
diff --git a/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html index e1aea3bf5b88..623bc70215db 100644 --- a/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html +++ b/plugins/devkit/resources/fileTemplates/j2ee/plugin.xml.html @@ -3,7 +3,7 @@
This is a built-in template used each time you create - a new IntelliJ IDEA plugin module. + a new IntelliJ Platform plugin module.
diff --git a/plugins/devkit/src/DevKitBundle.properties b/plugins/devkit/src/DevKitBundle.properties index c17b1f5d4863..2085019ba69c 100644 --- a/plugins/devkit/src/DevKitBundle.properties +++ b/plugins/devkit/src/DevKitBundle.properties @@ -1,8 +1,8 @@ #module type -module.title=IntelliJ IDEA Plugin -module.description=Plugin modules are used for development of IntelliJ IDEA Plugins. They support IntelliJ IDEA Plugin SDK configuration and \ - Run Configuration for running a dedicated IntelliJ IDEA instance for plugin debugging. -plugin.descriptor=IntelliJ IDEA Plugin Descriptor +module.title=IntelliJ Platform Plugin +module.description=Plugin modules are used for developing plugins for IntelliJ Platform-based IDEs.
\ + They provide IntelliJ Platform Plugin SDK and Run Configuration for running and debugging plugins inside an IDE. +plugin.descriptor=IntelliJ Platform Plugin Descriptor #Module Editor - Deployment deployment.title=Plugin Deployment @@ -30,7 +30,7 @@ success.deployment.message=Plugin Module ''{0}'' Successfully Prepared For Deplo success.deployment.message.all=All Plugins Successfully Prepared For Deployment ##Idea Sdk -sdk.title=IntelliJ IDEA Plugin SDK +sdk.title=IntelliJ Platform Plugin SDK sandbox.specification=Please configure the sandbox sandbox.home=Sandbox Home sandbox.home.label=Sandbox Home: @@ -64,8 +64,6 @@ presentable.plugin.module.name=Plugin Module ''{0}'' action.MakeJarAction.text=Prepare To Deploy action.MakeAllJarsAction.text=Prepare All Plugins To Deploy -plugin.DevKit.description=IntelliJ IDEA plugins development kit. Adds dedicated Plugin module type to IntelliJ IDEA project.\ - Allows running/debugging IDEA plugins through Plugin-oriented Run/Debug Configuration dont.add.idea.libs.to.classpath=IDEA-related libraries ({0}) must not be added to the module classpath. Please add them to the IDEA-JDK instead. new.action.id=&Action ID: From 8967e6b25a91957f8c318682ae7f01ec77fdab70 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sun, 20 Jan 2013 13:28:07 +0100 Subject: [PATCH 03/18] remove unused class --- .../com/siyeh/ig/InspectionComparator.java | 68 ------------------- 1 file changed, 68 deletions(-) delete mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java deleted file mode 100644 index e792c0e1e743..000000000000 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionComparator.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2003-2005 Dave Griffith - * - * 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.siyeh.ig; - -import com.intellij.codeInspection.InspectionProfileEntry; - -import java.util.Comparator; - -class InspectionComparator - implements Comparator> { - - public int compare(Class class1, - Class class2) { - final InspectionProfileEntry inspection1; - final InspectionProfileEntry inspection2; - try { - inspection1 = class1.newInstance(); - inspection2 = class2.newInstance(); - } - catch (InstantiationException ignore) { - return -1; - } - catch (IllegalAccessException ignore) { - return -1; - } - final String groupName1 = inspection1.getGroupDisplayName(); - final String groupName2 = inspection2.getGroupDisplayName(); - final int groupNameComparison = groupName1.compareTo(groupName2); - if (groupNameComparison != 0) { - return groupNameComparison; - } - String displayName1 = inspection1.getDisplayName(); - String displayName2 = inspection2.getDisplayName(); - displayName1 = displayName1.toUpperCase(); - displayName2 = displayName2.toUpperCase(); - displayName1 = stripQuotes(displayName1); - displayName2 = stripQuotes(displayName2); - return displayName1.compareTo(displayName2); - } - - private static String stripQuotes(String str) { - if (str.indexOf((int)'\'') < 0 && str.indexOf((int)'"') < 0) { - return str; - } - final int length = str.length(); - final StringBuffer buffer = new StringBuffer(length); - for (int i = 0; i < length; i++) { - final char ch = str.charAt(i); - if (ch != '"' && ch != '\'') { - buffer.append(ch); - } - } - return buffer.toString(); - } -} \ No newline at end of file From e060c684031c8f666942d3883f14c680a5f20463 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Sun, 20 Jan 2013 13:30:20 +0100 Subject: [PATCH 04/18] Rewrite "Field not used in 'toString()' method" inspection, add test, fixes IDEA-99324 & IDEA-99328 --- .../generate-tostring/generate-tostring.iml | 2 + .../ClassHasNoToStringMethodInspection.java | 9 +- .../FieldNotUsedInToStringInspection.java | 316 ++++++++---------- .../inspection/GenerateToStringQuickFix.java | 23 +- .../FieldNotUsedInToStringInspectionTest.java | 77 +++++ 5 files changed, 227 insertions(+), 200 deletions(-) create mode 100644 plugins/generate-tostring/testSrc/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspectionTest.java diff --git a/plugins/generate-tostring/generate-tostring.iml b/plugins/generate-tostring/generate-tostring.iml index e8e22247a171..501580be8464 100644 --- a/plugins/generate-tostring/generate-tostring.iml +++ b/plugins/generate-tostring/generate-tostring.iml @@ -5,6 +5,7 @@ + @@ -15,6 +16,7 @@ + diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/ClassHasNoToStringMethodInspection.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/ClassHasNoToStringMethodInspection.java index b716c5dd6706..95a165676c0f 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/ClassHasNoToStringMethodInspection.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/ClassHasNoToStringMethodInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2012 the original author or authors. + * Copyright 2001-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,8 @@ package org.jetbrains.generate.tostring.inspection; import com.intellij.codeInsight.TestFrameworks; -import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.ui.CheckBox; @@ -44,8 +42,6 @@ import java.awt.*; */ public class ClassHasNoToStringMethodInspection extends AbstractToStringInspection { - private final LocalQuickFix fix = new GenerateToStringQuickFix(); - /** User options for classes to exclude. Must be a regexp pattern */ public String excludeClassNames = ""; // must be public for JDOMSerialization /** User options for excluded exception classes */ @@ -161,7 +157,8 @@ public class ClassHasNoToStringMethodInspection extends AbstractToStringInspecti } if (log.isDebugEnabled()) log.debug("Class does not override toString() method: " + clazz.getQualifiedName()); - holder.registerProblem(nameIdentifier, "Class '" + clazz.getName() + "' does not override 'toString()' method", ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix); + holder.registerProblem(nameIdentifier, "Class '" + clazz.getName() + "' does not override 'toString()' method", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, GenerateToStringQuickFix.getInstance()); } }; } diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspection.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspection.java index 679d6ddae0ea..2f38c189979f 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspection.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2012 the original author or authors. + * Copyright 2001-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,217 +15,163 @@ */ package org.jetbrains.generate.tostring.inspection; -import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.util.PropertyUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.generate.tostring.GenerateToStringContext; import org.jetbrains.generate.tostring.GenerateToStringUtils; -import org.jetbrains.generate.tostring.psi.PsiAdapter; + +import java.util.Collections; /** - * Intention to check if the current class toString() method is out of - * sync with the fields defined. - *

- * This inspection will use filter information from the settings to exclude certain fields (eg. constants etc.). - *

- * This inspection will only perform inspection if the class has a toString() method. + * Inspection to check if the current class toString() method is out of + * sync with the fields defined. It uses filter information from the settings + * to exclude certain fields (eg. constants etc.). Will only warn if the + * class has a toString() method. */ public class FieldNotUsedInToStringInspection extends AbstractToStringInspection { - private final LocalQuickFix fix = new GenerateToStringQuickFix(); + @NotNull + public String getDisplayName() { + return "Field not used in 'toString()' method"; + } - @NotNull - public String getDisplayName() { - return "Field not used in 'toString()' method"; - } + @NotNull + public String getShortName() { + return "FieldNotUsedInToString"; + } - @NotNull - public String getShortName() { - return "FieldNotUsedInToString"; + @Override + public boolean runForWholeFile() { + return true; + } + + @NotNull + @Override + public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { + return new FieldNotUsedInToStringVisitor(holder); + } + + private static class FieldNotUsedInToStringVisitor extends JavaElementVisitor{ + + private final ProblemsHolder myHolder; + + public FieldNotUsedInToStringVisitor(ProblemsHolder holder) { + myHolder = holder; } @Override - public boolean runForWholeFile() { - return true; + public void visitField(PsiField field) { + super.visitField(field); } - @NotNull @Override - public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { - return new JavaElementVisitor() { - @Override - public void visitClass(PsiClass clazz) { - checkFields(holder, clazz); - checkMethods(holder, clazz); - } - }; + public void visitMethod(PsiMethod method) { + super.visitMethod(method); + @NonNls final String methodName = method.getName(); + if (!"toString".equals(methodName)) { + return; + } + final PsiParameterList parameterList = method.getParameterList(); + if (parameterList.getParametersCount() != 0) { + return; + } + final PsiType returnType = method.getReturnType(); + final PsiClassType javaLangString = PsiType.getJavaLangString(method.getManager(), method.getResolveScope()); + if (!javaLangString.equals(returnType)) { + return; + } + final PsiClass aClass = method.getContainingClass(); + if (aClass == null) { + return; + } + final PsiField[] fields = + GenerateToStringUtils.filterAvailableFields(aClass, GenerateToStringContext.getConfig().getFilterPattern()); + final PsiMethod[] methods; + if (GenerateToStringContext.getConfig().isEnableMethods()) { + methods = GenerateToStringUtils.filterAvailableMethods(aClass, GenerateToStringContext.getConfig().getFilterPattern()); + } + else { + methods = PsiMethod.EMPTY_ARRAY; + } + final FieldUsedVisitor visitor = new FieldUsedVisitor(fields, methods); + method.accept(visitor); + for (PsiField field : visitor.getUnusedFields()) { + final String fieldName = field.getName(); + myHolder.registerProblem(field.getNameIdentifier(), "Field '" + fieldName + "' is not used in 'toString()' method", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, GenerateToStringQuickFix.getInstance()); + } + for (PsiMethod unusedMethod : visitor.getUnusedMethods()) { + final PsiIdentifier identifier = unusedMethod.getNameIdentifier(); + final PsiElement target = identifier == null ? unusedMethod : identifier; + myHolder.registerProblem(target, "Method '" + unusedMethod.getName() + "' is not used in 'toString()' method", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, GenerateToStringQuickFix.getInstance()); + } + } + } + + private static class FieldUsedVisitor extends JavaRecursiveElementVisitor { + + private final THashSet myUnusedFields = new THashSet(); + private final THashSet myUnusedMethods = new THashSet(); + + public FieldUsedVisitor(PsiField[] fields, PsiMethod[] methods) { + Collections.addAll(myUnusedFields, fields); + Collections.addAll(myUnusedMethods, methods); } - /** - * Checking for problems with fields. - * - * @param clazz the class to check - * @param holder a sink to feed the problem to - */ - private void checkFields(ProblemsHolder holder, PsiClass clazz) { - if (log.isDebugEnabled()) log.debug("checkFields: clazz=" + clazz); - - // must be a class - if (clazz == null || clazz.getName() == null) { - return; + @Override + public void visitReferenceExpression(PsiReferenceExpression expression) { + if (myUnusedFields.isEmpty() && myUnusedMethods.isEmpty()) { + return; + } + super.visitReferenceExpression(expression); + final PsiElement target = expression.resolve(); + if (target instanceof PsiField) { + final PsiField field = (PsiField)target; + myUnusedFields.remove(field); + } + else if (target instanceof PsiMethod) { + final PsiMethod method = (PsiMethod)target; + if (usesReflection(method)) { + myUnusedFields.clear(); + myUnusedMethods.clear(); } - - // must have fields - PsiField[] fields = clazz.getFields(); - if (fields.length == 0) { - log.debug("Class does not have any fields"); - return; + else { + myUnusedMethods.remove(method); + final PsiField field = PropertyUtil.findPropertyFieldByMember(method); + myUnusedFields.remove(field); } - - // a toString method must exist - PsiMethod toStringMethod = PsiAdapter.findMethodByName(clazz, "toString"); - if (toStringMethod == null) { - log.debug("No toString() method"); - return; - } - - // a toString code block must exist - PsiCodeBlock code = toStringMethod.getBody(); - if (code == null) { - log.debug("No toString() code"); - return; - } - - // check if toString uses reflection if so exit - String body = code.getText(); - if (body.indexOf("getDeclaredFields()") != -1) { - log.debug("Using reflection"); - return; - } else if (body.indexOf("ReflectionToStringBuilder(this).toString()") != -1) { - log.debug("Using reflection (ReflectionToStringBuilder)"); - return; - } - - // get list of fields supposed to be dumped in the toString method - Project project = clazz.getProject(); - fields = GenerateToStringUtils.filterAvailableFields(clazz, GenerateToStringContext.getConfig().getFilterPattern()); - if (fields.length == 0) { - log.debug("No fields to be dumped as all fields was excluded (exclude field by XXX from Settings)"); - return; - } - - // toString exists and fields are supposed to be dumped - // check if any fields are missing (out of sync) - for (PsiField field : fields) { - final String fieldName = field.getName(); - if (log.isDebugEnabled()) log.debug("Evaluating if field " + fieldName + " is in toString() method"); - - // field must be enclosed with non words before and after the field to ensure the fieldname are dumped - String pattern = "(?s).*\\W" + StringUtil.escapeToRegexp(fieldName) + "[\\W&&[^=]].*"; - if (log.isDebugEnabled()) log.debug("Match pattern = " + pattern); - - // use regexp to match if field is used in code - if (!body.matches(pattern)) { - if (log.isDebugEnabled()) log.debug("Field is not used in toString() method (out-of-sync): " + field); - holder.registerProblem(field.getNameIdentifier(), "Field '" + fieldName + "' is not used in 'toString()' method", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix); - } - } - + } } - /** - * Checking for problems with fields. - * - * @param clazz the class to check - * @param holder a sink to feed the problem to - */ - private void checkMethods(ProblemsHolder holder, PsiClass clazz) { - if (log.isDebugEnabled()) log.debug("checkMethods: clazz=" + clazz); - - // must be a class - if (clazz == null || clazz.getName() == null) { - return; - } - - // must have 'Enable getters in code generation' set to true - if (! GenerateToStringContext.getConfig().isEnableMethods()) { - return; - } - - // a toString method must exist - PsiMethod toStringMethod = PsiAdapter.findMethodByName(clazz, "toString"); - if (toStringMethod == null) { - log.debug("No toString() method"); - return; - } - - // a toString code block must exist - PsiCodeBlock code = toStringMethod.getBody(); - if (code == null) { - log.debug("No toString() code"); - return; - } - - // check if toString uses reflection if so exit - String body = code.getText(); - if (body.contains("getDeclaredFields()")) { - log.debug("Using reflection"); - return; - } - - // must have methods - PsiMethod[] methods = clazz.getMethods(); - if (methods.length == 0) { - log.debug("Class does not have any methods"); - return; - } - - // get list of methods supposed to be dumped in the toString method - methods = GenerateToStringUtils.filterAvailableMethods(clazz, GenerateToStringContext.getConfig().getFilterPattern()); - if (methods.length == 0) { - log.debug("No getter methods to be dumped as all methods was excluded or a field existed for the getter method (exclude method by XXX from Settings)"); - return; - } - - // toString exists and methods are supposed to be dumped - // check if any methods are missing (out of sync) - for (PsiMethod method : methods) { - final String methodName = method.getName(); - if (log.isDebugEnabled()) log.debug("Evaluating if method " + methodName + " is in toString() method"); - - // method must be enclosed with non words before and after the method to ensure the fieldname are dumped - String pattern = "(?s).*\\W" + StringUtil.escapeToRegexp(methodName) + "[\\W&&[^=]].*"; - if (log.isDebugEnabled()) log.debug("Match pattern = " + pattern); - - // use regexp to match if method is used in code - if (!body.matches(pattern)) { - // method is not in toString - if (log.isDebugEnabled()) log.debug("Getter method is not used in toString() method (out-of-sync): " + method); - - final PsiIdentifier identifier = method.getNameIdentifier(); - final PsiElement target = identifier == null ? method : identifier; - holder.registerProblem(target, "Method '" + methodName + "' is not used in 'toString()' method", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, fix); - } - } - + private boolean usesReflection(PsiMethod method) { + @NonNls final String name = method.getName(); + final PsiClass containingClass = method.getContainingClass(); + if (containingClass == null) { + return false; + } + @NonNls final String qualifiedName = containingClass.getQualifiedName(); + if ("getDeclaredFields".equals(name)) { + return "java.lang.Class".equals(qualifiedName); + } + else if ("toString".equals(name)) { + return "org.apache.commons.lang.builder.ReflectionToStringBuilder".equals(qualifiedName) || + "java.util.Objects".equals(qualifiedName); + } + return false; } - -/* - public static void main(String[] args) { - // for testing regexp pattern - String me = "return \"DummyTestBean{\" +\n" + - " \", myNewString ='\" + myNewString + \"'\" +\n" + - " \"}\";"; - System.out.println("me = " + me); - System.out.println( me.matches("(?s).*\\WmyNewString[\\W*&&[^\\s*=]].*") ); + public THashSet getUnusedFields() { + return myUnusedFields; } -*/ + public THashSet getUnusedMethods() { + return myUnusedMethods; + } + } } diff --git a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/GenerateToStringQuickFix.java b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/GenerateToStringQuickFix.java index 982cd6d16953..47e5f63d599a 100644 --- a/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/GenerateToStringQuickFix.java +++ b/plugins/generate-tostring/src/org/jetbrains/generate/tostring/inspection/GenerateToStringQuickFix.java @@ -1,5 +1,5 @@ /* - * Copyright 2001-2012 the original author or authors. + * Copyright 2001-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,6 +29,16 @@ import org.jetbrains.generate.tostring.GenerateToStringActionHandlerImpl; */ public class GenerateToStringQuickFix implements LocalQuickFix { + public static final GenerateToStringQuickFix INSTANCE = new GenerateToStringQuickFix(); + + private final GenerateToStringActionHandler myHandler = new GenerateToStringActionHandlerImpl(); + + private GenerateToStringQuickFix() {} + + public static GenerateToStringQuickFix getInstance() { + return INSTANCE; + } + @NotNull public String getName() { return "Generate toString()"; @@ -40,15 +50,10 @@ public class GenerateToStringQuickFix implements LocalQuickFix { } public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor desc) { - - // find the class - PsiClass clazz = PsiTreeUtil.getParentOfType(desc.getPsiElement(), PsiClass.class); + final PsiClass clazz = PsiTreeUtil.getParentOfType(desc.getPsiElement(), PsiClass.class); if (clazz == null) { - return; // no class to fix, so return + return; // no class to fix } - - // execute the action - GenerateToStringActionHandler handler = new GenerateToStringActionHandlerImpl(); - handler.executeActionQuickFix(project, clazz); + myHandler.executeActionQuickFix(project, clazz); } } diff --git a/plugins/generate-tostring/testSrc/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspectionTest.java b/plugins/generate-tostring/testSrc/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspectionTest.java new file mode 100644 index 000000000000..0fbc07976950 --- /dev/null +++ b/plugins/generate-tostring/testSrc/org/jetbrains/generate/tostring/inspection/FieldNotUsedInToStringInspectionTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2013 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 org.jetbrains.generate.tostring.inspection; + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NonNls; + +/** + * @author Bas Leijdekkers + */ +public class FieldNotUsedInToStringInspectionTest extends LightCodeInsightFixtureTestCase { + + public void testBasic() { + doTest("class X {" + + " private int i = 0;" + + " public String toString() {" + + " return null;" + + " }" + + "}"); + } + + public void testGetterUsed() { + doTest("public class ToStringTest3 {" + + "" + + " int number;" + + "" + + " public int getNumber() {" + + " return number;" + + " }" + + "" + + " @Override" + + " public String toString() {" + + " final StringBuilder sb = new StringBuilder();" + + " sb.append(\"ToStringTest3\");" + + " sb.append(\"{number=\").append(getNumber());" + + " sb.append('}');" + + " return sb.toString();" + + " }" + + "}"); + } + + public void testReflectionUsed() { + myFixture.addClass("package java.util;" + + "public class Objects {" + + " public static String toString(Object object) {" + + " return null;" + + " }" + + "}"); + doTest("import java.util.Objects;" + + "class X {" + + " private int i = 0;" + + " " + + " public String toString() {" + + " return Objects.toString(this);" + + " }" + + "}"); + } + + private void doTest(@NonNls String text) { + myFixture.configureByText("X.java", text); + myFixture.enableInspections(new FieldNotUsedInToStringInspection()); + myFixture.testHighlighting(true, false, false); + } +} From 7cc0e89c20034705f9ee0a872f12c8996e78cd3d Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Sun, 20 Jan 2013 15:28:00 +0100 Subject: [PATCH 05/18] jbcolor.red --- .../codeInsight/lookup/impl/LookupCellRenderer.java | 9 ++++----- .../ui/components/panels/ValidatingComponent.java | 5 +++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java index 286bfb6af03c..24cda004f14c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -124,23 +124,22 @@ public class LookupCellRenderer implements ListCellRenderer { myIsSelected = isSelected; final LookupElement item = (LookupElement)value; - final boolean dark = UIUtil.isUnderDarcula(); final Color foreground = getForegroundColor(isSelected); - final Color background = isSelected ? SELECTED_BACKGROUND_COLOR : dark ? BACKGROUND_COLOR_DARK_VARIANT : BACKGROUND_COLOR; + final Color background = isSelected ? SELECTED_BACKGROUND_COLOR : new JBColor(BACKGROUND_COLOR, BACKGROUND_COLOR_DARK_VARIANT); int allowedWidth = list.getWidth() - AFTER_TAIL - AFTER_TYPE - getIconIndent(); final LookupElementPresentation presentation = new RealLookupElementPresentation(isSelected ? getMaxWidth() : allowedWidth, myNormalMetrics, myBoldMetrics, myLookup); if (item.isValid()) { item.renderElement(presentation); } else { - presentation.setItemTextForeground(Color.RED); + presentation.setItemTextForeground(JBColor.RED); presentation.setItemText("Invalid"); } myNameComponent.clear(); myNameComponent.setIcon(augmentIcon(presentation.getIcon(), myEmptyIcon)); myNameComponent.setBackground(background); - allowedWidth -= setItemTextLabel(item, dark ? foreground : isSelected ? SELECTED_FOREGROUND_COLOR : presentation.getItemTextForeground(), isSelected, presentation, allowedWidth); + allowedWidth -= setItemTextLabel(item, new JBColor(isSelected ? SELECTED_FOREGROUND_COLOR : presentation.getItemTextForeground(), foreground), isSelected, presentation, allowedWidth); myTypeLabel.clear(); if (allowedWidth > 0) { diff --git a/platform/platform-api/src/com/intellij/ui/components/panels/ValidatingComponent.java b/platform/platform-api/src/com/intellij/ui/components/panels/ValidatingComponent.java index 33ba62c1dc6f..3b779a15ce5e 100644 --- a/platform/platform-api/src/com/intellij/ui/components/panels/ValidatingComponent.java +++ b/platform/platform-api/src/com/intellij/ui/components/panels/ValidatingComponent.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -15,6 +15,7 @@ */ package com.intellij.ui.components.panels; +import com.intellij.ui.JBColor; import com.intellij.util.ui.UIUtil; import javax.swing.*; @@ -74,7 +75,7 @@ public abstract class ValidatingComponent extends NonOpaqu protected JLabel createErrorLabel() { final JLabel label = new JLabel(" "); - label.setForeground(Color.red); + label.setForeground(JBColor.red); label.setFont(ERROR_FONT); return label; } From b732464e00160012c535544d597c8bcfa6e47375 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Sun, 20 Jan 2013 15:29:29 +0100 Subject: [PATCH 06/18] live template customization --- .../codeInsight/template/impl/TemplateState.java | 14 +++++++++----- .../options/colors/pages/GeneralColorsPage.java | 3 ++- .../openapi/editor/colors/EditorColors.java | 3 ++- .../src/messages/OptionsBundle.properties | 3 ++- .../src/DefaultColorSchemesManager.xml | 8 ++++++++ 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 2781854470f6..a30b7c44ab24 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -35,10 +35,15 @@ import com.intellij.openapi.command.undo.DocumentReferenceManager; import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.*; +import com.intellij.openapi.editor.colors.EditorColors; +import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.event.DocumentAdapter; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.ex.DocumentEx; -import com.intellij.openapi.editor.markup.*; +import com.intellij.openapi.editor.markup.HighlighterLayer; +import com.intellij.openapi.editor.markup.HighlighterTargetArea; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; @@ -59,9 +64,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.*; import java.util.*; -import java.util.List; public class TemplateState implements Disposable { private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.template.impl.TemplateState"); @@ -969,7 +972,8 @@ public class TemplateState implements Disposable { } private RangeHighlighter getSegmentHighlighter(int segmentNumber, boolean isSelected, boolean isEnd) { - TextAttributes attributes = isSelected ? new TextAttributes(null, null, Color.red, EffectType.BOXED, Font.PLAIN) : new TextAttributes(); + final TextAttributes lvAttr = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.LIVE_TEMPLATE_ATTRIBUTES); + TextAttributes attributes = isSelected ? lvAttr : new TextAttributes(); TextAttributes endAttributes = new TextAttributes(); int start = mySegments.getSegmentStart(segmentNumber); diff --git a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java index 50e651ba9a38..b2bb141e9058 100644 --- a/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java +++ b/platform/lang-impl/src/com/intellij/openapi/options/colors/pages/GeneralColorsPage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -80,6 +80,7 @@ public class GeneralColorsPage implements ColorSettingsPage, InspectionColorSett new AttributesDescriptor(OptionsBundle.message("options.general.attribute.descriptior.identifier.under.caret.write"), EditorColors.WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES), new AttributesDescriptor(OptionsBundle.message("options.general.attribute.descriptor.text.search.result"), EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES), + new AttributesDescriptor(OptionsBundle.message("options.general.attribute.descriptor.live.template"), EditorColors.LIVE_TEMPLATE_ATTRIBUTES), new AttributesDescriptor(OptionsBundle.message("options.general.attribute.descriptor.template.variable"), TemplateColors.TEMPLATE_VARIABLE_ATTRIBUTES), new AttributesDescriptor(OptionsBundle.message("options.general.color.descriptor.injected.language.fragment"), EditorColors.INJECTED_LANGUAGE_FRAGMENT), diff --git a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java index a68b1ab19b0a..fe3242e47b44 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/colors/EditorColors.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 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. @@ -38,6 +38,7 @@ public interface EditorColors { TextAttributesKey REFERENCE_HYPERLINK_COLOR = TextAttributesKey.createTextAttributesKey("CTRL_CLICKABLE", new TextAttributes(JBColor.blue, null, JBColor.blue, EffectType.LINE_UNDERSCORE, 0)); TextAttributesKey SEARCH_RESULT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("SEARCH_RESULT_ATTRIBUTES"); + TextAttributesKey LIVE_TEMPLATE_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("LIVE_TEMPLATE_ATTRIBUTES"); TextAttributesKey WRITE_SEARCH_RESULT_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("WRITE_SEARCH_RESULT_ATTRIBUTES"); TextAttributesKey IDENTIFIER_UNDER_CARET_ATTRIBUTES = TextAttributesKey.createTextAttributesKey("IDENTIFIER_UNDER_CARET_ATTRIBUTES"); TextAttributesKey WRITE_IDENTIFIER_UNDER_CARET_ATTRIBUTES = diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties index c3c4cff26eb3..68a92243bd96 100644 --- a/platform/platform-resources-en/src/messages/OptionsBundle.properties +++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties @@ -229,4 +229,5 @@ color.settings.console.yellow=ANSI Yellow color.settings.console.blue=ANSI Blue color.settings.console.magenta=ANSI Magenta color.settings.console.cyan=ANSI Cyan -color.settings.console.gray=ANSI Gray \ No newline at end of file +color.settings.console.gray=ANSI Gray +options.general.attribute.descriptor.live.template=Live Template \ No newline at end of file diff --git a/platform/platform-resources/src/DefaultColorSchemesManager.xml b/platform/platform-resources/src/DefaultColorSchemesManager.xml index 74713cdd0eb8..d7819c5511e7 100644 --- a/platform/platform-resources/src/DefaultColorSchemesManager.xml +++ b/platform/platform-resources/src/DefaultColorSchemesManager.xml @@ -734,6 +734,14 @@ +