From 74905c8473cefffff4c63f13ae377e1d8b8f71fe Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 18 May 2015 13:38:30 +0200 Subject: [PATCH 01/36] Write snapshot even in case of sys.exit(0) (PY-15905) --- python/helpers/profiler/run_profiler.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/helpers/profiler/run_profiler.py b/python/helpers/profiler/run_profiler.py index dc60a201d37b..1b01dea126fc 100644 --- a/python/helpers/profiler/run_profiler.py +++ b/python/helpers/profiler/run_profiler.py @@ -81,10 +81,11 @@ class Profiler(object): self.start_profiling() - pydev_imports.execfile(file, globals, globals) # execute the script - - self.stop_profiling() - self.save_snapshot(0, generate_snapshot_filepath(base_snapshot_path, remote_run), remote_run) + try: + pydev_imports.execfile(file, globals, globals) # execute the script + finally: + self.stop_profiling() + self.save_snapshot(0, generate_snapshot_filepath(base_snapshot_path, remote_run), remote_run) def start_profiling(self): self.profiling_backend.enable() From 4830cb1b841825c34b6f9a596917dd856332690b Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 18 May 2015 14:22:01 +0200 Subject: [PATCH 02/36] Add script to python path when running in console (PY-15801). --- python/helpers/pydev/pydev_run_in_console.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/helpers/pydev/pydev_run_in_console.py b/python/helpers/pydev/pydev_run_in_console.py index 4224dd1ca999..9d5ac3b207fa 100644 --- a/python/helpers/pydev/pydev_run_in_console.py +++ b/python/helpers/pydev/pydev_run_in_console.py @@ -23,6 +23,7 @@ def run_file(file, globals=None, locals=None): if locals is None: locals = globals + sys.path.insert(0, os.path.split(file)[0]) print('Running %s'%file) pydev_imports.execfile(file, globals, locals) # execute the script From 63a58f0afab2571df384992a8aad151748782a2b Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 18 May 2015 15:01:29 +0200 Subject: [PATCH 03/36] Don't resolve name to import definer (PY-15929). --- .../src/com/jetbrains/python/debugger/PyDebugProcess.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 7eed689b46ee..0ab8651f56fd 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -61,6 +61,7 @@ import com.jetbrains.python.console.PythonDebugLanguageConsoleView; import com.jetbrains.python.console.pydev.PydevCompletionVariant; import com.jetbrains.python.debugger.pydev.*; import com.jetbrains.python.psi.PyFunction; +import com.jetbrains.python.psi.PyImportElement; import com.jetbrains.python.psi.resolve.PyResolveUtil; import com.jetbrains.python.psi.types.PyClassType; import com.jetbrains.python.psi.types.PyType; @@ -854,7 +855,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() { @Override public boolean execute(@NotNull PsiElement element, @NotNull ResolveState state) { - elementRef.set(element); + if (!(element instanceof PyImportElement)) { + if (elementRef.isNull()) { + elementRef.set(element); + } + } return false; } From 344c7c74a80b2e467c21a3298546af1d2eb96513 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 13 May 2015 21:07:59 +0300 Subject: [PATCH 04/36] PY-15867 Initial cleanup in AddCallSuperQuickFix --- .../quickfix/AddCallSuperQuickFix.java | 77 +++++++++++-------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java index c8ac88af9da1..0243cf6c0463 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java @@ -32,10 +32,10 @@ import java.util.List; /** * For: * class B(A): - * def __init__(self): - * A.__init__(self) # inserted - * print "Constructor B was called" - * + * def __init__(self): + * A.__init__(self) # inserted + * print "Constructor B was called" + *

