From 8d41d02f0969ccddccd479c64d2a7474dcb420f1 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 23 Nov 2016 10:50:03 +0100 Subject: [PATCH 01/37] initialize UndoManagerImpl earlier (refix IDEA-163699, IDEA-CR-16066) --- .../execution/impl/ConsoleViewImpl.java | 11 +++--- .../openapi/command/impl/UndoManagerImpl.java | 34 ++++--------------- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java index f3cd34b1f9e2..418c73b0d6e7 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java @@ -66,7 +66,6 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; -import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -420,13 +419,11 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo } private void addFlushRequest(@NotNull MyFlushRunnable flushRunnable, final int millis) { - StartupManager.getInstance(myProject).runWhenProjectIsInitialized(() -> { - synchronized (myCurrentRequests) { - if (!myFlushAlarm.isDisposed() && myCurrentRequests.add(flushRunnable)) { - myFlushAlarm.addRequest(flushRunnable, millis, getStateForUpdate()); - } + synchronized (myCurrentRequests) { + if (!myFlushAlarm.isDisposed() && myCurrentRequests.add(flushRunnable)) { + myFlushAlarm.addRequest(flushRunnable, millis, getStateForUpdate()); } - }); + } } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java index 230e9cbb62ec..a936a9e3e98d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/command/impl/UndoManagerImpl.java @@ -36,7 +36,6 @@ import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectEx; -import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.EmptyRunnable; @@ -66,7 +65,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap @Nullable private final ProjectEx myProject; private final CommandProcessor myCommandProcessor; - private final StartupManager myStartupManager; private UndoProvider[] myUndoProviders; private CurrentEditorProvider myEditorProvider; @@ -101,29 +99,21 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap return Registry.intValue("undo.documentUndoLimit"); } - public UndoManagerImpl(Application application, CommandProcessor commandProcessor) { - this(application, null, commandProcessor, null); + public UndoManagerImpl(CommandProcessor commandProcessor) { + this(null, commandProcessor); } - public UndoManagerImpl(Application application, - @Nullable ProjectEx project, - CommandProcessor commandProcessor, - StartupManager startupManager) { + public UndoManagerImpl(@Nullable ProjectEx project, CommandProcessor commandProcessor) { myProject = project; myCommandProcessor = commandProcessor; - myStartupManager = startupManager; - init(application); + if (myProject == null || !myProject.isDefault()) { + runStartupActivity(); + } myMerger = new CommandMerger(this); } - private void init(@NotNull Application application) { - if (myProject == null || application.isUnitTestMode() && !myProject.isDefault()) { - initialize(); - } - } - @Override @NotNull public String getComponentName() { @@ -141,9 +131,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap @Override public void projectOpened() { - if (!ApplicationManager.getApplication().isUnitTestMode()) { - initialize(); - } } @Override @@ -158,15 +145,6 @@ public class UndoManagerImpl extends UndoManager implements ProjectComponent, Ap public void dispose() { } - private void initialize() { - if (myProject == null) { - runStartupActivity(); - } - else { - myStartupManager.registerStartupActivity(this::runStartupActivity); - } - } - private void runStartupActivity() { myEditorProvider = new FocusBasedCurrentEditorProvider(); CommandListener commandListener = new CommandAdapter() { From f1092d42fb1904d0f36586279f9e6b01511f23d5 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 23 Nov 2016 11:11:35 +0100 Subject: [PATCH 02/37] IDEA-164257 Declarations visible from a Java file shouldn't include current package's subpackages --- .../intellij/psi/impl/JavaPsiFacadeImpl.java | 40 ++++++++--------- .../psi/impl/source/PsiJavaFileBaseImpl.java | 40 ++++++++++++----- .../resolve/class/NoSubpackagesAccess.java | 8 ++++ .../psi/resolve/ResolveClassTest.java | 44 +++++++++++++++++++ 4 files changed, 100 insertions(+), 32 deletions(-) create mode 100644 java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java index d450c1fb02b5..9166725178d7 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/JavaPsiFacadeImpl.java @@ -16,6 +16,9 @@ package com.intellij.psi.impl; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.ExtensionPoint; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.SimpleSmartExtensionPoint; import com.intellij.openapi.progress.ProgressIndicatorProvider; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; @@ -48,7 +51,7 @@ import java.util.concurrent.ConcurrentMap; public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { private static final Logger LOG = Logger.getInstance(JavaPsiFacadeImpl.class); - private final PsiElementFinder[] myElementFinders; + private final SimpleSmartExtensionPoint myElementFinders; private final PsiConstantEvaluationHelper myConstantEvaluationHelper; private final ConcurrentMap myPackageCache = ContainerUtil.createConcurrentSoftValueMap(); private final ConcurrentMap> myClassCache = ContainerUtil.createConcurrentWeakKeySoftValueMap(); @@ -82,7 +85,13 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } DummyHolderFactory.setFactory(new JavaDummyHolderFactory()); - myElementFinders = calcFinders(); + myElementFinders = new SimpleSmartExtensionPoint(Collections.emptyList()) { + @NotNull + @Override + protected ExtensionPoint getExtensionPoint() { + return Extensions.getArea(myProject).getExtensionPoint(PsiElementFinder.EP_NAME); + } + }; } @Override @@ -115,7 +124,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return null; } - PsiElementFinder[] finders = finders(); + List finders = finders(); Condition classesFilter = getFilterFromFinders(scope, finders); for (PsiElementFinder finder : finders) { @@ -156,7 +165,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return findClassesInDumbMode(qualifiedName, scope); } - PsiElementFinder[] finders = finders(); + List finders = finders(); Condition classesFilter = getFilterFromFinders(scope, finders); List result = null; @@ -171,7 +180,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return result == null || result.isEmpty() ? PsiClass.EMPTY_ARRAY : result.toArray(new PsiClass[result.size()]); } - private static Condition getFilterFromFinders(@NotNull GlobalSearchScope scope, @NotNull PsiElementFinder[] finders) { + private static Condition getFilterFromFinders(@NotNull GlobalSearchScope scope, @NotNull List finders) { Condition filter = null; for (PsiElementFinder finder : finders) { Condition finderFilter = finder.getClassesFilter(scope); @@ -187,13 +196,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { return dumbService.isDumb() && dumbService.isAlternativeResolveEnabled(); } - private PsiElementFinder[] finders() { - return myElementFinders; - } - - @NotNull - protected PsiElementFinder[] calcFinders() { - return myProject.getExtensions(PsiElementFinder.EP_NAME); + private List finders() { + return myElementFinders.getExtensions(); } @Override @@ -220,14 +224,8 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { } @NotNull - private PsiElementFinder[] filteredFinders() { - DumbService dumbService = DumbService.getInstance(getProject()); - PsiElementFinder[] finders = finders(); - if (dumbService.isDumb()) { - List list = dumbService.filterByDumbAwareness(finders); - finders = list.toArray(new PsiElementFinder[list.size()]); - } - return finders; + private List filteredFinders() { + return DumbService.getInstance(getProject()).filterByDumbAwareness(finders()); } @Override @@ -259,7 +257,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx { @NotNull public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) { - PsiElementFinder[] finders = filteredFinders(); + List finders = filteredFinders(); Condition classesFilter = getFilterFromFinders(scope, finders); List result = null; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java index e3fc076fab1c..35ec88e550aa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaFileBaseImpl.java @@ -35,10 +35,7 @@ import com.intellij.psi.impl.java.stubs.PsiJavaFileStub; import com.intellij.psi.impl.source.resolve.ClassResolverProcessor; import com.intellij.psi.impl.source.resolve.SymbolCollectingProcessor; import com.intellij.psi.impl.source.tree.JavaElementType; -import com.intellij.psi.scope.ElementClassHint; -import com.intellij.psi.scope.JavaScopeProcessorEvent; -import com.intellij.psi.scope.NameHint; -import com.intellij.psi.scope.PsiScopeProcessor; +import com.intellij.psi.scope.*; import com.intellij.psi.stubs.StubElement; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; @@ -348,11 +345,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava // check in current package final PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(getPackageName()); - if (aPackage != null) { - if (!aPackage.processDeclarations(processor, state, null, place)) { - return false; - } - } + if (aPackage != null && !processPackageDeclarations(processor, state, place, aPackage)) return false; // on-demand processing for (PsiImportStatement statement : importStatements) { @@ -414,6 +407,31 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava return true; } + private static boolean processPackageDeclarations(PsiScopeProcessor processor, + @NotNull ResolveState state, + PsiElement place, + @NotNull PsiPackage aPackage) { + if (!aPackage.getQualifiedName().isEmpty()) { + processor = new DelegatingScopeProcessor(processor) { + @Nullable + @Override + public T getHint(@NotNull Key hintKey) { + if (hintKey == ElementClassHint.KEY) { + //noinspection unchecked + return (T)new ElementClassHint() { + @Override + public boolean shouldProcess(DeclarationKind kind) { + return kind == DeclarationKind.CLASS; + } + }; + } + return super.getHint(hintKey); + } + }; + } + return aPackage.processDeclarations(processor, state, null, place); + } + @NotNull private static PsiSubstitutor createRawSubstitutor(PsiClass containingClass) { return JavaPsiFacade.getElementFactory(containingClass.getProject()).createRawSubstitutor(containingClass); @@ -421,7 +439,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava private static boolean processOnDemandTarget(PsiElement target, PsiScopeProcessor processor, ResolveState substitutor, PsiElement place) { if (target instanceof PsiPackage) { - if (!target.processDeclarations(processor, substitutor, null, place)) { + if (!processPackageDeclarations(processor, substitutor, place, (PsiPackage)target)) { return false; } } @@ -436,7 +454,7 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava } } else { - LOG.assertTrue(false); + LOG.error(target); } return true; } diff --git a/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java b/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java new file mode 100644 index 000000000000..d8d09972b64a --- /dev/null +++ b/java/java-tests/testData/psi/resolve/class/NoSubpackagesAccess.java @@ -0,0 +1,8 @@ +import javax.*; + +class Foo { + { + foo.bar.goo d; + } +} + diff --git a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java index 81ef00ffdbbb..36637e540dbd 100644 --- a/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/resolve/ResolveClassTest.java @@ -17,6 +17,7 @@ package com.intellij.psi.resolve; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; @@ -31,8 +32,14 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.ResolveTestCase; +import com.intellij.util.containers.ContainerUtil; +import org.easymock.IArgumentMatcher; +import java.lang.reflect.Method; import java.util.Collections; +import java.util.Set; + +import static org.easymock.EasyMock.*; public class ResolveClassTest extends ResolveTestCase { public void testFQName() throws Exception { @@ -268,4 +275,41 @@ public class ResolveClassTest extends ResolveTestCase { private PsiReference configure() throws Exception { return configureByFile("class/" + getTestName(false) + ".java"); } + + public void testNoSubpackagesAccess() throws Exception { + PsiElementFinder mock = createMockFinder(); + PlatformTestUtil.registerExtension(Extensions.getArea(getProject()), PsiElementFinder.EP_NAME, mock, getTestRootDisposable()); + + PsiReference reference = configure(); + assertNull(reference.resolve()); + reference.getVariants(); + + verify(mock); + } + + private static PsiElementFinder createMockFinder() { + Set ignoredMethods = ContainerUtil.newHashSet("getClassesFilter", "processPackageDirectories", "getClasses"); + Method[] methods = ContainerUtil.findAllAsArray(PsiElementFinder.class.getDeclaredMethods(), m -> !ignoredMethods.contains(m.getName())); + PsiElementFinder mock = createMockBuilder(PsiElementFinder.class).addMockedMethods(methods).createMock(); + expect(mock.findClasses(anyObject(), anyObject())).andReturn(PsiClass.EMPTY_ARRAY).anyTimes(); + expect(mock.findPackage(eq("foo"))).andReturn(null); + expect(mock.getSubPackages(rootPackage(), anyObject())).andReturn(PsiPackage.EMPTY_ARRAY); + replay(mock); + return mock; + } + + private static PsiPackage rootPackage() { + reportMatcher(new IArgumentMatcher() { + @Override + public boolean matches(Object argument) { + return "PsiPackage:".equals(String.valueOf(argument)); + } + + @Override + public void appendTo(StringBuffer buffer) { + buffer.append("PsiPackage:"); + } + }); + return null; + } } From e5e55e3479aef213c5ded0b0c5a9d208d1cd353e Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 23 Nov 2016 11:18:12 +0100 Subject: [PATCH 03/37] ProjectStoreBase.isProjectFile: check that a file could be project config file before asking for its path --- platform/configuration-store-impl/src/ProjectStoreImpl.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/configuration-store-impl/src/ProjectStoreImpl.kt b/platform/configuration-store-impl/src/ProjectStoreImpl.kt index 227f124482b9..0248817ce07e 100644 --- a/platform/configuration-store-impl/src/ProjectStoreImpl.kt +++ b/platform/configuration-store-impl/src/ProjectStoreImpl.kt @@ -31,6 +31,7 @@ import com.intellij.openapi.diagnostic.catchAndLog import com.intellij.openapi.module.Module import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectCoreUtil import com.intellij.openapi.project.impl.ProjectImpl import com.intellij.openapi.project.impl.ProjectManagerImpl.UnableToSaveProjectNotification import com.intellij.openapi.project.impl.ProjectStoreClassProvider @@ -255,7 +256,7 @@ abstract class ProjectStoreBase(override final val project: ProjectImpl) : Compo } override fun isProjectFile(file: VirtualFile): Boolean { - if (!file.isInLocalFileSystem) { + if (!file.isInLocalFileSystem || !ProjectCoreUtil.isProjectOrWorkspaceFile(file, file.fileType)) { return false } From 4ec11eb771ccc89ace0d2b99e9efe2b0738ea064 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Wed, 23 Nov 2016 16:06:35 +0700 Subject: [PATCH 04/37] ActionHint understands ProblemHighlightType now in addition to simple true/false --- .../daemon/quickFix/ActionHint.java | 49 ++++++++++++++----- .../codeInspection/ex/QuickFixWrapper.java | 9 +++- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java index 425a6558ba4e..897d79453bd4 100644 --- a/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java +++ b/java/testFramework/src/com/intellij/codeInsight/daemon/quickFix/ActionHint.java @@ -16,6 +16,8 @@ package com.intellij.codeInsight.daemon.quickFix; import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.codeInspection.ex.QuickFixWrapper; import com.intellij.lang.Commenter; import com.intellij.lang.LanguageCommenters; import com.intellij.lang.injection.InjectedLanguageManager; @@ -40,10 +42,12 @@ import static org.junit.Assert.fail; public class ActionHint { final String myExpectedText; final boolean myShouldPresent; + final ProblemHighlightType myHighlightType; - private ActionHint(String expectedText, boolean shouldPresent) { + private ActionHint(String expectedText, boolean shouldPresent, ProblemHighlightType severity) { myExpectedText = expectedText; myShouldPresent = shouldPresent; + myHighlightType = severity; } /** @@ -79,11 +83,25 @@ public class ActionHint { @Nullable public IntentionAction findAndCheck(Collection actions, Supplier infoSupplier) { IntentionAction result = actions.stream().filter(t -> t.getText().equals(myExpectedText)).findFirst().orElse(null); - if(result == null && myShouldPresent) { - fail("Action with text '" + myExpectedText + "' not found\nAvailable actions: " + - actions.stream().map(IntentionAction::getText).collect(Collectors.joining(", ", "[", "]\n")) + - infoSupplier.get()); - } else if(result != null && !myShouldPresent) { + if(myShouldPresent) { + if(result == null) { + fail("Action with text '" + myExpectedText + "' not found\nAvailable actions: " + + actions.stream().map(IntentionAction::getText).collect(Collectors.joining(", ", "[", "]\n")) + + infoSupplier.get()); + } else if(myHighlightType != null) { + if(!(result instanceof QuickFixWrapper)) { + fail("Action with text '" + myExpectedText + "' is not a LocalQuickFix, but " + result.getClass().getName() + + "\nExpected LocalQuickFix with ProblemHighlightType=" + myHighlightType + "\n" + + infoSupplier.get()); + } + ProblemHighlightType actualType = ((QuickFixWrapper)result).getHighlightType(); + if(actualType != myHighlightType) { + fail("Action with text '" + myExpectedText + "' has wrong ProblemHighlightType.\nExpected: " + myHighlightType + + "\nActual: " + actualType + "\n" + infoSupplier.get()); + } + } + } + else if(result != null) { fail("Action with text '" + myExpectedText + "' is present, but should not\n" + infoSupplier.get()); } return result; @@ -93,8 +111,13 @@ public class ActionHint { * Parse given file with given contents extracting ActionHint of it. *

* Currently the following syntax is supported: - * // "quick-fix name or intention text" "true|false" - * (replace // with line comment prefix in the corresponding language if necessary) + *

+ * {@code // "quick-fix name or intention text" "true|false|"} + *

+ * (replace // with line comment prefix in the corresponding language if necessary). + * If {@link ProblemHighlightType} enum value is specified instead of true/false + * (e.g. {@code "INFORMATION"}), then + * it's expected that the action is present and it's a quick-fix with given highlight type. *

* * @param file PsiFile associated with contents (used to determine the language) @@ -114,11 +137,15 @@ public class ActionHint { assert comment != null : commenter; // "quick fix action text to perform" "should be available" - Pattern pattern = Pattern.compile("^" + Pattern.quote(comment) + " \"(.*)\" \"(true|false)\".*", Pattern.DOTALL); + Pattern pattern = Pattern.compile("^" + Pattern.quote(comment) + " \"(.*)\" \"(\\w+)\".*", Pattern.DOTALL); Matcher matcher = pattern.matcher(contents); TestCase.assertTrue("No comment found in " + file.getVirtualFile(), matcher.matches()); final String text = matcher.group(1); - final boolean actionShouldBeAvailable = Boolean.parseBoolean(matcher.group(2)); - return new ActionHint(text, actionShouldBeAvailable); + String state = matcher.group(2); + if(state.equals("true") || state.equals("false")) { + return new ActionHint(text, Boolean.parseBoolean(state), null); + } else { + return new ActionHint(text, true, ProblemHighlightType.valueOf(state)); + } } } diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java index 5c6d17c4c560..13e15b3b801d 100644 --- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java +++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/QuickFixWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2016 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,6 +20,7 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.QuickFix; import com.intellij.openapi.command.undo.UndoUtil; import com.intellij.openapi.diagnostic.Logger; @@ -29,6 +30,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.TestOnly; /** * @author max @@ -104,6 +106,11 @@ public class QuickFixWrapper implements IntentionAction { return (LocalQuickFix)myDescriptor.getFixes()[myFixNumber]; } + @TestOnly + public ProblemHighlightType getHighlightType() { + return myDescriptor.getHighlightType(); + } + public String toString() { return getText(); } From 0f7c78a5a62b56f8289cf2692ea8428e7f457dc9 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Wed, 23 Nov 2016 16:07:04 +0700 Subject: [PATCH 05/37] IDEA-163991 ifPresent is not suggested when value is not used inside expression; OptionalIsPresentInspection uses CommentTracker now --- .../OptionalIsPresentInspection.java | 147 ++++++++++-------- .../afterAnnotationInverted.java | 15 ++ .../optionalIsPresent/afterAssignmentMap.java | 19 +-- .../optionalIsPresent/afterConsumer.java | 2 +- .../afterConsumerNestedIf.java | 12 ++ .../afterConsumerTwoStatements.java | 13 ++ .../afterReturnComments.java | 7 +- .../beforeAnnotationInverted.java | 2 +- .../beforeAssignmentMap.java | 22 +-- .../optionalIsPresent/beforeConsumer.java | 2 +- .../beforeConsumerNestedIf.java | 12 ++ .../beforeConsumerTwoStatements.java | 3 +- 12 files changed, 166 insertions(+), 90 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java diff --git a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java index 6c79ed10075c..173311616a04 100644 --- a/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/OptionalIsPresentInspection.java @@ -17,6 +17,7 @@ package com.intellij.codeInspection; import com.intellij.codeInsight.ExceptionUtil; import com.intellij.codeInsight.FileModificationService; +import com.intellij.codeInsight.PsiEquivalenceUtil; import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.codeInspection.util.LambdaGenerationUtil; import com.intellij.codeInspection.util.OptionalUtil; @@ -33,10 +34,9 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.siyeh.ig.psiutils.BoolUtils; +import com.siyeh.ig.psiutils.CommentTracker; import com.siyeh.ig.psiutils.ControlFlowUtils; -import com.siyeh.ig.psiutils.EquivalenceChecker; import com.siyeh.ig.psiutils.ExpressionUtils; -import one.util.streamex.StreamEx; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -55,6 +55,18 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo new TernaryCase() }; + private enum ProblemType { + WARNING, INFO, NONE; + + void registerProblem(ProblemsHolder holder, PsiExpression condition, OptionalIfPresentCase scenario) { + if(this != NONE) { + holder.registerProblem(condition, "Can be replaced with single expression in functional style", + this == INFO ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + new OptionalIfPresentFix(scenario)); + } + } + } + @NotNull @Override public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { @@ -100,10 +112,7 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo void check(PsiExpression condition, PsiVariable optionalVariable, PsiElement thenElement, PsiElement elseElement) { for (OptionalIfPresentCase scenario : CASES) { - if (scenario.isApplicable(optionalVariable, thenElement, elseElement)) { - holder.registerProblem(condition, "Can be replaced with single expression in functional style", - new OptionalIfPresentFix(scenario)); - } + scenario.getProblemType(optionalVariable, thenElement, elseElement).registerProblem(holder, condition, scenario); } } }; @@ -162,13 +171,16 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo ExpressionUtils.isReferenceTo(methodExpression.getQualifierExpression(), variable); } - @Contract("_, null, _ -> false") - static boolean isOptionalLambdaCandidate(PsiVariable optionalVariable, PsiExpression lambdaCandidate, PsiExpression falseExpression) { - if (lambdaCandidate == null) return false; - if (ExpressionUtils.isReferenceTo(lambdaCandidate, optionalVariable) && OptionalUtil.isOptionalEmptyCall(falseExpression)) return true; - if (!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return false; + @NotNull + static ProblemType getTypeByLambdaCandidate(PsiVariable optionalVariable, PsiElement lambdaCandidate, PsiExpression falseExpression) { + if (lambdaCandidate == null) return ProblemType.NONE; + if (lambdaCandidate instanceof PsiReferenceExpression && + ((PsiReferenceExpression)lambdaCandidate).isReferenceTo(optionalVariable) && OptionalUtil.isOptionalEmptyCall(falseExpression)) { + return ProblemType.WARNING; + } + if (!ExceptionUtil.getThrownCheckedExceptions(lambdaCandidate).isEmpty()) return ProblemType.NONE; Ref hasOptionalReference = new Ref<>(Boolean.FALSE); - return PsiTreeUtil.processElements(lambdaCandidate, e -> { + boolean hasNoBadRefs = PsiTreeUtil.processElements(lambdaCandidate, e -> { if (!(e instanceof PsiReferenceExpression)) return true; PsiElement element = ((PsiReferenceExpression)e).resolve(); if (!(element instanceof PsiVariable)) return true; @@ -178,11 +190,14 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo return isOptionalGetCall(e.getParent().getParent(), optionalVariable); } return HighlightControlFlowUtil.isEffectivelyFinal((PsiVariable)element, lambdaCandidate, null); - }) && hasOptionalReference.get(); + }); + if(!hasNoBadRefs) return ProblemType.NONE; + if(hasOptionalReference.get() && lambdaCandidate instanceof PsiExpression) return ProblemType.WARNING; + return ProblemType.INFO; } @NotNull - static String generateOptionalLambda(PsiElementFactory factory, PsiVariable optionalVariable, PsiExpression trueValue) { + static String generateOptionalLambda(PsiElementFactory factory, CommentTracker ct, PsiVariable optionalVariable, PsiElement trueValue) { PsiType type = optionalVariable.getType(); JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(trueValue.getProject()); SuggestedNameInfo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type); @@ -190,16 +205,23 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo info = javaCodeStyleManager.suggestVariableName(VariableKind.PARAMETER, "value", null, type); } String paramName = javaCodeStyleManager.suggestUniqueVariableName(info, trueValue, true).names[0]; + if(trueValue instanceof PsiExpressionStatement) { + trueValue = ((PsiExpressionStatement)trueValue).getExpression(); + } + ct.markUnchanged(trueValue); PsiElement copy = trueValue.copy(); for (PsiElement getCall : PsiTreeUtil.collectElements(copy, e -> isOptionalGetCall(e, optionalVariable))) { PsiElement result = getCall.replace(factory.createIdentifier(paramName)); if (copy == getCall) copy = result; } + if(copy instanceof PsiStatement && !(copy instanceof PsiBlockStatement)) { + return paramName + "->{" + copy.getText()+"}"; + } return paramName + "->" + copy.getText(); } static String generateOptionalUnwrap(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiExpression trueValue, PsiExpression falseValue, PsiType targetType) { @@ -210,10 +232,14 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo if (ExpressionUtils.isReferenceTo(falseValue, optionalVariable)) { falseValue = factory.createExpressionFromText(CommonClassNames.JAVA_UTIL_OPTIONAL + ".empty()", falseValue); } - String lambdaText = generateOptionalLambda(factory, optionalVariable, trueValue); + String lambdaText = generateOptionalLambda(factory, ct, optionalVariable, trueValue); PsiLambdaExpression lambda = (PsiLambdaExpression)factory.createExpressionFromText(lambdaText, trueValue); return OptionalUtil.generateOptionalUnwrap(optionalVariable.getName(), lambda.getParameterList().getParameters()[0], - (PsiExpression)lambda.getBody(), falseValue, targetType, true); + (PsiExpression)lambda.getBody(), ct.markUnchanged(falseValue), targetType, true); + } + + static boolean isSimpleOrUnchecked(PsiExpression expression) { + return ExpressionUtils.isSimpleExpression(expression) || LambdaGenerationUtil.canBeUncheckedLambda(expression); } static class OptionalIfPresentFix implements LocalQuickFix { @@ -252,24 +278,17 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo thenElement = invert ? ((PsiConditionalExpression)cond).getElseExpression() : ((PsiConditionalExpression)cond).getThenExpression(); elseElement = invert ? ((PsiConditionalExpression)cond).getThenExpression() : ((PsiConditionalExpression)cond).getElseExpression(); } else return; - if (!myScenario.isApplicable(optionalVariable, thenElement, elseElement)) return; + if (myScenario.getProblemType(optionalVariable, thenElement, elseElement) == ProblemType.NONE) return; if (!FileModificationService.getInstance().preparePsiElementForWrite(element.getContainingFile())) return; PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - PsiElement parent = cond.getParent(); - StreamEx.of(cond, thenElement, elseElement).nonNull() - .flatCollection(st -> PsiTreeUtil.findChildrenOfType(st, PsiComment.class)) - .distinct() - .forEach(comment -> { - parent.addBefore(comment, cond); - comment.delete(); - }); - String replacementText = myScenario.generateReplacement(factory, optionalVariable, thenElement, elseElement); - if (thenElement != null && !PsiTreeUtil.isAncestor(cond, thenElement, true)) thenElement.delete(); - if (elseElement != null && !PsiTreeUtil.isAncestor(cond, elseElement, true)) elseElement.delete(); + CommentTracker ct = new CommentTracker(); + String replacementText = myScenario.generateReplacement(factory, ct, optionalVariable, thenElement, elseElement); + if (thenElement != null && !PsiTreeUtil.isAncestor(cond, thenElement, true)) ct.delete(thenElement); + if (elseElement != null && !PsiTreeUtil.isAncestor(cond, elseElement, true)) ct.delete(elseElement); PsiElement replacement = cond instanceof PsiExpression ? factory.createExpressionFromText(replacementText, cond) : factory.createStatementFromText(replacementText, cond); - PsiElement result = cond.replace(replacement); + PsiElement result = ct.replaceAndRestoreComments(cond, replacement); LambdaCanBeMethodReferenceInspection.replaceAllLambdasWithMethodReferences(result); PsiDiamondTypeUtil.removeRedundantTypeArguments(result); CodeStyleManager.getInstance(project).reformat(result); @@ -277,28 +296,27 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo } interface OptionalIfPresentCase { - boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); + ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement); } static class ReturnCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if (!(trueElement instanceof PsiReturnStatement) || !(falseElement instanceof PsiReturnStatement)) return false; + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (!(trueElement instanceof PsiReturnStatement) || !(falseElement instanceof PsiReturnStatement)) return ProblemType.NONE; PsiExpression falseValue = ((PsiReturnStatement)falseElement).getReturnValue(); - if (!ExpressionUtils.isSimpleExpression(falseValue) && - !LambdaGenerationUtil.canBeUncheckedLambda(falseValue)) return false; PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); - return isOptionalLambdaCandidate(optionalVariable, trueValue, falseValue); + if (!isSimpleOrUnchecked(falseValue)) return ProblemType.NONE; + return getTypeByLambdaCandidate(optionalVariable, trueValue, falseValue); } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiExpression trueValue = ((PsiReturnStatement)trueElement).getReturnValue(); @@ -306,30 +324,29 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo LOG.assertTrue(trueValue != null); LOG.assertTrue(falseValue != null); return "return " + - generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue, PsiTypesUtil.getMethodReturnType(trueElement)) + + generateOptionalUnwrap(factory, ct, optionalVariable, trueValue, falseValue, PsiTypesUtil.getMethodReturnType(trueElement)) + ";"; } } static class AssignmentCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); PsiAssignmentExpression falseAssignment = ExpressionUtils.getAssignment(falseElement); - if (trueAssignment == null || - falseAssignment == null || - !EquivalenceChecker.getCanonicalPsiEquivalence() - .expressionsAreEquivalent(trueAssignment.getLExpression(), falseAssignment.getLExpression()) || - !isOptionalLambdaCandidate(optionalVariable, trueAssignment.getRExpression(), falseAssignment.getRExpression())) { - return false; + if (trueAssignment == null || falseAssignment == null) return ProblemType.NONE; + PsiExpression falseVal = falseAssignment.getRExpression(); + PsiExpression trueVal = trueAssignment.getRExpression(); + if (PsiEquivalenceUtil.areElementsEquivalent(trueAssignment.getLExpression(), falseAssignment.getLExpression()) && + isSimpleOrUnchecked(falseVal)) { + return getTypeByLambdaCandidate(optionalVariable, trueVal, falseVal); } - return ExpressionUtils.isSimpleExpression(falseAssignment.getRExpression()) || - LambdaGenerationUtil.canBeUncheckedLambda(falseAssignment.getRExpression()); + return ProblemType.NONE; } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiAssignmentExpression trueAssignment = ExpressionUtils.getAssignment(trueElement); @@ -340,49 +357,51 @@ public class OptionalIsPresentInspection extends BaseJavaBatchLocalInspectionToo PsiExpression trueValue = trueAssignment.getRExpression(); PsiExpression falseValue = falseAssignment.getRExpression(); LOG.assertTrue(falseValue != null); - return lValue.getText() + " = " + generateOptionalUnwrap(factory, optionalVariable, trueValue, falseValue, lValue.getType()) + ";"; + return lValue.getText() + " = " + generateOptionalUnwrap(factory, ct, optionalVariable, trueValue, falseValue, lValue.getType()) + ";"; } } static class TernaryCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if(!(trueElement instanceof PsiExpression) || !(falseElement instanceof PsiExpression)) return false; + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if(!(trueElement instanceof PsiExpression) || !(falseElement instanceof PsiExpression)) return ProblemType.NONE; PsiExpression trueExpression = (PsiExpression)trueElement; PsiExpression falseExpression = (PsiExpression)falseElement; - return isOptionalLambdaCandidate(optionalVariable, trueExpression, falseExpression) && - (ExpressionUtils.isSimpleExpression(falseExpression) || LambdaGenerationUtil.canBeUncheckedLambda(falseExpression)); + return (isSimpleOrUnchecked(falseExpression)) ? + getTypeByLambdaCandidate(optionalVariable, trueExpression, falseExpression) : ProblemType.NONE; } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { PsiExpression ternary = PsiTreeUtil.getParentOfType(trueElement, PsiConditionalExpression.class); LOG.assertTrue(ternary != null); PsiExpression trueExpression = (PsiExpression)trueElement; PsiExpression falseExpression = (PsiExpression)falseElement; - return generateOptionalUnwrap(factory, optionalVariable, trueExpression, falseExpression, ternary.getType()); + return generateOptionalUnwrap(factory, ct, optionalVariable, trueExpression, falseExpression, ternary.getType()); } } static class ConsumerCase implements OptionalIfPresentCase { @Override - public boolean isApplicable(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - if (falseElement != null && !(falseElement instanceof PsiEmptyStatement)) return false; - if (!(trueElement instanceof PsiExpressionStatement)) return false; - PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); - return isOptionalLambdaCandidate(optionalVariable, expression, null) && !isOptionalGetCall(expression, optionalVariable); + public ProblemType getProblemType(PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { + if (falseElement != null && !(falseElement instanceof PsiEmptyStatement)) return ProblemType.NONE; + if (trueElement instanceof PsiExpressionStatement) { + PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); + if(isOptionalGetCall(expression, optionalVariable)) return ProblemType.NONE; + trueElement = expression; + } + return getTypeByLambdaCandidate(optionalVariable, trueElement, null); } @Override public String generateReplacement(PsiElementFactory factory, - PsiVariable optionalVariable, + CommentTracker ct, PsiVariable optionalVariable, PsiElement trueElement, PsiElement falseElement) { - PsiExpression expression = ((PsiExpressionStatement)trueElement).getExpression(); - return optionalVariable.getName() + ".ifPresent(" + generateOptionalLambda(factory, optionalVariable, expression) + ");"; + return optionalVariable.getName() + ".ifPresent(" + generateOptionalLambda(factory, ct, optionalVariable, trueElement) + ");"; } } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java new file mode 100644 index 000000000000..4fed8347f15e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAnnotationInverted.java @@ -0,0 +1,15 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.Optional; + +public class Main { + public static Optional findAnnotation(Optional element) { + return element.>map(annotatedElement -> Optional.empty()).orElseGet(() -> findAnnotation((AnnotatedElement) null)); + } + + private static Optional findAnnotation(AnnotatedElement element) { + return Optional.empty(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java index a097e38e57e1..d1565ef90a3a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterAssignmentMap.java @@ -3,13 +3,14 @@ import java.util.*; public class Main { - public void testOptional(Optional str) { - String val; - // line comment -// another line comment -//before trim -/* block comment *//*block comment*/ - val = str.map(String::trim).orElse(""); - System.out.println(val); - } + public void testOptional(Optional str) { + String val; + // line comment + // another line comment + /* block comment */ + /*block comment*/ + //before trim + val = str.map(String::trim).orElse(""); + System.out.println(val); + } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java index fba7408b5a4e..b25e341e57cc 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "true" +// "Replace Optional.isPresent() condition with functional style expression" "GENERIC_ERROR_OR_WARNING" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java new file mode 100644 index 000000000000..7887a72881d0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerNestedIf.java @@ -0,0 +1,12 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.Optional; + +public class Main { + public void test(Optional opt) { + opt.ifPresent(s -> { + if (s.equals("abc")) + System.out.println(s); + }); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java new file mode 100644 index 000000000000..b63c5938df8c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterConsumerTwoStatements.java @@ -0,0 +1,13 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.*; + +public class Main { + public void testOptional(Optional str) { + str.ifPresent(s -> { + System.out.println(s); + // once again! + System.out.println(s); + }); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java index 07ee230d09cd..1a664ad0350d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/afterReturnComments.java @@ -11,7 +11,10 @@ public class Main { } public Number testOptionalComments(Optional strList) { - /* optional is present *//*return something *//*too big*//* optional is absent *//* return null*/ - return strList.map(myList -> myList.size() > 1 ? myList.get(1) : 1.0).orElse(null); + /* optional is present */ + /*return something */ + /* optional is absent */ + /* return null*/ + return strList.map(myList -> myList.size() > /*too big*/ 1 ? myList.get(1) : 1.0).orElse(null); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java index 2b8fadbd3cde..51d83a5dd283 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAnnotationInverted.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "false" +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java index b22119c8d5ec..a303b52c9d6d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeAssignmentMap.java @@ -3,16 +3,16 @@ import java.util.*; public class Main { - public void testOptional(Optional str) { - String val; - if (str.isPresent()) { - val = // line comment - // another line comment - str.get()//before trim - .trim() /* block comment *//*block comment*/; - } else { - val = ""; + public void testOptional(Optional str) { + String val; + if (str.isPresent()) { + val = // line comment + // another line comment + str.get()//before trim + .trim() /* block comment *//*block comment*/; + } else { + val = ""; + } + System.out.println(val); } - System.out.println(val); - } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java index c8bd21c05e06..aa493a049e19 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumer.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "true" +// "Replace Optional.isPresent() condition with functional style expression" "GENERIC_ERROR_OR_WARNING" import java.util.*; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java new file mode 100644 index 000000000000..e147d990743c --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerNestedIf.java @@ -0,0 +1,12 @@ +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" + +import java.util.Optional; + +public class Main { + public void test(Optional opt) { + if(opt.isPresent()) { + if(opt.get().equals("abc")) + System.out.println(opt.get()); + } + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java index e62b7210bfee..2c5766ed79b8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/optionalIsPresent/beforeConsumerTwoStatements.java @@ -1,4 +1,4 @@ -// "Replace Optional.isPresent() condition with functional style expression" "false" +// "Replace Optional.isPresent() condition with functional style expression" "INFORMATION" import java.util.*; @@ -6,6 +6,7 @@ public class Main { public void testOptional(Optional str) { if (str.isPresent()) { System.out.println(str.get()); + // once again! System.out.println(str.get()); } } From ad8c623aca3c5e394b92faa49d6d54ecae0c5ab5 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 21 Nov 2016 19:59:56 +0100 Subject: [PATCH 06/37] add parentheses to quick fix presentation --- .../wrapArrayToArraysAsList/afterFewParameters.java | 2 +- .../wrapArrayToArraysAsList/afterSingleParameter.java | 2 +- .../wrapArrayToArraysAsList/beforeFewParameters.java | 2 +- .../wrapArrayToArraysAsList/beforeNotConvertible.java | 2 +- .../wrapArrayToArraysAsList/beforeNotConvertible2.java | 2 +- .../wrapArrayToArraysAsList/beforeSingleParameter.java | 2 +- .../quickFix/wrapExpression/afterParseAssignment.java | 2 +- .../quickFix/wrapExpression/afterParseInCall.java | 2 +- .../quickFix/wrapExpression/afterParseInVarargsCall.java | 2 +- .../quickFix/wrapExpression/afterValueofAssignment.java | 2 +- .../quickFix/wrapExpression/afterValueofCall.java | 2 +- .../quickFix/wrapExpression/afterValueofInVarargsCall.java | 2 +- .../quickFix/wrapExpression/afterValueofVarargsCall.java | 2 +- .../quickFix/wrapExpression/beforeParseAssignment.java | 2 +- .../quickFix/wrapExpression/beforeParseInCall.java | 2 +- .../quickFix/wrapExpression/beforeParseInVarargsCall.java | 2 +- .../quickFix/wrapExpression/beforeValueofAssignment.java | 2 +- .../quickFix/wrapExpression/beforeValueofCall.java | 2 +- .../quickFix/wrapExpression/beforeValueofInVarargsCall.java | 2 +- .../quickFix/wrapExpression/beforeValueofVarargsCall.java | 2 +- resources-en/src/messages/QuickFixBundle.properties | 6 +++--- 21 files changed, 23 insertions(+), 23 deletions(-) diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java index 868cf5e74f5c..41be36ab87bc 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterFewParameters.java @@ -1,4 +1,4 @@ -// "Wrap 4th parameter using 'Arrays.asList'" "true" +// "Wrap 4th parameter using 'Arrays.asList()'" "true" import java.util.Arrays; import java.util.List; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java index 9544df9a4c52..12514e409eb2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/afterSingleParameter.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "true" +// "Wrap using 'Arrays.asList()'" "true" import java.util.Arrays; import java.util.List; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java index 92ed4293c63b..6538e52c7a1a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeFewParameters.java @@ -1,4 +1,4 @@ -// "Wrap 4th parameter using 'Arrays.asList'" "true" +// "Wrap 4th parameter using 'Arrays.asList()'" "true" import java.util.List; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java index 8a8e0153aed4..4090aae07fe8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "false" +// "Wrap using 'Arrays.asList()'" "false" import java.util.LinkedList; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java index c27ca44463db..8ac304049dcf 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeNotConvertible2.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "false" +// "Wrap using 'Arrays.asList()'" "false" import java.util.LinkedList; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java index a29aaa36c86d..70aa10c065d2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapArrayToArraysAsList/beforeSingleParameter.java @@ -1,4 +1,4 @@ -// "Wrap using 'Arrays.asList'" "true" +// "Wrap using 'Arrays.asList()'" "true" import java.util.List; public class Test { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java index ea20b8721e18..0a14af950feb 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { private long lo = Long.parseLong("42"); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java index 5ce32b3862cb..a98cbeaf2fc1 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba() { fa(Long.parseLong("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java index 31706139c373..686660bc26be 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterParseInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba(long l) { fa(l, Long.parseLong("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java index 1ac02ad800e2..80f3fc0f8f3a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { private Long lo = Long.valueOf("42"); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java index 19333acdf670..b0eeadc9d417 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa(Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java index 11e61b1c5d59..2c1aee72c86c 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba(Long l) { fa(l, Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java index 4291e43fe0a1..13cf7d09d885 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/afterValueofVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa(Long.valueOf("42")); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java index 0700d003d994..cb594414444f 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { private long lo = "42"; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java index d4d0283e1f6c..2535e8ed769d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba() { fa("42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java index 62ca613e69d9..364221f6c461 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeParseInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.parseLong'" "true" +// "Wrap using 'Long.parseLong()'" "true" public class Test { void ba(long l) { fa(l, "42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java index 8b812118de12..36b4c9c596f0 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofAssignment.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { private Long lo = "42"; } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java index 17604b21f05c..04a28c62cc92 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa("42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java index a49a329bbf79..fb52654805b8 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofInVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba(Long l) { fa(l, "42"); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java index 7dd6f914ff0a..c82e585b9a0d 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/wrapExpression/beforeValueofVarargsCall.java @@ -1,4 +1,4 @@ -// "Wrap using 'Long.valueOf'" "true" +// "Wrap using 'Long.valueOf()'" "true" public class Test { void ba() { fa("42"); diff --git a/resources-en/src/messages/QuickFixBundle.properties b/resources-en/src/messages/QuickFixBundle.properties index f6d9b8fe0db7..7161dbe0a4f1 100644 --- a/resources-en/src/messages/QuickFixBundle.properties +++ b/resources-en/src/messages/QuickFixBundle.properties @@ -178,7 +178,7 @@ fix.variable.type.text=Change {0} ''{1}'' type to ''{2}'' # Sample: Boolean b = "true"; -> Boolean b = Boolean.valueOf("true"); wrap.expression.using.static.accessor.family=Wrap Expression -wrap.expression.using.static.accessor.text=Wrap using ''{0}'' +wrap.expression.using.static.accessor.text=Wrap using ''{0}()'' # {0} - qualified class name suggested to be imported. side.effect.action.remove=&Remove @@ -263,8 +263,8 @@ replace.with.list.access.text=Replace with list access add.qualifier=Add qualifier add.qualifier.original.class.chooser.title=Original class -wrap.array.to.arrays.as.list.parameter.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''Arrays.asList'' -wrap.array.to.arrays.as.list.single.parameter.text=Wrap using 'Arrays.asList' +wrap.array.to.arrays.as.list.parameter.text=Wrap {0, choice, 1#1st|2#2nd|3#3rd|4#{0,number}th} parameter using ''Arrays.asList()'' +wrap.array.to.arrays.as.list.single.parameter.text=Wrap using 'Arrays.asList()' annotations.fix=Annotations add.missing.annotation.parameters.fix=Add missing annotation parameters - {0} From b837dc9d64661e17b8ab3e6fcb11c224cbbba6ea Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Wed, 23 Nov 2016 11:20:52 +0100 Subject: [PATCH 07/37] IPP: don't replace unicode carriage return with character (EA-92213) --- .../src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java | 4 +++- .../test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java | 1 + .../com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java index 7bd009b720ef..6fba69f56e06 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/unicode/UnicodeUnescapeIntention.java @@ -110,7 +110,7 @@ public class UnicodeUnescapeIntention extends Intention { /** * see JLS 3.3. Unicode Escapes */ - private static int indexOfUnicodeEscape(@NotNull String text, int offset) { + static int indexOfUnicodeEscape(@NotNull String text, int offset) { final int length = text.length(); for (int i = 0; i < length; i++) { final char c = text.charAt(i); @@ -143,6 +143,8 @@ public class UnicodeUnescapeIntention extends Intention { StringUtil.isHexDigit(text.charAt(nextChar + 3))) { final int escapeEnd = nextChar + 4; if (offset <= escapeEnd) { + final char d = (char)Integer.parseInt(text.substring(nextChar, nextChar + 4), 16); + if (d == '\r') return -1; // carriage return not allowed return i; } } diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java new file mode 100644 index 000000000000..045e900b2bbb --- /dev/null +++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/unicode/unescape/NoCarriageReturn.java @@ -0,0 +1 @@ +// \u000D \ No newline at end of file diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java index bb68178ed414..06209bbf5ac7 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/unicode/UnicodeUnescapeIntentionTest.java @@ -29,6 +29,7 @@ public class UnicodeUnescapeIntentionTest extends IPPTestCase { public void testSurrogatePairs2() { doTest(); } public void testNoException() { assertIntentionNotAvailable(); } public void testU() { assertIntentionNotAvailable(); } + public void testNoCarriageReturn() { assertIntentionNotAvailable(); } @Override protected String getRelativePath() { From 5cecdc77ac3273240739264b4853438a7c8c163c Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Wed, 23 Nov 2016 13:33:32 +0300 Subject: [PATCH 08/37] make replace operation undo transparent --- .../jetbrains/edu/learning/StudySubtaskUtils.java | 6 +++--- .../actions/StudyFillPlaceholdersAction.java | 2 +- .../actions/StudyRefreshAnswerPlaceholder.java | 2 +- .../actions/StudyRefreshTaskFileAction.java | 2 +- .../com/jetbrains/edu/learning/core/EduUtils.java | 15 +++++++-------- .../learning/courseFormat/AnswerPlaceholder.java | 11 +++++------ 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java index f595eaaa7183..6d3ee722f530 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java @@ -119,15 +119,15 @@ public class StudySubtaskUtils { int toSubtaskIndex) { taskFile.setTrackLengths(false); for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) { - placeholder.switchSubtask(project, document, fromSubtaskIndex, toSubtaskIndex); + placeholder.switchSubtask(document, fromSubtaskIndex, toSubtaskIndex); } taskFile.setTrackLengths(true); } - public static void refreshPlaceholder(@NotNull Project project, @NotNull Editor editor, @NotNull AnswerPlaceholder placeholder) { + public static void refreshPlaceholder(@NotNull Editor editor, @NotNull AnswerPlaceholder placeholder) { int prevSubtaskIndex = placeholder.getActiveSubtaskIndex() - 1; AnswerPlaceholderSubtaskInfo info = placeholder.getSubtaskInfos().get(prevSubtaskIndex); String replacementText = info != null ? info.getAnswer() : placeholder.getTaskText(); - EduUtils.replaceAnswerPlaceholder(project, editor.getDocument(), placeholder, placeholder.getRealLength(), replacementText); + EduUtils.replaceAnswerPlaceholder(editor.getDocument(), placeholder, placeholder.getRealLength(), replacementText); } } \ No newline at end of file diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java index 4bd0daa96cb0..9f4e0ca7c193 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyFillPlaceholdersAction.java @@ -32,7 +32,7 @@ public class StudyFillPlaceholdersAction extends AnAction { if (answer == null) { continue; } - EduUtils.replaceAnswerPlaceholder(project, document, placeholder, placeholder.getRealLength(), answer); + EduUtils.replaceAnswerPlaceholder(document, placeholder, placeholder.getRealLength(), answer); } } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java index 3c45e8e701e0..2b71699ec4b1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshAnswerPlaceholder.java @@ -43,7 +43,7 @@ public class StudyRefreshAnswerPlaceholder extends DumbAwareAction { StudyEditor studyEditor = StudyUtils.getSelectedStudyEditor(project); final StudyState studyState = new StudyState(studyEditor); if (answerPlaceholder.getTaskFile().getTask().hasSubtasks()) { - StudySubtaskUtils.refreshPlaceholder(project, studyState.getEditor(), answerPlaceholder); + StudySubtaskUtils.refreshPlaceholder(studyState.getEditor(), answerPlaceholder); return; } Document patternDocument = StudyUtils.getPatternDocument(answerPlaceholder.getTaskFile(), studyState.getVirtualFile().getName()); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java index 08bd1056b968..42cf44f7efc1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/actions/StudyRefreshTaskFileAction.java @@ -63,7 +63,7 @@ public class StudyRefreshTaskFileAction extends StudyActionWithShortcut { final TaskFile taskFile = studyState.getTaskFile(); if (taskFile.getTask().hasSubtasks()) { for (AnswerPlaceholder placeholder : taskFile.getActivePlaceholders()) { - StudySubtaskUtils.refreshPlaceholder(project, editor, placeholder); + StudySubtaskUtils.refreshPlaceholder(editor, placeholder); } } else { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java index 2beea69c8805..1796db1ec90e 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/core/EduUtils.java @@ -170,17 +170,17 @@ public class EduUtils { taskFile.setTrackLengths(false); for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) { int fromSubtask = task.getActiveSubtaskIndex(); - placeholder.switchSubtask(project, studentDocument, fromSubtask, targetSubtaskIndex); + placeholder.switchSubtask(studentDocument, fromSubtask, targetSubtaskIndex); } for (AnswerPlaceholder placeholder : taskFile.getAnswerPlaceholders()) { - replaceWithTaskText(project, studentDocument, placeholder, targetSubtaskIndex); + replaceWithTaskText(studentDocument, placeholder, targetSubtaskIndex); } taskFile.setTrackChanges(true); studentDocument.removeDocumentListener(listener); return Pair.create(studentFile, taskFile); } - private static void replaceWithTaskText(Project project, Document studentDocument, AnswerPlaceholder placeholder, int toSubtaskIndex) { + private static void replaceWithTaskText(Document studentDocument, AnswerPlaceholder placeholder, int toSubtaskIndex) { AnswerPlaceholderSubtaskInfo info = placeholder.getSubtaskInfos().get(toSubtaskIndex); if (info == null) { return; @@ -193,19 +193,18 @@ public class EduUtils { Integer max = Collections.max(ContainerUtil.filter(placeholder.getSubtaskInfos().keySet(), i -> i < toSubtaskIndex)); replacementText = placeholder.getSubtaskInfos().get(max).getPossibleAnswer(); } - replaceAnswerPlaceholder(project, studentDocument, placeholder, placeholder.getVisibleLength(toSubtaskIndex), replacementText); + replaceAnswerPlaceholder(studentDocument, placeholder, placeholder.getVisibleLength(toSubtaskIndex), replacementText); } - public static void replaceAnswerPlaceholder(@NotNull final Project project, - @NotNull final Document document, + public static void replaceAnswerPlaceholder(@NotNull final Document document, @NotNull final AnswerPlaceholder answerPlaceholder, int length, String replacementText) { final int offset = answerPlaceholder.getOffset(); - CommandProcessor.getInstance().executeCommand(project, () -> ApplicationManager.getApplication().runWriteAction(() -> { + CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> { document.replaceString(offset, offset + length, replacementText); FileDocumentManager.getInstance().saveDocument(document); - }), "Replace Answer Placeholders", "Replace Answer Placeholders"); + })); } public static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) { diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java index 6cfb41eeb03b..a8f7e51d42e8 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/courseFormat/AnswerPlaceholder.java @@ -3,7 +3,6 @@ package com.jetbrains.edu.learning.courseFormat; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.project.Project; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.hash.HashMap; import com.intellij.util.xmlb.annotations.Transient; @@ -247,13 +246,13 @@ public class AnswerPlaceholder { return getUseLength() ? myLength : mySubtaskInfos.get(maxIndex).getPossibleAnswer().length(); } - public void switchSubtask(@NotNull Project project, @NotNull Document document, int fromSubtask, int toSubtask) { + public void switchSubtask(@NotNull Document document, int fromSubtask, int toSubtask) { Set indexes = mySubtaskInfos.keySet(); int visibleLength = getVisibleLength(fromSubtask); if (indexes.contains(fromSubtask) && indexes.contains(toSubtask)) { if (!myUseLength) { String replacementText = mySubtaskInfos.get(toSubtask).getPossibleAnswer(); - EduUtils.replaceAnswerPlaceholder(project, document, this, visibleLength, replacementText); + EduUtils.replaceAnswerPlaceholder(document, this, visibleLength, replacementText); } return; } @@ -263,7 +262,7 @@ public class AnswerPlaceholder { Integer maxIndex = Collections.max(ContainerUtil.filter(indexes, integer -> integer <= toSubtask)); AnswerPlaceholderSubtaskInfo maxInfo = mySubtaskInfos.get(maxIndex); String replacementText = myUseLength ? maxInfo.getPlaceholderText() : maxInfo.getPossibleAnswer(); - EduUtils.replaceAnswerPlaceholder(project, document, this, visibleLength, replacementText); + EduUtils.replaceAnswerPlaceholder(document, this, visibleLength, replacementText); return; } } @@ -271,11 +270,11 @@ public class AnswerPlaceholder { if (minIndex > toSubtask && minIndex <= fromSubtask) { AnswerPlaceholderSubtaskInfo minInfo = mySubtaskInfos.get(minIndex); if (minInfo.isNeedInsertText()) { - EduUtils.replaceAnswerPlaceholder(project, document, this, visibleLength, ""); + EduUtils.replaceAnswerPlaceholder(document, this, visibleLength, ""); } else { String replacementText = minInfo.getPlaceholderText(); - EduUtils.replaceAnswerPlaceholder(project, document, this, visibleLength, replacementText); + EduUtils.replaceAnswerPlaceholder(document, this, visibleLength, replacementText); } } } From 21e14a61b4704251228a3cc5703cbff2be76a678 Mon Sep 17 00:00:00 2001 From: "Maxim.Mossienko" Date: Wed, 23 Nov 2016 11:29:54 +0100 Subject: [PATCH 09/37] api for InvertedIndex in util --- .../com/intellij/index/StringIndex.java | 3 +- .../ChangeTrackingValueContainer.java | 21 +--------- .../util/indexing/FileBasedIndexImpl.java | 14 +++---- .../util/indexing/FileId2ValueMapping.java | 2 +- .../intellij/util/indexing/IntPredicate.java | 23 +++++++++++ .../util/indexing/UpdatableIndex.java | 17 ++------- .../indexing/UpdatableValueContainer.java | 10 +++++ .../util/indexing/ValueContainerImpl.java | 38 +++---------------- .../util/indexing/ValueIteratorImpl.java | 28 ++++++++++++++ .../containers/ChangeBufferingList.java | 7 ++-- .../util/indexing/containers/IdBitSet.java | 5 ++- .../util/indexing/containers/IdSet.java | 5 ++- .../containers/RandomAccessIntContainer.java | 3 +- .../util/indexing/containers/SortedIdSet.java | 5 ++- .../intellij/util/indexing/DataIndexer.java | 0 .../src/com/intellij/util/indexing/ID.java | 0 .../util/indexing/IndexExtension.java | 0 .../util/indexing/InvertedIndex.java} | 19 +++++++--- .../util/indexing/StorageException.java | 0 .../util/indexing/ValueContainer.java | 32 +--------------- 20 files changed, 112 insertions(+), 120 deletions(-) create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java create mode 100644 platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java rename platform/{indexing-api => util}/src/com/intellij/util/indexing/DataIndexer.java (100%) rename platform/{core-api => util}/src/com/intellij/util/indexing/ID.java (100%) rename platform/{indexing-api => util}/src/com/intellij/util/indexing/IndexExtension.java (100%) rename platform/{lang-impl/src/com/intellij/util/indexing/AbstractIndex.java => util/src/com/intellij/util/indexing/InvertedIndex.java} (69%) rename platform/{lang-impl => util}/src/com/intellij/util/indexing/StorageException.java (100%) rename platform/{lang-impl => util}/src/com/intellij/util/indexing/ValueContainer.java (74%) diff --git a/java/java-tests/testSrc/com/intellij/index/StringIndex.java b/java/java-tests/testSrc/com/intellij/index/StringIndex.java index b5e2603eb09e..379a0e2ae236 100644 --- a/java/java-tests/testSrc/com/intellij/index/StringIndex.java +++ b/java/java-tests/testSrc/com/intellij/index/StringIndex.java @@ -15,6 +15,7 @@ */ package com.intellij.index; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.indexing.*; import com.intellij.util.io.DataExternalizer; import com.intellij.util.io.EnumeratorStringDescriptor; @@ -75,7 +76,7 @@ public class StringIndex { } public List getFilesByWord(@NotNull String word) throws StorageException { - return myIndex.getData(word).toValueList(); + return ContainerUtil.collect(myIndex.getData(word).getValueIterator()); } public void update(final String path, @Nullable String content, @Nullable String oldContent) throws StorageException { diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java index 467ba0cf3202..6679a10040ab 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ChangeTrackingValueContainer.java @@ -26,7 +26,6 @@ import org.jetbrains.annotations.Nullable; import java.io.DataOutput; import java.io.IOException; -import java.util.List; /** * @author Eugene Zhuravlev @@ -82,24 +81,6 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer return getMergedData().getValueIterator(); } - @NotNull - @Override - public List toValueList() { - return getMergedData().toValueList(); - } - - @NotNull - @Override - public IntPredicate getValueAssociationPredicate(Value value) { - return getMergedData().getValueAssociationPredicate(value); - } - - @NotNull - @Override - public IntIterator getInputIdsIterator(final Value value) { - return getMergedData().getInputIdsIterator(value); - } - public void dropMergedData() { myMerged = null; } @@ -164,7 +145,7 @@ class ChangeTrackingValueContainer extends UpdatableValueContainer } }); } - setNeedsCompacting(fromDisk.needsCompacting()); + setNeedsCompacting(((UpdatableValueContainer)fromDisk).needsCompacting()); myMerged = newMerged; return newMerged; diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java index 86afd87c55aa..7f770c9c17b6 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileBasedIndexImpl.java @@ -914,9 +914,9 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull K dataKey, @Nullable VirtualFile restrictToFile, @NotNull GlobalSearchScope scope, - @NotNull Processor> valueProcessor) { + @NotNull Processor> valueProcessor) { final Boolean result = processExceptions(indexId, restrictToFile, scope, - index -> valueProcessor.process(index.getData(dataKey).getValueIterator())); + index -> valueProcessor.process((ValueIteratorImpl)index.getData(dataKey).getValueIterator())); return result == null || result.booleanValue(); } @@ -1053,10 +1053,10 @@ public class FileBasedIndexImpl extends FileBasedIndex { } @Nullable - private static TIntHashSet collectInputIdsContainingAllKeys(@NotNull UpdatableIndex index, + private static TIntHashSet collectInputIdsContainingAllKeys(@NotNull InvertedIndex index, @NotNull Collection dataKeys, @Nullable Condition valueChecker, - @Nullable ValueContainer.IntPredicate idChecker) + @Nullable IntPredicate idChecker) throws StorageException { TIntHashSet mainIntersection = null; @@ -1065,7 +1065,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { final TIntHashSet copy = new TIntHashSet(); final ValueContainer container = index.getData(dataKey); - for (final ValueContainer.ValueIterator valueIt = container.getValueIterator(); valueIt.hasNext(); ) { + for (ValueIteratorImpl valueIt = (ValueIteratorImpl)container.getValueIterator(); valueIt.hasNext(); ) { final V value = valueIt.next(); if (valueChecker != null && !valueChecker.value(value)) { continue; @@ -1085,7 +1085,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { } else { mainIntersection.forEach(new TIntProcedure() { - final ValueContainer.IntPredicate predicate = valueIt.getValueAssociationPredicate(); + final IntPredicate predicate = valueIt.getValueAssociationPredicate(); @Override public boolean execute(int id) { @@ -1107,7 +1107,7 @@ public class FileBasedIndexImpl extends FileBasedIndex { @NotNull - public static ValueContainer.IntIterator collectInputIdsContainingAllKeys(@NotNull UpdatableIndex index, + public static ValueContainer.IntIterator collectInputIdsContainingAllKeys(@NotNull InvertedIndex index, @NotNull Collection dataKeys) throws StorageException { TIntHashSet result = collectInputIdsContainingAllKeys(index, dataKeys, null, null); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java b/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java index 5a6b3357bc99..48f5e6127a0f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/FileId2ValueMapping.java @@ -73,7 +73,7 @@ class FileId2ValueMapping { valueContainer.removeValue(inputId, mapped); } if (DebugAssertions.EXTRA_SANITY_CHECKS && myOnePerFileValidationEnabled) { - for (final ValueContainer.ValueIterator valueIterator = valueContainer.getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = valueContainer.getValueIterator(); valueIterator.hasNext();) { valueIterator.next(); DebugAssertions.assertTrue(!valueIterator.getValueAssociationPredicate().contains(inputId)); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java b/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java new file mode 100644 index 000000000000..a0d2e86bcc35 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/IntPredicate.java @@ -0,0 +1,23 @@ +/* + * Copyright 2000-2016 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.util.indexing; + +/** + * Created by Maxim.Mossienko on 11/22/2016. + */ +public interface IntPredicate { + boolean contains(int id); +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java index 3d8c5fb15d9b..2a8da9085bc9 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableIndex.java @@ -16,8 +16,9 @@ package com.intellij.util.indexing; -import com.intellij.openapi.util.Computable; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -27,25 +28,15 @@ import java.util.concurrent.locks.Lock; * @author Eugene Zhuravlev * Date: Dec 10, 2007 */ -public interface UpdatableIndex extends AbstractIndex { +public interface UpdatableIndex extends InvertedIndex { - void clear() throws StorageException; - - void flush() throws StorageException; - - /** - * @param inputId *positive* id of content. - */ - @NotNull - Computable update(int inputId, @Nullable Input content); + boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; @NotNull Lock getReadLock(); @NotNull Lock getWriteLock(); - - void dispose(); void setIndexedStateForFile(int fileId, @NotNull VirtualFile file); void resetIndexedStateForFile(int fileId); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java index 789e9c18bc8e..9b5770ec0c71 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/UpdatableValueContainer.java @@ -25,4 +25,14 @@ public abstract class UpdatableValueContainer extends ValueContainer{ public abstract void addValue(int inputId, T value); public abstract void removeAssociatedValue(int inputId); + + private volatile boolean myNeedsCompacting; + + boolean needsCompacting() { + return myNeedsCompacting; + } + + void setNeedsCompacting(boolean value) { + myNeedsCompacting = value; + } } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java index 591a4a0d5b6e..d39fa1f150bb 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java @@ -31,8 +31,6 @@ import org.jetbrains.annotations.Nullable; import java.io.DataInputStream; import java.io.DataOutput; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -86,7 +84,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement if (myInputIdMapping == null) return; List fileSetObjects = null; List valueObjects = null; - for (final ValueIterator valueIterator = getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); if (valueIterator.getValueAssociationPredicate().contains(inputId)) { @@ -144,10 +142,10 @@ class ValueContainerImpl extends UpdatableValueContainer implement @NotNull @Override - public ValueIterator getValueIterator() { + public ValueIteratorImpl getValueIterator() { if (myInputIdMapping != null) { if (!(myInputIdMapping instanceof THashMap)) { - return new ValueIterator() { + return new ValueIteratorImpl() { private Value value = (Value)myInputIdMapping; @NotNull @@ -186,7 +184,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } }; } else { - return new ValueIterator() { + return new ValueIteratorImpl() { private Value current; private Object currentValue; private final THashMap myMapping = ((THashMap)myInputIdMapping); @@ -235,7 +233,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement } } - static class EmptyValueIterator extends EmptyIterator implements ValueIterator { + static class EmptyValueIterator extends EmptyIterator implements ValueIteratorImpl { @NotNull @Override @@ -257,24 +255,6 @@ class ValueContainerImpl extends UpdatableValueContainer implement private static final EmptyValueIterator emptyIterator = new EmptyValueIterator(); - @NotNull - @Override - public List toValueList() { - if (myInputIdMapping == null) { - return Collections.emptyList(); - } else if (myInputIdMapping instanceof THashMap) { - return new ArrayList<>(((THashMap)myInputIdMapping).keySet()); - } else { - return new SmartList<>((Value)myInputIdMapping); - } - } - - @NotNull - @Override - public IntPredicate getValueAssociationPredicate(Value value) { - return getPredicateOutOfFileSetObject(getFileSetObject(value)); - } - private static @NotNull IntPredicate getPredicateOutOfFileSetObject(@Nullable Object input) { if (input == null) return EMPTY_PREDICATE; @@ -291,12 +271,6 @@ class ValueContainerImpl extends UpdatableValueContainer implement return ((ChangeBufferingList)input).intPredicate(); } - @NotNull - @Override - public IntIterator getInputIdsIterator(Value value) { - return getIntIteratorOutOfFileSetObject(getFileSetObject(value)); - } - private static @NotNull IntIterator getIntIteratorOutOfFileSetObject(@Nullable Object input) { if (input == null) return EMPTY_ITERATOR; if (input instanceof Integer){ @@ -436,7 +410,7 @@ class ValueContainerImpl extends UpdatableValueContainer implement public void saveTo(DataOutput out, DataExternalizer externalizer) throws IOException { DataInputOutputUtil.writeINT(out, size()); - for (final ValueIterator valueIterator = getValueIterator(); valueIterator.hasNext();) { + for (final ValueIteratorImpl valueIterator = getValueIterator(); valueIterator.hasNext();) { final Value value = valueIterator.next(); externalizer.save(out, value); Object fileSetObject = valueIterator.getFileSetObject(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java new file mode 100644 index 000000000000..93e91e53b4ca --- /dev/null +++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueIteratorImpl.java @@ -0,0 +1,28 @@ +/* + * Copyright 2000-2016 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.util.indexing; + +import org.jetbrains.annotations.NotNull; + +/** + * Created by Maxim.Mossienko on 11/22/2016. + */ +interface ValueIteratorImpl extends ValueContainer.ValueIterator { + @NotNull + IntPredicate getValueAssociationPredicate(); + + Object getFileSetObject(); +} diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java index 7e9076282b8e..6464b8a51493 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java @@ -16,6 +16,7 @@ package com.intellij.util.indexing.containers; import com.intellij.util.indexing.DebugAssertions; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntProcedure; @@ -266,10 +267,10 @@ public class ChangeBufferingList implements Cloneable { return intContainer.size() == 0; } - public ValueContainer.IntPredicate intPredicate() { - final ValueContainer.IntPredicate predicate = getRandomAccessContainer().intPredicate(); + public IntPredicate intPredicate() { + final IntPredicate predicate = getRandomAccessContainer().intPredicate(); if (checkSet != null) { - return new ValueContainer.IntPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { boolean answer = predicate.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java index 357c919f7162..266341b3cb9f 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdBitSet.java @@ -16,6 +16,7 @@ package com.intellij.util.indexing.containers; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; /** @@ -126,8 +127,8 @@ class IdBitSet implements Cloneable, RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { return IdBitSet.this.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java index bbe7ff7891e7..23ad57050113 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/IdSet.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntHashSet; @@ -36,8 +37,8 @@ public class IdSet extends TIntHashSet implements RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { return IdSet.this.contains(id); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java index 3618cb97e32e..1bdb1e42ce14 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/RandomAccessIntContainer.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; /** @@ -25,7 +26,7 @@ interface RandomAccessIntContainer { boolean add(int value); boolean remove(int value); ValueContainer.IntIterator intIterator(); - ValueContainer.IntPredicate intPredicate(); + IntPredicate intPredicate(); void compact(); int size(); diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java index fdb459784761..2bd87c729310 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java +++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/SortedIdSet.java @@ -15,6 +15,7 @@ */ package com.intellij.util.indexing.containers; +import com.intellij.util.indexing.IntPredicate; import com.intellij.util.indexing.ValueContainer; import gnu.trove.TIntProcedure; @@ -94,8 +95,8 @@ public class SortedIdSet implements Cloneable, RandomAccessIntContainer { } @Override - public ValueContainer.IntPredicate intPredicate() { - return new ValueContainer.IntPredicate() { + public IntPredicate intPredicate() { + return new IntPredicate() { @Override public boolean contains(int id) { diff --git a/platform/indexing-api/src/com/intellij/util/indexing/DataIndexer.java b/platform/util/src/com/intellij/util/indexing/DataIndexer.java similarity index 100% rename from platform/indexing-api/src/com/intellij/util/indexing/DataIndexer.java rename to platform/util/src/com/intellij/util/indexing/DataIndexer.java diff --git a/platform/core-api/src/com/intellij/util/indexing/ID.java b/platform/util/src/com/intellij/util/indexing/ID.java similarity index 100% rename from platform/core-api/src/com/intellij/util/indexing/ID.java rename to platform/util/src/com/intellij/util/indexing/ID.java diff --git a/platform/indexing-api/src/com/intellij/util/indexing/IndexExtension.java b/platform/util/src/com/intellij/util/indexing/IndexExtension.java similarity index 100% rename from platform/indexing-api/src/com/intellij/util/indexing/IndexExtension.java rename to platform/util/src/com/intellij/util/indexing/IndexExtension.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java b/platform/util/src/com/intellij/util/indexing/InvertedIndex.java similarity index 69% rename from platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java rename to platform/util/src/com/intellij/util/indexing/InvertedIndex.java index 34b7937cb7a1..6cac01b5311a 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/AbstractIndex.java +++ b/platform/util/src/com/intellij/util/indexing/InvertedIndex.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -16,8 +16,7 @@ package com.intellij.util.indexing; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.util.Processor; +import com.intellij.openapi.util.Computable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,9 +24,19 @@ import org.jetbrains.annotations.Nullable; * @author Eugene Zhuravlev * Date: Dec 24, 2007 */ -public interface AbstractIndex { +public interface InvertedIndex { @NotNull ValueContainer getData(@NotNull Key key) throws StorageException; - boolean processAllKeys(@NotNull Processor processor, @NotNull GlobalSearchScope scope, @Nullable IdFilter idFilter) throws StorageException; + /** + * @param inputId *positive* id of content. + */ + @NotNull + Computable update(int inputId, @Nullable Input content); + + void flush() throws StorageException; + + void clear() throws StorageException; + + void dispose(); } diff --git a/platform/lang-impl/src/com/intellij/util/indexing/StorageException.java b/platform/util/src/com/intellij/util/indexing/StorageException.java similarity index 100% rename from platform/lang-impl/src/com/intellij/util/indexing/StorageException.java rename to platform/util/src/com/intellij/util/indexing/StorageException.java diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java b/platform/util/src/com/intellij/util/indexing/ValueContainer.java similarity index 74% rename from platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java rename to platform/util/src/com/intellij/util/indexing/ValueContainer.java index 983a4d257c63..2a4076885c1c 100644 --- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainer.java +++ b/platform/util/src/com/intellij/util/indexing/ValueContainer.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 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. @@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull; import java.io.DataOutput; import java.io.IOException; import java.util.Iterator; -import java.util.List; /** * @author Eugene Zhuravlev @@ -41,35 +40,16 @@ public abstract class ValueContainer { IntIterator createCopyInInitialState(); } - public interface IntPredicate { - boolean contains(int id); - } - - @NotNull - public abstract IntIterator getInputIdsIterator(Value value); - - @NotNull - public abstract IntPredicate getValueAssociationPredicate(Value value); - @NotNull public abstract ValueIterator getValueIterator(); public interface ValueIterator extends Iterator { @NotNull IntIterator getInputIdsIterator(); - - @NotNull - IntPredicate getValueAssociationPredicate(); - - Object getFileSetObject(); } - @NotNull - public abstract List toValueList(); - public abstract int size(); - public interface ContainerAction { boolean perform(int id, T value); } @@ -84,15 +64,5 @@ public abstract class ValueContainer { return true; } - private volatile boolean myNeedsCompacting; - - boolean needsCompacting() { - return myNeedsCompacting; - } - - void setNeedsCompacting(boolean value) { - myNeedsCompacting = value; - } - public abstract void saveTo(DataOutput out, DataExternalizer externalizer) throws IOException; } From 76b697148cdf50a6bc33810d9c2ea2d8097cc0b3 Mon Sep 17 00:00:00 2001 From: Rustam Vishnyakov Date: Wed, 23 Nov 2016 13:32:18 +0300 Subject: [PATCH 10/37] Css tests fixed --- .../src/com/intellij/lang/folding/CustomFoldingBuilder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java index be3fd5f63435..38e7384b0e5c 100644 --- a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java +++ b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java @@ -213,7 +213,8 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements P } public final boolean isCustomFoldingCandidate(@NotNull PsiElement element) { - return isCustomFoldingCandidate(element.getNode()); + ASTNode node = element.getNode(); + return node != null && isCustomFoldingCandidate(node); } /** From 87d9169d09190f9e2d5642ec0ea07c1c5142ee4c Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Wed, 23 Nov 2016 10:52:31 +0100 Subject: [PATCH 11/37] postpone check for accessible to prevent access to another (lombok) index (IDEA-159135) [^peter] --- .../com/intellij/psi/impl/java/ReferenceChainLink.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java b/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java index 15ccb80fa2b0..31c6527bc090 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/java/ReferenceChainLink.java @@ -29,8 +29,11 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; /** * @author peter @@ -83,8 +86,7 @@ public class ReferenceChainLink { List candidates = new ArrayList<>(); AtomicInteger count = new AtomicInteger(); Processor processor = member -> { - if (canBeAccessible(placeFile, member) && (!(member instanceof PsiMethod) || - ApproximateResolver.canHaveArgCount((PsiMethod)member, argCount))) { + if (!(member instanceof PsiMethod && !ApproximateResolver.canHaveArgCount((PsiMethod)member, argCount))) { candidates.add(member); } return count.incrementAndGet() < 42; @@ -112,7 +114,7 @@ public class ReferenceChainLink { return null; } - return candidates; + return candidates.stream().filter(candidate -> canBeAccessible(placeFile, candidate)).collect(Collectors.toList()); } private static boolean canBeAccessible(VirtualFile placeFile, PsiMember member) { From 049a253fdf73fa39509f5f45c7dea2276849f080 Mon Sep 17 00:00:00 2001 From: "Anna.Kozlova" Date: Wed, 23 Nov 2016 11:51:57 +0100 Subject: [PATCH 12/37] inference: don't erase types when target type is parameterized with unbounded wildcards only, in this case no unchecked warning would be generated and the types won't be affected by unchecked warning clause --- .../ExpressionCompatibilityConstraint.java | 3 +- ...perTypeExpressionConstraintResolution.java | 37 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 79b1c1151bbb..8112b4d60872 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.graphInference.constraints; +import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; @@ -51,7 +52,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm final PsiType type = myExpression.getType(); session.registerIncompatibleErrorMessage((type != null ? type.getPresentableText() : myExpression.getText()) + " is not compatible with " + session.getPresentableText(myT)); } - else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType)) { + else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType) && !JavaGenericsUtil.isReifiableType(myT)) { session.setErasedDuringApplicabilityCheck(); } return assignmentCompatible; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java index 4d85bb7bce2a..4382aeba2e9e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/UncheckedConversionDuringProperTypeExpressionConstraintResolution.java @@ -1,3 +1,4 @@ +import java.util.function.Consumer; class Test { private static AG foo(Class clz) { return (AG) foo1(clz); @@ -15,3 +16,39 @@ class Test { } +class Test1 { + + static class D { + public D(Consumer c, Class cl) { + } + + static D create(Consumer c, Class ck) { + return new D<>(c, ck); + } + } + + { + Class c = D.class; + + D d = new D<>(s -> s.isEmpty(), c); + D d1 = D.create(s -> s.isEmpty(), c); + } +} +class Test2 { + + static class D { + public D(Consumer c, Class cl) { + } + + static D create(Consumer c, Class ck) { + return new D<>(c, ck); + } + } + + { + Class c = D.class; + + D d = new D<>(s -> s.isEmpty(), c); + D d1 = D.create(s -> s.isEmpty(), c); + } +} \ No newline at end of file From b80a13f05e1feb4f169bee6531cd19e79ee6d168 Mon Sep 17 00:00:00 2001 From: "Maxim.Kolmakov" Date: Wed, 23 Nov 2016 11:53:33 +0100 Subject: [PATCH 13/37] Fix link for kotlin plugin --- build/scripts/download_kotlin.gant | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/download_kotlin.gant b/build/scripts/download_kotlin.gant index 7fa565e439a7..c601a822034d 100644 --- a/build/scripts/download_kotlin.gant +++ b/build/scripts/download_kotlin.gant @@ -321,6 +321,6 @@ class TeamCityBuildLocator { String getDownloadUrl(String buildNumber) { String encodedBuildNumber = URLEncoder.encode(buildNumber, "UTF-8") - return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-${encodedBuildNumber}-IJ2016.3-1.zip" + return "$host/guestAuth/repository/download/$buildTypeId/$encodedBuildNumber/kotlin-plugin-1.0.5-release-IJ2016.3-2.zip" } } From e10506857cbc496b7e10d8e5681e2f67a3879b27 Mon Sep 17 00:00:00 2001 From: "Liana.Bakradze" Date: Wed, 23 Nov 2016 14:01:09 +0300 Subject: [PATCH 14/37] EDU-791 Subtasks: undo "Hide from prev subtasks" can break a course --- .../placeholder/CCChangePlaceholderVisibility.java | 9 +++++++-- .../com/jetbrains/edu/learning/StudySubtaskUtils.java | 8 +++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java index eb0c7dfde710..2366f569acbc 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCChangePlaceholderVisibility.java @@ -2,6 +2,7 @@ package com.jetbrains.edu.coursecreator.actions.placeholder; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.command.UndoConfirmationPolicy; import com.intellij.openapi.command.undo.BasicUndoableAction; import com.intellij.openapi.command.undo.UnexpectedUndoException; import com.intellij.openapi.editor.Document; @@ -39,7 +40,7 @@ public abstract class CCChangePlaceholderVisibility extends CCAnswerPlaceholderA public void redo() throws UnexpectedUndoException { setVisible(placeholder, !isVisible(), state); } - }); + }, UndoConfirmationPolicy.REQUEST_CONFIRMATION); } private void setVisible(AnswerPlaceholder placeholder, boolean visible, CCState state) { @@ -97,10 +98,14 @@ public abstract class CCChangePlaceholderVisibility extends CCAnswerPlaceholderA return; } Integer minSubtaskIndex = Collections.min(placeholder.getSubtaskInfos().keySet()); - if (placeholder.isActive() && minSubtaskIndex != 0 && minSubtaskIndex == task.getActiveSubtaskIndex() && isAvailable(placeholder)) { + if (canChangeState(placeholder, task, minSubtaskIndex)) { presentation.setEnabledAndVisible(true); } } + private boolean canChangeState(@NotNull AnswerPlaceholder placeholder, @NotNull Task task, int minSubtaskIndex) { + return placeholder.isActive() && minSubtaskIndex != 0 && minSubtaskIndex == task.getActiveSubtaskIndex() && isAvailable(placeholder); + } + protected abstract boolean isAvailable(AnswerPlaceholder placeholder); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java index 6d3ee722f530..6ff9d92a21cf 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java @@ -2,6 +2,8 @@ package com.jetbrains.edu.learning; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.undo.DocumentReferenceManager; +import com.intellij.openapi.command.undo.UndoManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; @@ -56,7 +58,8 @@ public class StudySubtaskUtils { if (document == null) { continue; } - updatePlaceholderTexts(project, document, taskFile, fromSubtaskIndex, toSubtaskIndex); + updatePlaceholderTexts(document, taskFile, fromSubtaskIndex, toSubtaskIndex); + UndoManager.getInstance(project).nonundoableActionPerformed(DocumentReferenceManager.getInstance().create(document), false); EditorNotifications.getInstance(project).updateNotifications(virtualFile); if (StudyUtils.isStudentProject(project)) { WolfTheProblemSolver.getInstance(project).clearProblems(virtualFile); @@ -112,8 +115,7 @@ public class StudySubtaskUtils { } } - private static void updatePlaceholderTexts(@NotNull Project project, - @NotNull Document document, + private static void updatePlaceholderTexts(@NotNull Document document, @NotNull TaskFile taskFile, int fromSubtaskIndex, int toSubtaskIndex) { From bdada4021d0a4701c7437b9ec556ae0e4ee8acfc Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Wed, 23 Nov 2016 14:12:32 +0300 Subject: [PATCH 15/37] Tab completion does not work in Debugger Python Console (PY-21504) Reuse tab completion from integrated Python console --- .../python/console/PyConsoleUtil.java | 47 ++++++++++++++++++- .../console/PydevConsoleRunnerImpl.java | 45 +----------------- .../PythonDebugLanguageConsoleView.java | 8 ++++ 3 files changed, 55 insertions(+), 45 deletions(-) diff --git a/python/src/com/jetbrains/python/console/PyConsoleUtil.java b/python/src/com/jetbrains/python/console/PyConsoleUtil.java index a2218e70270e..064b4186dabb 100644 --- a/python/src/com/jetbrains/python/console/PyConsoleUtil.java +++ b/python/src/com/jetbrains/python/console/PyConsoleUtil.java @@ -15,17 +15,26 @@ */ package com.jetbrains.python.console; +import com.google.common.base.CharMatcher; +import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.execution.console.LanguageConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.Key; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.jetbrains.python.console.parsing.PythonConsoleData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.awt.event.KeyEvent; + /** * @author traff */ @@ -146,6 +155,42 @@ public class PyConsoleUtil { PythonConsoleData consoleData = getOrCreateIPythonData(file); consoleData.setIndentSize(indentSize); } + + public static AnAction createTabCompletionAction(PythonConsoleView consoleView) { + final AnAction runCompletions = new AnAction() { + @Override + public void actionPerformed(AnActionEvent e) { + Editor editor = consoleView.getConsoleEditor(); + if (LookupManager.getActiveLookup(editor) != null) { + AnAction replace = ActionManager.getInstance().getAction("EditorChooseLookupItemReplace"); + ActionUtil.performActionDumbAware(replace, e); + return; + } + AnAction completionAction = ActionManager.getInstance().getAction("CodeCompletion"); + if (completionAction != null) { + ActionUtil.performActionDumbAware(completionAction, e); + } + } + + @Override + public void update(AnActionEvent e) { + Editor editor = consoleView.getConsoleEditor(); + if (LookupManager.getActiveLookup(editor) != null) { + e.getPresentation().setEnabled(false); + } + int offset = editor.getCaretModel().getOffset(); + Document document = editor.getDocument(); + int lineStart = document.getLineStartOffset(document.getLineNumber(offset)); + String textToCursor = document.getText(new TextRange(lineStart, offset)); + e.getPresentation().setEnabled(!CharMatcher.WHITESPACE.matchesAllOf(textToCursor)); + } + }; + + runCompletions + .registerCustomShortcutSet(KeyEvent.VK_TAB, 0, consoleView.getConsoleEditor().getComponent()); + runCompletions.getTemplatePresentation().setVisible(false); + return runCompletions; + } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java index 119a5db33531..ac650a4456ba 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunnerImpl.java @@ -17,7 +17,6 @@ package com.jetbrains.python.console; import com.google.common.base.CharMatcher; import com.google.common.collect.Lists; -import com.intellij.codeInsight.lookup.LookupManager; import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionHelper; import com.intellij.execution.ExecutionManager; @@ -42,14 +41,12 @@ import com.intellij.ide.CommonActionsManager; import com.intellij.ide.errorTreeView.NewErrorTreeViewPanel; import com.intellij.internal.statistic.UsageTrigger; import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Caret; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; @@ -69,7 +66,6 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.io.StreamUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; @@ -211,7 +207,7 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { actions.add(0, createRerunAction()); actions.add(createInterruptAction()); - actions.add(createTabCompletionAction()); + actions.add(PyConsoleUtil.createTabCompletionAction(myConsoleView)); actions.add(createSplitLineAction()); @@ -711,45 +707,6 @@ public class PydevConsoleRunnerImpl implements PydevConsoleRunner { return anAction; } - private AnAction createTabCompletionAction() { - final AnAction runCompletions = new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - - Editor editor = myConsoleView.getConsoleEditor(); - if (LookupManager.getActiveLookup(editor) != null) { - AnAction replace = ActionManager.getInstance().getAction("EditorChooseLookupItemReplace"); - ActionUtil.performActionDumbAware(replace, e); - return; - } - AnAction completionAction = ActionManager.getInstance().getAction("CodeCompletion"); - if (completionAction == null) { - return; - } - ActionUtil.performActionDumbAware(completionAction, e); - } - - @Override - public void update(AnActionEvent e) { - Editor editor = myConsoleView.getConsoleEditor(); - if (LookupManager.getActiveLookup(editor) != null) { - e.getPresentation().setEnabled(false); - } - int offset = editor.getCaretModel().getOffset(); - Document document = editor.getDocument(); - int lineStart = document.getLineStartOffset(document.getLineNumber(offset)); - String textToCursor = document.getText(new TextRange(lineStart, offset)); - e.getPresentation().setEnabled(!CharMatcher.WHITESPACE.matchesAllOf(textToCursor)); - } - }; - - runCompletions - .registerCustomShortcutSet(KeyEvent.VK_TAB, 0, myConsoleView.getConsoleEditor().getComponent()); - runCompletions.getTemplatePresentation().setVisible(false); - return runCompletions; - } - - private boolean isIndentSubstring(String text) { int indentSize = myConsoleExecuteActionHandler.getPythonIndent(); return text.length() >= indentSize && CharMatcher.WHITESPACE.matchesAllOf(text.substring(text.length() - indentSize)); diff --git a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java index d2d5257c3e5c..4a64d5f8e671 100644 --- a/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java +++ b/python/src/com/jetbrains/python/console/PythonDebugLanguageConsoleView.java @@ -19,16 +19,21 @@ import com.intellij.execution.console.DuplexConsoleView; import com.intellij.execution.filters.TextConsoleBuilderFactory; import com.intellij.execution.impl.ConsoleViewImpl; import com.intellij.execution.process.ProcessOutputTypes; +import com.intellij.execution.runners.AbstractConsoleRunnerWithHistory; import com.intellij.execution.ui.ConsoleView; +import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.wm.IdeFocusManager; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyBundle; import icons.PythonIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + /** * @author traff */ @@ -44,6 +49,9 @@ public class PythonDebugLanguageConsoleView extends DuplexConsoleView actions = ContainerUtil.newArrayList(PyConsoleUtil.createTabCompletionAction(getPydevConsoleView())); + AbstractConsoleRunnerWithHistory.registerActionShortcuts(actions, getPydevConsoleView().getEditor().getComponent()); } public PythonDebugLanguageConsoleView(final Project project, Sdk sdk) { From 986a98eee19b72a417427b33cd8360cfbceb05e3 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Nov 2016 17:53:03 +0300 Subject: [PATCH 16/37] Update length properly after editing answer placeholder --- .../actions/placeholder/CCEditAnswerPlaceholder.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java index 11fac1e9b018..103ef2e4557b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/placeholder/CCEditAnswerPlaceholder.java @@ -3,6 +3,7 @@ package com.jetbrains.edu.coursecreator.actions.placeholder; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.jetbrains.edu.learning.courseFormat.AnswerPlaceholder; @@ -29,7 +30,9 @@ public class CCEditAnswerPlaceholder extends CCAnswerPlaceholderAction { CCCreateAnswerPlaceholderDialog dlg = new CCCreateAnswerPlaceholderDialog(project, answerPlaceholder.getTaskText(), answerPlaceholder.getHints()); dlg.setTitle("Edit Answer Placeholder"); if (dlg.showAndGet()) { - answerPlaceholder.setTaskText(dlg.getTaskText()); + final String answerPlaceholderText = dlg.getTaskText(); + answerPlaceholder.setTaskText(answerPlaceholderText); + answerPlaceholder.setLength(StringUtil.notNullize(answerPlaceholderText).length()); answerPlaceholder.setHints(dlg.getHints()); } } From 0935834d85900a6fae2a0365df4bcdf75c806713 Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Tue, 22 Nov 2016 18:23:22 +0300 Subject: [PATCH 17/37] Added inner directories support to the educational edition --- .../CCRefactoringElementListenerProvider.java | 10 +-- .../jetbrains/edu/coursecreator/CCUtils.java | 2 +- .../coursecreator/CCVirtualFileListener.java | 14 ++--- .../actions/CCAddAsTaskFile.java | 5 +- .../actions/CCCreateCourseArchive.java | 2 +- .../actions/CCFromCourseArchive.java | 2 +- .../actions/CCHideFromStudent.java | 8 +-- .../projectView/CCCourseDirectoryNode.java | 4 +- .../projectView/CCDirectoryNode.java | 62 +++++++++++++++++++ .../projectView/CCLessonDirectoryNode.java | 4 +- .../projectView/CCTaskDirectoryNode.java | 7 +++ .../learning/StudyBasePluginConfigurator.java | 4 +- .../edu/learning/StudyProjectComponent.java | 6 +- .../jetbrains/edu/learning/StudyState.java | 2 +- .../edu/learning/StudySubtaskUtils.java | 2 +- .../jetbrains/edu/learning/StudyUtils.java | 56 ++++++++++------- .../actions/StudyEditInputAction.java | 6 +- .../edu/learning/checker/StudyCheckTask.java | 2 +- .../edu/learning/checker/StudyCheckUtils.java | 10 +-- .../learning/checker/StudySmartChecker.java | 6 +- .../jetbrains/edu/learning/core/EduUtils.java | 17 ++--- .../courseGeneration/StudyGenerator.java | 8 +-- .../StudyProjectGenerator.java | 4 +- .../learning/navigation/StudyNavigator.java | 4 +- .../projectView/CourseDirectoryNode.java | 3 +- .../learning/projectView/DirectoryNode.java | 57 +++++++++++++++++ .../projectView/LessonDirectoryNode.java | 3 +- .../projectView/SandboxDirectoryNode.java | 3 +- .../projectView/StudyDirectoryNode.java | 4 +- .../projectView/TaskDirectoryNode.java | 9 ++- .../stepic/EduAdaptiveStepicConnector.java | 8 +-- .../edu/learning/stepic/StepicWrappers.java | 2 +- .../edu/learning/ui/StudyToolWindow.java | 2 +- .../fileTemplates/internal/test_helper.py.ft | 11 ++-- .../edu/learning/PyStudyCheckAction.java | 2 +- 35 files changed, 247 insertions(+), 104 deletions(-) create mode 100644 python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java create mode 100644 python/educational-core/student/src/com/jetbrains/edu/learning/projectView/DirectoryNode.java diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java index 86121ab4340f..f26eda11b698 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCRefactoringElementListenerProvider.java @@ -50,20 +50,20 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL static class CCRenameListener extends RefactoringElementAdapter { - private String myElementName; + private String myElementRelativePath; public CCRenameListener(PsiElement element) { if (element instanceof PsiFile) { PsiFile psiFile = (PsiFile)element; - myElementName = psiFile.getName(); + myElementRelativePath = StudyUtils.pathRelativeToTask(psiFile.getVirtualFile()); } } @Override protected void elementRenamedOrMoved(@NotNull PsiElement newElement) { - if (newElement instanceof PsiFile && myElementName != null) { + if (newElement instanceof PsiFile && myElementRelativePath != null) { PsiFile psiFile = (PsiFile)newElement; - tryToRenameTaskFile(psiFile, myElementName); + tryToRenameTaskFile(psiFile, myElementRelativePath); } } @@ -107,7 +107,7 @@ public class CCRefactoringElementListenerProvider implements RefactoringElementL }); taskFiles.remove(oldName); - taskFiles.put(file.getName(), taskFile); + taskFiles.put(StudyUtils.pathRelativeToTask(file.getVirtualFile()), taskFile); CCUtils.createResourceFile(file.getVirtualFile(), course, taskDir.getVirtualFile()); } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java index 2dd6270f5d67..5d93a6191abc 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCUtils.java @@ -266,7 +266,7 @@ public class CCUtils { } for (Map.Entry entry : task.getTaskFiles().entrySet()) { String name = entry.getKey(); - VirtualFile answerFile = taskDir.findChild(name); + VirtualFile answerFile = taskDir.findFileByRelativePath(name); if (answerFile == null) { continue; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java index c34c6260669f..e1dc9fc980fd 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/CCVirtualFileListener.java @@ -44,7 +44,7 @@ public class CCVirtualFileListener extends VirtualFileAdapter { return; } - String name = createdFile.getName(); + String taskRelativePath = StudyUtils.pathRelativeToTask(createdFile); CCLanguageManager manager = CCUtils.getStudyLanguageManager(course); if (manager != null && manager.doNotPackFile(new File(createdFile.getPath()))) { @@ -52,10 +52,10 @@ public class CCVirtualFileListener extends VirtualFileAdapter { } if (CCUtils.isTestsFile(project, createdFile) - || StudyUtils.isTaskDescriptionFile(name) - || name.contains(EduNames.WINDOW_POSTFIX) - || name.contains(EduNames.WINDOWS_POSTFIX) - || name.contains(EduNames.ANSWERS_POSTFIX)) { + || StudyUtils.isTaskDescriptionFile(taskRelativePath) + || taskRelativePath.contains(EduNames.WINDOW_POSTFIX) + || taskRelativePath.contains(EduNames.WINDOWS_POSTFIX) + || taskRelativePath.contains(EduNames.ANSWERS_POSTFIX)) { return; } VirtualFile taskVF = StudyUtils.getTaskDir(createdFile); @@ -69,7 +69,7 @@ public class CCVirtualFileListener extends VirtualFileAdapter { CCUtils.createResourceFile(createdFile, course, taskVF); - task.addTaskFile(name, 1); + task.addTaskFile(taskRelativePath, 1); } @Override @@ -136,6 +136,6 @@ public class CCVirtualFileListener extends VirtualFileAdapter { if (task == null) { return; } - task.getTaskFiles().remove(removedTaskFile.getName()); + task.getTaskFiles().remove(StudyUtils.pathRelativeToTask(removedTaskFile)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java index 925bc592fea3..457970c95746 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCAddAsTaskFile.java @@ -55,8 +55,9 @@ public class CCAddAsTaskFile extends CCTaskFileActionBase { if (myTaskFile != null) { myTask.addTaskFile(myTaskFile); } else { - myTask.addTaskFile(myFile.getName(), myTask.getTaskFiles().size()); - myTaskFile = myTask.getTaskFile(myFile.getName()); + final String taskRelativePath = StudyUtils.pathRelativeToTask(myFile); + myTask.addTaskFile(taskRelativePath, myTask.getTaskFiles().size()); + myTaskFile = myTask.getTaskFile(taskRelativePath); } CCUtils.createResourceFile(myFile, myCourse, StudyUtils.getTaskDir(myFile)); ProjectView.getInstance(myProject).refresh(); diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java index 244a0b984384..425ba8a1ea99 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCCreateCourseArchive.java @@ -137,7 +137,7 @@ public class CCCreateCourseArchive extends DumbAwareAction { transformSubtaskTestsToTextFiles(studentFileDir); } for (String taskFile : task.getTaskFiles().keySet()) { - VirtualFile answerFile = taskDir.findChild(taskFile); + VirtualFile answerFile = taskDir.findFileByRelativePath(taskFile); if (answerFile == null) { continue; } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java index 91e13d9314d0..1f5a02a45d7d 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCFromCourseArchive.java @@ -130,7 +130,7 @@ public class CCFromCourseArchive extends DumbAwareAction { @NotNull final Map.Entry taskFileEntry) { final String name = taskFileEntry.getKey(); final TaskFile taskFile = taskFileEntry.getValue(); - VirtualFile file = userFileDir.findChild(name); + VirtualFile file = userFileDir.findFileByRelativePath(name); assert file != null; final Document originDocument = FileDocumentManager.getInstance().getDocument(file); if (originDocument == null) { diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java index b183eeda7b38..45496606bfe8 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/actions/CCHideFromStudent.java @@ -58,7 +58,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase { @Override public void undo() throws UnexpectedUndoException { - myTask.getTaskFiles().put(myFile.getName(), myTaskFile); + myTask.getTaskFiles().put(StudyUtils.pathRelativeToTask(myFile), myTaskFile); CCUtils.createResourceFile(myFile, myCourse, StudyUtils.getTaskDir(myFile)); if (!myTaskFile.getAnswerPlaceholders().isEmpty() && FileEditorManager.getInstance(myProject).isFileOpen(myFile)) { for (FileEditor fileEditor : FileEditorManager.getInstance(myProject).getEditors(myFile)) { @@ -92,8 +92,8 @@ public class CCHideFromStudent extends CCTaskFileActionBase { } } } - String name = file.getName(); - VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, name); + String taskRelativePath = StudyUtils.pathRelativeToTask(file); + VirtualFile patternFile = StudyUtils.getPatternFile(taskFile, taskRelativePath); ApplicationManager.getApplication().runWriteAction(() -> { if (patternFile != null) { try { @@ -104,7 +104,7 @@ public class CCHideFromStudent extends CCTaskFileActionBase { } } }); - taskFiles.remove(name); + taskFiles.remove(taskRelativePath); } @Override diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java index 04cd3f4b051c..bb06f8e8741b 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCCourseDirectoryNode.java @@ -1,6 +1,7 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; @@ -11,7 +12,6 @@ import com.jetbrains.edu.learning.courseFormat.Course; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.projectView.CourseDirectoryNode; -import com.jetbrains.edu.learning.projectView.StudyDirectoryNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -45,7 +45,7 @@ public class CCCourseDirectoryNode extends CourseDirectoryNode { } @Override - public StudyDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { return new CCLessonDirectoryNode(myProject, directory, myViewSettings, ((Lesson)item)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java new file mode 100644 index 000000000000..28334c43f9a8 --- /dev/null +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCDirectoryNode.java @@ -0,0 +1,62 @@ +package com.jetbrains.edu.coursecreator.projectView; + +import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; +import com.intellij.ide.util.treeView.AbstractTreeNode; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.edu.coursecreator.CCUtils; +import com.jetbrains.edu.learning.StudyLanguageManager; +import com.jetbrains.edu.learning.StudyTaskManager; +import com.jetbrains.edu.learning.StudyUtils; +import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.StudyItem; +import com.jetbrains.edu.learning.projectView.DirectoryNode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class CCDirectoryNode extends DirectoryNode { + public CCDirectoryNode(@NotNull Project project, + PsiDirectory value, + ViewSettings viewSettings) { + super(project, value, viewSettings); + } + + @Override + public boolean canNavigate() { + return true; + } + + @Nullable + @Override + public AbstractTreeNode modifyChildNode(AbstractTreeNode childNode) { + final AbstractTreeNode node = super.modifyChildNode(childNode); + if (node != null) return node; + Object value = childNode.getValue(); + if (value instanceof PsiElement) { + PsiFile psiFile = ((PsiElement) value).getContainingFile(); + VirtualFile virtualFile = psiFile.getVirtualFile(); + + Course course = StudyTaskManager.getInstance(myProject).getCourse(); + if (course == null) { + return null; + } + StudyLanguageManager manager = StudyUtils.getLanguageManager(course); + if (manager == null) { + return new CCStudentInvisibleFileNode(myProject, psiFile, myViewSettings); + } + if (!CCUtils.isTestsFile(myProject, virtualFile)) { + return new CCStudentInvisibleFileNode(myProject, psiFile, myViewSettings); + } + } + return null; + } + + @Override + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory value) { + return new CCDirectoryNode(myProject, value, myViewSettings); + } +} diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java index 1be30f7613cb..07fef6bd43d2 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCLessonDirectoryNode.java @@ -1,13 +1,13 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiDirectory; import com.jetbrains.edu.learning.courseFormat.Lesson; import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.projectView.LessonDirectoryNode; -import com.jetbrains.edu.learning.projectView.StudyDirectoryNode; import org.jetbrains.annotations.NotNull; public class CCLessonDirectoryNode extends LessonDirectoryNode { @@ -19,7 +19,7 @@ public class CCLessonDirectoryNode extends LessonDirectoryNode { } @Override - public StudyDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory directory) { return new CCTaskDirectoryNode(myProject, directory, myViewSettings, ((Task)item)); } } diff --git a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java index 69a7b664b840..93d9ca6bec11 100644 --- a/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java +++ b/python/educational-core/course-creator/src/com/jetbrains/edu/coursecreator/projectView/CCTaskDirectoryNode.java @@ -1,6 +1,7 @@ package com.jetbrains.edu.coursecreator.projectView; import com.intellij.ide.projectView.ViewSettings; +import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; @@ -14,6 +15,7 @@ import com.jetbrains.edu.learning.StudyTaskManager; import com.jetbrains.edu.learning.StudyUtils; import com.jetbrains.edu.learning.core.EduNames; import com.jetbrains.edu.learning.courseFormat.Course; +import com.jetbrains.edu.learning.courseFormat.StudyItem; import com.jetbrains.edu.learning.courseFormat.Task; import com.jetbrains.edu.learning.projectView.TaskDirectoryNode; import org.jetbrains.annotations.NotNull; @@ -95,4 +97,9 @@ public class CCTaskDirectoryNode extends TaskDirectoryNode { int stepIndex = Integer.valueOf(nameWithoutExtension.substring(EduNames.SUBTASK_MARKER.length() + stepMarkerStart)); return stepIndex == myTask.getActiveSubtaskIndex(); } + + @Override + public PsiDirectoryNode createChildDirectoryNode(StudyItem item, PsiDirectory value) { + return new CCDirectoryNode(myProject, value, myViewSettings); + } } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java index 328d2e462294..2764d192f3a9 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyBasePluginConfigurator.java @@ -51,7 +51,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur @Override public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) { Task task = getTask(file); - setTaskText(task, file.getParent()); + setTaskText(task, StudyUtils.getTaskDir(file)); } @Override @@ -69,7 +69,7 @@ public abstract class StudyBasePluginConfigurator implements StudyPluginConfigur VirtualFile file = event.getNewFile(); if (file != null) { Task task = getTask(file); - setTaskText(task, file.getParent()); + setTaskText(task, StudyUtils.getTaskDir(file)); } toolWindow.setBottomComponent(null); } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java index 18c21ff1e270..8b81440ed71d 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyProjectComponent.java @@ -224,7 +224,7 @@ public class StudyProjectComponent implements ProjectComponent { private static void copyFile(@NotNull final File from, @NotNull final File to) { if (from.exists()) { try { - FileUtil.copy(from, to); + FileUtil.copyFileOrDir(from, to); } catch (IOException e) { LOG.warn("Failed to copy " + from.getName()); @@ -326,7 +326,7 @@ public class StudyProjectComponent implements ProjectComponent { public void fileCreated(@NotNull VirtualFileEvent event) { if (myProject.isDisposed()) return; final VirtualFile createdFile = event.getFile(); - final VirtualFile taskDir = createdFile.getParent(); + final VirtualFile taskDir = StudyUtils.getTaskDir(createdFile); final Course course = StudyTaskManager.getInstance(myProject).getCourse(); if (course == null || !EduNames.STUDY.equals(course.getCourseMode())) { return; @@ -345,7 +345,7 @@ public class StudyProjectComponent implements ProjectComponent { final TaskFile taskFile = new TaskFile(); taskFile.initTaskFile(task, false); taskFile.setUserCreated(true); - final String name = createdFile.getName(); + final String name = FileUtil.getRelativePath(taskDir.getPath(), createdFile.getPath(), File.separatorChar); taskFile.name = name; //TODO: put to other steps as well task.getTaskFiles().put(name, taskFile); diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java index f4cb42a1340c..26706b25339c 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyState.java @@ -21,7 +21,7 @@ public class StudyState { myEditor = studyEditor != null ? studyEditor.getEditor() : null; myTaskFile = studyEditor != null ? studyEditor.getTaskFile() : null; myVirtualFile = myEditor != null ? FileDocumentManager.getInstance().getFile(myEditor.getDocument()) : null; - myTaskDir = myVirtualFile != null ? myVirtualFile.getParent() : null; + myTaskDir = myVirtualFile != null ? StudyUtils.getTaskDir(myVirtualFile) : null; myTask = myTaskFile != null ? myTaskFile.getTask() : null; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java index 6ff9d92a21cf..e3eb2d4892eb 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudySubtaskUtils.java @@ -49,7 +49,7 @@ public class StudySubtaskUtils { int fromSubtaskIndex = task.getActiveSubtaskIndex(); for (Map.Entry entry : task.getTaskFiles().entrySet()) { String name = entry.getKey(); - VirtualFile virtualFile = taskDir.findChild(name); + VirtualFile virtualFile = taskDir.findFileByRelativePath(name); if (virtualFile == null) { continue; } diff --git a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java index 5186c3e57d95..960f3acc60d1 100644 --- a/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java +++ b/python/educational-core/student/src/com/jetbrains/edu/learning/StudyUtils.java @@ -82,7 +82,6 @@ public class StudyUtils { } private static final Logger LOG = Logger.getInstance(StudyUtils.class.getName()); - private static final String EMPTY_TASK_TEXT = "Please, open any task to see task description"; private static final String ourPrefix = "