diff --git a/.idea/inspectionProfiles/idea_default.xml b/.idea/inspectionProfiles/idea_default.xml
index e3a1f1109e8f..3366d229b7d4 100644
--- a/.idea/inspectionProfiles/idea_default.xml
+++ b/.idea/inspectionProfiles/idea_default.xml
@@ -513,6 +513,9 @@
+
+
+
diff --git a/build/scripts/nsis_installer.gant b/build/scripts/nsis_installer.gant
new file mode 100644
index 000000000000..39795a6cf4b6
--- /dev/null
+++ b/build/scripts/nsis_installer.gant
@@ -0,0 +1,105 @@
+target(nsis: 'Build nsis windows installer') {
+ nsis_installer()
+}
+
+String p(String key) {
+ return getProperty(key)
+}
+
+def nsis_installer(pathsToInclude, stringsFile, pathsFile, outNamePrefix, includeToolsJar = true, associateIpr = true,
+ system_selector = getProperty("system_selector"), failOnSignError = false, outFileName = null,
+ boolean hasBundledJRE = false) {
+ // p.s: Groovy reevaluates default value of system_selector on each call, so it always uses actual property value.
+
+ if (outFileName == null) {
+ outFileName = "${outNamePrefix}${buildNumber}"
+ }
+
+ ant.taskdef(name: "nsis", classname: "com.intellij.internalUtilities.ant.NsiFiles", classpath: "${home}/community/build/lib/NsiFiles.jar")
+
+ def box = paths.sandbox
+ ant.mkdir(dir: "$box/bin")
+ ant.mkdir(dir: "$box/nsiconf")
+
+ if (!hasBundledJRE) {
+ ant.mkdir(dir: "$box/jre")
+ requireProperty("jdk_bundled_win", "1.7")
+ def jdk_bundled_version = p("jdk_bundled_win") == "1.8" ? "${home}/build/jdk/jdk8_redist.zip" : "${home}/build/jdk/jdk_redist.zip"
+ getBundledJDK(new File("${home}/build/jdk/win"), "jdk"+ p("jdk_bundled_win"), "x32.zip", jdk_bundled_version)
+ ant.unzip(dest: "$box/jre", src: "${jdk_bundled_version}")
+
+ ant.copy(todir: "$box/bin") {
+ fileset(dir: "$box/jre/jre/bin") {
+ include(name: "msvcr71.dll")
+ }
+ }
+ }
+
+ ant.copy(todir: "$box/nsiconf") {
+ fileset(dir: "$home/community/build/conf/nsis") {
+ include(name: "*")
+ exclude(name: "version*")
+ exclude(name: "strings*")
+ exclude(name: "paths*")
+ }
+ }
+
+ if (isEap()) {
+ ant.copy(file: "$home/community/build/conf/nsis/version.eap.nsi",
+ tofile: "$box/nsiconf/version.nsi", overwrite: true)
+ }
+ else {
+ ant.copy(file: "$home/community/build/conf/nsis/version.nsi",
+ tofile: "$box/nsiconf/version.nsi", overwrite: true)
+ }
+ ant.copy(file: pathsFile, toFile: "$box/nsiconf/paths.nsi", overwrite: true)
+
+ ant.nsis(instfile: "$box/nsiconf/idea_win.nsh", uninstfile: "$box/nsiconf/unidea_win.nsh") {
+ pathsToInclude.each {
+ fileset(dir: it, includes: "**/*") {
+ exclude(name: "**/idea.properties")
+ exclude(name: "**/*.vmoptions")
+ }
+ }
+ fileset(dir: box, includes: "bin/msvcr71.dll")
+ if (!hasBundledJRE) {
+ fileset(dir: box, includes: "jre/**/*")
+ if (includeToolsJar) {
+ fileset(dir: box) {
+ include(name: "jre/lib/tools.jar")
+ }
+ }
+ }
+ }
+
+ ant.replace(file: "$stringsFile") {
+ replacefilter(token: "__VERSION_MAJOR__", value: p("component.version.major"))
+ replacefilter(token: "__VERSION_MINOR__", value: p("component.version.minor"))
+ }
+ ant.copy(file: stringsFile, toFile: "$box/nsiconf/strings.nsi", overwrite: true)
+
+ ant.replace(file: "$box/nsiconf/version.nsi") {
+ replacefilter(token: "__BUILD_NUMBER__", value: buildNumber)
+ replacefilter(token: "__VERSION_MAJOR__", value: p("component.version.major"))
+ replacefilter(token: "__VERSION_MINOR__", value: p("component.version.minor"))
+ replacefilter(token: "__MIN_UPGRADE_BUILD__", value: p("component.install-over.minbuild"))
+ replacefilter(token: "__MAX_UPGRADE_BUILD__", value: p("component.install-over.maxbuild"))
+ replacefilter(token: "__UPGRADE_VERSION__", value: p("component.install-over.version"))
+ replacefilter(token: "__PRODUCT_PATHS_SELECTOR__", value: system_selector)
+ }
+
+ ant.unzip(src: "$home/build/tools/NSIS.zip", dest: box)
+ ant.exec(command: "$box/NSIS/makensis.exe" +
+ " /DBASE_DIR=\"$home\"" +
+ " /DCOMMUNITY_DIR=\"$home/community\"" +
+ " /DIPR=\"${associateIpr}\"" +
+ " /DOUT_FILE=\"${outFileName}\"" +
+ " /DOUT_DIR=\"$paths.artifacts\"" +
+ " $box/nsiconf/idea.nsi")
+
+ projectBuilder.stage("Signing binaries")
+ executeExternalAnt(["dirName": "${paths.artifacts}", "fileName": "${outFileName}.exe"], "$home/build/signBuild.xml")
+ projectBuilder.stage("Signing done")
+
+ return "${paths.artifacts}/${outFileName}.exe"
+}
diff --git a/build/scripts/utils.gant b/build/scripts/utils.gant
index 2ee16b096b45..c1549976e15e 100644
--- a/build/scripts/utils.gant
+++ b/build/scripts/utils.gant
@@ -754,17 +754,18 @@ private List getChildren(File file) {
return file.listFiles().sort { File f -> f.name.toLowerCase() }
}
-binding.setVariable("getCustomJDK", { File customJdkDir ->
- getChildren(customJdkDir).each {
- if (it.getName().endsWith(".tar.gz")) {
- def customJdkFileName = it.getAbsolutePath().substring(0, it.getAbsolutePath().length() - 3)
- if (new File(customJdkFileName).exists()){ ant.delete(file: customJdkFileName) }
- if (new File("${home}/build/jdk/custom_jdk_${buildNumber}.tar").exists()){
- ant.delete(file: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
+binding.setVariable("getBundledJDK", { File jdkDir, String prefix, String ext, String bundledJDKFileName ->
+ getChildren(jdkDir).each {
+ if (it.getName().startsWith(prefix) && it.getName().endsWith(ext)) {
+ if (new File(bundledJDKFileName).exists()) { ant.delete(file: bundledJDKFileName) }
+ def JdkFileName = it.getAbsolutePath()
+ if (ext == ".tar.gz") {
+ JdkFileName = JdkFileName.substring(0, JdkFileName.length() - 3)
+ if (new File(JdkFileName).exists()) { ant.delete(file: JdkFileName) }
+ ant.gunzip(src: it.getAbsolutePath())
}
- ant.gunzip(src: it.getAbsolutePath())
- projectBuilder.info("customJdkFileName: " + customJdkFileName)
- ant.copy(file: customJdkFileName, tofile: "${home}/build/jdk/custom_jdk_${buildNumber}.tar")
+ projectBuilder.info("JdkFileName: " + JdkFileName)
+ ant.copy(file: JdkFileName, tofile: bundledJDKFileName)
}
}
})
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
index 9c094e255ca9..9b9a45c70c4d 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * 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.
@@ -240,7 +240,14 @@ public class DebuggerManagerImpl extends DebuggerManagerEx implements Persistent
}
});
DebuggerSession session = new DebuggerSession(environment.getSessionName(), debugProcess);
- final ExecutionResult executionResult = session.attach(environment);
+ ExecutionResult executionResult;
+ try {
+ executionResult = session.attach(environment);
+ }
+ catch (ExecutionException e) {
+ session.dispose();
+ throw e;
+ }
if (executionResult == null) {
return null;
}
diff --git a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
index bc75c4f1359d..f98778128f5d 100644
--- a/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
+++ b/java/execution/impl/src/com/intellij/execution/JavaTestFrameworkRunnableState.java
@@ -45,6 +45,7 @@ import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.JavaPsiFacade;
@@ -195,6 +196,11 @@ public abstract class JavaTestFrameworkRunnableState & CommonJavaRunConfigurationParameters> extends SMTRunnerConsoleProperties {
@@ -48,6 +49,11 @@ public abstract class JavaAwareTestConsoleProperties getLocation(@NotNull String protocolId, @NotNull String locationData, Project project) {
List results = Collections.emptyList();
+ final int idx = locationData.indexOf("[");
+ final String paramName = idx >= 0 ? locationData.substring(idx) : null;
+ if (idx >= 0) {
+ locationData = locationData.substring(0, idx);
+ }
+
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
if (SUITE_PROTOCOL.equals(protocolId)) {
+ locationData = StringUtil.trimEnd(locationData, ".");
PsiClass[] classes = javaPsiFacade.findClasses(locationData, myScope);
if (classes.length > 0) {
results = ContainerUtil.newSmartList();
for (PsiClass aClass : classes) {
- results.add(new PsiLocation(project, aClass));
- }
- }
- else {
- //parameter root for parameterized tests: ClassName.[paramName]
- final String className = StringUtil.getPackageName(locationData);
- classes = javaPsiFacade.findClasses(className, myScope);
- if (classes.length > 0) {
- final String paramName = StringUtil.getShortName(locationData);
- results = ContainerUtil.newSmartList();
- for (PsiClass aClass : classes) {
- results.add(PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName));
- }
+ results.add(paramName != null ? PsiMemberParameterizedLocation.getParameterizedLocation(aClass, paramName)
+ : new PsiLocation(project, aClass));
}
}
}
@@ -80,18 +76,8 @@ public class JavaTestLocationProvider implements TestLocationProvider {
PsiMethod[] methods = aClass.findMethodsByName(methodName, true);
if (methods.length > 0) {
for (PsiMethod method : methods) {
- results.add(MethodLocation.elementInClass(method, aClass));
- }
- }
- else {
- //parameterized tests: ClassName.testName[paramName]
- final int paramIdx = methodName.indexOf("[");
- if (paramIdx > -1 && methodName.endsWith("]")) {
- final String paramName = methodName.substring(paramIdx);
- methods = aClass.findMethodsByName(methodName.substring(0, paramIdx), true);
- for (PsiMethod method : methods) {
- results.add(new PsiMemberParameterizedLocation(project, method, aClass, paramName));
- }
+ results.add(paramName != null ? new PsiMemberParameterizedLocation(project, method, aClass, paramName)
+ : MethodLocation.elementInClass(method, aClass));
}
}
}
diff --git a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
index c992d544a4e3..40206ba56b1e 100644
--- a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
+++ b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
@@ -82,7 +82,7 @@ public class ImportModuleAction extends AnAction {
}
public static List createFromWizard(@Nullable Project project, AbstractProjectWizard wizard) {
- if (project == null && wizard.getStepCount() > 0) {
+ if (project == null) {
Project newProject = NewProjectUtil.createFromWizard(wizard, null);
return newProject == null ? Collections.emptyList() : Arrays.asList(ModuleManager.getInstance(newProject).getModules());
}
@@ -94,7 +94,6 @@ public class ImportModuleAction extends AnAction {
return Collections.singletonList(module);
}
else {
- assert project != null;
return projectBuilder.commit(project);
}
}
diff --git a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java
index 0c41048c0db8..ae544ea419ed 100644
--- a/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java
+++ b/java/idea-ui/src/com/intellij/openapi/projectRoots/ui/SdkEditor.java
@@ -331,7 +331,9 @@ public class SdkEditor implements Configurable, Place.Navigator {
}
sdkModificator = dummySdk.getSdkModificator();
for (OrderRootType type : myPathEditors.keySet()) {
- myPathEditors.get(type).addPaths(sdkModificator.getRoots(type));
+ SdkPathEditor pathEditor = myPathEditors.get(type);
+ pathEditor.setAddBaseDir(dummySdk.getHomeDirectory());
+ pathEditor.addPaths(sdkModificator.getRoots(type));
}
mySdkModel.getMulticaster().sdkHomeSelected(dummySdk, homePath);
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
index 68a74f887f3f..8c3804d8a500 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java
@@ -53,7 +53,6 @@ import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import org.jdom.Element;
-import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -211,7 +210,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
}
}
- ContainerUtil.addIfNotNull(fixes, ReplaceOptionalOfWithOfNullableFix.registerReplaceOptionalOfWithOfNullableFix(qualifier));
+ ContainerUtil.addIfNotNull(fixes, DfaOptionalSupport.registerReplaceOptionalOfWithOfNullableFix(qualifier));
return fixes.isEmpty() ? null : fixes.toArray(new LocalQuickFix[fixes.size()]);
}
catch (IncorrectOperationException e) {
@@ -272,11 +271,29 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
reportNullableArgumentsPassedToNonAnnotated(visitor, holder, reportedAnchors);
}
+ reportOptionalOfNullableImprovements(holder, visitor, reportedAnchors);
+
+
if (REPORT_CONSTANT_REFERENCE_VALUES) {
reportConstantReferenceValues(holder, visitor, reportedAnchors);
}
}
+ private static void reportOptionalOfNullableImprovements(ProblemsHolder holder,
+ DataFlowInstructionVisitor visitor,
+ HashSet reportedAnchors) {
+ for (PsiElement expr : visitor.getProblems(NullabilityProblem.passingNullToOptional)) {
+ if (!reportedAnchors.add(expr)) continue;
+ holder.registerProblem(expr, "Passing null argument to Optional",
+ DfaOptionalSupport.createReplaceOptionalOfNullableWithEmptyFix(expr));
+ }
+ for (PsiElement expr : visitor.getProblems(NullabilityProblem.passingNotNullToOptional)) {
+ if (!reportedAnchors.add(expr)) continue;
+ holder.registerProblem(expr, "Passing a non-null argument to Optional",
+ DfaOptionalSupport.createReplaceOptionalOfNullableWithOfFix());
+ }
+ }
+
private static void reportConstantReferenceValues(ProblemsHolder holder, StandardInstructionVisitor visitor, Set reportedAnchors) {
for (Pair pair : visitor.getConstantReferenceValues()) {
PsiReferenceExpression ref = pair.first;
@@ -764,67 +781,4 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
boolean normalOk;
}
}
-
- private static class ReplaceOptionalOfWithOfNullableFix implements LocalQuickFix {
-
- private static final String GUAVA_OPTIONAL = "com.google.common.base.Optional";
- private final String myTargetMethodName;
-
- public ReplaceOptionalOfWithOfNullableFix(final String targetMethodName) {
- myTargetMethodName = targetMethodName;
- }
-
- private static LocalQuickFix registerReplaceOptionalOfWithOfNullableFix(PsiExpression qualifier) {
- final PsiElement argList = PsiUtil.skipParenthesizedExprUp(qualifier).getParent();
- if (argList instanceof PsiExpressionList) {
- final PsiElement parent = argList.getParent();
- if (parent instanceof PsiMethodCallExpression) {
- final PsiMethod method = ((PsiMethodCallExpression)parent).resolveMethod();
- if (method != null) {
- final PsiClass containingClass = method.getContainingClass();
- if ("of".equals(method.getName()) && containingClass != null) {
- final String qualifiedName = containingClass.getQualifiedName();
- if (CommonClassNames.JAVA_UTIL_OPTIONAL.equals(qualifiedName)) {
- return new ReplaceOptionalOfWithOfNullableFix("ofNullable");
- }
- else if (GUAVA_OPTIONAL.equals(qualifiedName)) {
- return new ReplaceOptionalOfWithOfNullableFix("fromNullable");
- }
- }
- }
- }
- }
- return null;
- }
-
- @Nls
- @NotNull
- @Override
- public String getName() {
- return getFamilyName();
- }
-
- @NotNull
- @Override
- public String getFamilyName() {
- return "Replace with '." + myTargetMethodName + "()'";
- }
-
- @Override
- public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
- final PsiMethodCallExpression
- methodCallExpression = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class);
- if (methodCallExpression != null) {
- final PsiElement ofNullableExprName =
- ((PsiMethodCallExpression)JavaPsiFacade.getElementFactory(project)
- .createExpressionFromText("Optional.ofNullable(null)", null)).getMethodExpression();
- final PsiElement referenceNameElement = methodCallExpression.getMethodExpression().getReferenceNameElement();
- if (referenceNameElement != null) {
- final PsiElement ofNullableNameElement = ((PsiReferenceExpression)ofNullableExprName).getReferenceNameElement();
- LOG.assertTrue(ofNullableNameElement != null);
- referenceNameElement.replace(ofNullableNameElement);
- }
- }
- }
- }
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaOptionalSupport.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaOptionalSupport.java
new file mode 100644
index 000000000000..12c0d3ca6f3f
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaOptionalSupport.java
@@ -0,0 +1,139 @@
+/*
+ * 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.codeInspection.dataFlow;
+
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author anet, peter
+ */
+class DfaOptionalSupport {
+ private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DfaOptionalSupport");
+ private static final String GUAVA_OPTIONAL = "com.google.common.base.Optional";
+
+ @Nullable
+ static LocalQuickFix registerReplaceOptionalOfWithOfNullableFix(@NotNull PsiExpression qualifier) {
+ final PsiElement call = findCallExpression(qualifier);
+ final PsiMethod method = call == null ? null : ((PsiMethodCallExpression)call).resolveMethod();
+ final PsiClass containingClass = method == null ? null : method.getContainingClass();
+ if (containingClass != null && "of".equals(method.getName())) {
+ final String qualifiedName = containingClass.getQualifiedName();
+ if (CommonClassNames.JAVA_UTIL_OPTIONAL.equals(qualifiedName)) {
+ return new ReplaceOptionalCallFix("ofNullable", false);
+ }
+ if (GUAVA_OPTIONAL.equals(qualifiedName)) {
+ return new ReplaceOptionalCallFix("fromNullable", false);
+ }
+ }
+ return null;
+ }
+
+ private static PsiMethodCallExpression findCallExpression(@NotNull PsiElement anchor) {
+ final PsiElement argList = PsiUtil.skipParenthesizedExprUp(anchor).getParent();
+ if (argList instanceof PsiExpressionList) {
+ final PsiElement parent = argList.getParent();
+ if (parent instanceof PsiMethodCallExpression) {
+ return (PsiMethodCallExpression)parent;
+ }
+ }
+ return null;
+ }
+ private static boolean isJdkOptional(@NotNull PsiElement anchor) {
+ final PsiElement parent = findCallExpression(anchor);
+ PsiMethod method = parent == null ? null : resolveOfNullable(findCallExpression(anchor));
+ return method != null && "ofNullable".equals(method.getName());
+ }
+
+ @NotNull
+ static LocalQuickFix createReplaceOptionalOfNullableWithEmptyFix(@NotNull PsiElement anchor) {
+ return new ReplaceOptionalCallFix(isJdkOptional(anchor) ? "empty" : "absent", true);
+ }
+
+ @NotNull
+ static LocalQuickFix createReplaceOptionalOfNullableWithOfFix() {
+ return new ReplaceOptionalCallFix("of", false);
+ }
+
+ @Nullable
+ static PsiMethod resolveOfNullable(PsiCallExpression expression) {
+ String name = ((PsiMethodCallExpression)expression).getMethodExpression().getReferenceName();
+ if ("ofNullable".equals(name) || "fromNullable".equals(name)) {
+ PsiMethod method = expression.resolveMethod();
+ PsiClass psiClass = method == null ? null : method.getContainingClass();
+ String qname = psiClass == null ? null : psiClass.getQualifiedName();
+ if (CommonClassNames.JAVA_UTIL_OPTIONAL.equals(qname) || GUAVA_OPTIONAL.equals(qname)) {
+ return method;
+ }
+ }
+ return null;
+ }
+
+ private static class ReplaceOptionalCallFix implements LocalQuickFix {
+ private final String myTargetMethodName;
+ private final boolean myClearArguments;
+
+ public ReplaceOptionalCallFix(final String targetMethodName, boolean clearArguments) {
+ myTargetMethodName = targetMethodName;
+ myClearArguments = clearArguments;
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getName() {
+ return getFamilyName();
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return "Replace with '." + myTargetMethodName + "()'";
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ final PsiMethodCallExpression
+ methodCallExpression = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiMethodCallExpression.class);
+ if (methodCallExpression != null) {
+ final PsiElement ofNullableExprName =
+ ((PsiMethodCallExpression)JavaPsiFacade.getElementFactory(project)
+ .createExpressionFromText("Optional." + myTargetMethodName + "(null)", null)).getMethodExpression();
+ final PsiElement referenceNameElement = methodCallExpression.getMethodExpression().getReferenceNameElement();
+ if (referenceNameElement != null) {
+ final PsiElement ofNullableNameElement = ((PsiReferenceExpression)ofNullableExprName).getReferenceNameElement();
+ LOG.assertTrue(ofNullableNameElement != null);
+ referenceNameElement.replace(ofNullableNameElement);
+ }
+ if (myClearArguments) {
+ PsiExpressionList argList = methodCallExpression.getArgumentList();
+ PsiExpression[] args = argList.getExpressions();
+ if (args.length > 0) {
+ argList.deleteChildRange(args[0], args[args.length - 1]);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java
index 8155149ed1ec..2810ffdb2e34 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullabilityProblem.java
@@ -11,4 +11,6 @@ public enum NullabilityProblem {
nullableReturn,
passingNullableToNotNullParameter,
passingNullableArgumentToNonAnnotatedParameter,
+ passingNullToOptional,
+ passingNotNullToOptional
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
index 898c744286bc..66893c0c0c1b 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
@@ -57,6 +57,15 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return callExpression != null ? DfaPsiUtil.getElementNullability(key.getResultType(), callExpression.resolveMethod()) : null;
}
};
+ @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
+ private final FactoryMap myOptionOfNullable = new FactoryMap() {
+ @Nullable
+ @Override
+ protected Boolean create(MethodCallInstruction key) {
+ PsiCallExpression expression = key.getCallExpression();
+ return expression instanceof PsiMethodCallExpression && DfaOptionalSupport.resolveOfNullable(expression) != null;
+ }
+ };
@Override
public DfaInstructionState[] visitAssign(AssignInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
@@ -231,6 +240,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
forceNotNull(runner, memState, arg);
}
}
+ else if (myOptionOfNullable.get(instruction)) {
+ checkNotNullable(memState, arg, NullabilityProblem.passingNotNullToOptional, expr);
+ checkNotNullable(memState, arg, NullabilityProblem.passingNullToOptional, expr);
+ }
else if (requiredNullability == Nullness.UNKNOWN) {
checkNotNullable(memState, arg, NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter, expr);
}
@@ -371,8 +384,14 @@ public class StandardInstructionVisitor extends InstructionVisitor {
protected boolean checkNotNullable(DfaMemoryState state,
DfaValue value, NullabilityProblem problem,
PsiElement anchor) {
+ if (problem == NullabilityProblem.passingNotNullToOptional) {
+ return !state.isNotNull(value);
+ }
+
boolean notNullable = state.checkNotNullable(value);
- if (notNullable && problem != NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter) {
+ if (notNullable &&
+ problem != NullabilityProblem.passingNullableArgumentToNonAnnotatedParameter &&
+ problem != NullabilityProblem.passingNullToOptional) {
DfaValueFactory factory = ((DfaMemoryStateImpl)state).getFactory();
state.applyCondition(factory.getRelationFactory().createRelation(value, factory.getConstFactory().getNull(), NE, false));
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java
index 63f50480bcfc..37a41a198182 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/java15api/Java15APIUsageInspectionBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * 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.
@@ -21,6 +21,7 @@ import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInspection.*;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
@@ -31,6 +32,7 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -43,7 +45,6 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashSet;
import gnu.trove.THashSet;
import org.jdom.Element;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -52,6 +53,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.ref.Reference;
+import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -107,16 +109,17 @@ public class Java15APIUsageInspectionBase extends BaseJavaBatchLocalInspectionTo
return result;
}
- private static void loadForbiddenApi(@NonNls String fileName, Set set) {
+ private static void loadForbiddenApi(String fileName, Set set) {
+ URL resource = Java15APIUsageInspectionBase.class.getResource(fileName);
+ if (resource == null) {
+ Logger.getInstance(Java15APIUsageInspectionBase.class).warn("not found: " + fileName);
+ return;
+ }
+
try {
- Class> aClass = Java15APIUsageInspectionBase.class;
- BufferedReader reader = new BufferedReader(new InputStreamReader(aClass.getResourceAsStream(fileName), CharsetToolkit.UTF8_CHARSET));
+ BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream(), CharsetToolkit.UTF8_CHARSET));
try {
- do {
- String line = reader.readLine();
- if (line == null) break;
- set.add(line);
- } while(true);
+ set.addAll(FileUtil.loadLines(reader));
}
finally {
reader.close();
@@ -330,6 +333,7 @@ public class Java15APIUsageInspectionBase extends BaseJavaBatchLocalInspectionTo
private void registerError(PsiJavaCodeReferenceElement reference, LanguageLevel api) {
if (reference != null && isInProject(reference)) {
+ //noinspection DialogTitleCapitalization
myHolder.registerProblem(reference, InspectionsBundle.message("inspection.1.5.problem.descriptor", getShortName(api)));
}
}
@@ -382,7 +386,7 @@ public class Java15APIUsageInspectionBase extends BaseJavaBatchLocalInspectionTo
}
/**
- * please leave public for {@link #com.intellij.codeInspection.JavaAPIUsagesInspectionTest#testCollectSinceApiUsages}
+ * please leave public for JavaAPIUsagesInspectionTest#testCollectSinceApiUsages
*/
@Nullable
public static String getSignature(@Nullable PsiMember member) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java
index e96eb36c6385..a6ee18c6e4a1 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaInheritorsGetter.java
@@ -160,20 +160,23 @@ public class JavaInheritorsGetter extends CompletionProvider()", parameters.getOriginalFile());
- final PsiVariable declaredVar = (PsiVariable)((PsiDeclarationStatement)statement).getDeclaredElements()[0];
- final PsiNewExpression initializer = (PsiNewExpression)declaredVar.getInitializer();
- final boolean hasDefaultConstructorOrNoGenericsOne = PsiDiamondTypeImpl.hasDefaultConstructor(psiClass) ||
- !PsiDiamondTypeImpl.haveConstructorsGenericsParameters(psiClass);
- if (hasDefaultConstructorOrNoGenericsOne) {
- final PsiDiamondTypeImpl.DiamondInferenceResult inferenceResult = PsiDiamondTypeImpl.resolveInferredTypes(initializer);
- if (inferenceResult.getErrorMessage() == null &&
- !psiClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
- areInferredTypesApplicable(inferenceResult.getTypes(), parameters.getPosition())) {
- psiType = initializer.getType();
+ try {
+ final PsiStatement statement = elementFactory
+ .createStatementFromText(canonicalText + " v = new " + erasedText + "<>()", parameters.getOriginalFile());
+ final PsiVariable declaredVar = (PsiVariable)((PsiDeclarationStatement)statement).getDeclaredElements()[0];
+ final PsiNewExpression initializer = (PsiNewExpression)declaredVar.getInitializer();
+ final boolean hasDefaultConstructorOrNoGenericsOne = PsiDiamondTypeImpl.hasDefaultConstructor(psiClass) ||
+ !PsiDiamondTypeImpl.haveConstructorsGenericsParameters(psiClass);
+ if (hasDefaultConstructorOrNoGenericsOne) {
+ final PsiDiamondTypeImpl.DiamondInferenceResult inferenceResult = PsiDiamondTypeImpl.resolveInferredTypes(initializer);
+ if (inferenceResult.getErrorMessage() == null &&
+ !psiClass.hasModifierProperty(PsiModifier.ABSTRACT) &&
+ areInferredTypesApplicable(inferenceResult.getTypes(), parameters.getPosition())) {
+ psiType = initializer.getType();
+ }
}
}
+ catch (IncorrectOperationException ignore) {}
}
}
final PsiTypeLookupItem item = PsiTypeLookupItem.createLookupItem(psiType, position);
diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java
index ce84d8a84dbc..11df0db74a8a 100644
--- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java
+++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureDialog.java
@@ -26,7 +26,6 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorFontType;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
-import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
@@ -226,7 +225,8 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase item = getRowItem(row);
@@ -249,12 +249,6 @@ public class JavaChangeSignatureDialog extends ChangeSignatureDialogBase1);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterGuavaNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterGuavaNullLiteral.java
new file mode 100644
index 000000000000..e5599f2a86b6
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterGuavaNullLiteral.java
@@ -0,0 +1,6 @@
+// "Replace with '.absent()'" "true"
+class A{
+ void test(){
+ com.google.common.base.Optional.absent();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullLiteral.java
new file mode 100644
index 000000000000..bfe725293c8b
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullLiteral.java
@@ -0,0 +1,6 @@
+// "Replace with '.of()'" "true"
+class A{
+ void test(){
+ java.util.Optional.of(11);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullVariable.java
new file mode 100644
index 000000000000..c1e85703be4b
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNotNullVariable.java
@@ -0,0 +1,8 @@
+// "Replace with '.of()'" "true"
+
+class A{
+ void test(String s){
+ assert s != null;
+ java.util.Optional.of(s);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullLiteral.java
new file mode 100644
index 000000000000..850a7c3df1c8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullLiteral.java
@@ -0,0 +1,7 @@
+// "Replace with '.empty()'" "true"
+class A {
+ void test() {
+ String s = null;
+ java.util.Optional.empty();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullVariable.java
new file mode 100644
index 000000000000..850a7c3df1c8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/afterNullVariable.java
@@ -0,0 +1,7 @@
+// "Replace with '.empty()'" "true"
+class A {
+ void test() {
+ String s = null;
+ java.util.Optional.empty();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNotNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNotNullLiteral.java
new file mode 100644
index 000000000000..8c7c9be02f35
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNotNullLiteral.java
@@ -0,0 +1,6 @@
+// "Replace with '.of()'" "true"
+class A{
+ void test(){
+ com.google.common.base.Optional.fromNullable(11);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNullLiteral.java
new file mode 100644
index 000000000000..fa25c555e2d0
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeGuavaNullLiteral.java
@@ -0,0 +1,6 @@
+// "Replace with '.absent()'" "true"
+class A{
+ void test(){
+ com.google.common.base.Optional.fromNullable(null);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullLiteral.java
new file mode 100644
index 000000000000..5ef9972f2ca8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullLiteral.java
@@ -0,0 +1,6 @@
+// "Replace with '.of()'" "true"
+class A{
+ void test(){
+ java.util.Optional.ofNullable(11);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullVariable.java
new file mode 100644
index 000000000000..53c9a43841f6
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNotNullVariable.java
@@ -0,0 +1,8 @@
+// "Replace with '.of()'" "true"
+
+class A{
+ void test(String s){
+ assert s != null;
+ java.util.Optional.ofNullable(s);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullLiteral.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullLiteral.java
new file mode 100644
index 000000000000..b57dda49a134
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullLiteral.java
@@ -0,0 +1,7 @@
+// "Replace with '.empty()'" "true"
+class A {
+ void test() {
+ String s = null;
+ java.util.Optional.ofNullable(null);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullVariable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullVariable.java
new file mode 100644
index 000000000000..5f6d350318ae
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeNullVariable.java
@@ -0,0 +1,7 @@
+// "Replace with '.empty()'" "true"
+class A {
+ void test() {
+ String s = null;
+ java.util.Optional.ofNullable(s);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeUnknown.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeUnknown.java
new file mode 100644
index 000000000000..6d506e8e8529
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable/beforeUnknown.java
@@ -0,0 +1,6 @@
+// "Replace with '.of()'" "false"
+class A{
+ void test(String s){
+ java.util.Optional.ofNullable(s);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/afterGuavaNullable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/afterGuavaNullable.java
new file mode 100644
index 000000000000..007fbb6d4e2a
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/afterGuavaNullable.java
@@ -0,0 +1,6 @@
+// "Replace with '.fromNullable()'" "true"
+class A{
+ void test(){
+ com.google.common.base.Optional.fromNullable(null);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/beforeGuavaNullable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/beforeGuavaNullable.java
new file mode 100644
index 000000000000..a438e6a82110
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable/beforeGuavaNullable.java
@@ -0,0 +1,6 @@
+// "Replace with '.fromNullable()'" "true"
+class A{
+ void test(){
+ com.google.common.base.Optional.of(null);
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceFromOfNullableFixTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceFromOfNullableFixTest.groovy
new file mode 100644
index 000000000000..15ef5ff77f14
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceFromOfNullableFixTest.groovy
@@ -0,0 +1,89 @@
+/*
+ * 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.daemon.quickFix
+import com.intellij.codeInspection.LocalInspectionTool
+import com.intellij.codeInspection.dataFlow.DataFlowInspection
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.command.WriteCommandAction
+import com.intellij.openapi.projectRoots.Sdk
+import com.intellij.openapi.vfs.VfsUtil
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.testFramework.IdeaTestUtil
+import org.jetbrains.annotations.NotNull
+
+public class ReplaceFromOfNullableFixTest extends LightQuickFixParameterizedTestCase {
+ @NotNull
+ @Override
+ protected LocalInspectionTool[] configureLocalInspectionTools() {
+ return [new DataFlowInspection()] as LocalInspectionTool[]
+ }
+
+ public void test() throws Exception {
+ doAllTests();
+ }
+
+ @Override
+ protected String getBasePath() {
+ return "/codeInsight/daemonCodeAnalyzer/quickFix/replaceFromOfNullable";
+ }
+
+ static void addGuavaOptional(Disposable parent) {
+ WriteCommandAction.runWriteCommandAction(project) {
+ VirtualFile optional = getSourceRoot()
+ .createChildDirectory(this, "com")
+ .createChildDirectory(this, "google")
+ .createChildDirectory(this, "common")
+ .createChildDirectory(this, "base")
+ .createChildData(this, "Optional.java");
+ VfsUtil.saveText(optional, """
+package com.google.common.base;
+public abstract class Optional {
+ public static Optional absent() { }
+
+ public static Optional of(@org.jetbrains.annotations.NotNull T reference) { }
+
+ public static Optional fromNullable(T nullableReference) { }
+}
+""")
+ }
+ }
+
+ static void cleanupGuava() {
+ WriteCommandAction.runWriteCommandAction(project) {
+ getSourceRoot().findChild("com")?.delete(this)
+ }
+ }
+
+ @Override
+ protected void beforeActionStarted(String testName, String contents) {
+ if (testName.contains("Guava")) {
+ addGuavaOptional(testRootDisposable)
+ }
+ super.beforeActionStarted(testName, contents)
+ }
+
+ @Override
+ protected void afterActionCompleted(String testName, String contents) {
+ cleanupGuava()
+ super.afterActionCompleted(testName, contents)
+ }
+
+ @Override
+ protected Sdk getProjectJDK() {
+ return IdeaTestUtil.getMockJdk18();
+ }
+}
\ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceWithOfNullableFixTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceWithOfNullableFixTest.java
index 6eef97352f65..9c5c07013b7e 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceWithOfNullableFixTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/quickFix/ReplaceWithOfNullableFixTest.java
@@ -42,6 +42,20 @@ public class ReplaceWithOfNullableFixTest extends LightQuickFixParameterizedTest
return "/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithOfNullable";
}
+ @Override
+ protected void beforeActionStarted(String testName, String contents) {
+ if (testName.contains("Guava")) {
+ ReplaceFromOfNullableFixTest.addGuavaOptional(myTestRootDisposable);
+ }
+ super.beforeActionStarted(testName, contents);
+ }
+
+ @Override
+ protected void afterActionCompleted(String testName, String contents) {
+ ReplaceFromOfNullableFixTest.cleanupGuava();
+ super.afterActionCompleted(testName, contents);
+ }
+
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java
index 674a0f8cbb50..c7664bd15bc8 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java
@@ -17,6 +17,9 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.completion.NormalCompletionDfaTest;
import com.intellij.codeInsight.completion.SmartTypeCompletionDfaTest;
+import com.intellij.codeInsight.daemon.quickFix.AddAssertStatementFixTest;
+import com.intellij.codeInsight.daemon.quickFix.ReplaceFromOfNullableFixTest;
+import com.intellij.codeInsight.daemon.quickFix.ReplaceWithOfNullableFixTest;
import com.intellij.slicer.SliceBackwardTest;
import com.intellij.slicer.SliceTreeTest;
import junit.framework.Test;
@@ -25,20 +28,29 @@ import junit.framework.TestSuite;
public class DataFlowInspectionTestSuite {
public static Test suite() {
TestSuite suite = new TestSuite();
+
suite.addTestSuite(DataFlowInspectionTest.class);
suite.addTestSuite(DataFlowInspection8Test.class);
suite.addTestSuite(DataFlowInspectionAncientTest.class);
suite.addTestSuite(ContractCheckTest.class);
+
suite.addTestSuite(ContractInferenceFromSourceTest.class);
suite.addTestSuite(NullityInferenceFromSourceTestCase.DfaInferenceTest.class);
suite.addTestSuite(NullityInferenceFromSourceTestCase.LightInferenceTest.class);
suite.addTestSuite(PurityInferenceFromSourceTest.class);
+
suite.addTestSuite(SliceTreeTest.class);
suite.addTestSuite(SliceBackwardTest.class);
+
suite.addTestSuite(SmartTypeCompletionDfaTest.class);
suite.addTestSuite(NormalCompletionDfaTest.class);
+
suite.addTestSuite(NullableStuffInspectionTest.class);
suite.addTestSuite(NullableStuffInspection14Test.class);
+
+ suite.addTestSuite(AddAssertStatementFixTest.class);
+ suite.addTestSuite(ReplaceWithOfNullableFixTest.class);
+ suite.addTestSuite(ReplaceFromOfNullableFixTest.class);
return suite;
}
}
diff --git a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java
index 73ddb14b4805..1bc6d3e6a92b 100644
--- a/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java
+++ b/java/java-tests/testSrc/com/intellij/execution/ConfigurationsTest.java
@@ -136,8 +136,9 @@ public class ConfigurationsTest extends BaseConfigurationTestCase {
JUnitConfiguration configuration = createConfiguration(testA);
JavaParameters parameters = checkCanRun(configuration);
CHECK.empty(parameters.getVMParametersList().getList());
+ final SegmentedOutputStream notifications = new SegmentedOutputStream(System.out);
assertTrue(JUnitStarter.checkVersion(parameters.getProgramParametersList().getArray(),
- new SegmentedOutputStream(System.out)));
+ new PrintStream(notifications)));
assertTrue(parameters.getProgramParametersList().getList().contains(testA.getQualifiedName()));
assertEquals(JUnitStarter.class.getName(), parameters.getMainClass());
assertEquals(myJdk.getHomeDirectory().getPresentableUrl(), parameters.getJdkPath());
diff --git a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
index e4d0bc039c5d..730ea6005104 100644
--- a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
+++ b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * 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.
@@ -18,7 +18,7 @@ package com.intellij.execution.configurations;
import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.ExecutionException;
-import com.intellij.execution.process.DefaultJavaProcessHandler;
+import com.intellij.execution.process.KillableColoredProcessHandler;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
@@ -101,7 +101,7 @@ public class JavaCommandLineTest extends LightIdeaTestCase {
public void testCreateProcess() {
try {
- new DefaultJavaProcessHandler(new GeneralCommandLine());
+ new KillableColoredProcessHandler(new GeneralCommandLine());
fail("ExecutionException (executable is not specified) expected");
}
catch (ExecutionException e) {
diff --git a/java/manifest/src/org/jetbrains/lang/manifest/highlighting/MissingFinalNewlineInspection.java b/java/manifest/src/org/jetbrains/lang/manifest/highlighting/MissingFinalNewlineInspection.java
index 7404b27de30f..60bfce5fd13c 100644
--- a/java/manifest/src/org/jetbrains/lang/manifest/highlighting/MissingFinalNewlineInspection.java
+++ b/java/manifest/src/org/jetbrains/lang/manifest/highlighting/MissingFinalNewlineInspection.java
@@ -61,16 +61,14 @@ public class MissingFinalNewlineInspection extends LocalInspectionTool {
return null;
}
- private static class AddNewlineQuickFix implements LocalQuickFix {
- private final Section mySection;
-
+ private static class AddNewlineQuickFix extends LocalQuickFixOnPsiElement {
private AddNewlineQuickFix(Section section) {
- mySection = section;
+ super(section);
}
@NotNull
@Override
- public String getName() {
+ public String getText() {
return ManifestBundle.message("inspection.newline.fix");
}
@@ -81,8 +79,8 @@ public class MissingFinalNewlineInspection extends LocalInspectionTool {
}
@Override
- public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
- PsiElement lastChild = mySection.getLastChild();
+ public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
+ PsiElement lastChild = startElement.getLastChild();
if (lastChild instanceof Header) {
lastChild.getNode().addLeaf(ManifestTokenType.NEWLINE, "\n", null);
}
diff --git a/java/manifest/test/org/jetbrains/lang/manifest/MissingFinalNewlineInspectionTest.java b/java/manifest/test/org/jetbrains/lang/manifest/MissingFinalNewlineInspectionTest.java
index a55b938145cb..d0b56a2fd6df 100644
--- a/java/manifest/test/org/jetbrains/lang/manifest/MissingFinalNewlineInspectionTest.java
+++ b/java/manifest/test/org/jetbrains/lang/manifest/MissingFinalNewlineInspectionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -17,7 +17,6 @@ package org.jetbrains.lang.manifest;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
-import junit.framework.Assert;
import org.jetbrains.lang.manifest.highlighting.MissingFinalNewlineInspection;
public class MissingFinalNewlineInspectionTest extends LightCodeInsightFixtureTestCase {
@@ -29,12 +28,12 @@ public class MissingFinalNewlineInspectionTest extends LightCodeInsightFixtureTe
public void testEmptyFile() {
myFixture.configureByText(ManifestFileTypeFactory.MANIFEST, "");
- Assert.assertEquals(0, myFixture.getAvailableIntentions().size());
+ assertEquals(0, myFixture.getAvailableIntentions().size());
}
public void testNoProblem() {
myFixture.configureByText(ManifestFileTypeFactory.MANIFEST, "Manifest-Version: 1.0\n");
- Assert.assertEquals(0, myFixture.getAvailableIntentions().size());
+ assertEquals(0, myFixture.getAvailableIntentions().size());
}
public void testFix() {
diff --git a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
index 2854c8a7132e..c468c0767697 100644
--- a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
+++ b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
@@ -54,7 +54,7 @@ public class JsonLiteralAnnotator implements Annotator {
final int length = text.length();
// Check that string literal is closed properly
- if (length <= 1 || text.charAt(0) != text.charAt(length - 1) || quoteEscaped(text, length - 1)) {
+ if (length <= 1 || text.charAt(0) != text.charAt(length - 1) || JsonPsiUtil.isEscapedChar(text, length - 1)) {
holder.createErrorAnnotation(element, JsonBundle.message("msg.missing.closing.quote"));
}
@@ -79,12 +79,4 @@ public class JsonLiteralAnnotator implements Annotator {
}
}
}
-
- private static boolean quoteEscaped(String text, int quotePos) {
- int count = 0;
- for (int i = quotePos - 1; i >= 0 && text.charAt(i) == '\\'; i--) {
- count++;
- }
- return count % 2 != 0;
- }
}
diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
index 58dab5945dfc..b4f7ffc2374d 100644
--- a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
+++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
@@ -6,9 +6,9 @@ import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.json.JsonBundle;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
+import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementVisitor;
@@ -139,13 +139,42 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool {
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement element = descriptor.getPsiElement();
+ final String rawText = element.getText();
if (element instanceof JsonLiteral || element instanceof JsonReferenceExpression) {
- final String content = StringUtil.stripQuotesAroundValue(element.getText());
- element.replace(new JsonElementGenerator(project).createStringLiteral(content));
+ String content = JsonPsiUtil.stripQuotes(rawText);
+ if (element instanceof JsonStringLiteral && rawText.startsWith("'")) {
+ content = escapeSingleQuotedStringContent(content);
+ }
+ // TODO: find out better way to replace element and skip reformatting step afterwards
+ final ASTNode replacement = new JsonElementGenerator(project).createValue("\"" + content + "\"").getNode();
+ element.getParent().getNode().replaceChild(element.getNode(), replacement);
}
else if (element != null) {
- LOG.error("Quick fix was applied to unexpected element", element.getText(), element.getParent().getText());
+ LOG.error("Quick fix was applied to unexpected element", rawText, element.getParent().getText());
}
}
+
+ @NotNull
+ private static String escapeSingleQuotedStringContent(@NotNull String content) {
+ final StringBuilder result = new StringBuilder();
+ boolean nextCharEscaped = false;
+ for (int i = 0; i < content.length(); i++) {
+ final char c = content.charAt(i);
+ if ((nextCharEscaped && c != '\'') || (!nextCharEscaped && c == '"')) {
+ result.append('\\');
+ }
+ if (c != '\\' || nextCharEscaped) {
+ result.append(c);
+ nextCharEscaped = false;
+ }
+ else {
+ nextCharEscaped = true;
+ }
+ }
+ if (nextCharEscaped) {
+ result.append('\\');
+ }
+ return result.toString();
+ }
}
}
diff --git a/json/src/com/intellij/json/formatter/JsonBlock.java b/json/src/com/intellij/json/formatter/JsonBlock.java
index c503c0df2290..174e1607f010 100644
--- a/json/src/com/intellij/json/formatter/JsonBlock.java
+++ b/json/src/com/intellij/json/formatter/JsonBlock.java
@@ -66,10 +66,10 @@ public class JsonBlock implements ASTBlock {
mySpacingBuilder = JsonFormattingBuilderModel.createSpacingBuilder(settings);
if (myPsiElement instanceof JsonObject) {
- myChildWrap = Wrap.createWrap(getCustomSettings().OBJECT_WRAPPING, false);
+ myChildWrap = Wrap.createWrap(getCustomSettings().OBJECT_WRAPPING, true);
}
else if (myPsiElement instanceof JsonArray) {
- myChildWrap = Wrap.createWrap(getCustomSettings().ARRAY_WRAPPING, false);
+ myChildWrap = Wrap.createWrap(getCustomSettings().ARRAY_WRAPPING, true);
}
else {
myChildWrap = null;
@@ -113,7 +113,10 @@ public class JsonBlock implements ASTBlock {
final JsonCodeStyleSettings customSettings = getCustomSettings();
if (hasElementType(myNode, JSON_CONTAINERS)) {
- if (!hasElementType(childNode, COMMA) && !hasElementType(childNode, JSON_ALL_BRACES)) {
+ if (hasElementType(childNode, COMMA)) {
+ wrap = Wrap.createWrap(WrapType.NONE, true);
+ }
+ else if (!hasElementType(childNode, JSON_ALL_BRACES)) {
assert myChildWrap != null;
wrap = myChildWrap;
indent = Indent.getNormalIndent();
diff --git a/json/src/com/intellij/json/psi/JsonPsiUtil.java b/json/src/com/intellij/json/psi/JsonPsiUtil.java
index 66f785c0e76b..80105014aa39 100644
--- a/json/src/com/intellij/json/psi/JsonPsiUtil.java
+++ b/json/src/com/intellij/json/psi/JsonPsiUtil.java
@@ -137,4 +137,46 @@ public class JsonPsiUtil {
return element.getText();
}
}
+
+ /**
+ * Returns content of the string literal (without escaping) striving to preserve as much of user data as possible.
+ *
+ *
If literal length is greater than one and it starts and ends with the same quote and the last quote is not escaped, returns
+ * text without first and last characters.
+ *
Otherwise if literal still begins with a quote, returns text without first character only.
+ *
Returns unmodified text in all other cases.
+ *
+ *
+ * @param text presumably result of {@link JsonStringLiteral#getText()}
+ * @return
+ */
+ @NotNull
+ public static String stripQuotes(@NotNull String text) {
+ if (text.length() > 0) {
+ final char firstChar = text.charAt(0);
+ final char lastChar = text.charAt(text.length() - 1);
+ if (firstChar == '\'' || firstChar == '"') {
+ if (text.length() > 1 && firstChar == lastChar && !isEscapedChar(text, text.length() - 1)) {
+ return text.substring(1, text.length() - 1);
+ }
+ return text.substring(1);
+ }
+ }
+ return text;
+ }
+
+ /**
+ * Checks that character in given position is escaped with backslashes.
+ *
+ * @param text text character belongs to
+ * @param position position of the character
+ * @return whether character at given position is escaped, i.e. preceded by odd number of backslashes
+ */
+ public static boolean isEscapedChar(@NotNull String text, int position) {
+ int count = 0;
+ for (int i = position - 1; i >= 0 && text.charAt(i) == '\\'; i--) {
+ count++;
+ }
+ return count % 2 != 0;
+ }
}
diff --git a/json/src/com/intellij/json/psi/impl/JsonPsiImplUtils.java b/json/src/com/intellij/json/psi/impl/JsonPsiImplUtils.java
index 59a112103398..d3814dc6c498 100644
--- a/json/src/com/intellij/json/psi/impl/JsonPsiImplUtils.java
+++ b/json/src/com/intellij/json/psi/impl/JsonPsiImplUtils.java
@@ -28,7 +28,7 @@ public class JsonPsiImplUtils {
@NotNull
public static String getName(@NotNull JsonProperty property) {
- return StringUtil.stripQuotesAroundValue(property.getNameElement().getText());
+ return StringUtil.unescapeStringCharacters(JsonPsiUtil.stripQuotes(property.getNameElement().getText()));
}
/**
@@ -210,7 +210,7 @@ public class JsonPsiImplUtils {
@NotNull
public static String getValue(@NotNull JsonStringLiteral literal) {
- return StringUtil.unescapeStringCharacters(StringUtil.unquoteString(literal.getText()));
+ return StringUtil.unescapeStringCharacters(JsonPsiUtil.stripQuotes(literal.getText()));
}
public static boolean getValue(@NotNull JsonBooleanLiteral literal) {
diff --git a/json/tests/test/com/intellij/json/JsonFormattingTest.java b/json/tests/test/com/intellij/json/JsonFormattingTest.java
index ff2b8a915eaf..f8d8d55f0691 100644
--- a/json/tests/test/com/intellij/json/JsonFormattingTest.java
+++ b/json/tests/test/com/intellij/json/JsonFormattingTest.java
@@ -101,6 +101,16 @@ public class JsonFormattingTest extends FormatterTestCase {
});
}
+ // IDEA-138902
+ public void testObjectsWithSingleProperty() throws Exception {
+ withPreservedSettings(new ThrowableRunnable() {
+ @Override
+ public void run() throws Exception {
+ doTest();
+ }
+ });
+ }
+
// Moved from JavaScript
public void testWeb3830() throws Exception {
diff --git a/json/tests/test/com/intellij/json/JsonQuickFixTest.java b/json/tests/test/com/intellij/json/JsonQuickFixTest.java
index 8a80967b4da7..92d4cc4bb175 100644
--- a/json/tests/test/com/intellij/json/JsonQuickFixTest.java
+++ b/json/tests/test/com/intellij/json/JsonQuickFixTest.java
@@ -27,8 +27,10 @@ public class JsonQuickFixTest extends JsonTestCase {
checkWrapInDoubleQuotes("{42: false}", "{\"42\": false}");
checkWrapInDoubleQuotes("{foo: false}", "{\"foo\": false}");
checkWrapInDoubleQuotes("{'foo': false}", "{\"foo\": false}");
+ checkWrapInDoubleQuotes("'foo\\\"", "\"foo\\\"\"");
checkWrapInDoubleQuotes("{\"foo\": bar}", "{\"foo\": \"bar\"}");
checkWrapInDoubleQuotes("{\"foo\": 'bar'}", "{\"foo\": \"bar\"}");
+ checkWrapInDoubleQuotes("'foo\\n\\'\"\\\\\\\"bar", "\"foo\\n'\\\"\\\\\\\"bar\"");
}
private void checkWrapInDoubleQuotes(@NotNull String before, @NotNull String after) {
diff --git a/json/tests/testData/formatting/ObjectsWithSingleProperty.json b/json/tests/testData/formatting/ObjectsWithSingleProperty.json
new file mode 100644
index 000000000000..a75a8d3af061
--- /dev/null
+++ b/json/tests/testData/formatting/ObjectsWithSingleProperty.json
@@ -0,0 +1 @@
+{"level0": {"level1": {"level2": "someValue"}}}
\ No newline at end of file
diff --git a/json/tests/testData/formatting/ObjectsWithSingleProperty_after.json b/json/tests/testData/formatting/ObjectsWithSingleProperty_after.json
new file mode 100644
index 000000000000..fe42890beca0
--- /dev/null
+++ b/json/tests/testData/formatting/ObjectsWithSingleProperty_after.json
@@ -0,0 +1,7 @@
+{
+ "level0": {
+ "level1": {
+ "level2": "someValue"
+ }
+ }
+}
\ No newline at end of file
diff --git a/json/tests/testData/formatting/Wrapping_after.json b/json/tests/testData/formatting/Wrapping_after.json
index f6f41b61f43b..e53138a182de 100644
--- a/json/tests/testData/formatting/Wrapping_after.json
+++ b/json/tests/testData/formatting/Wrapping_after.json
@@ -8,5 +8,7 @@
5,
6,
7,
- ["this line is long too"]
+ [
+ "this line is long too"
+ ]
]
\ No newline at end of file
diff --git a/json/tests/testData/surround/SingleValue_after.json b/json/tests/testData/surround/SingleValue_after.json
index 440c9ce72ee7..876ab8e46e66 100644
--- a/json/tests/testData/surround/SingleValue_after.json
+++ b/json/tests/testData/surround/SingleValue_after.json
@@ -1,3 +1,5 @@
{
- "property": [null]
+ "property": [
+ null
+ ]
}
\ No newline at end of file
diff --git a/platform/core-api/src/com/intellij/lang/FCTSBackedLighterAST.java b/platform/core-api/src/com/intellij/lang/FCTSBackedLighterAST.java
index dc241b519872..33151bba0359 100644
--- a/platform/core-api/src/com/intellij/lang/FCTSBackedLighterAST.java
+++ b/platform/core-api/src/com/intellij/lang/FCTSBackedLighterAST.java
@@ -21,6 +21,7 @@ import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.diff.FlyweightCapableTreeStructure;
import org.jetbrains.annotations.NotNull;
+import java.util.AbstractList;
import java.util.List;
public class FCTSBackedLighterAST extends LighterAST {
@@ -53,6 +54,38 @@ public class FCTSBackedLighterAST extends LighterAST {
}
LighterASTNode[] elements = into.get();
assert elements != null : myTreeStructure +" ("+parent+")";
- return ContainerUtil.newArrayList(elements, 0, numKids);
+ return new LighterASTNodeList(numKids, elements);
+ }
+
+ public void disposeChildren(@NotNull List children) {
+ if (children instanceof LighterASTNodeList) {
+ LighterASTNodeList nodes = (LighterASTNodeList)children;
+
+ myTreeStructure.disposeChildren(nodes.myElements, nodes.mySize);
+ } else {
+ LighterASTNode[] astNodes = new LighterASTNode[children.size()];
+ myTreeStructure.disposeChildren(children.toArray(astNodes), astNodes.length);
+ }
+ }
+
+ private static class LighterASTNodeList extends AbstractList {
+ private final int mySize;
+ private final LighterASTNode[] myElements;
+
+ public LighterASTNodeList(int size, LighterASTNode[] elements) {
+ mySize = size;
+ myElements = elements;
+ }
+
+ @Override
+ public LighterASTNode get(final int index) {
+ if (index < 0 || index >= mySize) throw new IndexOutOfBoundsException("index:" + index + " size:" + mySize);
+ return myElements[index];
+ }
+
+ @Override
+ public int size() {
+ return mySize;
+ }
}
}
diff --git a/platform/core-api/src/com/intellij/lang/LighterAST.java b/platform/core-api/src/com/intellij/lang/LighterAST.java
index 73bedde677e9..7d60edca0591 100644
--- a/platform/core-api/src/com/intellij/lang/LighterAST.java
+++ b/platform/core-api/src/com/intellij/lang/LighterAST.java
@@ -44,4 +44,6 @@ public abstract class LighterAST {
@NotNull
public abstract List getChildren(@NotNull final LighterASTNode parent);
+
+ public abstract void disposeChildren(@NotNull List children);
}
\ No newline at end of file
diff --git a/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java b/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java
index 8bfbd3c5da36..277e98650305 100644
--- a/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java
+++ b/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java
@@ -45,9 +45,8 @@ public class TreeBackedLighterAST extends LighterAST {
@Override
public List getChildren(@NotNull final LighterASTNode parent) {
final ASTNode[] children = ((NodeWrapper)parent).myNode.getChildren(null);
- if (children == null || children.length == 0) {
- return ContainerUtil.emptyList();
- }
+ if (children.length == 0) return ContainerUtil.emptyList();
+
List result = new ArrayList(children.length);
for (final ASTNode child : children) {
result.add(wrap(child));
@@ -55,6 +54,9 @@ public class TreeBackedLighterAST extends LighterAST {
return result;
}
+ public void disposeChildren(@NotNull List children) {
+ }
+
@NotNull
private static LighterASTNode wrap(@NotNull ASTNode node) {
return node.getFirstChildNode() == null && node.getTextLength() > 0 ? new TokenNodeWrapper(node) : new NodeWrapper(node);
diff --git a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
index a247bedf51e2..0959b4e3f4c0 100644
--- a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
+++ b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
@@ -19,6 +19,8 @@ import com.intellij.lang.ASTNode;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.PossiblyDumbAware;
import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.registry.RegistryValue;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Stack;
@@ -38,7 +40,7 @@ import java.util.Set;
public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements PossiblyDumbAware {
private CustomFoldingProvider myDefaultProvider;
- private static final int MAX_LOOKUP_DEPTH = 10;
+ private final RegistryValue myMaxLookupDepth = Registry.get("custom.folding.max.lookup.depth");
private static final ThreadLocal> ourCustomRegionElements = new ThreadLocal>();
@NotNull
@@ -103,7 +105,7 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements P
}
}
else {
- if (currDepth < MAX_LOOKUP_DEPTH) {
+ if (currDepth < myMaxLookupDepth.asInteger()) {
addCustomFoldingRegionsRecursively(localFoldingStack, child, descriptors, currDepth + 1);
}
}
diff --git a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
index 90c243c6a947..b9a0330c90e3 100644
--- a/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
+++ b/platform/core-impl/src/com/intellij/openapi/application/impl/ApplicationInfoImpl.java
@@ -210,7 +210,7 @@ public class ApplicationInfoImpl extends ApplicationInfoEx implements JDOMExtern
@Override
public String getApiVersion() {
if (myApiVersion != null) {
- return BuildNumber.fromString(myApiVersion, getProductPrefix()).asString();
+ return BuildNumber.fromString(myApiVersion, getBuild().getProductCode()).asString();
}
return getBuild().asString();
}
diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java
index 761a7ce8467f..f81a25c9b238 100644
--- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java
+++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleDiffViewer.java
@@ -411,12 +411,19 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
return true;
}
- private void doScrollToChange(@NotNull SimpleDiffChange change, boolean animated) {
+ private void doScrollToChange(@NotNull SimpleDiffChange change, final boolean animated) {
if (myEditor1 == null || myEditor2 == null) return;
+ assert mySyncScrollSupport != null;
- EditorEx editor = getCurrentEditor();
- int line = change.getStartLine(getCurrentSide());
- DiffUtil.scrollEditor(editor, line, animated);
+ final int line1 = change.getStartLine(Side.LEFT);
+ final int line2 = change.getStartLine(Side.RIGHT);
+ final int endLine1 = change.getEndLine(Side.LEFT);
+ final int endLine2 = change.getEndLine(Side.RIGHT);
+
+ DiffUtil.moveCaret(myEditor1, line1);
+ DiffUtil.moveCaret(myEditor2, line2);
+
+ mySyncScrollSupport.makeVisible(getCurrentSide(), line1, endLine1, line2, endLine2, animated);
}
@Override
diff --git a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java
index 64e54c98258b..1471ad397d33 100644
--- a/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java
+++ b/platform/diff-impl/src/com/intellij/diff/tools/simple/SimpleThreesideDiffViewer.java
@@ -346,6 +346,7 @@ public class SimpleThreesideDiffViewer extends ThreesideTextDiffViewer {
}
private void doScrollToChange(@NotNull SimpleThreesideDiffChange change, boolean animated) {
+ // TODO: use anchors to fix scrolling issue at the start/end of file
EditorEx editor = getCurrentEditor();
int line = change.getStartLine(getCurrentSide());
DiffUtil.scrollEditor(editor, line, animated);
diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java b/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java
index 68788e3b9030..3ae8591b103e 100644
--- a/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java
+++ b/platform/diff-impl/src/com/intellij/diff/tools/util/SyncScrollSupport.java
@@ -15,15 +15,18 @@
*/
package com.intellij.diff.tools.util;
+import com.intellij.diff.util.IntPair;
import com.intellij.diff.util.Side;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.ScrollingModel;
import com.intellij.openapi.editor.event.VisibleAreaEvent;
import com.intellij.openapi.editor.event.VisibleAreaListener;
+import com.intellij.openapi.editor.ex.EditorEx;
import gnu.trove.TIntFunction;
import org.jetbrains.annotations.CalledInAwt;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -82,6 +85,51 @@ public class SyncScrollSupport {
public boolean isDuringSyncScroll() {
return myDuringSyncScroll;
}
+
+ public void makeVisible(@NotNull Side masterSide,
+ int startLine1, int endLine1, int startLine2, int endLine2,
+ final boolean animate) {
+ Side slaveSide = masterSide.other();
+
+ final IntPair offsets = getTargetOffsets(myEditor1, myEditor2, startLine1, endLine1, startLine2, endLine2);
+
+ final Editor masterEditor = masterSide.select(myEditor1, myEditor2);
+ final Editor slaveEditor = slaveSide.select(myEditor1, myEditor2);
+
+ final int masterOffset = masterSide.select(offsets.val1, offsets.val2);
+ final int slaveOffset = slaveSide.select(offsets.val1, offsets.val2);
+
+ int startOffset1 = myEditor1.getScrollingModel().getVisibleArea().y;
+ int startOffset2 = myEditor2.getScrollingModel().getVisibleArea().y;
+ final int masterStartOffset = masterSide.select(startOffset1, startOffset2);
+
+ myHelper1.setAnchor(startOffset1, offsets.val1, startOffset2, offsets.val2);
+ myHelper2.setAnchor(startOffset2, offsets.val2, startOffset1, offsets.val1);
+
+ doScrollHorizontally(masterEditor, 0, false); // animation will be canceled by "scroll vertically" anyway
+ doScrollVertically(masterEditor, masterOffset, animate);
+
+ masterEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
+ @Override
+ public void run() {
+ myHelper1.removeAnchor();
+ myHelper2.removeAnchor();
+
+ if (masterOffset == masterStartOffset) { // master editor didn't scrolled
+ myDuringSyncScroll = true;
+
+ doScrollVertically(slaveEditor, slaveOffset, animate);
+
+ slaveEditor.getScrollingModel().runActionOnScrollingFinished(new Runnable() {
+ @Override
+ public void run() {
+ myDuringSyncScroll = false;
+ }
+ });
+ }
+ }
+ });
+ }
}
public static class ThreesideSyncScrollSupport {
@@ -157,78 +205,150 @@ public class SyncScrollSupport {
private static class MyScrollHelper implements VisibleAreaListener {
@NotNull private final Editor myMaster;
@NotNull private final Editor mySlave;
-
@NotNull private final TIntFunction myConvertor;
+ @Nullable private Anchor myAnchor;
+
public MyScrollHelper(@NotNull Editor master, @NotNull Editor slave, @NotNull TIntFunction convertor) {
myMaster = master;
mySlave = slave;
myConvertor = convertor;
}
+ public void setAnchor(int masterStartOffset, int masterEndOffset, int slaveStartOffset, int slaveEndOffset) {
+ myAnchor = new Anchor(masterStartOffset, masterEndOffset, slaveStartOffset, slaveEndOffset);
+ }
+
+ public void removeAnchor() {
+ myAnchor = null;
+ }
+
@Override
public void visibleAreaChanged(VisibleAreaEvent e) {
Rectangle newRectangle = e.getNewRectangle();
Rectangle oldRectangle = e.getOldRectangle();
if (oldRectangle == null) return;
- syncVerticalScroll(newRectangle, oldRectangle);
- syncHorizontalScroll(newRectangle, oldRectangle);
+ if (newRectangle.x != oldRectangle.x) syncHorizontalScroll(false);
+ if (newRectangle.y != oldRectangle.y) syncVerticalScroll(false);
}
- private void syncVerticalScroll(@NotNull Rectangle newRectangle, @NotNull Rectangle oldRectangle) {
- if (newRectangle.y == oldRectangle.y) return;
-
+ private void syncVerticalScroll(boolean animated) {
if (myMaster.getDocument().getTextLength() == 0) return;
- int masterVerticalScrollOffset = myMaster.getScrollingModel().getVerticalScrollOffset();
-
Rectangle viewRect = myMaster.getScrollingModel().getVisibleArea();
int middleY = viewRect.height / 3;
- LogicalPosition masterPos = myMaster.xyToLogicalPosition(new Point(viewRect.x, masterVerticalScrollOffset + middleY));
- int masterCenterLine = masterPos.line;
- int scrollToLine = myConvertor.execute(masterCenterLine);
+ int offset;
+ if (myAnchor == null) {
+ LogicalPosition masterPos = myMaster.xyToLogicalPosition(new Point(viewRect.x, viewRect.y + middleY));
+ int masterCenterLine = masterPos.line;
+ int convertedCenterLine = myConvertor.execute(masterCenterLine);
- int correction = (masterVerticalScrollOffset + middleY) % myMaster.getLineHeight();
- Point point = mySlave.logicalPositionToXY(new LogicalPosition(scrollToLine, masterPos.column));
- int offset = point.y - middleY + correction;
+ Point point = mySlave.logicalPositionToXY(new LogicalPosition(convertedCenterLine, masterPos.column));
+ int correction = (viewRect.y + middleY) % myMaster.getLineHeight();
+ offset = point.y - middleY + correction;
+ }
+ else {
+ double progress = myAnchor.masterStartOffset == myAnchor.masterEndOffset || viewRect.y == myAnchor.masterEndOffset ? 1 :
+ ((double)(viewRect.y - myAnchor.masterStartOffset)) / (myAnchor.masterEndOffset - myAnchor.masterStartOffset);
+
+ offset = myAnchor.slaveStartOffset + (int)((myAnchor.slaveEndOffset - myAnchor.slaveStartOffset) * progress);
+ }
int deltaHeaderOffset = getHeaderOffset(mySlave) - getHeaderOffset(myMaster);
- doScrollVertically(mySlave.getScrollingModel(), offset + deltaHeaderOffset);
+ doScrollVertically(mySlave, offset + deltaHeaderOffset, animated);
}
- private void syncHorizontalScroll(@NotNull Rectangle newRectangle, @NotNull Rectangle oldRectangle) {
- if (newRectangle.x == oldRectangle.x) return;
-
- int offset = newRectangle.x;
-
- doScrollHorizontally(mySlave.getScrollingModel(), offset);
+ private void syncHorizontalScroll(boolean animated) {
+ int offset = myMaster.getScrollingModel().getVisibleArea().x;
+ doScrollHorizontally(mySlave, offset, animated);
}
}
- private static void doScrollVertically(@NotNull ScrollingModel model, int offset) {
- model.disableAnimation();
- try {
- model.scrollVertically(offset);
- }
- finally {
- model.enableAnimation();
- }
+ private static void doScrollVertically(@NotNull Editor editor, int offset, boolean animated) {
+ ScrollingModel model = editor.getScrollingModel();
+ if (!animated) model.disableAnimation();
+ model.scrollVertically(offset);
+ if (!animated) model.enableAnimation();
}
- private static void doScrollHorizontally(@NotNull ScrollingModel model, int offset) {
- model.disableAnimation();
- try {
- model.scrollHorizontally(offset);
- }
- finally {
- model.enableAnimation();
- }
+ private static void doScrollHorizontally(@NotNull Editor editor, int offset, boolean animated) {
+ ScrollingModel model = editor.getScrollingModel();
+ if (!animated) model.disableAnimation();
+ model.scrollHorizontally(offset);
+ if (!animated) model.enableAnimation();
}
private static int getHeaderOffset(@NotNull final Editor editor) {
final JComponent header = editor.getHeaderComponent();
return header == null ? 0 : header.getHeight();
}
+
+ @NotNull
+ private static IntPair getTargetOffsets(@NotNull Editor editor1, @NotNull Editor editor2,
+ int startLine1, int endLine1, int startLine2, int endLine2) {
+ int topOffset1 = editor1.logicalPositionToXY(new LogicalPosition(startLine1, 0)).y;
+ int bottomOffset1 = editor1.logicalPositionToXY(new LogicalPosition(endLine1 + 1, 0)).y;
+ int topOffset2 = editor2.logicalPositionToXY(new LogicalPosition(startLine2, 0)).y;
+ int bottomOffset2 = editor2.logicalPositionToXY(new LogicalPosition(endLine2 + 1, 0)).y;
+
+ int rangeHeight1 = bottomOffset1 - topOffset1;
+ int rangeHeight2 = bottomOffset2 - topOffset2;
+
+ int gapLines1 = 2 * editor1.getLineHeight();
+ int gapLines2 = 2 * editor2.getLineHeight();
+
+ int editorHeight1 = editor1.getScrollingModel().getVisibleArea().height;
+ int editorHeight2 = editor2.getScrollingModel().getVisibleArea().height;
+
+ int maximumOffset1 = ((EditorEx)editor1).getScrollPane().getVerticalScrollBar().getMaximum() - editorHeight1;
+ int maximumOffset2 = ((EditorEx)editor1).getScrollPane().getVerticalScrollBar().getMaximum() - editorHeight2;
+
+ // 'shift' here - distance between editor's top and first line of range
+
+ // make whole range visible. If possible, locate it at 'center' (1/3 of height)
+ // If can't show whole range - show as much as we can
+ boolean canShow1 = 2 * gapLines1 + rangeHeight1 <= editorHeight1;
+ boolean canShow2 = 2 * gapLines2 + rangeHeight2 <= editorHeight2;
+
+ int topShift1 = canShow1 ? Math.min(editorHeight1 - gapLines1 - rangeHeight1, editorHeight1 / 3) : gapLines1;
+ int topShift2 = canShow2 ? Math.min(editorHeight2 - gapLines2 - rangeHeight2, editorHeight2 / 3) : gapLines2;
+
+ int topShift = Math.min(topShift1, topShift2);
+
+ // check if we're at the top of file
+ topShift = Math.min(topShift, Math.min(topOffset1, topOffset2));
+
+ int offset1 = topOffset1 - topShift;
+ int offset2 = topOffset2 - topShift;
+ if (maximumOffset1 > offset1 && maximumOffset2 > offset2) return new IntPair(offset1, offset2);
+
+ // One of the ranges is at end of file - we can't scroll where we want to.
+ topShift = Math.min(topOffset1 - maximumOffset1, topOffset2 - maximumOffset2);
+
+ // Try to show as much of range as we can (even if it breaks alignment)
+ offset1 = topOffset1 - topShift + Math.max(topShift + rangeHeight1 + gapLines1 - editorHeight1, 0);
+ offset2 = topOffset2 - topShift + Math.max(topShift + rangeHeight2 + gapLines2 - editorHeight2, 0);
+
+ // always show top of the range
+ offset1 = Math.min(offset1, topOffset1 - gapLines1);
+ offset2 = Math.min(offset2, topOffset2 - gapLines2);
+
+ return new IntPair(offset1, offset2);
+ }
+
+ private static class Anchor {
+ public final int masterStartOffset;
+ public final int masterEndOffset;
+ public final int slaveStartOffset;
+ public final int slaveEndOffset;
+
+ public Anchor(int masterStartOffset, int masterEndOffset, int slaveStartOffset, int slaveEndOffset) {
+ this.masterStartOffset = masterStartOffset;
+ this.masterEndOffset = masterEndOffset;
+ this.slaveStartOffset = slaveStartOffset;
+ this.slaveEndOffset = slaveEndOffset;
+ }
+ }
}
diff --git a/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java b/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java
index cc81f9d39742..011b4459bc02 100644
--- a/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java
+++ b/platform/diff-impl/src/com/intellij/diff/tools/util/twoside/TwosideTextDiffViewer.java
@@ -82,7 +82,7 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase {
@NotNull private final MyScrollToLineHelper myScrollToLineHelper = new MyScrollToLineHelper();
- @Nullable private TwosideSyncScrollSupport mySyncScrollListener;
+ @Nullable protected TwosideSyncScrollSupport mySyncScrollSupport;
@NotNull private Side myCurrentSide;
@@ -230,7 +230,7 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase {
if (myEditor1 != null && myEditor2 != null) {
SyncScrollSupport.SyncScrollable scrollable = getSyncScrollable();
if (scrollable != null) {
- mySyncScrollListener = new TwosideSyncScrollSupport(myEditor1, myEditor2, scrollable);
+ mySyncScrollSupport = new TwosideSyncScrollSupport(myEditor1, myEditor2, scrollable);
}
}
}
@@ -248,15 +248,15 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase {
myEditor2.getScrollingModel().removeVisibleAreaListener(myVisibleAreaListener);
}
if (myEditor1 != null && myEditor2 != null) {
- if (mySyncScrollListener != null) {
- mySyncScrollListener = null;
+ if (mySyncScrollSupport != null) {
+ mySyncScrollSupport = null;
}
}
}
protected void disableSyncScrollSupport(boolean disable) {
- if (mySyncScrollListener != null) {
- mySyncScrollListener.myDuringSyncScroll = disable;
+ if (mySyncScrollSupport != null) {
+ mySyncScrollSupport.myDuringSyncScroll = disable;
}
}
@@ -325,8 +325,8 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase {
@CalledInAwt
@NotNull
protected LogicalPosition transferPosition(@NotNull Side baseSide, @NotNull LogicalPosition position) {
- if (mySyncScrollListener == null) return position;
- int line = mySyncScrollListener.getScrollable().transfer(baseSide, position.line);
+ if (mySyncScrollSupport == null) return position;
+ int line = mySyncScrollSupport.getScrollable().transfer(baseSide, position.line);
return new LogicalPosition(line, position.column);
}
@@ -479,7 +479,7 @@ public abstract class TwosideTextDiffViewer extends TextDiffViewerBase {
private class MyVisibleAreaListener implements VisibleAreaListener {
@Override
public void visibleAreaChanged(VisibleAreaEvent e) {
- if (mySyncScrollListener != null) mySyncScrollListener.visibleAreaChanged(e);
+ if (mySyncScrollSupport != null) mySyncScrollSupport.visibleAreaChanged(e);
if (Registry.is("diff.divider.repainting.fix")) {
myContentPanel.repaint();
}
diff --git a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java
index b2af70e18c92..d1df97e088b3 100644
--- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java
+++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java
@@ -191,6 +191,12 @@ public class DiffUtil {
// Scrolling
//
+ public static void moveCaret(@Nullable final Editor editor, int line) {
+ if (editor == null) return;
+ editor.getCaretModel().removeSecondaryCarets();
+ editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(line, 0));
+ }
+
public static void scrollEditor(@Nullable final Editor editor, int line, boolean animated) {
scrollEditor(editor, line, 0, animated);
}
@@ -203,11 +209,15 @@ public class DiffUtil {
}
public static void scrollToPoint(@Nullable Editor editor, @NotNull Point point) {
+ scrollToPoint(editor, point, false);
+ }
+
+ public static void scrollToPoint(@Nullable Editor editor, @NotNull Point point, boolean animated) {
if (editor == null) return;
- editor.getScrollingModel().disableAnimation();
+ if (!animated) editor.getScrollingModel().disableAnimation();
editor.getScrollingModel().scrollHorizontally(point.x);
editor.getScrollingModel().scrollVertically(point.y);
- editor.getScrollingModel().enableAnimation();
+ if (!animated) editor.getScrollingModel().enableAnimation();
}
public static void scrollToCaret(@Nullable Editor editor, boolean animated) {
diff --git a/platform/lang-impl/src/com/intellij/execution/runners/FakeRerunAction.java b/platform/lang-impl/src/com/intellij/execution/runners/FakeRerunAction.java
index 34f96b0b51c6..be7a2da4ef41 100644
--- a/platform/lang-impl/src/com/intellij/execution/runners/FakeRerunAction.java
+++ b/platform/lang-impl/src/com/intellij/execution/runners/FakeRerunAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * 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.
@@ -37,11 +37,11 @@ class FakeRerunAction extends AnAction implements DumbAware {
if (environment != null) {
presentation.setText(ExecutionBundle.message("rerun.configuration.action.name", environment.getRunProfile().getName()));
presentation.setIcon(ExecutionManagerImpl.isProcessRunning(getDescriptor(event)) ? AllIcons.Actions.Restart : environment.getExecutor().getIcon());
- presentation.setEnabledAndVisible(isEnabled(event));
+ presentation.setEnabled(isEnabled(event));
return;
}
- presentation.setEnabledAndVisible(false);
+ presentation.setEnabled(false);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewPane.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewPane.java
index 788a6d48366f..9f15bffa9a88 100644
--- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewPane.java
+++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewPane.java
@@ -35,6 +35,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizerUtil;
@@ -191,7 +192,7 @@ public class ProjectViewPane extends AbstractProjectViewPSIPane {
}
}
- private final class ShowExcludedFilesAction extends ToggleAction {
+ private final class ShowExcludedFilesAction extends ToggleAction implements DumbAware {
private ShowExcludedFilesAction() {
super(IdeBundle.message("action.show.excluded.files"), IdeBundle.message("action.show.hide.excluded.files"), null);
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
index c04131596627..7f58f14c89ff 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java
@@ -2456,14 +2456,14 @@ public class FileBasedIndexImpl extends FileBasedIndex {
private boolean isTooLarge(@NotNull VirtualFile file) {
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file)) {
- return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file);
+ return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file);
}
return false;
}
private boolean isTooLarge(@NotNull VirtualFile file, long contentSize) {
if (SingleRootFileViewProvider.isTooLargeForIntelligence(file, contentSize)) {
- return !myNoLimitCheckTypes.contains(file.getFileType()) && !SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
+ return !myNoLimitCheckTypes.contains(file.getFileType()) || SingleRootFileViewProvider.isTooLargeForContentLoading(file, contentSize);
}
return false;
}
diff --git a/platform/platform-api/src/com/intellij/ui/ListUtil.java b/platform/platform-api/src/com/intellij/ui/ListUtil.java
index 7f36ffd55bb8..23e99899048f 100644
--- a/platform/platform-api/src/com/intellij/ui/ListUtil.java
+++ b/platform/platform-api/src/com/intellij/ui/ListUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * 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.
@@ -37,7 +37,8 @@ public class ListUtil {
boolean myIsEngaged = false;
public void mouseMoved(MouseEvent e) {
- if (myIsEngaged && !UIUtil.isSelectionButtonDown(e)) {
+ Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
+ if (myIsEngaged && !UIUtil.isSelectionButtonDown(e) && !(focusOwner instanceof JRootPane)) {
Point point = e.getPoint();
int index = list.locationToIndex(point);
list.putClientProperty(SELECTED_BY_MOUSE_EVENT, Boolean.TRUE);
diff --git a/platform/platform-api/src/com/intellij/ui/table/JBTable.java b/platform/platform-api/src/com/intellij/ui/table/JBTable.java
index 2d86e10c244e..a375375f1dae 100644
--- a/platform/platform-api/src/com/intellij/ui/table/JBTable.java
+++ b/platform/platform-api/src/com/intellij/ui/table/JBTable.java
@@ -45,6 +45,7 @@ import java.util.EventObject;
public class JBTable extends JTable implements ComponentWithEmptyText, ComponentWithExpandableItems {
public static final int PREFERRED_SCROLLABLE_VIEWPORT_HEIGHT_IN_ROWS = 7;
public static final int COLUMN_RESIZE_AREA_WIDTH = 3; // same as in BasicTableHeaderUI
+ private static final int DEFAULT_MIN_COLUMN_WIDTH = 15; // see TableColumn constructor javadoc
private final StatusText myEmptyText;
private final ExpandableItemsHandler myExpandableItemsHandler;
@@ -794,27 +795,6 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
});
}
- protected int getExpandedColumnWidth(int columnToExpand) {
- int expandedWidth = getPreferredHeaderWidth(columnToExpand);
- for (int row = 0; row < getRowCount(); row++) {
- TableCellRenderer cellRenderer = getCellRenderer(row, columnToExpand);
- if (cellRenderer != null) {
- Component c = JBTable.this.prepareRenderer(cellRenderer, row, columnToExpand);
- expandedWidth = Math.max(expandedWidth, c.getPreferredSize().width);
- }
- }
- return expandedWidth;
- }
-
- private int getPreferredHeaderWidth(int columnIdx) {
- TableColumn column = getColumnModel().getColumn(columnIdx);
- TableCellRenderer renderer = column.getHeaderRenderer();
- renderer = renderer == null ? getDefaultRenderer() : renderer;
- Object headerValue = column.getHeaderValue();
- Component headerCellRenderer = renderer.getTableCellRendererComponent(JBTable.this, headerValue, false, false, -1, columnIdx);
- return headerCellRenderer.getPreferredSize().width;
- }
-
private int getColumnToPack(Point p) {
int viewColumnIdx = JBTable.this.columnAtPoint(p);
if (viewColumnIdx == -1) return -1;
@@ -836,6 +816,33 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
}
}
+ public int getExpandedColumnWidth(int columnToExpand) {
+ int expandedWidth = getPreferredHeaderWidth(columnToExpand);
+ for (int row = 0; row < getRowCount(); row++) {
+ TableCellRenderer cellRenderer = getCellRenderer(row, columnToExpand);
+ if (cellRenderer != null) {
+ Component c = prepareRenderer(cellRenderer, row, columnToExpand);
+ expandedWidth = Math.max(expandedWidth, c.getPreferredSize().width);
+ }
+ }
+ return expandedWidth;
+ }
+
+ private int getPreferredHeaderWidth(int columnIdx) {
+ TableColumn column = getColumnModel().getColumn(columnIdx);
+ TableCellRenderer renderer = column.getHeaderRenderer();
+ if (renderer == null) {
+ JTableHeader header = getTableHeader();
+ if (header == null) {
+ return DEFAULT_MIN_COLUMN_WIDTH;
+ }
+ renderer = header.getDefaultRenderer();
+ }
+ Object headerValue = column.getHeaderValue();
+ Component headerCellRenderer = renderer.getTableCellRendererComponent(this, headerValue, false, false, -1, columnIdx);
+ return headerCellRenderer.getPreferredSize().width;
+ }
+
/**
* JTable gets table data from model lazily - only for a table part to be shown.
* JBTable loads all the data on initialization to calculate cell size.
diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.form b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.form
index 1f9cea154af4..bba955d00422 100644
--- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.form
+++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerMain.form
@@ -54,7 +54,10 @@
-
+
+
+
+
@@ -91,7 +94,10 @@
-
+
+
+
+
diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
index e4805a1efff8..6e0348d8e0d3 100644
--- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
+++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java
@@ -124,7 +124,7 @@ public class StartupUtil {
if (!"true".equals(System.getProperty("idea.no.jre.check"))) {
try {
// try to find a class from tools.jar
- Class.forName("com.sun.jdi.Field");
+ Class.forName("com.sun.jdi.Field", false, StartupUtil.class.getClassLoader());
}
catch (ClassNotFoundException e) {
String message = "'tools.jar' seems to be not in " + ApplicationNamesInfo.getInstance().getProductName() + " classpath.\n" +
@@ -132,6 +132,12 @@ public class StartupUtil {
Main.showMessage("JDK Required", message, true);
return false;
}
+ catch (LinkageError e) {
+ String message = "Cannot load a class from 'tools.jar': " + e.getMessage() + "\n" +
+ "Please ensure JAVA_HOME points to JDK rather than JRE.";
+ Main.showMessage("JDK Required", message, true);
+ return false;
+ }
if (StringUtil.containsIgnoreCase(System.getProperty("java.vm.name", ""), "OpenJDK") && !SystemInfo.isJavaVersionAtLeast("1.7")) {
String message = "OpenJDK 6 is not supported. Please use Oracle Java or newer OpenJDK.";
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java
index bc8910697014..55d4d523bb31 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/NewRecentProjectPanel.java
@@ -27,6 +27,7 @@ import com.intellij.ui.PopupHandler;
import com.intellij.ui.components.JBList;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.ui.speedSearch.ListWithFilter;
+import com.intellij.ui.speedSearch.NameFilteringListModel;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nullable;
@@ -80,17 +81,44 @@ public class NewRecentProjectPanel extends RecentProjectPanel {
list.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
- if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
- FlatWelcomeFrame frame = UIUtil.getParentOfType(FlatWelcomeFrame.class, list);
- if (frame != null) {
- FocusTraversalPolicy policy = frame.getFocusTraversalPolicy();
- if (policy != null) {
- Component next = policy.getComponentAfter(frame, list);
- if (next != null) {
- next.requestFocus();
+ Object selected = list.getSelectedValue();
+ final ProjectGroup group;
+ if (selected instanceof ProjectGroupActionGroup) {
+ group = ((ProjectGroupActionGroup)selected).getGroup();
+ } else {
+ group = null;
+ }
+
+ int keyCode = e.getKeyCode();
+ if (keyCode == KeyEvent.VK_RIGHT) {
+ if (group != null) {
+ if (!group.isExpanded()) {
+ group.setExpanded(true);
+ ListModel model = ((NameFilteringListModel)list.getModel()).getOriginalModel();
+ int index = list.getSelectedIndex();
+ RecentProjectsWelcomeScreenActionBase.rebuildRecentProjectDataModel((DefaultListModel)model);
+ list.setSelectedIndex(group.getProjects().isEmpty() ? index : index + 1);
+ }
+ } else {
+ FlatWelcomeFrame frame = UIUtil.getParentOfType(FlatWelcomeFrame.class, list);
+ if (frame != null) {
+ FocusTraversalPolicy policy = frame.getFocusTraversalPolicy();
+ if (policy != null) {
+ Component next = policy.getComponentAfter(frame, list);
+ if (next != null) {
+ next.requestFocus();
+ }
}
}
}
+ } else if (keyCode == KeyEvent.VK_LEFT ) {
+ if (group != null && group.isExpanded()) {
+ group.setExpanded(false);
+ int index = list.getSelectedIndex();
+ ListModel model = ((NameFilteringListModel)list.getModel()).getOriginalModel();
+ RecentProjectsWelcomeScreenActionBase.rebuildRecentProjectDataModel((DefaultListModel)model);
+ list.setSelectedIndex(index);
+ }
}
}
});
@@ -186,7 +214,7 @@ public class NewRecentProjectPanel extends RecentProjectPanel {
return new JPanel() {
{
setLayout(new BorderLayout());
- setBackground(UIUtil.getListBackground(isSelected));
+ setBackground(back);
boolean isGroup = value instanceof ProjectGroupActionGroup;
boolean isInsideGroup = false;
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java
index 0137e46f8c6a..ccdc1236df17 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectPanel.java
@@ -235,7 +235,8 @@ public class RecentProjectPanel extends JPanel {
boolean myIsEngaged = false;
@Override
public void mouseMoved(MouseEvent e) {
- if (myIsEngaged && !UIUtil.isSelectionButtonDown(e)) {
+ Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
+ if (myIsEngaged && !UIUtil.isSelectionButtonDown(e) && !(focusOwner instanceof JRootPane)) {
Point point = e.getPoint();
int index = myList.locationToIndex(point);
myList.setSelectedIndex(index);
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectsWelcomeScreenActionBase.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectsWelcomeScreenActionBase.java
index ca83e853a8a6..bffa0b76d8b7 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectsWelcomeScreenActionBase.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/welcomeScreen/RecentProjectsWelcomeScreenActionBase.java
@@ -35,7 +35,7 @@ import java.util.List;
*/
public abstract class RecentProjectsWelcomeScreenActionBase extends DumbAwareAction {
@Nullable
- public DefaultListModel getDataModel(AnActionEvent e) {
+ public static DefaultListModel getDataModel(AnActionEvent e) {
final JList list = getList(e);
if (list != null) {
ListModel model = list.getModel();
@@ -50,7 +50,7 @@ public abstract class RecentProjectsWelcomeScreenActionBase extends DumbAwareAct
}
@NotNull
- public List getSelectedElements(AnActionEvent e) {
+ public static List getSelectedElements(AnActionEvent e) {
final JList list = getList(e);
final List actions = new ArrayList();
if (list != null) {
@@ -64,7 +64,7 @@ public abstract class RecentProjectsWelcomeScreenActionBase extends DumbAwareAct
}
@Nullable
- public JList getList(AnActionEvent e) {
+ public static JList getList(AnActionEvent e) {
final Component component = e.getData(PlatformDataKeys.CONTEXT_COMPONENT);
if (component instanceof JList) {
return (JList)component;
@@ -72,7 +72,7 @@ public abstract class RecentProjectsWelcomeScreenActionBase extends DumbAwareAct
return null;
}
- public boolean hasGroupSelected(AnActionEvent e) {
+ public static boolean hasGroupSelected(AnActionEvent e) {
for (AnAction action : getSelectedElements(e)) {
if (action instanceof ProjectGroupActionGroup) {
return true;
@@ -81,14 +81,18 @@ public abstract class RecentProjectsWelcomeScreenActionBase extends DumbAwareAct
return false;
}
- public void rebuildRecentProjectsList(AnActionEvent e) {
+ public static void rebuildRecentProjectsList(AnActionEvent e) {
final DefaultListModel model = getDataModel(e);
if (model != null) {
- model.clear();
- for (AnAction action : RecentProjectsManager.getInstance().getRecentProjectsActions(false, FlatWelcomeFrame.isUseProjectGroups())) {
- //noinspection unchecked
- model.addElement(action);
- }
+ rebuildRecentProjectDataModel(model);
+ }
+ }
+
+ public static void rebuildRecentProjectDataModel(@NotNull DefaultListModel model) {
+ model.clear();
+ for (AnAction action : RecentProjectsManager.getInstance().getRecentProjectsActions(false, FlatWelcomeFrame.isUseProjectGroups())) {
+ //noinspection unchecked
+ model.addElement(action);
}
}
}
diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java
index 4fdd374d4bca..293ae39c8db1 100644
--- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java
+++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java
@@ -21,7 +21,6 @@ import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
-import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.colors.impl.DelegateColorScheme;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.ex.*;
@@ -58,54 +57,37 @@ import java.util.List;
*/
public abstract class EditorTextFieldCellRenderer implements TableCellRenderer, Disposable {
- private static final Key MY_PANEL_PROPERTY = Key.create("EditorTextFieldCellRenderer.MyEditorPanel");
+ private static final Key MY_PANEL_PROPERTY = Key.create("EditorTextFieldCellRenderer.MyEditorPanel");
private final Project myProject;
+ private final FileType myFileType;
private final boolean myInheritFontFromLaF;
- protected EditorTextFieldCellRenderer(@Nullable Project project, @NotNull Disposable parent) {
- this(project, true, parent);
+ protected EditorTextFieldCellRenderer(@Nullable Project project, @Nullable FileType fileType, @NotNull Disposable parent) {
+ this(project, fileType, true, parent);
}
- protected EditorTextFieldCellRenderer(@Nullable Project project, boolean inheritFontFromLaF, @NotNull Disposable parent) {
+ protected EditorTextFieldCellRenderer(@Nullable Project project, @Nullable FileType fileType,
+ boolean inheritFontFromLaF, @NotNull Disposable parent) {
myProject = project;
+ myFileType = fileType;
myInheritFontFromLaF = inheritFontFromLaF;
Disposer.register(parent, this);
}
protected abstract String getText(JTable table, Object value, int row, int column);
- @Nullable
- protected TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) {
- return null;
- }
-
- protected Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
- return UIUtil.getTableBackground(selected);
- }
-
- @Nullable
- protected FileType getFileType() {
- return null;
- }
-
- @NotNull
- protected EditorColorsScheme getColorScheme() {
- return EditorColorsManager.getInstance().getGlobalScheme();
- }
-
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
- MyPanel panel = getEditorPanel(table);
- EditorEx editor = panel.myEditor;
+ RendererComponent panel = getEditorPanel(table);
+ EditorEx editor = panel.getEditor();
editor.getColorsScheme().setEditorFontSize(table.getFont().getSize());
String text = getText(table, value, row, column);
- TextAttributes textAttributes = getTextAttributes(table, value, selected, focused, row, column);
- panel.setText(text, textAttributes, selected);
+ panel.setText(text, null, selected);
editor.getColorsScheme().setColor(EditorColors.SELECTION_BACKGROUND_COLOR, table.getSelectionBackground());
editor.getColorsScheme().setColor(EditorColors.SELECTION_FOREGROUND_COLOR, table.getSelectionForeground());
- editor.setBackgroundColor(getCellBackground(table, value, selected, focused, row, column));
+ editor.setBackgroundColor(selected ? table.getSelectionBackground() : table.getBackground());
panel.setOpaque(!Comparing.equal(editor.getBackgroundColor(), table.getBackground()));
panel.setBorder(null); // prevents double border painting when ExtendedItemRendererComponentWrapper is used
@@ -114,29 +96,15 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer,
}
@NotNull
- private MyPanel getEditorPanel(final JTable table) {
- MyPanel panel = UIUtil.getClientProperty(table, MY_PANEL_PROPERTY);
+ private RendererComponent getEditorPanel(final JTable table) {
+ RendererComponent panel = UIUtil.getClientProperty(table, MY_PANEL_PROPERTY);
if (panel != null) {
DelegateColorScheme scheme = (DelegateColorScheme)panel.myEditor.getColorsScheme();
- scheme.setDelegate(getColorScheme());
+ scheme.setDelegate(EditorColorsManager.getInstance().getGlobalScheme());
return panel;
}
- FileType fileType = ObjectUtils.notNull(getFileType(), FileTypes.PLAIN_TEXT);
- EditorTextField field = new EditorTextField(new MyDocument(), myProject, fileType, false, false);
- field.setSupplementary(true);
- field.setFontInheritedFromLAF(myInheritFontFromLaF);
- field.addNotify(); // creates editor
-
- EditorEx editor = (EditorEx)ObjectUtils.assertNotNull(field.getEditor());
- editor.setRendererMode(true);
-
- editor.setColorsScheme(editor.createBoundColorSchemeDelegate(null));
- editor.getSettings().setCaretRowShown(false);
-
- editor.getScrollPane().setBorder(null);
-
- panel = new MyPanel(editor);
+ panel = new RendererComponent(myProject, myFileType, myInheritFontFromLaF);
Disposer.register(this, panel);
Disposer.register(this, new Disposable() {
@Override
@@ -153,7 +121,7 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer,
public void dispose() {
}
- private static class MyPanel extends CellRendererPanel implements Disposable {
+ public static class RendererComponent extends CellRendererPanel implements Disposable {
private static final char ABBREVIATION_SUFFIX = '\u2026'; // 2026 '...'
private static final char RETURN_SYMBOL = '\u23ce';
@@ -165,9 +133,13 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer,
private TextAttributes myTextAttributes;
private boolean mySelected;
- public MyPanel(EditorEx editor) {
- add(editor.getContentComponent());
- this.myEditor = editor;
+ public RendererComponent(Project project, @Nullable FileType fileType, boolean inheritFontFromLaF) {
+ myEditor = createEditor(project, fileType, inheritFontFromLaF);
+ add(myEditor.getContentComponent());
+ }
+
+ public EditorEx getEditor() {
+ return myEditor;
}
@Override
@@ -200,14 +172,6 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer,
@Override
protected void paintComponent(Graphics g) {
- if (getBorder() == null || !myEditor.getContentComponent().isOpaque()) return;
-
- Color oldColor = g.getColor();
- g.setColor(myEditor.getBackgroundColor());
- Insets insets = getInsets();
- g.fillRect(0, 0, insets.left, getHeight());
- g.fillRect(getWidth() - insets.left - insets.right, 0, getWidth(), getHeight());
- g.setColor(oldColor);
}
@Override
@@ -325,6 +289,25 @@ public abstract class EditorTextFieldCellRenderer implements TableCellRenderer,
return abbrLength;
}
+
+ @NotNull
+ private static EditorEx createEditor(Project project, @Nullable FileType fileType, boolean inheritFontFromLaF) {
+ fileType = ObjectUtils.notNull(fileType, FileTypes.PLAIN_TEXT);
+ EditorTextField field = new EditorTextField(new MyDocument(), project, fileType, false, false);
+ field.setSupplementary(true);
+ field.setFontInheritedFromLAF(inheritFontFromLaF);
+ field.addNotify(); // creates editor
+
+ EditorEx editor = (EditorEx)ObjectUtils.assertNotNull(field.getEditor());
+ editor.setRendererMode(true);
+
+ editor.setColorsScheme(editor.createBoundColorSchemeDelegate(null));
+ editor.getSettings().setCaretRowShown(false);
+
+ editor.getScrollPane().setBorder(null);
+
+ return editor;
+ }
}
private static class MyDocument extends UserDataHolderBase implements DocumentEx {
diff --git a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java
index 5c64391669ec..c6553dcfec70 100644
--- a/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java
+++ b/platform/platform-impl/src/com/intellij/util/ui/table/EditorTextFieldJBTableRowRenderer.java
@@ -16,18 +16,17 @@
package com.intellij.util.ui.table;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.ui.EditorTextFieldCellRenderer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import java.awt.*;
public abstract class EditorTextFieldJBTableRowRenderer extends EditorTextFieldCellRenderer implements JBTableRowRenderer {
- protected EditorTextFieldJBTableRowRenderer(@Nullable Project project, @NotNull Disposable parent) {
- super(project, parent);
+ protected EditorTextFieldJBTableRowRenderer(@Nullable Project project, @Nullable FileType fileType, @NotNull Disposable parent) {
+ super(project, fileType, parent);
}
@Override
@@ -40,25 +39,5 @@ public abstract class EditorTextFieldJBTableRowRenderer extends EditorTextFieldC
return getText(table, row);
}
- @Override
- protected final Color getCellBackground(JTable table, Object value, boolean selected, boolean focused, int row, int column) {
- return getRowBackground(table, selected, focused, row);
- }
-
- @Nullable
- @Override
- protected final TextAttributes getTextAttributes(JTable table, Object value, boolean selected, boolean focused, int row, int col) {
- return getTextAttributes(table, row);
- }
-
protected abstract String getText(JTable table, int row);
-
- @Nullable
- protected TextAttributes getTextAttributes(JTable table, int row) {
- return null;
- }
-
- protected Color getRowBackground(JTable table, boolean selected, boolean focused, int row) {
- return super.getCellBackground(table, null, selected, focused, row, 0);
- }
}
diff --git a/platform/platform-resources/src/idea/PlatformActions.xml b/platform/platform-resources/src/idea/PlatformActions.xml
index 339d402bca62..a9b758c281b0 100644
--- a/platform/platform-resources/src/idea/PlatformActions.xml
+++ b/platform/platform-resources/src/idea/PlatformActions.xml
@@ -555,7 +555,7 @@
-
+
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/ui/ActionsTreeTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/ui/ActionsTreeTest.java
index 465b570afe81..6e9b494183c1 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/ui/ActionsTreeTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/keymap/impl/ui/ActionsTreeTest.java
@@ -28,6 +28,7 @@ import com.intellij.openapi.keymap.impl.ShortcutRestrictions;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.picocontainer.MutablePicoContainer;
@@ -208,6 +209,8 @@ public class ActionsTreeTest extends LightPlatformCodeInsightTestCase {
public void testPresentation() {
ActionManager manager = ActionManager.getInstance();
+
+ List failures = new SmartList();
for (String id : manager.getActionIds("")) {
if (!ACTION_WITHOUT_TEXT_AND_DESCRIPTION.equals(id)) {
try {
@@ -224,8 +227,8 @@ public class ActionsTreeTest extends LightPlatformCodeInsightTestCase {
if (action instanceof ActionGroup) {
System.out.println("ignored action group: " + message);
}
- else {
- assertFalse("no text: " + message, StringUtil.isEmpty(action.getTemplatePresentation().getText()));
+ else if (StringUtil.isEmpty(action.getTemplatePresentation().getText())) {
+ failures.add("no text: " + message);
}
}
catch (PluginException exception) {
@@ -233,6 +236,8 @@ public class ActionsTreeTest extends LightPlatformCodeInsightTestCase {
}
}
}
+
+ assertEmpty(failures);
}
private static void checkPresentationProperty(String name, String message, Object expected, Object actual) {
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
index 7d39fb8ca451..b25d555d465c 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
@@ -1,3 +1,18 @@
+/*
+ * 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 org.jetbrains.debugger;
import org.jetbrains.annotations.NotNull;
@@ -6,7 +21,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface MemberFilter {
- boolean isMemberVisible(@NotNull Variable variable, boolean filterFunctions);
+ boolean isMemberVisible(@NotNull Variable variable);
@NotNull
Collection getAdditionalVariables();
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilterBase.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilterBase.java
index 414b169b4679..27ca585710ab 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilterBase.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilterBase.java
@@ -1,3 +1,18 @@
+/*
+ * 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 org.jetbrains.debugger;
import org.jetbrains.annotations.NotNull;
@@ -8,7 +23,7 @@ import java.util.Collections;
public abstract class MemberFilterBase implements MemberFilter {
@Override
- public boolean isMemberVisible(@NotNull Variable variable, boolean filterFunctions) {
+ public boolean isMemberVisible(@NotNull Variable variable) {
return variable.isReadable();
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
index 8e3bf4b8c93c..e6462e61cce5 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
@@ -431,7 +431,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
}
private void computeArrayRanges(@NotNull List properties, @NotNull XCompositeNode node) {
- final List variables = Variables.filterAndSort(properties, memberFilter, false);
+ final List variables = Variables.filterAndSort(properties, memberFilter);
int count = variables.size();
int bucketSize = XCompositeNode.MAX_CHILDREN_TO_SHOW;
if (count <= bucketSize) {
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
index 9d3fbc5724ac..ad38b972d3b6 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
@@ -1,3 +1,18 @@
+/*
+ * 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 org.jetbrains.debugger;
import com.intellij.openapi.util.text.StringUtil;
@@ -65,7 +80,7 @@ public final class Variables {
List properties = new ArrayList(variables.size() + additionalVariables.size());
List functions = new SmartList();
for (Variable variable : variables) {
- if (memberFilter.isMemberVisible(variable, false)) {
+ if (memberFilter.isMemberVisible(variable)) {
Value value = variable.getValue();
if (value != null &&
value.getType() == ValueType.FUNCTION &&
@@ -112,7 +127,7 @@ public final class Variables {
@NotNull MemberFilter memberFilter,
int maxChildrenToAdd,
boolean defaultIsLast) {
- List list = filterAndSort(variables, memberFilter, true);
+ List list = filterAndSort(variables, memberFilter);
if (list.isEmpty()) {
if (defaultIsLast) {
node.addChildren(XValueChildrenList.EMPTY, true);
@@ -133,7 +148,7 @@ public final class Variables {
}
@NotNull
- public static List filterAndSort(@NotNull List variables, @NotNull MemberFilter memberFilter, boolean filterFunctions) {
+ public static List filterAndSort(@NotNull List variables, @NotNull MemberFilter memberFilter) {
if (variables.isEmpty()) {
return Collections.emptyList();
}
@@ -141,7 +156,7 @@ public final class Variables {
Collection additionalVariables = memberFilter.getAdditionalVariables();
List result = new ArrayList(variables.size() + additionalVariables.size());
for (Variable variable : variables) {
- if (memberFilter.isMemberVisible(variable, filterFunctions)) {
+ if (memberFilter.isMemberVisible(variable)) {
result.add(variable);
}
}
diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java
index e3e1fc3543b6..d6232de605ee 100644
--- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java
+++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralToSMTRunnerEventsConvertor.java
@@ -52,6 +52,7 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
private final String myTestFrameworkName;
private boolean myIsTestingFinished;
private TestLocationProvider myLocator = null;
+ private boolean myTreeBuildBeforeStart = false;
public GeneralToSMTRunnerEventsConvertor(@NotNull final SMTestProxy.SMRootTestProxy testsRootNode,
@NotNull final String testFrameworkName) {
@@ -117,6 +118,7 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
@Override
public void onSuiteTreeNodeAdded(final String testName, final String locationHint) {
+ myTreeBuildBeforeStart = true;
addToInvokeLater(new Runnable() {
@Override
public void run() {
@@ -132,6 +134,7 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
@Override
public void onSuiteTreeStarted(final String suiteName, final String locationHint) {
+ myTreeBuildBeforeStart = true;
addToInvokeLater(new Runnable() {
@Override
public void run() {
@@ -229,10 +232,12 @@ public class GeneralToSMTRunnerEventsConvertor extends GeneralTestEventsProcesso
});
}
- private static SMTestProxy findChildByName(SMTestProxy parentSuite, String fullName) {
- for (SMTestProxy proxy : parentSuite.getChildren()) {
- if (fullName.equals(proxy.getName())) {
- return proxy;
+ private SMTestProxy findChildByName(SMTestProxy parentSuite, String fullName) {
+ if (myTreeBuildBeforeStart) {
+ for (SMTestProxy proxy : parentSuite.getChildren()) {
+ if (fullName.equals(proxy.getName())) {
+ return proxy;
+ }
}
}
return null;
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java
index fbfd55d0cc85..568c52898594 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestConsoleProperties.java
@@ -37,9 +37,11 @@ import com.intellij.util.config.ToggleBooleanProperty;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
+import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
+import javax.swing.tree.TreeSelectionModel;
import java.util.List;
import java.util.Map;
@@ -195,4 +197,9 @@ public abstract class TestConsoleProperties extends StoringPropertyContainer imp
Icon icon = AllIcons.RunConfigurations.IncludeNonStartedTests_Rerun;
return new ToggleBooleanProperty(text, null, icon, this, INCLUDE_NON_STARTED_IN_RERUN_FAILED);
}
+
+ @JdkConstants.TreeSelectionMode
+ protected int getSelectionMode() {
+ return TreeSelectionModel.SINGLE_TREE_SELECTION;
+ }
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
index 5d1d2b346a85..ace77525a893 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
@@ -21,7 +21,6 @@
package com.intellij.execution.testframework;
import com.intellij.execution.Location;
-import com.intellij.execution.testframework.actions.ViewAssertEqualsDiffAction;
import com.intellij.ide.CopyProvider;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.openapi.Disposable;
@@ -35,12 +34,14 @@ import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.EditSourceOnDoubleClickHandler;
import com.intellij.util.containers.Convertor;
import com.intellij.util.ui.tree.TreeUtil;
-import org.intellij.lang.annotations.JdkConstants;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.plaf.TreeUI;
-import javax.swing.tree.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeCellRenderer;
+import javax.swing.tree.TreePath;
import java.awt.datatransfer.StringSelection;
import java.util.ArrayList;
import java.util.List;
@@ -68,7 +69,7 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
public void attachToModel(final TestFrameworkRunningModel model) {
setModel(new DefaultTreeModel(new DefaultMutableTreeNode(model.getRoot())));
- getSelectionModel().setSelectionMode(getSelectionMode());
+ getSelectionModel().setSelectionMode(model.getProperties().getSelectionMode());
myModel = model;
Disposer.register(myModel, myModel.getRoot());
Disposer.register(myModel, new Disposable() {
@@ -169,9 +170,4 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
TreeUtil.installActions(this);
PopupHandler.installPopupHandler(this, IdeActions.GROUP_TESTTREE_POPUP, ActionPlaces.TESTTREE_VIEW_POPUP);
}
-
- @JdkConstants.TreeSelectionMode
- protected int getSelectionMode() {
- return TreeSelectionModel.SINGLE_TREE_SELECTION;
- }
}
\ No newline at end of file
diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties
index c2dd64c84412..bc8338036e1f 100644
--- a/platform/util/resources/misc/registry.properties
+++ b/platform/util/resources/misc/registry.properties
@@ -575,3 +575,6 @@ search.everywhere.pattern.checking.description=Avoid searching classes and symbo
idea.concurrent.scanning.files.to.index=true
welcome.screen.project.grouping.enabled=true
welcome.screen.project.grouping.enabled.description=Allows to group recent projects
+
+custom.folding.max.lookup.depth=50
+custom.folding.max.lookup.depth.description=Max lookup depth for custom folding comments in a PSI tree.
\ No newline at end of file
diff --git a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java
index 0bf9ba824f53..18d35615f54f 100644
--- a/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java
+++ b/platform/util/src/com/intellij/openapi/util/LowMemoryWatcher.java
@@ -21,6 +21,7 @@ import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.WeakList;
import org.jetbrains.annotations.NotNull;
+import javax.management.ListenerNotFoundException;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;
@@ -66,6 +67,21 @@ public class LowMemoryWatcher {
}
}
};
+ private static final NotificationListener ourLowMemoryListener = new NotificationListener() {
+ @Override
+ public void handleNotification(Notification n, Object hb) {
+ if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) ||
+ MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
+ synchronized (ourJanitor) {
+ if (!ourSubmitted) {
+ //noinspection AssignmentToStaticFieldFromInstanceMethod
+ ourSubmitted = true;
+ ourExecutor.submit(ourJanitor);
+ }
+ }
+ }
+ }
+ };
private final Runnable myRunnable;
@@ -79,20 +95,7 @@ public class LowMemoryWatcher {
}
}
}
- ((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(new NotificationListener() {
- @Override
- public void handleNotification(Notification n, Object hb) {
- if (MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED.equals(n.getType()) || MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED.equals(n.getType())) {
- synchronized (ourJanitor) {
- if (!ourSubmitted) {
- //noinspection AssignmentToStaticFieldFromInstanceMethod
- ourSubmitted = true;
- ourExecutor.submit(ourJanitor);
- }
- }
- }
- }
- }, null, null);
+ ((NotificationEmitter)ManagementFactory.getMemoryMXBean()).addNotificationListener(ourLowMemoryListener, null, null);
}
/**
@@ -135,6 +138,12 @@ public class LowMemoryWatcher {
public static void stopAll() {
ourExecutor.shutdown();
ourInstances.clear();
+ try {
+ ((NotificationEmitter)ManagementFactory.getMemoryMXBean()).removeNotificationListener(ourLowMemoryListener);
+ }
+ catch (ListenerNotFoundException e) {
+ LOG.error(e);
+ }
}
}
diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index efff439b12c2..ebfc3caf7161 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -1503,14 +1503,13 @@ public class StringUtil extends StringUtilRt {
}
/**
- * Strips quotes around the value.
- * Quotes are removed even if leading and trailing quotes are different or if there is only one quote (leading or trailing).
- * @deprecated use {@link com.intellij.openapi.util.text.StringUtil#unquoteString(String)} instead
- * To be removed in IDEA 17
+ * Consider using {@link StringUtil#unquoteString(String)} instead.
+ * Note: this method has an odd behavior:
+ * Quotes are removed even if leading and trailing quotes are different or
+ * if there is only one quote (leading or trailing).
*/
@NotNull
@Contract(pure = true)
- @Deprecated
public static String stripQuotesAroundValue(@NotNull String text) {
final int len = text.length();
if (len > 0) {
diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java
index b1d27b3c27fb..8620f356f11d 100644
--- a/platform/util/src/com/intellij/util/ui/UIUtil.java
+++ b/platform/util/src/com/intellij/util/ui/UIUtil.java
@@ -314,13 +314,16 @@ public class UIUtil {
}
try {
- isRetina = (getScaleFactorMethod == null) || ((Integer)getScaleFactorMethod.invoke(device) != 1);
+ isRetina = getScaleFactorMethod == null || (Integer)getScaleFactorMethod.invoke(device) != 1;
} catch (IllegalAccessException e) {
LOG.debug("CGraphicsDevice.getScaleFactor(): Access issue");
isRetina = false;
} catch (InvocationTargetException e) {
LOG.debug("CGraphicsDevice.getScaleFactor(): Invocation issue");
isRetina = false;
+ } catch (IllegalArgumentException e) {
+ LOG.debug("object is not an instance of declaring class: " + device.getClass().getName());
+ isRetina = false;
}
devicesToRetinaSupportCacheMap.put(device, isRetina);
@@ -1783,7 +1786,7 @@ public class UIUtil {
}
public static BufferedImage createImageForGraphics(Graphics2D g, int width, int height, int type) {
- if (DetectRetinaKit.isMacRetina(g)) {
+ if (isRetina(g)) {
return RetinaImage.create(width, height, type);
}
//noinspection UndesirableClassUsage
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ChangeGoToChangePopupAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ChangeGoToChangePopupAction.java
index 2e5b6dfd2c30..012591b0baa5 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ChangeGoToChangePopupAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/diff/ChangeGoToChangePopupAction.java
@@ -1,5 +1,7 @@
package com.intellij.openapi.vcs.changes.actions.diff;
+import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
+import com.intellij.diff.chains.DiffRequestChain;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.project.Project;
@@ -7,12 +9,11 @@ import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Ref;
-import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
-import com.intellij.diff.chains.DiffRequestChain;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ui.ChangesBrowser;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.util.Consumer;
+import com.intellij.util.ui.update.UiNotifyConnector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -68,16 +69,22 @@ public abstract class ChangeGoToChangePopupAction myPopup;
+ @NotNull private final Ref myPopup;
public MyChangesBrowser(@NotNull Project project,
@NotNull List changes,
- @Nullable Change currentChange,
+ @Nullable final Change currentChange,
@NotNull Ref popup) {
super(project, null, changes, null, false, false, null, MyUseCase.LOCAL_CHANGES, null);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setChangesToDisplay(changes);
- if (currentChange != null) select(Collections.singletonList(currentChange));
+
+ UiNotifyConnector.doWhenFirstShown(this, new Runnable() {
+ @Override
+ public void run() {
+ if (currentChange != null) select(Collections.singletonList(currentChange));
+ }
+ });
myPopup = popup;
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java
index f629904d14cc..b663348762a1 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/actions/XFetchValueActionBase.java
@@ -48,14 +48,7 @@ public abstract class XFetchValueActionBase extends AnAction {
if (paths != null) {
for (TreePath path : paths) {
Object node = path.getLastPathComponent();
- if (node instanceof XValueNodeImpl) {
- if (((XValueNodeImpl)node).isComputed()) {
- e.getPresentation().setEnabled(true);
- return;
- }
- }
- else if (node instanceof WatchMessageNode) {
- e.getPresentation().setEnabled(true);
+ if (isEnabled(e, node)) {
return;
}
}
@@ -63,8 +56,22 @@ public abstract class XFetchValueActionBase extends AnAction {
e.getPresentation().setEnabled(false);
}
+ protected boolean isEnabled(@NotNull AnActionEvent event, @NotNull Object node) {
+ if (node instanceof XValueNodeImpl) {
+ if (((XValueNodeImpl)node).isComputed()) {
+ event.getPresentation().setEnabled(true);
+ return true;
+ }
+ }
+ else if (node instanceof WatchMessageNode) {
+ event.getPresentation().setEnabled(true);
+ return true;
+ }
+ return false;
+ }
+
@Override
- public void actionPerformed(@NotNull final AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
TreePath[] paths = getSelectedNodes(e.getDataContext());
if (paths == null) {
return;
@@ -72,28 +79,31 @@ public abstract class XFetchValueActionBase extends AnAction {
ValueCollector valueCollector = createCollector(e);
for (TreePath path : paths) {
- Object node = path.getLastPathComponent();
- if (node instanceof XValueNodeImpl) {
- XValueNodeImpl valueNode = (XValueNodeImpl)node;
- XFullValueEvaluator fullValueEvaluator = valueNode.getFullValueEvaluator();
- if (paths.length > 1) { // multiselection - copy the whole node text, see IDEA-136722
- valueCollector.add(valueNode.getText().toString(), valueNode.getPath().getPathCount());
- }
- else {
- if (fullValueEvaluator == null || !fullValueEvaluator.isShowValuePopup()) {
- valueCollector.add(StringUtil.notNullize(DebuggerUIUtil.getNodeRawValue(valueNode)));
- }
- else {
- new CopyValueEvaluationCallback(valueNode, valueCollector).startFetchingValue(fullValueEvaluator);
- }
- }
- }
- else if (node instanceof WatchMessageNode) {
- valueCollector.add(((WatchMessageNode)node).getExpression().getExpression());
- }
+ addToCollector(paths, path.getLastPathComponent(), valueCollector);
}
valueCollector.processed = true;
- valueCollector.finish(e.getProject());
+ valueCollector.finish();
+ }
+
+ protected void addToCollector(@NotNull TreePath[] paths, @NotNull Object node, @NotNull ValueCollector valueCollector) {
+ if (node instanceof XValueNodeImpl) {
+ XValueNodeImpl valueNode = (XValueNodeImpl)node;
+ XFullValueEvaluator fullValueEvaluator = valueNode.getFullValueEvaluator();
+ if (paths.length > 1) { // multiselection - copy the whole node text, see IDEA-136722
+ valueCollector.add(valueNode.getText().toString(), valueNode.getPath().getPathCount());
+ }
+ else {
+ if (fullValueEvaluator == null || !fullValueEvaluator.isShowValuePopup()) {
+ valueCollector.add(StringUtil.notNullize(DebuggerUIUtil.getNodeRawValue(valueNode)));
+ }
+ else {
+ new CopyValueEvaluationCallback(valueNode, valueCollector).startFetchingValue(fullValueEvaluator);
+ }
+ }
+ }
+ else if (node instanceof WatchMessageNode) {
+ valueCollector.add(((WatchMessageNode)node).getExpression().getExpression());
+ }
}
@NotNull
@@ -120,7 +130,8 @@ public abstract class XFetchValueActionBase extends AnAction {
indents.put(values.size() - 1, indent);
}
- public void finish(Project project) {
+ public void finish() {
+ Project project = myTree.getProject();
if (processed && !values.contains(null) && !project.isDisposed()) {
int minIndent = Integer.MAX_VALUE;
for (int indent : indents.getValues()) {
@@ -151,12 +162,12 @@ public abstract class XFetchValueActionBase extends AnAction {
return index;
}
- public void evaluationComplete(final int index, @NotNull final String value, final Project project) {
+ public void evaluationComplete(final int index, @NotNull final String value) {
AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
values.set(index, value);
- finish(project);
+ finish();
}
});
}
@@ -177,7 +188,7 @@ public abstract class XFetchValueActionBase extends AnAction {
@Override
protected void evaluationComplete(@NotNull String value, @NotNull Project project) {
- myValueCollector.evaluationComplete(myValueIndex, value, project);
+ myValueCollector.evaluationComplete(myValueIndex, value);
}
}
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
index 21ba183afedc..0bec30a07106 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
@@ -149,6 +149,9 @@
+ #ref replaceable by 'Objects.equals()' expression #loc
-equals.replaceable.by.objects.call.quickfix=Replace with 'Objects.equals()' expression
\ No newline at end of file
+equals.replaceable.by.objects.call.quickfix=Replace with 'Objects.equals()' expression
+array.objects.equals.display.name='Objects.equals()' called on arrays
+array.objects.equals.problem.descriptor=Objects.#ref() on arrays should probably be 'Arrays.equals()' #loc
+array.objects.deep.equals.problem.descriptor=Objects.#ref() on arrays should probably be 'Arrays.deepEquals()' #loc
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayEqualityInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayEqualityInspection.java
index b52b9be3d873..f42ec5eba0ac 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayEqualityInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayEqualityInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2011-2015 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -79,7 +79,7 @@ public class ArrayEqualityInspection extends BaseInspection {
@NotNull
@Override
public String getFamilyName() {
- return "Replace with implicit equals";
+ return InspectionGadgetsBundle.message("replace.with.arrays.equals");
}
@Override
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayObjectsEqualsInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayObjectsEqualsInspection.java
new file mode 100644
index 000000000000..6b08cf993657
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ArrayObjectsEqualsInspection.java
@@ -0,0 +1,149 @@
+/*
+ * 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.siyeh.ig.bugs;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.siyeh.HardcodedMethodConstants;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.PsiReplacementUtil;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class ArrayObjectsEqualsInspection extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("array.objects.equals.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ final boolean deep = ((Boolean)infos[0]).booleanValue();
+ return deep
+ ? InspectionGadgetsBundle.message("array.objects.deep.equals.problem.descriptor")
+ : InspectionGadgetsBundle.message("array.objects.equals.problem.descriptor");
+ }
+
+ @Override
+ public boolean isEnabledByDefault() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ final boolean deep = ((Boolean)infos[0]).booleanValue();
+ return new ArrayObjectsEqualsFix(deep);
+ }
+
+ private static class ArrayObjectsEqualsFix extends InspectionGadgetsFix {
+
+ private final boolean myDeep;
+
+ public ArrayObjectsEqualsFix(boolean deep) {
+ myDeep = deep;
+ }
+
+ @Nls
+ @NotNull
+ @Override
+ public String getName() {
+ return myDeep ?
+ InspectionGadgetsBundle.message("replace.with.arrays.deep.equals") :
+ InspectionGadgetsBundle.message("replace.with.arrays.equals");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return InspectionGadgetsBundle.message("replace.with.arrays.equals");
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement().getParent().getParent();
+ if (!(element instanceof PsiMethodCallExpression)) {
+ return;
+ }
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)element;
+ final StringBuilder newExpression = new StringBuilder("java.util.Arrays.");
+ if (myDeep) {
+ newExpression.append("deepEquals");
+ }
+ else {
+ newExpression.append("equals");
+ }
+ newExpression.append(methodCallExpression.getArgumentList().getText());
+ PsiReplacementUtil.replaceExpressionAndShorten(methodCallExpression, newExpression.toString());
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new ArrayObjectsEqualsVisitor();
+ }
+
+ private static class ArrayObjectsEqualsVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
+ final PsiReferenceExpression methodExpression = expression.getMethodExpression();
+ final String methodName = methodExpression.getReferenceName();
+ if (!HardcodedMethodConstants.EQUALS.equals(methodName)) {
+ return;
+ }
+ final PsiExpressionList argumentList = expression.getArgumentList();
+ final PsiExpression[] expressions = argumentList.getExpressions();
+ if (expressions.length != 2) {
+ return;
+ }
+ final PsiExpression argument1 = expressions[0];
+ final PsiType type1 = argument1.getType();
+ if (!(type1 instanceof PsiArrayType)) {
+ return;
+ }
+ final PsiExpression argument2 = expressions[1];
+ final PsiType type2 = argument2.getType();
+ if (!(type2 instanceof PsiArrayType)) {
+ return;
+ }
+ final int dimensions = type1.getArrayDimensions();
+ if (dimensions != type2.getArrayDimensions()) {
+ return;
+ }
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass == null || !"java.util.Objects".equals(containingClass.getQualifiedName())) {
+ return;
+ }
+ registerMethodCallError(expression, Boolean.valueOf(dimensions > 1));
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayEquality.html
index 3b44d8e6846f..09c017ac0fdc 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayEquality.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayEquality.html
@@ -1,7 +1,7 @@
-Reports any use of == to test for Array equality,
-rather than the "java.util.Arrays.equals()" method.
+Reports any use of == or != to test for array equality,
+rather than the java.util.Arrays.equals() method.
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayObjectsEquals.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayObjectsEquals.html
new file mode 100644
index 000000000000..ebed149a381f
--- /dev/null
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ArrayObjectsEquals.html
@@ -0,0 +1,11 @@
+
+
+Reports java.util.Objects.equals() called on two arrays.
+Calling java.util.Objects.equals() with array arguments compares identity and is equivalent to using ==.
+Use Arrays.equals() to compare the contents of two arrays
+or Arrays.deepEquals() to compare the contents of two multi-dimensional arrays.
+
+
+New in 15
+
+
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NumberEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NumberEquality.html
index 29933a8529f6..7d6c87fcd44a 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/NumberEquality.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NumberEquality.html
@@ -1,7 +1,7 @@
-Reports any use of == to test for Number equality,
-rather than the ".equals()" method. With auto-boxing it is easy
+Reports any use of == or != to test for Number equality,
+rather than the equals() method. With auto-boxing it is easy
to make the mistake of comparing two Integer (or other subclass of java.lang.Number) objects instead
of two ints.
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html
index 3dccf4b78876..cef5adf14edf 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ObjectEquality.html
@@ -1,7 +1,7 @@
-Reports any use of ==
-to test for Object equality, rather than the ".equals()" method.
+Reports any use of == or !=
+to test for Object equality, rather than the equals() method.
Note that comparison of Strings or Numbers using == is not reported by this
inspection, nor is the comparison of an object to null using
==, or the comparison of two array objects.
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html
index 0a4cc9ba3578..21415b2bfa45 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEquality.html
@@ -1,7 +1,7 @@
-Reports any use of == to test for String equality,
-rather than the ".equals()" method.
+Reports any use of == or != to test for String equality,
+rather than the equals() method.
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/array_objects_equals/ArrayObjectsEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/array_objects_equals/ArrayObjectsEquals.java
new file mode 100644
index 000000000000..f8f863dc5c6b
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/array_objects_equals/ArrayObjectsEquals.java
@@ -0,0 +1,14 @@
+class ArrayObjectsEquals {
+
+ boolean one(String[] ss1, String[] ss2) {
+ return java.util.Objects.equals(ss1, ss2);
+ }
+
+ boolean two(String[][] ss1, String[][] ss2) {
+ return java.util.Objects.equals(ss1, ss2);
+ }
+
+ boolean noWarn(String s1, String[] ss2) {
+ return java.util.Objects.equals(s1, ss2);
+ }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ArrayObjectsEqualsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ArrayObjectsEqualsInspectionTest.java
new file mode 100644
index 000000000000..a8b7fae1aa4e
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ArrayObjectsEqualsInspectionTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.siyeh.ig.bugs;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import junit.framework.TestCase;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class ArrayObjectsEqualsInspectionTest extends LightInspectionTestCase {
+
+ public void testArrayObjectsEquals() {
+ doTest();
+ }
+
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new ArrayObjectsEqualsInspection();
+ }
+
+ @Override
+ protected String[] getEnvironmentClasses() {
+ return new String[]{
+ "package java.util;" +
+ "public class Objects {" +
+ " public static boolean equals(Object a, Object b) {" +
+ " return (a == b) || (a != null && a.equals(b));" +
+ " }" +
+ "}"
+ };
+ }
+}
\ No newline at end of file
diff --git a/plugins/editorconfig/src/org/editorconfig/configmanagement/LineEndingsManager.java b/plugins/editorconfig/src/org/editorconfig/configmanagement/LineEndingsManager.java
index a65d00796699..0cfd3d6e9b36 100644
--- a/plugins/editorconfig/src/org/editorconfig/configmanagement/LineEndingsManager.java
+++ b/plugins/editorconfig/src/org/editorconfig/configmanagement/LineEndingsManager.java
@@ -48,7 +48,7 @@ public class LineEndingsManager extends FileDocumentManagerAdapter {
@Override
public void run() {
IdeFrame frame = WindowManager.getInstance().getIdeFrame(myProject);
- StatusBar statusBar = frame.getStatusBar();
+ StatusBar statusBar = frame != null ? frame.getStatusBar() : null;
StatusBarWidget widget = statusBar != null ? statusBar.getWidget("LineSeparator") : null;
if (widget instanceof LineSeparatorPanel) {
diff --git a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java
index 042b651c6840..50ba95a046fb 100644
--- a/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java
+++ b/plugins/git4idea/src/git4idea/actions/GitRepositoryAction.java
@@ -29,6 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsFileUtil;
import git4idea.GitUtil;
import git4idea.GitVcs;
+import git4idea.branch.GitBranchUtil;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryManager;
@@ -57,22 +58,8 @@ public abstract class GitRepositoryAction extends DumbAwareAction {
GitVcs vcs = GitVcs.getInstance(project);
final List roots = getGitRoots(project, vcs);
if (roots == null) return;
- // get default root
- final VirtualFile[] vFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
- VirtualFile defaultRootVar = null;
- if (vFiles != null) {
- for (VirtualFile file : vFiles) {
- final VirtualFile root = GitUtil.gitRootOrNull(file);
- if (root != null) {
- defaultRootVar = root;
- break;
- }
- }
- }
- if (defaultRootVar == null) {
- defaultRootVar = roots.get(0);
- }
- final VirtualFile defaultRoot = defaultRootVar;
+
+ final VirtualFile defaultRoot = getDefaultRoot(project, roots, e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY));
final Set affectedRoots = new HashSet();
String actionName = getActionName();
@@ -88,6 +75,20 @@ public abstract class GitRepositoryAction extends DumbAwareAction {
}
}
+ @NotNull
+ private static VirtualFile getDefaultRoot(@NotNull Project project, @NotNull List roots, @Nullable VirtualFile[] vFiles) {
+ if (vFiles != null) {
+ for (VirtualFile file : vFiles) {
+ VirtualFile root = GitUtil.gitRootOrNull(file);
+ if (root != null) {
+ return root;
+ }
+ }
+ }
+ GitRepository currentRepository = GitBranchUtil.getCurrentRepository(project);
+ return currentRepository != null ? currentRepository.getRoot() : roots.get(0);
+ }
+
protected final void runFinalTasks(Project project, GitVcs vcs, Set affectedRoots, String actionName,
List exceptions) {
VcsFileUtil.refreshFiles(project, affectedRoots);
diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties
index a141fbe4cb86..7b1ad1821161 100644
--- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties
+++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties
@@ -256,7 +256,7 @@ rebase.editor.button=Start Rebasing
rebase.editor.comment.column=Comment
rebase.editor.commit.column=Commit
rebase.editor.invalid.entryset=No commits found to rebase
-rebase.editor.invalid.squash=The first non-skip commit can't be marked as {0} since it merges commit with the previous commit.
+rebase.editor.invalid.squash=The first non-skip commit can''t be marked as {0} since it merges commit with the previous commit.
rebase.editor.message=Reorder and edit &rebased commits
rebase.editor.move.down.tooltip=Move commit down (commit will be applied later)
rebase.editor.move.down=Move &Down
diff --git a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java
index e0c9aa035257..7514aa940bbe 100644
--- a/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java
+++ b/plugins/git4idea/src/git4idea/rebase/GitRebaseEditor.java
@@ -21,14 +21,21 @@ import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.Cell;
+import com.intellij.ui.TableSpeedSearch;
+import com.intellij.ui.table.JBTable;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ListWithSelection;
+import com.intellij.util.PairFunction;
import com.intellij.util.ui.ComboBoxTableCellRenderer;
+import com.intellij.util.ui.JBUI;
+import com.intellij.util.ui.UIUtil;
import git4idea.GitUtil;
import git4idea.config.GitConfigUtil;
import git4idea.i18n.GitBundle;
import git4idea.util.StringScanner;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
@@ -53,7 +60,7 @@ public class GitRebaseEditor extends DialogWrapper {
/**
* The table that lists all commits
*/
- private JTable myCommitsTable;
+ private JBTable myCommitsTable;
/**
* The move up button
*/
@@ -115,6 +122,7 @@ public class GitRebaseEditor extends DialogWrapper {
myTableModel.load(file);
myCommitsTable.setModel(myTableModel);
myCommitsTable.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+ myCommitsTable.setIntercellSpacing(JBUI.emptySize());
final JComboBox editorComboBox = new JComboBox();
for (Object option : GitRebaseEntry.Action.values()) {
@@ -128,9 +136,9 @@ public class GitRebaseEditor extends DialogWrapper {
public void valueChanged(final ListSelectionEvent e) {
myViewButton.setEnabled(myCommitsTable.getSelectedRowCount() == 1);
final ListSelectionModel selectionModel = myCommitsTable.getSelectionModel();
- myMoveUpButton.setEnabled( selectionModel.getMinSelectionIndex() > 0);
- myMoveDownButton.setEnabled( selectionModel.getMaxSelectionIndex() != -1 &&
- selectionModel.getMaxSelectionIndex() < myTableModel.myEntries.size() - 1);
+ myMoveUpButton.setEnabled(selectionModel.getMinSelectionIndex() > 0);
+ myMoveDownButton.setEnabled(selectionModel.getMaxSelectionIndex() != -1 &&
+ selectionModel.getMaxSelectionIndex() < myTableModel.myEntries.size() - 1);
}
});
myViewButton.addActionListener(new ActionListener() {
@@ -152,8 +160,37 @@ public class GitRebaseEditor extends DialogWrapper {
validateFields();
}
});
+
+ installSpeedSearch();
+
+ adjustColumnWidth(0);
+ adjustColumnWidth(1);
init();
}
+
+ private void installSpeedSearch() {
+ new TableSpeedSearch(myCommitsTable, new PairFunction