* User: catherine */ public class AddCallSuperQuickFix implements LocalQuickFix { @@ -52,7 +52,7 @@ public class AddCallSuperQuickFix implements LocalQuickFix { } public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { - PyFunction problemFunction = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PyFunction.class); + final PyFunction problemFunction = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PyFunction.class); if (problemFunction == null) return; final StringBuilder superCall = new StringBuilder(); final PyClass klass = problemFunction.getContainingClass(); @@ -66,16 +66,18 @@ public class AddCallSuperQuickFix implements LocalQuickFix { boolean addComma = true; if (klass.isNewStyleClass()) { addComma = false; - if (LanguageLevel.forElement(klass).isPy3K()) + if (LanguageLevel.forElement(klass).isPy3K()) { superCall.append("super().__init__("); - else + } + else { superCall.append("super(").append(klass.getName()).append(", self).__init__("); + } } else { superCall.append(superClass.getName()); superCall.append(".__init__(self"); } - StringBuilder newFunction = new StringBuilder("def __init__(self"); + final StringBuilder newFunction = new StringBuilder("def __init__(self"); buildParameterList(problemFunction, superInit, superCall, newFunction, addComma); @@ -84,14 +86,16 @@ public class AddCallSuperQuickFix implements LocalQuickFix { PyExpression docstring = null; final PyStatement[] statements = statementList.getStatements(); if (statements.length != 0 && statements[0] instanceof PyExpressionStatement) { - PyExpressionStatement st = (PyExpressionStatement)statements[0]; - if (st.getExpression() instanceof PyStringLiteralExpression) + final PyExpressionStatement st = (PyExpressionStatement)statements[0]; + if (st.getExpression() instanceof PyStringLiteralExpression) { docstring = st.getExpression(); + } } newFunction.append("):\n\t"); - if (docstring != null) + if (docstring != null) { newFunction.append(docstring.getText()).append("\n\t"); + } newFunction.append(superCall).append("\n\t"); boolean first = true; for (PyStatement statement : statements) { @@ -102,22 +106,22 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunction.append(statement.getText()).append("\n\t"); } - problemFunction.replace( - PyElementGenerator.getInstance(project).createFromText(LanguageLevel.forElement(problemFunction), PyFunction.class, - newFunction.toString())); + final PyElementGenerator generator = PyElementGenerator.getInstance(project); + problemFunction.replace(generator.createFromText(LanguageLevel.forElement(problemFunction), PyFunction.class, newFunction.toString())); } - private static void buildParameterList(@NotNull final PyFunction problemFunction, - @NotNull final PyFunction superInit, - @NotNull final StringBuilder superCall, - @NotNull final StringBuilder newFunction, boolean addComma) { + private static void buildParameterList(@NotNull PyFunction problemFunction, + @NotNull PyFunction superInit, + @NotNull StringBuilder superCall, + @NotNull StringBuilder newFunction, + boolean addComma) { final PyParameter[] parameters = problemFunction.getParameterList().getParameters(); final List problemParams = new ArrayList(); final List functionParams = new ArrayList(); String starName = null; String doubleStarName = null; for (int i = 1; i != parameters.length; i++) { - PyParameter p = parameters[i]; + final PyParameter p = parameters[i]; functionParams.add(p.getName()); if (p.getText().startsWith("**")) { doubleStarName = p.getText(); @@ -134,43 +138,52 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunction.append(",").append(p.getText()); } - addParametersFromSuper(superInit, superCall, newFunction, addComma, problemParams, functionParams, starName, doubleStarName); + addParametersFromSuper(superInit, superCall, newFunction, problemParams, functionParams, starName, doubleStarName, addComma); } - private static void addParametersFromSuper(@NotNull final PyFunction superInit, @NotNull final StringBuilder superCall, - @NotNull final StringBuilder newFunction, boolean addComma, - @NotNull final List problemParams, @NotNull final List functionParams, - @Nullable String starName, @Nullable String doubleStarName) { + private static void addParametersFromSuper(@NotNull PyFunction superInit, + @NotNull StringBuilder superCall, + @NotNull StringBuilder newFunction, + @NotNull List problemParams, + @NotNull List functionParams, + @Nullable String starName, + @Nullable String doubleStarName, + boolean addComma) { final PyParameterList paramList = superInit.getParameterList(); - PyParameter[] parameters = paramList.getParameters(); + final PyParameter[] parameters = paramList.getParameters(); boolean addDouble = false; boolean addStar = false; for (int i = 1; i != parameters.length; i++) { - PyParameter p = parameters[i]; + final PyParameter p = parameters[i]; if (p.getDefaultValue() != null) continue; final String param = p.getName(); - String paramText = p.getText(); + final String paramText = p.getText(); if (paramText.startsWith("**")) { addDouble = true; - if (doubleStarName == null) + if (doubleStarName == null) { doubleStarName = p.getText(); + } continue; } if (paramText.startsWith("*")) { addStar = true; - if (starName == null) + if (starName == null) { starName = p.getText(); + } continue; } - if (addComma) + if (addComma) { superCall.append(","); + } superCall.append(param); - if (!functionParams.contains(param)) + if (!functionParams.contains(param)) { newFunction.append(",").append(param); + } addComma = true; } - for(String p : problemParams) + for (String p : problemParams) { newFunction.append(",").append(p); + } if (starName != null) { newFunction.append(",").append(starName); if (addStar) { From e75faff0f9af7378ef2f78a40f99021ac00296ed Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Thu, 14 May 2015 13:13:12 +0300 Subject: [PATCH 05/36] PY-15867 Improve AddCallSuperQuickFix to handle varargs and keyword-only parameters --- .../quickfix/AddCallSuperQuickFix.java | 299 +++++++++++++----- .../AddCallSuperKeywordOnlyParamInInit.py | 7 + ...ddCallSuperKeywordOnlyParamInInit_after.py | 7 + ...AddCallSuperKeywordOnlyParamInSuperInit.py | 8 + ...lSuperKeywordOnlyParamInSuperInit_after.py | 8 + .../AddCallSuperSingleStarParamInSuperInit.py | 7 + ...ngleStarParamInSuperInitAndVarargInInit.py | 7 + ...arParamInSuperInitAndVarargInInit_after.py | 7 + ...llSuperSingleStarParamInSuperInit_after.py | 7 + .../com/jetbrains/python/PyQuickFixTest.java | 43 +++ 10 files changed, 320 insertions(+), 80 deletions(-) create mode 100644 python/testData/inspections/AddCallSuperKeywordOnlyParamInInit.py create mode 100644 python/testData/inspections/AddCallSuperKeywordOnlyParamInInit_after.py create mode 100644 python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit.py create mode 100644 python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit_after.py create mode 100644 python/testData/inspections/AddCallSuperSingleStarParamInSuperInit.py create mode 100644 python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py create mode 100644 python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit_after.py create mode 100644 python/testData/inspections/AddCallSuperSingleStarParamInSuperInit_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java index 0243cf6c0463..52087e9fbcb3 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java @@ -18,7 +18,11 @@ package com.jetbrains.python.inspections.quickfix; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Couple; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; import com.jetbrains.python.psi.*; @@ -63,7 +67,7 @@ public class AddCallSuperQuickFix implements LocalQuickFix { final PyClass superClass = superClasses[0]; final PyFunction superInit = superClass.findMethodByName(PyNames.INIT, true); if (superInit == null) return; - boolean addComma = true; + final boolean addComma; if (klass.isNewStyleClass()) { addComma = false; if (LanguageLevel.forElement(klass).isPy3K()) { @@ -74,14 +78,28 @@ public class AddCallSuperQuickFix implements LocalQuickFix { } } else { + addComma = true; superCall.append(superClass.getName()); superCall.append(".__init__(self"); } final StringBuilder newFunction = new StringBuilder("def __init__(self"); - buildParameterList(problemFunction, superInit, superCall, newFunction, addComma); + final Couple> couple = buildNewFunctionParamsAndSuperInitCallArgs(problemFunction, superInit); + final List newParameters = couple.getFirst(); + if (!newParameters.isEmpty()) { + newFunction.append(", "); + } + StringUtil.join(newParameters, ", ", newFunction); + newFunction.append("):\n\t"); + + final List superCallArguments = couple.getSecond(); + if (addComma && !superCallArguments.isEmpty()) { + superCall.append(", "); + } + StringUtil.join(superCallArguments, ", ", superCall); superCall.append(")"); + final PyStatementList statementList = problemFunction.getStatementList(); PyExpression docstring = null; final PyStatement[] statements = statementList.getStatements(); @@ -92,7 +110,6 @@ public class AddCallSuperQuickFix implements LocalQuickFix { } } - newFunction.append("):\n\t"); if (docstring != null) { newFunction.append(docstring.getText()).append("\n\t"); } @@ -110,94 +127,216 @@ public class AddCallSuperQuickFix implements LocalQuickFix { problemFunction.replace(generator.createFromText(LanguageLevel.forElement(problemFunction), PyFunction.class, newFunction.toString())); } - private static void buildParameterList(@NotNull PyFunction problemFunction, - @NotNull PyFunction superInit, - @NotNull StringBuilder superCall, - @NotNull StringBuilder newFunction, - boolean addComma) { - final PyParameter[] parameters = problemFunction.getParameterList().getParameters(); - final List problemParams = new ArrayList(); - final List functionParams = new ArrayList(); - String starName = null; - String doubleStarName = null; - for (int i = 1; i != parameters.length; i++) { - final PyParameter p = parameters[i]; - functionParams.add(p.getName()); - if (p.getText().startsWith("**")) { - doubleStarName = p.getText(); - continue; + @NotNull + private static Couple> buildNewFunctionParamsAndSuperInitCallArgs(@NotNull PyFunction origInit, + @NotNull PyFunction superInit) { + final List newFunctionParams = new ArrayList(); + final List superCallArgs = new ArrayList(); + + final ParametersInfo origInfo = new ParametersInfo(origInit.getParameterList()); + final ParametersInfo superInfo = new ParametersInfo(superInit.getParameterList()); + + // Required parameters (not-keyword) + for (PyParameter param : origInfo.getRequiredParameters()) { + newFunctionParams.add(param.getText()); + } + for (PyParameter param : superInfo.getRequiredParameters()) { + if (!origInfo.containsRequiredParam(param.getName())) { + newFunctionParams.add(param.getText()); } - if (p.getText().startsWith("*")) { - starName = p.getText(); - continue; - } - if (p.getDefaultValue() != null) { - problemParams.add(p.getText()); - continue; - } - newFunction.append(",").append(p.getText()); + superCallArgs.add(param.getName()); } - addParametersFromSuper(superInit, superCall, newFunction, problemParams, functionParams, starName, doubleStarName, addComma); + // Optional parameters (not-keyword) + for (PyParameter param : origInfo.getOptionalParameters()) { + newFunctionParams.add(param.getText()); + } + + // Positional vararg + PyParameter starredParam = null; + if (origInfo.getPositionalContainerParameter() != null) { + starredParam = origInfo.getPositionalContainerParameter(); + } + else if (superInfo.getPositionalContainerParameter() != null) { + starredParam = superInfo.getPositionalContainerParameter(); + } + else if (origInfo.getSingleStarParameter() != null) { + starredParam = origInfo.getSingleStarParameter(); + } + else if (superInfo.getSingleStarParameter() != null) { + starredParam = superInfo.getSingleStarParameter(); + } + if (starredParam != null) { + newFunctionParams.add(starredParam.getText()); + if (superInfo.getPositionalContainerParameter() != null) { + superCallArgs.add("*" + starredParam.getName()); + } + } + + // Required keyword-only parameters + for (PyParameter param : origInfo.getRequiredKeywordOnlyParameters()) { + newFunctionParams.add(param.getText()); + } + for (PyParameter param : superInfo.getRequiredKeywordOnlyParameters()) { + if (!origInfo.containsRequiredKeywordOnlyParameter(param.getName())) { + newFunctionParams.add(param.getText()); + } + superCallArgs.add(param.getName() + "=" + param.getName()); + } + + // Optional keyword-only parameters + for (PyParameter param : origInfo.getOptionalKeywordOnlyParameters()) { + newFunctionParams.add(param.getText()); + } + + // Keyword vararg + PyParameter doubleStarredParam = null; + if (origInfo.getKeywordContainerParameter() != null) { + doubleStarredParam = origInfo.getKeywordContainerParameter(); + } + else if (superInfo.getKeywordContainerParameter() != null) { + doubleStarredParam = superInfo.getKeywordContainerParameter(); + } + if (doubleStarredParam != null) { + newFunctionParams.add(doubleStarredParam.getText()); + if (superInfo.getKeywordContainerParameter() != null) { + superCallArgs.add("**" + doubleStarredParam.getName()); + } + } + return Couple.of(newFunctionParams, superCallArgs); } - private static void addParametersFromSuper(@NotNull PyFunction superInit, - @NotNull StringBuilder superCall, - @NotNull StringBuilder newFunction, - @NotNull List problemParams, - @NotNull List functionParams, - @Nullable String starName, - @Nullable String doubleStarName, - boolean addComma) { - final PyParameterList paramList = superInit.getParameterList(); - final PyParameter[] parameters = paramList.getParameters(); - boolean addDouble = false; - boolean addStar = false; - for (int i = 1; i != parameters.length; i++) { - final PyParameter p = parameters[i]; - if (p.getDefaultValue() != null) continue; - final String param = p.getName(); - final String paramText = p.getText(); - if (paramText.startsWith("**")) { - addDouble = true; - if (doubleStarName == null) { - doubleStarName = p.getText(); + private static class ParametersInfo { + + private final PyParameter mySelfParam; + /** + * Parameters without default value that come before first "*..." parameter. + */ + private final List myRequiredParams = new ArrayList(); + /** + * Parameters with default value that come before first "*..." parameter. + */ + private final List myOptionalParams = new ArrayList(); + /** + * Parameter of form "*args" (positional vararg), not the same as single "*". + */ + private final PyParameter myPositionalContainerParam; + /** + * Parameter "*", that is used to delimit normal and keyword-only parameters. + */ + private final PyParameter mySingleStarParam; + /** + * Parameters without default value that come after first "*..." parameter. + */ + private final List myRequiredKwOnlyParams = new ArrayList(); + /** + * Parameters with default value that come after first "*..." parameter. + */ + private final List myOptionalKwOnlyParams = new ArrayList(); + /** + * Parameter of form "**kwargs" (keyword vararg). + */ + private final PyParameter myKeywordContainerParam; + + public ParametersInfo(@NotNull PyParameterList parameterList) { + PyParameter positionalContainer = null; + PyParameter singleStarParam = null; + PyParameter keywordContainer = null; + PyParameter selfParam = null; + + for (PyParameter param : parameterList.getParameters()) { + if (param.isSelf()) { + selfParam = param; } - continue; - } - if (paramText.startsWith("*")) { - addStar = true; - if (starName == null) { - starName = p.getText(); + else if (param.getText().equals("*")) { + singleStarParam = param; + } + else if (param.getText().startsWith("**")) { + keywordContainer = param; + } + else if (param.getText().startsWith("*")) { + positionalContainer = param; + } + else if (positionalContainer == null && singleStarParam == null) { + if (param.hasDefaultValue()) { + myOptionalParams.add(param); + } + else { + myRequiredParams.add(param); + } + } + else { + if (param.hasDefaultValue()) { + myOptionalKwOnlyParams.add(param); + } + else { + myRequiredKwOnlyParams.add(param); + } } - continue; } - if (addComma) { - superCall.append(","); - } - superCall.append(param); - if (!functionParams.contains(param)) { - newFunction.append(",").append(param); - } - addComma = true; + + mySelfParam = selfParam; + myPositionalContainerParam = positionalContainer; + mySingleStarParam = singleStarParam; + myKeywordContainerParam = keywordContainer; } - for (String p : problemParams) { - newFunction.append(",").append(p); + + public boolean containsRequiredParam(@Nullable final String name) { + return ContainerUtil.exists(myRequiredParams, new Condition() { + @Override + public boolean value(PyParameter parameter) { + return name != null && name.equals(parameter.getName()); + } + }); } - if (starName != null) { - newFunction.append(",").append(starName); - if (addStar) { - if (addComma) superCall.append(","); - superCall.append(starName); - addComma = true; - } + + public boolean containsRequiredKeywordOnlyParameter(@Nullable final String name) { + return ContainerUtil.exists(myRequiredKwOnlyParams, new Condition() { + @Override + public boolean value(PyParameter parameter) { + return name != null && name.equals(parameter.getName()); + } + }); } - if (doubleStarName != null) { - newFunction.append(",").append(doubleStarName); - if (addDouble) { - if (addComma) superCall.append(","); - superCall.append(doubleStarName); - } + + @Nullable + public PyParameter getSelfParameter() { + return mySelfParam; + } + + @NotNull + public List getRequiredParameters() { + return myRequiredParams; + } + + @NotNull + public List getOptionalParameters() { + return myOptionalParams; + } + + @Nullable + public PyParameter getPositionalContainerParameter() { + return myPositionalContainerParam; + } + + @Nullable + public PyParameter getSingleStarParameter() { + return mySingleStarParam; + } + + @NotNull + public List getRequiredKeywordOnlyParameters() { + return myRequiredKwOnlyParams; + } + + @NotNull + public List getOptionalKeywordOnlyParameters() { + return myOptionalKwOnlyParams; + } + + @Nullable + public PyParameter getKeywordContainerParameter() { + return myKeywordContainerParam; } } } diff --git a/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit.py b/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit.py new file mode 100644 index 000000000000..e1da8962d217 --- /dev/null +++ b/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, a): + pass + +class B(A): + def __init__(self, b, c=1, *args, kw_only): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit_after.py b/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit_after.py new file mode 100644 index 000000000000..925cac6746a3 --- /dev/null +++ b/python/testData/inspections/AddCallSuperKeywordOnlyParamInInit_after.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, a): + pass + +class B(A): + def __init__(self, b, a, c=1, *args, kw_only): + super().__init__(a) \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit.py b/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit.py new file mode 100644 index 000000000000..5248dd92742a --- /dev/null +++ b/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit.py @@ -0,0 +1,8 @@ +class A: + def __init__(self, a, b=1, *args, kw_only): + pass + + +class B(A): + def __init__(self, c): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit_after.py b/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit_after.py new file mode 100644 index 000000000000..0ee340e47d36 --- /dev/null +++ b/python/testData/inspections/AddCallSuperKeywordOnlyParamInSuperInit_after.py @@ -0,0 +1,8 @@ +class A: + def __init__(self, a, b=1, *args, kw_only): + pass + + +class B(A): + def __init__(self, c, a, *args, kw_only): + super().__init__(a, *args, kw_only=kw_only) \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit.py b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit.py new file mode 100644 index 000000000000..7ff489252191 --- /dev/null +++ b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, *, kw_only, optional_kw_only=None): + pass + +class B(A): + def __init__(self): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py new file mode 100644 index 000000000000..afca366ff1e3 --- /dev/null +++ b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, *, kw_only): + pass + +class B(A): + def __init__(self, *args, another_kw_only): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit_after.py b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit_after.py new file mode 100644 index 000000000000..01cf279b21fc --- /dev/null +++ b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInitAndVarargInInit_after.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, *, kw_only): + pass + +class B(A): + def __init__(self, *args, another_kw_only, kw_only): + super().__init__(kw_only=kw_only) \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit_after.py b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit_after.py new file mode 100644 index 000000000000..1eb8c4228300 --- /dev/null +++ b/python/testData/inspections/AddCallSuperSingleStarParamInSuperInit_after.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, *, kw_only, optional_kw_only=None): + pass + +class B(A): + def __init__(self, *, kw_only): + super().__init__(kw_only=kw_only) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 9a55254d8287..6ca5fe3e4211 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -360,6 +360,49 @@ public class PyQuickFixTest extends PyTestCase { PyBundle.message("QFIX.add.super"), true, true); } + + // PY-15867 + public void testAddCallSuperKeywordOnlyParamInSuperInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest("AddCallSuperKeywordOnlyParamInSuperInit.py", PyMissingConstructorInspection.class, + PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperKeywordOnlyParamInInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest("AddCallSuperKeywordOnlyParamInInit.py", PyMissingConstructorInspection.class, + PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperSingleStarParamInSuperInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest("AddCallSuperSingleStarParamInSuperInit.py", PyMissingConstructorInspection.class, + PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperSingleStarParamInSuperInitAndVarargInInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + @Override + public void run() { + doInspectionTest("AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py", PyMissingConstructorInspection.class, + PyBundle.message("QFIX.add.super"), true, true); + } + }); + + } + //PY-491, PY-13297 public void testAddEncoding() { doInspectionTest("AddEncoding.py", PyMandatoryEncodingInspection.class, From 482009a18020164dbeec94a0cdcd1a9de64f9966 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Fri, 15 May 2015 01:44:00 +0300 Subject: [PATCH 06/36] PY-11561 Preserve existing type annotations in the modified constructor --- .../inspections/quickfix/AddCallSuperQuickFix.java | 6 +++++- .../inspections/AddCallSuperAnnotations_after.py | 2 +- .../AddCallSuperTypeAnnotationsPreserved.py | 7 +++++++ .../AddCallSuperTypeAnnotationsPreserved_after.py | 7 +++++++ .../testSrc/com/jetbrains/python/PyQuickFixTest.java | 10 ++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 python/testData/inspections/AddCallSuperTypeAnnotationsPreserved.py create mode 100644 python/testData/inspections/AddCallSuperTypeAnnotationsPreserved_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java index 52087e9fbcb3..193104bdd3bb 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java @@ -91,7 +91,11 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunction.append(", "); } StringUtil.join(newParameters, ", ", newFunction); - newFunction.append("):\n\t"); + newFunction.append(")"); + if (problemFunction.getAnnotation() != null) { + newFunction.append(problemFunction.getAnnotation().getText()); + } + newFunction.append(":\n\t"); final List superCallArguments = couple.getSecond(); if (addComma && !superCallArguments.isEmpty()) { diff --git a/python/testData/inspections/AddCallSuperAnnotations_after.py b/python/testData/inspections/AddCallSuperAnnotations_after.py index 4bfd08c375e3..ddee178f3ace 100644 --- a/python/testData/inspections/AddCallSuperAnnotations_after.py +++ b/python/testData/inspections/AddCallSuperAnnotations_after.py @@ -4,5 +4,5 @@ class Example1: class Example2(Example1): - def __init__(self, field1): + def __init__(self, field1: str): super().__init__(field1) \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved.py b/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved.py new file mode 100644 index 000000000000..76b33e20063e --- /dev/null +++ b/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, a:int, b:float, *args:tuple, c:complex, **kwargs:dict) -> None: + pass + +class B(A): + def __init__(self, d:str, *, e:bytes) -> list: + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved_after.py b/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved_after.py new file mode 100644 index 000000000000..c8b5b3e67c00 --- /dev/null +++ b/python/testData/inspections/AddCallSuperTypeAnnotationsPreserved_after.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, a:int, b:float, *args:tuple, c:complex, **kwargs:dict) -> None: + pass + +class B(A): + def __init__(self, d:str, a:int, b:float, *args:tuple, e:bytes, c:complex, **kwargs:dict) -> list: + super().__init__(a, b, *args, c=c, **kwargs) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 6ca5fe3e4211..99a0dc27efbb 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -400,7 +400,17 @@ public class PyQuickFixTest extends PyTestCase { PyBundle.message("QFIX.add.super"), true, true); } }); + } + // PY-15867 + public void testAddCallSuperTypeAnnotationsPreserved() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + @Override + public void run() { + doInspectionTest("AddCallSuperTypeAnnotationsPreserved.py", PyMissingConstructorInspection.class, + PyBundle.message("QFIX.add.super"), true, true); + } + }); } //PY-491, PY-13297 From e3592fe5c4b75242cc60b057fd2156268a17cf59 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 12:42:44 +0300 Subject: [PATCH 07/36] PY-15867 Clean up in PyQuickFixTest and Py3QuickFixTest * Introduce overloaded version of doInspectionTest that doesn't require name of test data file * Add a few missing request IDs and place existing ones consistently above corresponding methods * Remove redundant "Py" and "QuickFix" parts from test names --- .../com/jetbrains/python/Py3QuickFixTest.java | 45 ++- .../com/jetbrains/python/PyQuickFixTest.java | 326 +++++++++--------- 2 files changed, 190 insertions(+), 181 deletions(-) diff --git a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java index f757da9f3fac..6d7389607e5c 100644 --- a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java @@ -24,6 +24,7 @@ import com.jetbrains.python.inspections.PyMissingConstructorInspection; import com.jetbrains.python.inspections.PyStatementEffectInspection; import com.jetbrains.python.psi.LanguageLevel; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; @TestDataPath("$CONTENT_ROOT/../testData/inspections/") public class Py3QuickFixTest extends PyTestCase { @@ -32,39 +33,42 @@ public class Py3QuickFixTest extends PyTestCase { return PyTestCase.ourPy3Descriptor; } + // PY-13685 public void testReplacePrintEnd() { runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() { @Override public void run() { - doInspectionTest("ReplacePrintEnd.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); - }}); + doInspectionTest(PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); + } + }); } + // PY-13685 public void testReplacePrintComment() { runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() { @Override public void run() { - doInspectionTest("ReplacePrintComment.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, - true); - }}); + doInspectionTest(PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); + } + }); } + // PY-13685 public void testReplaceExecComment() { runWithLanguageLevel(LanguageLevel.PYTHON34, new Runnable() { @Override public void run() { - doInspectionTest("ReplaceExecComment.py", PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, - true); - }}); + doInspectionTest(PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); + } + }); } + // PY-11561 public void testAddCallSuperAnnotations() { runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { @Override public void run() { - doInspectionTest("AddCallSuperAnnotations.py", - PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } @@ -75,9 +79,16 @@ public class Py3QuickFixTest extends PyTestCase { return PythonTestUtil.getTestDataPath() + "/inspections/"; } - protected void doInspectionTest(@TestDataFile @NonNls String testFileName, - final Class inspectionClass, - @NonNls String quickFixName, + private void doInspectionTest(@NotNull Class inspectionClass, + @NotNull String quickFixName, + boolean applyFix, + boolean available) { + doInspectionTest(getTestName(false) + ".py", inspectionClass, quickFixName, applyFix, available); + } + + protected void doInspectionTest(@TestDataFile @NonNls @NotNull String testFileName, + @NotNull Class inspectionClass, + @NonNls @NotNull String quickFixName, boolean applyFix, boolean available) { doInspectionTest(new String[]{testFileName}, inspectionClass, quickFixName, applyFix, available); @@ -93,9 +104,9 @@ public class Py3QuickFixTest extends PyTestCase { * @param available true if the fix should be available, false if it should be explicitly not available. * @throws Exception */ - protected void doInspectionTest(@NonNls String[] testFiles, - final Class inspectionClass, - @NonNls String quickFixName, + protected void doInspectionTest(@NonNls @NotNull String[] testFiles, + @NotNull Class inspectionClass, + @NonNls @NotNull String quickFixName, boolean applyFix, boolean available) { myFixture.enableInspections(inspectionClass); diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 99a0dc27efbb..05f8258b0e68 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -27,6 +27,7 @@ import com.jetbrains.python.inspections.*; import com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferencesInspection; import com.jetbrains.python.psi.LanguageLevel; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; /** * @author dcheryasov @@ -47,15 +48,19 @@ public class PyQuickFixTest extends PyTestCase { } public void testAddImport() { - doInspectionTest(new String[] { "AddImport.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true); + doInspectionTest(new String[]{"AddImport.py", "ImportTarget.py"}, PyUnresolvedReferencesInspection.class, + "Import 'ImportTarget'", true, true); } public void testAddImportDoc() { - doInspectionTest(new String[] { "AddImportDoc.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true); + doInspectionTest(new String[]{"AddImportDoc.py", "ImportTarget.py"}, PyUnresolvedReferencesInspection.class, + "Import 'ImportTarget'", true, true); } - public void testAddImportDocComment() { // PY-728 - doInspectionTest(new String[] { "AddImportDocComment.py", "ImportTarget.py" }, PyUnresolvedReferencesInspection.class, "Import 'ImportTarget'", true, true); + // PY-728 + public void testAddImportDocComment() { + doInspectionTest(new String[]{"AddImportDocComment.py", "ImportTarget.py"}, PyUnresolvedReferencesInspection.class, + "Import 'ImportTarget'", true, true); } public void testImportFromModule() { @@ -73,7 +78,8 @@ public class PyQuickFixTest extends PyTestCase { assertEquals("Import 'module.MyOldStyleClass'", intention.getText()); } - public void testImportFromModuleStar() { // PY-6302 + // PY-6302 + public void testImportFromModuleStar() { myFixture.enableInspections(PyUnresolvedReferencesInspection.class); myFixture.copyDirectoryToProject("importFromModuleStar", ""); myFixture.configureFromTempProjectFile("source.py"); @@ -91,7 +97,8 @@ public class PyQuickFixTest extends PyTestCase { settings.PREFER_FROM_IMPORT = false; settings.HIGHLIGHT_UNUSED_IMPORTS = false; try { - doInspectionTest(new String[]{"QualifyByImport.py", "QualifyByImportFoo.py"}, PyUnresolvedReferencesInspection.class, PyBundle.message("ACT.qualify.with.module"), true, true); + doInspectionTest(new String[]{"QualifyByImport.py", "QualifyByImportFoo.py"}, PyUnresolvedReferencesInspection.class, + PyBundle.message("ACT.qualify.with.module"), true, true); } finally { settings.PREFER_FROM_IMPORT = oldPreferFrom; @@ -104,7 +111,8 @@ public class PyQuickFixTest extends PyTestCase { boolean oldHighlightUnused = settings.HIGHLIGHT_UNUSED_IMPORTS; settings.HIGHLIGHT_UNUSED_IMPORTS = false; try { - doInspectionTest(new String[]{"AddToImportFromList.py", "AddToImportFromFoo.py"}, PyUnresolvedReferencesInspection.class, "Import 'foo(a) from AddToImportFromFoo'", true, true); + doInspectionTest(new String[]{"AddToImportFromList.py", "AddToImportFromFoo.py"}, PyUnresolvedReferencesInspection.class, + "Import 'foo(a) from AddToImportFromFoo'", true, true); } finally { settings.HIGHLIGHT_UNUSED_IMPORTS = oldHighlightUnused; @@ -115,90 +123,86 @@ public class PyQuickFixTest extends PyTestCase { // TODO: add tests for stub indexes-based autoimport of unimported somehow. public void testAddSelf() { - doInspectionTest("AddSelf.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "self"), true, true); + doInspectionTest(PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "self"), true, true); } public void testReplacePrint() { - doInspectionTest("ReplacePrint.py", PyCompatibilityInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); + doInspectionTest(PyCompatibilityInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); } - public void testAddSelfFunction() { //PY-4556 - doInspectionTest("AddSelfFunction.py", - PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "get_a", "self"), true, true); + // PY-4556 + public void testAddSelfFunction() { + doInspectionTest("AddSelfFunction.py", PyUnresolvedReferencesInspection.class, + PyBundle.message("QFIX.unresolved.reference", "get_a", "self"), true, true); } - public void testAddSelfToClassmethod() { //PY-9721 - doInspectionTest("AddSelfToClassmethod.py", - PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference", "foo", "cls"), true, true); + // PY-9721 + public void testAddSelfToClassmethod() { + doInspectionTest("AddSelfToClassmethod.py", PyUnresolvedReferencesInspection.class, + PyBundle.message("QFIX.unresolved.reference", "foo", "cls"), true, true); } public void testAddCls() { - doInspectionTest("AddCls.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "cls"), true, true); + doInspectionTest(PyMethodParametersInspection.class, PyBundle.message("QFIX.add.parameter.self", "cls"), true, true); } public void testRenameToSelf() { - doInspectionTest("RenameToSelf.py", PyMethodParametersInspection.class, PyBundle.message("QFIX.rename.parameter.to.$0", "self"), true, - true); + doInspectionTest(PyMethodParametersInspection.class, PyBundle.message("QFIX.rename.parameter.to.$0", "self"), true, true); } public void testRemoveTrailingSemicolon() { - doInspectionTest("RemoveTrailingSemicolon.py", PyTrailingSemicolonInspection.class, PyBundle.message("QFIX.remove.trailing.semicolon"), - true, true); + doInspectionTest(PyTrailingSemicolonInspection.class, PyBundle.message("QFIX.remove.trailing.semicolon"), true, true); } public void testDictCreation() { - doInspectionTest("DictCreation.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); + doInspectionTest(PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); } - public void testDictCreationTuple() { //PY-6283 - doInspectionTest("DictCreationTuple.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); + // PY-6283 + public void testDictCreationTuple() { + doInspectionTest(PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); } - public void testDictCreationDuplicate() { //PY-7318 - doInspectionTest("DictCreationDuplicate.py", PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); + // PY-7318 + public void testDictCreationDuplicate() { + doInspectionTest(PyDictCreationInspection.class, PyBundle.message("QFIX.dict.creation"), true, true); } public void testTransformClassicClass() { - doInspectionTest("TransformClassicClass.py", PyClassicStyleClassInspection.class, - PyBundle.message("QFIX.classic.class.transform"), true, true); + doInspectionTest(PyClassicStyleClassInspection.class, PyBundle.message("QFIX.classic.class.transform"), true, true); } - public void testAddGlobalQuickFix() { - doInspectionTest("AddGlobalStatement.py", PyUnboundLocalVariableInspection.class, - PyBundle.message("QFIX.add.global"), true, true); + public void testAddGlobalStatement() { + doInspectionTest(PyUnboundLocalVariableInspection.class, PyBundle.message("QFIX.add.global"), true, true); } - public void testAddGlobalExistingQuickFix() { - doInspectionTest("AddGlobalExistingStatement.py", PyUnboundLocalVariableInspection.class, - PyBundle.message("QFIX.add.global"), true, true); + public void testAddGlobalExistingStatement() { + doInspectionTest(PyUnboundLocalVariableInspection.class, PyBundle.message("QFIX.add.global"), true, true); } - public void testSimplifyBooleanCheckQuickFix() { - doInspectionTest("SimplifyBooleanCheck.py", PySimplifyBooleanCheckInspection.class, - PyBundle.message("QFIX.simplify.$0", "b"), true, true); + public void testSimplifyBooleanCheck() { + doInspectionTest(PySimplifyBooleanCheckInspection.class, PyBundle.message("QFIX.simplify.$0", "b"), true, true); } - public void testFromFutureImportQuickFix() { - doInspectionTest("MoveFromFutureImport.py", PyFromFutureImportInspection.class, - PyBundle.message("QFIX.move.from.future.import"), true, true); + public void testMoveFromFutureImport() { + doInspectionTest(PyFromFutureImportInspection.class, PyBundle.message("QFIX.move.from.future.import"), true, true); } - public void testFromFutureImportQuickFixDocString() { // PY-10080 - doInspectionTest("MoveFromFutureImportDocString.py", PyFromFutureImportInspection.class, - PyBundle.message("QFIX.move.from.future.import"), true, true); + // PY-10080 + public void testMoveFromFutureImportDocString() { + doInspectionTest(PyFromFutureImportInspection.class, PyBundle.message("QFIX.move.from.future.import"), true, true); } - public void testComparisonWithNoneQuickFix() { - doInspectionTest("ComparisonWithNone.py", PyComparisonWithNoneInspection.class, - PyBundle.message("QFIX.replace.equality"), true, true); + public void testComparisonWithNone() { + doInspectionTest(PyComparisonWithNoneInspection.class, PyBundle.message("QFIX.replace.equality"), true, true); } public void testAddClassFix() { doInspectionTest("AddClass.py", PyUnresolvedReferencesInspection.class, "Create class 'Xyzzy'", true, true); } - - public void testAddFunctionToModule() { // PY-1602 + // PY-1602 + public void testAddFunctionToModule() { doInspectionTest( "AddFunctionToModule.py", PyUnresolvedReferencesInspection.class, @@ -207,7 +211,8 @@ public class PyQuickFixTest extends PyTestCase { ); } - public void testRedundantParentheses() { // PY-1470 + // PY-1470 + public void testRedundantParentheses() { String[] testFiles = new String[]{"RedundantParentheses.py"}; myFixture.enableInspections(PyRedundantParenthesesInspection.class); myFixture.configureByFiles(testFiles); @@ -216,88 +221,86 @@ public class PyQuickFixTest extends PyTestCase { assertNotNull(intentionAction); myFixture.launchAction(intentionAction); myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after")); - } - public void testRedundantParenthesesBoolean() { // PY-3095 - doInspectionTest("RedundantParenthesesBoolean.py", PyRedundantParenthesesInspection.class, - PyBundle.message("QFIX.redundant.parentheses"), true, true); + // PY-3095 + public void testRedundantParenthesesBoolean() { + doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); } - public void testRedundantParenthesesMore() { // PY-3239 - doInspectionTest("RedundantParenthesesMore.py", PyRedundantParenthesesInspection.class, - PyBundle.message("QFIX.redundant.parentheses"), true, true); + // PY-3239 + public void testRedundantParenthesesMore() { + doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); } - public void testRedundantParenthesesParenthesizedExpression() { // PY-12679 - doInspectionTest("RedundantParenthesesParenthesizedExpression.py", PyRedundantParenthesesInspection.class, - PyBundle.message("QFIX.redundant.parentheses"), true, true); + // PY-12679 + public void testRedundantParenthesesParenthesizedExpression() { + doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); } // PY-15506 public void testEmptyListOfBaseClasses() { - doInspectionTest("EmptyListOfBaseClasses.py", PyRedundantParenthesesInspection.class, - PyBundle.message("QFIX.redundant.parentheses"), true, true); + doInspectionTest(PyRedundantParenthesesInspection.class, PyBundle.message("QFIX.redundant.parentheses"), true, true); } - public void testChainedComparisons() { // PY-1020 - doInspectionTest("ChainedComparisons.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-1020 + public void testChainedComparisons() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testChainedComparison1() { // PY-3126 - doInspectionTest("ChainedComparison1.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-3126 + public void testChainedComparison1() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testChainedComparison2() { // PY-3126 - doInspectionTest("ChainedComparison2.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-3126 + public void testChainedComparison2() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testChainedComparison3() { // PY-3126 - doInspectionTest("ChainedComparison3.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-3126 + public void testChainedComparison3() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testChainedComparison4() { // PY-5623 - doInspectionTest("ChainedComparison4.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-5623 + public void testChainedComparison4() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testChainedComparison5() { // PY-6467 - doInspectionTest("ChainedComparison5.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + // PY-6467 + public void testChainedComparison5() { + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } // PY-14002 public void testChainedComparisonWithCommonBinaryExpression() { - doInspectionTest("ChainedComparisonWithCommonBinaryExpression.py", PyChainedComparisonsInspection.class, - PyBundle.message("QFIX.chained.comparison"), true, true); + doInspectionTest(PyChainedComparisonsInspection.class, PyBundle.message("QFIX.chained.comparison"), true, true); } - public void testStatementEffect() { // PY-1362, PY-2585 - doInspectionTest("StatementEffect.py", PyStatementEffectInspection.class, - PyBundle.message("QFIX.statement.effect"), true, true); + // PY-1362, PY-2585 + public void testStatementEffect() { + doInspectionTest(PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect"), true, true); } - public void testStatementEffectIntroduceVariable() { // PY-1265 - doInspectionTest("StatementEffectIntroduceVariable.py", PyStatementEffectInspection.class, - PyBundle.message("QFIX.statement.effect.introduce.variable"), true, true); + // PY-1265 + public void testStatementEffectIntroduceVariable() { + doInspectionTest(PyStatementEffectInspection.class, PyBundle.message("QFIX.statement.effect.introduce.variable"), true, true); } - public void testUnresolvedWith() { // PY-2083 + // PY-2083 + public void testUnresolvedWith() { runWithLanguageLevel(LanguageLevel.PYTHON25, new Runnable() { @Override public void run() { - doInspectionTest("UnresolvedWith.py", PyUnresolvedReferencesInspection.class, - PyBundle.message("QFIX.unresolved.reference.add.future"), true, true); + doInspectionTest(PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference.add.future"), true, true); } }); } - public void testUnresolvedRefCreateFunction() { // PY-2092 - doInspectionTest("UnresolvedRefCreateFunction.py", PyUnresolvedReferencesInspection.class, + // PY-2092 + public void testUnresolvedRefCreateFunction() { + doInspectionTest(PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref"), true, true); } @@ -305,59 +308,55 @@ public class PyQuickFixTest extends PyTestCase { myFixture.enableInspections(PyUnresolvedReferencesInspection.class); myFixture.configureByFile("UnresolvedRefNoCreateFunction.py"); myFixture.checkHighlighting(true, false, false); - final IntentionAction intentionAction = myFixture.getAvailableIntention( - PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref")); + final IntentionAction intentionAction = myFixture.getAvailableIntention(PyBundle.message("QFIX.unresolved.reference.create.function.$0", "ref")); assertNull(intentionAction); } public void testReplaceNotEqOperator() { - doInspectionTest("ReplaceNotEqOperator.py", PyCompatibilityInspection.class, - PyBundle.message("INTN.replace.noteq.operator"), true, true); + doInspectionTest(PyCompatibilityInspection.class, PyBundle.message("INTN.replace.noteq.operator"), true, true); } public void testListCreation() { - doInspectionTest("ListCreation.py", PyListCreationInspection.class, - PyBundle.message("QFIX.list.creation"), true, true); + doInspectionTest(PyListCreationInspection.class, PyBundle.message("QFIX.list.creation"), true, true); } - public void testConvertSingleQuotedDocstring() { //PY-1445 - doInspectionTest("ConvertSingleQuotedDocstring.py", PySingleQuotedDocstringInspection.class, - PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true); + // PY-1445 + public void testConvertSingleQuotedDocstring() { + doInspectionTest(PySingleQuotedDocstringInspection.class, PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true); } - public void testConvertSingleQuotedDocstringEscape() { //PY-8926 - doInspectionTest("ConvertSingleQuotedDocstringEscape.py", PySingleQuotedDocstringInspection.class, - PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true); + // PY-8926 + public void testConvertSingleQuotedDocstringEscape() { + doInspectionTest(PySingleQuotedDocstringInspection.class, PyBundle.message("QFIX.convert.single.quoted.docstring"), true, true); } - public void testDefaultArgument() { //PY-3127 - doInspectionTest("DefaultArgument.py", PyDefaultArgumentInspection.class, - PyBundle.message("QFIX.default.argument"), true, true); + // PY-3127 + public void testDefaultArgument() { + doInspectionTest(PyDefaultArgumentInspection.class, PyBundle.message("QFIX.default.argument"), true, true); } public void testDefaultArgumentEmptyList() { - doInspectionTest("DefaultArgumentEmptyList.py", PyDefaultArgumentInspection.class, - PyBundle.message("QFIX.default.argument"), true, true); + doInspectionTest(PyDefaultArgumentInspection.class, PyBundle.message("QFIX.default.argument"), true, true); } - public void testPyArgumentEqualDefault() { //PY-3125 - doInspectionTest("ArgumentEqualDefault.py", PyArgumentEqualDefaultInspection.class, - PyBundle.message("QFIX.remove.argument.equal.default"), true, true); + // PY-3125 + public void testArgumentEqualDefault() { + doInspectionTest(PyArgumentEqualDefaultInspection.class, PyBundle.message("QFIX.remove.argument.equal.default"), true, true); } - public void testAddCallSuper() { //PY-3315 - doInspectionTest("AddCallSuper.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + // PY-3315 + public void testAddCallSuper() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } - public void testAddCallSuper1() { //PY-4017 - doInspectionTest("AddCallSuper1.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + // PY-4017 + public void testAddCallSuper1() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } - public void testAddCallSuperPass() { //PY-8654 - doInspectionTest("AddCallSuperPass.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + // PY-8654 + public void testAddCallSuperPass() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } @@ -365,8 +364,7 @@ public class PyQuickFixTest extends PyTestCase { public void testAddCallSuperKeywordOnlyParamInSuperInit() { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { public void run() { - doInspectionTest("AddCallSuperKeywordOnlyParamInSuperInit.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } @@ -375,8 +373,7 @@ public class PyQuickFixTest extends PyTestCase { public void testAddCallSuperKeywordOnlyParamInInit() { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { public void run() { - doInspectionTest("AddCallSuperKeywordOnlyParamInInit.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } @@ -385,8 +382,7 @@ public class PyQuickFixTest extends PyTestCase { public void testAddCallSuperSingleStarParamInSuperInit() { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { public void run() { - doInspectionTest("AddCallSuperSingleStarParamInSuperInit.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } @@ -396,8 +392,7 @@ public class PyQuickFixTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { @Override public void run() { - doInspectionTest("AddCallSuperSingleStarParamInSuperInitAndVarargInInit.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } @@ -407,60 +402,57 @@ public class PyQuickFixTest extends PyTestCase { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { @Override public void run() { - doInspectionTest("AddCallSuperTypeAnnotationsPreserved.py", PyMissingConstructorInspection.class, - PyBundle.message("QFIX.add.super"), true, true); + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } }); } - //PY-491, PY-13297 + // PY-491, PY-13297 public void testAddEncoding() { - doInspectionTest("AddEncoding.py", PyMandatoryEncodingInspection.class, - PyBundle.message("QFIX.add.encoding"), true, true); + doInspectionTest(PyMandatoryEncodingInspection.class, PyBundle.message("QFIX.add.encoding"), true, true); } // PY-13297 public void testAddEncodingAtLastLine() { - doInspectionTest("AddEncodingAtLastLine.py", PyMandatoryEncodingInspection.class, - PyBundle.message("QFIX.add.encoding"), true, true); + doInspectionTest(PyMandatoryEncodingInspection.class, PyBundle.message("QFIX.add.encoding"), true, true); } - public void testRemoveDecorator() { //PY-3348 - doInspectionTest("RemoveDecorator.py", PyDecoratorInspection.class, - PyBundle.message("QFIX.remove.decorator"), true, true); + // PY-3348 + public void testRemoveDecorator() { + doInspectionTest(PyDecoratorInspection.class, PyBundle.message("QFIX.remove.decorator"), true, true); } public void testAddParameter() { - doInspectionTest("AddParameter.py", PyUnresolvedReferencesInspection.class, + doInspectionTest(PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference.add.param.$0", "test"), true, true); } - public void testRenameUnresolvedReference() { //PY-6595 - doInspectionTest("RenameUnresolvedReference.py", PyUnresolvedReferencesInspection.class, - PyBundle.message("QFIX.rename.unresolved.reference"), true, true); + // PY-6595 + public void testRenameUnresolvedReference() { + doInspectionTest(PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.rename.unresolved.reference"), true, true); } - public void testSetFunctionToLiteral() { //PY-3120 + // PY-3120 + public void testSetFunctionToLiteral() { runWithLanguageLevel(LanguageLevel.PYTHON27, new Runnable() { @Override public void run() { - doInspectionTest("SetFunctionToLiteral.py", PySetFunctionToLiteralInspection.class, - PyBundle.message("QFIX.replace.function.set.with.literal"), true, true); + doInspectionTest(PySetFunctionToLiteralInspection.class, PyBundle.message("QFIX.replace.function.set.with.literal"), true, true); } }); } public void testDictComprehensionToCall() { - doInspectionTest("DictComprehensionToCall.py", PyCompatibilityInspection.class, - PyBundle.message("INTN.convert.dict.comp.to"), true, true); + doInspectionTest(PyCompatibilityInspection.class, PyBundle.message("INTN.convert.dict.comp.to"), true, true); } - public void testDocstringParams() { //PY-3394 + // PY-3394 + public void testDocstringParams() { PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule()); documentationSettings.setFormat(DocStringFormat.EPYTEXT); try { - doInspectionTest("DocstringParams.py", PyDocstringInspection.class, - PyBundle.message("QFIX.docstring.add.$0", "b"), true, true); + doInspectionTest(PyDocstringInspection.class, + PyBundle.message("QFIX.docstring.add.$0", "b"), true, true); } finally { documentationSettings.setFormat(DocStringFormat.PLAIN); @@ -471,20 +463,19 @@ public class PyQuickFixTest extends PyTestCase { PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule()); documentationSettings.setFormat(DocStringFormat.EPYTEXT); try { - doInspectionTest("DocstringParams1.py", PyDocstringInspection.class, - PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true); + doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.remove.$0", "c"), true, true); } finally { documentationSettings.setFormat(DocStringFormat.PLAIN); } } - public void testDocstringParams2() { //PY-4964 + // PY-4964 + public void testDocstringParams2() { PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(myFixture.getModule()); documentationSettings.setFormat(DocStringFormat.EPYTEXT); try { - doInspectionTest("DocstringParams2.py", PyDocstringInspection.class, - PyBundle.message("QFIX.docstring.add.$0", "ham"), true, true); + doInspectionTest(PyDocstringInspection.class, PyBundle.message("QFIX.docstring.add.$0", "ham"), true, true); } finally { documentationSettings.setFormat(DocStringFormat.PLAIN); @@ -502,9 +493,9 @@ public class PyQuickFixTest extends PyTestCase { myFixture.checkResultByFile(graftBeforeExt(testFiles[0], "_after")); } - public void testUnresolvedRefTrueFalse() { //PY-3051 - doInspectionTest("UnresolvedRefTrueFalse.py", PyUnresolvedReferencesInspection.class, - PyBundle.message("QFIX.unresolved.reference.replace.$0", "True"), true, true); + // PY-3051 + public void testUnresolvedRefTrueFalse() { + doInspectionTest(PyUnresolvedReferencesInspection.class, PyBundle.message("QFIX.unresolved.reference.replace.$0", "True"), true, true); } public void testUnnecessaryBackslashInArgumentList() { @@ -585,9 +576,16 @@ public class PyQuickFixTest extends PyTestCase { return PythonTestUtil.getTestDataPath() + "/inspections/"; } - protected void doInspectionTest(@TestDataFile @NonNls String testFileName, - final Class inspectionClass, - @NonNls String quickFixName, + private void doInspectionTest(@NotNull Class inspectionClass, + @NotNull String quickFixName, + boolean applyFix, + boolean available) { + doInspectionTest(getTestName(false) + ".py", inspectionClass, quickFixName, applyFix, available); + } + + protected void doInspectionTest(@TestDataFile @NonNls @NotNull String testFileName, + @NotNull Class inspectionClass, + @NonNls @NotNull String quickFixName, boolean applyFix, boolean available) { doInspectionTest(new String[]{testFileName}, inspectionClass, quickFixName, applyFix, available); @@ -603,9 +601,9 @@ public class PyQuickFixTest extends PyTestCase { * @param available true if the fix should be available, false if it should be explicitly not available. * @throws Exception */ - protected void doInspectionTest(@NonNls String[] testFiles, - final Class inspectionClass, - @NonNls String quickFixName, + protected void doInspectionTest(@NonNls @NotNull String[] testFiles, + @NotNull Class inspectionClass, + @NonNls @NotNull String quickFixName, boolean applyFix, boolean available) { myFixture.enableInspections(inspectionClass); From 9f6a7e6d073d4eedd4466df1b8e964ad41d25f6b Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 12:48:04 +0300 Subject: [PATCH 08/36] PY-15867 Move Python 3 specific tests from PyQuickFixTest to Py3QuickFixTest --- .../com/jetbrains/python/Py3QuickFixTest.java | 75 ++++++++++++++++++ .../com/jetbrains/python/PyQuickFixTest.java | 76 ------------------- 2 files changed, 75 insertions(+), 76 deletions(-) diff --git a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java index 6d7389607e5c..29108fe597c9 100644 --- a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java @@ -73,6 +73,81 @@ public class Py3QuickFixTest extends PyTestCase { }); } + // PY-15867 + public void testAddCallSuperKeywordOnlyParamInSuperInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperKeywordOnlyParamInInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperSingleStarParamInSuperInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + public void run() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperSingleStarParamInSuperInitAndVarargInInit() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + @Override + public void run() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-15867 + public void testAddCallSuperTypeAnnotationsPreserved() { + runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { + @Override + public void run() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + }); + } + + // PY-8991 + public void testRemoveUnicodePrefixFromGluedStringNodesWithSlash() { + runWithLanguageLevel(LanguageLevel.PYTHON32, new Runnable() { + public void run() { + myFixture.configureByFile(getTestName(false) + ".py"); + myFixture.checkHighlighting(true, false, false); + final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("INTN.remove.leading.$0", "U")); + assertNotNull(intentionAction); + myFixture.launchAction(intentionAction); + myFixture.checkResultByFile(getTestName(false) + "_after.py"); + } + }); + } + + // PY-8990 + public void testRemoveUnicodePrefixFromGluedStringNodesInParenthesis() { + runWithLanguageLevel(LanguageLevel.PYTHON32, new Runnable() { + public void run() { + myFixture.configureByFile(getTestName(false) + ".py"); + myFixture.checkHighlighting(true, false, false); + final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("INTN.remove.leading.$0", "U")); + assertNotNull(intentionAction); + myFixture.launchAction(intentionAction); + myFixture.checkResultByFile(getTestName(false) + "_after.py"); + } + }); + } + @Override @NonNls protected String getTestDataPath() { diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 05f8258b0e68..7b9c18c5e9f3 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -359,54 +359,6 @@ public class PyQuickFixTest extends PyTestCase { doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } - - // PY-15867 - public void testAddCallSuperKeywordOnlyParamInSuperInit() { - runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - - // PY-15867 - public void testAddCallSuperKeywordOnlyParamInInit() { - runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - - // PY-15867 - public void testAddCallSuperSingleStarParamInSuperInit() { - runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - - // PY-15867 - public void testAddCallSuperSingleStarParamInSuperInitAndVarargInInit() { - runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { - @Override - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - - // PY-15867 - public void testAddCallSuperTypeAnnotationsPreserved() { - runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { - @Override - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - // PY-491, PY-13297 public void testAddEncoding() { doInspectionTest(PyMandatoryEncodingInspection.class, PyBundle.message("QFIX.add.encoding"), true, true); @@ -542,34 +494,6 @@ public class PyQuickFixTest extends PyTestCase { myFixture.checkHighlighting(true, false, true); } - // PY-8991 - public void testRemoveUnicodePrefixFromGluedStringNodesWithSlash() { - runWithLanguageLevel(LanguageLevel.PYTHON32, new Runnable() { - public void run() { - myFixture.configureByFile(getTestName(false) + ".py"); - myFixture.checkHighlighting(true, false, false); - final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("INTN.remove.leading.$0", "U")); - assertNotNull(intentionAction); - myFixture.launchAction(intentionAction); - myFixture.checkResultByFile(getTestName(false) + "_after.py"); - } - }); - } - - // PY-8990 - public void testRemoveUnicodePrefixFromGluedStringNodesInParenthesis() { - runWithLanguageLevel(LanguageLevel.PYTHON32, new Runnable() { - public void run() { - myFixture.configureByFile(getTestName(false) + ".py"); - myFixture.checkHighlighting(true, false, false); - final IntentionAction intentionAction = myFixture.findSingleIntention(PyBundle.message("INTN.remove.leading.$0", "U")); - assertNotNull(intentionAction); - myFixture.launchAction(intentionAction); - myFixture.checkResultByFile(getTestName(false) + "_after.py"); - } - }); - } - @Override @NonNls protected String getTestDataPath() { From 225dfb37d1de9d62e01387b60101d0ef76c82f8f Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 15:31:52 +0300 Subject: [PATCH 09/36] PY-15867 Handle name collision between optional and required parameters --- .../quickfix/AddCallSuperQuickFix.java | 63 +++++++++++-------- ...rOptionalAndRequiredParamsNameCollision.py | 8 +++ ...nalAndRequiredParamsNameCollision_after.py | 8 +++ .../com/jetbrains/python/PyQuickFixTest.java | 5 ++ 4 files changed, 57 insertions(+), 27 deletions(-) create mode 100644 python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision.py create mode 100644 python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java index 193104bdd3bb..ad30ed956acb 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java @@ -18,7 +18,6 @@ package com.jetbrains.python.inspections.quickfix; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.util.PsiTreeUtil; @@ -30,8 +29,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; +import java.util.*; /** * For: @@ -145,7 +143,7 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunctionParams.add(param.getText()); } for (PyParameter param : superInfo.getRequiredParameters()) { - if (!origInfo.containsRequiredParam(param.getName())) { + if (!origInfo.getAllParameterNames().contains(param.getName())) { newFunctionParams.add(param.getText()); } superCallArgs.add(param.getName()); @@ -182,7 +180,7 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunctionParams.add(param.getText()); } for (PyParameter param : superInfo.getRequiredKeywordOnlyParameters()) { - if (!origInfo.containsRequiredKeywordOnlyParameter(param.getName())) { + if (!origInfo.getAllParameterNames().contains(param.getName())) { newFunctionParams.add(param.getText()); } superCallArgs.add(param.getName() + "=" + param.getName()); @@ -242,6 +240,8 @@ public class AddCallSuperQuickFix implements LocalQuickFix { */ private final PyParameter myKeywordContainerParam; + private final Set myAllParameterNames = new LinkedHashSet(); + public ParametersInfo(@NotNull PyParameterList parameterList) { PyParameter positionalContainer = null; PyParameter singleStarParam = null; @@ -249,6 +249,8 @@ public class AddCallSuperQuickFix implements LocalQuickFix { PyParameter selfParam = null; for (PyParameter param : parameterList.getParameters()) { + myAllParameterNames.addAll(collectParameterNames(param)); + if (param.isSelf()) { selfParam = param; } @@ -285,24 +287,6 @@ public class AddCallSuperQuickFix implements LocalQuickFix { myKeywordContainerParam = keywordContainer; } - public boolean containsRequiredParam(@Nullable final String name) { - return ContainerUtil.exists(myRequiredParams, new Condition() { - @Override - public boolean value(PyParameter parameter) { - return name != null && name.equals(parameter.getName()); - } - }); - } - - public boolean containsRequiredKeywordOnlyParameter(@Nullable final String name) { - return ContainerUtil.exists(myRequiredKwOnlyParams, new Condition() { - @Override - public boolean value(PyParameter parameter) { - return name != null && name.equals(parameter.getName()); - } - }); - } - @Nullable public PyParameter getSelfParameter() { return mySelfParam; @@ -310,12 +294,12 @@ public class AddCallSuperQuickFix implements LocalQuickFix { @NotNull public List getRequiredParameters() { - return myRequiredParams; + return Collections.unmodifiableList(myRequiredParams); } @NotNull public List getOptionalParameters() { - return myOptionalParams; + return Collections.unmodifiableList(myOptionalParams); } @Nullable @@ -330,17 +314,42 @@ public class AddCallSuperQuickFix implements LocalQuickFix { @NotNull public List getRequiredKeywordOnlyParameters() { - return myRequiredKwOnlyParams; + return Collections.unmodifiableList(myRequiredKwOnlyParams); } @NotNull public List getOptionalKeywordOnlyParameters() { - return myOptionalKwOnlyParams; + return Collections.unmodifiableList(myOptionalKwOnlyParams); } @Nullable public PyParameter getKeywordContainerParameter() { return myKeywordContainerParam; } + + @NotNull + public Set getAllParameterNames() { + return Collections.unmodifiableSet(myAllParameterNames); + } + } + + @NotNull + private static Set collectParameterNames(@NotNull PyParameter param) { + final LinkedHashSet result = new LinkedHashSet(); + collectParameterNames(param, result); + return Collections.unmodifiableSet(result); + } + + + private static void collectParameterNames(@NotNull PyParameter param, @NotNull Collection acc) { + final PyTupleParameter tupleParam = param.getAsTuple(); + if (tupleParam != null) { + for (PyParameter subParam : tupleParam.getContents()) { + collectParameterNames(subParam, acc); + } + } + else { + ContainerUtil.addIfNotNull(acc, param.getName()); + } } } diff --git a/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision.py b/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision.py new file mode 100644 index 000000000000..3d3bb7d4b64e --- /dev/null +++ b/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision.py @@ -0,0 +1,8 @@ +class A: + def __init__(self, a): + pass + + +class B(A): + def __init__(self, a=1): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision_after.py b/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision_after.py new file mode 100644 index 000000000000..1693904e6b58 --- /dev/null +++ b/python/testData/inspections/AddCallSuperOptionalAndRequiredParamsNameCollision_after.py @@ -0,0 +1,8 @@ +class A: + def __init__(self, a): + pass + + +class B(A): + def __init__(self, a=1): + A.__init__(self, a) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 7b9c18c5e9f3..1b791037720b 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -359,6 +359,11 @@ public class PyQuickFixTest extends PyTestCase { doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } + // PY-15867 + public void testAddCallSuperOptionalAndRequiredParamsNameCollision() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + // PY-491, PY-13297 public void testAddEncoding() { doInspectionTest(PyMandatoryEncodingInspection.class, PyBundle.message("QFIX.add.encoding"), true, true); From e307b42af18c424b740c99ba87e177c197ba4aa6 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 15:56:58 +0300 Subject: [PATCH 10/36] PY-15927 Handle tuple parameters conflicts in "Add call super" quickfix --- .../quickfix/AddCallSuperQuickFix.java | 30 +++++++++++++++---- .../AddCallSuperConflictingTupleParam.py | 7 +++++ ...AddCallSuperConflictingTupleParam_after.py | 7 +++++ .../com/jetbrains/python/PyQuickFixTest.java | 5 ++++ 4 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 python/testData/inspections/AddCallSuperConflictingTupleParam.py create mode 100644 python/testData/inspections/AddCallSuperConflictingTupleParam_after.py diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java index ad30ed956acb..d6568240ecf4 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddCallSuperQuickFix.java @@ -143,10 +143,28 @@ public class AddCallSuperQuickFix implements LocalQuickFix { newFunctionParams.add(param.getText()); } for (PyParameter param : superInfo.getRequiredParameters()) { - if (!origInfo.getAllParameterNames().contains(param.getName())) { - newFunctionParams.add(param.getText()); + // Special case as if base class has constructor __init__((a, b), c) and + // subclass has constructor __init__(a, (b, c)) + final PyTupleParameter tupleParam = param.getAsTuple(); + if (tupleParam != null) { + final List uniqueNames = collectParameterNames(tupleParam); + final boolean hasDuplicates = uniqueNames.removeAll(origInfo.getAllParameterNames()); + if (hasDuplicates) { + newFunctionParams.addAll(uniqueNames); + } + else { + newFunctionParams.add(param.getText()); + } + // Retain original structure of tuple parameter. + // Note that tuple parameters cannot have annotations or nested default values, so it's syntactically safe + superCallArgs.add(param.getText()); + } + else { + if (!origInfo.getAllParameterNames().contains(param.getName())) { + newFunctionParams.add(param.getText()); + } + superCallArgs.add(param.getName()); } - superCallArgs.add(param.getName()); } // Optional parameters (not-keyword) @@ -334,10 +352,10 @@ public class AddCallSuperQuickFix implements LocalQuickFix { } @NotNull - private static Set collectParameterNames(@NotNull PyParameter param) { - final LinkedHashSet result = new LinkedHashSet(); + private static List collectParameterNames(@NotNull PyParameter param) { + final List result = new ArrayList(); collectParameterNames(param, result); - return Collections.unmodifiableSet(result); + return result; } diff --git a/python/testData/inspections/AddCallSuperConflictingTupleParam.py b/python/testData/inspections/AddCallSuperConflictingTupleParam.py new file mode 100644 index 000000000000..276e16dc2e73 --- /dev/null +++ b/python/testData/inspections/AddCallSuperConflictingTupleParam.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, (a, (b, c)), (d, e)): + pass + +class B(A): + def __init__(self, (a, b), c, e): + pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperConflictingTupleParam_after.py b/python/testData/inspections/AddCallSuperConflictingTupleParam_after.py new file mode 100644 index 000000000000..5a41d4a81d09 --- /dev/null +++ b/python/testData/inspections/AddCallSuperConflictingTupleParam_after.py @@ -0,0 +1,7 @@ +class A: + def __init__(self, (a, (b, c)), (d, e)): + pass + +class B(A): + def __init__(self, (a, b), c, e, d): + A.__init__(self, (a, (b, c)), (d, e)) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java index 1b791037720b..1fc8572ae262 100644 --- a/python/testSrc/com/jetbrains/python/PyQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/PyQuickFixTest.java @@ -364,6 +364,11 @@ public class PyQuickFixTest extends PyTestCase { doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); } + // PY-15927 + public void testAddCallSuperConflictingTupleParam() { + doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); + } + // PY-491, PY-13297 public void testAddEncoding() { doInspectionTest(PyMandatoryEncodingInspection.class, PyBundle.message("QFIX.add.encoding"), true, true); From 9430f1ba424aeddc433a6e86c665cd54deb74fc0 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 16:07:09 +0300 Subject: [PATCH 11/36] PY-11561 Remove existing test case as it was replaced by more comprehensive one --- .../testData/inspections/AddCallSuperAnnotations.py | 8 -------- .../inspections/AddCallSuperAnnotations_after.py | 8 -------- .../com/jetbrains/python/Py3QuickFixTest.java | 12 +----------- 3 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 python/testData/inspections/AddCallSuperAnnotations.py delete mode 100644 python/testData/inspections/AddCallSuperAnnotations_after.py diff --git a/python/testData/inspections/AddCallSuperAnnotations.py b/python/testData/inspections/AddCallSuperAnnotations.py deleted file mode 100644 index b50ae1b4fb72..000000000000 --- a/python/testData/inspections/AddCallSuperAnnotations.py +++ /dev/null @@ -1,8 +0,0 @@ -class Example1: - def __init__(self, field1: str): - self.field1 = field1 - - -class Example2(Example1): - def __init__(self): ## Missed call to __init__ of super class - pass \ No newline at end of file diff --git a/python/testData/inspections/AddCallSuperAnnotations_after.py b/python/testData/inspections/AddCallSuperAnnotations_after.py deleted file mode 100644 index ddee178f3ace..000000000000 --- a/python/testData/inspections/AddCallSuperAnnotations_after.py +++ /dev/null @@ -1,8 +0,0 @@ -class Example1: - def __init__(self, field1: str): - self.field1 = field1 - - -class Example2(Example1): - def __init__(self, field1: str): - super().__init__(field1) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java index 29108fe597c9..10ed5fa597b4 100644 --- a/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/Py3QuickFixTest.java @@ -63,16 +63,6 @@ public class Py3QuickFixTest extends PyTestCase { }); } - // PY-11561 - public void testAddCallSuperAnnotations() { - runWithLanguageLevel(LanguageLevel.PYTHON33, new Runnable() { - @Override - public void run() { - doInspectionTest(PyMissingConstructorInspection.class, PyBundle.message("QFIX.add.super"), true, true); - } - }); - } - // PY-15867 public void testAddCallSuperKeywordOnlyParamInSuperInit() { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { @@ -110,7 +100,7 @@ public class Py3QuickFixTest extends PyTestCase { }); } - // PY-15867 + // PY-11561 public void testAddCallSuperTypeAnnotationsPreserved() { runWithLanguageLevel(LanguageLevel.PYTHON30, new Runnable() { @Override From 831bcb463a0ed651ee8e06ce9e608bec314e4024 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 18 May 2015 13:26:01 +0200 Subject: [PATCH 12/36] cleanup (prepare to fix IDEA-137908 External documentation (from javadoc.jar) is not shown) --- .../lang/java/JavaDocumentationProvider.java | 20 ++++---- .../PlatformDocumentationUtil.java | 20 ++++---- .../documentation/DocumentationComponent.java | 48 ++++++++++--------- .../ide/actions/ExternalJavaDocAction.java | 10 ++-- .../ide/browsers/BrowserLauncherAppless.java | 6 +-- .../browsers/impl/WebBrowserServiceImpl.java | 2 +- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java index cb215d06380d..8163544fd81a 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.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. @@ -684,7 +684,7 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } @Nullable - public static List findUrlForClass(PsiClass aClass) { + public static List findUrlForClass(@NotNull PsiClass aClass) { String qName = aClass.getQualifiedName(); if (qName == null) return null; @@ -696,11 +696,11 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext String packageName = ((PsiJavaFile)file).getPackageName(); String relPath; - if (packageName.length() > 0) { - relPath = packageName.replace('.', '/') + '/' + qName.substring(packageName.length() + 1) + HTML_EXTENSION; + if (packageName.isEmpty()) { + relPath = qName + HTML_EXTENSION; } else { - relPath = qName + HTML_EXTENSION; + relPath = packageName.replace('.', '/') + '/' + qName.substring(packageName.length() + 1) + HTML_EXTENSION; } return findUrlForVirtualFile(file.getProject(), virtualFile, relPath); @@ -728,11 +728,11 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } } - final List orderEntries = fileIndex.getOrderEntriesForFile(virtualFile); - for (OrderEntry orderEntry : orderEntries) { - final String[] files = JavadocOrderRootType.getUrls(orderEntry); - final List httpRoot = PlatformDocumentationUtil.getHttpRoots(files, relPath); - if (httpRoot != null) return httpRoot; + for (OrderEntry orderEntry : fileIndex.getOrderEntriesForFile(virtualFile)) { + List httpRoot = PlatformDocumentationUtil.getHttpRoots(JavadocOrderRootType.getUrls(orderEntry), relPath); + if (httpRoot != null) { + return httpRoot; + } } return null; } diff --git a/platform/core-impl/src/com/intellij/codeInsight/documentation/PlatformDocumentationUtil.java b/platform/core-impl/src/com/intellij/codeInsight/documentation/PlatformDocumentationUtil.java index 966d8173c150..fa519f0249bb 100644 --- a/platform/core-impl/src/com/intellij/codeInsight/documentation/PlatformDocumentationUtil.java +++ b/platform/core-impl/src/com/intellij/codeInsight/documentation/PlatformDocumentationUtil.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. @@ -19,10 +19,11 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.ex.http.HttpFileSystem; +import com.intellij.util.SmartList; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; @@ -30,7 +31,6 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class PlatformDocumentationUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.documentation.PlatformDocumentationUtil"); private static final @NonNls Pattern ourLtFixupPattern = Pattern.compile("<([^/^\\w^!])"); @@ -38,19 +38,23 @@ public class PlatformDocumentationUtil { private static final @NonNls String LT_ENTITY = "<"; @Nullable - public static List getHttpRoots(final String[] roots, String relPath) { - final ArrayList result = new ArrayList(); + public static List getHttpRoots(@NotNull String[] roots, String relPath) { + List result = new SmartList(); for (String root : roots) { - final VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(root); + VirtualFile virtualFile = VirtualFileManager.getInstance().findFileByUrl(root); if (virtualFile != null) { if (virtualFile.getFileSystem() instanceof HttpFileSystem) { String url = virtualFile.getUrl(); - if (!url.endsWith("/")) url += "/"; + if (!url.endsWith("/")) { + url += "/"; + } result.add(url + relPath); } else { VirtualFile file = virtualFile.findFileByRelativePath(relPath); - if (file != null) result.add(file.getUrl()); + if (file != null) { + result.add(file.getUrl()); + } } } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java index d687848a4949..36e8f4005070 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java @@ -705,33 +705,35 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr @Override public void actionPerformed(AnActionEvent e) { - if (myElement != null) { - final PsiElement element = myElement.getElement(); - final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element); - final PsiElement originalElement = DocumentationManager.getOriginalElement(element); - boolean processed = false; - if (provider instanceof CompositeDocumentationProvider) { - for (DocumentationProvider p : ((CompositeDocumentationProvider)provider).getAllProviders()) { - if (p instanceof ExternalDocumentationHandler && ((ExternalDocumentationHandler)p).handleExternal(element, originalElement)) { - processed = true; - break; - } - } - } + if (myElement == null) { + return; + } - if (!processed) { - final Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(e.getDataContext()); - final List urls; - if (!StringUtil.isEmptyOrSpaces(myEffectiveExternalUrl)) { - urls = Collections.singletonList(myEffectiveExternalUrl); - } else { - urls = provider.getUrlFor(element, originalElement); - assert urls != null : provider; - assert !urls.isEmpty() : provider; + final PsiElement element = myElement.getElement(); + final DocumentationProvider provider = DocumentationManager.getProviderFromElement(element); + final PsiElement originalElement = DocumentationManager.getOriginalElement(element); + boolean processed = false; + if (provider instanceof CompositeDocumentationProvider) { + for (DocumentationProvider p : ((CompositeDocumentationProvider)provider).getAllProviders()) { + if (p instanceof ExternalDocumentationHandler && ((ExternalDocumentationHandler)p).handleExternal(element, originalElement)) { + processed = true; + break; } - ExternalJavaDocAction.showExternalJavadoc(urls, component); } } + + if (!processed) { + List urls; + if (!StringUtil.isEmptyOrSpaces(myEffectiveExternalUrl)) { + urls = Collections.singletonList(myEffectiveExternalUrl); + } + else { + urls = provider.getUrlFor(element, originalElement); + assert urls != null : provider; + assert !urls.isEmpty() : provider; + } + ExternalJavaDocAction.showExternalJavadoc(urls, PlatformDataKeys.CONTEXT_COMPONENT.getData(e.getDataContext())); + } } @Override diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java index 9d73cd569c40..f974d35afd8d 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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. @@ -35,11 +35,13 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; import com.intellij.util.ArrayUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; -import java.util.HashSet; import java.util.List; +import java.util.Set; public class ExternalJavaDocAction extends AnAction { @@ -90,8 +92,8 @@ public class ExternalJavaDocAction extends AnAction { } } - public static void showExternalJavadoc(List urls, Component component) { - final HashSet set = new HashSet(urls); + public static void showExternalJavadoc(@NotNull List urls, Component component) { + Set set = new THashSet(urls); if (set.size() > 1) { JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep("Choose external documentation root", ArrayUtil.toStringArray(set)) { @Override diff --git a/platform/platform-api/src/com/intellij/ide/browsers/BrowserLauncherAppless.java b/platform/platform-api/src/com/intellij/ide/browsers/BrowserLauncherAppless.java index 2385d0000bee..c7f3989c8b7c 100644 --- a/platform/platform-api/src/com/intellij/ide/browsers/BrowserLauncherAppless.java +++ b/platform/platform-api/src/com/intellij/ide/browsers/BrowserLauncherAppless.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. @@ -137,10 +137,6 @@ public class BrowserLauncherAppless extends BrowserLauncher { private void openOrBrowse(@NotNull String url, boolean browse, @Nullable Project project) { url = url.trim(); - if (url.startsWith("jar:")) { - return; - } - URI uri; if (BrowserUtil.isAbsoluteURL(url)) { uri = VfsUtil.toUri(url); diff --git a/xml/impl/src/com/intellij/ide/browsers/impl/WebBrowserServiceImpl.java b/xml/impl/src/com/intellij/ide/browsers/impl/WebBrowserServiceImpl.java index 6cd24659c003..097a1d1859fc 100644 --- a/xml/impl/src/com/intellij/ide/browsers/impl/WebBrowserServiceImpl.java +++ b/xml/impl/src/com/intellij/ide/browsers/impl/WebBrowserServiceImpl.java @@ -48,7 +48,7 @@ public class WebBrowserServiceImpl extends WebBrowserService { VirtualFile file = request.getVirtualFile(); return file instanceof LightVirtualFile || !request.getFile().getViewProvider().isPhysical() ? Collections.emptyList() - : Collections.singleton(Urls.newFromVirtualFile(file)); + : Collections.singletonList(Urls.newFromVirtualFile(file)); } @NotNull From c679615edf09b7084ed639714adc91cbbc417888 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 18 May 2015 15:29:48 +0200 Subject: [PATCH 13/36] IDEA-137908 External documentation (from javadoc.jar) is not shown --- java/java-impl/java-impl.iml | 4 +- .../lang/java/JavaDocumentationProvider.java | 19 ++++++- .../DefaultWebServerRootsProvider.java | 53 ++++++++++++++++++- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/java/java-impl/java-impl.iml b/java/java-impl/java-impl.iml index cf601bbd0f76..ee71056b6734 100644 --- a/java/java-impl/java-impl.iml +++ b/java/java-impl/java-impl.iml @@ -56,11 +56,11 @@ + - - + \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java index 8163544fd81a..0a61a7c94c06 100644 --- a/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java +++ b/java/java-impl/src/com/intellij/lang/java/JavaDocumentationProvider.java @@ -50,11 +50,14 @@ import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.SmartList; +import com.intellij.util.Url; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.builtInWebServer.BuiltInWebBrowserUrlProvider; import java.util.LinkedHashSet; import java.util.List; @@ -707,7 +710,7 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } @Nullable - public static List findUrlForVirtualFile(final Project project, final VirtualFile virtualFile, final String relPath) { + public static List findUrlForVirtualFile(@NotNull Project project, @NotNull VirtualFile virtualFile, @NotNull String relPath) { final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex(); Module module = fileIndex.getModuleForFile(virtualFile); if (module == null) { @@ -729,6 +732,20 @@ public class JavaDocumentationProvider implements CodeDocumentationProvider, Ext } for (OrderEntry orderEntry : fileIndex.getOrderEntriesForFile(virtualFile)) { + for (VirtualFile root : orderEntry.getFiles(JavadocOrderRootType.getInstance())) { + if (root.getFileSystem() == JarFileSystem.getInstance()) { + VirtualFile file = root.findFileByRelativePath(relPath); + List urls = file == null ? null : BuiltInWebBrowserUrlProvider.getUrls(file, project, null); + if (!ContainerUtil.isEmpty(urls)) { + List result = new SmartList(); + for (Url url : urls) { + result.add(url.toExternalForm()); + } + return result; + } + } + } + List httpRoot = PlatformDocumentationUtil.getHttpRoots(JavadocOrderRootType.getUrls(orderEntry), relPath); if (httpRoot != null) { return httpRoot; diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java index fa09f74d71ea..e6b6ba3ffc46 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java @@ -33,6 +33,8 @@ import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.PairFunction; import com.intellij.util.PlatformUtils; @@ -207,7 +209,8 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { DirectoryInfo info = directoryIndex.getInfoForFile(file); // we serve excluded files if (!info.isExcluded() && !info.isInProject()) { - return null; + // javadoc jars is "not under project", but actually is, so, let's check project library table + return file.getFileSystem() == JarFileSystem.getInstance() ? getInfoForDocJar(file, project) : null; } VirtualFile root = info.getSourceRoot(); @@ -245,6 +248,54 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { } } + @Nullable + private static PathInfo getInfoForDocJar(@NotNull final VirtualFile file, @NotNull Project project) { + final OrderRootType javaDocRootType = JavadocOrderRootType.getInstance(); + if (javaDocRootType == null) { + return null; + } + + final Ref result = Ref.create(); + Processor processor = new Processor() { + @Override + public boolean process(Library library) { + for (VirtualFile root : library.getFiles(javaDocRootType)) { + if (VfsUtilCore.isAncestor(root, file, true)) { + result.set(new PathInfo(file, root, null, true)); + return false; + } + } + return true; + } + }; + + AccessToken token = ReadAction.start(); + try { + ModuleManager moduleManager = ModuleManager.getInstance(project); + for (Module module : moduleManager.getModules()) { + if (module.isDisposed()) { + continue; + } + + ModuleRootManager.getInstance(module).orderEntries().forEachLibrary(processor); + if (!result.isNull()) { + return result.get(); + } + } + + for (Library library : LibraryTablesRegistrar.getInstance().getLibraryTable(project).getLibraries()) { + if (!processor.process(library)) { + return result.get(); + } + } + } + finally { + token.finish(); + } + + return null; + } + @Nullable private static String getModuleNameQualifier(@NotNull Project project, @Nullable Module module) { if (module != null && From 062d7dbc1a2b0604ea02bfac4c34601838b68356 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 18 May 2015 15:43:05 +0200 Subject: [PATCH 14/36] =?UTF-8?q?IDEA-CR-2749=20must=20not=20be=20strict?= =?UTF-8?q?=20=E2=80=94=20root=20could=20be=20requested?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../builtInWebServer/DefaultWebServerRootsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java index e6b6ba3ffc46..5a22e1c7a7df 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java @@ -260,7 +260,7 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { @Override public boolean process(Library library) { for (VirtualFile root : library.getFiles(javaDocRootType)) { - if (VfsUtilCore.isAncestor(root, file, true)) { + if (VfsUtilCore.isAncestor(root, file, false)) { result.set(new PathInfo(file, root, null, true)); return false; } From c113e546f4766abd01beeb04baa31e0eaa6b2103 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Mon, 18 May 2015 15:52:04 +0200 Subject: [PATCH 15/36] IDEA-CR-2749 respect module name --- .../DefaultWebServerRootsProvider.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java index 5a22e1c7a7df..70ed18f5f98b 100644 --- a/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java +++ b/platform/built-in-server/src/org/jetbrains/builtInWebServer/DefaultWebServerRootsProvider.java @@ -255,20 +255,23 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { return null; } - final Ref result = Ref.create(); - Processor processor = new Processor() { + class LibraryProcessor implements Processor { + PathInfo result; + String moduleName; + @Override public boolean process(Library library) { for (VirtualFile root : library.getFiles(javaDocRootType)) { if (VfsUtilCore.isAncestor(root, file, false)) { - result.set(new PathInfo(file, root, null, true)); + result = new PathInfo(file, root, moduleName, true); return false; } } return true; } - }; + } + LibraryProcessor processor = new LibraryProcessor(); AccessToken token = ReadAction.start(); try { ModuleManager moduleManager = ModuleManager.getInstance(project); @@ -277,15 +280,17 @@ final class DefaultWebServerRootsProvider extends WebServerRootsProvider { continue; } + processor.moduleName = module.getName(); ModuleRootManager.getInstance(module).orderEntries().forEachLibrary(processor); - if (!result.isNull()) { - return result.get(); + if (processor.result != null) { + return processor.result; } } + processor.moduleName = null; for (Library library : LibraryTablesRegistrar.getInstance().getLibraryTable(project).getLibraries()) { if (!processor.process(library)) { - return result.get(); + return processor.result; } } } From ed2ac12ceb12d13b7177f65e4fb4e537a8b57a28 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Fri, 8 May 2015 17:24:03 +0300 Subject: [PATCH 16/36] IDEA-140053 diff: add by-word highlighting while showing LST-popup --- .../diff/util/BackgroundTaskUtil.java | 23 +++++++++ .../util/resources/misc/registry.properties | 1 + .../openapi/vcs/ex/LineStatusTracker.java | 11 ++++- .../vcs/ex/LineStatusTrackerDrawing.java | 48 ++++++++++++++++++- 4 files changed, 81 insertions(+), 2 deletions(-) diff --git a/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java index f624957695d6..52bb0a6d3409 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/BackgroundTaskUtil.java @@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.EmptyRunnable; +import com.intellij.openapi.util.Ref; import com.intellij.util.Function; import org.jetbrains.annotations.CalledInAwt; import org.jetbrains.annotations.NotNull; @@ -139,4 +140,26 @@ public class BackgroundTaskUtil { result.run(); indicator.stop(); } + + @CalledInAwt + @Nullable + public static T tryComputeFast(@NotNull final Function backgroundTask, + final int waitMillis) { + final Ref resultRef = new Ref(); + ProgressIndicator indicator = executeAndTryWait(new Function() { + @Override + public Runnable fun(final ProgressIndicator indicator) { + final T result = backgroundTask.fun(indicator); + return new Runnable() { + @Override + public void run() { + resultRef.set(result); + } + }; + } + }, null, waitMillis, false); + indicator.cancel(); + + return resultRef.get(); + } } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 099088b2cb62..44e369a5df3f 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -368,6 +368,7 @@ show.flex.debug.design.view=false diff.patience.alg=false diff.status.tracker.skip.spaces=true +diff.status.tracker.byword.delay=200 diff.verify.iterable=false diff.unimportant.line.char.count=3 diff.unimportant.line.char.count.description=Threshold number of non-space characters to mark line as unimportant diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index ad342908c47f..320d3f92ad51 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -868,12 +868,21 @@ public class LineStatusTracker { } } + public CharSequence getCurrentContent(@NotNull Range range) { + synchronized (myLock) { + TextRange textRange = getCurrentTextRange(range); + final int startOffset = textRange.getStartOffset(); + final int endOffset = textRange.getEndOffset(); + return myDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); + } + } + public CharSequence getVcsContent(@NotNull Range range) { synchronized (myLock) { TextRange textRange = getVcsRange(range); final int startOffset = textRange.getStartOffset(); final int endOffset = textRange.getEndOffset(); - return myVcsDocument.getCharsSequence().subSequence(startOffset, endOffset); + return myVcsDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index ed6db0e54467..4a17bbc937f7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -18,6 +18,14 @@ package com.intellij.openapi.vcs.ex; import com.intellij.codeInsight.hint.EditorFragmentComponent; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.hint.HintManagerImpl; +import com.intellij.diff.comparison.ByWord; +import com.intellij.diff.comparison.ComparisonPolicy; +import com.intellij.diff.comparison.DiffTooBigException; +import com.intellij.diff.fragments.DiffFragment; +import com.intellij.diff.util.BackgroundTaskUtil; +import com.intellij.diff.util.DiffDrawUtil; +import com.intellij.diff.util.DiffUtil; +import com.intellij.diff.util.TextDiffType; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.diff.DiffColors; @@ -32,8 +40,11 @@ import com.intellij.openapi.editor.highlighter.EditorHighlighter; import com.intellij.openapi.editor.highlighter.EditorHighlighterFactory; import com.intellij.openapi.editor.markup.ActiveGutterRenderer; import com.intellij.openapi.editor.markup.LineMarkerRenderer; +import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.vcs.actions.ShowNextChangeMarkerAction; import com.intellij.openapi.vcs.actions.ShowPrevChangeMarkerAction; import com.intellij.openapi.vfs.VirtualFile; @@ -41,6 +52,7 @@ import com.intellij.ui.ColoredSideBorder; import com.intellij.ui.HintHint; import com.intellij.ui.HintListener; import com.intellij.ui.LightweightHint; +import com.intellij.util.Function; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,6 +61,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; import java.util.EventObject; import java.util.List; @@ -256,7 +269,7 @@ public class LineStatusTrackerDrawing { component.add(toolbarPanel, BorderLayout.NORTH); - + final List highlighters = new ArrayList(); if (range.getType() != Range.INSERTED) { final DocumentEx doc = (DocumentEx)tracker.getVcsDocument(); final EditorEx uEditor = (EditorEx)EditorFactory.getInstance().createViewer(doc, tracker.getProject()); @@ -265,6 +278,36 @@ public class LineStatusTrackerDrawing { EditorHighlighterFactory.getInstance().createEditorHighlighter(tracker.getProject(), getFileName(tracker.getDocument())); uEditor.setHighlighter(highlighter); + try { + if (range.getType() == Range.MODIFIED) { + final CharSequence vcsContent = tracker.getVcsContent(range); + final CharSequence currentContent = tracker.getCurrentContent(range); + + List diff = BackgroundTaskUtil.tryComputeFast(new Function>() { + @Override + public List fun(ProgressIndicator indicator) { + return ByWord.compare(vcsContent, currentContent, ComparisonPolicy.DEFAULT, indicator); + } + }, Registry.intValue("diff.status.tracker.byword.delay")); + if (diff == null) throw new DiffTooBigException(); + + int vcsStartShift = tracker.getVcsRange(range).getStartOffset(); + int currentStartShift = tracker.getCurrentTextRange(range).getStartOffset(); + for (DiffFragment fragment : diff) { + int vcsStart = vcsStartShift + fragment.getStartOffset1(); + int vcsEnd = vcsStartShift + fragment.getEndOffset1(); + int currentStart = currentStartShift + fragment.getStartOffset2(); + int currentEnd = currentStartShift + fragment.getEndOffset2(); + TextDiffType type = DiffUtil.getDiffType(fragment); + + DiffDrawUtil.createInlineHighlighter(uEditor, vcsStart, vcsEnd, type); + highlighters.add(DiffDrawUtil.createInlineHighlighter(editor, currentStart, currentEnd, type)); + } + } + } + catch (DiffTooBigException ignore) { + } + final EditorFragmentComponent editorFragmentComponent = EditorFragmentComponent.createEditorFragmentComponent(uEditor, range.getVcsLine1(), range.getVcsLine2(), false, false); @@ -284,6 +327,9 @@ public class LineStatusTrackerDrawing { actionList.remove(copyRange); actionList.remove(localShowPrevAction); actionList.remove(localShowNextAction); + for (RangeHighlighter highlighter : highlighters) { + highlighter.dispose(); + } } }; hint.addHintListener(closeListener); From f20cfaa31e9fb9b7b3a1bd0884ba9dfbb161d20f Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 18 May 2015 17:24:22 +0300 Subject: [PATCH 17/36] fixed testSeveralClassesOnOneLine --- .../debugger/engine/PositionManagerImpl.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 4e9b273a0c03..21c9ccd7965c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -530,8 +530,19 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio return null; } final int line = Math.min(finalRangeBegin + 1, finalRangeEnd); - final SourcePosition candidatePosition = positionLine == line? position : SourcePosition.createFromLine(position.getFile(), line); - return classToFind.equals(JVMNameUtil.getClassAt(candidatePosition)) ? fromClass : null; + Set lineClasses = getLineClasses(position.getFile(), line); + if (lineClasses.size() > 1) { + // if there's more than one class on the line - try to match by name + for (PsiClass aClass : lineClasses) { + if (classToFind.equals(aClass)) { + return fromClass; + } + } + } + else if (!lineClasses.isEmpty()){ + return classToFind.equals(lineClasses.iterator().next())? fromClass : null; + } + return null; } }); } From 84c1ae9239c3eab30b1e5fbfb66c65a764e8a38c Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 18 May 2015 17:19:10 +0300 Subject: [PATCH 18/36] Pass DialogWrapper's disposable to the list table in "Change Signature" dialog Otherwise any attempt to create this dialog in tests ends up with error, because global "UI" disposable, that used as fallback in single-argument constructor, is not available in test environment. --- .../refactoring/changeSignature/ChangeSignatureDialogBase.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java index 0772fe6e487c..14e68d6c1069 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureDialogBase.java @@ -48,7 +48,6 @@ import com.intellij.ui.treeStructure.Tree; import com.intellij.util.Alarm; import com.intellij.util.Consumer; import com.intellij.util.IJSwingUtilities; -import com.intellij.util.PlatformIcons; import com.intellij.util.ui.UIUtil; import com.intellij.util.ui.table.JBListTable; import com.intellij.util.ui.table.JBTableRowEditor; @@ -689,7 +688,7 @@ public abstract class ChangeSignatureDialogBase Date: Mon, 18 May 2015 16:47:10 +0200 Subject: [PATCH 19/36] Darcula: editor text field border insets should match text filed insets --- .../darcula/ui/DarculaEditorTextFieldBorder.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java index 856218d2d9d6..519e14fc27c0 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaEditorTextFieldBorder.java @@ -40,10 +40,7 @@ public class DarculaEditorTextFieldBorder implements Border { final EditorTextField textField = UIUtil.getParentOfType(EditorTextField.class, c); if (textField == null) return; - final int x1 = x + 3; - final int y1 = y + 3; - final int width1 = width - 8; - final int height1 = height - 6; + final Rectangle r = new Rectangle(x + 1, y + 1, width - 2, height - 2); if (c.isOpaque()) { g.setColor(UIUtil.getPanelBackground()); @@ -51,26 +48,26 @@ public class DarculaEditorTextFieldBorder implements Border { } g.setColor(c.getBackground()); - g.fillRect(x1, y1, width1, height1); + g.fillRect(r.x, r.y, r.width, r.height); if (!textField.isEnabled()) { ((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.4f)); } if (textField.isEnabled() && textField.isVisible() && textField.getFocusTarget().hasFocus()) { - DarculaUIUtil.paintFocusRing(g, x1, y1, width1, height1); + DarculaUIUtil.paintFocusRing(g, r.x + 1, r.y + 1, r.width - 2, r.height - 2); } else { g.setColor(new JBColor(Gray._150, Gray._100)); - g.drawRect(x1, y1, width1, height1); + g.drawRect(r.x, r.y, r.width, r.height); } } @Override public Insets getBorderInsets(Component c) { if (isComboBoxEditor(c) /*|| isCellEditor(c)*/) { - return new InsetsUIResource(2,3,2,3); + return new InsetsUIResource(2, 3, 2, 3); } - return new InsetsUIResource(6, 7, 6, 7); + return new InsetsUIResource(4, 7, 4, 7); } @Override From 069adff3ddc4f5f1e254bffb7a6e271cbf091d6f Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 14:35:01 +0200 Subject: [PATCH 20/36] IDEA-140331 Improve intention action for 'Method invocation may produce NPE' --- .../intellij/codeInspection/SurroundWithIfFix.java | 8 +++++++- .../quickFix/surroundWithIf/afterIfCondition.java | 11 +++++++++++ .../quickFix/surroundWithIf/beforeIfCondition.java | 11 +++++++++++ .../codeInspection/DataFlowInspectionTestSuite.java | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/afterIfCondition.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/beforeIfCondition.java diff --git a/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java b/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java index 3bdbc7c067fd..9afbb9de848b 100644 --- a/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java +++ b/java/java-impl/src/com/intellij/codeInspection/SurroundWithIfFix.java @@ -27,6 +27,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilBase; import com.intellij.util.IncorrectOperationException; +import com.siyeh.ipp.trivialif.MergeIfAndIntention; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -57,7 +58,7 @@ public class SurroundWithIfFix implements LocalQuickFix { PsiFile file = element.getContainingFile(); PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project); Document document = documentManager.getDocument(file); - if (!FileModificationService.getInstance().prepareFileForWrite(file)) return; + if (document == null || !FileModificationService.getInstance().prepareFileForWrite(file)) return; PsiElement[] elements = {anchorStatement}; PsiElement prev = PsiTreeUtil.skipSiblingsBackward(anchorStatement, PsiWhiteSpace.class); if (prev instanceof PsiComment && JavaSuppressionUtil.getSuppressedInspectionIdsIn(prev) != null) { @@ -71,6 +72,11 @@ public class SurroundWithIfFix implements LocalQuickFix { document.replaceString(textRange.getStartOffset(), textRange.getEndOffset(),newText); editor.getCaretModel().moveToOffset(textRange.getEndOffset() + newText.length()); + + PsiDocumentManager.getInstance(project).commitAllDocuments(); + + new MergeIfAndIntention().invoke(project, editor, file); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } catch (IncorrectOperationException e) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/afterIfCondition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/afterIfCondition.java new file mode 100644 index 000000000000..68c92a641531 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/afterIfCondition.java @@ -0,0 +1,11 @@ +// "Surround with 'if (i != null)'" "true" +import org.jetbrains.annotations.Nullable; + +class A { + void foo(@Nullable String i) { + if (i != null && i.length() > 0) { + if (i != "a") { + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/beforeIfCondition.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/beforeIfCondition.java new file mode 100644 index 000000000000..ac6851a6c3d7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithIf/beforeIfCondition.java @@ -0,0 +1,11 @@ +// "Surround with 'if (i != null)'" "true" +import org.jetbrains.annotations.Nullable; + +class A { + void foo(@Nullable String i) { + if (i.length() > 0) { + if (i != "a") { + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java index c7664bd15bc8..adb0d9f35c50 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTestSuite.java @@ -20,6 +20,7 @@ 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.codeInsight.daemon.quickFix.SurroundWithIfFixTest; import com.intellij.slicer.SliceBackwardTest; import com.intellij.slicer.SliceTreeTest; import junit.framework.Test; @@ -49,6 +50,7 @@ public class DataFlowInspectionTestSuite { suite.addTestSuite(NullableStuffInspection14Test.class); suite.addTestSuite(AddAssertStatementFixTest.class); + suite.addTestSuite(SurroundWithIfFixTest.class); suite.addTestSuite(ReplaceWithOfNullableFixTest.class); suite.addTestSuite(ReplaceFromOfNullableFixTest.class); return suite; From d27b4997b95a7cde95247dbe607441a6f48c799d Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 15:51:10 +0200 Subject: [PATCH 21/36] IDEA-138441 Methods named like getters are wrongly treated as pure don't track state for primitive get* methods for reference-typed methods, track state only inside "if (getX() != null) ..." flush dfa variables on non-pure getter-like calls --- .../dataFlow/DfaMemoryStateImpl.java | 8 +++--- .../instructions/MethodCallInstruction.java | 3 +-- .../dataFlow/value/DfaExpressionFactory.java | 27 +++++++++++-------- .../dataFlow/fixture/FalseGetters.java | 21 +++++++++++++++ .../DataFlowInspectionTest.java | 1 + .../util/resources/misc/registry.properties | 2 +- 6 files changed, 45 insertions(+), 17 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/FalseGetters.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index d7c7c586890a..aa64c0a469d0 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -650,10 +650,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return true; } + // track "x" property state only inside "if (getX() != null) ..." + if (dfaLeft instanceof DfaVariableValue && ((DfaVariableValue)dfaLeft).containsCalls() && (!isNull(dfaRight) || !isNegated)) { + return true; + } + if (dfaLeft == dfaRight) { - if (dfaLeft instanceof DfaVariableValue && ((DfaVariableValue)dfaLeft).containsCalls()) { - return true; - } return !isNegated; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java index 189e96bf01f0..f7aa1da08598 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java @@ -27,7 +27,6 @@ package com.intellij.codeInspection.dataFlow.instructions; import com.intellij.codeInspection.dataFlow.*; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.psi.*; -import com.intellij.psi.util.PropertyUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -126,7 +125,7 @@ public class MethodCallInstruction extends Instruction { private boolean isPureCall() { if (myTargetMethod == null) return false; - return ControlFlowAnalyzer.isPure(myTargetMethod) || PropertyUtil.isSimplePropertyGetter(myTargetMethod); + return ControlFlowAnalyzer.isPure(myTargetMethod); } @Nullable diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java index d588c1cd9957..fa391bc53d6c 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; import com.intellij.psi.util.PropertyUtil; @@ -41,18 +42,21 @@ public class DfaExpressionFactory { private static Condition parseFalseGetters() { try { - final Pattern pattern = Pattern.compile(Registry.stringValue("ide.dfa.getters.with.side.effects")); - return new Condition() { - @Override - public boolean value(String s) { - return pattern.matcher(s).matches(); - } - }; + String regex = Registry.stringValue("ide.dfa.getters.with.side.effects").trim(); + if (!StringUtil.isEmpty(regex)) { + final Pattern pattern = Pattern.compile(regex); + return new Condition() { + @Override + public boolean value(String s) { + return pattern.matcher(s).matches(); + } + }; + } } catch (Exception e) { LOG.error(e); - return Conditions.alwaysFalse(); } + return Conditions.alwaysFalse(); } private final DfaValueFactory myFactory; @@ -152,10 +156,11 @@ public class DfaExpressionFactory { return (PsiVariable)target; } if (target instanceof PsiMethod) { - if (PropertyUtil.isSimplePropertyGetter((PsiMethod)target)) { - String qName = PsiUtil.getMemberQualifiedName((PsiMethod)target); + PsiMethod method = (PsiMethod)target; + if (PropertyUtil.isSimplePropertyGetter(method) && !(method.getReturnType() instanceof PsiPrimitiveType)) { + String qName = PsiUtil.getMemberQualifiedName(method); if (qName == null || !FALSE_GETTERS.value(qName)) { - return (PsiMethod)target; + return method; } } } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FalseGetters.java b/java/java-tests/testData/inspection/dataFlow/fixture/FalseGetters.java new file mode 100644 index 000000000000..162aedeac284 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FalseGetters.java @@ -0,0 +1,21 @@ +class A { + private String s; + private int next = 0; + + public A(final String s) { + this.s = s; + } + + private char getChar() { + return s.charAt(next++); + } + + private void foo() { + char c = getChar(); + if (c == 'a') { + if (getChar() == 'b') { + System.out.println("ab"); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index 2a105e5bf7d0..5805808d3a17 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -271,6 +271,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testUnusedCallDoesNotMakeUnknown() { doTest(); } public void testEmptyCallDoesNotMakeNullable() { doTest(); } public void testGettersAndPureNoFlushing() { doTest(); } + public void testFalseGetters() { doTest(); } public void testNotNullAfterDereference() { doTest(); } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 44e369a5df3f..cc38adeb76fc 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -294,7 +294,7 @@ ide.structural.navigation.visit.fields.description=Whether fields should be stop ide.non.english.keyboard.layout.fix=false ide.non.english.keyboard.layout.fix.description=Enables a fix for key codes with non-English keyboard layouts -ide.dfa.getters.with.side.effects=java\\.nio\\..*ByteBuffer\\.get.* +ide.dfa.getters.with.side.effects= ide.dfa.getters.with.side.effects.description=A regex on qualified names of methods that look like getters but are not. For Constant Conditions & Exception inspection ide.dfa.time.limit.online=1000 From 1bd313a730870c7c519fb3d209544f660ddb95d7 Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 16:59:35 +0200 Subject: [PATCH 22/36] IDEA-139340 Inner class appears twice in code completion popup --- .../completion/JavaNoVariantsDelegator.java | 15 +++++++++++---- .../completion/normal/DuplicateInnerClass.java | 8 ++++++++ .../completion/NormalCompletionTest.groovy | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/DuplicateInnerClass.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index d526f1bd828b..b416e851610e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -50,8 +50,16 @@ public class JavaNoVariantsDelegator extends CompletionContributor { result.restartCompletionWhenNothingMatches(); } + InheritorsHolder holder = new InheritorsHolder(parameters.getPosition(), result); + for (CompletionResult plainResult : plainResults) { + Object o = plainResult.getLookupElement().getObject(); + if (o instanceof PsiClass) { + holder.registerClass((PsiClass)o); + } + } + if (empty) { - delegate(parameters, JavaCompletionSorting.addJavaSorting(parameters, result)); + delegate(parameters, JavaCompletionSorting.addJavaSorting(parameters, result), holder); } else if (Registry.is("ide.completion.show.better.matching.classes")) { if (parameters.getCompletionType() == CompletionType.BASIC && parameters.getInvocationCount() <= 1 && @@ -59,7 +67,6 @@ public class JavaNoVariantsDelegator extends CompletionContributor { JavaCompletionContributor.isClassNamePossible(parameters) && !JavaSmartCompletionContributor.AFTER_NEW.accepts(parameters.getPosition())) { result = result.withPrefixMatcher(new BetterPrefixMatcher(result.getPrefixMatcher(), BetterPrefixMatcher.getBestMatchingDegree(plainResults))); - InheritorsHolder holder = new InheritorsHolder(parameters.getPosition(), result); for (CompletionResult plainResult : plainResults) { LookupElement element = plainResult.getLookupElement(); if (element instanceof TypeArgumentCompletionProvider.TypeArgsLookupElement) { @@ -86,7 +93,7 @@ public class JavaNoVariantsDelegator extends CompletionContributor { return true; } - private static void delegate(CompletionParameters parameters, final CompletionResultSet result) { + private static void delegate(CompletionParameters parameters, final CompletionResultSet result, final InheritorsHolder inheritorsHolder) { if (parameters.getCompletionType() == CompletionType.BASIC) { PsiElement position = parameters.getPosition(); suggestCollectionUtilities(parameters, result, position); @@ -94,7 +101,7 @@ public class JavaNoVariantsDelegator extends CompletionContributor { if (parameters.getInvocationCount() <= 1 && (JavaCompletionContributor.mayStartClassName(result) || suggestMetaAnnotations(parameters)) && JavaCompletionContributor.isClassNamePossible(parameters)) { - suggestNonImportedClasses(parameters, result, null); + suggestNonImportedClasses(parameters, result, inheritorsHolder); return; } diff --git a/java/java-tests/testData/codeInsight/completion/normal/DuplicateInnerClass.java b/java/java-tests/testData/codeInsight/completion/normal/DuplicateInnerClass.java new file mode 100644 index 000000000000..86031e5e9724 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/DuplicateInnerClass.java @@ -0,0 +1,8 @@ +class Foo { + + public static void main(String[] args) { + Innex + } + + private static final class Inner { } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index b95761cefba3..4c89fb35582d 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -1269,6 +1269,12 @@ class XInternalError {} assert LookupElementPresentation.renderElement(items[0]).tailText == ' (java.lang)' } + public void testDuplicateInnerClass() { + configure() + def items = myFixture.lookupElements.findAll { it.lookupString == 'Inner' } + assert items.size() == 1 + } + public void testSameSignature() { configure() myFixture.assertPreferredCompletionItems(0, 's', 's, file', 's, file, a') From 254f33cb657d6969ec37edc20dde08e5368af63b Mon Sep 17 00:00:00 2001 From: Yaroslav Lepenkin Date: Mon, 18 May 2015 17:32:23 +0300 Subject: [PATCH 23/36] Provided extension point for detecting if source file is test data file. On this "test data" files during "before commit" actions stage no "Reformat, Rearrange and Optimize imports" actions will be performed (part of IDEA-140314) --- .../JavaLanguageTestDataChecker.java | 40 ++++++++++++++++++ .../projectRoots/LanguageTestDataChecker.java | 42 +++++++++++++++++++ .../src/META-INF/LangExtensionPoints.xml | 1 + .../vcs/checkin/CheckinHandlerUtil.java | 21 ++++++---- resources/src/META-INF/IdeaPlugin.xml | 1 + 5 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 java/java-impl/src/com/intellij/openapi/projectRoots/JavaLanguageTestDataChecker.java create mode 100644 platform/lang-api/src/com/intellij/openapi/projectRoots/LanguageTestDataChecker.java diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/JavaLanguageTestDataChecker.java b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaLanguageTestDataChecker.java new file mode 100644 index 000000000000..f3eafb51fbea --- /dev/null +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/JavaLanguageTestDataChecker.java @@ -0,0 +1,40 @@ +/* + * 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.openapi.projectRoots; + +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.StdFileTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; + +public class JavaLanguageTestDataChecker implements LanguageTestDataChecker { + + @Override + @NotNull + public FileType getFileType() { + return StdFileTypes.JAVA; + } + + @Override + public boolean isTestData(@NotNull Project project, @NotNull VirtualFile virtualFile) { + ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); + return !index.isUnderSourceRootOfType(virtualFile, JavaModuleSourceRootTypes.SOURCES); + } +} diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/LanguageTestDataChecker.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/LanguageTestDataChecker.java new file mode 100644 index 000000000000..bca5e35211ee --- /dev/null +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/LanguageTestDataChecker.java @@ -0,0 +1,42 @@ +/* + * 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.openapi.projectRoots; + +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +/** + * Files for which #isTestData returns true won't be processed by + * Optimize Imports, Reformat Code and Rearrange Code actions during before-commit stage. + * + * When developing language plugin it is improperly to perform any modification actions + * for language test data files (files that looks like source code, but are used only as test data) + * on commit, even if appropriate checkboxes in commit dialog are turned on. + */ +public interface LanguageTestDataChecker { + + ExtensionPointName EP_NAME = + new ExtensionPointName("com.intellij.languageTestDataChecker"); + + @NotNull + FileType getFileType(); + + boolean isTestData(@NotNull Project project, @NotNull VirtualFile virtualFile); + +} diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml index faea9a0a61ee..2aa532f8303d 100644 --- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml +++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml @@ -254,6 +254,7 @@ + diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/checkin/CheckinHandlerUtil.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/checkin/CheckinHandlerUtil.java index 4a5a644d4fbe..0a7389951b29 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/checkin/CheckinHandlerUtil.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/checkin/CheckinHandlerUtil.java @@ -16,10 +16,10 @@ package com.intellij.openapi.vcs.checkin; import com.intellij.openapi.components.StorageScheme; -import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; +import com.intellij.openapi.projectRoots.LanguageTestDataChecker; import com.intellij.openapi.roots.GeneratedSourcesFilter; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; @@ -30,7 +30,6 @@ import com.intellij.psi.PsiManager; import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; import javax.swing.*; import java.util.ArrayList; @@ -67,7 +66,8 @@ public class CheckinHandlerUtil { for (VirtualFile file : selectedFiles) { if (file.isValid()) { - if (isUnderProjectFileDir(projectFileDir, file) || !isFileUnderSourceRoot(project, file)) { + if (isUnderProjectFileDir(projectFileDir, file) || !isFileUnderSourceRoot(project, file) + || isLanguageTestData(project, file)) { continue; } PsiFile psiFile = psiManager.findFile(file); @@ -83,12 +83,17 @@ public class CheckinHandlerUtil { private static boolean isFileUnderSourceRoot(@NotNull Project project, @NotNull VirtualFile file) { ProjectFileIndex index = ProjectRootManager.getInstance(project).getFileIndex(); - if (StdFileTypes.JAVA == file.getFileType()) { - return index.isUnderSourceRootOfType(file, JavaModuleSourceRootTypes.SOURCES) && !index.isInLibrarySource(file); - } - else { - return index.isInContent(file) && !index.isInLibrarySource(file) ; + return index.isInContent(file) && !index.isInLibrarySource(file); + } + + private static boolean isLanguageTestData(@NotNull Project project, @NotNull VirtualFile file) { + for (LanguageTestDataChecker checker : LanguageTestDataChecker.EP_NAME.getExtensions()) { + if (checker.getFileType() == file.getFileType() + && checker.isTestData(project, file)) { + return true; + } } + return false; } static void disableWhenDumb(@NotNull Project project, @NotNull JCheckBox checkBox, @NotNull String tooltip) { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index a518d3a5e771..2f1aa5b7bb32 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1621,6 +1621,7 @@ + Date: Mon, 18 May 2015 17:09:59 +0200 Subject: [PATCH 24/36] make Darcula combos have same height as text fields --- .../ide/ui/laf/darcula/ui/DarculaComboBoxUI.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java index 259adc27f914..ec05f531f5bd 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/DarculaComboBoxUI.java @@ -93,7 +93,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { final int tH = JBUI.scale(6); final int xU = (w - tW) / 2; final int yU = (h - tH) / 2; - g.translate(JBUI.scale(2), 0); + g.translate(JBUI.scale(2), JBUI.scale(1)); final Path2D.Double path = new Path2D.Double(); path.moveTo(xU, yU); path.lineTo(xU + tW, yU); @@ -105,7 +105,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { //path.lineTo(xU + 1, yU + 2); path.closePath(); g.fill(path); - g.translate(-JBUI.scale(2), 0); + g.translate(-JBUI.scale(2), -JBUI.scale(1)); if (!isTableCellEditor(myComboBox)) { g.setColor(getArrowButtonFillColor(getBorderColor())); g.drawLine(0, -1, 0, h); @@ -224,7 +224,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { protected Rectangle rectangleForCurrentValue() { final Rectangle r = super.rectangleForCurrentValue(); r.x-= JBUI.scale(2); - r.y-= isTableCellEditor(myComboBox) ? 0 : JBUI.scale(1); + r.y-= isTableCellEditor(myComboBox) ? 0 : 0;//JBUI.scale(1); return r; } @@ -362,7 +362,7 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { final Color borderColor = getBorderColor();//ColorUtil.shift(UIUtil.getBorderColor(), 4); g.setColor(getArrowButtonFillColor(borderColor)); int off = hasFocus ? 1 : 0; - g.drawLine(xxx + JBUI.scale(5), y + JBUI.scale(1) + off, xxx + JBUI.scale(5), height - JBUI.scale(3)); + g.drawLine(xxx + JBUI.scale(5), y + JBUI.scale(1) + off, xxx + JBUI.scale(5), height - JBUI.scale(2)); Rectangle r = rectangleForCurrentValue(); paintCurrentValueBackground(g, r, hasFocus); @@ -373,13 +373,13 @@ public class DarculaComboBoxUI extends BasicComboBoxUI implements Border { } else { g.setColor(borderColor); - g.drawRoundRect(JBUI.scale(1), JBUI.scale(1), width - JBUI.scale(2), height - JBUI.scale(4), R, R); + g.drawRoundRect(JBUI.scale(1), JBUI.scale(1), width - JBUI.scale(2), height - JBUI.scale(2), R, R); if (!UIUtil.isUnderDarcula() && comboBox.isEnabled()) { g.setColor(getArrowButtonFillColor(getBorderColor())); final Shape clip = g.getClip(); final int offX = xxx + JBUI.scale(5); g.setClip(offX, y, width - offX, height); - g.drawRoundRect(JBUI.scale(1), JBUI.scale(1), width - JBUI.scale(2), height - JBUI.scale(4), R, R); + g.drawRoundRect(JBUI.scale(1), JBUI.scale(1), width - JBUI.scale(2), height - JBUI.scale(2), R, R); g.setClip(clip); } } From cde4257c5f434c2268a092bb843f48b01aa71a3c Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 18 May 2015 18:40:38 +0300 Subject: [PATCH 25/36] IDEA-140321 Wrong current line highlighting when debugging synchronized block in decompiled code --- .../stats/SynchronizedStatement.java | 11 +++++++ .../classes/pkg/TestSynchronizedMapping.class | Bin 577 -> 590 bytes .../results/TestSynchronizedMapping.dec | 30 ++++++++++-------- .../src/pkg/TestSynchronizedMapping.java | 3 +- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java index 3460e1404463..b71531f51d77 100644 --- a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java +++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java @@ -15,6 +15,8 @@ */ package org.jetbrains.java.decompiler.modules.decompiler.stats; +import org.jetbrains.java.decompiler.code.CodeConstants; +import org.jetbrains.java.decompiler.code.cfg.BasicBlock; import org.jetbrains.java.decompiler.main.TextBuffer; import org.jetbrains.java.decompiler.main.collectors.BytecodeMappingTracer; import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor; @@ -84,11 +86,20 @@ public class SynchronizedStatement extends Statement { buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true, tracer)); buf.appendIndent(indent).append("}").appendLineSeparator(); + mapMonitorExitInstr(tracer); tracer.incrementCurrentSourceLine(); return buf; } + private void mapMonitorExitInstr(BytecodeMappingTracer tracer) { + BasicBlock block = body.getBasichead().getBlock(); + if (!block.getSeq().isEmpty() && block.getLastInstruction().opcode == CodeConstants.opc_monitorexit) { + Integer offset = block.getOldOffset(block.size() - 1); + if (offset > -1) tracer.addMapping(offset); + } + } + public void initExprents() { headexprent.set(0, first.getExprents().remove(first.getExprents().size() - 1)); } diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestSynchronizedMapping.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestSynchronizedMapping.class index 4691cfd73b71245676afb1d365d86eb3f6efac4c..e320211ee8c1d159d989ef836cb6cc6dcd0b574f 100644 GIT binary patch delta 155 zcmW-ZJrV&y6okJwrfOzbX05V`l8Mwh3b_lohQtjVLO`HgK(V<4N$8rS`}OOem;do?DZ)UCLQN{NbG*pZ}~(u%@FV91nFaa-I^#~?7azyv}5 cDrMBl7*XAoR-HILI4|8iXD!t78vPuzKiYE;XaE2J delta 118 zcmW-Y!4W_(6h!w&W+FkDIO@Pq3iqf-2g=}}1B1Jk*m2pvZ+HKrPra`)MJQ+hRU3z^ znMJyL8@szd{@fvBm%;y6!IC@@YRWIm)FCI;ke84c6k@obluJ;3=|KlU;7FnV06Mk| A)&Kwi diff --git a/plugins/java-decompiler/engine/testData/results/TestSynchronizedMapping.dec b/plugins/java-decompiler/engine/testData/results/TestSynchronizedMapping.dec index 82b553b2bfdf..84ad48a1e660 100644 --- a/plugins/java-decompiler/engine/testData/results/TestSynchronizedMapping.dec +++ b/plugins/java-decompiler/engine/testData/results/TestSynchronizedMapping.dec @@ -3,33 +3,37 @@ package pkg; public class TestSynchronizedMapping { public int test(int var1) { synchronized(this) {// 8 - return var1++;// 9 - } + ++var1;// 9 + }// 10 + + return var1++;// 11 } public void test2(String var1) { - System.out.println(var1);// 14 - }// 15 + System.out.println(var1);// 15 + }// 16 } class 'pkg/TestSynchronizedMapping' { method 'test (I)I' { 3 4 - 5 5 - a 5 + 4 5 + 8 6 + 12 8 + 15 8 } method 'test2 (Ljava/lang/String;)V' { - 0 10 - 4 10 - 7 11 + 0 12 + 4 12 + 7 13 } } Lines mapping: 8 <-> 5 9 <-> 6 -14 <-> 11 -15 <-> 12 -Not mapped: -10 +10 <-> 7 +11 <-> 9 +15 <-> 13 +16 <-> 14 diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestSynchronizedMapping.java b/plugins/java-decompiler/engine/testData/src/pkg/TestSynchronizedMapping.java index 37f028236153..8effb75f24af 100644 --- a/plugins/java-decompiler/engine/testData/src/pkg/TestSynchronizedMapping.java +++ b/plugins/java-decompiler/engine/testData/src/pkg/TestSynchronizedMapping.java @@ -6,8 +6,9 @@ import java.lang.Runnable; public class TestSynchronizedMapping { public int test(int a) { synchronized (this) { - return a++; + a++; } + return a++; } public void test2(String a) { From d92ab690a72e93c3a8c13cdd84b388bd54a0b12e Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Tue, 17 Mar 2015 21:05:08 +0300 Subject: [PATCH 26/36] lst: remove duplication --- .../src/com/intellij/diff/util/DiffUtil.java | 6 ++ .../openapi/vcs/ex/LineStatusTracker.java | 79 +++---------------- .../com/intellij/openapi/vcs/ex/Range.java | 9 +-- 3 files changed, 18 insertions(+), 76 deletions(-) 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 cf487b335e6a..d634a57b7612 100644 --- a/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java +++ b/platform/diff-impl/src/com/intellij/diff/util/DiffUtil.java @@ -656,6 +656,12 @@ public class DiffUtil { return document.getImmutableCharSequence().subSequence(otherRange.getStartOffset(), otherRange.getEndOffset()); } + /** + * Return affected range, without non-internal newlines + *

+ * we consider '\n' not as a part of line, but a separator between lines + * ex: if last line is not empty, the last symbol will not be '\n' + */ @NotNull public static TextRange getLinesRange(@NotNull Document document, int line1, int line2) { if (line1 == line2) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 320d3f92ad51..7d9582233e5b 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.ex; +import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.undo.UndoConstants; @@ -49,6 +50,8 @@ import java.util.BitSet; import java.util.Collections; import java.util.List; +import static com.intellij.diff.util.DiffUtil.getLineCount; + /** * @author irengrig * author: lesya @@ -729,39 +732,7 @@ public class LineStatusTracker { } private void doRollbackRange(@NotNull Range range) { - if (range.getType() == Range.MODIFIED) { - TextRange currentTextRange = getCurrentTextRange(range); - int offset1 = currentTextRange.getStartOffset(); - int offset2 = currentTextRange.getEndOffset(); - - CharSequence vcsContent = getVcsContent(range); - myDocument.replaceString(offset1, offset2, vcsContent); - } - else if (range.getType() == Range.INSERTED) { - TextRange currentTextRange = getCurrentTextRange(range); - int offset1 = currentTextRange.getStartOffset(); - int offset2 = currentTextRange.getEndOffset(); - - if (offset1 > 0) { - offset1--; - } - else if (offset2 < myDocument.getTextLength()) { - offset2++; - } - myDocument.deleteString(offset1, offset2); - } - else if (range.getType() == Range.DELETED) { - CharSequence content = getVcsContent(range); - if (range.getLine2() == getLineCount(myDocument)) { - myDocument.insertString(myDocument.getTextLength(), "\n" + content); - } - else { - myDocument.insertString(myDocument.getLineStartOffset(range.getLine2()), content + "\n"); - } - } - else { - throw new IllegalArgumentException("Unknown range type: " + range.getType()); - } + DiffUtil.applyModification(myDocument, range.getLine1(), range.getLine2(), myVcsDocument, range.getVcsLine1(), range.getVcsLine2()); } public void rollbackChanges(@NotNull Range range) { @@ -793,14 +764,7 @@ public class LineStatusTracker { break; } - boolean check; - if (range.getLine1() == range.getLine2()) { - check = lines.get(range.getLine1()); - } - else { - int next = lines.nextSetBit(range.getLine1()); - check = next != -1 && next < range.getLine2(); - } + boolean check = DiffUtil.isSelectedByLine(lines, range.getLine1(), range.getLine2()); if (check) { if (first == null) { @@ -895,7 +859,7 @@ public class LineStatusTracker { LOG.warn("Current TextRange of invalid range"); } - return getRange(range.getLine1(), range.getLine2(), myDocument); + return DiffUtil.getLinesRange(myDocument, range.getLine1(), range.getLine2()); } } @@ -906,34 +870,15 @@ public class LineStatusTracker { LOG.warn("Vcs TextRange of invalid range"); } - return getRange(range.getVcsLine1(), range.getVcsLine2(), myVcsDocument); - } - } - - /** - * Return affected range, without non-internal '\n' - * so if last line is not empty, the last symbol will be not '\n' - *

- * So we consider '\n' not as a part of line, but a separator between lines - */ - @NotNull - private static TextRange getRange(int line1, int line2, @NotNull Document document) { - if (line1 == line2) { - int lineStartOffset = line1 < getLineCount(document) ? document.getLineStartOffset(line1) : document.getTextLength(); - return new TextRange(lineStartOffset, lineStartOffset); - } - else { - int startOffset = document.getLineStartOffset(line1); - int endOffset = document.getLineEndOffset(line2 - 1); - return new TextRange(startOffset, endOffset); + return DiffUtil.getLinesRange(myVcsDocument, range.getVcsLine1(), range.getVcsLine2()); } } public static LineStatusTracker createOn(@NotNull VirtualFile virtualFile, @NotNull final Document doc, final Project project, @NotNull Mode mode) { - final Document document = new DocumentImpl("", true); - document.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); - return new LineStatusTracker(doc, document, project, virtualFile, mode); + final Document vcsDocument = new DocumentImpl("", true); + vcsDocument.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); + return new LineStatusTracker(doc, vcsDocument, project, virtualFile, mode); } public static class RevisionPack { @@ -979,8 +924,4 @@ public class LineStatusTracker { myLabel.setText("Can not highlight changed lines. File is too big and there are too many changes."); } } - - private static int getLineCount(@NotNull Document document) { - return Math.max(document.getLineCount(), 1); - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java index 8b87fbf5c23e..69884fe22ae1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.ex; +import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.markup.RangeHighlighter; import com.intellij.util.diff.Diff; @@ -249,12 +250,6 @@ public class Range { * Check, if caret at is corresponds to the current range */ public boolean isSelectedByLine(int line) { - if (getType() == DELETED && line == myLine1) { - return true; - } - else if (line >= myLine1 && line < myLine2) { - return true; - } - return false; + return DiffUtil.isSelectedByLine(line, myLine1, myLine2); } } From 5040aa3d836734e548f58f047a13e4c9c4368db3 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 18 May 2015 18:43:03 +0300 Subject: [PATCH 27/36] lst: cleanup --- .../openapi/vcs/ex/LineStatusTracker.java | 28 ++++++++++--------- .../vcs/ex/LineStatusTrackerDrawing.java | 2 +- .../vcs/ex/ShowLineStatusRangeDiffAction.java | 3 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 7d9582233e5b..d4935922453a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -252,7 +252,7 @@ public class LineStatusTracker { } @NotNull - Project getProject() { + public Project getProject() { return myProject; } @@ -274,7 +274,7 @@ public class LineStatusTracker { @NotNull public List getRanges() { synchronized (myLock) { - return myRanges; + return Collections.unmodifiableList(myRanges); } } @@ -679,7 +679,7 @@ public class LineStatusTracker { } @Nullable - Range getNextRange(final Range range) { + public Range getNextRange(Range range) { synchronized (myLock) { final int index = myRanges.indexOf(range); if (index == myRanges.size() - 1) return null; @@ -688,7 +688,7 @@ public class LineStatusTracker { } @Nullable - Range getPrevRange(final Range range) { + public Range getPrevRange(Range range) { synchronized (myLock) { final int index = myRanges.indexOf(range); if (index <= 0) return null; @@ -697,7 +697,7 @@ public class LineStatusTracker { } @Nullable - public Range getNextRange(final int line) { + public Range getNextRange(int line) { synchronized (myLock) { for (Range range : myRanges) { if (line < range.getLine2() && !range.isSelectedByLine(line)) { @@ -709,7 +709,7 @@ public class LineStatusTracker { } @Nullable - public Range getPrevRange(final int line) { + public Range getPrevRange(int line) { synchronized (myLock) { for (int i = myRanges.size() - 1; i >= 0; i--) { Range range = myRanges.get(i); @@ -722,7 +722,7 @@ public class LineStatusTracker { } @Nullable - public Range getRangeForLine(final int line) { + public Range getRangeForLine(int line) { synchronized (myLock) { for (final Range range : myRanges) { if (range.isSelectedByLine(line)) return range; @@ -832,6 +832,7 @@ public class LineStatusTracker { } } + @NotNull public CharSequence getCurrentContent(@NotNull Range range) { synchronized (myLock) { TextRange textRange = getCurrentTextRange(range); @@ -841,9 +842,10 @@ public class LineStatusTracker { } } + @NotNull public CharSequence getVcsContent(@NotNull Range range) { synchronized (myLock) { - TextRange textRange = getVcsRange(range); + TextRange textRange = getVcsTextRange(range); final int startOffset = textRange.getStartOffset(); final int endOffset = textRange.getEndOffset(); return myVcsDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); @@ -851,7 +853,7 @@ public class LineStatusTracker { } @NotNull - TextRange getCurrentTextRange(@NotNull Range range) { + public TextRange getCurrentTextRange(@NotNull Range range) { myApplication.assertReadAccessAllowed(); synchronized (myLock) { @@ -864,7 +866,7 @@ public class LineStatusTracker { } @NotNull - TextRange getVcsRange(@NotNull Range range) { + public TextRange getVcsTextRange(@NotNull Range range) { synchronized (myLock) { if (!range.isValid()) { LOG.warn("Vcs TextRange of invalid range"); @@ -874,11 +876,11 @@ public class LineStatusTracker { } } - public static LineStatusTracker createOn(@NotNull VirtualFile virtualFile, @NotNull final Document doc, final Project project, + public static LineStatusTracker createOn(@NotNull VirtualFile virtualFile, @NotNull final Document document, final Project project, @NotNull Mode mode) { final Document vcsDocument = new DocumentImpl("", true); vcsDocument.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE); - return new LineStatusTracker(doc, vcsDocument, project, virtualFile, mode); + return new LineStatusTracker(document, vcsDocument, project, virtualFile, mode); } public static class RevisionPack { @@ -919,7 +921,7 @@ public class LineStatusTracker { } } - public static class CanNotCalculateDiffPanel extends EditorNotificationPanel { + private static class CanNotCalculateDiffPanel extends EditorNotificationPanel { public CanNotCalculateDiffPanel() { myLabel.setText("Can not highlight changed lines. File is too big and there are too many changes."); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java index 4a17bbc937f7..d29e373cca59 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTrackerDrawing.java @@ -291,7 +291,7 @@ public class LineStatusTrackerDrawing { }, Registry.intValue("diff.status.tracker.byword.delay")); if (diff == null) throw new DiffTooBigException(); - int vcsStartShift = tracker.getVcsRange(range).getStartOffset(); + int vcsStartShift = tracker.getVcsTextRange(range).getStartOffset(); int currentStartShift = tracker.getCurrentTextRange(range).getStartOffset(); for (DiffFragment fragment : diff) { int vcsStart = vcsStartShift + fragment.getStartOffset1(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index e8418e230fac..ffb1b7c29ea3 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -16,7 +16,6 @@ package com.intellij.openapi.vcs.ex; import com.intellij.diff.DiffContentFactory; -import com.intellij.diff.DiffDialogHints; import com.intellij.diff.DiffManager; import com.intellij.diff.actions.DocumentFragmentContent; import com.intellij.diff.contents.DiffContent; @@ -53,7 +52,7 @@ public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { Range range = expand(myRange, myLineStatusTracker.getDocument(), myLineStatusTracker.getVcsDocument()); DiffContent vcsContent = createDiffContent(myLineStatusTracker.getVcsDocument(), - myLineStatusTracker.getVcsRange(range), + myLineStatusTracker.getVcsTextRange(range), null); DiffContent currentContent = createDiffContent(myLineStatusTracker.getDocument(), myLineStatusTracker.getCurrentTextRange(range), From 12c3d7f0069cfbe26ad5d51b294176dcbd1ea16b Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Sat, 18 Apr 2015 15:48:09 +0300 Subject: [PATCH 28/36] lst: remove unnecessary field --- .../openapi/vcs/ex/LineStatusTracker.java | 4 +- .../com/intellij/openapi/vcs/ex/Range.java | 118 +++++++----------- .../openapi/vcs/ex/RangesBuilder.java | 8 +- .../vcs/ex/ShowLineStatusRangeDiffAction.java | 2 +- .../impl/UpToDateLineNumberProviderImpl.java | 22 ++-- 5 files changed, 63 insertions(+), 91 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index d4935922453a..4c95033ed1bb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -526,10 +526,10 @@ public class LineStatusTracker { return Collections.emptyList(); } if (changedLine1 == changedLine2) { - return Collections.singletonList(new Range(changedLine1, changedLine2, vcsLine1, vcsLine2, Range.DELETED)); + return Collections.singletonList(new Range(changedLine1, changedLine2, vcsLine1, vcsLine2)); } if (vcsLine1 == vcsLine2) { - return Collections.singletonList(new Range(changedLine1, changedLine2, vcsLine1, vcsLine2, Range.INSERTED)); + return Collections.singletonList(new Range(changedLine1, changedLine2, vcsLine1, vcsLine2)); } List lines = new DocumentWrapper(myDocument).getLines(changedLine1, changedLine2 - 1); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java index 69884fe22ae1..1840022ce0d2 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/Range.java @@ -18,16 +18,11 @@ package com.intellij.openapi.vcs.ex; import com.intellij.diff.util.DiffUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.markup.RangeHighlighter; -import com.intellij.util.diff.Diff; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -/** - * author: lesya - */ public class Range { private static final Logger LOG = Logger.getInstance(Range.class); public static final byte EQUAL = 0; @@ -42,81 +37,64 @@ public class Range { private int myLine2; private final int myVcsLine1; private final int myVcsLine2; - private final byte myType; - @Nullable private RangeHighlighter myRangeHighlighter; @Nullable private final List myInnerRanges; + @Nullable private RangeHighlighter myRangeHighlighter; private boolean myValid = true; public Range(@NotNull Range range) { - this(range.getLine1(), range.getLine2(), range.getVcsLine1(), range.getVcsLine2(), range.getType()); + this(range.getLine1(), range.getLine2(), range.getVcsLine1(), range.getVcsLine2()); } - public Range(int line1, int line2, int vcsLine1, int vcsLine2, byte type) { - this(line1, line2, vcsLine1, vcsLine2, type, null); + public Range(int line1, int line2, int vcsLine1, int vcsLine2) { + this(line1, line2, vcsLine1, vcsLine2, null); } - public Range(int line1, int line2, int vcsLine1, int vcsLine2, byte type, @Nullable List innerRanges) { + public Range(int line1, int line2, int vcsLine1, int vcsLine2, @Nullable List innerRanges) { + assert line1 != line2 || vcsLine1 != vcsLine2; + myLine1 = line1; myLine2 = line2; myVcsLine1 = vcsLine1; myVcsLine2 = vcsLine2; - myType = type; myInnerRanges = innerRanges; } public int hashCode() { - return myVcsLine1 ^ myVcsLine2 ^ myType ^ myLine1 ^ myLine2; + return myVcsLine1 ^ myVcsLine2 ^ myLine1 ^ myLine2; } - public boolean equals(Object object) { - if (!(object instanceof Range)) return false; - Range other = (Range)object; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; - if (myInnerRanges != null) { - if (other.myInnerRanges == null) return false; - if (myInnerRanges.size() != other.myInnerRanges.size()) return false; + Range range = (Range)o; - for (int i = 0; i < myInnerRanges.size(); i++) { - if (!myInnerRanges.get(i).equals(other.myInnerRanges.get(i))) return false; - } - } - else { - if (other.myInnerRanges != null) return false; + if (myLine1 != range.myLine1) return false; + if (myLine2 != range.myLine2) return false; + if (myVcsLine1 != range.myVcsLine1) return false; + if (myVcsLine2 != range.myVcsLine2) return false; + + if (myInnerRanges == null) return range.myInnerRanges == null; + if (range.myInnerRanges == null) return false; + + if (myInnerRanges.size() != range.myInnerRanges.size()) return false; + for (int i = 0; i < myInnerRanges.size(); i++) { + if (!myInnerRanges.get(i).equals(range.myInnerRanges.get(i))) return false; } - return - (myVcsLine1 == other.myVcsLine1) - && (myVcsLine2 == other.myVcsLine2) - && (myLine1 == other.myLine1) - && (myLine2 == other.myLine2) - && (myType == other.myType); + return true; } public String toString() { - return String.format("%s, %s, %s, %s, %s", myLine1, myLine2, myVcsLine1, myVcsLine2, getTypeName()); - } - - @NonNls - private String getTypeName() { - switch (myType) { - case MODIFIED: - return "MODIFIED"; - case INSERTED: - return "INSERTED"; - case DELETED: - return "DELETED"; - } - return "UNKNOWN"; + return String.format("%s, %s, %s, %s", myLine1, myLine2, myVcsLine1, myVcsLine2); } public byte getType() { - return myType; - } - - public int getUpToDateRangeLength() { - return myVcsLine2 - myVcsLine1; + if (myLine1 == myLine2) return DELETED; + if (myVcsLine1 == myVcsLine2) return INSERTED; + return MODIFIED; } public void shift(int shift) { @@ -151,15 +129,11 @@ public class Range { return myVcsLine2; } - public boolean rightBefore(@NotNull Range range) { - return myLine2 == range.myLine1; - } - public boolean hasHighlighter() { return myRangeHighlighter != null; } - public void setHighlighter(RangeHighlighter highlighter) { + public void setHighlighter(@Nullable RangeHighlighter highlighter) { myRangeHighlighter = highlighter; } @@ -211,8 +185,8 @@ public class Range { InnerRange range = (InnerRange)o; - if (myLine2 != range.myLine2) return false; if (myLine1 != range.myLine1) return false; + if (myLine2 != range.myLine2) return false; if (myType != range.myType) return false; return true; @@ -227,22 +201,7 @@ public class Range { } public String toString() { - return String.format("%s, %s, %s", myLine1, myLine2, getTypeName()); - } - - @NonNls - private String getTypeName() { - switch (myType) { - case MODIFIED: - return "MODIFIED"; - case INSERTED: - return "INSERTED"; - case DELETED: - return "DELETED"; - case EQUAL: - return "EQUAL"; - } - return "UNKNOWN"; + return String.format("%s, %s, %s", myLine1, myLine2, getTypeName(myType)); } } @@ -252,4 +211,19 @@ public class Range { public boolean isSelectedByLine(int line) { return DiffUtil.isSelectedByLine(line, myLine1, myLine2); } + + @NotNull + private static String getTypeName(byte type) { + switch (type) { + case MODIFIED: + return "MODIFIED"; + case INSERTED: + return "INSERTED"; + case DELETED: + return "DELETED"; + case EQUAL: + return "EQUAL"; + } + return "UNKNOWN(" + type + ")"; + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java index ccb5b3390a30..18cf26ec9be1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RangesBuilder.java @@ -101,15 +101,13 @@ public class RangesBuilder { } private static Range createOn(@NotNull Diff.Change change, int shift, int vcsShift) { - byte type = getChangeType(change); - int offset1 = shift + change.line1; int offset2 = offset1 + change.inserted; int uOffset1 = vcsShift + change.line0; int uOffset2 = uOffset1 + change.deleted; - return new Range(offset1, offset2, uOffset1, uOffset2, type); + return new Range(offset1, offset2, uOffset1, uOffset2); } private static Range createOnSmart(@NotNull Diff.Change change, @@ -126,7 +124,7 @@ public class RangesBuilder { int uOffset2 = uOffset1 + change.deleted; if (type != Range.MODIFIED) { - return new Range(offset1, offset2, uOffset1, uOffset2, type, Collections.singletonList(new Range.InnerRange(offset1, offset2, type))); + return new Range(offset1, offset2, uOffset1, uOffset2, Collections.singletonList(new Range.InnerRange(offset1, offset2, type))); } LineWrapper[] lines1 = new LineWrapper[change.deleted]; @@ -169,7 +167,7 @@ public class RangesBuilder { inner.add(new Range.InnerRange(innerStart, innerEnd, innerType)); } - return new Range(offset1, offset2, uOffset1, uOffset2, type, inner); + return new Range(offset1, offset2, uOffset1, uOffset2, inner); } private static byte getChangeType(@NotNull Diff.Change change) { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java index ffb1b7c29ea3..67ba09038d7f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/ShowLineStatusRangeDiffAction.java @@ -80,6 +80,6 @@ public class ShowLineStatusRangeDiffAction extends BaseLineStatusRangeAction { int uOffset1 = range.getVcsLine1() - (canExpandBefore ? 1 : 0); int offset2 = range.getLine2() + (canExpandAfter ? 1 : 0); int uOffset2 = range.getVcsLine2() + (canExpandAfter ? 1 : 0); - return new Range(offset1, offset2, uOffset1, uOffset2, range.getType()); + return new Range(offset1, offset2, uOffset1, uOffset2); } } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java index 5d049f3e9c14..19f28961b96a 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/UpToDateLineNumberProviderImpl.java @@ -44,7 +44,7 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide } return calcLineNumber(tracker, currentNumber); } - + public boolean isRangeChanged(final int start, final int end) { LineStatusTracker tracker = LineStatusTrackerManager.getInstance(myProject).getLineStatusTracker(myDocument); if (tracker == null) { @@ -60,7 +60,7 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide } return false; } - + private static boolean lineInRange(final Range range, final int currentNumber) { return range.getLine1() <= currentNumber && range.getLine2() >= currentNumber; } @@ -106,23 +106,23 @@ public class UpToDateLineNumberProviderImpl implements UpToDateLineNumberProvide private static int calcLineNumber(LineStatusTracker tracker, int currentNumber){ if (tracker == null) return -1; - List ranges = tracker.getRanges(); + List ranges = tracker.getRanges(); int result = currentNumber; - for (final Object range1 : ranges) { - Range range = (Range)range1; - int startOffset = range.getLine1(); - int endOffset = range.getLine2(); + for (final Range range : ranges) { + int startLine = range.getLine1(); + int endLine = range.getLine2(); - if ((startOffset <= currentNumber) && (endOffset > currentNumber)) { + if ((startLine <= currentNumber) && (endLine > currentNumber)) { return ABSENT_LINE_NUMBER; } - if (endOffset > currentNumber) return result; + if (endLine > currentNumber) return result; - int currentRangeLength = endOffset - startOffset; + int currentRangeLength = endLine - startLine; + int vcsRangeLength = range.getVcsLine2() - range.getVcsLine1(); - result += range.getUpToDateRangeLength() - currentRangeLength; + result += vcsRangeLength - currentRangeLength; } return result; From 8e83f655d6df89c8988dfd94bb1f0ce833a6d241 Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 18 May 2015 18:50:21 +0300 Subject: [PATCH 29/36] lst: replace myLock with ReadLock using LST has little sense without readlock anyway --- .../openapi/vcs/ex/LineStatusTracker.java | 392 +++++++++--------- .../vcs/impl/LineStatusTrackerManager.java | 2 + 2 files changed, 188 insertions(+), 206 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java index 4c95033ed1bb..bc5de9fbda92 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java @@ -42,8 +42,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotificationPanel; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.diff.FilesTooBigForDiffException; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.*; import java.util.ArrayList; import java.util.BitSet; @@ -63,7 +62,6 @@ public class LineStatusTracker { private static final Key PANEL_KEY = new Key("LineStatusTracker.CanNotCalculateDiffPanel"); - private final Object myLock = new Object(); private boolean myInitialized; @NotNull private final Project myProject; @@ -106,51 +104,50 @@ public class LineStatusTracker { myRanges = new ArrayList(); } + @CalledInAwt public void initialize(@NotNull final String vcsContent, @NotNull RevisionPack baseRevisionNumber) { myApplication.assertIsDispatchThread(); + if (myReleased) return; - synchronized (myLock) { - try { - if (myReleased) return; - if (myBaseRevisionNumber != null && myBaseRevisionNumber.contains(baseRevisionNumber)) return; + try { + if (myBaseRevisionNumber != null && myBaseRevisionNumber.contains(baseRevisionNumber)) return; - myBaseRevisionNumber = baseRevisionNumber; + myBaseRevisionNumber = baseRevisionNumber; - myVcsDocument.setReadOnly(false); - myVcsDocument.setText(vcsContent); - myVcsDocument.setReadOnly(true); - reinstallRanges(); + myVcsDocument.setReadOnly(false); + myVcsDocument.setText(vcsContent); + myVcsDocument.setReadOnly(true); + reinstallRanges(); - if (myDocumentListener == null) { - myDocumentListener = new MyDocumentListener(); - myDocument.addDocumentListener(myDocumentListener); - } - } - finally { - myInitialized = true; + if (myDocumentListener == null) { + myDocumentListener = new MyDocumentListener(); + myDocument.addDocumentListener(myDocumentListener); } } + finally { + myInitialized = true; + } } + @CalledInAwt private void reinstallRanges() { myApplication.assertIsDispatchThread(); - synchronized (myLock) { - removeAnathema(); - removeHighlightersFromMarkupModel(); - try { - myRanges = new RangesBuilder(myDocument, myVcsDocument, myMode).getRanges(); - } - catch (FilesTooBigForDiffException e) { - installAnathema(); - return; - } - for (final Range range : myRanges) { - range.setHighlighter(createHighlighter(range)); - } + removeAnathema(); + removeHighlightersFromMarkupModel(); + try { + myRanges = new RangesBuilder(myDocument, myVcsDocument, myMode).getRanges(); + } + catch (FilesTooBigForDiffException e) { + installAnathema(); + return; + } + for (final Range range : myRanges) { + range.setHighlighter(createHighlighter(range)); } } + @CalledInAwt private void installAnathema() { myAnathemaThrown = true; final FileEditor[] editors = myFileEditorManager.getAllEditors(myVirtualFile); @@ -164,6 +161,7 @@ public class LineStatusTracker { } } + @CalledInAwt private void removeAnathema() { if (!myAnathemaThrown) return; myAnathemaThrown = false; @@ -177,15 +175,15 @@ public class LineStatusTracker { } } + @CalledInAwt public void setMode(@NotNull Mode mode) { - synchronized (myLock) { - if (myMode == mode) return; - myMode = mode; - reinstallRanges(); - } + if (myMode == mode) return; + myMode = mode; + reinstallRanges(); } @NotNull + @CalledInAwt private RangeHighlighter createHighlighter(@NotNull Range range) { myApplication.assertIsDispatchThread(); @@ -228,27 +226,31 @@ public class LineStatusTracker { } public void release() { - synchronized (myLock) { - myReleased = true; - if (myDocumentListener != null) { - myDocument.removeDocumentListener(myDocumentListener); - } + myApplication.runReadAction(new Runnable() { + @Override + public void run() { + if (myReleased) return; + myReleased = true; + if (myDocumentListener != null) { + myDocument.removeDocumentListener(myDocumentListener); + } - if (myApplication.isDispatchThread()) { - removeAnathema(); - removeHighlightersFromMarkupModel(); + if (myApplication.isDispatchThread()) { + removeAnathema(); + removeHighlightersFromMarkupModel(); + } + else { + invalidateRanges(); + myApplication.invokeLater(new Runnable() { + @Override + public void run() { + removeAnathema(); + removeHighlightersFromMarkupModel(); + } + }); + } } - else { - invalidateRanges(); - myApplication.invokeLater(new Runnable() { - @Override - public void run() { - removeAnathema(); - removeHighlightersFromMarkupModel(); - } - }); - } - } + }); } @NotNull @@ -272,51 +274,46 @@ public class LineStatusTracker { } @NotNull + @CalledWithReadLock public List getRanges() { - synchronized (myLock) { - return Collections.unmodifiableList(myRanges); - } + return Collections.unmodifiableList(myRanges); } + @CalledInAwt public void startBulkUpdate() { - synchronized (myLock) { - if (myReleased) return; + if (myReleased) return; - myBulkUpdate = true; - removeAnathema(); - removeHighlightersFromMarkupModel(); - } + myBulkUpdate = true; + removeAnathema(); + removeHighlightersFromMarkupModel(); } + @CalledInAwt private void removeHighlightersFromMarkupModel() { myApplication.assertIsDispatchThread(); - synchronized (myLock) { - for (Range range : myRanges) { - if (range.getHighlighter() != null) { - range.getHighlighter().dispose(); - } - range.invalidate(); + for (Range range : myRanges) { + if (range.getHighlighter() != null) { + range.getHighlighter().dispose(); } - myRanges.clear(); + range.invalidate(); } + myRanges.clear(); } + @CalledWithReadLock private void invalidateRanges() { - synchronized (myLock) { - for (Range range : myRanges) { - range.invalidate(); - } + for (Range range : myRanges) { + range.invalidate(); } } + @CalledInAwt public void finishBulkUpdate() { - synchronized (myLock) { - if (myReleased) return; + if (myReleased) return; - myBulkUpdate = false; - reinstallRanges(); - } + myBulkUpdate = false; + reinstallRanges(); } private void markFileUnchanged() { @@ -324,11 +321,7 @@ public class LineStatusTracker { @Override public void run() { FileDocumentManager.getInstance().saveDocument(myDocument); - boolean stillEmpty; - synchronized (myLock) { - stillEmpty = myRanges.isEmpty(); - } - if (stillEmpty) { + if (myRanges.isEmpty()) { // file was modified, and now it's not -> dirty local change myVcsDirtyScopeManager.fileDirty(myVirtualFile); } @@ -349,27 +342,25 @@ public class LineStatusTracker { @Override public void beforeDocumentChange(DocumentEvent e) { myApplication.assertIsDispatchThread(); + if (myReleased) return; - synchronized (myLock) { - if (myReleased) return; - if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return; - assert myDocument == e.getDocument(); + if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return; + assert myDocument == e.getDocument(); - try { - myLine1 = myDocument.getLineNumber(e.getOffset()); - if (e.getOldLength() == 0) { - myBeforeChangedLines = 1; - } - else { - int line1 = myLine1; - int line2 = myDocument.getLineNumber(e.getOffset() + e.getOldLength()); - myBeforeChangedLines = line2 - line1 + 1; - } - - myBeforeTotalLines = getLineCount(myDocument); + try { + myLine1 = myDocument.getLineNumber(e.getOffset()); + if (e.getOldLength() == 0) { + myBeforeChangedLines = 1; } - catch (ProcessCanceledException ignore) { + else { + int line1 = myLine1; + int line2 = myDocument.getLineNumber(e.getOffset() + e.getOldLength()); + myBeforeChangedLines = line2 - line1 + 1; } + + myBeforeTotalLines = getLineCount(myDocument); + } + catch (ProcessCanceledException ignore) { } } @@ -377,32 +368,30 @@ public class LineStatusTracker { public void documentChanged(final DocumentEvent e) { myApplication.assertIsDispatchThread(); - synchronized (myLock) { - if (myReleased) return; - if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return; - assert myDocument == e.getDocument(); + if (myReleased) return; + if (myBulkUpdate || mySuppressUpdate || myAnathemaThrown || !myInitialized) return; + assert myDocument == e.getDocument(); - int afterChangedLines; - if (e.getNewLength() == 0) { - afterChangedLines = 1; - } - else { - int line1 = myLine1; - int line2 = myDocument.getLineNumber(e.getOffset() + e.getNewLength()); - afterChangedLines = line2 - line1 + 1; - } - - int linesShift = afterChangedLines - myBeforeChangedLines; - - int line1 = myLine1; - int line2 = line1 + myBeforeChangedLines; - - int[] fixed = fixRanges(e, line1, line2); - line1 = fixed[0]; - line2 = fixed[1]; - - doUpdateRanges(line1, line2, linesShift, myBeforeTotalLines); + int afterChangedLines; + if (e.getNewLength() == 0) { + afterChangedLines = 1; } + else { + int line1 = myLine1; + int line2 = myDocument.getLineNumber(e.getOffset() + e.getNewLength()); + afterChangedLines = line2 - line1 + 1; + } + + int linesShift = afterChangedLines - myBeforeChangedLines; + + int line1 = myLine1; + int line2 = line1 + myBeforeChangedLines; + + int[] fixed = fixRanges(e, line1, line2); + line1 = fixed[0]; + line2 = fixed[1]; + + doUpdateRanges(line1, line2, linesShift, myBeforeTotalLines); } } @@ -679,77 +668,73 @@ public class LineStatusTracker { } @Nullable + @CalledWithReadLock public Range getNextRange(Range range) { - synchronized (myLock) { - final int index = myRanges.indexOf(range); - if (index == myRanges.size() - 1) return null; - return myRanges.get(index + 1); - } + final int index = myRanges.indexOf(range); + if (index == myRanges.size() - 1) return null; + return myRanges.get(index + 1); } @Nullable + @CalledWithReadLock public Range getPrevRange(Range range) { - synchronized (myLock) { - final int index = myRanges.indexOf(range); - if (index <= 0) return null; - return myRanges.get(index - 1); - } + final int index = myRanges.indexOf(range); + if (index <= 0) return null; + return myRanges.get(index - 1); } @Nullable + @CalledWithReadLock public Range getNextRange(int line) { - synchronized (myLock) { - for (Range range : myRanges) { - if (line < range.getLine2() && !range.isSelectedByLine(line)) { - return range; - } + for (Range range : myRanges) { + if (line < range.getLine2() && !range.isSelectedByLine(line)) { + return range; } - return null; } + return null; } @Nullable + @CalledWithReadLock public Range getPrevRange(int line) { - synchronized (myLock) { - for (int i = myRanges.size() - 1; i >= 0; i--) { - Range range = myRanges.get(i); - if (line > range.getLine1() && !range.isSelectedByLine(line)) { - return range; - } + for (int i = myRanges.size() - 1; i >= 0; i--) { + Range range = myRanges.get(i); + if (line > range.getLine1() && !range.isSelectedByLine(line)) { + return range; } - return null; } + return null; } @Nullable + @CalledWithReadLock public Range getRangeForLine(int line) { - synchronized (myLock) { - for (final Range range : myRanges) { - if (range.isSelectedByLine(line)) return range; - } - return null; + for (final Range range : myRanges) { + if (range.isSelectedByLine(line)) return range; } + return null; } + @CalledWithWriteLock private void doRollbackRange(@NotNull Range range) { DiffUtil.applyModification(myDocument, range.getLine1(), range.getLine2(), myVcsDocument, range.getVcsLine1(), range.getVcsLine2()); } + @CalledWithWriteLock public void rollbackChanges(@NotNull Range range) { myApplication.assertWriteAccessAllowed(); - synchronized (myLock) { - if (myBulkUpdate) return; + if (myBulkUpdate) return; - if (!range.isValid()) { - LOG.warn("Rollback of invalid range"); - return; - } - - doRollbackRange(range); + if (!range.isValid()) { + LOG.warn("Rollback of invalid range"); + return; } + + doRollbackRange(range); } + @CalledWithWriteLock public void rollbackChanges(@NotNull final BitSet lines) { runBulkRollback(new Runnable() { @Override @@ -793,6 +778,7 @@ public class LineStatusTracker { }); } + @CalledWithWriteLock public void rollbackAllChanges() { runBulkRollback(new Runnable() { @Override @@ -807,75 +793,69 @@ public class LineStatusTracker { }); } + @CalledWithWriteLock private void runBulkRollback(@NotNull Runnable task) { myApplication.assertWriteAccessAllowed(); - synchronized (myLock) { - if (myBulkUpdate) return; + if (myBulkUpdate) return; - try { - mySuppressUpdate = true; + try { + mySuppressUpdate = true; - task.run(); - } - catch (Error e) { - reinstallRanges(); - throw e; - } - catch (RuntimeException e) { - reinstallRanges(); - throw e; - } - finally { - mySuppressUpdate = false; - } + task.run(); + } + catch (Error e) { + reinstallRanges(); + throw e; + } + catch (RuntimeException e) { + reinstallRanges(); + throw e; + } + finally { + mySuppressUpdate = false; } } @NotNull + @CalledWithReadLock public CharSequence getCurrentContent(@NotNull Range range) { - synchronized (myLock) { - TextRange textRange = getCurrentTextRange(range); - final int startOffset = textRange.getStartOffset(); - final int endOffset = textRange.getEndOffset(); - return myDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); - } + TextRange textRange = getCurrentTextRange(range); + final int startOffset = textRange.getStartOffset(); + final int endOffset = textRange.getEndOffset(); + return myDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); } @NotNull + @CalledWithReadLock public CharSequence getVcsContent(@NotNull Range range) { - synchronized (myLock) { - TextRange textRange = getVcsTextRange(range); - final int startOffset = textRange.getStartOffset(); - final int endOffset = textRange.getEndOffset(); - return myVcsDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); - } + TextRange textRange = getVcsTextRange(range); + final int startOffset = textRange.getStartOffset(); + final int endOffset = textRange.getEndOffset(); + return myVcsDocument.getImmutableCharSequence().subSequence(startOffset, endOffset); } @NotNull + @CalledWithReadLock public TextRange getCurrentTextRange(@NotNull Range range) { - myApplication.assertReadAccessAllowed(); - - synchronized (myLock) { - if (!range.isValid()) { - LOG.warn("Current TextRange of invalid range"); - } - - return DiffUtil.getLinesRange(myDocument, range.getLine1(), range.getLine2()); + if (!range.isValid()) { + LOG.warn("Current TextRange of invalid range"); } + + return DiffUtil.getLinesRange(myDocument, range.getLine1(), range.getLine2()); } @NotNull + @CalledWithReadLock public TextRange getVcsTextRange(@NotNull Range range) { - synchronized (myLock) { - if (!range.isValid()) { - LOG.warn("Vcs TextRange of invalid range"); - } - - return DiffUtil.getLinesRange(myVcsDocument, range.getVcsLine1(), range.getVcsLine2()); + if (!range.isValid()) { + LOG.warn("Vcs TextRange of invalid range"); } + + return DiffUtil.getLinesRange(myVcsDocument, range.getVcsLine1(), range.getVcsLine2()); } + @NotNull public static LineStatusTracker createOn(@NotNull VirtualFile virtualFile, @NotNull final Document document, final Project project, @NotNull Mode mode) { final Document vcsDocument = new DocumentImpl("", true); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java index 6de1143b6f8a..265e7fe38871 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/impl/LineStatusTrackerManager.java @@ -62,6 +62,7 @@ import com.intellij.util.containers.HashMap; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.CalledInAwt; import java.util.Map; @@ -208,6 +209,7 @@ public class LineStatusTrackerManager implements ProjectComponent, LineStatusTra } } + @CalledInAwt public void updateSettings() { synchronized (myLock) { LineStatusTracker.Mode mode = getMode(); From 987942fbd0d73ae89715c5d0f9e1a6ffb36b20fa Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 17:20:31 +0200 Subject: [PATCH 30/36] IDEA-138472 Cannot step into current line when debug groovy code suppose the extension is not ".groovy" --- .../jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java | 3 +-- .../groovy/lang/psi/stubs/elements/GrStubFileElementType.java | 2 +- .../src/org/jetbrains/plugins/groovy/GroovyFileTypeLoader.java | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java index 4d482477da42..abe676008c09 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/GrFileStub.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.groovy.lang.psi.stubs; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.stubs.PsiFileStubImpl; import com.intellij.psi.tree.IStubFileElementType; import com.intellij.util.ArrayUtil; @@ -34,7 +33,7 @@ public class GrFileStub extends PsiFileStubImpl { public GrFileStub(GroovyFile file) { super(file); - myName = StringRef.fromString(StringUtil.trimEnd(file.getName(), ".groovy")); + myName = StringRef.fromString(file.getViewProvider().getVirtualFile().getNameWithoutExtension()); isScript = file.isScript(); final GrPackageDefinition definition = file.getPackageDefinition(); if (definition != null) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java index 8ccfe21915f8..1942f869f58f 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/stubs/elements/GrStubFileElementType.java @@ -58,7 +58,7 @@ public class GrStubFileElementType extends IStubFileElementType { @Override public int getStubVersion() { - return super.getStubVersion() + 21; + return super.getStubVersion() + 22; } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileTypeLoader.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileTypeLoader.java index 734cae7b3470..16cb6a7b1142 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileTypeLoader.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/GroovyFileTypeLoader.java @@ -32,8 +32,7 @@ public class GroovyFileTypeLoader extends FileTypeFactory{ public static Set getCustomGroovyScriptExtensions() { final LinkedHashSet strings = new LinkedHashSet(); strings.add("gdsl"); - strings.add("gpp"); - strings.add("grunit"); + strings.add("gy"); for (GroovyScriptTypeDetector ep : GroovyScriptTypeDetector.EP_NAME.getExtensions()) { Collections.addAll(strings, ep.getExtensions()); } From 6198d8700e665c9da19dc30e82d7be49d03f1acf Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 17:47:12 +0200 Subject: [PATCH 31/36] IDEA-138115 Disable middle matching for Java keyword completion --- .../completion/Java18CompletionData.java | 8 +- .../completion/JavaAwareCompletionData.java | 2 - .../completion/JavaCompletionContributor.java | 27 ++++- .../completion/JavaCompletionData.java | 104 ++++++++---------- .../completion/JavaAutoPopupTest.groovy | 2 +- .../completion/NormalCompletionTest.groovy | 4 +- .../completion/VariablesCompletionTest.groovy | 4 +- 7 files changed, 82 insertions(+), 69 deletions(-) diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java index 7ab087b78b8f..c169dc8cf0b6 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/Java18CompletionData.java @@ -17,9 +17,11 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.daemon.impl.analysis.LambdaHighlightingUtil; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.patterns.PsiElementPattern; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.Consumer; import static com.intellij.patterns.PsiJavaPatterns.psiElement; @@ -28,14 +30,14 @@ public class Java18CompletionData extends Java15CompletionData { .afterLeaf(psiElement(JavaTokenType.DOUBLE_COLON)); @Override - public void fillCompletions(final CompletionParameters parameters, final CompletionResultSet result) { + public void fillCompletions(final CompletionParameters parameters, final Consumer result) { PsiElement position = parameters.getPosition(); if (!inComment(position)) { if (AFTER_DOUBLE_COLON.accepts(position)) { PsiMethodReferenceExpression parent = PsiTreeUtil.getParentOfType(parameters.getPosition(), PsiMethodReferenceExpression.class); TailType tail = parent != null && !LambdaHighlightingUtil.insertSemicolon(parent.getParent()) ? TailType.SEMICOLON : TailType.NONE; - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), tail)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), tail)); return; } @@ -43,7 +45,7 @@ public class Java18CompletionData extends Java15CompletionData { PsiElement scope = position.getParent(); while (scope != null && !(scope instanceof PsiFile)) { if (scope instanceof PsiClass && ((PsiClass)scope).isInterface()) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.HUMBLE_SPACE_BEFORE_WORD)); break; } scope = scope.getParent(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java index c49e78287738..c124826a4b58 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaAwareCompletionData.java @@ -86,6 +86,4 @@ public class JavaAwareCompletionData extends CompletionData{ } } - public void fillCompletions(CompletionParameters parameters, CompletionResultSet result) { - } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index b154c38f9f29..9789ec76a99a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -241,6 +241,8 @@ public class JavaCompletionContributor extends CompletionContributor { addKeywords(parameters, result); + addExpressionVariants(parameters, position, result); + Set usedWords = addReferenceVariants(parameters, result, inheritors); if (psiElement().inside(PsiLiteralExpression.class).accepts(position)) { @@ -264,6 +266,16 @@ public class JavaCompletionContributor extends CompletionContributor { result.stopHere(); } + private void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, CompletionResultSet result) { + if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) && + !JavaCompletionData.AFTER_DOT.accepts(position)) { + JavaCompletionData.addExpectedTypeMembers(parameters, result); + if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) { + new SameSignatureCallParametersProvider().addCompletions(parameters, new ProcessingContext(), result); + } + } + } + public static boolean isInJavaContext(PsiElement position) { return PsiUtilCore.findLanguageFromElement(position).isKindOf(JavaLanguage.INSTANCE); } @@ -382,17 +394,26 @@ public class JavaCompletionContributor extends CompletionContributor { return usedWords; } - private static void addKeywords(CompletionParameters parameters, CompletionResultSet result) { + private static void addKeywords(CompletionParameters parameters, final CompletionResultSet result) { + Consumer noMiddleMatches = new Consumer() { + @Override + public void consume(LookupElement element) { + if (element.getLookupString().startsWith(result.getPrefixMatcher().getPrefix())) { + result.addElement(element); + } + } + }; + PsiElement position = parameters.getPosition(); final Set lookupSet = new LinkedHashSet(); final Set keywordVariants = new HashSet(); final JavaCompletionData completionData = getCompletionData(PsiUtil.getLanguageLevel(position)); completionData.addKeywordVariants(keywordVariants, position, parameters.getOriginalFile()); completionData.completeKeywordsBySet(lookupSet, keywordVariants, position, result.getPrefixMatcher(), parameters.getOriginalFile()); - completionData.fillCompletions(parameters, result); + completionData.fillCompletions(parameters, noMiddleMatches); for (final LookupElement item : lookupSet) { - result.addElement(item); + noMiddleMatches.consume(item); } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java index bede9bd170e5..67670d5d2d18 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionData.java @@ -34,6 +34,7 @@ import com.intellij.psi.jsp.JspElementType; import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.Consumer; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NonNls; @@ -368,19 +369,19 @@ public class JavaCompletionData extends JavaAwareCompletionData { } } - private static void addStatementKeywords(CompletionResultSet variant, PsiElement position) { - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.SWITCH), TailTypes.SWITCH_LPARENTH)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.WHILE), TailTypes.WHILE_LPARENTH)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DO), TailTypes.DO_LBRACE)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FOR), TailTypes.FOR_LPARENTH)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.IF), TailTypes.IF_LPARENTH)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.TRY), TailTypes.TRY_LBRACE)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.THROW), TailType.INSERT_SPACE)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE)); - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.SYNCHRONIZED), TailTypes.SYNCHRONIZED_LPARENTH)); + private static void addStatementKeywords(Consumer variant, PsiElement position) { + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.SWITCH), TailTypes.SWITCH_LPARENTH)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.WHILE), TailTypes.WHILE_LPARENTH)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.DO), TailTypes.DO_LBRACE)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.FOR), TailTypes.FOR_LPARENTH)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.IF), TailTypes.IF_LPARENTH)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.TRY), TailTypes.TRY_LBRACE)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.THROW), TailType.INSERT_SPACE)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.SYNCHRONIZED), TailTypes.SYNCHRONIZED_LPARENTH)); if (PsiUtil.getLanguageLevel(position).isAtLeast(LanguageLevel.JDK_1_4)) { - variant.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.ASSERT), TailType.INSERT_SPACE)); + variant.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.ASSERT), TailType.INSERT_SPACE)); } TailType returnTail = getReturnTail(position); @@ -388,11 +389,10 @@ public class JavaCompletionData extends JavaAwareCompletionData { if (returnTail != TailType.NONE) { ret = new OverrideableSpace(ret, returnTail); } - variant.addElement(ret); + variant.consume(ret); } - @Override - public void fillCompletions(CompletionParameters parameters, final CompletionResultSet result) { + public void fillCompletions(CompletionParameters parameters, final Consumer result) { final PsiElement position = parameters.getPosition(); if (PsiTreeUtil.getParentOfType(position, PsiComment.class, false) != null) { return; @@ -407,15 +407,15 @@ public class JavaCompletionData extends JavaAwareCompletionData { if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).afterLeaf("{").accepts(statement)) { PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(prevLeaf, PsiTryStatement.class); if (tryStatement == null || tryStatement.getCatchSections().length > 0 || tryStatement.getFinallyBlock() != null) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD)); } } } if (isStatementPosition(position)) { if (PsiTreeUtil.getParentOfType(position, PsiSwitchStatement.class, false, PsiMember.class) != null) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.CASE), TailType.INSERT_SPACE)); - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.CASE_COLON)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.CASE), TailType.INSERT_SPACE)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.DEFAULT), TailType.CASE_COLON)); if (START_SWITCH.accepts(position)) { return; } @@ -431,7 +431,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { final boolean insideInheritorClass = PsiUtil.isLanguageLevel8OrHigher(position) && isInsideInheritorClass(position); if (!afterDot || insideQualifierClass || insideInheritorClass) { if (!afterDot || insideQualifierClass) { - result.addElement(createKeyword(position, PsiKeyword.THIS)); + result.consume(createKeyword(position, PsiKeyword.THIS)); } final LookupItem superItem = (LookupItem)createKeyword(position, PsiKeyword.SUPER); @@ -453,18 +453,18 @@ public class JavaCompletionData extends JavaAwareCompletionData { }); } - result.addElement(superItem); + result.consume(superItem); } } if (isExpressionPosition(position)) { if (PsiTreeUtil.getParentOfType(position, PsiAnnotation.class) == null) { - result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE)); - result.addElement(createKeyword(position, PsiKeyword.NULL)); + result.consume(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.NEW), TailType.INSERT_SPACE)); + result.consume(createKeyword(position, PsiKeyword.NULL)); } if (mayExpectBoolean(parameters)) { - result.addElement(createKeyword(position, PsiKeyword.TRUE)); - result.addElement(createKeyword(position, PsiKeyword.FALSE)); + result.consume(createKeyword(position, PsiKeyword.TRUE)); + result.consume(createKeyword(position, PsiKeyword.FALSE)); } } @@ -473,22 +473,22 @@ public class JavaCompletionData extends JavaAwareCompletionData { !(file instanceof PsiJavaCodeReferenceCodeFragment) && !(file instanceof PsiTypeCodeFragment)) { if (prevLeaf == null) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.PACKAGE), TailType.HUMBLE_SPACE_BEFORE_WORD)); - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.PACKAGE), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); } else if (END_OF_BLOCK.isAcceptable(position, position) && PsiTreeUtil.getParentOfType(position, PsiMember.class) == null) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.IMPORT), TailType.HUMBLE_SPACE_BEFORE_WORD)); } } if ((isInsideParameterList(position) || isAtResourceVariableStart(position) || isAtCatchVariableStart(position)) && !psiElement().afterLeaf(PsiKeyword.FINAL).accepts(position) && !AFTER_DOT.accepts(position)) { - result.addElement(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(TailTypeDecorator.withTail(createKeyword(position, PsiKeyword.FINAL), TailType.HUMBLE_SPACE_BEFORE_WORD)); } if (isInstanceofPlace(position)) { - result.addElement(LookupElementDecorator.withInsertHandler( + result.consume(LookupElementDecorator.withInsertHandler( createKeyword(position, PsiKeyword.INSTANCEOF), new InsertHandler>() { @Override @@ -497,7 +497,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { if (tailType.isApplicable(context)) { tailType.processTail(context.getEditor(), context.getTailOffset()); } - + if ('!' == context.getCompletionChar()) { context.setAddCompletionChar(false); context.commitDocument(); @@ -515,13 +515,13 @@ public class JavaCompletionData extends JavaAwareCompletionData { if (isSuitableForClass(position)) { for (String s : ModifierChooser.getKeywords(position)) { - result.addElement(new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, s), TailType.HUMBLE_SPACE_BEFORE_WORD)); } - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.CLASS), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.CLASS), TailType.HUMBLE_SPACE_BEFORE_WORD)); if (PsiTreeUtil.getParentOfType(position, PsiCodeBlock.class, true, PsiMember.class) == null) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.INTERFACE), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.INTERFACE), TailType.HUMBLE_SPACE_BEFORE_WORD)); if (PsiUtil.getLanguageLevel(position).isAtLeast(LanguageLevel.JDK_1_5)) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.ENUM), TailType.INSERT_SPACE)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.ENUM), TailType.INSERT_SPACE)); } } } @@ -529,22 +529,14 @@ public class JavaCompletionData extends JavaAwareCompletionData { addPrimitiveTypes(result, position); if (isAfterTypeDot(position)) { - result.addElement(createKeyword(position, PsiKeyword.CLASS)); + result.consume(createKeyword(position, PsiKeyword.CLASS)); } addUnfinishedMethodTypeParameters(position, result); - if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) && - !AFTER_DOT.accepts(position)) { - addExpectedTypeMembers(parameters, result); - if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) { - new SameSignatureCallParametersProvider().addCompletions(parameters, new ProcessingContext(), result); - } - } - if (JavaMemberNameCompletionContributor.INSIDE_TYPE_PARAMS_PATTERN.accepts(position)) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.EXTENDS), TailType.HUMBLE_SPACE_BEFORE_WORD)); - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.SUPER), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.EXTENDS), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.SUPER), TailType.HUMBLE_SPACE_BEFORE_WORD)); } } @@ -608,7 +600,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { } } - private static void addUnfinishedMethodTypeParameters(PsiElement position, CompletionResultSet result) { + private static void addUnfinishedMethodTypeParameters(PsiElement position, final Consumer result) { final ProcessingContext context = new ProcessingContext(); if (psiElement().inside( psiElement(PsiTypeElement.class).afterLeaf( @@ -621,7 +613,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { } if (current instanceof PsiClass) { for (PsiTypeParameter typeParameter : list.getTypeParameters()) { - result.addElement(new JavaPsiClassReferenceElement(typeParameter)); + result.consume(new JavaPsiClassReferenceElement(typeParameter)); } } } @@ -643,7 +635,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { isAfterPrimitiveOrArrayType(position); } - private static void addPrimitiveTypes(CompletionResultSet result, PsiElement position) { + private static void addPrimitiveTypes(final Consumer result, PsiElement position) { if (AFTER_DOT.accepts(position)) { return; } @@ -653,9 +645,9 @@ public class JavaCompletionData extends JavaAwareCompletionData { if (afterNew) { PsiElementFactory factory = JavaPsiFacade.getElementFactory(position.getProject()); for (String primitiveType : PRIMITIVE_TYPES) { - result.addElement(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText(primitiveType + "[]", null), null)); + result.consume(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText(primitiveType + "[]", null), null)); } - result.addElement(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText("void[]", null), null)); + result.consume(PsiTypeLookupItem.createLookupItem(factory.createTypeFromText("void[]", null), null)); return; } @@ -677,14 +669,14 @@ public class JavaCompletionData extends JavaAwareCompletionData { expressionPosition || isStatementPosition(position)) { for (String primitiveType : PRIMITIVE_TYPES) { - result.addElement(createKeyword(position, primitiveType)); + result.consume(createKeyword(position, primitiveType)); } } if (declaration) { - result.addElement(new OverrideableSpace(createKeyword(position, PsiKeyword.VOID), TailType.HUMBLE_SPACE_BEFORE_WORD)); + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.VOID), TailType.HUMBLE_SPACE_BEFORE_WORD)); } else if (typeFragment && ((PsiTypeCodeFragment)position.getContainingFile()).isVoidValid()) { - result.addElement(createKeyword(position, PsiKeyword.VOID)); + result.consume(createKeyword(position, PsiKeyword.VOID)); } } @@ -696,7 +688,7 @@ public class JavaCompletionData extends JavaAwareCompletionData { return psiElement().insideStarting(psiElement(PsiTypeElement.class).withParent(PsiCatchSection.class)).accepts(position); } - private static void addBreakContinue(CompletionResultSet result, PsiElement position) { + private static void addBreakContinue(Consumer result, PsiElement position) { PsiLoopStatement loop = PsiTreeUtil.getParentOfType(position, PsiLoopStatement.class); LookupElement br = createKeyword(position, PsiKeyword.BREAK); @@ -714,11 +706,11 @@ public class JavaCompletionData extends JavaAwareCompletionData { cont = TailTypeDecorator.withTail(cont, tailType); if (loop != null && new InsideElementFilter(new ClassFilter(PsiStatement.class)).isAcceptable(position, loop)) { - result.addElement(br); - result.addElement(cont); + result.consume(br); + result.consume(cont); } if (psiElement().inside(PsiSwitchStatement.class).accepts(position)) { - result.addElement(br); + result.consume(br); } } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy index 157e7a341be3..3781cfffcf88 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/JavaAutoPopupTest.groovy @@ -1599,7 +1599,7 @@ class Foo { myFixture.configureByText "a.java", "class Foo {{ }}" myFixture.type('a') joinAutopopup() - myFixture.type('\na') + myFixture.type('\nf') joinCompletion() assert lookup } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy index 4c89fb35582d..116bb969dc74 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/NormalCompletionTest.groovy @@ -389,7 +389,7 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase { checkResult() } - public void testFieldType() throws Throwable { doTest('\n'); } + public void testFieldType() { doTest(); } public void testPackageInAnnoParam() throws Throwable { doTest(); @@ -903,7 +903,7 @@ public class ListUtils { checkResult(); } - public void testSecondAnonymousClassParameter() throws Throwable { doTest('\n'); } + public void testSecondAnonymousClassParameter() { doTest(); } public void testSpaceAfterReturn() throws Throwable { configure() diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/VariablesCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/completion/VariablesCompletionTest.groovy index 4bf387841eae..afd99d40dee4 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/VariablesCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/VariablesCompletionTest.groovy @@ -45,7 +45,7 @@ public class VariablesCompletionTest extends LightFixtureCompletionTestCase { } public void testLocals3() throws Exception { - doSelectTest("TestSource3.java", "TestResult3.java"); + doTest("TestSource3.java", "TestResult3.java"); } public void testLocals4() throws Exception { @@ -53,7 +53,7 @@ public class VariablesCompletionTest extends LightFixtureCompletionTestCase { } public void testLocals5() throws Exception { - doSelectTest("TestSource5.java", "TestResult5.java"); + doTest("TestSource5.java", "TestResult5.java"); } public void testLocals6() throws Exception { From 7d2b66d73807881d383954a02a17f384c417e37d Mon Sep 17 00:00:00 2001 From: peter Date: Mon, 18 May 2015 18:29:20 +0200 Subject: [PATCH 32/36] IDEA-138483 Issue with setting of dynamic variable in debugger of groovy script --- .../plugins/groovy/debugger/GroovyCodeFragmentFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java index b71a3d3d6f93..c1f27061eca6 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyCodeFragmentFactory.java @@ -175,7 +175,7 @@ public class GroovyCodeFragmentFactory extends CodeFragmentFactory { "java.lang.Object |res = ((groovy.lang.MetaClassImpl)|emc).invokeStaticMethod(|clazz, \"" ).append(EVAL_NAME).append("\", |resVals);\n"); } - javaText.append("if (|res instanceof java.lang.Boolean) ((java.lang.Boolean) |res).booleanValue() else |res"); + javaText.append("|res"); final PsiElementFactory factory = JavaPsiFacade.getInstance(toEval.getProject()).getElementFactory(); From 0d71a383ce67983ebb131655a6ab4cbb7a710ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Mon, 18 May 2015 18:33:56 +0200 Subject: [PATCH 33/36] FinderRecursivePanel#mergeListItems: optimize when adding items to empty list (initial population) --- .../src/com/intellij/ui/FinderRecursivePanel.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java index 6014cb829993..c3943d0f31d3 100644 --- a/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.java +++ b/platform/platform-impl/src/com/intellij/ui/FinderRecursivePanel.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. @@ -533,7 +533,13 @@ public abstract class FinderRecursivePanel extends JBSplitter implements Data }); } - public static void mergeListItems(@NotNull CollectionListModel listModel, @NotNull List newItems) { + static void mergeListItems(@NotNull CollectionListModel listModel, @NotNull List newItems) { + boolean isEmptyList = listModel.getSize() == 0; + if (isEmptyList) { + listModel.add(newItems); + return; + } + // remove items for (int i = listModel.getSize() - 1; i >= 0; i--) { if (!newItems.contains(listModel.getElementAt(i))) { @@ -574,7 +580,8 @@ public abstract class FinderRecursivePanel extends JBSplitter implements Data final FinderRecursivePanel childPanel = (FinderRecursivePanel)myChild; if (withUpdatePanel) { childPanel.init(); - } else { + } + else { childPanel.initWithoutUpdatePanel(); } } From f2809a16a063f9fcaeb8999d571dd0e0dd0d3595 Mon Sep 17 00:00:00 2001 From: "Egor.Ushakov" Date: Mon, 18 May 2015 19:37:57 +0300 Subject: [PATCH 34/36] allow to assign primitives to Objects --- .../debugger/engine/JavaValueModifier.java | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java index 16f75368edf9..612c50db271f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java @@ -22,29 +22,19 @@ import com.intellij.debugger.engine.evaluation.*; import com.intellij.debugger.engine.evaluation.expression.*; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; -import com.intellij.debugger.impl.*; +import com.intellij.debugger.impl.DebuggerContextImpl; +import com.intellij.debugger.impl.DebuggerSession; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.LocalVariableProxyImpl; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; -import com.intellij.debugger.ui.DebuggerExpressionComboBox; -import com.intellij.debugger.ui.EditorEvaluationCommand; -import com.intellij.debugger.ui.impl.DebuggerTreeRenderer; import com.intellij.debugger.ui.impl.watch.*; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter; import com.intellij.openapi.progress.util.ProgressWindowWithNotification; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.PsiDocumentManager; -import com.intellij.psi.PsiFile; -import com.intellij.ui.SimpleColoredComponent; -import com.intellij.util.IJSwingUtilities; import com.intellij.xdebugger.frame.XValueModifier; import com.sun.jdi.*; import org.jetbrains.annotations.NotNull; -import javax.swing.*; - import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING; /* @@ -255,14 +245,14 @@ public class JavaValueModifier extends XValueModifier { } } - private Value preprocessValue(EvaluationContextImpl context, Value value, Type varType) throws EvaluateException { + private static Value preprocessValue(EvaluationContextImpl context, Value value, Type varType) throws EvaluateException { if (value != null && JAVA_LANG_STRING.equals(varType.name()) && !(value instanceof StringReference)) { - String v = DebuggerUtilsEx.getValueAsString(context, value); + String v = DebuggerUtils.getValueAsString(context, value); if (v != null) { value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf(v); } } - if(value instanceof DoubleValue) { + if (value instanceof DoubleValue) { double dValue = ((DoubleValue) value).doubleValue(); if(varType instanceof FloatType && Float.MIN_VALUE <= dValue && dValue <= Float.MAX_VALUE){ value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf((float)dValue); @@ -274,8 +264,7 @@ public class JavaValueModifier extends XValueModifier { value = (Value)new UnBoxingEvaluator(new IdentityEvaluator(value)).evaluate(context); } } - else if (UnBoxingEvaluator.isTypeUnboxable(varType.name())) { - // variable is not primitive and boxing/unboxing is applicable + else if (varType instanceof ReferenceType) { if (value instanceof PrimitiveValue) { value = (Value)new BoxingEvaluator(new IdentityEvaluator(value)).evaluate(context); } From 0326bfc1bb6060edbaf4e6929501397692484fdb Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 18 May 2015 19:50:51 +0300 Subject: [PATCH 35/36] Fix top hit provider for Editor Tabs --- .../src/com/intellij/ide/ui/EditorOptionsTopHitProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/platform-impl/src/com/intellij/ide/ui/EditorOptionsTopHitProvider.java b/platform/platform-impl/src/com/intellij/ide/ui/EditorOptionsTopHitProvider.java index 8e53a81e9f30..e1faa3473cff 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/EditorOptionsTopHitProvider.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/EditorOptionsTopHitProvider.java @@ -67,11 +67,13 @@ public class EditorOptionsTopHitProvider extends OptionsTopHitProvider { editorCode("Appearance: " + messageApp("checkbox.show.small.icons.in.gutter"), "SHOW_SMALL_ICONS_IN_GUTTER"), option("Appearance: " + messageApp("checkbox.show.code.folding.outline"), "IS_FOLDING_OUTLINE_SHOWN", "editor.preferences.folding"), editorTabs("Tabs: " + messageApp("checkbox.editor.tabs.in.single.row"), "SCROLL_TAB_LAYOUT_IN_EDITOR"), + editorTabs("Tabs: " + messageApp("checkbox.editor.scroll.if.need"), "HIDE_TABS_IF_NEED"), editorTabs("Tabs: " + messageApp("checkbox.hide.file.extension.in.editor.tabs"), "HIDE_KNOWN_EXTENSION_IN_TABS"), editorTabs("Tabs: Show directory in editor tabs for non-unique filenames", "SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES"), editorTabs("Tabs: " + messageApp("checkbox.editor.tabs.show.close.button"), "SHOW_CLOSE_BUTTON"), editorTabs("Tabs: " + messageApp("checkbox.mark.modified.tabs.with.asterisk"), "MARK_MODIFIED_TABS_WITH_ASTERISK"), editorTabs("Tabs: " + messageApp("checkbox.show.tabs.tooltips"), "SHOW_TABS_TOOLTIPS"), + editorTabs("Tabs: " + messageApp("checkbox.smart.tab.reuse"), "REUSE_NOT_MODIFIED_TABS"), editorTabs("Tabs: " + messageApp("radio.close.non.modified.files.first"), "CLOSE_NON_MODIFIED_FILES_FIRST") ); From c7a756c10862cd5bc80475dfa373495deb66dbde Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 18 May 2015 19:37:03 +0300 Subject: [PATCH 36/36] wrapped actions should have same DumbAware-ness and other flags --- .../openapi/actionSystem/EmptyAction.java | 114 +++++++++++++----- 1 file changed, 85 insertions(+), 29 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java index 38499eb25394..63918ed1e9a0 100644 --- a/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java +++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/EmptyAction.java @@ -85,38 +85,94 @@ public final class EmptyAction extends AnAction { } public static AnAction wrap(final AnAction action) { - return action instanceof ActionGroup ? new ActionGroup() { - { - setPopup(((ActionGroup)action).isPopup()); - copyFrom(action); - setShortcutSet(new CustomShortcutSet()); - } + final boolean isDumbAware = action.isDumbAware(); + final boolean isEnabledInModalContext = action.isEnabledInModalContext(); + final boolean inInjectedContext = action.isInInjectedContext(); + final boolean isTransparentUpdate = action.isTransparentUpdate(); + if (action instanceof ActionGroup) { + final ActionGroup group = ((ActionGroup)action); + final boolean isHideIfNoVisibleChildren = group.hideIfNoVisibleChildren(); + final boolean isDisableIfNoVisibleChildren = group.disableIfNoVisibleChildren(); + return new ActionGroup() { + { + setPopup(group.isPopup()); + copyFrom(group); + setShortcutSet(new CustomShortcutSet()); + setEnabledInModalContext(isEnabledInModalContext); + setInjectedContext(inInjectedContext); + } - @Override - public void update(final AnActionEvent e) { - action.update(e); - } + @Override + public void update(final AnActionEvent e) { + group.update(e); + } - @NotNull - @Override - public AnAction[] getChildren(@Nullable final AnActionEvent e) { - return ((ActionGroup)action).getChildren(e); - } - } : new AnAction() { - { - copyFrom(action); - setShortcutSet(new CustomShortcutSet()); - } + @NotNull + @Override + public AnAction[] getChildren(@Nullable final AnActionEvent e) { + return group.getChildren(e); + } - @Override - public void actionPerformed(final AnActionEvent e) { - action.actionPerformed(e); - } + @Override + public boolean canBePerformed(DataContext context) { + return group.canBePerformed(context); + } - @Override - public void update(final AnActionEvent e) { - action.update(e); - } - }; + @Override + public void actionPerformed(AnActionEvent e) { + group.actionPerformed(e); + } + + @Override + public boolean isDumbAware() { + return isDumbAware; + } + + @Override + public boolean isTransparentUpdate() { + return isTransparentUpdate; + } + + @Override + public boolean hideIfNoVisibleChildren() { + return isHideIfNoVisibleChildren; + } + + @Override + public boolean disableIfNoVisibleChildren() { + return isDisableIfNoVisibleChildren; + } + }; + } + else { + return new AnAction() { + { + copyFrom(action); + setShortcutSet(new CustomShortcutSet()); + setEnabledInModalContext(isEnabledInModalContext); + setInjectedContext(inInjectedContext); + } + + @Override + public void actionPerformed(final AnActionEvent e) { + action.actionPerformed(e); + } + + @Override + public void update(final AnActionEvent e) { + action.update(e); + } + + @Override + public boolean isDumbAware() { + return isDumbAware; + } + + @Override + public boolean isTransparentUpdate() { + return isTransparentUpdate; + } + }; + } } }