Merge branch 'master' of git.labs.intellij.net:idea/community
authorDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 7 Feb 2017 10:50:13 +0000 (13:50 +0300)
committerDmitry Trofimov <dmitry.trofimov@jetbrains.com>
Tue, 7 Feb 2017 10:50:13 +0000 (13:50 +0300)
117 files changed:
java/compiler/impl/testSrc/com/intellij/compiler/BaseCompilerTestCase.java
java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java
java/java-analysis-impl/src/com/intellij/codeInspection/canBeFinal/CanBeFinalInspection.java
java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
java/java-analysis-impl/src/com/intellij/codeInspection/reference/RefFieldImpl.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromNewFix.java
java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateInnerClassFromUsageFix.java
java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java [new file with mode: 0644]
java/java-impl/src/com/intellij/codeInspection/streamMigration/StreamApiMigrationInspection.java
java/java-impl/src/com/intellij/refactoring/memberPullUp/PullUpConflictsUtil.java
java/java-psi-impl/src/com/intellij/lang/java/parser/StatementParser.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting/Loop.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/afterInInterface.java
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/afterInLocal.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/beforeInLocal.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterInLocal.java [new file with mode: 0644]
java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeInLocal.java [new file with mode: 0644]
java/java-tests/testData/inspection/canBeFinal/fieldImplicitWrite/expected.xml
java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/expected.xml [new file with mode: 0644]
java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/src/Test.java [new file with mode: 0644]
java/java-tests/testData/inspection/dataFlow/fixture/ReportConstantReferences.java
java/java-tests/testData/inspection/dataFlow/fixture/ReportConstantReferences_after.java
java/java-tests/testData/inspection/java8MapForEach/afterForEach.java [new file with mode: 0644]
java/java-tests/testData/inspection/java8MapForEach/beforeForEach.java [new file with mode: 0644]
java/java-tests/testData/psi/parser-partial/statements/ForInvalid0.txt [new file with mode: 0644]
java/java-tests/testData/psi/parser-partial/statements/ForInvalid1.txt [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInspection/CanBeFinalTest.java
java/java-tests/testSrc/com/intellij/codeInspection/java18api/Java8MapForEachInspectionTest.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/find/impl/FindManagerTest.java
java/java-tests/testSrc/com/intellij/lang/java/parser/partial/StatementParserTest.java
java/java-tests/testSrc/com/intellij/psi/StubAstSwitchTest.groovy
java/testFramework/src/com/intellij/codeInsight/CodeInsightTestCase.java
platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/BundledJreManager.groovy
platform/build-scripts/groovy/org/jetbrains/intellij/build/impl/WinExeInstallerBuilder.groovy
platform/configuration-store-impl/testSrc/TemplateSchemeTest.kt
platform/core-api/src/com/intellij/psi/CommonClassNames.java
platform/core-api/src/com/intellij/util/IconUtil.java
platform/core-impl/src/com/intellij/psi/impl/source/DummyHolder.java
platform/core-impl/src/com/intellij/psi/impl/source/FileTrees.java [new file with mode: 0644]
platform/core-impl/src/com/intellij/psi/impl/source/PsiFileImpl.java
platform/core-impl/src/com/intellij/psi/stubs/PsiFileStubImpl.java
platform/diff-impl/src/com/intellij/diff/impl/DiffSettingsHolder.kt
platform/diff-impl/src/com/intellij/diff/tools/fragmented/ChangedBlock.java
platform/diff-impl/src/com/intellij/diff/tools/fragmented/UnifiedFragmentBuilder.java
platform/diff-impl/src/com/intellij/diff/tools/util/base/TextDiffSettingsHolder.kt
platform/diff-impl/tests/com/intellij/diff/comparison/IgnoreComparisonUtilTest.kt
platform/lang-impl/src/com/intellij/codeInsight/hints/settings/ParameterNameHintsConfigurable.java
platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupCellRenderer.java
platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/LookupManagerImpl.java
platform/lang-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java
platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java
platform/lang-impl/src/com/intellij/tools/FilterDialog.java
platform/lang-impl/src/com/intellij/util/ui/tree/PerFileConfigurableBase.java
platform/platform-api/src/com/intellij/openapi/MnemonicWrapper.java
platform/platform-api/src/com/intellij/util/io/HttpRequests.java
platform/platform-impl/src/com/intellij/ide/plugins/RepositoryContentHandler.java
platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
platform/platform-resources-en/src/messages/InspectionsBundle.properties
platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/BaseSMTRunnerTestCase.java
platform/testFramework/src/_LastInSuiteTest.java
platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java
platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java
platform/testFramework/src/com/intellij/testFramework/fixtures/impl/BareTestFixtureImpl.java
platform/util/src/com/intellij/openapi/util/Disposer.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/control/finalVar/InvalidWriteAccessSearcher.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/control/finalVar/VariableInitializationChecker.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/dataflow/WritesCounterDFAInstance.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/parser/parsing/statements/expressions/ExpressionStatement.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/ControlFlowBuilderUtil.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DFAEngine.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/DfaInstance.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/WorkList.kt
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsCollector.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/reachingDefs/ReachingDefinitionsDfaInstance.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteInstance.kt [new file with mode: 0644]
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteSemilattice.kt [new file with mode: 0644]
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteState.kt [new file with mode: 0644]
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/types/TypeInferenceHelper.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/GrMapType.java
plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/SubstitutorComputer.java
plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/JpsGroovycRunner.java
plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfiguration.java
plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrTypeCheckHighlightingTest.groovy
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrUnassignedVariableAccessTest.groovy
plugins/groovy/test/org/jetbrains/plugins/groovy/lang/parser/ExpressionsParsingTest.groovy
plugins/groovy/testdata/parsing/groovy/expressions/commandExpr/indexAccess4.test [new file with mode: 0644]
plugins/groovy/testdata/parsing/groovy/expressions/indexpropertyWithUnfinishedInvokedExpression.test [new file with mode: 0644]
plugins/svn4idea/src/org/jetbrains/idea/svn/difftool/SvnDiffSettingsHolder.kt
python/educational-python/build/customInstallActions.nsi
python/helpers/pip-7.1.0.tar.gz [deleted file]
python/helpers/pip-9.0.1.tar.gz [new file with mode: 0644]
python/helpers/setuptools-18.1.tar.gz [deleted file]
python/helpers/setuptools-28.8.0.tar.gz [new file with mode: 0644]
python/helpers/typeshed/stdlib/2/__builtin__.pyi
python/helpers/typeshed/stdlib/3/builtins.pyi
python/helpers/virtualenv-13.1.0.tar.gz [deleted file]
python/helpers/virtualenv-15.1.0.tar.gz [new file with mode: 0644]
python/psi-api/src/com/jetbrains/python/psi/PyClass.java
python/src/com/jetbrains/python/console/PydevConsoleExecuteActionHandler.kt
python/src/com/jetbrains/python/console/PythonConsoleView.java
python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java
python/src/com/jetbrains/python/inspections/PyArgumentListInspection.java
python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
python/src/com/jetbrains/python/psi/PyUtil.java
python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java
python/testData/inspections/PyArgumentListInspection/floatConstructor.py
python/testData/inspections/PyArgumentListInspection/slice.py
python/testData/inspections/PyArgumentListInspection/unicodeConstructor.py
python/testData/inspections/PyArgumentListInspection/xRange.py
resources-en/src/inspectionDescriptions/Java8MapForEach.html [new file with mode: 0644]
resources/src/META-INF/IdeaPlugin.xml

index 4305c37547e5673c3cd10a3bac3bb8897e98b76c..6464086e12058e7905422a5875eddabb46cb329f 100644 (file)
@@ -251,7 +251,6 @@ public abstract class BaseCompilerTestCase extends ModuleTestCase {
       }
     }, getTestRootDisposable());
     UIUtil.invokeAndWaitIfNeeded((Runnable)() -> {
-
       final CompileStatusNotification callback = new CompileStatusNotification() {
         @Override
         public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
index d245a8c0d3e8545bc3b73980ee4b9f75a10dd7b4..d88aa0fca4f6ce2292405558a947b8bcd2815ddf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -100,10 +100,7 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider {
         parent = pparent;
       }
       else if (pparent instanceof PsiReferenceExpression) {
-        PsiElement resolve = ((PsiReferenceExpression)parent).resolve();
-        if (resolve instanceof PsiClass) {
-          parent = pparent;
-        }
+        return findExpression(pparent, allowMethodCalls);
       }
       if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
         expression = parent;
index e1325aa193e0d44cdc3370a1b00376ec00a39e3a..9449999a2e5e45ad7f3d02b7de366077c58d95d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -2929,14 +2929,16 @@ public class HighlightUtil extends HighlightUtilBase {
   @Nullable
   static HighlightInfo checkForStatement(@NotNull PsiForStatement statement) {
     PsiStatement init = statement.getInitialization();
-    if (!(init == null || init instanceof PsiEmptyStatement ||
-          init instanceof PsiDeclarationStatement ||
-          init instanceof PsiExpressionStatement || init instanceof PsiExpressionListStatement)) {
-      String message = JavaErrorMessages.message("invalid.statement");
-      return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(init).descriptionAndTooltip(message).create();
+    if (init == null ||
+        init instanceof PsiEmptyStatement ||
+        init instanceof PsiDeclarationStatement && ArrayUtil.getFirstElement(((PsiDeclarationStatement)init).getDeclaredElements()) instanceof PsiLocalVariable ||
+        init instanceof PsiExpressionStatement ||
+        init instanceof PsiExpressionListStatement) {
+      return null;
     }
 
-    return null;
+    String message = JavaErrorMessages.message("invalid.statement");
+    return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(init).descriptionAndTooltip(message).create();
   }
 
   private static void registerChangeParameterClassFix(PsiType lType, PsiType rType, HighlightInfo info) {
index 80109a54f4a7cd9f68c30a81ad3d8a869bd1f3b4..b4aa6c0f0f11c914dca4ac672cabfeafc2ed83fe 100644 (file)
@@ -161,6 +161,7 @@ public class CanBeFinalInspection extends GlobalJavaBatchInspectionTool {
         psiIdentifier = ((PsiMethod)psiMember).getNameIdentifier();
       }
       else if (refElement instanceof RefField) {
+        if (!((RefField)refElement).isUsedForWriting()) return null;
         if (!isReportFields()) return null;
         psiIdentifier = ((PsiField)psiMember).getNameIdentifier();
       }
index 4b7d08a5c1822542084b70ec799122cb1d0104d0..e4e9715c210404187489f59fb871afaae6560477 100644 (file)
@@ -163,7 +163,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
       rExpr.accept(this);
       addInstruction(new BinopInstruction(JavaTokenType.PLUS, null, myProject));
     }
-    else if ((op == JavaTokenType.PERCEQ || op == JavaTokenType.DIVEQ) && type != null && PsiType.LONG.isAssignableFrom(type)) {
+    else if (isAssignmentDivision(op) && type != null && PsiType.LONG.isAssignableFrom(type)) {
       lExpr.accept(this);
       generateBoxingUnboxingInstructionFor(lExpr, type);
       rExpr.accept(this);
@@ -958,7 +958,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
     else if (op == JavaTokenType.OR && PsiType.BOOLEAN.equals(type)) {
       generateOrExpression(operands, type, false);
     }
-    else if ((op == JavaTokenType.DIV || op == JavaTokenType.PERC) && operands.length == 2 &&
+    else if (isBinaryDivision(op) && operands.length == 2 &&
              type != null && PsiType.LONG.isAssignableFrom(type)) {
       generateDivMod(expression, type, operands[0], operands[1]);
     }
@@ -968,6 +968,14 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
     finishElement(expression);
   }
 
+  static boolean isBinaryDivision(IElementType binaryOp) {
+    return binaryOp == JavaTokenType.DIV || binaryOp == JavaTokenType.PERC;
+  }
+
+  static boolean isAssignmentDivision(IElementType op) {
+    return op == JavaTokenType.PERCEQ || op == JavaTokenType.DIVEQ;
+  }
+
   private void generateDivMod(PsiPolyadicExpression expression, PsiType type, PsiExpression left, PsiExpression right) {
     left.accept(this);
     generateBoxingUnboxingInstructionFor(left, type);
index 6b7b932edc80e4bd56065bdca1d7b350196bb11e..30fbafd4cd0490ee34012b1a257d206e2cad75a8 100644 (file)
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.Pair;
 import com.intellij.psi.*;
 import com.intellij.psi.tree.IElementType;
 import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
 import com.intellij.psi.util.TypeConversionUtil;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.containers.FactoryMap;
@@ -109,18 +110,34 @@ public class StandardInstructionVisitor extends InstructionVisitor {
 
   @Override
   public DfaInstructionState[] visitPush(PushInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
-    if (!instruction.isReferenceWrite() && instruction.getPlace() instanceof PsiReferenceExpression) {
+    PsiExpression place = instruction.getPlace();
+    if (!instruction.isReferenceWrite() && place instanceof PsiReferenceExpression) {
       DfaValue dfaValue = instruction.getValue();
       if (dfaValue instanceof DfaVariableValue) {
         DfaConstValue constValue = memState.getConstantValue((DfaVariableValue)dfaValue);
-        myPossibleVariableValues.putValue(instruction, constValue != null && shouldReportConstValue(constValue.getValue()) ? constValue : ANY_VALUE);
+        boolean report = constValue != null && shouldReportConstValue(constValue.getValue(), place);
+        myPossibleVariableValues.putValue(instruction, report ? constValue : ANY_VALUE);
       }
     }
     return super.visitPush(instruction, runner, memState);
   }
 
-  private static boolean shouldReportConstValue(Object value) {
-    return value == null || value instanceof Boolean || value.equals(new Long(0));
+  private static boolean shouldReportConstValue(Object value, PsiElement place) {
+    return value == null || value instanceof Boolean ||
+           value.equals(new Long(0)) && isDivider(PsiUtil.skipParenthesizedExprUp(place));
+  }
+
+  private static boolean isDivider(PsiElement expr) {
+    PsiElement parent = expr.getParent();
+    if (parent instanceof PsiBinaryExpression) {
+      return ControlFlowAnalyzer.isBinaryDivision(((PsiBinaryExpression)parent).getOperationTokenType()) &&
+             ((PsiBinaryExpression)parent).getROperand() == expr;
+    }
+    if (parent instanceof PsiAssignmentExpression) {
+      return ControlFlowAnalyzer.isAssignmentDivision(((PsiAssignmentExpression)parent).getOperationTokenType()) &&
+             ((PsiAssignmentExpression)parent).getRExpression() == expr;
+    }
+    return false;
   }
 
   public List<Pair<PsiReferenceExpression, DfaConstValue>> getConstantReferenceValues() {
index b976ad92508a2faac9171c279193d1dbc15ac1e9..0e65a9e144dd1afbf5b4270e5e31d2baf692c908 100644 (file)
@@ -60,8 +60,9 @@ public class RefFieldImpl extends RefJavaElementImpl implements RefField {
 
     if (forWriting && expressionFrom != null) {
       PsiClassInitializer initializer = PsiTreeUtil.getParentOfType(expressionFrom, PsiClassInitializer.class);
-      if (initializer != null) {
-        if (initializer.getParent() instanceof PsiClass && psiFrom == initializer.getParent() && !expressionFrom.isQualified()) {
+      if (initializer != null && initializer.getParent() instanceof PsiClass && psiFrom == initializer.getParent()) {
+        PsiExpression qualifierExpression = expressionFrom.getQualifierExpression();
+        if (qualifierExpression == null || qualifierExpression instanceof PsiThisExpression && ((PsiThisExpression)qualifierExpression).getQualifier() == null) {
           referencedFromClassInitializer = true;
         }
       }
index bb10dc5cad712a0f0730f4078681145d8c4d78b6..42f0d3ca22a5672d268e6c6d728e0a3511a2d7c9 100644 (file)
@@ -54,14 +54,14 @@ public class CreateInnerClassFromNewFix extends CreateClassFromNewFix {
     final PsiModifierList modifierList = created.getModifierList();
     LOG.assertTrue(modifierList != null);
     if (PsiTreeUtil.isAncestor(targetClass, newExpression, true)) {
-      if (targetClass.isInterface()) {
+      if (targetClass.isInterface() || PsiUtil.isLocalOrAnonymousClass(targetClass)) {
         modifierList.setModifierProperty(PsiModifier.PACKAGE_LOCAL, true);
       } else {
         modifierList.setModifierProperty(PsiModifier.PRIVATE, true);
       }
     }
 
-    if (!PsiTreeUtil.isAncestor(targetClass, newExpression, true) || PsiUtil.getEnclosingStaticElement(newExpression, targetClass) != null || isInThisOrSuperCall(newExpression)) {
+    if (!targetClass.isInterface() && (!PsiTreeUtil.isAncestor(targetClass, newExpression, true) || PsiUtil.getEnclosingStaticElement(newExpression, targetClass) != null || isInThisOrSuperCall(newExpression))) {
       modifierList.setModifierProperty(PsiModifier.STATIC, true);
     }
     created = (PsiClass)targetClass.add(created);
index 87f34c4345214675225cc483aac374f795ea5192..291d07a00a48372f02e7912262585ca32ba495c3 100644 (file)
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project;
 import com.intellij.openapi.ui.popup.PopupChooserBuilder;
 import com.intellij.psi.*;
 import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
 import com.intellij.refactoring.util.RefactoringUtil;
 import com.intellij.ui.components.JBList;
 import com.intellij.util.IncorrectOperationException;
@@ -139,12 +140,12 @@ public class CreateInnerClassFromUsageFix extends CreateClassFromUsageBaseFix {
                       : myKind == CreateClassKind.CLASS ? elementFactory.createClass(refName) : elementFactory.createEnum(refName);
     final PsiModifierList modifierList = created.getModifierList();
     LOG.assertTrue(modifierList != null);
-    if (aClass.isInterface()) {
+    if (aClass.isInterface() || PsiUtil.isLocalOrAnonymousClass(aClass)) {
       modifierList.setModifierProperty(PsiModifier.PACKAGE_LOCAL, true);
     } else {
       modifierList.setModifierProperty(PsiModifier.PRIVATE, true);
     }
-    if (RefactoringUtil.isInStaticContext(ref, aClass)) {
+    if (RefactoringUtil.isInStaticContext(ref, aClass) && !aClass.isInterface()) {
       modifierList.setModifierProperty(PsiModifier.STATIC, true);
     }
     if (superClassName != null) {
diff --git a/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java b/java/java-impl/src/com/intellij/codeInspection/java18api/Java8MapForEachInspection.java
new file mode 100644 (file)
index 0000000..5b1ea73
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.java18api;
+
+import com.intellij.codeInspection.*;
+import com.intellij.codeInspection.util.LambdaGenerationUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.refactoring.util.LambdaRefactoringUtil;
+import com.intellij.util.ObjectUtils;
+import com.siyeh.ig.callMatcher.CallMatcher;
+import com.siyeh.ig.psiutils.CommentTracker;
+import com.siyeh.ig.psiutils.EquivalenceChecker;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.MethodCallUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * @author Tagir Valeev
+ */
+public class Java8MapForEachInspection extends BaseJavaBatchLocalInspectionTool {
+  private static final String JAVA_UTIL_MAP_ENTRY = CommonClassNames.JAVA_UTIL_MAP + ".Entry";
+
+  private static final CallMatcher ITERABLE_FOREACH =
+    CallMatcher.instanceCall(CommonClassNames.JAVA_LANG_ITERABLE, "forEach").parameterTypes(CommonClassNames.JAVA_UTIL_FUNCTION_CONSUMER);
+  private static final CallMatcher MAP_ENTRY_SET =
+    CallMatcher.instanceCall(CommonClassNames.JAVA_UTIL_MAP, "entrySet").parameterCount(0);
+  private static final CallMatcher ENTRY_GETTER =
+    CallMatcher.instanceCall(JAVA_UTIL_MAP_ENTRY, "getValue", "getKey").parameterCount(0);
+
+  @NotNull
+  @Override
+  public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+    if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
+      return PsiElementVisitor.EMPTY_VISITOR;
+    }
+    return new JavaElementVisitor() {
+      @Override
+      public void visitMethodCallExpression(PsiMethodCallExpression call) {
+        if (ITERABLE_FOREACH.test(call)) {
+          PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
+          if (MAP_ENTRY_SET.test(qualifierCall)) {
+            PsiLambdaExpression lambda = ObjectUtils.tryCast(call.getArgumentList().getExpressions()[0], PsiLambdaExpression.class);
+            if (lambda != null) {
+              PsiParameter[] lambdaParameters = lambda.getParameterList().getParameters();
+              if (lambdaParameters.length == 1) {
+                PsiParameter entry = lambdaParameters[0];
+                if (allUsagesAllowed(entry)) {
+                  PsiElement nameElement = Objects.requireNonNull(call.getMethodExpression().getReferenceNameElement());
+                  holder.registerProblem(nameElement, InspectionsBundle.message("inspection.map.foreach.message"),
+                                         new ReplaceWithMapForEachFix());
+                }
+              }
+            }
+          }
+        }
+      }
+
+      private boolean allUsagesAllowed(@NotNull PsiParameter entry) {
+        return ReferencesSearch.search(entry).forEach(entryRef -> {
+          PsiMethodCallExpression entryCall =
+            ExpressionUtils.getCallForQualifier(ObjectUtils.tryCast(entryRef.getElement(), PsiExpression.class));
+          return ENTRY_GETTER.test(entryCall);
+        });
+      }
+
+      @Override
+      public void visitForeachStatement(PsiForeachStatement loop) {
+        PsiMethodCallExpression call =
+          ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(loop.getIteratedValue()), PsiMethodCallExpression.class);
+        if (MAP_ENTRY_SET.test(call) &&
+            LambdaGenerationUtil.canBeUncheckedLambda(loop.getBody()) &&
+            allUsagesAllowed(loop.getIterationParameter())) {
+          holder.registerProblem(loop.getFirstChild(), InspectionsBundle.message("inspection.map.foreach.message"),
+                                 new ReplaceWithMapForEachFix());
+        }
+      }
+    };
+  }
+
+  private static class ReplaceWithMapForEachFix implements LocalQuickFix {
+    @Nls
+    @NotNull
+    @Override
+    public String getFamilyName() {
+      return InspectionsBundle.message("inspection.map.foreach.fix.name");
+    }
+
+    @Override
+    public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+      PsiElement element = descriptor.getStartElement();
+      if (element.getParent() instanceof PsiForeachStatement) {
+        fixInForeach((PsiForeachStatement)element.getParent());
+        return;
+      }
+      PsiMethodCallExpression call = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
+      if (call == null) return;
+      PsiMethodCallExpression entrySetCall = MethodCallUtils.getQualifierMethodCall(call);
+      if (entrySetCall == null) return;
+      PsiExpression[] args = call.getArgumentList().getExpressions();
+      if (args.length != 1) return;
+      PsiLambdaExpression lambda = ObjectUtils.tryCast(args[0], PsiLambdaExpression.class);
+      if (lambda == null) return;
+      PsiElement body = lambda.getBody();
+      if (body == null) return;
+      PsiParameterList parameterList = lambda.getParameterList();
+      PsiParameter[] lambdaParameters = parameterList.getParameters();
+      if (lambdaParameters.length != 1) return;
+      CommentTracker ct = new CommentTracker();
+      PsiParameter entryParameter = lambdaParameters[0];
+      String replacement = createReplacementExpression(entrySetCall, entryParameter, body, ct);
+      ct.replaceAndRestoreComments(call, replacement);
+    }
+
+    private static String createReplacementExpression(PsiMethodCallExpression entrySetCall,
+                                                      PsiParameter entryParameter,
+                                                      PsiElement body,
+                                                      CommentTracker ct) {
+      PsiType entryType = entryParameter.getType();
+      ParameterCandidate key = new ParameterCandidate(entryType, true);
+      ParameterCandidate value = new ParameterCandidate(entryType, false);
+      Collection<PsiReference> references = ReferencesSearch.search(entryParameter).findAll();
+      for (PsiReference ref : references) {
+        PsiMethodCallExpression entryCall = ExpressionUtils.getCallForQualifier(ObjectUtils.tryCast(ref.getElement(), PsiExpression.class));
+        if (ENTRY_GETTER.test(entryCall)) {
+          ParameterCandidate.select(entryCall, key, value).accept(entryCall);
+        }
+      }
+      key.createName(body, ct);
+      value.createName(body, ct);
+      PsiElementFactory factory = JavaPsiFacade.getElementFactory(entrySetCall.getProject());
+      for (PsiReference ref : references) {
+        PsiExpression expression = ObjectUtils.tryCast(ref.getElement(), PsiExpression.class);
+        if (expression == null || !expression.isValid()) continue;
+        PsiMethodCallExpression entryCall = ExpressionUtils.getCallForQualifier(expression);
+        if (ENTRY_GETTER.test(entryCall)) {
+          ct.replace(entryCall, factory.createIdentifier(ParameterCandidate.select(entryCall, key, value).myName));
+        }
+      }
+      String lambdaBody;
+      if (body instanceof PsiExpression || body instanceof PsiCodeBlock || body instanceof PsiBlockStatement) {
+        lambdaBody = ct.text(body);
+      }
+      else {
+        lambdaBody = "{" + ct.text(body) + "}";
+      }
+      PsiLambdaExpression newLambda =
+        (PsiLambdaExpression)factory.createExpressionFromText("(" + key.myName + "," + value.myName + ")->" + lambdaBody, body);
+      LambdaRefactoringUtil.simplifyToExpressionLambda(newLambda);
+      entrySetCall.getArgumentList().add(newLambda);
+      entrySetCall.getMethodExpression().handleElementRename("forEach");
+      return entrySetCall.getText();
+    }
+
+    private static void fixInForeach(PsiForeachStatement loop) {
+      PsiMethodCallExpression entrySetCall =
+        ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(loop.getIteratedValue()), PsiMethodCallExpression.class);
+      if (entrySetCall == null) return;
+      PsiElement body = loop.getBody();
+      if (body == null) return;
+      PsiParameter entryParameter = loop.getIterationParameter();
+      CommentTracker ct = new CommentTracker();
+      String replacementExpression = createReplacementExpression(entrySetCall, entryParameter, body, ct);
+      ct.replaceAndRestoreComments(loop, replacementExpression + ";");
+    }
+
+    private static class ParameterCandidate {
+      PsiVariable myOriginalVar;
+      final PsiType myType;
+      String myName;
+
+      public ParameterCandidate(PsiType entryType, boolean isKey) {
+        myName = isKey ? "key" : "value";
+        myType = GenericsUtil
+          .getVariableTypeByExpressionType(PsiUtil.substituteTypeParameter(entryType, JAVA_UTIL_MAP_ENTRY, isKey ? 0 : 1, true));
+      }
+
+      private void createName(PsiElement context, CommentTracker ct) {
+        if (myOriginalVar != null) {
+          myName = myOriginalVar.getName();
+          ct.delete(myOriginalVar);
+        }
+        else {
+          myName = JavaCodeStyleManager.getInstance(context.getProject()).suggestUniqueVariableName(myName, context, true);
+        }
+      }
+
+      public void accept(PsiMethodCallExpression call) {
+        if (myOriginalVar != null) return;
+        PsiLocalVariable variable = ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprUp(call.getParent()), PsiLocalVariable.class);
+        if (variable != null && EquivalenceChecker.getCanonicalPsiEquivalence().typesAreEquivalent(variable.getType(), myType)) {
+          myOriginalVar = variable;
+        }
+      }
+
+      static ParameterCandidate select(PsiMethodCallExpression entryCall, ParameterCandidate key, ParameterCandidate value) {
+        String methodName = entryCall.getMethodExpression().getReferenceName();
+        return "getKey".equals(methodName) ? key : value;
+      }
+    }
+  }
+}
\ No newline at end of file
index aecda0333c38b3826aff62df83196bc9417d6c83..87daff2cbf90c7bd62db6526701da905c6aa2343 100644 (file)
@@ -29,7 +29,6 @@ import com.intellij.openapi.util.TextRange;
 import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
 import com.intellij.psi.*;
 import com.intellij.psi.controlFlow.*;
-import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.search.LocalSearchScope;
 import com.intellij.psi.search.searches.ReferencesSearch;
 import com.intellij.psi.util.InheritanceUtil;
@@ -303,7 +302,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo
   @Nullable
   private static PsiClassType createDefaultConsumerType(Project project, PsiVariable variable) {
     final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
-    final PsiClass consumerClass = psiFacade.findClass("java.util.function.Consumer", GlobalSearchScope.allScope(project));
+    final PsiClass consumerClass = psiFacade.findClass(CommonClassNames.JAVA_UTIL_FUNCTION_CONSUMER, variable.getResolveScope());
     return consumerClass != null ? psiFacade.getElementFactory().createType(consumerClass, variable.getType()) : null;
   }
 
index 40572d9f68fec648724b274d9cf568e22061fe85..f3cd9c2e7abe3acb9e98768b1c22a3c63d1a0e6b 100644 (file)
@@ -154,8 +154,7 @@ public class PullUpConflictsUtil {
       ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getReturnTypeElement());
       ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getTypeParameterList());
     }
-    RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList,
-                                                    UsageInfo.EMPTY_ARRAY, targetRepresentativeElement, conflicts);
+    RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList, UsageInfo.EMPTY_ARRAY, targetDirectory, conflicts);
 
     final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiClassOwner.class);
     final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(),
index 973b96df90ae81f88a9d23dc0f24dab0b5b23de3..8c72fc460335dc8821ea09723199dda0a8878505 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2015 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -381,7 +381,7 @@ public class StatementParser {
     final PsiBuilder.Marker param = myParser.getDeclarationParser().parseParameter(builder, false, false);
     if (param == null || exprType(param) != JavaElementType.PARAMETER || builder.getTokenType() != JavaTokenType.COLON) {
       afterParenth.rollbackTo();
-      return parseForLoopFromInitialization(builder, statement);
+      return parseForLoopFromInitializer(builder, statement);
     }
     else {
       afterParenth.drop();
@@ -390,9 +390,9 @@ public class StatementParser {
   }
 
   @NotNull
-  private PsiBuilder.Marker parseForLoopFromInitialization(final PsiBuilder builder, final PsiBuilder.Marker statement) {
-    final PsiBuilder.Marker init = parseStatement(builder);
-    if (init == null){
+  private PsiBuilder.Marker parseForLoopFromInitializer(PsiBuilder builder, PsiBuilder.Marker statement) {
+    PsiBuilder.Marker init = parseStatement(builder);
+    if (init == null) {
       error(builder, JavaErrorMessages.message("expected.statement"));
       if (!expect(builder, JavaTokenType.RPARENTH)) {
         done(statement, JavaElementType.FOR_STATEMENT);
@@ -400,9 +400,18 @@ public class StatementParser {
       }
     }
     else {
-      myParser.getExpressionParser().parse(builder);
+      boolean missingSemicolon = false;
+      if (getLastToken(builder) != JavaTokenType.SEMICOLON) {
+        missingSemicolon = !expectOrError(builder, JavaTokenType.SEMICOLON, "expected.semicolon");
+      }
+
+      PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder);
+      missingSemicolon &= expr == null;
+
       if (!expect(builder, JavaTokenType.SEMICOLON)) {
-        error(builder, JavaErrorMessages.message("expected.semicolon"));
+        if (!missingSemicolon) {
+          error(builder, JavaErrorMessages.message("expected.semicolon"));
+        }
         if (!expect(builder, JavaTokenType.RPARENTH)) {
           done(statement, JavaElementType.FOR_STATEMENT);
           return statement;
@@ -418,7 +427,7 @@ public class StatementParser {
       }
     }
 
-    final PsiBuilder.Marker bodyStatement = parseStatement(builder);
+    PsiBuilder.Marker bodyStatement = parseStatement(builder);
     if (bodyStatement == null) {
       error(builder, JavaErrorMessages.message("expected.statement"));
     }
@@ -427,6 +436,13 @@ public class StatementParser {
     return statement;
   }
 
+  private static IElementType getLastToken(PsiBuilder builder) {
+    IElementType token;
+    int offset = -1;
+    while (ElementType.JAVA_COMMENT_OR_WHITESPACE_BIT_SET.contains((token = builder.rawLookup(offset)))) offset--;
+    return token;
+  }
+
   private void parseExpressionOrExpressionList(final PsiBuilder builder) {
     final PsiBuilder.Marker expr = myParser.getExpressionParser().parse(builder);
     if (expr == null) return;
index 5dd2c92da54b9882deead6d25fd17efb53e127ac..57c45e4ce1fcd950ed40f2b0a4fab6cba18939d6 100644 (file)
@@ -1,5 +1,5 @@
 class a {
-  class ff { }
+  static class ff { }
 
   void f() {
     <error descr="Continue outside of loop">continue;</error>
@@ -61,5 +61,6 @@ class a {
     for (<error descr="Not a statement">i==0?7:8;</error> ; ) ;
     for (<error descr="Invalid statement">if (i<0) i++;</error> ; ) ;
     for (new ff(), new ff(); ; ) ;
+    for (<error descr="Invalid statement">class C { }</error>; true; ) ;
   }
-}
+}
\ No newline at end of file
index 172dea52df8db29cfda2fbfbe82a1127d541684e..7c85dd0090051d01ec2258552084f028fd1d429f 100644 (file)
@@ -6,7 +6,7 @@ public interface I {
         Collection c = new MyCollection(1, "test");
     }
 
-    static class MyCollection implements Collection {
+    class MyCollection implements Collection {
         public MyCollection(int i, String test) {
         }
     }
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/afterInLocal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/afterInLocal.java
new file mode 100644 (file)
index 0000000..f3a4648
--- /dev/null
@@ -0,0 +1,17 @@
+// "Create inner class 'MyCollection'" "true"
+import java.util.*;
+
+public interface I {
+    public static void main() {
+        class C {
+            {
+                Collection c = new MyCollection(1, "test");
+            }
+
+            class MyCollection implements Collection {
+                public MyCollection(int i, String test) {
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/beforeInLocal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromNew/beforeInLocal.java
new file mode 100644 (file)
index 0000000..c7cacaf
--- /dev/null
@@ -0,0 +1,12 @@
+// "Create inner class 'MyCollection'" "true"
+import java.util.*;
+
+public interface I {
+    public static void main() {
+        class C {
+            {
+                Collection c = new <caret>MyCollection(1, "test");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterInLocal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/afterInLocal.java
new file mode 100644 (file)
index 0000000..368acdd
--- /dev/null
@@ -0,0 +1,9 @@
+// "Create inner class 'Param'" "true"
+import java.util.*;
+
+public interface I {
+    void foo(Param p);
+
+    class Param {
+    }
+}
\ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeInLocal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/createInnerClassFromUsage/beforeInLocal.java
new file mode 100644 (file)
index 0000000..9c9953b
--- /dev/null
@@ -0,0 +1,6 @@
+// "Create inner class 'Param'" "true"
+import java.util.*;
+
+public interface I {
+    void foo(Par<caret>am p);
+}
\ No newline at end of file
index 93b56fb7e0e468265bf0bbf004d3a185c3061bb8..4704d91e891d53dbf9fd79e0c4797366143fb7d1 100644 (file)
@@ -1,9 +1,2 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<problems>
-  <problem>
-    <file>Test.java</file>
-    <line>3</line>
-    <description>Declaration can have final modifier</description>
-  </problem>
-
-</problems>
\ No newline at end of file
+<problems/>
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/expected.xml b/java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/expected.xml
new file mode 100644 (file)
index 0000000..2296325
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<problems>
+  <problem>
+    <file>Test.java</file>
+    <line>2</line>
+    <description>Declaration can have final modifier</description>
+  </problem>
+</problems>
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/src/Test.java b/java/java-tests/testData/inspection/canBeFinal/fieldInitializedInClassInitializer/src/Test.java
new file mode 100644 (file)
index 0000000..3f6b54d
--- /dev/null
@@ -0,0 +1,10 @@
+final class G {
+    private Object foo;
+    {
+        this.foo = "";
+    }
+
+    void fooBar() {
+        System.out.println(foo);
+    }
+}
\ No newline at end of file
index be47ecb091ed8bf6c45bff4239810459c2a4f78a..9e8d08306dfbd24485773ab7bc962e9f4aa74742 100644 (file)
@@ -24,4 +24,12 @@ class Test {
     }
   }
 
+  void println(int i) {}
+
+  void testZero(int b) {
+    if (b == 0) {
+      println(b);
+    }
+  }
+
 }
\ No newline at end of file
index 395fd486c388efdf008daa0c59b057df91c23c61..3cc4aa36e619071015d1cf53b3582ae77f765bf7 100644 (file)
@@ -24,4 +24,12 @@ class Test {
     }
   }
 
+  void println(int i) {}
+
+  void testZero(int b) {
+    if (b == 0) {
+      println(b);
+    }
+  }
+
 }
\ No newline at end of file
diff --git a/java/java-tests/testData/inspection/java8MapForEach/afterForEach.java b/java/java-tests/testData/inspection/java8MapForEach/afterForEach.java
new file mode 100644 (file)
index 0000000..b292556
--- /dev/null
@@ -0,0 +1,89 @@
+// "Fix all 'Replace with Map.forEach' problems in file" "true"
+import java.util.Map;
+import java.util.function.Supplier;
+
+public class Test {
+  public static void testInline(Map<String, Integer> map) {
+    map.forEach((key, value) -> System.out.println(key + ":" + value));
+  }
+
+  public static void testKey(Map<String, Integer> map) {
+    map.forEach((str, value) -> System.out.println(str + ":" + value));
+  }
+
+  public static void testValue(Map<String, Integer> map) {
+    map.forEach((str, num) -> System.out.println(str + ":" + num));
+  }
+
+  public static void testTwoVarsWildcard(Map<? extends String, Integer> map) {
+    map.forEach((str, num) -> {
+        System.out.println(str + ":" + num);
+        String str2 = str;
+        System.out.println(str2);
+    });
+  }
+
+  public static <T extends Map<?, ?>> void testGeneric(Supplier<T> map) {
+    map.get().forEach((key, value) -> System.out.println(key + ":" + value));
+  }
+
+  public static <T extends Map<?, ?>> void testUsedHashCode(Supplier<T> map) {
+    map.get().entrySet().forEach(e -> System.out.println(e.getKey()+":"+e.getValue()+":"+e.hashCode()));
+  }
+
+  public static void testForLoop(Map<String, Integer> map) {
+      map.forEach((key, value) -> System.out.println(key + ":" + value));
+  }
+
+  public static void testForLoop2(Map<String, Integer> map) {
+      map.forEach((str, num) -> System.out.println(str + ":" + num));
+  }
+
+  public static void testForLoop3(Map<String, Integer> map) {
+      map.forEach((str, num) -> {
+          System.out.println(str + ":" + num);
+          System.out.println(num + ":" + str);
+      });
+  }
+
+  public static void testForLoopSet(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str + ":" + entry.getValue());
+      entry.setValue(1);
+    }
+  }
+
+  public static void testForLoopPrimitive(Map<String, Integer> map) {
+      map.forEach((str, value) -> {
+          int num = value;
+          System.out.println(str + ":" + num);
+      });
+  }
+
+  public static void testForLoopSideEffect(Map<String, Integer> map) {
+    Integer num;
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      num = entry.getValue();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoopThrow(Map<String, Integer> map) throws Exception {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      if(num > 0) throw new Exception();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoopThrowRuntime(Map<String, Integer> map) throws Exception {
+      map.forEach((str, num) -> {
+          if (num > 0) throw new RuntimeException();
+          System.out.println(str + ":" + num);
+      });
+  }
+}
diff --git a/java/java-tests/testData/inspection/java8MapForEach/beforeForEach.java b/java/java-tests/testData/inspection/java8MapForEach/beforeForEach.java
new file mode 100644 (file)
index 0000000..77a27e1
--- /dev/null
@@ -0,0 +1,111 @@
+// "Fix all 'Replace with Map.forEach' problems in file" "true"
+import java.util.Map;
+import java.util.function.Supplier;
+
+public class Test {
+  public static void testInline(Map<String, Integer> map) {
+    map.entrySet().for<caret>Each(entry ->
+                             System.out.println(entry.getKey() +":"+entry.getValue())
+    );
+  }
+
+  public static void testKey(Map<String, Integer> map) {
+    map.entrySet().forEach(entry -> {
+      String str = entry.getKey();
+      System.out.println(str +":"+entry.getValue());
+    });
+  }
+
+  public static void testValue(Map<String, Integer> map) {
+    map.entrySet().forEach(entry -> {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str +":"+ num);
+    });
+  }
+
+  public static void testTwoVarsWildcard(Map<? extends String, Integer> map) {
+    map.entrySet().forEach(entry -> {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str +":"+ num);
+      String str2 = entry.getKey();
+      System.out.println(str2);
+    });
+  }
+
+  public static <T extends Map<?, ?>> void testGeneric(Supplier<T> map) {
+    map.get().entrySet().forEach(e -> System.out.println(e.getKey()+":"+e.getValue()));
+  }
+
+  public static <T extends Map<?, ?>> void testUsedHashCode(Supplier<T> map) {
+    map.get().entrySet().forEach(e -> System.out.println(e.getKey()+":"+e.getValue()+":"+e.hashCode()));
+  }
+
+  public static void testForLoop(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      System.out.println(entry.getKey() + ":" + entry.getValue());
+    }
+  }
+
+  public static void testForLoop2(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoop3(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str + ":" + entry.getValue());
+      System.out.println(num + ":" + str);
+    }
+  }
+
+  public static void testForLoopSet(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      System.out.println(str + ":" + entry.getValue());
+      entry.setValue(1);
+    }
+  }
+
+  public static void testForLoopPrimitive(Map<String, Integer> map) {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      int num = entry.getValue();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoopSideEffect(Map<String, Integer> map) {
+    Integer num;
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      num = entry.getValue();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoopThrow(Map<String, Integer> map) throws Exception {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      if(num > 0) throw new Exception();
+      System.out.println(str + ":" + num);
+    }
+  }
+
+  public static void testForLoopThrowRuntime(Map<String, Integer> map) throws Exception {
+    for (Map.Entry<String, Integer> entry : map.entrySet()) {
+      String str = entry.getKey();
+      Integer num = entry.getValue();
+      if(num > 0) throw new RuntimeException();
+      System.out.println(str + ":" + num);
+    }
+  }
+}
diff --git a/java/java-tests/testData/psi/parser-partial/statements/ForInvalid0.txt b/java/java-tests/testData/psi/parser-partial/statements/ForInvalid0.txt
new file mode 100644 (file)
index 0000000..301b6f0
--- /dev/null
@@ -0,0 +1,32 @@
+PsiJavaFile:ForInvalid0.java
+  PsiForStatement
+    PsiKeyword:for('for')
+    PsiJavaToken:LPARENTH('(')
+    PsiIfStatement
+      PsiKeyword:if('if')
+      PsiWhiteSpace(' ')
+      PsiJavaToken:LPARENTH('(')
+      PsiBinaryExpression:i<0
+        PsiReferenceExpression:i
+          PsiReferenceParameterList
+            <empty list>
+          PsiIdentifier:i('i')
+        PsiJavaToken:LT('<')
+        PsiLiteralExpression:0
+          PsiJavaToken:INTEGER_LITERAL('0')
+      PsiJavaToken:RPARENTH(')')
+      PsiWhiteSpace(' ')
+      PsiExpressionStatement
+        PsiPostfixExpression:i++
+          PsiReferenceExpression:i
+            PsiReferenceParameterList
+              <empty list>
+            PsiIdentifier:i('i')
+          PsiJavaToken:PLUSPLUS('++')
+        PsiJavaToken:SEMICOLON(';')
+    PsiWhiteSpace(' ')
+    PsiJavaToken:SEMICOLON(';')
+    PsiJavaToken:RPARENTH(')')
+    PsiWhiteSpace(' ')
+    PsiEmptyStatement
+      PsiJavaToken:SEMICOLON(';')
\ No newline at end of file
diff --git a/java/java-tests/testData/psi/parser-partial/statements/ForInvalid1.txt b/java/java-tests/testData/psi/parser-partial/statements/ForInvalid1.txt
new file mode 100644 (file)
index 0000000..c85e243
--- /dev/null
@@ -0,0 +1,28 @@
+PsiJavaFile:ForInvalid1.java
+  PsiForStatement
+    PsiKeyword:for('for')
+    PsiJavaToken:LPARENTH('(')
+    PsiDeclarationStatement
+      PsiClass:C
+        PsiModifierList:
+          <empty list>
+        PsiKeyword:class('class')
+        PsiWhiteSpace(' ')
+        PsiIdentifier:C('C')
+        PsiTypeParameterList
+          <empty list>
+        PsiReferenceList
+          <empty list>
+        PsiReferenceList
+          <empty list>
+        PsiWhiteSpace(' ')
+        PsiJavaToken:LBRACE('{')
+        PsiWhiteSpace(' ')
+        PsiJavaToken:RBRACE('}')
+    PsiJavaToken:SEMICOLON(';')
+    PsiWhiteSpace(' ')
+    PsiJavaToken:SEMICOLON(';')
+    PsiJavaToken:RPARENTH(')')
+    PsiWhiteSpace(' ')
+    PsiEmptyStatement
+      PsiJavaToken:SEMICOLON(';')
\ No newline at end of file
index 859e985f80a4f39101c7e0724108666fafd7177f..fc5a56c5c5e7e0d2736f0ed107caf8dfd3227bf2 100644 (file)
@@ -162,4 +162,8 @@ public class CanBeFinalTest extends InspectionTestCase {
 
     doTest();
   }
+
+  public void testfieldInitializedInClassInitializer() throws Exception {
+    doTest();
+  }
 }
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/java18api/Java8MapForEachInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/java18api/Java8MapForEachInspectionTest.java
new file mode 100644 (file)
index 0000000..d19d530
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.java18api;
+
+import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
+import com.intellij.codeInspection.LocalInspectionTool;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Tagir Valeev
+ */
+public class Java8MapForEachInspectionTest extends LightQuickFixParameterizedTestCase {
+  @NotNull
+  @Override
+  protected LocalInspectionTool[] configureLocalInspectionTools() {
+    return new LocalInspectionTool[]{new Java8MapForEachInspection()};
+  }
+
+  public void test() throws Exception {
+    doAllTests();
+  }
+
+  @Override
+  protected String getBasePath() {
+    return "/inspection/java8MapForEach";
+  }
+}
index 4e88ccfb3563e7cbb8b1b0ecff8b18c442bd1562..a1b7b86864a2cac620760b6f7a18554ce4d2de17 100644 (file)
@@ -921,6 +921,23 @@ public class FindManagerTest extends DaemonAnalyzerTestCase {
     assertTrue(!findResult.isStringFound());
   }
 
+  public void testRegExpMatchReplacement() throws InterruptedException, FindManager.MalformedReplacementStringException {
+    String text = "final override val\n" +
+                  "      d1PrimitiveType by lazyThreadSafeIdempotentGenerator { D1PrimitiveType( typeManager = this ) }";
+    String pattern = "final override val\n" +
+                     "d(\\w+)PrimitiveType by lazyThreadSafeIdempotentGenerator \\{ D(\\w+)PrimitiveType\\( typeManager = this \\) \\}";
+    String replacement = "";
+
+    FindModel findModel = FindManagerTestUtils.configureFindModel(pattern);
+
+    findModel.setRegularExpressions(true);
+    findModel.setMultiline(true);
+
+    FindResult findResult = myFindManager.findString(text, 0, findModel, null);
+    assertTrue(findResult.isStringFound());
+    assertEquals(replacement, myFindManager.getStringToReplace(findResult.substring(text), findModel, 0, text));
+  }
+
   public void testRegExpSearchDoesCheckCancelled() throws InterruptedException {
     String text = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
     FindModel findModel = FindManagerTestUtils.configureFindModel("(x+x+)+y");
index b8255c6063231bd436ce68cc2de85305a50fef8f..c090443bebe884455b5777fe2f5e93ef08257b16 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -46,8 +46,6 @@ public class StatementParserTest extends JavaParsingTestCase {
   public void testLocalVar0() { doParserTest("List<Integer> list;"); }
   public void testLocalVar1() { doParserTest("p.@A T<P> x;"); }
 
-  public void testFor() { doParserTest("for(Iterator<String> it = null; it.hasNext();) { String s = it.next(); }"); }
-
   public void testDoNormal() { doParserTest("do{}while(true);"); }
   public void testDoIncomplete0() { doParserTest("do"); }
   public void testDoIncomplete1() { doParserTest("do foo();"); }
@@ -57,9 +55,9 @@ public class StatementParserTest extends JavaParsingTestCase {
   public void testDoIncomplete5() { doParserTest("do foo(); while(\n g();"); }
   public void testDoIncomplete6() { doParserTest("do foo(); while(cond)"); }
 
+  public void testFor() { doParserTest("for(Iterator<String> it = null; it.hasNext();) { String s = it.next(); }"); }
   public void testForNormal0() { doParserTest("for(int i = 0; i < 10; i++)\n ;"); }
   public void testForNormal1() { doParserTest("for( ; ; ) foo();"); }
-  public void testForEach() { doParserTest("for(Object o : map.entrySet()) ;"); }
   public void testForIncomplete0() { doParserTest("for"); }
   public void testForIncomplete1() { doParserTest("for("); }
   public void testForIncomplete2() { doParserTest("for(int i = 0;"); }
@@ -70,6 +68,10 @@ public class StatementParserTest extends JavaParsingTestCase {
   public void testForIncomplete7() { doParserTest("for() foo();"); }
   public void testForIncomplete8() { doParserTest("for(int i = 0;) foo();"); }
   public void testForIncomplete9() { doParserTest("for(int i = 0; i < 0) foo();"); }
+  public void testForInvalid0() { doParserTest("for(if (i<0) i++; ;) ;"); }
+  public void testForInvalid1() { doParserTest("for(class C { }; ;) ;"); }
+
+  public void testForEach() { doParserTest("for(Object o : map.entrySet()) ;"); }
   public void testForEachIncomplete0() { doParserTest("for(Object  : list) ;"); }
 
   public void testIfNormalWithElse() { doParserTest("if (a){ f1(); } else{ f2(); }"); }
index a239919f61c1b2c2e88e5d5f3a97486bffcf3bb8..ab733d329ffae95979fbeb61941229436876e018 100644 (file)
@@ -16,6 +16,7 @@
 package com.intellij.psi
 
 import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.ReadAction
 import com.intellij.openapi.command.WriteCommandAction
 import com.intellij.openapi.fileEditor.FileDocumentManager
 import com.intellij.openapi.vfs.VfsUtil
@@ -33,7 +34,9 @@ import com.intellij.testFramework.LeakHunter
 import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
 import com.intellij.util.GCUtil
 
+import java.util.concurrent.Callable
 import java.util.concurrent.CountDownLatch
+import java.util.concurrent.Future
 /**
  * @author peter
  */
@@ -259,4 +262,59 @@ class B {
     assert cls == myFixture.findClass('A')
   }
 
+  void "test load PSI via stub when AST is gc-ed and PSI remains that never knew stub"() {
+    PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}")
+    def cls = file.lastChild
+    assert cls instanceof PsiClass
+
+    GCUtil.tryGcSoftlyReachableObjects()
+    assert !file.treeElement
+
+    assert cls == myFixture.findClass('A')
+  }
+
+  void "test bind stubs to AST after AST has been loaded and gc-ed"() {
+    PsiJavaFileImpl file = (PsiJavaFileImpl)myFixture.addFileToProject("a.java", "class A{}")
+    file.node
+
+    GCUtil.tryGcSoftlyReachableObjects()
+    assert !file.treeElement
+
+    def cls1 = file.classes[0]
+    def cls2 = file.lastChild
+    assert cls1 == cls2
+  }
+
+  void "test concurrent stub and AST reloading"() {
+    def fileNumbers = 0..<10
+    List<PsiJavaFileImpl> files = fileNumbers.collect {
+      (PsiJavaFileImpl)myFixture.addFileToProject("a${it}.java", "import foo.bar; class A{}")
+    }
+    for (iteration in 0..10) {
+      GCUtil.tryGcSoftlyReachableObjects()
+      files.each { assert !it.treeElement }
+
+      List<Future<PsiImportList>> stubFutures = []
+      List<Future<PsiImportList>> astFutures = []
+
+      for (i in fileNumbers) {
+        def file = files[i]
+        stubFutures << ApplicationManager.application.executeOnPooledThread({ ReadAction.compute {
+          file.importList
+        } } as Callable)
+        astFutures << ApplicationManager.application.executeOnPooledThread({ ReadAction.compute {
+          PsiTreeUtil.findElementOfClassAtOffset(file, 0, PsiImportList, false)
+        } } as Callable)
+      }
+      GCUtil.tryGcSoftlyReachableObjects()
+
+      for (i in fileNumbers) {
+        def stubImport = stubFutures[i].get()
+        def astImport = astFutures[i].get()
+        if (stubImport != astImport) {
+          fail("Different import psi in ${files[i].name}: stub=$stubImport, ast=$astImport")
+        }
+      }
+    }
+  }
 }
index e10fbee71add88e2c81b6e145f368efcf5750a0c..5111b4f811266853c6aa972d0b9b9047644f74d5 100644 (file)
@@ -133,6 +133,9 @@ public abstract class CodeInsightTestCase extends PsiTestCase {
     final VirtualFile[] vFiles = new VirtualFile[files.length];
     for (int i = 0; i < files.length; i++) {
       vFiles[i] = findVirtualFile(files[i]);
+      if (vFiles[i] != null) {
+        VfsTestUtil.assertFilePathEndsWithCaseSensitivePath(vFiles[i], files[i]);
+      }
     }
 
     File projectFile = projectRoot == null ? null : new File(getTestDataPath() + projectRoot);
@@ -454,6 +457,8 @@ public abstract class CodeInsightTestCase extends PsiTestCase {
         PsiDocumentManager.getInstance(myProject).commitAllDocuments();
 
         VirtualFile vFile = findVirtualFile(filePath);
+
+        VfsTestUtil.assertFilePathEndsWithCaseSensitivePath(vFile, filePath);
         String ft;
         try {
           ft = VfsUtilCore.loadText(vFile);
index 418c8b21cf90581eea9388eb2a61a825fa2bf281..edba8126634ddd3ed3b5818871477dc247115b0f 100644 (file)
@@ -130,7 +130,7 @@ class BundledJreManager {
   }
 
   private enum JreVendor {
-    Oracle("jre8", "jdk8"), JetBrains("jbre8", "jbrex8")
+    Oracle("jre8", "jdk8"), JetBrains("jbre8", "jbsdk8")
 
     final String jreNamePrefix
     final String jreWithToolsJarNamePrefix
index 9fc3d729a6f46d2b6ad878513e6e1794f9f170ec..8b4aab1fcda6c4986b209a5ba5531041370e8055 100644 (file)
@@ -98,6 +98,10 @@ class WinExeInstallerBuilder {
                         " \"${box}/nsiconf/idea.nsi\"")
     }
     else if (SystemInfoRt.isLinux) {
+      buildContext.ant.fixcrlf(file: "$communityHome/build/conf/install_nsis3.sh", eol: "unix")
+      ant.exec(executable: "chmod") {
+        arg(line: " u+x \"${communityHome}/build/conf/install_nsis3.sh\"")
+      }
       ant.exec(command: "\"$communityHome/build/conf/install_nsis3.sh\"" +
                         " \"${buildContext.paths.communityHome}\"")
 
index 4d6183c597ac6cb6fe0808c66e80b7cc25c93377..4e3d000f4e4cadc4528a2d50aefd5420771cf1a7 100644 (file)
@@ -1,8 +1,8 @@
 package com.intellij.configurationStore
 
 import com.intellij.codeInsight.template.impl.TemplateSettings
-import com.intellij.testFramework.rules.InMemoryFsRule
 import com.intellij.testFramework.ProjectRule
+import com.intellij.testFramework.rules.InMemoryFsRule
 import com.intellij.util.io.readText
 import com.intellij.util.io.write
 import org.assertj.core.api.Assertions.assertThat
@@ -29,8 +29,8 @@ class TemplateSchemeTest {
     <templateSet group="Groovy">
       <template name="serr" value="System.err.println(&quot;$\END$&quot;)dwed" description="Prints a string to System.errwefwe" toReformat="true" toShortenFQNames="true" deactivated="true">
         <context>
-          <option name="__DO_NOT_DELETE_ME__" value="true" />
           <option name="GROOVY_STATEMENT" value="false" />
+          <option name="__DO_NOT_DELETE_ME__" value="true" />
         </context>
       </template>
     </templateSet>""".trimIndent()
index e894f69a1d77b2378ee47e6434a1e70e695918f4..fb277f6ea4ea76b67ad20499505c51be777a3ac7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -110,6 +110,7 @@ public interface CommonClassNames {
   @NonNls String JAVA_UTIL_STREAM_DOUBLE_STREAM = "java.util.stream.DoubleStream";
   @NonNls String JAVA_UTIL_STREAM_COLLECTORS = "java.util.stream.Collectors";
   @NonNls String JAVA_UTIL_FUNCTION_PREDICATE = "java.util.function.Predicate";
+  @NonNls String JAVA_UTIL_FUNCTION_CONSUMER = "java.util.function.Consumer";
   @NonNls String JAVA_UTIL_FUNCTION_FUNCTION = "java.util.function.Function";
   @NonNls String JAVA_UTIL_FUNCTION_BIFUNCTION = "java.util.function.BiFunction";
 
index 48c9244b110528a9c4e0e1687a0a224a72d3361d..323f11e676f6e0d16001a27f6a4f7f584a8ee383 100644 (file)
@@ -481,6 +481,16 @@ public class IconUtil {
     return filterIcon(null, source, new DesaturationFilter());
   }
 
+  @NotNull
+  public static Icon brighter(@NotNull Icon source, int tones) {
+    return filterIcon(null, source, new BrighterFilter(tones));
+  }
+
+  @NotNull
+  public static Icon darker(@NotNull Icon source, int tones) {
+    return filterIcon(null, source, new DarkerFilter(tones));
+  }
+
   @NotNull
   private static Icon filterIcon(Graphics2D g, @NotNull Icon source, @NotNull Filter filter) {
     BufferedImage src = g != null ? UIUtil.createImage(g, source.getIconWidth(), source.getIconHeight(), Transparency.TRANSLUCENT) :
@@ -537,6 +547,48 @@ public class IconUtil {
     }
   }
 
+  private static class BrighterFilter extends Filter {
+    private final int myTones;
+
+    public BrighterFilter(int tones) {
+      myTones = tones;
+    }
+
+    @NotNull
+    @Override
+    int[] convert(@NotNull int[] rgba) {
+      final float[] hsb = Color.RGBtoHSB(rgba[0], rgba[1], rgba[2], null);
+      float brightness = hsb[2];
+      for (int i = 0; i < myTones; i++) {
+        brightness = Math.min(1, brightness * 1.1F);
+        if (brightness == 1) break;
+      }
+      Color color = Color.getHSBColor(hsb[0], hsb[1], brightness);
+      return new int[]{color.getRed(), color.getGreen(), color.getBlue(), rgba[3]};
+    }
+  }
+
+  private static class DarkerFilter extends Filter {
+    private final int myTones;
+
+    public DarkerFilter(int tones) {
+      myTones = tones;
+    }
+
+    @NotNull
+    @Override
+    int[] convert(@NotNull int[] rgba) {
+      final float[] hsb = Color.RGBtoHSB(rgba[0], rgba[1], rgba[2], null);
+      float brightness = hsb[2];
+      for (int i = 0; i < myTones; i++) {
+        brightness = Math.max(0, brightness / 1.1F);
+        if (brightness == 0) break;
+      }
+      Color color = Color.getHSBColor(hsb[0], hsb[1], brightness);
+      return new int[]{color.getRed(), color.getGreen(), color.getBlue(), rgba[3]};
+    }
+  }
+
   @NotNull
   public static JBImageIcon createImageIcon(@NotNull final BufferedImage img) {
     return new JBImageIcon(img) {
index 36fd682058d9391122fda2b213eb66cffb0922be..377b66fcfabf30b5bf7e3b942c82adb487757447 100644 (file)
 package com.intellij.psi.impl.source;
 
 import com.intellij.lang.Language;
-import com.intellij.openapi.fileTypes.*;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.source.tree.FileElement;
 import com.intellij.psi.impl.source.tree.SharedImplUtil;
@@ -172,8 +175,4 @@ public class DummyHolder extends PsiFileImpl {
     return super.getViewProvider();
   }
 
-  @Override
-  public boolean useStrongRefs() {
-    return true;
-  }
 }
diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/FileTrees.java b/platform/core-impl/src/com/intellij/psi/impl/source/FileTrees.java
new file mode 100644 (file)
index 0000000..611413f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2000-2017 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.psi.impl.source;
+
+import com.intellij.openapi.util.Getter;
+import com.intellij.psi.impl.source.tree.FileElement;
+import com.intellij.psi.stubs.PsiFileStubImpl;
+import com.intellij.psi.stubs.StubTree;
+import com.intellij.reference.SoftReference;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.lang.ref.Reference;
+
+/**
+ * @author peter
+ */
+final class FileTrees {
+  private final Reference<StubTree> myStub;
+  private final Getter<FileElement> myTreeElementPointer; // SoftReference/WeakReference to ASTNode or a strong reference to a tree if the file is a DummyHolder
+  final boolean astLoaded;
+  final boolean useStrongRefs;
+
+  private FileTrees(@Nullable Reference<StubTree> stub, @Nullable Getter<FileElement> ast, boolean astLoaded, boolean useStrongRefs) {
+    this.myStub = stub;
+    this.myTreeElementPointer = ast;
+    this.astLoaded = astLoaded;
+    this.useStrongRefs = useStrongRefs;
+  }
+
+  @Nullable
+  StubTree derefStub() {
+    return SoftReference.dereference(myStub);
+  }
+
+  @Nullable
+  FileElement derefTreeElement() {
+    return SoftReference.deref(myTreeElementPointer);
+  }
+
+  FileTrees switchToStrongRefs() {
+    return new FileTrees(myStub, myTreeElementPointer, astLoaded, true);
+  }
+
+  FileTrees clearStub(@NotNull String reason) {
+    StubTree stubHolder = derefStub();
+    if (stubHolder != null) {
+      ((PsiFileStubImpl<?>)stubHolder.getRoot()).clearPsi(reason);
+    }
+    return new FileTrees(null, myTreeElementPointer, astLoaded, useStrongRefs);
+  }
+
+  FileTrees withAst(@NotNull Getter<FileElement> ast) {
+    return new FileTrees(myStub, ast, true, useStrongRefs);
+  }
+
+  FileTrees withExclusiveStub(@NotNull StubTree stub) {
+    assert derefTreeElement() == null;
+    assert !useStrongRefs;
+    return new FileTrees(new SoftReference<StubTree>(stub), null, false, false);
+  }
+
+  FileTrees withGreenStub(@NotNull StubTree stub) {
+    assert derefTreeElement() != null;
+    assert astLoaded;
+    return new FileTrees(new SoftReference<StubTree>(stub), myTreeElementPointer, true, useStrongRefs);
+  }
+
+  static FileTrees noStub(@Nullable FileElement ast, @NotNull PsiFileImpl file) {
+    return new FileTrees(null, ast, ast != null, file instanceof DummyHolder);
+  }
+
+  @Override
+  public String toString() {
+    return "FileTrees{" +
+           "stub=" + derefStub() +
+           ", AST=" + derefTreeElement() +
+           ", astLoaded=" + astLoaded +
+           ", useStrongRefs=" + useStrongRefs +
+           '}' ;
+  }
+}
index 0ab9c95f42313a4da358022de6bba5a350ba2019..9bb4b57300d217090bcbb483f4ebc4e7df6ebc21 100644 (file)
@@ -48,20 +48,25 @@ import com.intellij.psi.stubs.*;
 import com.intellij.psi.tree.*;
 import com.intellij.psi.util.PsiUtilCore;
 import com.intellij.reference.SoftReference;
-import com.intellij.util.*;
+import com.intellij.util.FileContentUtilCore;
+import com.intellij.util.Function;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.PatchedWeakReference;
+import com.intellij.util.concurrency.AtomicFieldUpdater;
 import com.intellij.util.containers.ContainerUtil;
 import com.intellij.util.text.CharArrayUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import javax.swing.*;
-import java.lang.ref.Reference;
 import java.lang.reflect.Array;
 import java.util.*;
 
 public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiFileWithStubSupport, Queryable {
   private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiFileImpl");
   public static final String STUB_PSI_MISMATCH = "stub-psi mismatch";
+  private static final AtomicFieldUpdater<PsiFileImpl, FileTrees> ourTreeUpdater =
+    AtomicFieldUpdater.forFieldOfType(PsiFileImpl.class, FileTrees.class);
 
   private IElementType myElementType;
   protected IElementType myContentElementType;
@@ -69,14 +74,12 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
 
   protected PsiFile myOriginalFile;
   private final FileViewProvider myViewProvider;
-  private volatile Reference<StubTree> myStub;
+  private volatile FileTrees myTrees = FileTrees.noStub(null, this);
   private boolean myInvalidated;
-  private volatile boolean myAstLoaded;
-  private volatile boolean myUseStrongRefs;
+  @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
   private AstPathPsiMap myRefToPsi;
   private final ThreadLocal<FileElement> myFileElementBeingLoaded = new ThreadLocal<FileElement>();
   protected final PsiManagerEx myManager;
-  private volatile Getter<FileElement> myTreeElementPointer; // SoftReference/WeakReference to ASTNode or a strong reference to a tree if the file is a DummyHolder
   public static final Key<Boolean> BUILDING_STUB = new Key<Boolean>("Don't use stubs mark!");
 
   protected PsiFileImpl(@NotNull IElementType elementType, IElementType contentElementType, @NotNull FileViewProvider provider) {
@@ -129,7 +132,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
   }
 
   private FileElement derefTreeElement() {
-    return SoftReference.deref(myTreeElementPointer);
+    return myTrees.derefTreeElement();
   }
 
   @Override
@@ -185,10 +188,10 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
     myFileElementBeingLoaded.set(treeElement);
     try {
       while (true) {
-        StubTree stub = derefStub();
-        List<Pair<StubBasedPsiElementBase, AstPath>> bindings = calcStubAstBindings(treeElement, cachedDocument, stub);
+        FileTrees trees = myTrees;
+        List<Pair<StubBasedPsiElementBase, AstPath>> bindings = calcStubAstBindings(treeElement, cachedDocument, trees);
 
-        FileElement savedTree = ensureTreeElement(viewProvider, treeElement, stub, bindings);
+        FileElement savedTree = ensureTreeElement(viewProvider, treeElement, trees, bindings);
         if (savedTree != null) {
           return savedTree;
         }
@@ -202,7 +205,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
   @Nullable
   private FileElement ensureTreeElement(@NotNull FileViewProvider viewProvider,
                                         @NotNull FileElement treeElement,
-                                        @Nullable StubTree stub,
+                                        @NotNull FileTrees trees,
                                         @NotNull List<Pair<StubBasedPsiElementBase, AstPath>> bindings) {
     synchronized (PsiLock.LOCK) {
       FileElement existing = derefTreeElement();
@@ -210,17 +213,12 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
         return existing;
       }
 
-      if (stub != derefStub()) {
-        return null; // stub has been just loaded by another thread, it needs to be bound to AST
+      if (trees != myTrees) {
+        return null; // try again
       }
 
-      if (stub != null) {
-        putUserData(ObjectStubTree.LAST_STUB_TREE_HASH, stub.hashCode());
-      }
-
-      switchFromStubToAst(bindings);
-      myTreeElementPointer = createTreeElementPointer(treeElement);
-      myAstLoaded = true;
+      switchFromStubToAst(bindings, trees);
+      updateTrees(trees.withAst(createTreeElementPointer(treeElement)));
 
       if (LOG.isDebugEnabled() && viewProvider.isPhysical()) {
         LOG.debug("Loaded text for file " + viewProvider.getVirtualFile().getPresentableUrl());
@@ -257,8 +255,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
     return null;
   }
 
-  private void switchFromStubToAst(List<Pair<StubBasedPsiElementBase, AstPath>> bindings) {
-    if (!bindings.isEmpty() && myUseStrongRefs) {
+  private void switchFromStubToAst(List<Pair<StubBasedPsiElementBase, AstPath>> bindings, FileTrees trees) {
+    if (!bindings.isEmpty() && trees.useStrongRefs) {
       List<String> psiStrings = ContainerUtil.map(bindings, new Function<Pair<StubBasedPsiElementBase, AstPath>, String>() {
         @Override
         public String fun(Pair<StubBasedPsiElementBase, AstPath> pair) {
@@ -280,8 +278,9 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
 
   private List<Pair<StubBasedPsiElementBase, AstPath>> calcStubAstBindings(@NotNull FileElement root,
                                                                            @Nullable final Document cachedDocument,
-                                                                           @Nullable final StubTree stubTree) {
-    if (stubTree == null || myAstLoaded) { // don't bind green stub to AST: the PSI should already be cached in myRefToPsi
+                                                                           FileTrees trees) {
+    final StubTree stubTree = trees.derefStub();
+    if (stubTree == null || trees.astLoaded) { // don't bind green stub to AST: the PSI should already be cached in myRefToPsi
       return Collections.emptyList();
     }
 
@@ -346,7 +345,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
 
   void reportStubAstMismatch(String message, StubTree stubTree, Document cachedDocument) {
     rebuildStub();
-    clearStub(STUB_PSI_MISMATCH);
+    updateTrees(myTrees.clearStub(STUB_PSI_MISMATCH));
 
     throw new AssertionError(message
                              + StubTreeLoader.getInstance().getStubAstMismatchDiagnostics(getViewProvider().getVirtualFile(), this,
@@ -372,14 +371,6 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
     return treeElement;
   }
 
-  private void clearStub(@NotNull String reason) {
-    StubTree stubHolder = derefStub();
-    if (stubHolder != null) {
-      ((PsiFileStubImpl<?>)stubHolder.getRoot()).clearPsi(reason);
-    }
-    myStub = null;
-  }
-
   public void clearCaches() {
     myModificationStamp ++;
   }
@@ -448,7 +439,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
     }
 
     synchronized (PsiLock.LOCK) {
-      clearStub(reason);
+      updateTrees(myTrees.clearStub(reason));
     }
     clearCaches();
   }
@@ -602,8 +593,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
   }
 
   public void setTreeElementPointer(@Nullable FileElement element) {
-    myTreeElementPointer = element;
-    myAstLoaded = myUseStrongRefs = false;
+    updateTrees(FileTrees.noStub(element, this));
   }
 
   @Override
@@ -664,7 +654,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
         treeElement.detachFromFile();
         DebugUtil.onInvalidated(treeElement);
       }
-      clearStub("onContentReload");
+      updateTrees(myTrees.clearStub("onContentReload"));
     }
     finally {
       DebugUtil.finishPsiModification();
@@ -703,7 +693,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
   public StubTree getStubTree() {
     ApplicationManager.getApplication().assertReadAccessAllowed();
 
-    if (myAstLoaded && !mayReloadStub()) return null;
+    if (myTrees.astLoaded && !mayReloadStub()) return null;
     if (Boolean.TRUE.equals(getUserData(BUILDING_STUB))) return null;
 
     final StubTree derefd = derefStub();
@@ -791,7 +781,14 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
 
   @Nullable
   private StubTree derefStub() {
-    return SoftReference.dereference(myStub);
+    return myTrees.derefStub();
+  }
+
+  private void updateTrees(@NotNull FileTrees trees) {
+    if (!ourTreeUpdater.compareAndSet(this, myTrees, trees)) {
+      LOG.error("Non-atomic trees update");
+      myTrees = trees;
+    }
   }
 
   private void setStubTree(StubTree stubTree) {
@@ -802,8 +799,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
         ((StubBase)stubTree.getPlainList().get(index)).setPsi(psi);
       }
     }
-    myStub = new SoftReference<StubTree>(stubTree);
-    myAstLoaded = false;
+    updateTrees(myTrees.withExclusiveStub(stubTree));
   }
 
   protected PsiFileImpl cloneImpl(FileElement treeElementClone) {
@@ -1115,7 +1111,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
           throw new RuntimeException("Stub and PSI element type mismatch in " + getName(), e);
         }
 
-        myStub = new SoftReference<StubTree>(tree);
+        updateTrees(myTrees.withGreenStub(tree));
       }
 
       return tree;
@@ -1162,7 +1158,7 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
 
   public final void beforeAstChange() {
     if (!useStrongRefs()) {
-      myUseStrongRefs = true;
+      updateTrees(myTrees.switchToStrongRefs());
       myRefToPsi.switchToStrongRefs();
 
       FileElement element = getTreeElement();
@@ -1193,8 +1189,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
     return myRefToPsi;
   }
 
-  public boolean useStrongRefs() {
-    return myUseStrongRefs;
+  public final boolean useStrongRefs() {
+    return myTrees.useStrongRefs;
   }
 
   public boolean mayCacheAst() {
index 4b1871c2560df33d1d6685d017736b84b6db67f4..29b08c3e5596abe598e8579f54861b287cabc63f 100644 (file)
@@ -141,14 +141,12 @@ public class PsiFileStubImpl<T extends PsiFile> extends StubBase<T> implements P
   public String getDiagnostics() {
     ObjectStubTree stubTree = ObjectStubTree.getStubTree(this);
     T file = myFile;
-    Integer lastStubTreeHash = file == null ? null : file.getUserData(ObjectStubTree.LAST_STUB_TREE_HASH);
     return toString() +
            MoreObjects.toStringHelper("")
              .add("myFile", file)
              .add("myInvalidationReason", myInvalidationReason)
              .add("myStubRoots", Arrays.toString(myStubRoots))
              .add("stubTree", stubTree)
-             .add("lastStubTreeHash", lastStubTreeHash)
              .toString();
   }
 }
\ No newline at end of file
index 515e10a763e01870ec05cbd2ae2152bdb5ea06cb..ed33d9d1449d9eac1ed52ec411ec6da1647bc956 100644 (file)
@@ -83,8 +83,8 @@ class DiffSettingsHolder : PersistentStateComponent<DiffSettingsHolder.State> {
 
   class State {
     @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
-    var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
-    var SHARED_SETTINGS = SharedSettings()
+    @JvmField var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
+    @JvmField var SHARED_SETTINGS = SharedSettings()
   }
 
   private var myState: State = State()
index 3be804c1987e26d5e4c5c1049cb84e4ab19139a9..936f6f728adf10e6598a9cfa49174fc9a8dbc30f 100644 (file)
@@ -20,21 +20,14 @@ import com.intellij.diff.util.LineRange;
 import org.jetbrains.annotations.NotNull;
 
 class ChangedBlock {
-  private final int myLine1;
-  private final int myLine2;
-
   @NotNull private final LineRange myRange1;
   @NotNull private final LineRange myRange2;
 
   @NotNull private final LineFragment myLineFragment;
 
-  public ChangedBlock(int line1,
-                      int line2,
-                      @NotNull LineRange range1,
+  public ChangedBlock(@NotNull LineRange range1,
                       @NotNull LineRange range2,
                       @NotNull LineFragment lineFragment) {
-    myLine1 = line1;
-    myLine2 = line2;
     myRange1 = range1;
     myRange2 = range2;
     myLineFragment = lineFragment;
@@ -51,11 +44,11 @@ class ChangedBlock {
   }
 
   public int getLine1() {
-    return myLine1;
+    return myRange1.start;
   }
 
   public int getLine2() {
-    return myLine2;
+    return myRange2.end;
   }
 
   @NotNull
index 143ebf9bb95812cd74e5e3d85c9ecbaab4abe2c1..42a562a7fc27e6ae7b27a97bc6957677968f574d 100644 (file)
@@ -109,8 +109,7 @@ class UnifiedFragmentBuilder {
     int blockStartLine2 = linesBetween;
     int blockEndLine2 = linesAfter;
 
-    myBlocks.add(new ChangedBlock(linesBefore, linesAfter,
-                                  new LineRange(blockStartLine1, blockEndLine1),
+    myBlocks.add(new ChangedBlock(new LineRange(blockStartLine1, blockEndLine1),
                                   new LineRange(blockStartLine2, blockEndLine2),
                                   fragment));
 
index d555b9e4b750a40c12b1e29e254a3e35514d10a7..5c1a3d3473229d4f961017ccbb3a9406dad120b7 100644 (file)
@@ -168,8 +168,8 @@ class TextDiffSettingsHolder : PersistentStateComponent<TextDiffSettingsHolder.S
 
   class State {
     @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
-    var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
-    var SHARED_SETTINGS = SharedSettings()
+    @JvmField var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
+    @JvmField var SHARED_SETTINGS = SharedSettings()
   }
 
   private var myState: State = State()
index 3e717cbde2690e14d15be781bc677061678f645a..a24e82dfa03a5e42bb5bd6ecc1ee3dccbcde32d1 100644 (file)
@@ -306,14 +306,76 @@ class IgnoreComparisonUtilTest : DiffTestCase() {
          " +     +", "+     +",
          "----    ", " --    ")
       .run()
+
+    Test("X Y", "XY",
+         " + ", "  ",
+         "   ", "  ")
+      .changedLinesNumber(0, 0)
+      .run()
+  }
+
+  fun `test Java samples`() {
+    Test("System . out.println(\"Hello world\");", "System.out.println(\"Hello world\");",
+         "      + +            .            .   ", "                   .            .   ",
+         "                     .            .   ", "                   .            .   ")
+      .changedLinesNumber(0, 0)
+      .run()
+
+    Test(" System . out . println(\"Hello  world\") ; ", "System.out.println(\"Hello world\");",
+         "+      + +   + +   .                  .  + +", "                   .            .   ",
+         "                        .      -      .     ", "                   .            .   ")
+      .run()
+
+    Test("import java.util.Random;_import java.util.List;__class Test {_}", "import java.util.List;_import java.util.Timer;__class Foo {_}",
+         "+++++++++++++++++++++++++++++++++++++++++++++++++              ", "++++++++++++++++++++++++++++++++++++++++++++++++             ",
+         "                                                       ----    ", "                                                      ---    ")
+      .changedLinesNumber(1, 1)
+      .run()
+
+    Test("final_int x = 0;", "final int Y = 0;",
+         "     +   + + +  ", "     +   + + +  ",
+         "          -     ", "          -     ")
+      .changedLinesNumber(2, 1)
+      .run()
+  }
+
+  fun `test Java bad samples`() {
+    //TODO
+
+    Test("int X = 0;", "intX = 0;",
+         "   + + +  ", "    + +  ",
+         "          ", "         ")
+      .changedLinesNumber(0, 0)
+      .run()
+
+    Test("System.out.println (\"Hello  world\");", "System.out.println(\"Hello world\");",
+         "              .   +               .   ", "                   .            .   ",
+         "                  - .      -      .   ", "                   .            .   ")
+      .run()
   }
 
-  private inner class Test(val input1: String, val input2: String,
-                           val ignored1: String, val ignored2: String,
-                           val result1: String, val result2: String) {
+  private inner class Test(input1: String, input2: String,
+                           ignored1: String, ignored2: String,
+                           result1: String, result2: String) {
+    private val input1: String
+    private val input2: String
+    private val ignored1: String
+    private val ignored2: String
+    private val result1: String
+    private val result2: String
+
     private var inner = true
     private var changedLines: IntPair? = null
 
+    init {
+      this.input1 = input1
+      this.input2 = input2
+      this.ignored1 = ignored1.filterNot { it == '.' }
+      this.ignored2 = ignored2.filterNot { it == '.' }
+      this.result1 = result1.filterNot { it == '.' }
+      this.result2 = result2.filterNot { it == '.' }
+    }
+
     fun noInnerChanges(): Test {
       inner = false
       return this
index addbd952f12480f38582c9a27c263b8ab9f528f3..03ceef0895be24fc01bf47133995d50cbde35fd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -121,7 +121,7 @@ public class ParameterNameHintsConfigurable extends DialogWrapper {
       storeBlackListDiff(lang, text);
     });
     
-    myOptions.forEach((option, checkBox) -> option.set(checkBox.isEnabled()));
+    myOptions.forEach((option, checkBox) -> option.set(checkBox.isSelected()));
   }
 
   private static void storeBlackListDiff(@NotNull Language language, @NotNull String text) {
index 8e5744dcef116420d0c1f99eb50f480a2b2a5692..f67460639b6b940ac55a6865c2e704027e64ac7c 100644 (file)
@@ -67,11 +67,11 @@ public class LookupCellRenderer implements ListCellRenderer {
   private final FontMetrics myBoldMetrics;
 
   public static final Color BACKGROUND_COLOR = new JBColor(() -> (JBColor.isBright() ? new Color(235, 244, 254) : JBColor.background()));
-  private static final Color FOREGROUND_COLOR = JBColor.foreground();
+  public static final Color FOREGROUND_COLOR = JBColor.foreground();
   private static final Color GRAYED_FOREGROUND_COLOR = new JBColor(Gray._160, Gray._110);
   private static final Color SELECTED_BACKGROUND_COLOR = new Color(0, 82, 164);
-  private static final Color SELECTED_NON_FOCUSED_BACKGROUND_COLOR = new JBColor(0x6e8ea2, 0x55585a);
-  private static final Color SELECTED_FOREGROUND_COLOR = new JBColor(() -> (JBColor.isBright() ? JBColor.WHITE : JBColor.foreground()));
+  public static final Color SELECTED_NON_FOCUSED_BACKGROUND_COLOR = new JBColor(0x6e8ea2, 0x55585a);
+  public static final Color SELECTED_FOREGROUND_COLOR = new JBColor(() -> (JBColor.isBright() ? JBColor.WHITE : JBColor.foreground()));
   private static final Color SELECTED_GRAYED_FOREGROUND_COLOR = new JBColor(() -> (JBColor.isBright() ? JBColor.WHITE: JBColor.foreground()));
 
   static final Color PREFIX_FOREGROUND_COLOR = new JBColor(0xb000b0, 0xd17ad6);
index 0f666f6ffd2776e3dc75e349cc9afabea3bf2dad..199c9c4ad89469c8ed4a7425b5e07cdb7a3e4abf 100644 (file)
@@ -140,7 +140,7 @@ public class LookupManagerImpl extends LookupManager {
       if (myActiveLookup != lookup) return;
 
       LookupElement currentItem = lookup.getCurrentItem();
-      if (currentItem != null && currentItem.isValid()) {
+      if (currentItem != null && currentItem.isValid() && isAutoPopupJavadocSupportedBy(currentItem)) {
         final CompletionProcess completion = CompletionService.getCompletionService().getCurrentCompletion();
         if (completion != null && !completion.isAutopopupCompletion()) {
           try {
@@ -208,6 +208,10 @@ public class LookupManagerImpl extends LookupManager {
     return lookup;
   }
 
+  protected boolean isAutoPopupJavadocSupportedBy(LookupElement lookupItem) {
+    return true;
+  }
+
   @NotNull
   protected LookupImpl createLookup(@NotNull Editor editor, @NotNull LookupArranger arranger, Project project) {
     return new LookupImpl(project, editor, arranger);
index d40d0da907aa9b52da082a0626d91c170f8e8fca..cd0cf62c0b35904d5ea40798e9f8a3eaeb6a6a46 100644 (file)
@@ -84,7 +84,7 @@ public class ProgramParametersConfigurator {
     if (workingDir == null) {
       throw new RuntimeConfigurationWarning("Working directory is null for "+
                                             "project '" + project.getName() + "' ("+project.getBasePath()+")"
-                                            + ", module '" + module.getName() + "' (" + module.getModuleFilePath() + ")");
+                                            + ", module " + (module == null? "null" : "'" + module.getName() + "' (" + module.getModuleFilePath() + ")"));
     }
     if (!new File(workingDir).exists()) {
       throw new RuntimeConfigurationWarning("Working directory '" + workingDir + "' doesn't exist");
index 4209077af697dff2ccbdf482675176f9283f11ae..8a6575f6348798304ad1821e8fc9cc05d574384f 100644 (file)
@@ -77,7 +77,6 @@ import java.util.*;
 import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
 
 public class FindManagerImpl extends FindManager {
   private static final Logger LOG = Logger.getInstance("#com.intellij.find.impl.FindManagerImpl");
@@ -840,6 +839,7 @@ public class FindManagerImpl extends FindManager {
   }
 
   private static Matcher compileRegexAndFindFirst(FindModel model, CharSequence text, int startOffset) {
+    model = normalizeIfMultilined(model);
     Matcher matcher = compileRegExp(model, text);
 
     if (model.isForward()){
@@ -866,38 +866,6 @@ public class FindManagerImpl extends FindManager {
     return new MalformedReplacementStringException(FindBundle.message("find.replace.invalid.replacement.string", model.getStringToReplace()), e);
   }
 
-  private static String getStringToReplaceByRegexp0(String foundString, final FindModel model) throws MalformedReplacementStringException{
-    String toFind = model.getStringToFind();
-    String toReplace = model.getStringToReplace();
-    Pattern pattern;
-    try{
-      int flags = Pattern.MULTILINE;
-      if (!model.isCaseSensitive()) {
-        flags |= Pattern.CASE_INSENSITIVE;
-      }
-      pattern = Pattern.compile(toFind, flags);
-    }
-    catch(PatternSyntaxException e){
-      return toReplace;
-    }
-
-    Matcher matcher = pattern.matcher(foundString);
-    if (matcher.matches()) {
-      try {
-        return matcher.replaceAll(StringUtil.unescapeStringCharacters(toReplace));
-      }
-      catch (Exception e) {
-        throw createMalformedReplacementException(model, e);
-      }
-    }
-    else {
-      // There are valid situations (for example, IDEADEV-2543 or positive lookbehind assertions)
-      // where an expression which matches a string in context will not match the same string
-      // separately).
-      return toReplace;
-    }
-  }
-
   private static String replaceWithCaseRespect(String toReplace, String foundString) {
     if (foundString.isEmpty() || toReplace.isEmpty()) return toReplace;
     StringBuilder buffer = new StringBuilder();
index 45bb0860b0f1dd6bd6979d6cf1b472c83dfce5aa..55b1630a9099e2dad72ad1620e3ef2e65fdb244c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -30,6 +30,7 @@ import javax.swing.text.BadLocationException;
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.util.regex.PatternSyntaxException;
 
 class FilterDialog extends DialogWrapper {
   private final JTextField myRegexpField = new JTextField();
@@ -147,7 +148,8 @@ class FilterDialog extends DialogWrapper {
 
     try {
       checkRegexp(myRegexpField.getText());
-    } catch (InvalidExpressionException e) {
+    }
+    catch (InvalidExpressionException | PatternSyntaxException e) {
       Messages.showMessageDialog(getContentPane(), e.getMessage(), ToolsBundle.message("tools.filters.add.regex.invalid.title"), Messages.getErrorIcon());
       return;
     }
index 5080db806108dfda69e82745736c9ad02fd3f2f4..7c9075e759f48fb18bd820c9501ea8a05a3fab89 100644 (file)
@@ -343,6 +343,7 @@ public abstract class PerFileConfigurableBase<T> implements SearchableConfigurab
       rows[i] = myTable.convertRowIndexToView(rows[i]);
     }
     TableUtil.selectRows(myTable, rows);
+    TableUtil.scrollSelectionToVisible(myTable);
     myFileToSelect = file;
   }
 
index 44fb95bb85f5062376835d3711dd6c222ae4fce5..54f14ec4b509c80eea6ebadface7e60762ea4c3c 100644 (file)
@@ -239,7 +239,9 @@ abstract class MnemonicWrapper<T extends Component> implements Runnable, Propert
 
     @Override
     void setMnemonicCode(int code) {
-      myComponent.setMnemonic(code);
+      if (getMnemonicCode() != code) {
+        myComponent.setMnemonic(code);
+      }
       if (SystemInfo.isMac && Registry.is("ide.mac.alt.mnemonic.without.ctrl")) {
         InputMap map = myComponent.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
         if (map != null) {
@@ -256,7 +258,9 @@ abstract class MnemonicWrapper<T extends Component> implements Runnable, Propert
 
     @Override
     void setMnemonicIndex(int index) {
-      myComponent.setDisplayedMnemonicIndex(index);
+      if (getMnemonicIndex() != index) {
+        myComponent.setDisplayedMnemonicIndex(index);
+      }
     }
   }
 
index 4ae43d01dfb932a414bca04f6f3658763dc07f78..e89e5417429c782fd1cddc38f1124b0fe202db65 100644 (file)
@@ -353,23 +353,12 @@ public final class HttpRequests {
       FileUtilRt.createParentDirs(file);
 
       boolean deleteFile = true;
-      try {
-        OutputStream out = new FileOutputStream(file);
-        try {
-          NetUtils.copyStreamContent(indicator, getInputStream(), out, getConnection().getContentLength());
-          deleteFile = false;
-        }
-        catch (IOException e) {
-          throw new IOException(createErrorMessage(e, this, false), e);
-        }
-        finally {
-          try {
-            out.close();
-          }
-          catch (IOException e) {
-            LOG.warn(e);
-          }
-        }
+      try (OutputStream out = new FileOutputStream(file)) {
+        NetUtils.copyStreamContent(indicator, getInputStream(), out, getConnection().getContentLength());
+        deleteFile = false;
+      }
+      catch (IOException e) {
+        throw new IOException(createErrorMessage(e, this, false), e);
       }
       finally {
         if (deleteFile) {
@@ -423,11 +412,14 @@ public final class HttpRequests {
   }
 
   private static <T> T doProcess(RequestBuilderImpl builder, RequestProcessor<T> processor) throws IOException {
+    CertificateManager manager = ApplicationManager.getApplication() != null ? CertificateManager.getInstance() : null;
     try (RequestImpl request = new RequestImpl(builder)) {
-      CertificateManager manager = ApplicationManager.getApplication() != null ? CertificateManager.getInstance() : null;
-      return manager != null
-             ? manager.runWithUntrustedCertificateStrategy(() -> processor.process(request), builder.myUntrustedCertificateStrategy)
-             : processor.process(request);
+      if (manager != null) {
+        return manager.runWithUntrustedCertificateStrategy(() -> processor.process(request), builder.myUntrustedCertificateStrategy);
+      }
+      else {
+        return processor.process(request);
+      }
     }
   }
 
index a86924a9549508b1ee1d49ad270eb3b64d002927..85915f8bb0d333e562c354ee568f2dd9f4c0620b 100644 (file)
@@ -90,7 +90,6 @@ class RepositoryContentHandler extends DefaultHandler {
         currentPlugin.setDate(dateString);
       }
       currentPlugin.setIncomplete(false);
-      plugins.add(currentPlugin);
     }
     else if (qName.equals(IDEA_VERSION)) {
       currentPlugin.setSinceBuild(attributes.getValue(SINCE_BUILD));
@@ -109,7 +108,6 @@ class RepositoryContentHandler extends DefaultHandler {
       currentPlugin.setDownloadUrl(attributes.getValue(URL));
       currentPlugin.setVersion(attributes.getValue(VERSION));
       currentPlugin.setIncomplete(true);
-      plugins.add(currentPlugin);
     }
     currentValue.setLength(0);
   }
@@ -130,9 +128,6 @@ class RepositoryContentHandler extends DefaultHandler {
     }
     else if (qName.equals(VERSION)) {
       currentPlugin.setVersion(currentValueString);
-      if (PluginManagerCore.isBrokenPlugin(currentPlugin)) {
-        plugins.remove(currentPlugin);
-      }
     }
     else if (qName.equals(VENDOR)) {
       currentPlugin.setVendor(currentValueString);
@@ -154,6 +149,9 @@ class RepositoryContentHandler extends DefaultHandler {
       currentPlugin.setDownloadUrl(currentValueString);
     }
     else if (qName.equals(IDEA_PLUGIN) || qName.equals(PLUGIN)) {
+      if (currentPlugin != null && !PluginManagerCore.isBrokenPlugin(currentPlugin)) {
+        plugins.add(currentPlugin);
+      }
       currentPlugin = null;
     }
   }
index 0f394f6af5128e8361127da8e8a2fa4536f1dea0..dd8d1bc050e345daa1867014909983fefd29a408 100644 (file)
@@ -51,6 +51,7 @@ import com.intellij.ui.content.Content;
 import com.intellij.ui.mac.MacPopupMenuUI;
 import com.intellij.ui.popup.OurHeavyWeightPopup;
 import com.intellij.util.IJSwingUtilities;
+import com.intellij.util.IconUtil;
 import com.intellij.util.ObjectUtils;
 import com.intellij.util.ReflectionUtil;
 import com.intellij.util.containers.ContainerUtil;
@@ -600,6 +601,11 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
       uiDefaults.put("Menu.opaque", true);
       uiDefaults.put("MenuItem.opaque", true);
     }
+
+    if ((SystemInfo.isLinux || SystemInfo.isWindows) && (UIUtil.isUnderIntelliJLaF() || UIUtil.isUnderDarcula())) {
+      uiDefaults.put("Menu.arrowIcon", new MenuArrowIcon(AllIcons.Actions.Right));
+    }
+
     uiDefaults.put("MenuItem.background", UIManager.getColor("Menu.background"));
   }
 
@@ -961,4 +967,39 @@ public final class LafManagerImpl extends LafManager implements ApplicationCompo
       }
     }
   }
+
+  private static class MenuArrowIcon implements Icon, UIResource {
+    private final Icon icon;
+    private final Icon selectedIcon;
+    private final Icon grayIcon;
+
+    private MenuArrowIcon(Icon icon) {
+      boolean invert = UIUtil.isUnderDarcula();
+      this.icon = invert ? IconUtil.brighter(icon, 2) : IconUtil.darker(icon, 2);
+      this.grayIcon = invert ? IconUtil.darker(icon, 2) : IconUtil.brighter(icon, 2);
+      this.selectedIcon = IconUtil.brighter(icon, 8);
+    }
+
+    @Override public void paintIcon(Component c, Graphics g, int x, int y) {
+      JMenuItem b = (JMenuItem) c;
+      ButtonModel model = b.getModel();
+
+      if (!model.isEnabled()) {
+        grayIcon.paintIcon(c, g, x, y);
+      } else if (model.isArmed() || ( c instanceof JMenu && model.isSelected())) {
+        selectedIcon.paintIcon(c, g, x, y);
+      }
+      else {
+        icon.paintIcon(c, g, x, y);
+      }
+    }
+
+    @Override public int getIconWidth() {
+      return icon.getIconWidth();
+    }
+
+    @Override public int getIconHeight() {
+      return icon.getIconHeight();
+    }
+  }
 }
index 144e58a2b56082f22548dab197a2f97cece8f7ed..7e6b0c7221a1cd825733d4745a70f025ba9c0b25 100644 (file)
@@ -163,8 +163,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
 
     AWTExceptionHandler.register(); // do not crash AWT on exceptions
 
-    String debugDisposer = System.getProperty("idea.disposer.debug");
-    Disposer.setDebugMode((isInternal || isUnitTestMode || "on".equals(debugDisposer)) && !"off".equals(debugDisposer));
+    Disposer.setDebugMode((isInternal || isUnitTestMode || Disposer.isDebugDisposerOn()));
 
     myStartTime = System.currentTimeMillis();
     mySplash = splash;
index b9beb42039b82975c790966877d68112b2871b51..21ed071c92d904505a8ba7644ab79e39a0703327 100644 (file)
@@ -775,3 +775,6 @@ inspection.redundant.stream.optional.call.explanation.parallel=there''s subseque
 inspection.redundant.stream.optional.call.fix.family.name=Remove redundant chain call
 inspection.redundant.stream.optional.call.fix.name=Remove ''{0}'' call
 inspection.redundant.stream.optional.call.option.streamboxing=Report useless boxing in Stream.map
+
+inspection.map.foreach.message=Can be replaced with 'Map.forEach'
+inspection.map.foreach.fix.name=Replace with Map.forEach
index 734e59f044a54c0069c6b7d2c092e2dddb9b6ba8..b90bf5beb88271186f391eacf22b77030f9c5615 100644 (file)
@@ -18,6 +18,7 @@ package com.intellij.execution.testframework.sm.runner;
 import com.intellij.execution.configurations.ModuleRunConfiguration;
 import com.intellij.execution.executors.DefaultDebugExecutor;
 import com.intellij.execution.testframework.TestConsoleProperties;
+import com.intellij.openapi.util.Disposer;
 import com.intellij.testFramework.LightPlatformTestCase;
 
 /**
@@ -35,6 +36,13 @@ public abstract class BaseSMTRunnerTestCase extends LightPlatformTestCase {
     mySimpleTest = createTestProxy();
   }
 
+  @Override
+  protected void tearDown() throws Exception {
+    if (mySuite != null) Disposer.dispose(mySuite);
+    if (mySimpleTest != null) Disposer.dispose(mySimpleTest);
+    super.tearDown();
+  }
+
   protected SMTestProxy createTestProxy() {
     return createTestProxy("test");
   }
index 0647c9eccf2703014302e263d3a6ba5edaabb57b..f0e29d0b8f436f3e6ebb78133cd2d512b95ff68b 100644 (file)
@@ -42,6 +42,12 @@ import java.util.concurrent.TimeUnit;
  */
 @SuppressWarnings("JUnitTestClassNamingConvention")
 public class _LastInSuiteTest extends TestCase {
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    Disposer.setDebugMode(true);
+  }
+
   public void testProjectLeak() throws Exception {
     boolean guiTestMode = Boolean.getBoolean("idea.test.guimode");
     if (guiTestMode) {
index bc544dcf9b2f1e086922c418c67ac2233c05bfad..03f53a01aedc06a71024fcf56f8094c54214443f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -25,6 +25,7 @@ import com.intellij.openapi.actionSystem.DataContext;
 import com.intellij.openapi.actionSystem.IdeActions;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.application.Result;
+import com.intellij.openapi.application.WriteAction;
 import com.intellij.openapi.application.ex.PathManagerEx;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.command.WriteCommandAction;
@@ -112,7 +113,9 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
    */
   protected void configureByFile(@TestDataFile @NonNls @NotNull String filePath) {
     try {
-      final File ioFile = new File(getTestDataPath() + filePath);
+      String fullPath = getTestDataPath() + filePath;
+      final File ioFile = new File(fullPath);
+      checkCaseSensitiveFS(fullPath, ioFile);
       String fileText = FileUtilRt.loadFile(ioFile, CharsetToolkit.UTF8, true);
       configureFromFileText(ioFile.getName(), fileText);
     }
@@ -121,6 +124,13 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
     }
   }
 
+  private static void checkCaseSensitiveFS(String fullPath, File ioFile) throws IOException {
+    fullPath = FileUtil.toSystemDependentName(FileUtil.toCanonicalPath(fullPath));
+    if (!ioFile.getCanonicalPath().equals(fullPath)) {
+      throw new RuntimeException("Search for: " + fullPath + "; but found: " + ioFile.getCanonicalPath());
+    }
+  }
+
   @NonNls
   @NotNull
   protected String getTestDataPath() {
@@ -208,7 +218,7 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
     PsiDocumentManager.getInstance(getProject()).commitAllDocuments();
     Editor editor = FileEditorManager.getInstance(getProject()).openTextEditor(new OpenFileDescriptor(getProject(), file, 0), false);
     DaemonCodeAnalyzer.getInstance(getProject()).restart();
-
+    assertNotNull(editor);
     ((EditorImpl)editor).setCaretActive();
     return editor;
   }
@@ -279,16 +289,11 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
 
   private static void deleteVFile() throws IOException {
     if (myVFile != null) {
-      ApplicationManager.getApplication().runWriteAction(new ThrowableComputable<Void, IOException>() {
-        @Override
-        public Void compute() throws IOException {
-          // avoid messing with invalid files, in case someone calls configureXXX() several times
-          PsiDocumentManager.getInstance(ourProject).commitAllDocuments();
-          FileEditorManager.getInstance(ourProject).closeFile(myVFile);
-
-          myVFile.delete(this);
-          return null;
-        }
+      WriteAction.run(() -> {
+        // avoid messing with invalid files, in case someone calls configureXXX() several times
+        PsiDocumentManager.getInstance(ourProject).commitAllDocuments();
+        FileEditorManager.getInstance(ourProject).closeFile(myVFile);
+        myVFile.delete(ourProject);
       });
     }
   }
@@ -345,6 +350,7 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest
     assertTrue(getMessage("Cannot find file " + fullPath, message), ioFile.exists());
     String fileText;
     try {
+     checkCaseSensitiveFS(fullPath, ioFile);
       fileText = FileUtil.loadFile(ioFile, CharsetToolkit.UTF8_CHARSET);
     }
     catch (IOException e) {
index e843cfa536c5abe9c1cc7c4b43cd4957b6be6187..c0bf9c24830737c255e45a4345688f9c3b7ae76b 100644 (file)
@@ -147,7 +147,7 @@ public abstract class UsefulTestCase extends TestCase {
     boolean isStressTest = isStressTest();
     ApplicationInfoImpl.setInStressTest(isStressTest);
     // turn off Disposer debugging for performance tests
-    oldDisposerDebug = Disposer.setDebugMode(Disposer.isDebugMode() && !isStressTest);
+    Disposer.setDebugMode(!isStressTest);
   }
 
   @Override
@@ -158,7 +158,6 @@ public abstract class UsefulTestCase extends TestCase {
       cleanupDeleteOnExitHookList();
     }
     finally {
-      Disposer.setDebugMode(oldDisposerDebug);
       if (shouldContainTempFiles()) {
         FileUtil.resetCanonicalTempPathCache(ORIGINAL_TEMP_DIR);
         if (hasTmpFilesToKeep()) {
index 9344ed4bb31176bf5b97b0ac9ff7c1686c372e91..d8a25fdf91088098f41d346f75d7ba8299782fba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2015 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -30,8 +30,9 @@ public class BareTestFixtureImpl extends BaseFixture implements BareTestFixture
 
   @Override
   public void tearDown() throws Exception {
-    new RunAll(() -> EdtTestUtil.runInEdtAndWait(() -> PlatformTestCase.cleanupApplicationCaches(null)),
-               () -> super.tearDown())
-      .run();
+    new RunAll(
+      () -> EdtTestUtil.runInEdtAndWait(() -> PlatformTestCase.cleanupApplicationCaches(null)),
+      () -> super.tearDown()
+    ).run();
   }
 }
\ No newline at end of file
index 90f69172eecc12d343209b2fa08476dad6f8d72b..ff637f5369667917c75b6e4a323755ae01bcd8c2 100644 (file)
@@ -56,6 +56,11 @@ public class Disposer {
     }
   };
 
+  private static String debugDisposer = System.getProperty("idea.disposer.debug");
+  public static boolean isDebugDisposerOn() {
+    return "on".equals(debugDisposer);
+  }
+
   private static boolean ourDebugMode;
 
   private Disposer() {
@@ -144,7 +149,10 @@ public class Disposer {
   /**
    * @return old value
    */
-  public static boolean setDebugMode(final boolean debugMode) {
+  public static boolean setDebugMode(boolean debugMode) {
+    if (debugMode) {
+      debugMode = !"off".equals(debugDisposer);
+    }
     boolean oldValue = ourDebugMode;
     ourDebugMode = debugMode;
     return oldValue;
index ac1c7d104a2ca59ba54eb8b718170e4abfc04ecd..6ad7349a39d0755a9e6b1eb440cf51eb6b61c7a9 100644 (file)
@@ -78,11 +78,6 @@ public class InvalidWriteAccessSearcher {
     public MyData initial() {
       return new MyData();
     }
-
-    @Override
-    public boolean isForward() {
-      return true;
-    }
   }
 
   private static class MySemilattice implements Semilattice<MyData> {
index c4c1aa4e06f53c99cbcddc96db380d58a0c7c77f..c5816086e130a64c8296a2302a24edf5f16ef055 100644 (file)
@@ -81,11 +81,6 @@ public class VariableInitializationChecker {
       return new Data(false);
     }
 
-    @Override
-    public boolean isForward() {
-      return true;
-    }
-
     private final String myVar;
   }
 
index 7416f84eca83b9902f0996e3022c5479d39ec450..73ef722cd963533c81c0789549336e86037f73bd 100644 (file)
@@ -69,9 +69,4 @@ public class WritesCounterDFAInstance implements DfaInstance<TObjectIntHashMap<G
   public TObjectIntHashMap<GrVariable> initial() {
     return new TObjectIntHashMap<>();
   }
-
-  @Override
-  public boolean isForward() {
-    return true;
-  }
 }
index 57ed7d8cc349bca6969e658ee0a2455bea1e2461..450f5d0abffe0d6198f4c2d1c751879fd85fcdf5 100644 (file)
@@ -823,11 +823,6 @@ public class ControlFlowUtils {
       public BitSet initial() {
         return new BitSet(flow.length);
       }
-
-      @Override
-      public boolean isForward() {
-        return true;
-      }
     };
 
     return new DFAEngine<>(flow, dfa, sem).performForceDFA();
index 1bd040e7fc2f8f7510748248b5a38de22cf2b9de..248ac4ea8e81d28b4d6d47a5bd395d7c99b24f67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -117,18 +117,23 @@ public class ExpressionStatement {
                !ParserUtils.lookAhead(builder, GroovyTokenTypes.mLBRACK, GroovyTokenTypes.mNLS, GroovyTokenTypes.mCOLON)) {
         PathExpression.indexPropertyArgsParse(builder, parser);
         exprStatement.done(GroovyElementTypes.PATH_INDEX_PROPERTY);
+        boolean isCall = false;
         if (GroovyTokenTypes.mLPAREN.equals(builder.getTokenType())) {
           PrimaryExpression.methodCallArgsParse(builder, parser);
+          isCall = true;
         }
         else if (GroovyTokenTypes.mLCURLY.equals(builder.getTokenType())) {
           PsiBuilder.Marker argsMarker = builder.mark();
           argsMarker.done(GroovyElementTypes.ARGUMENTS);
+          isCall = true;
         }
         while (GroovyTokenTypes.mLCURLY.equals(builder.getTokenType())) {
           OpenOrClosableBlock.parseClosableBlock(builder, parser);
         }
-        exprStatement = exprStatement.precede();
-        exprStatement.done(GroovyElementTypes.PATH_METHOD_CALL);
+        if (isCall) {
+          exprStatement = exprStatement.precede();
+          exprStatement.done(GroovyElementTypes.PATH_METHOD_CALL);
+        }
       }
       else if (nameParsed && CommandArguments.parseCommandArguments(builder, parser)) {
         isExprStatement = true;
index fdd861fe904e171277a1477ae5a0d93ab94378aa..179148cb1439149c1f1812d0c128d3bab54e813b 100644 (file)
@@ -22,7 +22,9 @@ import com.intellij.psi.PsiFile;
 import com.intellij.psi.search.PsiShortNamesCache;
 import com.intellij.util.ArrayUtil;
 import com.intellij.util.ArrayUtilRt;
-import gnu.trove.TIntHashSet;
+import com.intellij.util.containers.IntArrayList;
+import com.intellij.util.containers.IntStack;
+import com.intellij.util.containers.ObjectIntHashMap;
 import gnu.trove.TObjectIntHashMap;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
@@ -38,10 +40,16 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseSectio
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
 import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
 import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DFAEngine;
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite.ReadBeforeWriteInstance;
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite.ReadBeforeWriteSemilattice;
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite.ReadBeforeWriteState;
 import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor;
 import org.jetbrains.plugins.groovy.lang.resolve.processors.ResolverProcessor;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
 import java.util.List;
 
 import static org.jetbrains.plugins.groovy.lang.psi.util.PsiTreeUtilKt.treeWalkUp;
@@ -55,56 +63,69 @@ public class ControlFlowBuilderUtil {
   private ControlFlowBuilderUtil() {
   }
 
-  public static int[] postorder(Instruction[] flow) {
-    int[] result = new int[flow.length];
-    boolean[] visited = new boolean[flow.length];
-    for (int i = 0; i < result.length; i++) visited[i] = false;
-
-    int N = flow.length;
-    for (int i = 0; i < flow.length; i++) { //graph might not be connected
-      if (!visited[i]) N = doVisitForPostorder(flow[i], N, result, visited);
-    }
-
-    LOG.assertTrue(N == 0);
-    return result;
+  /**
+   * @return array of instruction numbers in topological order
+   */
+  @NotNull
+  public static int[] reversePostorder(@NotNull Instruction[] flow) {
+    return ArrayUtil.reverseArray(postorder(flow));
   }
 
-  private static int doVisitForPostorder(Instruction curr, int currN, int[] postorder, boolean[] visited) {
-    visited[curr.num()] = true;
-    for (Instruction succ : curr.allSuccessors()) {
-      if (!visited[succ.num()]) {
-        currN = doVisitForPostorder(succ, currN, postorder, visited);
+  @NotNull
+  public static int[] postorder(@NotNull Instruction[] flow) {
+    final int N = flow.length;
+    final boolean[] visited = new boolean[N];
+    Arrays.fill(visited, false);
+
+    final IntArrayList result = new IntArrayList(N);
+    final IntStack stack = new IntStack();
+    for (int i = 0; i < N; i++) { // graph might have multiple entry points
+      if (visited[i]) continue;
+      stack.push(i);
+      visited[i] = true;
+
+      dfs:
+      while (!stack.empty()) {
+        int current = stack.peek();
+
+        for (Instruction successorInst : flow[current].allSuccessors()) {
+          int successor = successorInst.num();
+          if (visited[successor]) continue;
+          stack.push(successor);
+          visited[successor] = true;  // discover successor
+          continue dfs;               // if new successor is discovered go discover its successors
+        }
+
+        result.add(current); // mark black if all successors are discovered, i.e. previous for-cycle was not interrupted
+        stack.pop();
       }
     }
-    postorder[curr.num()] = --currN;
-    return currN;
+
+    LOG.assertTrue(result.size() == N);
+    return result.toArray();
   }
 
   public static ReadWriteVariableInstruction[] getReadsWithoutPriorWrites(Instruction[] flow, boolean onlyFirstRead) {
+    DFAEngine<ReadBeforeWriteState> engine = new DFAEngine<>(
+      flow,
+      new ReadBeforeWriteInstance(buildNamesIndex(flow), onlyFirstRead),
+      ReadBeforeWriteSemilattice.INSTANCE
+    );
+    List<ReadBeforeWriteState> dfaResult = engine.performDFAWithTimeout();
+    if (dfaResult == null) {
+      return ReadWriteVariableInstruction.EMPTY_ARRAY;
+    }
     List<ReadWriteVariableInstruction> result = new ArrayList<>();
-    TObjectIntHashMap<String> namesIndex = buildNamesIndex(flow);
-
-    TIntHashSet[] definitelyAssigned = new TIntHashSet[flow.length];
-
-    int[] postorder = postorder(flow);
-    int[] invpostorder = invPostorder(postorder);
-
-    findReadsBeforeWrites(flow, definitelyAssigned, result, namesIndex, postorder, invpostorder, onlyFirstRead);
-    if (result.isEmpty()) return ReadWriteVariableInstruction.EMPTY_ARRAY;
-    return result.toArray(new ReadWriteVariableInstruction[result.size()]);
-  }
-
-  private static int[] invPostorder(int[] postorder) {
-    int[] result = new int[postorder.length];
-    for (int i = 0; i < postorder.length; i++) {
-      result[postorder[i]] = i;
+    BitSet reads = dfaResult.get(dfaResult.size() - 1).getReads();
+    for (int i = reads.nextSetBit(0); i >= 0; i = reads.nextSetBit(i + 1)) {
+      if (i == Integer.MAX_VALUE) break;
+      result.add((ReadWriteVariableInstruction)flow[i]);
     }
-
-    return result;
+    return result.toArray(ReadWriteVariableInstruction.EMPTY_ARRAY);
   }
 
   private static TObjectIntHashMap<String> buildNamesIndex(Instruction[] flow) {
-    TObjectIntHashMap<String> namesIndex = new TObjectIntHashMap<>();
+    TObjectIntHashMap<String> namesIndex = new ObjectIntHashMap<>();
     int idx = 0;
     for (Instruction instruction : flow) {
       if (instruction instanceof ReadWriteVariableInstruction) {
@@ -117,72 +138,6 @@ public class ControlFlowBuilderUtil {
     return namesIndex;
   }
 
-  private static void findReadsBeforeWrites(Instruction[] flow, TIntHashSet[] definitelyAssigned,
-                                            List<ReadWriteVariableInstruction> result,
-                                            TObjectIntHashMap<String> namesIndex,
-                                            int[] postorder,
-                                            int[] invpostorder,
-                                            boolean onlyFirstRead) {
-    //skip instructions that are not reachable from the start
-    int start = ArrayUtil.find(invpostorder, 0);
-
-    for (int i = start; i < flow.length; i++) {
-      int j = invpostorder[i];
-      Instruction curr = flow[j];
-      if (curr instanceof ReadWriteVariableInstruction) {
-        ReadWriteVariableInstruction rw = (ReadWriteVariableInstruction)curr;
-        int name = namesIndex.get(rw.getVariableName());
-        TIntHashSet vars = definitelyAssigned[j];
-        if (rw.isWrite()) {
-          if (vars == null) {
-            vars = new TIntHashSet();
-            definitelyAssigned[j] = vars;
-          }
-          vars.add(name);
-        }
-        else {
-          if (vars == null || !vars.contains(name)) {
-            result.add(rw);
-            if (onlyFirstRead) {
-              if (vars == null) {
-                vars = new TIntHashSet();
-                definitelyAssigned[j] = vars;
-              }
-              vars.add(name);
-            }
-          }
-        }
-      }
-
-      for (Instruction succ : curr.allSuccessors()) {
-        if (postorder[succ.num()] > postorder[curr.num()]) {
-          TIntHashSet currDefinitelyAssigned = definitelyAssigned[curr.num()];
-          TIntHashSet succDefinitelyAssigned = definitelyAssigned[succ.num()];
-          if (currDefinitelyAssigned != null) {
-            int[] currArray = currDefinitelyAssigned.toArray();
-            if (succDefinitelyAssigned == null) {
-              succDefinitelyAssigned = new TIntHashSet();
-              succDefinitelyAssigned.addAll(currArray);
-              definitelyAssigned[succ.num()] = succDefinitelyAssigned;
-            }
-            else {
-              succDefinitelyAssigned.retainAll(currArray);
-            }
-          }
-          else {
-            if (succDefinitelyAssigned != null) {
-              succDefinitelyAssigned.clear();
-            }
-            else {
-              succDefinitelyAssigned = new TIntHashSet();
-              definitelyAssigned[succ.num()] = succDefinitelyAssigned;
-            }
-          }
-        }
-      }
-    }
-  }
-
   public static boolean isInstanceOfBinary(GrBinaryExpression binary) {
     if (binary.getOperationTokenType() == GroovyTokenTypes.kIN) {
       GrExpression left = binary.getLeftOperand();
index 26c109b9a7fd5ed1cb065d450a46d32b54c9401d..26fd6ab1a1b7a280c6883cff9b1e72c09ef708eb 100644 (file)
@@ -16,7 +16,6 @@
 package org.jetbrains.plugins.groovy.lang.psi.dataFlow;
 
 import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.util.ArrayUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.plugins.groovy.lang.psi.controlFlow.CallEnvironment;
@@ -83,25 +82,20 @@ public class DFAEngine<E> {
     final List<E> info = new ArrayList<>(Collections.nCopies(n, myDfa.initial()));
     final CallEnvironment env = new MyCallEnvironment(n);
 
-    final WorkList workList = new WorkList(n);
-
-    final int[] flowOrder = getFlowOrder();
-    for (int i : flowOrder) {
-      if (!workList.offer(myFlow[i])) continue;
-
-      while (!workList.isEmpty()) {
-        ProgressManager.checkCanceled();
-        if (timeout && checkCounter()) return null;
-        final Instruction curr = workList.remove();
-        final int num = curr.num();
-        final E oldE = info.get(num);                     // saved outbound state
-        final E newE = getInboundState(curr, info, env);  // inbound state
-        myDfa.fun(newE, curr);                            // newly modified outbound state
-        if (!mySemilattice.eq(newE, oldE)) {              // if outbound state changed
-          info.set(num, newE);                            // save new state
-          for (Instruction next : getNext(curr, env)) {
-            workList.offerUnconditionally(next);
-          }
+    final WorkList workList = new WorkList(getFlowOrder());
+
+    while (!workList.isEmpty()) {
+      ProgressManager.checkCanceled();
+      if (timeout && checkCounter()) return null;
+      final int num = workList.next();
+      final Instruction curr = myFlow[num];
+      final E oldE = info.get(num);                     // saved outbound state
+      final E newE = getInboundState(curr, info, env);  // inbound state
+      myDfa.fun(newE, curr);                            // newly modified outbound state
+      if (!mySemilattice.eq(newE, oldE)) {              // if outbound state changed
+        info.set(num, newE);                            // save new state
+        for (Instruction next : getNext(curr, env)) {
+          workList.offer(next.num());
         }
       }
     }
@@ -109,13 +103,13 @@ public class DFAEngine<E> {
     return info;
   }
 
+  @NotNull
   private int[] getFlowOrder() {
-    int[] order = ControlFlowBuilderUtil.postorder(myFlow);
     if (myDfa.isForward()) {
-      return order;
+      return ControlFlowBuilderUtil.reversePostorder(myFlow);
     }
     else {
-      return ArrayUtil.reverseArray(order);
+      return ControlFlowBuilderUtil.postorder(myFlow);
     }
   }
 
index bd4ef0e9a8d43fe0888e262687639feb32b4b409..057439e3bc70e5e572c7139ee772a38dedebbd40 100644 (file)
@@ -22,10 +22,13 @@ import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
  * @author ven
  */
 public interface DfaInstance<E> {
+
   void fun(@NotNull E e, @NotNull Instruction instruction);
 
   @NotNull
   E initial();
 
-  boolean isForward();
+  default boolean isForward() {
+    return true;
+  }
 }
index 405b73a041b4fc3143b0aa0d2310e557c0754326..4a15aafd0662b0fbb5123909ad16a15c85e3389a 100644 (file)
  */
 package org.jetbrains.plugins.groovy.lang.psi.dataFlow
 
-import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction
 import java.util.*
 
-internal class WorkList(size: Int) {
+internal class WorkList(order: IntArray) {
 
-  private val myQueue: Queue<Instruction> = LinkedList<Instruction>()
-  private val myVisited: BooleanArray = BooleanArray(size)
+  private val mySize: Int = order.size
+  /**
+   * Mapping: index -> instruction number
+   */
+  private val myOrder: IntArray = order
+  /**
+   * Mapping: instruction number -> index in [myOrder] array
+   */
+  private val myInstructionToOrder: IntArray = IntArray(mySize)
+  /**
+   * Mapping: index -> whether instruction number needs to be processed
+   *
+   * Indexes match [myOrder] indexes
+   */
+  private val mySet: BitSet = BitSet()
 
-  fun remove(): Instruction = myQueue.remove()
+  init {
+    order.forEachIndexed { index, instruction ->
+      myInstructionToOrder[instruction] = index
+    }
+    mySet.set(0, mySize)
+  }
 
-  val isEmpty: Boolean get() = myQueue.isEmpty()
+  val isEmpty: Boolean get() = mySet.isEmpty
 
   /**
-   * Adds element to the queue and marks it as visited
+   * Instruction number to be processed next
    */
-  fun offerUnconditionally(instruction: Instruction) {
-    myQueue.add(instruction)
-    myVisited[instruction.num()] = true
+  fun next(): Int {
+    /**
+     * Index of instruction in [myOrder]
+     */
+    val next = mySet.nextSetBit(0)
+    assert(next >= 0 && next < mySize)
+    mySet.clear(next)
+    return myOrder[next]
   }
 
   /**
-   * Adds element to the queue and marks it as visited if it wasn't visited before
-   * @return `true` if element was added to the queue
+   * Marks instruction to be processed
    */
-  fun offer(instruction: Instruction): Boolean {
-    if (myVisited[instruction.num()]) return false
-    offerUnconditionally(instruction)
-    return true
+  fun offer(instructionIndex: Int) {
+    /**
+     * Index of instruction in [myOrder]
+     */
+    val orderIndex = myInstructionToOrder[instructionIndex]
+    mySet.set(orderIndex, true)
   }
 }
index 7d334c001c88b3cc962448182985f250c5e143b5..f8bcbf8991e8794fc45ca1f2766da02b00683f25 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -59,7 +59,7 @@ public class ReachingDefinitionsCollector {
     final DefinitionMap dfaResult = inferDfaResult(flow);
 
     final LinkedHashSet<Integer> fragmentInstructions = getFragmentInstructions(first, last, flow);
-    final int[] postorder = ControlFlowBuilderUtil.postorder(flow);
+    final int[] postorder = ControlFlowBuilderUtil.reversePostorder(flow);
     LinkedHashSet<Integer> reachableFromFragmentReads = getReachable(fragmentInstructions, flow, dfaResult, postorder);
     LinkedHashSet<Integer> fragmentReads = filterReads(fragmentInstructions, flow);
 
index 17162b0ccd5d33562fd245113f29b85764a353f8..a2ac05d10af0b4005d6b9c2db1616736c6524bf9 100644 (file)
@@ -66,9 +66,4 @@ public class ReachingDefinitionsDfaInstance implements DfaInstance<DefinitionMap
   public DefinitionMap initial() {
     return new DefinitionMap();
   }
-
-  @Override
-  public boolean isForward() {
-    return true;
-  }
 }
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteInstance.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteInstance.kt
new file mode 100644 (file)
index 0000000..a8cfe81
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite
+
+import gnu.trove.TObjectIntHashMap
+import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction
+import org.jetbrains.plugins.groovy.lang.psi.controlFlow.ReadWriteVariableInstruction
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.DfaInstance
+
+class ReadBeforeWriteInstance(val nameIndex: TObjectIntHashMap<String>, val onlyFirst: Boolean) : DfaInstance<ReadBeforeWriteState> {
+
+  override fun `fun`(state: ReadBeforeWriteState, instruction: Instruction) {
+    if (instruction !is ReadWriteVariableInstruction) return
+    val nameId = nameIndex.get(instruction.variableName)
+    if (nameId < 0) return
+
+    if (instruction.isWrite) {
+      state.writes.set(nameId)
+    }
+    else {
+      if (!state.writes.get(nameId)) {
+        state.reads.set(instruction.num())
+        if (onlyFirst) {
+          state.writes.set(nameId)
+        }
+      }
+    }
+  }
+
+  override fun initial() = ReadBeforeWriteState()
+}
\ No newline at end of file
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteSemilattice.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteSemilattice.kt
new file mode 100644 (file)
index 0000000..e1dd717
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite
+
+import org.jetbrains.plugins.groovy.lang.psi.dataFlow.Semilattice
+
+object ReadBeforeWriteSemilattice : Semilattice<ReadBeforeWriteState> {
+
+  override fun join(ins: List<ReadBeforeWriteState>): ReadBeforeWriteState {
+    if (ins.isEmpty()) return ReadBeforeWriteState()
+    val iterator = ins.iterator()
+    val accumulator = iterator.next().clone() // reduce optimized
+    while (iterator.hasNext()) {
+      val it = iterator.next()
+      accumulator.writes.and(it.writes)
+      accumulator.reads.or(it.reads)
+    }
+    return accumulator
+  }
+
+  override fun eq(e1: ReadBeforeWriteState, e2: ReadBeforeWriteState) = e1 == e2
+}
\ No newline at end of file
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteState.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/dataFlow/readWrite/ReadBeforeWriteState.kt
new file mode 100644 (file)
index 0000000..b1c18f5
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.plugins.groovy.lang.psi.dataFlow.readWrite
+
+import java.util.*
+
+class ReadBeforeWriteState(
+  val writes: BitSet = BitSet(),
+  val reads: BitSet = BitSet()
+) : Cloneable {
+
+  public override fun clone() = ReadBeforeWriteState(writes.clone() as BitSet, reads.clone() as BitSet)
+
+  override fun toString() = "(writes=$writes, reads=$reads)"
+
+  override fun equals(other: Any?): Boolean {
+    if (this === other) return true
+    if (other?.javaClass != javaClass) return false
+    other as ReadBeforeWriteState
+    return writes == other.writes && reads == other.reads
+  }
+
+  override fun hashCode(): Int {
+    return 31 * writes.hashCode() + reads.hashCode()
+  }
+}
\ No newline at end of file
index dcdb657b1ae323401e717d63d163d5897a5a7c32..2f647c79b62ba2f8138d42c3cff3933f9f425c7d 100644 (file)
@@ -284,12 +284,6 @@ public class TypeInferenceHelper {
     public TypeDfaState initial() {
       return new TypeDfaState();
     }
-
-    @Override
-    public boolean isForward() {
-      return true;
-    }
-
   }
 
   private static class InferenceCache {
index ed0e606f80e98a3e75c70132cd8fe87dfa2e3311..5f87fec5caef6f6439e67531458bdc919fcf6da0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -20,7 +20,10 @@ import com.intellij.openapi.util.Couple;
 import com.intellij.openapi.util.VolatileNotNullLazyValue;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.pom.java.LanguageLevel;
-import com.intellij.psi.*;
+import com.intellij.psi.JavaPsiFacade;
+import com.intellij.psi.PsiClassType;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiType;
 import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.util.containers.ContainerUtil;
 import org.jetbrains.annotations.NotNull;
@@ -107,7 +110,12 @@ public abstract class GrMapType extends GrLiteralClassType {
       if (otherEntries.isEmpty()) return "[:]";
       String name = getJavaClassName();
       final PsiType[] params = getParameters();
-      return name + "<" + getInternalText(params[0]) + ", " + getInternalText(params[1]) + ">";
+      if (params.length == 2) {
+        return name + "<" + getInternalText(params[0]) + ", " + getInternalText(params[1]) + ">";
+      }
+      else {
+        return name;
+      }
     }
 
     List<String> components = new ArrayList<>();
index f80f2ee05a46157d57753f5a31430cf352bc03b8..6158a66d83d3c7f4104db89af33ab8affa812a7d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -213,7 +213,8 @@ public class SubstitutorComputer {
 
   @Nullable
   private PsiType handleConversion(@Nullable PsiType paramType, @Nullable PsiType argType) {
-    if (ClosureToSamConverter.isSamConversionAllowed(myPlace) &&
+    if (argType instanceof PsiClassType &&
+        ClosureToSamConverter.isSamConversionAllowed(myPlace) &&
         InheritanceUtil.isInheritor(argType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE) &&
         !TypesUtil.isClassType(paramType, GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) {
       PsiType converted = handleConversionOfSAMType(paramType, (PsiClassType)argType);
index 8cc03b0ef4da4608cc26e5638ced1117883ca77c..6b071057613ddc5a827e1917e9c48572cc6eecd5 100644 (file)
@@ -229,7 +229,9 @@ public abstract class JpsGroovycRunner<R extends BuildRootDescriptor, T extends
 
   protected boolean checkChunkRebuildNeeded(CompileContext context, GroovycOutputParser parser) {
     if (CHUNK_REBUILD_ORDERED.get(context) != null) {
-      CHUNK_REBUILD_ORDERED.set(context, null);
+      if (!myForStubs) {
+        CHUNK_REBUILD_ORDERED.set(context, null);
+      }
       return false;
     }
 
index a5088d0534f14d681461554dc96f3d77860fc498..cab7c0c830d9be5a559dca0a28b960e4f436792d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -175,10 +175,10 @@ public class GroovyScriptRunConfiguration extends ModuleBasedConfiguration<RunCo
   @Override
   public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException {
     final VirtualFile scriptFile = ScriptFileUtil.findScriptFileByPath(getScriptPath());
-    assert scriptFile != null;
+    if (scriptFile == null) return null;
 
     final GroovyScriptRunner scriptRunner = getScriptRunner();
-    assert scriptRunner != null;
+    if (scriptRunner == null) return null;
 
     return new JavaCommandLineState(environment) {
       @NotNull
index c40b0abfb27919b02d707dcf4cb1ddc5f730cb83..955f53669b25c6cb740e7c2ccd69d535d22cbdb9 100644 (file)
@@ -942,6 +942,14 @@ class AppTest {
     assert !make().find { it.category == CompilerMessageCategory.ERROR }
   }
 
+  void "test report real compilation errors"() {
+    addModule('another', true)
+
+    myFixture.addClass('class Foo {}');
+    myFixture.addFileToProject('a.groovy', 'import goo.Goo; class Bar { }')
+    shouldFail { compileModule(myModule) }
+  }
+
   static class GroovycTest extends GroovyCompilerTest {
     void "test navigate from stub to source"() {
       GroovyFile groovyFile = (GroovyFile) myFixture.addFileToProject("a.groovy", "class Groovy3 { InvalidType type }")
index f9e02c80779205c64491748cfce62530283944e9..d6aea1eb8dc6b0a49bac196446411c3a3e733087 100644 (file)
@@ -56,6 +56,14 @@ interface X {
 
 method([X.C, X.D])
 method2([a: X.C, b: X.D])
+'''
+  }
+
+  void 'test map without string keys and values'() {
+    testHighlighting '''\
+def foo(int a) {}
+def m = [(aa): (<error descr="Expression expected">)</error>]
+foo<warning descr="'foo' in '_' cannot be applied to '(java.util.LinkedHashMap)'">(m)</warning>
 '''
   }
 }
index eb257fdaa2476a30a6ff5e65799db6d112c0fec9..8a4c2b835f7b89160599f6886ea4a907fb8d6823 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -37,9 +37,8 @@ class GrUnassignedVariableAccessTest extends GrHighlightingTestBase {
 
   void testUnassignedTryFinally() { doTest() }
 
-
   void testVarIsNotInitialized() {
-    testHighlighting('''\
+    testHighlighting '''\
 def xxx() {
   def category = null
   for (def update : updateIds) {
@@ -52,12 +51,28 @@ def xxx() {
     print p
   }
 }
+'''
+  }
 
+  void 'test simple'() {
+    testHighlighting '''\
 def bar() {
   def p
   print <warning descr="Variable 'p' might not be assigned">p</warning>
 }
-''')
+'''
+  }
+
+  void 'test assigned after read in loop'() {
+    testHighlighting '''\
+def xxx() {
+  def p
+  for (def update : updateIds) {
+    print <warning descr="Variable 'p' might not be assigned">p</warning>
+    p = 1 
+  }
+}
+'''
   }
 
   void testUnassignedAccessInCheck() {
index 4e970ec4a08ff1f20115a523f7197ae92c518543..c188c5af426ffc5ca1a706a1d4e3f774ebf22fff 100644 (file)
@@ -514,6 +514,8 @@ class ExpressionsParsingTest extends GroovyParsingTestCase {
 
   void testcommandExpr$indexAccess3() { doTest() }
 
+  void testcommandExpr$indexAccess4() { doTest() }
+
   void testcommandExpr$closureArg2() { doTest() }
 
   void testcommandExpr$closureArg3() { doTest() }
@@ -852,4 +854,6 @@ Groovy script
   }
 
   void testspecial$mapHang() { doTest() }
+
+  void testindexpropertyWithUnfinishedInvokedExpression() { doTest() }
 }
diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/commandExpr/indexAccess4.test b/plugins/groovy/testdata/parsing/groovy/expressions/commandExpr/indexAccess4.test
new file mode 100644 (file)
index 0000000..b6ac3e3
--- /dev/null
@@ -0,0 +1,21 @@
+Abc.getFoo() baz[0]
+-----
+Groovy script
+  Property by index
+    Reference expression
+      Method call
+        Reference expression
+          Reference expression
+            PsiElement(identifier)('Abc')
+          PsiElement(.)('.')
+          PsiElement(identifier)('getFoo')
+        Arguments
+          PsiElement(()('(')
+          PsiElement())(')')
+      PsiWhiteSpace(' ')
+      PsiElement(identifier)('baz')
+    Arguments
+      PsiElement([)('[')
+      Literal
+        PsiElement(Integer)('0')
+      PsiElement(])(']')
\ No newline at end of file
diff --git a/plugins/groovy/testdata/parsing/groovy/expressions/indexpropertyWithUnfinishedInvokedExpression.test b/plugins/groovy/testdata/parsing/groovy/expressions/indexpropertyWithUnfinishedInvokedExpression.test
new file mode 100644 (file)
index 0000000..8c81b86
--- /dev/null
@@ -0,0 +1,27 @@
+Abc.findAll().
+[a, b]
+-----
+Groovy script
+  Property by index
+    Method call
+      Reference expression
+        Reference expression
+          PsiElement(identifier)('Abc')
+        PsiElement(.)('.')
+        PsiElement(identifier)('findAll')
+      Arguments
+        PsiElement(()('(')
+        PsiElement())(')')
+    PsiElement(.)('.')
+    PsiElement(new line)('\n')
+    PsiErrorElement:Property selector expected
+      <empty list>
+    Arguments
+      PsiElement([)('[')
+      Reference expression
+        PsiElement(identifier)('a')
+      PsiElement(,)(',')
+      PsiWhiteSpace(' ')
+      Reference expression
+        PsiElement(identifier)('b')
+      PsiElement(])(']')
\ No newline at end of file
index 989c963d5c313f30282576d961148712c316e66a..3bd551b75aebd150d4565d36e98778ab3a765e99 100644 (file)
@@ -79,8 +79,8 @@ class SvnDiffSettingsHolder : PersistentStateComponent<SvnDiffSettingsHolder.Sta
 
   class State {
     @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false)
-    var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
-    var SHARED_SETTINGS = SharedSettings()
+    @JvmField var PLACES_MAP: TreeMap<String, PlaceSettings> = TreeMap()
+    @JvmField var SHARED_SETTINGS = SharedSettings()
   }
 
   private var myState: State = State()
index ccb538355c3e93738b2fed33b80194652b8dc6cf..ec1240f3c0b94e71477b3ec317f7fd9173490387 100644 (file)
@@ -82,7 +82,7 @@ get_python:
   inetc::get "$R3" "$INSTDIR\python\python_$R8" /END
   Pop $0
   ${If} $0 == "OK"
-    ExecCmd::exec '"$INSTDIR\python\python_$R8" $R9'
+    ExecDos::exec '"$INSTDIR\python\python_$R8" $R9'
   ${Else}
     MessageBox MB_OK|MB_ICONEXCLAMATION "The download is failed: $0"
   ${EndIf}
diff --git a/python/helpers/pip-7.1.0.tar.gz b/python/helpers/pip-7.1.0.tar.gz
deleted file mode 100644 (file)
index 00cc699..0000000
Binary files a/python/helpers/pip-7.1.0.tar.gz and /dev/null differ
diff --git a/python/helpers/pip-9.0.1.tar.gz b/python/helpers/pip-9.0.1.tar.gz
new file mode 100644 (file)
index 0000000..5416b0d
Binary files /dev/null and b/python/helpers/pip-9.0.1.tar.gz differ
diff --git a/python/helpers/setuptools-18.1.tar.gz b/python/helpers/setuptools-18.1.tar.gz
deleted file mode 100644 (file)
index d4b3043..0000000
Binary files a/python/helpers/setuptools-18.1.tar.gz and /dev/null differ
diff --git a/python/helpers/setuptools-28.8.0.tar.gz b/python/helpers/setuptools-28.8.0.tar.gz
new file mode 100644 (file)
index 0000000..93c14ac
Binary files /dev/null and b/python/helpers/setuptools-28.8.0.tar.gz differ
index eea2ac9af0d666aa347919a9ad52f015af6cd62c..c10dfcea5828bf7c842d726d7f9bc09b10c62004 100644 (file)
@@ -471,9 +471,9 @@ class slice(object):
     step = ...  # type: Optional[int]
     stop = ...  # type: Optional[int]
     @overload
-    def __init__(self, stop: int = None) -> None: ...
+    def __init__(self, stop: int) -> None: ...
     @overload
-    def __init__(self, start: int = None, stop: int = None, step: int = None) -> None: ...
+    def __init__(self, start: int, stop: int, step: int = None) -> None: ...
 
 class tuple(Sequence[_T_co], Generic[_T_co]):
     def __init__(self, iterable: Iterable[_T_co] = ...) -> None: ...
index 8bff35c6fb02039eae4f70850476dfce65201be8..f9ed70f6a7053b81a2d586a791bfc1b2b595559f 100644 (file)
@@ -487,9 +487,9 @@ class slice:
     step = ...  # type: Optional[int]
     stop = ...  # type: Optional[int]
     @overload
-    def __init__(self, stop: int = None) -> None: ...
+    def __init__(self, stop: int) -> None: ...
     @overload
-    def __init__(self, start: int = None, stop: int = None, step: int = None) -> None: ...
+    def __init__(self, start: int, stop: int, step: int = None) -> None: ...
 
 class tuple(Sequence[_T_co], Generic[_T_co]):
     def __init__(self, iterable: Iterable[_T_co] = ...) -> None: ...
diff --git a/python/helpers/virtualenv-13.1.0.tar.gz b/python/helpers/virtualenv-13.1.0.tar.gz
deleted file mode 100644 (file)
index 24f7140..0000000
Binary files a/python/helpers/virtualenv-13.1.0.tar.gz and /dev/null differ
diff --git a/python/helpers/virtualenv-15.1.0.tar.gz b/python/helpers/virtualenv-15.1.0.tar.gz
new file mode 100644 (file)
index 0000000..417873d
Binary files /dev/null and b/python/helpers/virtualenv-15.1.0.tar.gz differ
index ede0a007a927fdc9ae5cc8432c6701284ad33438..f069ae233b439b22c90f1ce989bfee3ae394134b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2017 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.
@@ -105,22 +105,33 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, PyDocStrin
   /**
    * Get class properties.
    *
-   * @return Map [property_name] = [{@link com.jetbrains.python.psi.Property}]
+   * @return Map [property_name] = [{@link Property}]
    */
   @NotNull
   Map<String, Property> getProperties();
 
   /**
-   * Finds a method with given name.
+   * Finds a method with the given name.
    *
    * @param name      what to look for
-   * @param inherited true: search in superclasses; false: only look for methods defined in this class.
-   * @param context
-   * @return
+   * @param inherited true: search in superclasses; false: only look for methods defined in this class
+   * @param context   context to be used to resolve ancestors
+   * @return method with given name or null.
    */
   @Nullable
   PyFunction findMethodByName(@Nullable @NonNls final String name, boolean inherited, TypeEvalContext context);
 
+  /**
+   * Finds a method with the given name and all its overloads.
+   *
+   * @param name      what to look for
+   * @param inherited true: search in superclasses; false: only look for methods defined in this class
+   * @param context   context to be used to resolve ancestors
+   * @return all methods with the given name or empty list.
+   */
+  @NotNull
+  List<PyFunction> multiFindMethodByName(@NotNull String name, boolean inherited, @Nullable TypeEvalContext context);
+
   /**
    * Finds either __init__ or __new__, whichever is defined for given class.
    * If __init__ is defined, it is found first. This mimics the way initialization methods
@@ -283,7 +294,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, PyDocStrin
 
   /**
    * @param context eval context
-   * @return {@link com.jetbrains.python.psi.types.PyType} casted if it has right type
+   * @return {@link PyType} casted if it has right type
    */
   @Nullable
   PyClassLikeType getType(@NotNull TypeEvalContext context);
index 533c889179cc974400f9ad639083c66d117cded0..f89b3490244063e6d436b267ee61d31d005e66bd 100644 (file)
@@ -71,7 +71,7 @@ open class PydevConsoleExecuteActionHandler(private val myConsoleView: LanguageC
     sendLineToConsole(ConsoleCommunication.ConsoleCodeFragment(commandText, checkSingleLine(text)))
   }
 
-  private fun checkSingleLine(text: String): Boolean {
+  fun checkSingleLine(text: String): Boolean {
     val pyFile: PyFile =PyElementGenerator.getInstance(project).createDummyFile(myConsoleView.virtualFile.getUserData(LanguageLevel.KEY), text) as PyFile
     return PsiTreeUtil.findChildOfAnyType(pyFile, PyStatementList::class.java) == null && pyFile.statements.size < 2
 
@@ -185,14 +185,13 @@ open class PydevConsoleExecuteActionHandler(private val myConsoleView: LanguageC
 
   override fun commandExecuted(more: Boolean) = updateConsoleState()
 
-  override fun inputRequested() = updateConsoleState()
-
+  override fun inputRequested() {
+    isEnabled = true
+  }
 
   val pythonIndent: Int
     get() = CodeStyleSettingsManager.getSettings(project).getIndentSize(PythonFileType.INSTANCE)
 
-
-
   val cantExecuteMessage: String
     get() {
       if (!isEnabled) {
index e2e13053f01b6b960b47a1df2df8a77668e08124..0668c1cbe9a9f8b6795e132aad084cac1f351ba3 100644 (file)
@@ -26,6 +26,7 @@ import com.intellij.ide.highlighter.HighlighterFactory;
 import com.intellij.injected.editor.EditorWindow;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.application.TransactionGuard;
+import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.colors.EditorColors;
@@ -52,7 +53,9 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.wm.IdeFocusManager;
+import com.intellij.psi.PsiDocumentManager;
 import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleManager;
 import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
 import com.intellij.ui.JBSplitter;
 import com.intellij.util.TimeoutUtil;
@@ -150,7 +153,8 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
   public void setConsoleEnabled(boolean flag) {
     if (myExecuteActionHandler != null) {
       myExecuteActionHandler.setEnabled(flag);
-    } else {
+    }
+    else {
       myInitialized.doWhenDone(() -> myExecuteActionHandler.setEnabled(flag));
     }
   }
@@ -208,17 +212,27 @@ public class PythonConsoleView extends LanguageConsoleImpl implements Observable
 
 
   public void executeInConsole(final String code) {
-    final String codeToExecute = code.endsWith("\n") ? code : code + "\n";
-
     TransactionGuard.submitTransaction(this, () -> {
-      String text = getConsoleEditor().getDocument().getText();
-      ApplicationManager.getApplication().runWriteAction(() -> setInputText(codeToExecute));
+      final String codeToExecute = code.endsWith("\n") || myExecuteActionHandler.checkSingleLine(code) ? code : code + "\n";
+      DocumentEx document = getConsoleEditor().getDocument();
+      String oldText = document.getText();
+      ApplicationManager.getApplication().runWriteAction(() -> {
+        setInputText(codeToExecute);
+        PsiDocumentManager.getInstance(getProject()).commitDocument(document);
+        PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
+        if (psiFile != null) {
+          CommandProcessor.getInstance().runUndoTransparentAction(() ->
+                                                                    CodeStyleManager.getInstance(getProject())
+                                                                      .adjustLineIndent(psiFile,
+                                                                                        new TextRange(0, psiFile.getTextLength())));
+        }
+      });
       int oldOffset = getConsoleEditor().getCaretModel().getOffset();
-      getConsoleEditor().getCaretModel().moveToOffset(codeToExecute.length());
+      getConsoleEditor().getCaretModel().moveToOffset(document.getTextLength());
       myExecuteActionHandler.runExecuteAction(this);
 
-      if (!StringUtil.isEmpty(text)) {
-        ApplicationManager.getApplication().runWriteAction(() -> setInputText(text));
+      if (!StringUtil.isEmpty(oldText)) {
+        ApplicationManager.getApplication().runWriteAction(() -> setInputText(oldText));
         getConsoleEditor().getCaretModel().moveToOffset(oldOffset);
       }
     });
index 6ff78911c57a116793a5f8cb0a810f174ea167b2..0cad728b8eabc9cbcad6916628e274e85e3af639 100644 (file)
@@ -89,8 +89,10 @@ public class PythonDebugLanguageConsoleView extends DuplexConsoleView<ConsoleVie
     if (!primary && !isPrimaryConsoleEnabled()) {
       PythonConsoleView console = getPydevConsoleView();
       if (!myDebugConsoleInitialized && console.getExecuteActionHandler() != null) {
-        console.addConsoleFolding(true);
-        showStartMessageForFirstExecution(DEBUG_CONSOLE_START_COMMAND, console);
+        if (!console.getExecuteActionHandler().getConsoleCommunication().isWaitingForInput()) {
+          console.addConsoleFolding(true);
+          showStartMessageForFirstExecution(DEBUG_CONSOLE_START_COMMAND, console);
+        }
         myDebugConsoleInitialized = true;
       }
 
index 73965b254ce518f1be2f37c95042b9967e3f0c10..4f9afe9e28680f07197980cd0a1de4e3b2582a6a 100644 (file)
@@ -274,13 +274,15 @@ public class PyArgumentListInspection extends PyInspection {
 
   @Nullable
   private static String calculatePossibleCalleeRepresentation(@NotNull PyCallable callable, @NotNull TypeEvalContext context) {
-    final String callableNameAndParameters = callable.getName() + callable.getParameterList().getPresentableText(true, context);
+    final String name = callable.getName();
+    final String parameters = callable.getParameterList().getPresentableText(true, context);
+    final String callableNameAndParameters = name + parameters;
 
     return Optional
       .ofNullable(PyUtil.as(callable, PyFunction.class))
       .map(PyFunction::getContainingClass)
       .map(PyClass::getName)
-      .map(className -> className + "." + callableNameAndParameters)
+      .map(className -> PyNames.INIT.equals(name) ? className + parameters : className + "." + callableNameAndParameters)
       .orElse(callableNameAndParameters);
   }
 }
index 3b6574612d62d709aa5b1bcac36a4e0c4118de83..d1b399040d1c5c8d2111b551e5082475b26cf6fe 100644 (file)
@@ -60,9 +60,9 @@ public class PyPackageManagerImpl extends PyPackageManager {
   private static final String PIP_PRE_26_VERSION = "1.1";
   private static final String VIRTUALENV_PRE_26_VERSION = "1.7.2";
 
-  private static final String SETUPTOOLS_VERSION = "18.1";
-  private static final String PIP_VERSION = "7.1.0";
-  private static final String VIRTUALENV_VERSION = "13.1.0";
+  private static final String SETUPTOOLS_VERSION = "28.8.0";
+  private static final String PIP_VERSION = "9.0.1";
+  private static final String VIRTUALENV_VERSION = "15.1.0";
 
   private static final int ERROR_NO_SETUPTOOLS = 3;
 
index 8b97fdfb2ace0014259192968c1492536e567fba..1760f67d0197ee8d223c6c148ef2c2e4f5bb1d96 100644 (file)
@@ -1629,9 +1629,11 @@ public class PyUtil {
 
   @NotNull
   public static List<PyParameter> getParameters(@NotNull PyCallable callable, @NotNull TypeEvalContext context) {
-    final List<List<PyParameter>> parametersSet = getOverloadedParametersSet(callable, context);
-    assert !parametersSet.isEmpty();
-    return parametersSet.get(0);
+    return Optional
+      .ofNullable(as(context.getType(callable), PyCallableType.class))
+      .map(callableType -> callableType.getParameters(context))
+      .map(callableParameters -> ContainerUtil.map(callableParameters, PyCallableParameter::getParameter))
+      .orElse(Arrays.asList(callable.getParameterList().getParameters()));
   }
 
   public static boolean isSignatureCompatibleTo(@NotNull PyCallable callable, @NotNull PyCallable otherCallable,
index 4bdf80eb6d17f0578d2b4bcaae72536ae851f807..978029b0d986d80d5f60a2c833bf7ee574df4404 100644 (file)
@@ -41,7 +41,10 @@ import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
 import com.jetbrains.python.documentation.docstrings.DocStringUtil;
 import com.jetbrains.python.psi.*;
 import com.jetbrains.python.psi.impl.stubs.PyClassElementType;
-import com.jetbrains.python.psi.resolve.*;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.resolve.PyResolveUtil;
+import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
+import com.jetbrains.python.psi.resolve.RatedResolveResult;
 import com.jetbrains.python.psi.stubs.PropertyStubStorage;
 import com.jetbrains.python.psi.stubs.PyClassStub;
 import com.jetbrains.python.psi.stubs.PyFunctionStub;
@@ -615,6 +618,41 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
     }
   }
 
+  private static class MultiNameFinder<T extends PyElement> implements Processor<T> {
+
+    @NotNull
+    private final List<T> myResult;
+
+    @NotNull
+    private final String[] myNames;
+
+    @Nullable
+    private PyClass myLastVisitedClass;
+
+    public MultiNameFinder(@NotNull String... names) {
+      myResult = new ArrayList<>();
+      myNames = names;
+      myLastVisitedClass = null;
+    }
+
+    @Override
+    public boolean process(T t) {
+      final PyClass currentClass = t instanceof PyPossibleClassMember ? ((PyPossibleClassMember)t).getContainingClass() : null;
+      // Stop when the current class changes and there was a result
+      if (myLastVisitedClass != null && currentClass != myLastVisitedClass && !myResult.isEmpty()) {
+        return false;
+      }
+
+      myLastVisitedClass = currentClass;
+
+      if (ArrayUtil.contains(t.getName(), myNames)) {
+        myResult.add(t);
+      }
+
+      return true;
+    }
+  }
+
   @Override
   public PyFunction findMethodByName(@Nullable final String name, boolean inherited, @Nullable TypeEvalContext context) {
     if (name == null) return null;
@@ -623,6 +661,14 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
     return proc.getResult();
   }
 
+  @NotNull
+  @Override
+  public List<PyFunction> multiFindMethodByName(@NotNull String name, boolean inherited, @Nullable TypeEvalContext context) {
+    final MultiNameFinder<PyFunction> processor = new MultiNameFinder<>(name);
+    visitMethods(processor, inherited, context);
+    return processor.myResult;
+  }
+
   @Nullable
   @Override
   public PyClass findNestedClass(String name, boolean inherited) {
index ff9771421bb3d68da3c3c9eca7e01f7804ffcf54..05dc987be1ef16ea355af347f1acaa31f3561830 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2016 JetBrains s.r.o.
+ * Copyright 2000-2017 JetBrains s.r.o.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -124,28 +124,29 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
     final String referencedName = myElement.getReferencedName();
     if (referencedName == null) return ResolveResult.EMPTY_ARRAY;
 
-    List<RatedResolveResult> targets = resolveInner();
-    if (targets.size() == 0) return ResolveResult.EMPTY_ARRAY;
+    final List<RatedResolveResult> targets = resolveInner();
+    if (targets.isEmpty()) return ResolveResult.EMPTY_ARRAY;
 
     // change class results to constructor results if there are any
     if (myElement.getParent() instanceof PyCallExpression) { // we're a call
-      ListIterator<RatedResolveResult> it = targets.listIterator();
-      while (it.hasNext()) {
-        final RatedResolveResult rrr = it.next();
-        final PsiElement elt = rrr.getElement();
-        if (elt instanceof PyClass) {
-          PyClass cls = (PyClass)elt;
-          PyFunction init = cls.findMethodByName(PyNames.INIT, false, null);
-          if (init != null) {
+      final ListIterator<RatedResolveResult> iterator = targets.listIterator();
+      while (iterator.hasNext()) {
+        final RatedResolveResult rrr = iterator.next();
+        final PsiElement element = rrr.getElement();
+        if (element instanceof PyClass) {
+          final PyClass cls = (PyClass)element;
+          final List<PyFunction> ownInits = cls.multiFindMethodByName(PyNames.INIT, false, null);
+          if (!ownInits.isEmpty()) {
             // replace
-            it.set(rrr.replace(init));
+            iterator.remove();
+            ownInits.forEach(init -> iterator.add(rrr.replace(init)));
           }
-          else { // init not found; maybe it's ancestor's
+          else {// init not found; maybe it's ancestor's
             for (PyClass ancestor : cls.getAncestorClasses(myContext.getTypeEvalContext())) {
-              init = ancestor.findMethodByName(PyNames.INIT, false, null);
-              if (init != null) {
+              final List<PyFunction> ancestorInits = ancestor.multiFindMethodByName(PyNames.INIT, false, null);
+              if (!ancestorInits.isEmpty()) {
                 // add to results as low priority
-                it.add(new RatedResolveResult(RatedResolveResult.RATE_LOW, init));
+                ancestorInits.forEach(init -> iterator.add(new RatedResolveResult(RatedResolveResult.RATE_LOW, init)));
                 break;
               }
             }
@@ -154,9 +155,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference
       }
     }
 
-    // put everything in a sorting container
-    List<RatedResolveResult> ret = RatedResolveResult.sorted(targets);
-    return ret.toArray(new ResolveResult[ret.size()]);
+    return RatedResolveResult.sorted(targets).toArray(ResolveResult.EMPTY_ARRAY);
   }
 
   @NotNull
index db2d50352138e5f03de104e9f1699292ca9921ea..7cdcb1ea6e49284c5afbc34db6762b5661ffd4a5 100644 (file)
@@ -1,2 +1,2 @@
 float()
-float(1, <warning descr="Unexpected argument">2</warning>)
+float<warning descr="Unexpected argument(s)Possible callees:float(self: float)float(self: float, x: SupportsFloat)float(self: float, x: unicode)float(self: float, x: bytearray)">(1, 2)</warning>
index 486eb2ecd158230f371445d8500c2137d9155998..9cab79222d1fd0d7608cededa8e5ef8966f5575e 100644 (file)
@@ -1,5 +1,5 @@
-print(slice(<warning descr="Parameter 'start' unfilled">)</warning>)
+print(slice(<warning descr="Parameter(s) unfilledPossible callees:slice(self: slice, stop: int)slice(self: slice, start: int, stop: int, step: Optional[int])">)</warning>)
 print(slice(1))
 print(slice(1, 2))
 print(slice(1, 2, 3))
-print(slice(1, 2, 3, <warning descr="Unexpected argument">4</warning>))
+print(slice<warning descr="Unexpected argument(s)Possible callees:slice(self: slice, stop: int)slice(self: slice, start: int, stop: int, step: Optional[int])">(1, 2, 3, 4)</warning>)
index b47f64aeb7d5b04e42ddf73ec0b6109f28d461df..3f97d8072128cdfb74ca0060f66f723e090c6311 100644 (file)
@@ -2,4 +2,4 @@ print(unicode())
 print(unicode(''))
 print(unicode('', 'utf-8'))
 print(unicode('', 'utf-8', 'ignore'))
-print(unicode('', 'utf-8', 'ignore', <warning descr="Unexpected argument">foo</warning>))
+print(unicode<warning descr="Unexpected argument(s)Possible callees:unicode(self: unicode)unicode(self: unicode, o: object)unicode(self: unicode, o: str, encoding: Optional[unicode]=..., errors: Optional[unicode]=...)">('', 'utf-8', 'ignore', foo)</warning>)
index 2eaede119bad76a2653fb34175a24c2928e809e2..eef50ee0cc86919d6fff4566d39a7a47d963ee91 100644 (file)
@@ -1,5 +1,5 @@
-print(xrange(<warning descr="Parameter 'start' unfilled">)</warning>)
+print(xrange(<warning descr="Parameter(s) unfilledPossible callees:xrange(self: xrange, stop: int)xrange(self: xrange, start: int, stop: int, step: int=1)">)</warning>)
 print(xrange(1))
 print(xrange(1, 2))
 print(xrange(1, 2, 3))
-print(xrange(1, 2, 3, <warning descr="Unexpected argument">4</warning>))
+print(xrange<warning descr="Unexpected argument(s)Possible callees:xrange(self: xrange, stop: int)xrange(self: xrange, start: int, stop: int, step: int=1)">(1, 2, 3, 4)</warning>)
diff --git a/resources-en/src/inspectionDescriptions/Java8MapForEach.html b/resources-en/src/inspectionDescriptions/Java8MapForEach.html
new file mode 100644 (file)
index 0000000..6302a70
--- /dev/null
@@ -0,0 +1,9 @@
+<html>
+<body>
+This inspection suggests to replace <code>for(Entry&lt;?,?&gt; entry : map.entrySet()) {...}</code> or
+<code>map.entrySet().forEach(entry -&gt; ...)</code> with <code>map.forEach((key, value) -> ...)</code>.
+<!-- tooltip end -->
+<p>This inspection is available since Java 8 only.</p>
+<small>New in 2017.1</small>
+</body>
+</html>
\ No newline at end of file
index 350ec891c52f3fa0b053e321786234c76236d41f..b5b47ff5e73d828493c38f766572d85cca535dc9 100644 (file)
                      groupKey="group.names.language.level.specific.issues.and.migration.aids" enabledByDefault="true" level="WARNING"
                      implementationClass="com.intellij.codeInspection.java18api.Java8MapApiInspection"
                      displayName="Replace with single Map method"/>
+    <localInspection groupPath="Java" language="JAVA" shortName="Java8MapForEach"
+                     groupBundle="messages.InspectionsBundle"
+                     groupKey="group.names.code.style.issues" enabledByDefault="true" level="WARNING"
+                     implementationClass="com.intellij.codeInspection.java18api.Java8MapForEachInspection"
+                     displayName="Replace with Map.forEach"/>
     <localInspection groupPath="Java" language="JAVA" shortName="ExcessiveLambdaUsage"
                      groupBundle="messages.InspectionsBundle"
                      groupKey="group.names.verbose.or.redundant.code.constructs" enabledByDefault="true" level="WARNING"