diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index 556e342110d2..a5ee8935ba5e 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -21,6 +21,7 @@ import com.intellij.codeInsight.TestFrameworks; import com.intellij.execution.*; import com.intellij.execution.junit2.info.MethodLocation; import com.intellij.execution.testframework.SourceScope; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.progress.ProgressManager; @@ -278,7 +279,7 @@ public class JUnitUtil { return aPackage != null && aPackage.getDirectories(scope).length > 0; }; - return foundCondition.value(TEST5_PACKAGE_FQN); + return ReadAction.compute(() -> foundCondition.value(TEST5_PACKAGE_FQN)); } public static boolean isTestAnnotated(final PsiMethod method) { diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java index ff95b6c02bcc..c83cd6b59b67 100644 --- a/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/generation/GenerateDelegateHandler.java @@ -163,7 +163,8 @@ public class GenerateDelegateHandler implements LanguageCodeInsightActionHandler stmt = (PsiStatement)CodeStyleManager.getInstance(psiManager.getProject()).reformat(stmt); method.getBody().add(stmt); - GenerateMembersUtil.copyAnnotations(methodCandidate.getElement().getModifierList(), method.getModifierList(), SuppressWarnings.class.getName()); + GenerateMembersUtil.copyAnnotations(methodCandidate.getElement().getModifierList(), method.getModifierList(), + SuppressWarnings.class.getName(), Override.class.getName()); if (isMethodStatic || modifierList != null && modifierList.hasModifierProperty(PsiModifier.STATIC)) { PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true); diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index bf3b6a65e519..e3416e934584 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -16,7 +16,6 @@ package com.intellij.psi; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.RecursionGuard; import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.search.GlobalSearchScope; @@ -83,13 +82,17 @@ public class PsiCapturedWildcardType extends PsiType.Stub { glb = substitutedBoundType; } else { - glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBoundType); + glb = getGreatestLowerBound(glb, substitutedBoundType, wildcardType); } } return glb; } + private static PsiType getGreatestLowerBound(PsiType glb, PsiType bound, Object guardObject) { + return guard.doPreventingRecursion(guardObject, true, () -> GenericsUtil.getGreatestLowerBound(glb, bound)); + } + @Override public boolean equals(Object o) { if (!(o instanceof PsiCapturedWildcardType)) { diff --git a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java index 4bd643b13974..331063c585dd 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiIntersectionType.java @@ -60,7 +60,7 @@ public class PsiIntersectionType extends PsiType.Stub { @NotNull private static PsiType[] flattenAndRemoveDuplicates(@NotNull PsiType[] conjuncts) { try { - final Set flattenConjuncts = PsiCapturedWildcardType.guard.doPreventingRecursion(conjuncts, true, () -> flatten(conjuncts, ContainerUtil.newLinkedHashSet())); + final Set flattenConjuncts = flatten(conjuncts, ContainerUtil.newLinkedHashSet()); if (flattenConjuncts == null) { return conjuncts; } diff --git a/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferUnderscoredCaseMatch.java b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferUnderscoredCaseMatch.java new file mode 100644 index 000000000000..21ba4e5aa742 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normalSorting/DispreferUnderscoredCaseMatch.java @@ -0,0 +1,5 @@ +class Zoo { + void zoo(String fooBar, String __foo_bar) { + foo + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/ValidIntersectionTypeWithCapturedBounds1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/ValidIntersectionTypeWithCapturedBounds1.java new file mode 100644 index 000000000000..bba01422feca --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/ValidIntersectionTypeWithCapturedBounds1.java @@ -0,0 +1,21 @@ + +abstract class Bug { + void m1(){ + D jobHandler = m(); + } + + abstract > J m(); +} + +interface B { +} + +abstract class C { + +} + +abstract class D extends C { + +} + +abstract class E implements B { } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/delegateMethods/afterEnsureCorrectOverride.java b/java/java-tests/testData/codeInsight/delegateMethods/afterEnsureCorrectOverride.java new file mode 100644 index 000000000000..aaf6f267b571 --- /dev/null +++ b/java/java-tests/testData/codeInsight/delegateMethods/afterEnsureCorrectOverride.java @@ -0,0 +1,17 @@ +interface I { + void foo(); +} +class A implements I { + @Override + public void foo() { + + } +} + +class B { + A a; + + public void foo() { + a.foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/delegateMethods/beforeEnsureCorrectOverride.java b/java/java-tests/testData/codeInsight/delegateMethods/beforeEnsureCorrectOverride.java new file mode 100644 index 000000000000..5cb936e92b07 --- /dev/null +++ b/java/java-tests/testData/codeInsight/delegateMethods/beforeEnsureCorrectOverride.java @@ -0,0 +1,14 @@ +interface I { + void foo(); +} +class A implements I { + @Override + public void foo() { + + } +} + +class B { + A a; + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/DelegateMethodsTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/DelegateMethodsTest.java index f68980165c96..f087829c9a19 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/DelegateMethodsTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/DelegateMethodsTest.java @@ -58,6 +58,7 @@ public class DelegateMethodsTest extends LightCodeInsightTestCase { public void testMultipleOverrideAnnotations() { doTest(); } public void testStripSuppressWarningsAnnotation() { doTest(); } public void testDoNotOverrideFinal() { doTest(); } + public void testEnsureCorrectOverride() { doTest(); } public void testAllowDelegateToFinal() { doTest(); } public void testDelegateWithSubstitutionOverrides() { doTest(); } public void testDelegateWithSubstitutionNoOverrides() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy index 46257504acf2..f44f25fd1adf 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionOrderingTest.groovy @@ -443,6 +443,10 @@ interface TxANotAnno {} checkPreferredItems(0, 'fooBar', '_fooBar', 'FooBar') } + void testDispreferUnderscoredCaseMatch() { + checkPreferredItems(0, 'fooBar', '__foo_bar') + } + void testStatisticsMattersOnNextCompletion() { configureByFile(getTestName(false) + ".java") myFixture.completeBasic() diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 2aad6e703571..fd044c5a5e0e 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -116,6 +116,7 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase public void testIDEA149774() { doTest(); } public void testDisjunctionTypes() { doTest(); } public void testValidIntersectionTypeWithCapturedBounds() { doTest(); } + public void testValidIntersectionTypeWithCapturedBounds1() { doTest(); } public void testPushErasedStateToArguments() { doTest(); } public void testStopAtStandaloneConditional() { doTest(); } public void testTransitiveInferenceVariableDependencies() { doTest(); } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/SingleInspectionProfilePanelTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInspection/SingleInspectionProfilePanelTest.kt index 0e34161e0e42..9df2acbac466 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/SingleInspectionProfilePanelTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/SingleInspectionProfilePanelTest.kt @@ -25,6 +25,7 @@ import com.intellij.profile.codeInspection.ui.SingleInspectionProfilePanel import com.intellij.testFramework.LightIdeaTestCase import com.intellij.testFramework.configureInspections import com.intellij.testFramework.createProfile +import com.intellij.testFramework.runInInitMode import junit.framework.TestCase import org.assertj.core.api.Assertions.assertThat @@ -33,23 +34,25 @@ class SingleInspectionProfilePanelTest : LightIdeaTestCase() { // see IDEA-85700 fun testSettingsModification() { - val project = ProjectManager.getInstance().defaultProject - val profile = configureInspections(arrayOf(myInspection), project, testRootDisposable) + runInInitMode { + val project = ProjectManager.getInstance().defaultProject + val profile = configureInspections(arrayOf(myInspection), project, testRootDisposable) - val model = profile.modifiableModel - val panel = SingleInspectionProfilePanel(ProjectInspectionProfileManager.getInstance(project), model) - panel.isVisible = true - panel.reset() + val model = profile.modifiableModel + val panel = SingleInspectionProfilePanel(ProjectInspectionProfileManager.getInstance(project), model) + panel.isVisible = true + panel.reset() - val tool = getInspection(model) - assertEquals("", tool.myAdditionalJavadocTags) - tool.myAdditionalJavadocTags = "foo" - model.setModified(true) - panel.apply() - assertThat(InspectionProfileTest.countInitializedTools(model)).isEqualTo(1) + val tool = getInspection(model) + assertEquals("", tool.myAdditionalJavadocTags) + tool.myAdditionalJavadocTags = "foo" + model.setModified(true) + panel.apply() + assertThat(InspectionProfileTest.countInitializedTools(model)).isEqualTo(1) - assertThat(getInspection(profile).myAdditionalJavadocTags).isEqualTo("foo") - panel.disposeUI() + assertThat(getInspection(profile).myAdditionalJavadocTags).isEqualTo("foo") + panel.disposeUI() + } } fun testModifyInstantiatedTool() { diff --git a/platform/build-scripts/tools/mac/scripts/makedmg.pl b/platform/build-scripts/tools/mac/scripts/makedmg.pl index 8a7076715ace..4c4f1c34f7c0 100644 --- a/platform/build-scripts/tools/mac/scripts/makedmg.pl +++ b/platform/build-scripts/tools/mac/scripts/makedmg.pl @@ -6,15 +6,16 @@ use Mac::Files qw( NewAliasMinimal ); $name = $ARGV[0]; $bg_pic = $ARGV[1]; +$mountName = $ARGV[2]; -&writeDSDBEntries("/Volumes/$name/.DS_Store", +&writeDSDBEntries("/Volumes/$mountName/.DS_Store", &makeEntries(".background", Iloc_xy => [ 560, 170 ]), &makeEntries(".DS_Store", Iloc_xy => [ 610, 170 ]), &makeEntries(".fseventsd", Iloc_xy => [ 660, 170 ]), &makeEntries(".Trashes", Iloc_xy => [ 710, 170 ]), &makeEntries(" ", Iloc_xy => [ 335, 120 ]), &makeEntries(".", - BKGD_alias => NewAliasMinimal("/Volumes/$name/.background/$bg_pic"), + BKGD_alias => NewAliasMinimal("/Volumes/$mountName/.background/$bg_pic"), ICVO => 1, fwi0_flds => [ 100, 400, 396, 855, "icnv", 0, 0 ], fwsw => 170, diff --git a/platform/build-scripts/tools/mac/scripts/makedmg.sh b/platform/build-scripts/tools/mac/scripts/makedmg.sh index 22ab16318398..3b91e1811aa0 100644 --- a/platform/build-scripts/tools/mac/scripts/makedmg.sh +++ b/platform/build-scripts/tools/mac/scripts/makedmg.sh @@ -37,17 +37,17 @@ echo "Creating unpacked r/w disk image ${VOLNAME}..." hdiutil create -srcfolder ./${EXPLODED} -volname "$VOLNAME" -anyowners -nospotlight -quiet -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW $2.temp.dmg # check if the image already mounted -if [ -d "/Volumes/$VOLNAME" ]; then +if [ -d "/Volumes/$1" ]; then attempt=1 limit=5 while [ $attempt -le $limit ] do - echo "/Volumes/$VOLNAME - the image is already mounted. This build will wait for unmount for 1 min (up to 5 times)." + echo "/Volumes/$1 - the image is already mounted. This build will wait for unmount for 1 min (up to 5 times)." sleep 60; let "attempt += 1" - if [ -d "/Volumes/$VOLNAME" ]; then - if [ $attempt -eq $limit ]; then - echo "/Volumes/$VOLNAME - the image is still mounted. By the reason the build will be stopped." + if [ -d "/Volumes/$1" ]; then + if [ $attempt -ge $limit ]; then + echo "/Volumes/$1 - the image is still mounted. By the reason the build will be stopped." rm -rf ${EXPLODED} rm -f $2.temp.dmg exit 1 @@ -58,16 +58,17 @@ fi # mount this image echo "Mounting unpacked r/w disk image..." -device=$(hdiutil attach -readwrite -noverify -noautoopen $2.temp.dmg | egrep '^/dev/' | sed 1q | awk '{print $1.dmg}') +device=$(hdiutil attach -readwrite -noverify -mountpoint /Volumes/"$1" -noautoopen $2.temp.dmg | egrep '^/dev/' | sed 1q | awk '{print $1.dmg}') echo "Mounted as ${device}." sleep 10 -find /Volumes/"$VOLNAME" -maxdepth 1 +find /Volumes/"$1" -maxdepth 1 # set properties echo "Updating $VOLNAME disk image styles..." -stat /Volumes/"$VOLNAME"/DSStorePlaceHolder || true -rm /Volumes/"$VOLNAME"/DSStorePlaceHolder -perl makedmg.pl "$VOLNAME" ${BG_PIC} +stat /Volumes/"$1"/DSStorePlaceHolder || true +rm /Volumes/"$1"/DSStorePlaceHolder +perl makedmg.pl "$VOLNAME" ${BG_PIC} "$1" + sync;sync;sync hdiutil detach ${device} diff --git a/platform/core-api/src/com/intellij/lang/injection/MultiHostInjector.java b/platform/core-api/src/com/intellij/lang/injection/MultiHostInjector.java index 4172eaf05570..d76b7edf4380 100644 --- a/platform/core-api/src/com/intellij/lang/injection/MultiHostInjector.java +++ b/platform/core-api/src/com/intellij/lang/injection/MultiHostInjector.java @@ -24,12 +24,64 @@ import java.util.List; /** * @see com.intellij.psi.PsiLanguageInjectionHost + * @see MultiHostRegistrar */ public interface MultiHostInjector { ExtensionPointName MULTIHOST_INJECTOR_EP_NAME = ExtensionPointName.create("com.intellij.multiHostInjector"); + /** + * Provides list of places to inject a language to.
+ * + * For example, to inject "RegExp" language to java string literal, you can override this method with something like this: + *
+   * class MyRegExpToJavaInjector implements MultiHostInjector {
+   *   void getLanguagesToInject(MultiHostRegistrar registrar, PsiElement context) {
+   *     if (context instanceof PsiLiteralExpression && looksLikeAGoodPlaceToInject(context)) {
+   *       registrar.startInjecting(REGEXP_LANG).addPlace(null,null,context,innerRangeStrippingQuotes(context));
+   *     }
+   *   }
+   * }
+   * 
+ * + * Also, we may need to inject into several fragments at once. For example, if we have this really bizarre XML-based DSL: + *
+   * {@code
+   *
+   * 
+   *   
+   *     foo
+   *     System.out.println(42);
+   *   
+   * 
+   * }
+   * 
+ * + * which should be converted to Java: + *
class MyDsl { void foo() { System.out.println(42);} }
+ * + * Then we can inject Java into several places at once - method name and its body: + *
+   * class MyBizarreDSLInjector implements MultiHostInjector {
+   *   void getLanguagesToInject(MultiHostRegistrar registrar, PsiElement context) {
+   *     if (isMethodTag(context)) {
+   *       registrar.startInjecting(JavaLanguage.INSTANCE);
+   *       // construct class header, method header, inject method name, append code block start
+   *       registrar.addPlace("class MyDsl { void ", "() {", context, rangeForMethodName(context));
+   *       // inject method body, append closing braces to form a valid Java class structure
+   *       registrar.addPlace(null, "}}", context, rangeForBody(context));
+   *       registrar.doneInjecting();
+   *     }
+   *   }
+   * }
+   * 
+ * + * Now, then we look at this XML in the editor, "foo" will feel like a method name + * and "System.out.println(42);" will look and feel like a method body - with highlighting, completion, goto definitions etc. + * + */ void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement context); + @NotNull List> elementsToInjectIn(); } \ No newline at end of file diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java index d4315050916c..ea324d64073f 100644 --- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/VirtualFilePointerContainerImpl.java @@ -259,14 +259,17 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir return myList.hashCode(); } + @NotNull protected VirtualFilePointer create(@NotNull VirtualFile file) { return myVirtualFilePointerManager.create(file, myParent, myListener); } + @NotNull protected VirtualFilePointer create(@NotNull String url) { return myVirtualFilePointerManager.create(url, myParent, myListener); } + @NotNull protected VirtualFilePointer duplicate(@NotNull VirtualFilePointer virtualFilePointer) { return myVirtualFilePointerManager.duplicate(virtualFilePointer, myParent, myListener); } @@ -300,5 +303,6 @@ class VirtualFilePointerContainerImpl extends TraceableDisposable implements Vir assert !myDisposed; myDisposed = true; kill(null); + clear(); } } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java index 73923b6e395c..9fc55743281d 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/impl/CamelHumpMatcher.java @@ -63,14 +63,26 @@ public class CamelHumpMatcher extends PrefixMatcher { @Override public boolean prefixMatches(@NotNull final String name) { if (name.startsWith("_") && - myPrefix.length() > 0 && Character.isLetter(myPrefix.charAt(0)) && - CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.FIRST_LETTER) { + CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE == CodeInsightSettings.FIRST_LETTER && + firstLetterCaseDiffers(name)) { return false; } return myMatcher.matches(name); } + private boolean firstLetterCaseDiffers(String name) { + int nameFirst = skipUnderscores(name); + int prefixFirst = skipUnderscores(myPrefix); + return nameFirst < name.length() && + prefixFirst < myPrefix.length() && + caseDiffers(name.charAt(nameFirst), myPrefix.charAt(prefixFirst)); + } + + private static boolean caseDiffers(char c1, char c2) { + return Character.isLowerCase(c1) != Character.isLowerCase(c2) || Character.isUpperCase(c1) != Character.isUpperCase(c2); + } + @Override public boolean prefixMatches(@NotNull final LookupElement element) { return prefixMatchersInternal(element, !element.isCaseSensitive()); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java index 3cb83e976bae..cd4ae0f05f3c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java @@ -112,8 +112,9 @@ public class ExternalToolPass extends ProgressableTextEditorHighlightingPass { String shortName = annotator.getPairedBatchInspectionShortName(); if (shortName != null) { HighlightDisplayKey key = HighlightDisplayKey.find(shortName); - LOG.assertTrue(key != null, "Paired tool '" + shortName + "' not found for external annotator: " + annotator); - if (!profile.isToolEnabled(key, myFile)) continue; + LOG.assertTrue(key != null || ApplicationManager.getApplication().isUnitTestMode(), + "Paired tool '" + shortName + "' not found for external annotator: " + annotator); + if (key == null || !profile.isToolEnabled(key, myFile)) continue; //test should register corresponding paired tool for annotator to run } Object collectedInfo = editor != null ? annotator.collectInformation(psiRoot, editor, errorFound) : annotator.collectInformation(psiRoot); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java index 496b3817abe7..c92b102d3158 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/highlighting/BraceHighlightingHandler.java @@ -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. @@ -529,7 +529,7 @@ public class BraceHighlightingHandler { myAlarm.addRequest(() -> { if (myProject.isDisposed()) return; PsiDocumentManager.getInstance(myProject).performLaterWhenAllCommitted(() -> { - if (!myEditor.getComponent().isShowing()) return; + if (myEditor.isDisposed() || !myEditor.getComponent().isShowing()) return; Rectangle viewRect = myEditor.getScrollingModel().getVisibleArea(); if (y < viewRect.y) { int start = lbraceStart; diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java index 15793c351689..0dde9268c9d6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java @@ -464,6 +464,8 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec } private PlaceInfo createPlaceInfo(@NotNull final FileEditor fileEditor, final FileEditorProvider fileProvider) { + if (!fileEditor.isValid()) return null; + final VirtualFile file = myEditorManager.getFile(fileEditor); LOG.assertTrue(file != null); diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index 09635cd1cb1e..f2f550374d75 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -30,7 +30,7 @@ com.intellij.apacheConfig 144.3713 143.2287.2 143.381.48 142.5266 141.388 139.78 org.intellij.clojure 0.2.1.178 net.nicoulaj.idea.markdown 0.9.7 0.9.6 0.9.5 0.9.4 0.9.3 0.9.2 0.9.1 0.8.3 0.8.2 0.8.1 0.8 0.7 0.6.1 0.6 0.5.1 0.5 0.4 0.3 0.2 0.1 zielu.gittoolbox 13.1.0 13.5.2 -mobi.hsz.idea.gitignore 1.2 1.3 1.3.3 1.4.1 1.5 1.6 1.7.5 1.7.6 2.0.4 +mobi.hsz.idea.gitignore 1.2 1.3 1.3.3 1.4.1 1.5 1.6 1.7.5 1.7.6 2.0.4 2.1.1 2.2.0 com.vladsch.idea.multimarkdown 1.4.2 1.4.7 com.jetbrains.chronon 134.1221 134.1414 134.1618 135.1291 135.476 135.666 ArgoUML.Integration 0.1.1 0.1.2 diff --git a/platform/platform-resources/src/idea/VcsActions.xml b/platform/platform-resources/src/idea/VcsActions.xml index 977adafa24cb..1dad5b71986d 100644 --- a/platform/platform-resources/src/idea/VcsActions.xml +++ b/platform/platform-resources/src/idea/VcsActions.xml @@ -323,8 +323,8 @@ - + @@ -339,6 +339,7 @@ + diff --git a/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewTreeTest.java b/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewTreeTest.java index fa1839c2f9ca..2416f18b16e1 100644 --- a/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewTreeTest.java +++ b/platform/platform-tests/testSrc/com/intellij/usages/impl/UsageViewTreeTest.java @@ -46,15 +46,12 @@ public class UsageViewTreeTest extends UsefulTestCase { super.setUp(); myFixtureBuilder = IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder("moduleGroups"); myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(myFixtureBuilder.getFixture()); - myDisposable = new Disposable() { - @Override - public void dispose() { - try { - myFixture.tearDown(); - } - catch (Exception e) { - throw new RuntimeException(e); - } + myDisposable = () -> { + try { + myFixture.tearDown(); + } + catch (Exception e) { + throw new RuntimeException(e); } }; myFixture.setUp(); @@ -72,7 +69,7 @@ public class UsageViewTreeTest extends UsefulTestCase { public void testSimpleModule() throws Exception { addModule("main"); PsiFile file = myFixture.addFileToProject("main/A.txt", "hello"); - Usage[] usages = new Usage[] {new UsageInfo2UsageAdapter(new UsageInfo(file))}; + Usage[] usages = {new UsageInfo2UsageAdapter(new UsageInfo(file))}; assertUsageViewStructureEquals(usages, "Usage (1 usage)\n" + " Non-code usages (1 usage)\n" + " main (1 usage)\n" + @@ -83,7 +80,7 @@ public class UsageViewTreeTest extends UsefulTestCase { public void testModuleWithQualifiedName() throws Exception { addModule("xxx.main"); PsiFile file = myFixture.addFileToProject("xxx.main/A.txt", "hello"); - Usage[] usages = new Usage[] {new UsageInfo2UsageAdapter(new UsageInfo(file))}; + Usage[] usages = {new UsageInfo2UsageAdapter(new UsageInfo(file))}; UsageViewSettings.getInstance().FLATTEN_MODULES = false; ModuleGroupTestsKt.runWithQualifiedModuleNamesEnabled(() -> { assertUsageViewStructureEquals(usages, "Usage (1 usage)\n" + diff --git a/platform/platform-tests/testSrc/com/intellij/util/AlarmTest.java b/platform/platform-tests/testSrc/com/intellij/util/AlarmTest.java index 83f423317f7c..c026c3ef1afe 100644 --- a/platform/platform-tests/testSrc/com/intellij/util/AlarmTest.java +++ b/platform/platform-tests/testSrc/com/intellij/util/AlarmTest.java @@ -16,21 +16,19 @@ package com.intellij.util; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.application.impl.LaterInvocator; -import com.intellij.testFramework.PlatformTestCase; -import com.intellij.util.ui.UIUtil; -import org.jetbrains.annotations.NotNull; + import com.intellij.openapi.application.ModalityState; + import com.intellij.openapi.application.impl.LaterInvocator; + import com.intellij.testFramework.PlatformTestCase; + import com.intellij.util.ui.UIUtil; + import org.jetbrains.annotations.NotNull; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; + import java.util.*; + import java.util.concurrent.ExecutionException; + import java.util.concurrent.Future; + import java.util.concurrent.TimeUnit; + import java.util.concurrent.TimeoutException; + import java.util.concurrent.atomic.AtomicInteger; + import java.util.stream.Collectors; public class AlarmTest extends PlatformTestCase { public void testTwoAddsWithZeroDelayMustExecuteSequentially() throws Exception { @@ -93,7 +91,12 @@ public class AlarmTest extends PlatformTestCase { UIUtil.dispatchAllInvocationEvents(); } Map after = Thread.getAllStackTraces(); - assertTrue("before: "+before.size()+"; after: "+after.size(), after.size() - before.size() < 10); + Map> diff = new HashMap<>(); + after.forEach((key, value) -> diff.put(key, Arrays.asList(value))); + before.keySet().forEach(diff::remove); + if (!(after.size() - before.size() < 10)) { + fail("before: "+before.size()+"; after: "+after.size()+"Diff:\n"+diff); + } } public void testManyAlarmsDoNotStartTooManyThreads() { diff --git a/platform/testFramework/src/com/intellij/testFramework/FileEditorManagerTestCase.java b/platform/testFramework/src/com/intellij/testFramework/FileEditorManagerTestCase.java index c890cfc486d7..c194b71ac749 100644 --- a/platform/testFramework/src/com/intellij/testFramework/FileEditorManagerTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/FileEditorManagerTestCase.java @@ -20,6 +20,7 @@ import com.intellij.openapi.components.ExpandMacroToPathMap; import com.intellij.openapi.components.impl.ComponentManagerImpl; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.ex.FileEditorProviderManager; +import com.intellij.openapi.fileEditor.impl.EditorHistoryManager; import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl; import com.intellij.openapi.fileEditor.impl.FileEditorProviderManagerImpl; import com.intellij.openapi.util.Disposer; @@ -73,6 +74,9 @@ public abstract class FileEditorManagerTestCase extends LightPlatformCodeInsight myOldDockContainers = null; ((ComponentManagerImpl)getProject()).registerComponentInstance(FileEditorManager.class, myOldManager); myManager.closeAllFiles(); + for (VirtualFile file : EditorHistoryManager.getInstance(getProject()).getFiles()) { + EditorHistoryManager.getInstance(getProject()).removeFile(file); + } ((FileEditorProviderManagerImpl)FileEditorProviderManager.getInstance()).clearSelectedProviders(); } finally { @@ -82,11 +86,6 @@ public abstract class FileEditorManagerTestCase extends LightPlatformCodeInsight } } - @Override - protected boolean isWriteActionRequired() { - return false; - } - protected VirtualFile getFile(String path) { String fullPath = getTestDataPath() + path; VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(fullPath); diff --git a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java index 457b231d5737..c4d2b6f71ef4 100644 --- a/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java +++ b/platform/testFramework/src/com/intellij/testFramework/PsiTestUtil.java @@ -15,6 +15,7 @@ */ package com.intellij.testFramework; +import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.application.RunResult; @@ -34,6 +35,7 @@ import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -247,6 +249,20 @@ public class PsiTestUtil { public static void addLibrary(Module module, String libName, String libPath, String... jarArr) { ModuleRootModificationUtil.updateModel(module, model -> addLibrary(module, model, libName, libPath, jarArr)); } + public static void addLibrary(@NotNull Disposable parent, Module module, String libName, String libPath, String... jarArr) { + Ref ref = new Ref<>(); + ModuleRootModificationUtil.updateModel(module, model -> ref.set(addLibrary(module, model, libName, libPath, jarArr))); + Disposer.register(parent, () -> { + Library library = ref.get(); + ModuleRootModificationUtil.updateModel(module, model -> model.removeOrderEntry(model.findLibraryOrderEntry(library))); + WriteCommandAction.runWriteCommandAction(null, ()-> { + LibraryTable table = ProjectLibraryTable.getInstance(module.getProject()); + LibraryTable.ModifiableModel model = table.getModifiableModel(); + model.removeLibrary(library); + model.commit(); + }); + }); + } public static void addProjectLibrary(Module module, String libName, List classesRootPaths) { List roots = ContainerUtil.map(classesRootPaths, path -> VirtualFileManager.getInstance().refreshAndFindFileByUrl(VfsUtil.getUrlForLibraryRoot(new File(path)))); @@ -263,6 +279,7 @@ public class PsiTestUtil { return result.get(); } + @NotNull private static Library addProjectLibrary(Module module, ModifiableRootModel model, String libName, @@ -302,11 +319,12 @@ public class PsiTestUtil { return result.getResultObject(); } - public static void addLibrary(Module module, - ModifiableRootModel model, - String libName, - String libPath, - String... jarArr) { + @NotNull + public static Library addLibrary(Module module, + ModifiableRootModel model, + String libName, + String libPath, + String... jarArr) { List classesRoots = new ArrayList<>(); for (String jar : jarArr) { if (!libPath.endsWith("/") && !jar.startsWith("/")) { @@ -323,7 +341,7 @@ public class PsiTestUtil { assert root != null : "Library root folder not found: " + path + "!/"; classesRoots.add(root); } - addProjectLibrary(module, model, libName, classesRoots, Collections.emptyList()); + return addProjectLibrary(module, model, libName, classesRoots, Collections.emptyList()); } public static void addLibrary(Module module, diff --git a/platform/testFramework/src/com/intellij/testFramework/inspections.kt b/platform/testFramework/src/com/intellij/testFramework/inspections.kt index ae3530e07273..0a9a360c706d 100644 --- a/platform/testFramework/src/com/intellij/testFramework/inspections.kt +++ b/platform/testFramework/src/com/intellij/testFramework/inspections.kt @@ -23,6 +23,8 @@ import com.intellij.codeInspection.ex.* import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.profile.codeInspection.BaseInspectionProfileManager +import com.intellij.profile.codeInspection.InspectionProfileManager import com.intellij.profile.codeInspection.InspectionProjectProfileManager import com.intellij.profile.codeInspection.ProjectInspectionProfileManager import com.intellij.testFramework.fixtures.impl.GlobalInspectionContextForTests @@ -35,21 +37,21 @@ import java.util.* fun configureInspections(tools: Array, project: Project, parentDisposable: Disposable): InspectionProfileImpl { - runInInitMode { - val profile = createSimple(UUID.randomUUID().toString(), project, tools.mapSmart { InspectionToolRegistrar.wrapTool(it) }) - val profileManager = ProjectInspectionProfileManager.getInstance(project) - // we don't restore old project profile because in tests it must be in any case null - app default profile - Disposer.register(parentDisposable, Disposable { - profileManager.deleteProfile(profile) - profileManager.setCurrentProfile(null) - clearAllToolsIn(BASE_PROFILE) - }) + val profile = InspectionProfileImpl(UUID.randomUUID().toString(), + { tools.mapSmart { InspectionToolRegistrar.wrapTool(it) } }, + InspectionProfileManager.getInstance() as BaseInspectionProfileManager) + val profileManager = ProjectInspectionProfileManager.getInstance(project) + // we don't restore old project profile because in tests it must be in any case null - app default profile + Disposer.register(parentDisposable, Disposable { + profileManager.deleteProfile(profile) + profileManager.setCurrentProfile(null) + clearAllToolsIn(BASE_PROFILE) + }) - profileManager.addProfile(profile) - profile.initInspectionTools(project) - profileManager.setCurrentProfile(profile) - return profile - } + profileManager.addProfile(profile) + profileManager.setCurrentProfile(profile) + enableInspectionTools(project, parentDisposable, *tools) + return profile } @JvmOverloads diff --git a/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java b/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java index 385274ff1b41..0fea8964ba97 100644 --- a/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java +++ b/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java @@ -303,6 +303,6 @@ public class UnsafeWeakList extends AbstractList { } private T throwNotRandomAccess() { - throw new IncorrectOperationException("UnsafeWeakList is not RandomAccess, use list.iterator() instead."); + throw new IncorrectOperationException("index/size-based operations in UnsafeWeakList are not supported because they don't make sense in the presence of weak references. Use list.iterator() (which retains elements to avoid sudden GC) instead."); } } diff --git a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java index 7c96cd7de1e8..a84bfe67f691 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java +++ b/plugins/coverage-common/src/com/intellij/coverage/CoverageDataManagerImpl.java @@ -137,7 +137,6 @@ public class CoverageDataManagerImpl extends CoverageDataManager { @Override public void readExternal(Element element) throws InvalidDataException { - //noinspection unchecked for (Element suiteElement : element.getChildren(SUITE)) { final CoverageRunner coverageRunner = BaseCoverageSuite.readRunnerAttribute(suiteElement); // skip unknown runners diff --git a/plugins/coverage/src/META-INF/plugin.xml b/plugins/coverage/src/META-INF/plugin.xml index 6b9f5961d53e..97c83b556bf5 100644 --- a/plugins/coverage/src/META-INF/plugin.xml +++ b/plugins/coverage/src/META-INF/plugin.xml @@ -26,6 +26,8 @@ + + diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java index 49be86c13f47..b36f7847dc83 100644 --- a/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageEngine.java @@ -654,8 +654,11 @@ public class JavaCoverageEngine extends CoverageEngine { @Override public boolean isGeneratedCode(Project project, String qualifiedName, Object lineData) { - PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName)); - return PackageAnnotator.isGeneratedDefaultConstructor(psiClass, ((LineData)lineData).getMethodSignature()); + if (JavaCoverageOptionsProvider.getInstance(project).ignoreEmptyPrivateConstructors()) { + PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName)); + return PackageAnnotator.isGeneratedDefaultConstructor(psiClass, ((LineData)lineData).getMethodSignature()); + } + return super.isGeneratedCode(project, qualifiedName, lineData); } @Override diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java new file mode 100644 index 000000000000..2af4314e3c82 --- /dev/null +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptions.java @@ -0,0 +1,84 @@ +/* + * 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.coverage; + +import com.intellij.ui.IdeBorderFactory; + +import javax.swing.*; +import java.awt.*; + +public class JavaCoverageOptions extends CoverageOptions { + + private final JavaCoverageOptionsProvider myCoverageOptionsProvider; + private JavaCoverageOptionsEditor myEditor; + + public JavaCoverageOptions(JavaCoverageOptionsProvider coverageOptionsProvider) { + myCoverageOptionsProvider = coverageOptionsProvider; + } + + @Override + public JComponent getComponent() { + myEditor = new JavaCoverageOptionsEditor(); + return myEditor.getComponent(); + } + + @Override + public boolean isModified() { + return myEditor.isModified(myCoverageOptionsProvider); + } + + @Override + public void apply() { + myEditor.apply(myCoverageOptionsProvider); + } + + @Override + public void reset() { + myEditor.reset(myCoverageOptionsProvider); + } + + @Override + public void disposeUIResources() { + myEditor = null; + } + + private static class JavaCoverageOptionsEditor { + + private JPanel myPanel = new JPanel(new BorderLayout(0, 10)); + private JCheckBox myCheckBox = new JCheckBox("Ignore empty private and implicit constructors", true); + + public JavaCoverageOptionsEditor() { + myPanel.setBorder(IdeBorderFactory.createTitledBorder("Java coverage")); + myPanel.add(myCheckBox, BorderLayout.NORTH); + } + + public JPanel getComponent() { + return myPanel; + } + + public boolean isModified(JavaCoverageOptionsProvider provider) { + return myCheckBox.isSelected() != provider.ignoreEmptyPrivateConstructors(); + } + + public void apply(JavaCoverageOptionsProvider provider) { + provider.setIgnoreEmptyPrivateConstructors(myCheckBox.isSelected()); + } + + public void reset(JavaCoverageOptionsProvider provider) { + myCheckBox.setSelected(provider.ignoreEmptyPrivateConstructors()); + } + } +} diff --git a/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java new file mode 100644 index 000000000000..22fb29900059 --- /dev/null +++ b/plugins/coverage/src/com/intellij/coverage/JavaCoverageOptionsProvider.java @@ -0,0 +1,60 @@ +/* + * 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.coverage; + +import com.intellij.openapi.components.*; +import com.intellij.openapi.project.Project; +import org.jetbrains.annotations.Nullable; + +@State( + name = "JavaCoverageOptionsProvider", + storages = { + @Storage(StoragePathMacros.WORKSPACE_FILE) + } +) +public class JavaCoverageOptionsProvider implements PersistentStateComponent { + private State myState = new State(); + + public static JavaCoverageOptionsProvider getInstance(Project project) { + return ServiceManager.getService(project, JavaCoverageOptionsProvider.class); + } + + + public void setIgnoreEmptyPrivateConstructors(boolean state) { + myState.myIgnoreEmptyPrivateConstructors = state; + } + + public boolean ignoreEmptyPrivateConstructors() { + return myState.myIgnoreEmptyPrivateConstructors; + } + + @Nullable + @Override + public JavaCoverageOptionsProvider.State getState() { + return myState; + } + + @Override + public void loadState(JavaCoverageOptionsProvider.State state) { + myState.myIgnoreEmptyPrivateConstructors = state.myIgnoreEmptyPrivateConstructors; + } + + + public static class State { + public boolean myIgnoreEmptyPrivateConstructors = true; + } + +} diff --git a/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java b/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java index 2f90f21a4db0..4f450db59e0d 100644 --- a/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java +++ b/plugins/coverage/src/com/intellij/coverage/PackageAnnotator.java @@ -23,6 +23,7 @@ import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -37,6 +38,7 @@ import com.intellij.rt.coverage.data.LineData; import com.intellij.rt.coverage.data.ProjectData; import com.intellij.util.containers.HashMap; import com.intellij.util.containers.SmartHashSet; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes; import org.jetbrains.jps.model.java.JavaSourceRootType; @@ -57,12 +59,14 @@ public class PackageAnnotator { private final Project myProject; private final PsiManager myManager; private final CoverageDataManager myCoverageManager; + private final boolean myIgnoreEmptyPrivateConstructors; public PackageAnnotator(final PsiPackage aPackage) { myPackage = aPackage; myProject = myPackage.getProject(); myManager = PsiManager.getInstance(myProject); myCoverageManager = CoverageDataManager.getInstance(myProject); + myIgnoreEmptyPrivateConstructors = JavaCoverageOptionsProvider.getInstance(myProject).ignoreEmptyPrivateConstructors(); } public interface Annotator { @@ -455,7 +459,7 @@ public class PackageAnnotator { touchedClass = true; } - if (isGeneratedDefaultConstructor(psiClass, (String)nameAndSig)) { + if (myIgnoreEmptyPrivateConstructors && isGeneratedDefaultConstructor(psiClass, (String)nameAndSig)) { continue; } @@ -505,16 +509,16 @@ public class PackageAnnotator { * in the bytecode, so we need to look at the PSI to see if the class defines such a constructor. */ public static boolean isGeneratedDefaultConstructor(@Nullable final PsiClass aClass, String nameAndSig) { + if (aClass == null) { + return false; + } if (DEFAULT_CONSTRUCTOR_NAME_SIGNATURE.equals(nameAndSig)) { return hasGeneratedOrEmptyPrivateConstructor(aClass); } return false; } - private static boolean hasGeneratedOrEmptyPrivateConstructor(@Nullable final PsiClass aClass) { - if (aClass == null) { - return false; - } + private static boolean hasGeneratedOrEmptyPrivateConstructor(@NotNull final PsiClass aClass) { return ReadAction.compute(() -> { PsiMethod[] constructors = aClass.getConstructors(); if (constructors.length == 1 && constructors[0].hasModifierProperty(PsiModifier.PRIVATE)) { @@ -563,6 +567,6 @@ public class PackageAnnotator { if (coverageSuite == null) return false; return SourceLineCounterUtil .collectNonCoveredClassInfo(classCoverageInfo, packageCoverageInfo, content, coverageSuite.isTracingEnabled(), - psiClass); + myIgnoreEmptyPrivateConstructors ? description -> !isGeneratedDefaultConstructor(psiClass, description) : Condition.TRUE); } } diff --git a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java index e5e8851fbae7..b3be240bcdaf 100644 --- a/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java +++ b/plugins/coverage/src/com/intellij/coverage/SourceLineCounterUtil.java @@ -17,6 +17,7 @@ package com.intellij.coverage; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiManager; import com.intellij.psi.util.ClassUtil; @@ -29,11 +30,10 @@ import java.util.List; import java.util.Set; public class SourceLineCounterUtil { - public static boolean collectNonCoveredClassInfo(final PackageAnnotator.ClassCoverageInfo classCoverageInfo, - final PackageAnnotator.PackageCoverageInfo packageCoverageInfo, - byte[] content, + public static boolean collectNonCoveredClassInfo(final PackageAnnotator.ClassCoverageInfo classCoverageInfo, + final PackageAnnotator.PackageCoverageInfo packageCoverageInfo, byte[] content, final boolean excludeLines, - final PsiClass psiClass) { + final Condition includeDescriptionCondition) { if (content == null) return false; ClassReader reader = new ClassReader(content, 0, content.length); @@ -42,13 +42,13 @@ public class SourceLineCounterUtil { Set descriptions = new HashSet<>(); TIntObjectHashMap lines = counter.getSourceLines(); lines.forEachEntry((line, description) -> { - if (!PackageAnnotator.isGeneratedDefaultConstructor(psiClass, (String)description)) { - classCoverageInfo.totalLineCount ++; - packageCoverageInfo.totalLineCount ++; - descriptions.add(description); - } - return true; - }); + if (includeDescriptionCondition.value((String)description)) { + classCoverageInfo.totalLineCount++; + packageCoverageInfo.totalLineCount++; + descriptions.add(description); + } + return true; + }); classCoverageInfo.totalMethodCount += descriptions.size(); packageCoverageInfo.totalMethodCount += descriptions.size(); @@ -68,10 +68,16 @@ public class SourceLineCounterUtil { reader.accept(collector, 0); String qualifiedName = reader.getClassName(); - PsiClass psiClass = ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName)); + boolean ignoreEmptyPrivateConstructors = JavaCoverageOptionsProvider.getInstance(project).ignoreEmptyPrivateConstructors(); + PsiClass psiClass = ignoreEmptyPrivateConstructors + ? ReadAction.compute(() -> ClassUtil.findPsiClassByJVMName(PsiManager.getInstance(project), qualifiedName)) + : null; + Condition includeDescriptionCondition = ignoreEmptyPrivateConstructors + ? description -> !PackageAnnotator.isGeneratedDefaultConstructor(psiClass, description) + : Condition.TRUE; TIntObjectHashMap lines = collector.getSourceLines(); lines.forEachEntry((line, description) -> { - if (!PackageAnnotator.isGeneratedDefaultConstructor(psiClass, (String)description)) { + if (includeDescriptionCondition.value((String)description)) { line--; uncoveredLines.add(line); } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java index 450f5d0abffe..458a88e632a4 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/utils/ControlFlowUtils.java @@ -415,20 +415,10 @@ public class ControlFlowUtils { } private static boolean statementIsLastInBlock(@NotNull GrStatementOwner block, @NotNull GrStatement statement) { - final GrStatement[] statements = block.getStatements(); - for (int i = statements.length - 1; i >= 0; i--) { - final GrStatement childStatement = statements[i]; - if (statement.equals(childStatement)) { - return true; - } - if (!(childStatement instanceof GrReturnStatement)) { - return false; - } - } - return false; + GrStatement lastStatement = ArrayUtil.getLastElement(block.getStatements()); + return statement == lastStatement; } - @NotNull public static List collectReturns(@Nullable PsiElement element) { return collectReturns(element, element instanceof GrCodeBlock || element instanceof GroovyFile); diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index 5a7a0a919822..b23789355b81 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -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. @@ -18,14 +18,11 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; import com.intellij.openapi.util.TextRange; -import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.util.InheritanceUtil; import com.intellij.util.ArrayUtil; -import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.NullableFunction; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,18 +35,16 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrArrayD import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousClassDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.types.GrBuiltInTypeElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnonymousClassType; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrClassReferenceType; import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrCallExpressionImpl; import org.jetbrains.plugins.groovy.lang.psi.util.GrInnerClassConstructorUtil; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.typing.GrTypeCalculator; import java.util.ArrayList; import java.util.List; @@ -59,33 +54,6 @@ import java.util.List; */ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewExpression { - private static final Function MY_TYPE_CALCULATOR = - (NullableFunction)newExpression -> { - final GrAnonymousClassDefinition anonymous = newExpression.getAnonymousClassDefinition(); - if (anonymous != null) { - return new GrAnonymousClassType(LanguageLevel.JDK_1_5, anonymous.getResolveScope(), - JavaPsiFacade.getInstance(newExpression.getProject()), anonymous); - } - PsiType type = null; - GrCodeReferenceElement refElement = newExpression.getReferenceElement(); - if (refElement != null) { - type = new GrClassReferenceType(refElement); - } - else { - GrBuiltInTypeElement builtin = newExpression.findChildByClass(GrBuiltInTypeElement.class); - if (builtin != null) type = builtin.getType(); - } - - if (type != null) { - for (int i = 0; i < newExpression.getArrayCount(); i++) { - type = type.createArrayType(); - } - return type; - } - - return null; - }; - private static final ResolveCache.PolyVariantResolver RESOLVER = new ResolveCache.PolyVariantResolver() { @NotNull @Override @@ -111,7 +79,7 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx @Override public PsiType getType() { - return TypeInferenceHelper.getCurrentContext().getExpressionType(this, MY_TYPE_CALCULATOR); + return TypeInferenceHelper.getCurrentContext().getExpressionType(this, GrTypeCalculator::getTypeFromCalculators); } @Override diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrDefaultMethodComparator.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrDefaultMethodComparator.java index 138f10ea9b10..ba676a2b1bb3 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrDefaultMethodComparator.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/GrDefaultMethodComparator.java @@ -69,6 +69,11 @@ public class GrDefaultMethodComparator extends GrMethodComparator { PsiParameter[] params1 = method1.getParameterList().getParameters(); PsiParameter[] params2 = method2.getParameterList().getParameters(); + + if (argTypes != null && argTypes.length == 0) { + if (params2.length == 1 && params2[0].getType() instanceof PsiArrayType) return true; + } + if (argTypes == null && params1.length != params2.length) return false; if (params1.length < params2.length) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultNewExpressionTypeCalculator.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultNewExpressionTypeCalculator.kt new file mode 100644 index 000000000000..8d308117e97d --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/typing/DefaultNewExpressionTypeCalculator.kt @@ -0,0 +1,52 @@ +/* + * 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.typing + +import com.intellij.pom.java.LanguageLevel +import com.intellij.psi.JavaPsiFacade +import com.intellij.psi.PsiType +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrBuiltInTypeElement +import org.jetbrains.plugins.groovy.lang.psi.impl.GrAnonymousClassType +import org.jetbrains.plugins.groovy.lang.psi.impl.GrClassReferenceType + +class DefaultNewExpressionTypeCalculator : GrTypeCalculator { + + override fun getType(expression: GrNewExpression): PsiType? { + return getAnonymousType(expression) ?: + getRegularType(expression) + } + + private fun getAnonymousType(expression: GrNewExpression): PsiType? { + val anonymous = expression.anonymousClassDefinition ?: return null + return GrAnonymousClassType( + LanguageLevel.JDK_1_5, + anonymous.resolveScope, + JavaPsiFacade.getInstance(expression.project), + anonymous + ) + } + + private fun getRegularType(expression: GrNewExpression): PsiType? { + var type: PsiType = expression.referenceElement?.let { GrClassReferenceType(it) } ?: + (expression.typeElement as? GrBuiltInTypeElement)?.type ?: + return null + repeat(expression.arrayCount) { + type = type.createArrayType() + } + return type + } +} \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 174979088681..2afc47c51a00 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -170,6 +170,8 @@ + continue + } else { + return + } +} ''', GroovyUnnecessaryContinueInspection) } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy index d3489f52e201..296b65190619 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/ResolveMethodTest.groovy @@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.lang.resolve import com.intellij.psi.* import com.intellij.psi.util.PropertyUtil import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression @@ -2292,4 +2293,19 @@ new SomeClass().size() ''', GrMethodImpl } + + void 'test prefer varargs in no-arg call'() { + def file = fixture.configureByText('_.groovy', '''\ +class A { + A(String... a) { println "varargs" } + A(A a) { println "single" } +} + +new A() +''') as GroovyFile + def expression = file.statements.last() as GrNewExpression + def resolved = expression.resolveMethod() + assert resolved instanceof GrMethod + assert resolved.isVarArgs() + } } diff --git a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt index c44752e292d2..cf605238dd38 100644 --- a/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt +++ b/plugins/java-decompiler/plugin/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.kt @@ -26,6 +26,8 @@ import com.intellij.ide.structureView.newStructureView.StructureViewComponent import com.intellij.ide.util.treeView.AbstractTreeNode import com.intellij.openapi.application.PluginPathManager import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx +import com.intellij.openapi.fileEditor.impl.EditorHistoryManager import com.intellij.openapi.fileTypes.StdFileTypes import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil @@ -45,6 +47,14 @@ class IdeaDecompilerTest : LightCodeInsightFixtureTestCase() { myFixture.testDataPath = "${PluginPathManager.getPluginHomePath("java-decompiler")}/plugin/testData" } + override fun tearDown() { + FileEditorManagerEx.getInstanceEx(project).closeAllFiles() + for (file in EditorHistoryManager.getInstance(project).files) { + EditorHistoryManager.getInstance(project).removeFile(file) + } + super.tearDown() + } + fun testSimple() { val file = getTestFile("${PlatformTestUtil.getRtJarPath()}!/java/lang/String.class") val decompiled = IdeaDecompiler().getText(file).toString() diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/RegExResponseHandler.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/RegExResponseHandler.java index c1147bba89e2..4f0bfaa48308 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/RegExResponseHandler.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/generic/RegExResponseHandler.java @@ -15,15 +15,11 @@ */ package com.intellij.tasks.generic; -import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.DocumentListener; import com.intellij.openapi.project.Project; -import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.XmlElementFactory; -import com.intellij.psi.xml.XmlTag; import com.intellij.tasks.Task; import com.intellij.ui.EditorTextField; import com.intellij.ui.LanguageTextField; @@ -31,7 +27,6 @@ import com.intellij.ui.components.JBScrollPane; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.FormBuilder; import com.intellij.util.xmlb.annotations.Tag; -import com.intellij.xml.util.XmlUtil; import org.intellij.lang.regexp.RegExpLanguage; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -117,14 +112,6 @@ public final class RegExResponseHandler extends ResponseHandler { for (int i = 0; i < max && matcher.find(); i++) { String id = matcher.group(placeholders.indexOf(ID_PLACEHOLDER) + 1); String summary = matcher.group(placeholders.indexOf(SUMMARY_PLACEHOLDER) + 1); - // temporary workaround to make AssemblaIntegrationTestPass - final String finalSummary = summary; - summary = ReadAction.compute(() -> { - XmlElementFactory factory = XmlElementFactory.getInstance(ProjectManager.getInstance().getDefaultProject()); - XmlTag text = factory.createTagFromText("" + finalSummary + ""); - String trimmedText = text.getValue().getTrimmedText(); - return XmlUtil.decode(trimmedText); - }); tasks.add(new GenericTask(id, summary, myRepository)); } return tasks.toArray(new Task[tasks.size()]); diff --git a/python/educational-core/resources/META-INF/plugin.xml b/python/educational-core/resources/META-INF/plugin.xml index 83ddbb6ed724..6b169c7829c8 100644 --- a/python/educational-core/resources/META-INF/plugin.xml +++ b/python/educational-core/resources/META-INF/plugin.xml @@ -157,8 +157,6 @@ - diff --git a/python/resources/icons/com/jetbrains/python/condaenv@2x_dark.png b/python/resources/icons/com/jetbrains/python/condaenv@2x_dark.png index 5ed486884ef0..d3d752947012 100644 Binary files a/python/resources/icons/com/jetbrains/python/condaenv@2x_dark.png and b/python/resources/icons/com/jetbrains/python/condaenv@2x_dark.png differ diff --git a/python/src/META-INF/python-core-common.xml b/python/src/META-INF/python-core-common.xml index cb744f18e557..2b48df70978a 100644 --- a/python/src/META-INF/python-core-common.xml +++ b/python/src/META-INF/python-core-common.xml @@ -105,6 +105,9 @@ + + x()"); + " C.ba()"); assertNotNull(suggested); assertContainsElements(suggested, "baz"); @@ -1081,7 +1082,7 @@ public class PythonCompletionTest extends PyTestCase { "@a_m(M)\n" + "class C(object):\n" + " def foo(self):\n" + - " C.bax()"); + " C.ba()"); assertNotNull(suggested); assertContainsElements(suggested, "baz"); diff --git a/python/testSrc/com/jetbrains/python/pyi/PyiInspectionsTest.java b/python/testSrc/com/jetbrains/python/pyi/PyiInspectionsTest.java index 5b330270b4d0..99d444c0be78 100644 --- a/python/testSrc/com/jetbrains/python/pyi/PyiInspectionsTest.java +++ b/python/testSrc/com/jetbrains/python/pyi/PyiInspectionsTest.java @@ -16,6 +16,8 @@ package com.jetbrains.python.pyi; import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; import com.jetbrains.python.fixtures.PyTestCase; @@ -27,6 +29,18 @@ import org.jetbrains.annotations.NotNull; * @author vlan */ public class PyiInspectionsTest extends PyTestCase { + + private Disposable myRootsDisposable; + + @Override + protected void tearDown() throws Exception { + if (myRootsDisposable != null) { + Disposer.dispose(myRootsDisposable); + myRootsDisposable = null; + } + super.tearDown(); + } + private void doTestByExtension(@NotNull Class inspectionClass, @NotNull String extension) { doTestByFileName(inspectionClass, getTestName(false) + extension); } @@ -106,7 +120,7 @@ public class PyiInspectionsTest extends PyTestCase { } public void testPyiRelativeImports() { - PyiTypeTest.addPyiStubsToContentRoot(myFixture); + myRootsDisposable = PyiTypeTest.addPyiStubsToContentRoot(myFixture); doTestByFileName(PyUnresolvedReferencesInspection.class, "package_with_stub_in_path/a.pyi"); } } diff --git a/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java b/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java index ce6e92eb9cc9..6a8b81cc6dc7 100644 --- a/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java +++ b/python/testSrc/com/jetbrains/python/pyi/PyiTypeTest.java @@ -15,8 +15,11 @@ */ package com.jetbrains.python.pyi; +import com.intellij.openapi.Disposable; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ContentEntry; import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.StandardFileSystems; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; @@ -35,12 +38,23 @@ import org.jetbrains.annotations.Nullable; * @author vlan */ public class PyiTypeTest extends PyTestCase { - public static void addPyiStubsToContentRoot(CodeInsightTestFixture fixture) { + + private Disposable myDisposable; + + // return Disposable which undoes configuration + public static Disposable addPyiStubsToContentRoot(CodeInsightTestFixture fixture) { final String path = fixture.getTestDataPath() + "/pyi/pyiStubs"; final VirtualFile file = StandardFileSystems.local().refreshAndFindFileByPath(path); assertNotNull(file); file.refresh(false, true); ModuleRootModificationUtil.addContentRoot(fixture.getModule(), path); + return ()->ModuleRootModificationUtil.updateModel(fixture.getModule(), model -> { + for (ContentEntry entry : model.getContentEntries()) { + if (file.equals(entry.getFile())) { + model.removeContentEntry(entry); + } + } + }); } @Nullable @@ -57,6 +71,10 @@ public class PyiTypeTest extends PyTestCase { @Override public void tearDown() throws Exception { + if (myDisposable != null) { + Disposer.dispose(myDisposable); + myDisposable = null; + } setLanguageLevel(null); super.tearDown(); } @@ -97,7 +115,7 @@ public class PyiTypeTest extends PyTestCase { } public void testPyiOnPythonPath() { - addPyiStubsToContentRoot(myFixture); + myDisposable = addPyiStubsToContentRoot(myFixture); doTest("int"); } diff --git a/tools/index-tools/src/org/jetbrains/index/stubs/StubsGenerator.kt b/tools/index-tools/src/org/jetbrains/index/stubs/StubsGenerator.kt index 04cc88379ada..d47c6ea2248f 100644 --- a/tools/index-tools/src/org/jetbrains/index/stubs/StubsGenerator.kt +++ b/tools/index-tools/src/org/jetbrains/index/stubs/StubsGenerator.kt @@ -155,7 +155,7 @@ fun mergeStubs(paths: List, stubsFilePath: String, projectPath: String, for (path in paths) { println("Reading stubs from $path") var count = 0 - val fromStorageFile = File(stubsFilePath + ".input") + val fromStorageFile = File(path + ".input") val fromStorage = PersistentHashMap(fromStorageFile, HashCodeDescriptor.instance, stubExternalizer)