diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java index dc81e12c3030..974258537298 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpCompletionContributor.java @@ -97,6 +97,12 @@ public final class RegExpCompletionContributor extends CompletionContributor { final ElementPattern propertyNamePattern = psiElement().afterLeaf(psiElement().withText("{").afterLeaf(propertyPattern)); extend(CompletionType.BASIC, propertyNamePattern, new PropertyNameCompletionProvider()); + + final PsiElementPattern.Capture namedCharacterPattern = psiElement().withText("N"); + extend(CompletionType.BASIC, psiElement().afterLeaf(namedCharacterPattern), + new NamedCharacterCompletionProvider(true)); + extend(CompletionType.BASIC, psiElement().afterLeaf(psiElement(RegExpTT.LBRACE).afterLeaf(namedCharacterPattern)), + new NamedCharacterCompletionProvider(false)); } } diff --git a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java index 5b6e3305ba6d..493c0f76b24e 100644 --- a/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java +++ b/RegExpSupport/src/org/intellij/lang/regexp/RegExpLanguageHosts.java @@ -15,11 +15,11 @@ */ package org.intellij.lang.regexp; -import com.intellij.lang.injection.InjectedLanguageManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.util.ClassExtension; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.FileContextUtil; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.intellij.lang.regexp.psi.*; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -51,36 +51,19 @@ public final class RegExpLanguageHosts extends ClassExtension null") @Nullable private static RegExpLanguageHost findRegExpHost(@Nullable final PsiElement element) { - if (ApplicationManager.getApplication().isUnitTestMode() && myHost != null) { - return myHost; - } if (element == null) { return null; } - PsiLanguageInjectionHost injectionHost = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element); - final RegExpLanguageHost host = getRegExpHost(injectionHost); - if (host != null) { - return host; + if (ApplicationManager.getApplication().isUnitTestMode() && myHost != null) { + return myHost; } final PsiFile file = element.getContainingFile(); - final SmartPsiElementPointer pointer = file.getUserData(FileContextUtil.INJECTED_IN_ELEMENT); - if (pointer == null) { - return null; + final PsiElement context = file.getContext(); + if (context instanceof RegExpLanguageHost) { + return (RegExpLanguageHost)context; } - final PsiElement pointerElement = pointer.getElement(); - if (pointerElement == null) { - return null; - } - return getRegExpHost(pointerElement); - } - - @Nullable - private static RegExpLanguageHost getRegExpHost(@Nullable PsiElement languageInjectionHostElement) { - if (languageInjectionHostElement instanceof RegExpLanguageHost) { - return (RegExpLanguageHost)languageInjectionHostElement; - } - if (languageInjectionHostElement != null) { - return INSTANCE.forClass(languageInjectionHostElement.getClass()); + if (context != null) { + return INSTANCE.forClass(context.getClass()); } return null; } @@ -171,7 +154,6 @@ public final class RegExpLanguageHosts extends ClassExtension>> 8, index & 0xff, AsciiUtil.ASCII_CHARSET); consumer.accept(name); } diff --git a/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java b/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java index 3ba88ab02baa..abdee64fbc05 100644 --- a/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java +++ b/RegExpSupport/test/org/intellij/lang/regexp/RegExpCompletionTest.java @@ -15,9 +15,11 @@ */ package org.intellij.lang.regexp; +import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.application.PathManager; import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; import java.io.File; import java.util.ArrayList; @@ -57,6 +59,17 @@ public class RegExpCompletionTest extends CodeInsightFixtureTestCase { myFixture.checkResult("[[:^alpha:]"); } + public void testNamedCharacter() { + myFixture.configureByText(RegExpFileType.INSTANCE, "\\\\N{SMILE}"); + final LookupElement[] elements = myFixture.completeBasic(); + final List strings = ContainerUtil.map(elements, LookupElement::getLookupString); + assertEquals(Arrays.asList("SMILE", "SMILING FACE WITH SMILING EYES", "SMILING FACE WITH HEART-SHAPED EYES", + "SMILING CAT FACE WITH HEART-SHAPED EYES", "SMILING FACE WITH OPEN MOUTH AND SMILING EYES", + "SMILING FACE WITH OPEN MOUTH AND TIGHTLY-CLOSED EYES", "CAT FACE WITH WRY SMILE", + "GRINNING CAT FACE WITH SMILING EYES", "GRINNING FACE WITH SMILING EYES", + "KISSING FACE WITH SMILING EYES"), strings); + } + public void testBackSlashVariants() throws Throwable { List nameList = new ArrayList<>(Arrays.asList("d", "D", "s", "S", "w", "W", "b", "B", "A", "G", "Z", "z", "Q", "E", diff --git a/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy b/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy index aababf51b22b..121e52b0b0c4 100644 --- a/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy +++ b/build/groovy/org/jetbrains/intellij/build/BuildContext.groovy @@ -65,6 +65,12 @@ abstract class BuildContext { abstract boolean includeBreakGenLibraries() + /** + * If the method returns {@code false} 'idea.jars.nocopy' property will be set to {@code true} in idea.properties by default. Otherwise it + * won't be set and the IDE will copy library *.jar files to avoid their locking when running under Windows. + */ + abstract boolean shouldIDECopyJarsByDefault() + abstract void patchInspectScript(String path) abstract String getAdditionalJvmArguments() diff --git a/build/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy b/build/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy index 56199beed166..47a6c04b73fb 100644 --- a/build/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy +++ b/build/groovy/org/jetbrains/intellij/build/CommunityRepositoryModules.groovy @@ -178,6 +178,7 @@ class CommunityRepositoryModules { plugin("course-creator"), plugin("course-creator-python"), plugin("ipnb"), - plugin("IntelliLang-python") + plugin("IntelliLang-python"), + plugin("python-rest") ] } \ No newline at end of file diff --git a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy index 8302320628e9..d7316081fb6e 100644 --- a/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy +++ b/build/groovy/org/jetbrains/intellij/build/WindowsDistributionCustomizer.groovy @@ -78,7 +78,7 @@ abstract class WindowsDistributionCustomizer { /** * The returned name will be used to create links on Desktop */ - String fullNameIncludingEditionAndVendor(ApplicationInfoProperties applicationInfo) { applicationInfo.shortCompanyName + " " + applicationInfo.productName } + String fullNameIncludingEditionAndVendor(ApplicationInfoProperties applicationInfo) { applicationInfo.shortCompanyName + " " + fullNameIncludingEdition(applicationInfo) } String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) { return null diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy index b741ca5fdbbe..5fe53ef1e029 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BuildContextImpl.groovy @@ -259,8 +259,18 @@ class BuildContextImpl extends BuildContext { @Override boolean includeBreakGenLibraries() { + return isJavaSupportedInProduct() + } + + @Override + boolean shouldIDECopyJarsByDefault() { + return isJavaSupportedInProduct() + } + + private boolean isJavaSupportedInProduct() { def productLayout = productProperties.productLayout - return productLayout.mainJarName == null || //todo[nik] remove this condition later + return productLayout.mainJarName == null || + //todo[nik] remove this condition later; currently build scripts for IDEA don't fully migrated to the new scheme productLayout.includedPlatformModules.contains("execution-impl") } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy b/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy index 81592affda5e..6d03a54eca40 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/BuildTasksImpl.groovy @@ -84,7 +84,7 @@ class BuildTasksImpl extends BuildTasks { @Override void buildSearchableOptions(String targetModuleName, List modulesToIndex, List pathsToLicenses) { - buildSearchableOptions(new File(buildContext.projectBuilder.moduleOutput(buildContext.findModule(targetModuleName))), modulesToIndex, pathsToLicenses) + buildSearchableOptions(new File(buildContext.projectBuilder.moduleOutput(buildContext.findRequiredModule(targetModuleName))), modulesToIndex, pathsToLicenses) } //todo[nik] do we need 'cp' and 'jvmArgs' parameters? @@ -143,6 +143,14 @@ class BuildTasksImpl extends BuildTasks { File originalFile = new File("$buildContext.paths.communityHome/bin/idea.properties") String text = originalFile.text + if (!buildContext.shouldIDECopyJarsByDefault()) { + text += """ +#--------------------------------------------------------------------- +# IDE can copy library .jar files to prevent their locking. Set this property to 'false' to enable copying. +#--------------------------------------------------------------------- +idea.jars.nocopy=true +""" + } buildContext.productProperties.additionalIDEPropertiesFilePaths.each { text += "\n" + new File(it).text } diff --git a/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy b/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy index 9df697b418b8..f0930d64183d 100644 --- a/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy +++ b/build/groovy/org/jetbrains/intellij/build/impl/DistributionJARsBuilder.groovy @@ -79,6 +79,7 @@ class DistributionJARsBuilder { exclude(name: "tips/**") exclude(name: "tips") exclude(name: "search/**") + exclude(name: "**/icon-robots.txt") } def productLayout = buildContext.productProperties.productLayout @@ -146,7 +147,8 @@ class DistributionJARsBuilder { List getPlatformModules() { (platform.moduleJars.values() as List) + - ["java-runtime" /*required to build searchable options index*/, "updater"] + ["java-runtime", "platform-main", /*required to build searchable options index*/ + "updater", buildContext.productProperties.productLayout.mainModule] } diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java index 707612ab4bce..0d46f2fba155 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaSmartStepIntoHandler.java @@ -16,8 +16,13 @@ package com.intellij.debugger.actions; import com.intellij.debugger.SourcePosition; +import com.intellij.debugger.engine.DebuggerUtils; import com.intellij.debugger.engine.SuspendContextImpl; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl; +import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; import com.intellij.debugger.engine.events.DebuggerContextCommandImpl; +import com.intellij.debugger.impl.DebuggerContextImpl; import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.MethodBytecodeUtil; @@ -36,6 +41,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.util.DocumentUtil; import com.intellij.util.Range; +import com.intellij.util.ThreeState; import com.intellij.util.containers.OrderedSet; import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; import com.sun.jdi.Location; @@ -68,7 +74,7 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { @Override public void threadAction(@NotNull SuspendContextImpl suspendContext) { List targets = ApplicationManager.getApplication().runReadAction( - (Computable>)() -> findSmartStepTargets(position, suspendContext)); + (Computable>)() -> findSmartStepTargets(position, suspendContext, getDebuggerContext())); DebuggerUIUtil.invokeLater(() -> { if (targets.isEmpty()) { doStepInto(session, Registry.is("debugger.single.smart.step.force"), null); @@ -93,7 +99,9 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { throw new IllegalStateException("Should not be used"); } - protected List findSmartStepTargets(final SourcePosition position, @Nullable SuspendContextImpl suspendContext) { + protected List findSmartStepTargets(final SourcePosition position, + @Nullable SuspendContextImpl suspendContext, + @NotNull DebuggerContextImpl debuggerContext) { final int line = position.getLine(); if (line < 0) { return Collections.emptyList(); // the document has been changed @@ -174,38 +182,78 @@ public class JavaSmartStepIntoHandler extends JvmSmartStepIntoHandler { @Override public void visitField(PsiField field) { - TextRange range = field.getTextRange(); - if (lineRange.intersects(range)) { - //textRange.set(textRange.get().union(range)); + if (checkTextRange(field, false)) { super.visitField(field); } } @Override public void visitMethod(PsiMethod method) { - TextRange range = method.getTextRange(); - if (lineRange.intersects(range)) { - //textRange.set(textRange.get().union(range)); + if (checkTextRange(method, false)) { super.visitMethod(method); } } @Override public void visitStatement(PsiStatement statement) { - TextRange range = statement.getTextRange(); - if (lineRange.intersects(range)) { - textRange.set(textRange.get().union(range)); + if (checkTextRange(statement, true)) { super.visitStatement(statement); } } + @Override + public void visitIfStatement(PsiIfStatement statement) { + visitConditional(statement.getCondition(), statement.getThenBranch(), statement.getElseBranch()); + } + + @Override + public void visitConditionalExpression(PsiConditionalExpression expression) { + visitConditional(expression.getCondition(), expression.getThenExpression(), expression.getElseExpression()); + } + + private void visitConditional(@Nullable PsiElement condition, + @Nullable PsiElement thenBranch, + @Nullable PsiElement elseBranch) { + if (condition != null) { + condition.accept(this); + } + ThreeState conditionRes = evaluateCondition(condition); + if (conditionRes != ThreeState.NO && thenBranch != null) { + thenBranch.accept(this); + } + if (conditionRes != ThreeState.YES && elseBranch != null) { + elseBranch.accept(this); + } + } + + private ThreeState evaluateCondition(@Nullable PsiElement condition) { + if (condition != null && !DebuggerUtils.hasSideEffects(condition)) { + try { + ExpressionEvaluator evaluator = EvaluatorBuilderImpl.getInstance().build(condition, position); + return ThreeState.fromBoolean(DebuggerUtilsEx.evaluateBoolean(evaluator, debuggerContext.createEvaluationContext())); + } + catch (EvaluateException e) { + LOG.info(e); + } + } + return ThreeState.UNSURE; + } + @Override public void visitExpression(PsiExpression expression) { + checkTextRange(expression, true); + super.visitExpression(expression); + } + + boolean checkTextRange(PsiElement expression, boolean expand) { TextRange range = expression.getTextRange(); if (lineRange.intersects(range)) { - textRange.set(textRange.get().union(range)); + if (expand) { + textRange.set(textRange.get().union(range)); + } + return true; } - super.visitExpression(expression); + return false; } public void visitExpressionList(PsiExpressionList expressionList) { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java index 14a8a1994abd..6d34c7f0dc69 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java @@ -25,6 +25,8 @@ import com.intellij.debugger.SourcePosition; import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.evaluation.*; import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilder; +import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; +import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator; import com.intellij.debugger.engine.requests.RequestManagerImpl; import com.intellij.debugger.jdi.VirtualMachineProxyImpl; import com.intellij.debugger.requests.Requestor; @@ -865,6 +867,14 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils { return PsiParameter.EMPTY_ARRAY; } + public static boolean evaluateBoolean(ExpressionEvaluator evaluator, EvaluationContextImpl context) throws EvaluateException { + Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context); + if (!(value instanceof BooleanValue)) { + throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected")); + } + return ((BooleanValue)value).booleanValue(); + } + public static boolean intersects(@NotNull TextRange range, @NotNull PsiElement elem) { TextRange elemRange = elem.getTextRange(); return elemRange != null && elemRange.intersects(range); diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java index cfee49e7c399..c76b62fb1f68 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/breakpoints/Breakpoint.java @@ -25,8 +25,8 @@ import com.intellij.debugger.engine.*; import com.intellij.debugger.engine.evaluation.*; import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl; import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; -import com.intellij.debugger.engine.evaluation.expression.UnBoxingEvaluator; import com.intellij.debugger.engine.events.SuspendContextCommandImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.jdi.ThreadReferenceProxyImpl; import com.intellij.debugger.requests.ClassPrepareRequestor; @@ -371,13 +371,7 @@ public abstract class Breakpoint

implements return EvaluatorBuilderImpl.build(getCondition(), contextPsiElement, contextSourcePosition, project); } }); - Object value = UnBoxingEvaluator.unbox(evaluator.evaluate(context), context); - if (!(value instanceof BooleanValue)) { - throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.boolean.expected")); - } - if (!((BooleanValue)value).booleanValue()) { - return false; - } + return DebuggerUtilsEx.evaluateBoolean(evaluator, context); } catch (EvaluateException ex) { if (ex.getCause() instanceof VMDisconnectedException) { @@ -387,7 +381,6 @@ public abstract class Breakpoint

implements DebuggerBundle.message("error.failed.evaluating.breakpoint.condition", getCondition(), ex.getMessage()) ); } - return true; } protected String calculateEventClass(EvaluationContextImpl context, LocatableEvent event) throws EvaluateException { diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java index 2f382f0ca80f..f81fee187349 100644 --- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java +++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebuggerUtils.java @@ -423,11 +423,14 @@ public abstract class DebuggerUtils { } } - public static boolean hasSideEffects(PsiElement element) { + public static boolean hasSideEffects(@Nullable PsiElement element) { return hasSideEffectsOrReferencesMissingVars(element, null); } - public static boolean hasSideEffectsOrReferencesMissingVars(PsiElement element, @Nullable final Set visibleLocalVariables) { + public static boolean hasSideEffectsOrReferencesMissingVars(@Nullable PsiElement element, @Nullable final Set visibleLocalVariables) { + if (element == null) { + return false; + } final Ref rv = new Ref<>(Boolean.FALSE); element.accept(new JavaRecursiveElementWalkingVisitor() { @Override diff --git a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java index 399c004e1e14..e6baf6ba00a5 100644 --- a/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java +++ b/java/execution/impl/src/com/intellij/execution/junit/JUnitUtil.java @@ -112,7 +112,7 @@ public class JUnitUtil { if (psiMethod.hasModifierProperty(PsiModifier.STATIC) && SUITE_METHOD_NAME.equals(psiMethod.getName())) return false; if (!psiMethod.getName().startsWith("test")) return false; PsiClass testCaseClass = getTestCaseClassOrNull(location); - return testCaseClass != null && psiMethod.getContainingClass().isInheritor(testCaseClass, true); + return testCaseClass != null && psiMethod.getContainingClass().isInheritor(testCaseClass, true) && PsiType.VOID.equals(psiMethod.getReturnType()); } public static boolean isTestCaseInheritor(final PsiClass aClass) { diff --git a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetector.java b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetector.java index f0259c79d5cb..800a82d71a05 100644 --- a/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetector.java +++ b/java/idea-ui/src/com/intellij/ide/util/projectWizard/importSources/JavaSourceRootDetector.java @@ -33,6 +33,10 @@ public abstract class JavaSourceRootDetector extends ProjectStructureDetector { @Override public DirectoryProcessingResult detectRoots(@NotNull File dir, @NotNull File[] children, @NotNull File base, @NotNull List result) { + if (dir.getName().equals("node_modules")) { + return DirectoryProcessingResult.SKIP_CHILDREN; + } + final String fileExtension = getFileExtension(); for (File child : children) { if (child.isFile() && FileUtilRt.extensionEquals(child.getName(), fileExtension)) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java index 823513cdef5d..5dfb5cfd8ae6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/SimplifyStreamApiCallChainsInspection.java @@ -45,6 +45,16 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns private static final String EMPTY_SET_METHOD = "emptySet"; private static final String SINGLETON_LIST_METHOD = "singletonList"; private static final String SINGLETON_METHOD = "singleton"; + private static final String COLLECT_METHOD = "collect"; + + private static final String COUNTING_COLLECTOR = "counting"; + private static final String MIN_BY_COLLECTOR = "minBy"; + private static final String MAX_BY_COLLECTOR = "maxBy"; + private static final String MAPPING_COLLECTOR = "mapping"; + private static final String REDUCING_COLLECTOR = "reducing"; + private static final String SUMMING_INT_COLLECTOR = "summingInt"; + private static final String SUMMING_LONG_COLLECTOR = "summingLong"; + private static final String SUMMING_DOUBLE_COLLECTOR = "summingDouble"; @Override public boolean isEnabledByDefault() { @@ -95,6 +105,44 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns holder.registerProblem(methodCall, null, fix.getMessage(), fix); } } + else if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, COLLECT_METHOD, 1)) { + PsiElement parameter = methodCall.getArgumentList().getExpressions()[0]; + if(parameter instanceof PsiMethodCallExpression) { + PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter; + PsiMethod collectorMethod = collectorCall.resolveMethod(); + ReplaceCollectorFix fix = null; + if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, COUNTING_COLLECTOR, 0)) { + fix = new ReplaceCollectorFix(COUNTING_COLLECTOR, "count()", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MIN_BY_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(MIN_BY_COLLECTOR, "min({1})", true); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAX_BY_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(MAX_BY_COLLECTOR, "max({1})", true); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, MAPPING_COLLECTOR, 2)) { + fix = new ReplaceCollectorFix(MAPPING_COLLECTOR, "map({1}).collect({2})", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({1})", true); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 2)) { + fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "reduce({1}, {2})", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, REDUCING_COLLECTOR, 3)) { + fix = new ReplaceCollectorFix(REDUCING_COLLECTOR, "map({2}).reduce({1}, {3})", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_INT_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(SUMMING_INT_COLLECTOR, "mapToInt({1}).sum()", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_LONG_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(SUMMING_LONG_COLLECTOR, "mapToLong({1}).sum()", false); + } else if(isCallOf(collectorMethod, CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS, SUMMING_DOUBLE_COLLECTOR, 1)) { + fix = new ReplaceCollectorFix(SUMMING_DOUBLE_COLLECTOR, "mapToDouble({1}).sum()", false); + } + if (fix != null && + collectorCall.getArgumentList().getExpressions().length == collectorMethod.getParameterList().getParametersCount()) { + TextRange range = methodCall.getTextRange(); + PsiElement nameElement = methodCall.getMethodExpression().getReferenceNameElement(); + if(nameElement != null) { + range = new TextRange(nameElement.getTextOffset(), range.getEndOffset()); + } + holder.registerProblem(methodCall, range.shiftRight(-methodCall.getTextOffset()), fix.getMessage(), fix); + } + } + } else { final String name; if (isCallOf(method, CommonClassNames.JAVA_UTIL_STREAM_STREAM, FOR_EACH_METHOD, 1)) { @@ -390,4 +438,87 @@ public class SimplifyStreamApiCallChainsInspection extends BaseJavaBatchLocalIns } } } + + private static class ReplaceCollectorFix implements LocalQuickFix { + private final String myCollector; + private final String myStreamSequence; + private final String myStreamSequenceStripped; + private final boolean myChangeSemantics; + + public ReplaceCollectorFix(String collector, String streamSequence, boolean changeSemantics) { + myCollector = collector; + myStreamSequence = streamSequence; + myStreamSequenceStripped = streamSequence.replaceAll("\\([^)]+\\)", "()"); + myChangeSemantics = changeSemantics; + } + + @Nls + @NotNull + @Override + public String getName() { + return getFamilyName(); + } + + @Nls + @NotNull + @Override + public String getFamilyName() { + return "Replace Stream.collect(" + myCollector + + "()) with Stream." + myStreamSequenceStripped + + (myChangeSemantics ? " (may change semantics when result is null)" : ""); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getStartElement(); + if (element instanceof PsiMethodCallExpression) { + PsiMethodCallExpression collectCall = (PsiMethodCallExpression)element; + PsiExpression qualifierExpression = collectCall.getMethodExpression().getQualifierExpression(); + if (qualifierExpression != null) { + PsiElement parameter = collectCall.getArgumentList().getExpressions()[0]; + if (parameter instanceof PsiMethodCallExpression) { + PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)parameter; + PsiExpression[] collectorArgs = collectorCall.getArgumentList().getExpressions(); + String result = myStreamSequence; + for(int i=0; i .count() change the result type from boxed to primitive + // In rare cases it's necessary to add cast to return back to boxed type + // example: + // List intList; List stringList; + // intList.remove(stringList.stream().collect(summingInt(String::length)) -- remove given element + // intList.remove(stringList.stream().mapToInt(String::length).sum()) -- remove element by index + if(expression instanceof PsiExpression) { + PsiType type = ((PsiExpression)expression).getType(); + if(type instanceof PsiPrimitiveType) { + PsiClassType boxedType = ((PsiPrimitiveType)type).getBoxedType(expression); + if(boxedType != null) { + PsiExpression castExpression = + factory.createExpressionFromText("(" + boxedType.getCanonicalText() + ") " + expression.getText(), expression); + PsiElement cast = expression.replace(castExpression); + if (cast instanceof PsiTypeCastExpression && RedundantCastUtil.isCastRedundant((PsiTypeCastExpression)cast)) { + RedundantCastUtil.removeCast((PsiTypeCastExpression)cast); + } + } + } + } + } + } + } + } + + @NotNull + String getMessage() { + return "Stream.collect(" + myCollector + + "()) can be replaced with Stream." + myStreamSequenceStripped + "()" + + (myChangeSemantics ? " (may change semantics when result is null)" : ""); + } + } + } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java index 8d244022701a..06a9ed709b4d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/AllClassesGetter.java @@ -126,13 +126,8 @@ public class AllClassesGetter { public static final InsertHandler INSERT_FQN = (context, item) -> { final String qName = item.getQualifiedName(); if (qName != null) { - int start = context.getTailOffset() - 1; - while (start >= 0) { - final char ch = context.getDocument().getCharsSequence().charAt(start); - if (!Character.isJavaIdentifierPart(ch) && ch != '.') break; - start--; - } - context.getDocument().replaceString(start + 1, context.getTailOffset(), qName); + int start = JavaCompletionUtil.findQualifiedNameStart(context); + context.getDocument().replaceString(start, context.getTailOffset(), qName); LOG.assertTrue(context.getTailOffset() >= 0); } }; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java index b0dc386a4a57..d31afee0a899 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ConstructorInsertHandler.java @@ -7,7 +7,10 @@ import com.intellij.codeInsight.generation.OverrideImplementExploreUtil; import com.intellij.codeInsight.generation.OverrideImplementUtil; import com.intellij.codeInsight.generation.PsiGenerationInfo; import com.intellij.codeInsight.intention.impl.TypeExpression; -import com.intellij.codeInsight.lookup.*; +import com.intellij.codeInsight.lookup.Lookup; +import com.intellij.codeInsight.lookup.LookupElement; +import com.intellij.codeInsight.lookup.LookupElementDecorator; +import com.intellij.codeInsight.lookup.PsiTypeLookupItem; import com.intellij.codeInsight.template.*; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.application.ApplicationManager; @@ -260,6 +263,8 @@ public class ConstructorInsertHandler implements InsertHandler { + TemplateManager.getInstance(project).finishTemplate(editor); + PsiDocumentManager.getInstance(project).commitDocument(editor.getDocument()); final PsiAnonymousClass aClass = PsiTreeUtil.findElementOfClassAtOffset(file, editor.getCaretModel().getOffset(), PsiAnonymousClass.class, false); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java index dcd1e597ae48..4026930f4e6f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaClassNameInsertHandler.java @@ -16,7 +16,6 @@ package com.intellij.codeInsight.completion; import com.intellij.codeInsight.AutoPopupController; -import com.intellij.codeInsight.ExpectedTypeInfo; import com.intellij.codeInsight.ExpectedTypesProvider; import com.intellij.codeInsight.lookup.Lookup; import com.intellij.codeInsight.lookup.LookupElement; @@ -34,6 +33,7 @@ import com.intellij.psi.javadoc.PsiDocComment; import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import static com.intellij.psi.codeStyle.JavaCodeStyleSettings.*; @@ -159,18 +159,17 @@ class JavaClassNameInsertHandler implements InsertHandler info.getType() instanceof PsiArrayType); + } + private static boolean insertingAnnotation(InsertionContext context, LookupElement item) { final Object obj = item.getObject(); if (!(obj instanceof PsiClass) || !((PsiClass)obj).isAnnotationType()) return false; diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 3e7509751754..f8a321402aab 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -226,12 +226,8 @@ public class JavaCompletionContributor extends CompletionContributor { PrefixMatcher matcher = result.getPrefixMatcher(); PsiElement parent = position.getParent(); - if (JavaModuleCompletion.isModuleFile(position.getContainingFile())) { - JavaModuleCompletion.addVariants(position, element -> { - if (element.getLookupString().startsWith(result.getPrefixMatcher().getPrefix())) { - result.addElement(element); - } - }); + if (JavaModuleCompletion.isModuleFile(parameters.getOriginalFile())) { + JavaModuleCompletion.addVariants(position, result); result.stopHere(); return; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index ca955ed337c0..b69f87c23522 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.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. @@ -528,10 +528,7 @@ public class JavaCompletionUtil { .accepts(reference), JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, Conditions.alwaysTrue()); - if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) { - return JBIterable.from(classItems).flatMap(i -> JavaConstructorCallElement.wrap(i, reference.getElement())); - } - return classItems; + return JBIterable.from(classItems).flatMap(i -> JavaConstructorCallElement.wrap(i, reference.getElement())); } } @@ -544,11 +541,7 @@ public class JavaCompletionUtil { if (completion instanceof PsiClass) { JavaPsiClassReferenceElement classItem = JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true).setSubstitutor(substitutor); - if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) { - return JavaConstructorCallElement.wrap(classItem, reference.getElement()); - } - - return Collections.singletonList(classItem); + return JavaConstructorCallElement.wrap(classItem, reference.getElement()); } if (completion instanceof PsiMethod) { JavaMethodCallElement item = new JavaMethodCallElement((PsiMethod)completion).setQualifierSubstitutor(substitutor); @@ -935,4 +928,14 @@ public class JavaCompletionUtil { } return false; } -} + + public static int findQualifiedNameStart(@NotNull InsertionContext context) { + int start = context.getTailOffset() - 1; + while (start >= 0) { + char ch = context.getDocument().getCharsSequence().charAt(start); + if (!Character.isJavaIdentifierPart(ch) && ch != '.') break; + start--; + } + return start + 1; + } +} \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java index f9e5fa120837..29bbd8b9b80a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaConstructorCallElement.java @@ -20,7 +20,11 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator; import com.intellij.codeInsight.lookup.LookupElementPresentation; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.JBIterable; import org.jetbrains.annotations.NotNull; @@ -42,6 +46,10 @@ public class JavaConstructorCallElement extends JavaMethodCallElement { myType = type.get(); setQualifierSubstitutor(myType.resolveGenerics().getSubstitutor()); + markClassItemWrapped(classItem); + } + + private void markClassItemWrapped(@NotNull LookupElement classItem) { LookupElement delegate = classItem; while (true) { delegate.putUserData(WRAPPING_CONSTRUCTOR_CALL, this); @@ -65,19 +73,24 @@ public class JavaConstructorCallElement extends JavaMethodCallElement { @Override public void renderElement(LookupElementPresentation presentation) { myClassItem.renderElement(presentation); - String itemText = presentation.getItemText(); - super.renderElement(presentation); - presentation.setItemText(itemText); + String tailText = StringUtil.notNullize(presentation.getTailText()); + int genericsEnd = tailText.lastIndexOf('>') + 1; + + presentation.clearTail(); + presentation.appendTailText(tailText.substring(0, genericsEnd), false); + presentation.appendTailText(MemberLookupHelper.getMethodParameterString(getObject(), getSubstitutor()), false); + presentation.appendTailText(tailText.substring(genericsEnd), true); } - static List wrap(JavaPsiClassReferenceElement classItem, PsiElement position) { + static List wrap(@NotNull JavaPsiClassReferenceElement classItem, @NotNull PsiElement position) { PsiClass psiClass = classItem.getObject(); return wrap(classItem, psiClass, position, () -> JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, PsiSubstitutor.EMPTY)); } - static List wrap(LookupElement classItem, PsiClass psiClass, PsiElement position, Supplier type) { - if (Registry.is("java.completion.show.constructors") && JavaClassNameCompletionContributor.AFTER_NEW.accepts(position)) { + static List wrap(@NotNull LookupElement classItem, @NotNull PsiClass psiClass, + @NotNull PsiElement position, @NotNull Supplier type) { + if (Registry.is("java.completion.show.constructors") && isConstructorCallPlace(position)) { PsiMethod[] constructors = psiClass.getConstructors(); if (constructors.length > 0) { return JBIterable.of(constructors). @@ -89,6 +102,14 @@ public class JavaConstructorCallElement extends JavaMethodCallElement { return Collections.singletonList(classItem); } + private static boolean isConstructorCallPlace(@NotNull PsiElement position) { + return CachedValuesManager.getCachedValue(position, () -> { + boolean result = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position) && + !JavaClassNameInsertHandler.isArrayTypeExpected(PsiTreeUtil.getParentOfType(position, PsiNewExpression.class)); + return CachedValueProvider.Result.create(result, position); + }); + } + static boolean isWrapped(LookupElement element) { return element.getUserData(WRAPPING_CONSTRUCTOR_CALL) != null; } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index 9a6925cf58fd..2c7275accd5e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -22,10 +22,15 @@ import com.intellij.codeInsight.template.Template; import com.intellij.codeInsight.template.TemplateManager; import com.intellij.codeInsight.template.impl.ConstantNode; import com.intellij.codeInsight.template.impl.MacroCallNode; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; import com.intellij.codeInsight.template.macro.CompleteMacro; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.ClassConditionKey; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; @@ -170,7 +175,7 @@ public class JavaMethodCallElement extends LookupItem implements Type } } - if (hasParams && Registry.is("java.completion.argument.live.template")) { + if (hasParams && context.getCompletionChar() != Lookup.COMPLETE_STATEMENT_SELECT_CHAR && Registry.is("java.completion.argument.live.template")) { startArgumentLiveTemplate(context, method); } } @@ -187,7 +192,8 @@ public class JavaMethodCallElement extends LookupItem implements Type qualifyMethodCall(file, startOffset, document); } - private static void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) { + public static final Key ARGUMENT_TEMPLATE_ACTIVE = Key.create("ARGUMENT_TEMPLATE_ACTIVE"); + private void startArgumentLiveTemplate(InsertionContext context, PsiMethod method) { TemplateManager manager = TemplateManager.getInstance(method.getProject()); Template template = manager.createTemplate("", ""); PsiParameter[] parameters = method.getParameterList().getParameters(); @@ -199,7 +205,18 @@ public class JavaMethodCallElement extends LookupItem implements Type template.addVariable(name, new MacroCallNode(new CompleteMacro()), new ConstantNode(name), true); } - manager.startTemplate(context.getEditor(), template); + Editor editor = context.getEditor(); + manager.startTemplate(editor, template); + + TemplateState templateState = TemplateManagerImpl.getTemplateState(editor); + if (templateState == null) return; + + editor.putUserData(ARGUMENT_TEMPLATE_ACTIVE, this); + Disposer.register(templateState, () -> { + if (editor.getUserData(ARGUMENT_TEMPLATE_ACTIVE) == this) { + editor.putUserData(ARGUMENT_TEMPLATE_ACTIVE, null); + } + }); } private boolean shouldInsertTypeParameters() { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java index d9414f11c9b4..2620e664e599 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaModuleCompletion.java @@ -19,21 +19,22 @@ import com.intellij.codeInsight.TailType; import com.intellij.codeInsight.completion.JavaKeywordCompletion.OverrideableSpace; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.lookup.LookupElementBuilder; -import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.module.impl.scopes.ModulesScope; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.impl.file.impl.JavaFileManager; import com.intellij.psi.impl.java.stubs.index.JavaModuleNameIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; +import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.Consumer; import org.jetbrains.annotations.NotNull; +import java.util.function.Predicate; + import static com.intellij.codeInsight.completion.JavaKeywordCompletion.createKeyword; class JavaModuleCompletion { @@ -41,7 +42,13 @@ class JavaModuleCompletion { return PsiUtil.isLanguageLevel9OrHigher(file) && PsiJavaModule.MODULE_INFO_FILE.equals(file.getName()); } - static void addVariants(@NotNull PsiElement position, @NotNull Consumer result) { + static void addVariants(@NotNull PsiElement position, @NotNull CompletionResultSet resultSet) { + Consumer result = element -> { + if (element.getLookupString().startsWith(resultSet.getPrefixMatcher().getPrefix())) { + resultSet.addElement(element); + } + }; + if (position instanceof PsiIdentifier) { PsiElement context = position.getParent(); if (context instanceof PsiErrorElement) context = context.getParent(); @@ -52,11 +59,14 @@ class JavaModuleCompletion { else if (context instanceof PsiJavaModule) { addModuleStatementKeywords(position, result); } + else if (context instanceof PsiProvidesStatement) { + addProvidesStatementKeywords(position, result); + } else if (context instanceof PsiJavaModuleReferenceElement) { addModuleReferences(context, result); } else if (context instanceof PsiJavaCodeReferenceElement) { - addCodeReferences(context, result); + addCodeReferences(context, result, resultSet); } } } @@ -74,6 +84,10 @@ class JavaModuleCompletion { result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.PROVIDES), TailType.HUMBLE_SPACE_BEFORE_WORD)); } + private static void addProvidesStatementKeywords(PsiElement position, Consumer result) { + result.consume(new OverrideableSpace(createKeyword(position, PsiKeyword.WITH), TailType.HUMBLE_SPACE_BEFORE_WORD)); + } + private static void addModuleReferences(PsiElement context, Consumer result) { PsiJavaModule host = PsiTreeUtil.getParentOfType(context, PsiJavaModule.class); if (host != null) { @@ -90,24 +104,81 @@ class JavaModuleCompletion { } } - private static void addCodeReferences(PsiElement context, Consumer result) { - PsiElement statement = PsiTreeUtil.skipParentsOfType(context, PsiJavaCodeReferenceElement.class); + private static void addCodeReferences(PsiElement context, Consumer result, CompletionResultSet resultSet) { + PsiElement statement = context.getParent(); if (statement instanceof PsiExportsStatement) { Module module = ModuleUtilCore.findModuleForPsiElement(context); - PsiPackage topPackage = ServiceManager.getService(context.getProject(), JavaFileManager.class).findPackage(""); + PsiPackage topPackage = JavaPsiFacade.getInstance(context.getProject()).findPackage(""); if (module != null && topPackage != null) { processPackage(topPackage, new ModulesScope(module), result); } } + else if (statement instanceof PsiUsesStatement) { + processClasses(context.getProject(), null, resultSet, SERVICE_FILTER, TailType.SEMICOLON); + } + else if (statement instanceof PsiProvidesStatement) { + PsiJavaCodeReferenceElement intRef = ((PsiProvidesStatement)statement).getInterfaceReference(); + if (context == intRef) { + processClasses(context.getProject(), null, resultSet, SERVICE_FILTER, TailType.HUMBLE_SPACE_BEFORE_WORD); + } + else if (context == ((PsiProvidesStatement)statement).getImplementationReference() && intRef != null) { + PsiElement service = intRef.resolve(); + Module module = ModuleUtilCore.findModuleForPsiElement(context); + if (service instanceof PsiClass && module != null) { + Predicate filter = psiClass -> !psiClass.hasModifierProperty(PsiModifier.ABSTRACT) && + InheritanceUtil.isInheritorOrSelf(psiClass, (PsiClass)service, true); + processClasses(context.getProject(), new ModulesScope(module), resultSet, filter, TailType.SEMICOLON); + } + } + } } private static void processPackage(PsiPackage pkg, ModulesScope scope, Consumer result) { String packageName = pkg.getQualifiedName(); - if (packageName.indexOf('.') > 0 && !PsiUtil.isPackageEmpty(pkg.getDirectories(scope), packageName)) { - result.consume(new OverrideableSpace(LookupElementBuilder.create(packageName), TailType.SEMICOLON)); + if (isQualified(packageName) && !PsiUtil.isPackageEmpty(pkg.getDirectories(scope), packageName)) { + result.consume(new OverrideableSpace(lookupElement(pkg), TailType.SEMICOLON)); } for (PsiPackage subPackage : pkg.getSubPackages(scope)) { processPackage(subPackage, scope, result); } } + + private static final Predicate SERVICE_FILTER = + psiClass -> !psiClass.isEnum() && psiClass.hasModifierProperty(PsiModifier.PUBLIC); + + private static void processClasses(Project project, + GlobalSearchScope scope, + CompletionResultSet resultSet, + Predicate filter, + TailType tail) { + GlobalSearchScope _scope = scope != null ? scope : ProjectScope.getAllScope(project); + AllClassesGetter.processJavaClasses(resultSet.getPrefixMatcher(), project, _scope, psiClass -> { + if (isQualified(psiClass.getQualifiedName()) && filter.test(psiClass)) { + resultSet.addElement(new OverrideableSpace(lookupElement(psiClass), tail)); + } + return true; + }); + } + + private static LookupElementBuilder lookupElement(PsiNamedElement e) { + LookupElementBuilder lookup = LookupElementBuilder.create(e).withInsertHandler(FQN_INSERT_HANDLER); + String fqn = e instanceof PsiClass ? ((PsiClass)e).getQualifiedName() : ((PsiQualifiedNamedElement)e).getQualifiedName(); + return fqn != null ? lookup.withPresentableText(fqn) : lookup; + } + + private static boolean isQualified(String name) { + return name != null && name.indexOf('.') > 0; + } + + private static final InsertHandler FQN_INSERT_HANDLER = new InsertHandler() { + @Override + public void handleInsert(InsertionContext context, LookupElement item) { + Object e = item.getObject(); + String fqn = e instanceof PsiClass ? ((PsiClass)e).getQualifiedName() : ((PsiQualifiedNamedElement)e).getQualifiedName(); + if (fqn != null) { + int start = JavaCompletionUtil.findQualifiedNameStart(context); + context.getDocument().replaceString(start, context.getTailOffset(), fqn); + } + } + }; } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java index 5b80538771b4..aa69cb91909b 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaNoVariantsDelegator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -42,6 +42,10 @@ import static com.intellij.patterns.PsiJavaPatterns.psiElement; public class JavaNoVariantsDelegator extends CompletionContributor { @Override public void fillCompletionVariants(@NotNull final CompletionParameters parameters, @NotNull final CompletionResultSet result) { + if (JavaModuleCompletion.isModuleFile(parameters.getOriginalFile())) { + return; + } + final JavaCompletionSession session = new JavaCompletionSession(result); ResultTracker tracker = new ResultTracker(result) { @Override diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java index 6589f4a815e3..cd338c747c86 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/MemberLookupHelper.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiFormatUtil; import com.intellij.psi.util.PsiFormatUtilBase; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -78,9 +79,7 @@ public class MemberLookupHelper { final String params = myMergedOverloads ? "(...)" : myMember instanceof PsiMethod - ? PsiFormatUtil.formatMethod((PsiMethod)myMember, substitutor, - PsiFormatUtilBase.SHOW_PARAMETERS, - PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE) + ? getMethodParameterString((PsiMethod)myMember, substitutor) : ""; presentation.clearTail(); presentation.appendTailText(params, false); @@ -96,5 +95,9 @@ public class MemberLookupHelper { } } - + @NotNull + static String getMethodParameterString(@NotNull PsiMethod method, @NotNull PsiSubstitutor substitutor) { + return PsiFormatUtil.formatMethod(method, substitutor, + PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_TYPE); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/template/macro/JavaTemplateCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/template/macro/JavaTemplateCompletionProcessor.java index 75d4d7ec2cde..06491b964227 100644 --- a/java/java-impl/src/com/intellij/codeInsight/template/macro/JavaTemplateCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/template/macro/JavaTemplateCompletionProcessor.java @@ -16,10 +16,13 @@ package com.intellij.codeInsight.template.macro; import com.intellij.codeInsight.completion.JavaCompletionUtil; +import com.intellij.codeInsight.completion.JavaMethodCallElement; +import com.intellij.codeInsight.completion.SmartCompletionDecorator; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.codeInsight.template.ExpressionContext; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.ClassConditionKey; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiPackage; import java.util.List; @@ -34,6 +37,12 @@ public class JavaTemplateCompletionProcessor implements TemplateCompletionProces if (elements != null && elements.size() == 1 && elements.get(0) instanceof PsiPackage) { return false; } + + Editor editor = context.getEditor(); + if (editor != null && editor.getUserData(JavaMethodCallElement.ARGUMENT_TEMPLATE_ACTIVE) != null) { + return item.as(ClassConditionKey.create(SmartCompletionDecorator.class)) != null; + } + return true; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java index c53f363a470b..0aac8ceb56c6 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/DummyEntryPointsPresentation.java @@ -15,7 +15,6 @@ */ package com.intellij.codeInspection.deadCode; -import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.GlobalJavaInspectionContext; import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ex.*; @@ -24,6 +23,7 @@ import com.intellij.codeInspection.reference.RefEntity; import com.intellij.codeInspection.reference.RefJavaElement; import com.intellij.codeInspection.ui.InspectionNode; import com.intellij.codeInspection.ui.InspectionResultsView; +import com.intellij.codeInspection.ui.InspectionTree; import com.intellij.codeInspection.ui.InspectionTreeNode; import com.intellij.codeInspection.util.RefFilter; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -43,7 +43,7 @@ public class DummyEntryPointsPresentation extends UnusedDeclarationPresentation } @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) { if (myQuickFixActions == null) { myQuickFixActions = new QuickFixAction[]{new MoveEntriesToSuspicious(getToolWrapper())}; } diff --git a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java index 341b24194be4..11482cb727c3 100644 --- a/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java +++ b/java/java-impl/src/com/intellij/codeInspection/deadCode/UnusedDeclarationPresentation.java @@ -67,6 +67,7 @@ import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLDocument; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; +import javax.swing.tree.TreePath; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; @@ -182,7 +183,7 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } @Override - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) { boolean showFixes = false; for (RefEntity element : refElements) { if (!getIgnoredRefElements().contains(element) && element.isValid()) { @@ -192,8 +193,23 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta } if (showFixes) { - final QuickFixAction[] fixes = super.getQuickFixes(refElements, allowedDescriptors); - return fixes != null ? ArrayUtil.mergeArrays(fixes, myQuickFixActions) : myQuickFixActions; + final TreePath[] paths = tree.getSelectionPaths(); + if (paths != null) { + int count = 0; + for (TreePath path : paths) { + final Object component = path.getLastPathComponent(); + if (component instanceof ProblemDescriptionNode) { + count++; + } + } + if (count > 0) { + final QuickFixAction[] fixes = super.getQuickFixes(refElements, tree); + if (fixes != null) { + return count == paths.length ? fixes : ArrayUtil.mergeArrays(fixes, myQuickFixActions); + } + } + } + return myQuickFixActions; } return QuickFixAction.EMPTY; } diff --git a/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt b/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt index ccb63e96b143..544a739d08c6 100644 --- a/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt +++ b/java/java-impl/src/com/intellij/reporting/ReportMissingOrExcessiveInlineHint.kt @@ -23,6 +23,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.PathManager +import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Inlay import com.intellij.openapi.project.Project @@ -35,6 +36,10 @@ class ReportMissingOrExcessiveInlineHint : AnAction() { private val text = "Report Missing or Excessive Inline Hint" private val description = "Text line at caret will be anonymously reported to our servers" + companion object { + private val LOG = Logger.getInstance(ReportMissingOrExcessiveInlineHint::class.java) + } + init { val presentation = templatePresentation presentation.text = text @@ -85,12 +90,14 @@ class ReportMissingOrExcessiveInlineHint : AnAction() { } private fun trySendFileInBackground() { + LOG.debug("File: ${file.path} Length: ${file.length()}") if (!file.exists() || file.length() == 0L) return - ApplicationManager.getApplication().executeOnPooledThread { val text = file.readText() + LOG.debug("File text $text") if (StatsSender.send(text)) { file.delete() + LOG.debug("File deleted") } } } diff --git a/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java index c2a01117d72b..7ac842b28928 100644 --- a/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java +++ b/java/java-indexing-impl/src/com/intellij/psi/impl/search/ConstructorReferencesSearchHelper.java @@ -63,9 +63,10 @@ class ConstructorReferencesSearchHelper { DumbService.getInstance(project).runReadActionInSmartMode(new Computable() { @Override public Void compute() { - constructorCanBeCalledImplicitly[0] = constructor.getParameterList().getParametersCount() == 0; + final PsiParameter[] parameters = constructor.getParameterList().getParameters(); + constructorCanBeCalledImplicitly[0] = parameters.length == 0; if (!constructorCanBeCalledImplicitly[0]) { - constructorCanBeCalledImplicitly[0] = hasDefaultConstructorWithVarargParameter(containingClass); + constructorCanBeCalledImplicitly[0] = parameters.length == 1 && parameters[0].isVarArgs(); } isEnum[0] = containingClass.isEnum(); isUnder18[0] = PsiUtil.getLanguageLevel(containingClass).isAtLeast(LanguageLevel.JDK_1_8); @@ -127,17 +128,6 @@ class ConstructorReferencesSearchHelper { return ClassInheritorsSearch.search(containingClass, searchScope, false).forEach(processor2); } - private static boolean hasDefaultConstructorWithVarargParameter(@NotNull PsiClass containingClass) { - final PsiMethod[] constructors = containingClass.getConstructors(); - for (PsiMethod ctr : constructors) { - final PsiParameter[] parameters = ctr.getParameterList().getParameters(); - if (parameters.length == 1 && parameters[0].isVarArgs()) { - return true; - } - } - return false; - } - private static boolean processEnumReferences(@NotNull final Processor processor, @NotNull final PsiMethod constructor, @NotNull final Project project, diff --git a/java/java-psi-impl/src/com/intellij/lang/java/parser/ModuleParser.java b/java/java-psi-impl/src/com/intellij/lang/java/parser/ModuleParser.java index deb016b7d84a..9216f033cb5a 100644 --- a/java/java-psi-impl/src/com/intellij/lang/java/parser/ModuleParser.java +++ b/java/java-psi-impl/src/com/intellij/lang/java/parser/ModuleParser.java @@ -21,13 +21,19 @@ import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiKeyword; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.tree.IElementType; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; +import java.util.Set; + import static com.intellij.lang.PsiBuilderUtil.expect; import static com.intellij.lang.java.parser.JavaParserUtil.error; import static com.intellij.lang.java.parser.JavaParserUtil.semicolon; public class ModuleParser { + private static final Set STATEMENT_KEYWORDS = + ContainerUtil.newHashSet(PsiKeyword.REQUIRES, PsiKeyword.EXPORTS, PsiKeyword.USES, PsiKeyword.PROVIDES); + public static void parseModule(@NotNull PsiBuilder builder) { PsiBuilder.Marker module = builder.mark(); mapAndAdvance(builder, JavaTokenType.MODULE_KEYWORD); @@ -225,7 +231,15 @@ public class ModuleParser { } } else if (!hasError) { - error(builder, JavaErrorMessages.message("expected.with")); + IElementType next = builder.getTokenType(); + if (next == JavaTokenType.IDENTIFIER && !STATEMENT_KEYWORDS.contains(builder.getTokenText())) { + PsiBuilder.Marker marker = builder.mark(); + builder.advanceLexer(); + marker.error(JavaErrorMessages.message("expected.with")); + } + else { + error(builder, JavaErrorMessages.message("expected.with")); + } hasError = true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiAnonymousClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiAnonymousClassImpl.java index ca9663bdaf8d..d63e372a501f 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiAnonymousClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiAnonymousClassImpl.java @@ -20,7 +20,6 @@ import com.intellij.psi.*; import com.intellij.psi.impl.java.stubs.JavaStubElementTypes; import com.intellij.psi.impl.java.stubs.PsiClassStub; import com.intellij.psi.impl.source.tree.ChildRole; -import com.intellij.psi.impl.source.tree.SharedImplUtil; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.reference.SoftReference; import com.intellij.util.IncorrectOperationException; @@ -66,7 +65,7 @@ public class PsiAnonymousClassImpl extends PsiClassImpl implements PsiAnonymousC @Override @NotNull public PsiClassType getBaseClassType() { - final PsiClassStub stub = getStub(); + final PsiClassStub stub = getGreenStub(); if (stub == null) { myCachedBaseType = null; return getTypeByTree(); @@ -192,7 +191,7 @@ public class PsiAnonymousClassImpl extends PsiClassImpl implements PsiAnonymousC @Override public boolean isInQualifiedNew() { - final PsiClassStub stub = getStub(); + final PsiClassStub stub = getGreenStub(); if (stub != null) { return stub.isAnonymousInQualifiedNew(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java index e016b4279670..ab28e1992311 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassImpl.java @@ -242,7 +242,7 @@ public class PsiClassImpl extends JavaStubPsiElement> implements @Override @Nullable public PsiClass getContainingClass() { - final PsiClassStub stub = getStub(); + final PsiClassStub stub = getGreenStub(); if (stub != null) { StubElement parent = stub.getParentStub(); return parent instanceof PsiClassStub ? ((PsiClassStub)parent).getPsi() : null; @@ -540,7 +540,7 @@ public class PsiClassImpl extends JavaStubPsiElement> implements private static boolean isAnonymousOrLocal(PsiClass aClass) { if (aClass instanceof PsiAnonymousClass) return true; - final PsiClassStub stub = ((PsiClassImpl)aClass).getStub(); + final PsiClassStub stub = ((PsiClassImpl)aClass).getGreenStub(); if (stub != null) { final StubElement parentStub = stub.getParentStub(); return !(parentStub instanceof PsiClassStub || parentStub instanceof PsiFileStub); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java index 3ffb565ab5ca..47b3d271e948 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiEnumConstantImpl.java @@ -174,7 +174,7 @@ public class PsiEnumConstantImpl extends JavaStubPsiElement implem @Override @NotNull public String getName() { - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null) { return stub.getName(); } @@ -194,7 +194,7 @@ public class PsiEnumConstantImpl extends JavaStubPsiElement implem @Override public boolean isDeprecated() { - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null) { return stub.isDeprecated(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java index db17f1a9b9e5..3b0ad2efed61 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java @@ -104,7 +104,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps @Override @NotNull public String getName() { - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null) { return stub.getName(); } @@ -185,7 +185,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps private PsiField findFirstFieldInDeclaration() { if (getSelfModifierList() != null) return this; - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null) { final List siblings = stub.getParentStub().getChildrenStubs(); final int idx = siblings.indexOf(stub); @@ -226,7 +226,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps // avoids stub-to-AST switch if possible, // returns the light generated initializer literal expression if stored in stubs, the regular initializer if wasn't public PsiExpression getDetachedInitializer() { - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); PsiExpression initializer; if (stub == null) { initializer = getInitializer(); @@ -251,7 +251,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps @Override public boolean hasInitializer() { - PsiFieldStub stub = getStub(); + PsiFieldStub stub = getGreenStub(); if (stub != null) { return stub.getInitializerText() != null; } @@ -299,7 +299,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps @Override public boolean isDeprecated() { - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null) { return stub.isDeprecated() || stub.hasDeprecatedAnnotation() && PsiImplUtil.isDeprecatedByAnnotation(this); } @@ -309,7 +309,7 @@ public class PsiFieldImpl extends JavaStubPsiElement implements Ps @Override public PsiDocComment getDocComment(){ - final PsiFieldStub stub = getStub(); + final PsiFieldStub stub = getGreenStub(); if (stub != null && !stub.hasDocComment()) return null; CompositeElement treeElement = getNode(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStatementBaseImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStatementBaseImpl.java index c5af2ad5b312..ceb6ce7d9116 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStatementBaseImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImportStatementBaseImpl.java @@ -40,7 +40,7 @@ public abstract class PsiImportStatementBaseImpl extends JavaStubPsiElement imp @NotNull @Override public String getModuleName() { - PsiJavaModuleStub stub = getStub(); + PsiJavaModuleStub stub = getGreenStub(); if (stub != null) { return stub.getName(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java index f565fc1541d4..e9e08148a1fa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiMethodImpl.java @@ -20,6 +20,7 @@ import com.intellij.navigation.ItemPresentation; import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.Queryable; +import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.psi.*; import com.intellij.psi.impl.ElementPresentationUtil; @@ -136,7 +137,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements @NotNull public String getName() { final String name; - final PsiMethodStub stub = getStub(); + final PsiMethodStub stub = getGreenStub(); if (stub != null) { name = stub.getName(); } @@ -241,7 +242,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements @Override public boolean isDeprecated() { - final PsiMethodStub stub = getStub(); + final PsiMethodStub stub = getGreenStub(); if (stub != null) { return stub.isDeprecated() || stub.hasDeprecatedAnnotation() && PsiImplUtil.isDeprecatedByAnnotation(this); } @@ -251,7 +252,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements @Override public PsiDocComment getDocComment() { - final PsiMethodStub stub = getStub(); + final PsiMethodStub stub = getGreenStub(); if (stub != null && !stub.hasDocComment()) return null; return (PsiDocComment)getNode().findChildByRoleAsPsiElement(ChildRole.DOC_COMMENT); @@ -259,7 +260,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements @Override public boolean isConstructor() { - final PsiMethodStub stub = getStub(); + final PsiMethodStub stub = getGreenStub(); if (stub != null) { return stub.isConstructor(); } @@ -269,7 +270,7 @@ public class PsiMethodImpl extends JavaStubPsiElement implements @Override public boolean isVarArgs() { - final PsiMethodStub stub = getStub(); + final PsiMethodStub stub = getGreenStub(); if (stub != null) { return stub.isVarArgs(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index 5276b11f0efa..c9cc626e371b 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -113,7 +113,7 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override @NotNull public final String getName() { - PsiParameterStub stub = getStub(); + PsiParameterStub stub = getGreenStub(); if (stub != null) { return stub.getName(); } @@ -269,7 +269,7 @@ public class PsiParameterImpl extends JavaStubPsiElement imple @Override public boolean isVarArgs() { - final PsiParameterStub stub = getStub(); + final PsiParameterStub stub = getGreenStub(); if (stub != null) { return stub.isParameterTypeEllipsis(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterListImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterListImpl.java index 687c19f90dfe..c4ac677bacfa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterListImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterListImpl.java @@ -59,7 +59,7 @@ public class PsiParameterListImpl extends JavaStubPsiElement data) { + return data.stream().filter(x -> x.startsWith("xyz")).count(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMapping.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMapping.java new file mode 100644 index 000000000000..5947f90e9c27 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMapping.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(mapping()) with Stream.map().collect()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public List sizes(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).map(String::length).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMaxBy.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMaxBy.java new file mode 100644 index 000000000000..d854a721537a --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMaxBy.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(maxBy()) with Stream.max() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public String max(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).max(String.CASE_INSENSITIVE_ORDER).orElse(""); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMinBy.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMinBy.java new file mode 100644 index 000000000000..c9feabac14e4 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorMinBy.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(minBy()) with Stream.min() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public Optional min(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).min(String.CASE_INSENSITIVE_ORDER); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing1.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing1.java new file mode 100644 index 000000000000..37374e316f13 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing1.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.reduce() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public Optional concat(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).reduce(String::concat); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing2.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing2.java new file mode 100644 index 000000000000..a5a5a24b9580 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing2.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.reduce()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public String concat(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).reduce("", String::concat); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing3.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing3.java new file mode 100644 index 000000000000..ab3b2ccea49c --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorReducing3.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.map().reduce()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public int sum(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).map(String::length).reduce(0, Integer::sum); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingInt.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingInt.java new file mode 100644 index 000000000000..249a0358d3e6 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingInt.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(summingInt()) with Stream.mapToInt().sum()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public void remove(List ints, List data) { + ints.remove((Integer) data.stream().mapToInt(String::length).sum()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingLong.java b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingLong.java new file mode 100644 index 000000000000..6b86f89a7693 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/afterCollectorSummingLong.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(summingLong()) with Stream.mapToLong().sum()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public void remove(List ints, List data) { + ints.remove(data.stream().mapToLong(String::length).sum()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorCounting.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorCounting.java new file mode 100644 index 000000000000..b40342231759 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorCounting.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(counting()) with Stream.count()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public long count(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.counting()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMapping.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMapping.java new file mode 100644 index 000000000000..a6642d790f95 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMapping.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(mapping()) with Stream.map().collect()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public List sizes(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.mapping(String::length, Collectors.toList())); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMaxBy.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMaxBy.java new file mode 100644 index 000000000000..e6c59cd4caa1 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMaxBy.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(maxBy()) with Stream.max() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public String max(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.maxBy(String.CASE_INSENSITIVE_ORDER)).orElse(""); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMinBy.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMinBy.java new file mode 100644 index 000000000000..7be18c5687b9 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorMinBy.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(minBy()) with Stream.min() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public Optional min(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.minBy(String.CASE_INSENSITIVE_ORDER)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing1.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing1.java new file mode 100644 index 000000000000..a10971f7ee78 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing1.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.reduce() (may change semantics when result is null)" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public Optional concat(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.reducing(String::concat)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing2.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing2.java new file mode 100644 index 000000000000..0f0da24629f6 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing2.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.reduce()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public String concat(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.reducing("", String::concat)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing3.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing3.java new file mode 100644 index 000000000000..7ac6bff960d7 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorReducing3.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(reducing()) with Stream.map().reduce()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public int sum(List data) { + return data.stream().filter(x -> x.startsWith("xyz")).collect(Collectors.reducing(0, String::length, Integer::sum)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingInt.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingInt.java new file mode 100644 index 000000000000..0a0e77601350 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingInt.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(summingInt()) with Stream.mapToInt().sum()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public void remove(List ints, List data) { + ints.remove(data.stream().collect(Collectors.summingInt(String::length))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingLong.java b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingLong.java new file mode 100644 index 000000000000..305cc7bc13d4 --- /dev/null +++ b/java/java-tests/testData/inspection/streamApiCallChains/beforeCollectorSummingLong.java @@ -0,0 +1,10 @@ +// "Replace Stream.collect(summingLong()) with Stream.mapToLong().sum()" "true" + +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public void remove(List ints, List data) { + ints.remove(data.stream().collect(Collectors.summingLong(String::length))); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/psi/parser-partial/modules/Provides7.txt b/java/java-tests/testData/psi/parser-partial/modules/Provides7.txt new file mode 100644 index 000000000000..df577c34d4d2 --- /dev/null +++ b/java/java-tests/testData/psi/parser-partial/modules/Provides7.txt @@ -0,0 +1,21 @@ +PsiJavaFile:Provides7.java + PsiJavaModule:M + PsiKeyword:module('module') + PsiWhiteSpace(' ') + PsiJavaModuleReference + PsiIdentifier:M('M') + PsiWhiteSpace(' ') + PsiJavaToken:LBRACE('{') + PsiWhiteSpace(' ') + PsiProvidesStatement + PsiKeyword:provides('provides') + PsiWhiteSpace(' ') + PsiJavaCodeReferenceElement:Spi + PsiIdentifier:Spi('Spi') + PsiReferenceParameterList + + PsiWhiteSpace(' ') + PsiErrorElement:'with' expected + PsiIdentifier:_('_') + PsiWhiteSpace(' ') + PsiJavaToken:RBRACE('}') \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ModuleCompletionTest.kt b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ModuleCompletionTest.kt index 28dd8eb35089..9fcd9c2fc2a0 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/ModuleCompletionTest.kt +++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/ModuleCompletionTest.kt @@ -33,7 +33,22 @@ class ModuleCompletionTest : LightFixtureCompletionTestCase() { addFile("pkg/empty/package-info.java", "package pkg.empty;") addFile("pkg/main/C.java", "package pkg.main;\nclass C { }") addFile("pkg/other/C.groovy", "package pkg.other\nclass C { }") - variants("module M { exports pkg. }", "pkg.main", "pkg.other") + variants("module M { exports pkg. }", "main", "other") + complete("module M { exports pkg.o }", "module M { exports pkg.other; }") + } + + fun testUses() { + addFile("pkg/main/MySvc.java", "package pkg.main;\npublic class MySvc { }") + addFile("pkg/main/MySvcImpl.java", "package pkg.main;\nclass MySvcImpl extends MySvc { }") + complete("module M { uses MyS }", "module M { uses pkg.main.MySvc; }") + } + + fun testProvides() { + addFile("pkg/main/MySvc.java", "package pkg.main;\npublic class MySvc { }") + addFile("pkg/main/MySvcImpl.java", "package pkg.main;\nclass MySvcImpl extends MySvc { }") + complete("module M { provides MyS }", "module M { provides pkg.main.MySvc }") + complete("module M { provides pkg.main.MySvc }", "module M { provides pkg.main.MySvc with }") + complete("module M { provides pkg.main.MySvc with MSI }", "module M { provides pkg.main.MySvc with pkg.main.MySvcImpl; }") } // diff --git a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java index 2c4ad310ede7..5141a5d897a1 100644 --- a/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java +++ b/java/java-tests/testSrc/com/intellij/lang/java/parser/partial/ModuleParserTest.java @@ -69,6 +69,7 @@ public class ModuleParserTest extends JavaParsingTestCase { public void testProvides4() { doParserTest("module M { provides Spi with ; }"); } public void testProvides5() { doParserTest("module M { provides Spi with Impl }"); } public void testProvides6() { doParserTest("module M { provides Spi with Impl; }"); } + public void testProvides7() { doParserTest("module M { provides Spi _ }"); } private void doParserTest(String text) { doParserTest(text, builder -> JavaParser.INSTANCE.getFileParser().parse(builder)); diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/VoidConversionRule.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/VoidConversionRule.java index 6385b079f450..748e49e02da6 100644 --- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/VoidConversionRule.java +++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/rules/VoidConversionRule.java @@ -15,12 +15,14 @@ */ package com.intellij.refactoring.typeMigration.rules; +import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase; import com.intellij.refactoring.typeMigration.TypeEvaluator; import com.intellij.refactoring.typeMigration.TypeMigrationLabeler; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.controlflow.UnnecessaryReturnInspection; +import com.siyeh.ig.fixes.DeleteUnnecessaryStatementFix; import com.siyeh.ig.psiutils.SideEffectChecker; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -43,10 +45,11 @@ public class VoidConversionRule extends TypeConversionRule { @Override public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) throws IncorrectOperationException { final PsiElement parent = expression.getParent(); + final Project project = expression.getProject(); if (parent instanceof PsiReturnStatement) { - expression.delete(); - if (UnnecessaryReturnInspection.isReturnRedundant((PsiReturnStatement)parent, false, null)) { - parent.delete(); + final PsiReturnStatement replaced = (PsiReturnStatement)parent.replace(JavaPsiFacade.getElementFactory(project).createStatementFromText("return;", null)); + if (UnnecessaryReturnInspection.isReturnRedundant(replaced, false, null)) { + DeleteUnnecessaryStatementFix.deleteUnnecessaryStatement(replaced); } } return null; diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompiledClass.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompiledClass.java index 6a57e2707ac7..5dacdb596078 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompiledClass.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompiledClass.java @@ -28,6 +28,7 @@ import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * In-memory representation of JVM *.class file produced by a compiler. @@ -84,7 +85,7 @@ public class CompiledClass extends UserDataHolderBase{ } @NotNull - public Collection getSourceFilesPaths() { + public List getSourceFilesPaths() { return ContainerUtil.map(mySourceFiles, new Function() { @Override public String fun(File file) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java index fffa64cb6ccb..f8c46abf3e57 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/BaseInstrumentingBuilder.java @@ -20,6 +20,7 @@ import com.intellij.compiler.instrumentation.InstrumentationClassFinder; import com.intellij.compiler.instrumentation.InstrumenterClassWriter; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.ModuleChunk; import org.jetbrains.jps.incremental.*; @@ -72,7 +73,7 @@ public abstract class BaseInstrumentingBuilder extends ClassProcessingBuilder { LOG.info(e); final String message = e.getMessage(); if (message != null) { - context.processMessage(new CompilerMessage(getPresentableName(), message, compiledClass.getSourceFilesPaths(), BuildMessage.Kind.ERROR)); + context.processMessage(new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message, ContainerUtil.getFirstItem(compiledClass.getSourceFilesPaths()))); } else { context.processMessage(new CompilerMessage(getPresentableName(), e)); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java index 5ae766ce0e59..a4e7873b373b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/instrumentation/NotNullInstrumentingBuilder.java @@ -93,9 +93,9 @@ public class NotNullInstrumentingBuilder extends BaseInstrumentingBuilder{ } }) + ": " + e.getMessage(); context.processMessage(new CompilerMessage(getPresentableName(), + BuildMessage.Kind.ERROR, msg, - compiledClass.getSourceFilesPaths(), - BuildMessage.Kind.ERROR)); + ContainerUtil.getFirstItem(compiledClass.getSourceFilesPaths()))); } return null; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java index c627ab7df75a..a594a9bef12d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/messages/CompilerMessage.java @@ -16,16 +16,12 @@ package org.jetbrains.jps.incremental.messages; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.Function; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.PrintStream; -import java.util.Collection; -import java.util.Collections; /** * @author Eugene Zhuravlev @@ -37,28 +33,24 @@ public class CompilerMessage extends BuildMessage { private final long myProblemBeginOffset; private final long myProblemEndOffset; private final long myProblemLocationOffset; - private final Collection mySourcePaths; + private final String mySourcePath; private final long myLine; private final long myColumn; public CompilerMessage(@NotNull String compilerName, @NotNull Throwable internalError) { - this(compilerName, Kind.ERROR, getTextFromThrowable(internalError)); + this(compilerName, Kind.ERROR, getTextFromThrowable(internalError), null, -1L, -1L, -1L, -1L, -1L); } public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText) { - this(compilerName, kind, messageText, (String)null, -1L, -1L, -1L, -1L, -1L); - } - - public CompilerMessage(@NotNull String compilerName, String messageText, Collection sourcePaths, Kind kind) { - this(compilerName, kind, messageText, sourcePaths, -1L, -1L, -1L, -1L, -1L); + this(compilerName, kind, messageText, null, -1L, -1L, -1L, -1L, -1L); } public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, String sourcePath) { - this(compilerName, messageText, sourcePath == null ? Collections.emptyList() : Collections.singleton(sourcePath), kind); + this(compilerName, kind, messageText, sourcePath, -1L, -1L, -1L, -1L, -1L); } public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, - @NotNull Collection sourcePaths, + @Nullable String sourcePath, long problemBeginOffset, long problemEndOffset, long problemLocationOffset, @@ -69,34 +61,11 @@ public class CompilerMessage extends BuildMessage { myProblemBeginOffset = problemBeginOffset; myProblemEndOffset = problemEndOffset; myProblemLocationOffset = problemLocationOffset; - mySourcePaths = ContainerUtil.map(sourcePaths, new Function() { - @Override - public String fun(String s) { - return s.replace(File.separatorChar, '/'); - } - }); + mySourcePath = sourcePath != null && !sourcePath.isEmpty()? sourcePath.replace(File.separatorChar, '/') : null; myLine = locationLine; myColumn = locationColumn; } - public CompilerMessage(@NotNull String compilerName, Kind kind, String messageText, - @Nullable String sourcePath, - long problemBeginOffset, - long problemEndOffset, - long problemLocationOffset, - long locationLine, - long locationColumn) { - this(compilerName, - kind, - messageText, - sourcePath == null ? Collections.emptyList() : Collections.singleton(sourcePath), - problemBeginOffset, - problemEndOffset, - problemLocationOffset, - locationLine, - locationColumn); - } - @NotNull public String getCompilerName() { return myCompilerName; @@ -104,7 +73,7 @@ public class CompilerMessage extends BuildMessage { @Nullable public String getSourcePath() { - return mySourcePaths.size() == 1 ? ContainerUtil.getFirstItem(mySourcePaths) : null; + return mySourcePath; } public long getLine() { @@ -130,16 +99,7 @@ public class CompilerMessage extends BuildMessage { public String toString() { final StringBuilder builder = new StringBuilder(); builder.append(getCompilerName()).append(":").append(getKind().name()).append(":").append(super.toString()); - String result; - if (mySourcePaths.isEmpty()) { - result = null; - } - else if (mySourcePaths.size() == 1) { - result = ContainerUtil.getFirstItem(mySourcePaths); - } else { - result = mySourcePaths.toString(); - } - final String path = result; + final String path = getSourcePath(); if (path != null) { builder.append("; file: ").append(path); final long line = getLine(); diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java index 78c18d1aef00..444c78bd77b8 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaDefinitionResolver.java @@ -121,8 +121,7 @@ public class JsonSchemaDefinitionResolver { if (parSchema.getId() != null) { schemaFile = JsonSchemaService.Impl.getEx(myElement.getProject()).getSchemaFileById(parSchema.getId()); } - return resolveInSomeSchema(definitionAddress.substring(1) + PROPERTIES + propertyName, myElement.getProject(), parSchema.getId(), - schemaFile != null ? GlobalSearchScope.fileScope(myElement.getProject(), schemaFile) : null); + return resolveInSomeSchema(definitionAddress.substring(1) + PROPERTIES + propertyName, myElement.getProject(), parSchema.getId(), schemaFile); } else { String relative = splitter.getRelativePath(); if (StringUtil.isEmptyOrSpaces(relative)) { @@ -139,19 +138,20 @@ public class JsonSchemaDefinitionResolver { if (myRef == null) initializeName(); if (myRef == null) return null; - GlobalSearchScope filter = null; + VirtualFile filter = null; if (mySchemaId != null && myRef.startsWith("#/")) { - filter = GlobalSearchScope.fileScope(myElement.getContainingFile()); + filter = myElement.getContainingFile().getVirtualFile(); } else { final JsonSchemaServiceEx schemaServiceEx = JsonSchemaService.Impl.getEx(myElement.getProject()); final Collection> pairs = schemaServiceEx.getSchemaFilesByFile(myElement.getContainingFile().getVirtualFile()); if (pairs != null && ! pairs.isEmpty()) { for (Pair pair : pairs) { - final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), pair.getSecond(), - GlobalSearchScope.fileScope(myElement.getProject(), pair.getFirst())); + final PsiElement element = resolveInSomeSchema(myRef, myElement.getProject(), pair.getSecond(), pair.getFirst()); if (element != null) return element; } + // if not in schema file + if (mySchemaId == null) return null; } } return resolveInSomeSchema(myRef, myElement.getProject(), mySchemaId, filter); @@ -161,10 +161,13 @@ public class JsonSchemaDefinitionResolver { private static PsiElement resolveInSomeSchema(@NotNull String referenceName, @NotNull final Project project, @Nullable final String schemaId, - final @Nullable GlobalSearchScope filter) { + final @Nullable VirtualFile filterFile) { final Ref> reference = new Ref<>(); final FileBasedIndex index = FileBasedIndex.getInstance(); + final GlobalSearchScope fileScope = filterFile == null ? null : GlobalSearchScope.fileScope(project, filterFile); + final GlobalSearchScope enlarged = fileScope != null && JsonSchemaResourcesRootsProvider.ourFiles.getValue().contains(filterFile) ? fileScope : + JsonSchemaResourcesRootsProvider.enlarge(project, fileScope == null ? GlobalSearchScope.allScope(project) : fileScope); index.processValues(JsonSchemaFileIndex.PROPERTIES_INDEX, referenceName, null, new FileBasedIndex.ValueProcessor() { @Override public boolean process(VirtualFile file, Integer value) { @@ -176,7 +179,7 @@ public class JsonSchemaDefinitionResolver { reference.set(Pair.create(file, value)); return false; } - }, JsonSchemaResourcesRootsProvider.enlarge(project, filter == null ? GlobalSearchScope.allScope(project) : filter)); + }, enlarged); if (!reference.isNull()) { final Pair pair = reference.get(); diff --git a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaFileIndex.java b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaFileIndex.java index 296bf2d23f2a..d61dea1c9ca5 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaFileIndex.java +++ b/json/src/com/jetbrains/jsonSchema/extension/schema/JsonSchemaFileIndex.java @@ -35,7 +35,7 @@ import java.util.Map; */ public class JsonSchemaFileIndex extends FileBasedIndexExtension { public static final ID PROPERTIES_INDEX = ID.create("json.schema.properties.index"); - public static final int VERSION = 4; + public static final int VERSION = 5; private IntInlineKeyDescriptor myKeyDescriptor = new IntInlineKeyDescriptor(); @NotNull diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java index dd6801d6a931..97637deb51f8 100644 --- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java +++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/SeverityRegistrar.java @@ -159,6 +159,11 @@ public class SeverityRegistrar implements Comparator { read.add(severity); } } + myOrderMap = ensureAllStandardIncluded(read, knownSeverities); + severitiesChanged(); + } + + private OrderMap ensureAllStandardIncluded(List read, final List knownSeverities) { OrderMap orderMap = fromList(read); if (orderMap.isEmpty()) { orderMap = fromList(knownSeverities); @@ -182,8 +187,7 @@ public class SeverityRegistrar implements Comparator { } orderMap = fromList(list); } - myOrderMap = orderMap; - severitiesChanged(); + return orderMap; } public void writeExternal(Element element) { @@ -345,7 +349,7 @@ public class SeverityRegistrar implements Comparator { } public void setOrder(@NotNull List orderList) { - myOrderMap = fromList(orderList); + myOrderMap = ensureAllStandardIncluded(orderList, getDefaultOrder()); myReadOrder = null; severitiesChanged(); } diff --git a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt index a0ea74611b0d..cf06a8f296f8 100644 --- a/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt +++ b/platform/analysis-impl/src/com/intellij/profile/codeInspection/ProjectInspectionProfileManager.kt @@ -21,6 +21,7 @@ import com.intellij.codeInspection.ex.InspectionToolRegistrar import com.intellij.configurationStore.SchemeDataHolder import com.intellij.configurationStore.SchemeManagerIprProvider import com.intellij.configurationStore.digest +import com.intellij.configurationStore.wrapState import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.PersistentStateComponent @@ -32,7 +33,6 @@ import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ProjectManagerListener import com.intellij.openapi.startup.StartupActivity import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.JDOMUtil import com.intellij.openapi.util.text.StringUtil import com.intellij.packageDependencies.DependencyValidationManager import com.intellij.profile.Profile @@ -209,6 +209,23 @@ class ProjectInspectionProfileManager(val project: Project, } } + @Synchronized override fun getState(): Element? { + val result = Element("settings") + + schemeManagerIprProvider?.writeState(result) + + val state = this.state + state.projectProfile = schemeManager.currentSchemeName + XmlSerializer.serializeInto(state, result, skipDefaultsSerializationFilter) + if (!result.children.isEmpty()) { + result.addContent(Element("version").setAttribute("value", VERSION)) + } + + severityRegistrar.writeExternal(result) + + return wrapState(result) + } + @Synchronized override fun loadState(state: Element) { val data = state.getChild("settings") @@ -250,29 +267,6 @@ class ProjectInspectionProfileManager(val project: Project, } } - @Synchronized override fun getState(): Element? { - val result = Element("settings") - - schemeManagerIprProvider?.writeState(result) - - val state = this.state - state.projectProfile = schemeManager.currentSchemeName - XmlSerializer.serializeInto(state, result, skipDefaultsSerializationFilter) - if (!result.children.isEmpty()) { - result.addContent(Element("version").setAttribute("value", VERSION)) - } - - severityRegistrar.writeExternal(result) - - if (JDOMUtil.isEmpty(result)) { - result.name = "state" - return result - } - else { - return Element("state").addContent(result) - } - } - override fun getScopesManager() = scopeManager @Synchronized override fun getProfiles(): Collection { diff --git a/platform/configuration-store-impl/src/SchemeManagerImpl.kt b/platform/configuration-store-impl/src/SchemeManagerImpl.kt index 50634e5b4433..3b759da23c11 100644 --- a/platform/configuration-store-impl/src/SchemeManagerImpl.kt +++ b/platform/configuration-store-impl/src/SchemeManagerImpl.kt @@ -370,12 +370,16 @@ class SchemeManagerImpl(val fileSpec: String, override fun updateDigest(scheme: MUTABLE_SCHEME) { try { - externalInfo.digest = (processor.writeScheme(scheme) as Element).digest() + updateDigest(processor.writeScheme(scheme) as Element) } catch (e: WriteExternalException) { LOG.error("Cannot update digest", e) } } + + override fun updateDigest(data: Element) { + externalInfo.digest = data.digest() + } } private fun loadScheme(fileName: String, input: InputStream, schemes: MutableList, filesToDelete: MutableSet? = null): MUTABLE_SCHEME? { @@ -438,7 +442,7 @@ class SchemeManagerImpl(val fileSpec: String, XmlPullParser.START_TAG -> { if (!isUseOldFileNameSanitize || parser.name != "component") { var name: String? = null - if (isUseOldFileNameSanitize && parser.name == "profile") { + if (isUseOldFileNameSanitize && (parser.name == "profile" || parser.name == "copyright")) { eventType = parser.next() findName@ while (eventType != XmlPullParser.END_DOCUMENT) { when (eventType) { diff --git a/platform/core-api/src/com/intellij/diagnostic/ImplementationConflictException.java b/platform/core-api/src/com/intellij/diagnostic/ImplementationConflictException.java new file mode 100644 index 000000000000..e9348739f3e4 --- /dev/null +++ b/platform/core-api/src/com/intellij/diagnostic/ImplementationConflictException.java @@ -0,0 +1,44 @@ +/* + * 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.diagnostic; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class ImplementationConflictException extends RuntimeException { + + @NotNull + private final Collection> myConflictingClasses; + + public ImplementationConflictException(String message, Throwable cause, @NotNull Object ...implementationObjects) { + super(message, cause); + final List> classes = new ArrayList>(); + for (Object object : implementationObjects) { + classes.add(object.getClass()); + } + + myConflictingClasses = Collections.unmodifiableList(classes); + } + + @NotNull + public Collection> getConflictingClasses() { + return myConflictingClasses; + } +} diff --git a/platform/core-api/src/com/intellij/lang/Language.java b/platform/core-api/src/com/intellij/lang/Language.java index d941110520dc..9dbe2bccff2f 100644 --- a/platform/core-api/src/com/intellij/lang/Language.java +++ b/platform/core-api/src/com/intellij/lang/Language.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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. @@ -15,6 +15,7 @@ */ package com.intellij.lang; +import com.intellij.diagnostic.ImplementationConflictException; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.FileTypeRegistry; @@ -24,7 +25,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.containers.ContainerUtil; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,12 +33,10 @@ import java.util.concurrent.ConcurrentMap; /** * The base class for all programming language support implementations. Specific language implementations should inherit from this class - * and its register instance wrapped with {@link com.intellij.openapi.fileTypes.LanguageFileType} instance through - * FileTypeManager.getInstance().registerFileType + * and its register instance wrapped with {@link LanguageFileType} instance via {@code FileTypeManager.getInstance().registerFileType()}. * There should be exactly one instance of each Language. - * It is usually created when creating {@link com.intellij.openapi.fileTypes.LanguageFileType} and can be retrieved later - * with {@link #findInstance(Class)}. - * For the list of standard languages, see {@link com.intellij.lang.StdLanguages}. + * It is usually created when creating {@link LanguageFileType} and can be retrieved later with {@link #findInstance(Class)}. + * For the list of standard languages, see {@code com.intellij.lang.StdLanguages}. */ public abstract class Language extends UserDataHolderBase { private static final Logger LOG = Logger.getInstance("#com.intellij.lang.Language"); @@ -46,14 +44,15 @@ public abstract class Language extends UserDataHolderBase { private static final Map, Language> ourRegisteredLanguages = ContainerUtil.newConcurrentMap(); private static final ConcurrentMap> ourRegisteredMimeTypes = ContainerUtil.newConcurrentMap(); private static final Map ourRegisteredIDs = ContainerUtil.newConcurrentMap(); + private final Language myBaseLanguage; private final String myID; private final String[] myMimeTypes; private final List myDialects = ContainerUtil.createLockFreeCopyOnWriteList(); + public static final Language ANY = new Language("") { @Override public String toString() { - //noinspection HardCodedStringLiteral return "Language: ANY"; } @@ -64,28 +63,31 @@ public abstract class Language extends UserDataHolderBase { } }; - protected Language(@NotNull @NonNls String ID) { + protected Language(@NotNull String ID) { this(ID, ArrayUtil.EMPTY_STRING_ARRAY); } - protected Language(@NotNull @NonNls final String ID, @NotNull @NonNls final String... mimeTypes) { + protected Language(@NotNull String ID, @NotNull String... mimeTypes) { this(null, ID, mimeTypes); } - protected Language(@Nullable Language baseLanguage, @NotNull @NonNls final String ID, @NotNull @NonNls final String... mimeTypes) { + protected Language(@Nullable Language baseLanguage, @NotNull String ID, @NotNull String... mimeTypes) { myBaseLanguage = baseLanguage; myID = ID; myMimeTypes = mimeTypes; + Class langClass = getClass(); Language prev = ourRegisteredLanguages.put(langClass, this); if (prev != null) { - LOG.error("Language of '" + langClass + "' is already registered: " + prev); + LOG.error(new ImplementationConflictException("Language of '" + langClass + "' is already registered: " + prev, null, prev, this)); return; } + prev = ourRegisteredIDs.put(ID, this); if (prev != null) { - LOG.error("Language with ID '" + ID + "' is already registered: " + prev.getClass()); + LOG.error(new ImplementationConflictException("Language with ID '" + ID + "' is already registered: " + prev.getClass(), null, prev, this)); } + for (String mimeType : mimeTypes) { if (StringUtil.isEmpty(mimeType)) { continue; @@ -96,6 +98,7 @@ public abstract class Language extends UserDataHolderBase { } languagesByMimeType.add(this); } + if (baseLanguage != null) { baseLanguage.myDialects.add(this); } @@ -129,10 +132,8 @@ public abstract class Language extends UserDataHolderBase { return result == null ? Collections.emptyList() : Collections.unmodifiableCollection(result); } - @Override public String toString() { - //noinspection HardCodedStringLiteral return "Language: " + myID; } @@ -228,4 +229,4 @@ public abstract class Language extends UserDataHolderBase { myBaseLanguage = null; myMimeTypes = null; } -} +} \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/openapi/module/Module.java b/platform/core-api/src/com/intellij/openapi/module/Module.java index 36c9bef94dc9..155d71eb9bdd 100644 --- a/platform/core-api/src/com/intellij/openapi/module/Module.java +++ b/platform/core-api/src/com/intellij/openapi/module/Module.java @@ -102,41 +102,58 @@ public interface Module extends ComponentManager, AreaInstance, Disposable { String getOptionValue(@NotNull String key); /** - * Returns module scope including sources and tests, excluding libraries and dependencies. - * - * @return scope including sources and tests, excluding libraries and dependencies. + * @return module scope including source and tests, excluding libraries and dependencies. */ @NotNull GlobalSearchScope getModuleScope(); + /** + * @param includeTests whether to include test source + * @return module scope including source and, optionally, tests, excluding libraries and dependencies. + */ @NotNull GlobalSearchScope getModuleScope(boolean includeTests); /** - * Returns module scope including sources, tests, and libraries, excluding dependencies. - * - * @return scope including sources, tests, and libraries, excluding dependencies. + * @return module scope including source, tests, and libraries, excluding dependencies. */ @NotNull GlobalSearchScope getModuleWithLibrariesScope(); /** - * Returns module scope including sources, tests, and dependencies, excluding libraries. - * - * @return scope including sources, tests, and dependencies, excluding libraries. + * @return module scope including source, tests, and dependencies, excluding libraries. */ @NotNull GlobalSearchScope getModuleWithDependenciesScope(); + /** + * @return a scope that includes everything in module content roots, without any dependencies or libraries + */ @NotNull GlobalSearchScope getModuleContentScope(); + + /** + * @return a scope that includes everything under the content roots of this module and its dependencies, with test source + */ @NotNull GlobalSearchScope getModuleContentWithDependenciesScope(); + /** + * @param includeTests whether test source and test dependencies should be included + * @return a scope including module source and dependencies with libraries + */ @NotNull GlobalSearchScope getModuleWithDependenciesAndLibrariesScope(boolean includeTests); + + /** + * @return a scope including everything under the content roots of this module and all modules that depend on it, directly or indirectly (via exported dependencies), excluding test source and resources + */ @NotNull GlobalSearchScope getModuleWithDependentsScope(); + + /** + * @return same as {@link #getModuleWithDependentsScope()}, but with test source/resources included + */ @NotNull GlobalSearchScope getModuleTestsWithDependentsScope(); @NotNull diff --git a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java index fcf71fd24fc1..2221418c116c 100644 --- a/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java +++ b/platform/core-impl/src/com/intellij/openapi/components/impl/ComponentManagerImpl.java @@ -383,11 +383,10 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements private void registerComponents(@NotNull ComponentConfig config) { ClassLoader loader = config.getClassLoader(); try { - final Class interfaceClass = Class.forName(config.getInterfaceClass(), true, loader); - final Class implementationClass = Comparing.equal(config.getInterfaceClass(), config.getImplementationClass()) - ? - interfaceClass - : StringUtil.isEmpty(config.getImplementationClass()) ? null : Class.forName(config.getImplementationClass(), true, loader); + Class interfaceClass = Class.forName(config.getInterfaceClass(), true, loader); + Class implementationClass = Comparing.equal(config.getInterfaceClass(), config.getImplementationClass()) ? interfaceClass : + StringUtil.isEmpty(config.getImplementationClass()) ? null : + Class.forName(config.getImplementationClass(), true, loader); MutablePicoContainer picoContainer = getPicoContainer(); if (config.options != null && Boolean.parseBoolean(config.options.get("overrides"))) { ComponentAdapter oldAdapter = picoContainer.getComponentAdapterOfType(interfaceClass); @@ -398,8 +397,8 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements } // implementationClass == null means we want to unregister this component if (implementationClass != null) { - picoContainer.registerComponent(new ComponentConfigComponentAdapter(interfaceClass, implementationClass, config.getPluginId(), - config.options != null && Boolean.parseBoolean(config.options.get("workspace")))); + boolean ws = config.options != null && Boolean.parseBoolean(config.options.get("workspace")); + picoContainer.registerComponent(new ComponentConfigComponentAdapter(interfaceClass, implementationClass, config.getPluginId(), ws)); } } catch (Throwable t) { @@ -522,4 +521,4 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements return "ComponentConfigAdapter[" + getComponentKey() + "]: implementation=" + getComponentImplementation() + ", plugin=" + myPluginId; } } -} +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java index 9153a80dd67d..4ec77f5e5b8c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/TrafficLightRenderer.java @@ -115,12 +115,8 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { private void refresh() { int maxIndex = mySeverityRegistrar.getSeverityMaxIndex(); - if (errorCount != null && maxIndex == errorCount.length) return; - int[] newErrors = new int[maxIndex+1]; - if (errorCount != null) { - System.arraycopy(errorCount, 0, newErrors, 0, Math.min(errorCount.length, newErrors.length)); - } - errorCount = newErrors; + if (errorCount != null && maxIndex + 1 == errorCount.length) return; + errorCount = new int[maxIndex + 1]; } static void setOrRefreshErrorStripeRenderer(@NotNull EditorMarkupModel editorMarkupModel, @@ -334,7 +330,7 @@ public class TrafficLightRenderer implements ErrorStripeRenderer, Disposable { Icon icon = AllIcons.General.InspectionsOK; for (int i = status.errorCount.length - 1; i >= 0; i--) { - if (status.errorCount[i] != 0) { + if (status.errorCount[i] > 0) { icon = SeverityRegistrar.getSeverityRegistrar(project).getRendererIconByIndex(i); break; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java index b4d905848c2c..ffe46825d84b 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/TemplateManager.java @@ -56,4 +56,10 @@ public abstract class TemplateManager { @Nullable public abstract Template getActiveTemplate(@NotNull Editor editor); + + /** + * Finished a live template in the given editor, if it's present + * @return whether a live template was present + */ + public abstract boolean finishTemplate(@NotNull Editor editor); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java index 64d7fe640fd5..6f5e4f455133 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateManagerImpl.java @@ -521,6 +521,16 @@ public class TemplateManagerImpl extends TemplateManager implements Disposable { return templateState != null ? templateState.getTemplate() : null; } + @Override + public boolean finishTemplate(@NotNull Editor editor) { + TemplateState state = getTemplateState(editor); + if (state != null) { + state.gotoEnd(); + return true; + } + return false; + } + public static boolean isApplicable(PsiFile file, int offset, TemplateImpl template) { return isApplicable(template, getApplicableContextTypes(file, offset)); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java index 813412589ea6..0a4e9104df61 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/CleanupInspectionIntention.java @@ -31,16 +31,16 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Computable; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.IncorrectOperationException; import com.intellij.util.SequentialModalProgressTask; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -74,39 +74,45 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException { - if (!FileModificationService.getInstance().preparePsiElementForWrite(file)) return; + final List descriptions = ProgressManager.getInstance().runProcess(() -> { InspectionManager inspectionManager = InspectionManager.getInstance(project); return InspectionEngine.runInspectionOnFile(file, myToolWrapper, inspectionManager.createNewGlobalContext(false)); }, new EmptyProgressIndicator()); - Collections.sort(descriptions, new Comparator() { - @Override - public int compare(final CommonProblemDescriptor o1, final CommonProblemDescriptor o2) { - final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1; - final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2; - final int offset2 = d2.getTextRange().getStartOffset(); - final int offset1 = d1.getTextRange().getStartOffset(); - return offset2 < offset1 ? -1 : offset1 == offset2 ? 0 : 1; - } + if (!descriptions.isEmpty() && !FileModificationService.getInstance().preparePsiElementForWrite(file)) return; + + final AbstractPerformFixesTask fixesTask = applyFixes(project, "Apply Fixes", descriptions, myQuickfixClass); + + if (!fixesTask.isApplicableFixFound()) { + HintManager.getInstance().showErrorHint(editor, "Unfortunately '" + myText + "' is currently not available for batch mode\n User interaction is required for each problem found"); + } + } + + public static AbstractPerformFixesTask applyFixes(@NotNull Project project, + @NotNull String presentationText, + @NotNull List descriptions, + @Nullable Class quickfixClass) { + Collections.sort(descriptions, (o1, o2) -> { + final ProblemDescriptorBase d1 = (ProblemDescriptorBase)o1; + final ProblemDescriptorBase d2 = (ProblemDescriptorBase)o2; + return -PsiUtilCore.compareElementsByPosition(d1.getPsiElement(), d2.getPsiElement()); }); - - final String templatePresentationText = "Apply Fixes"; + final SequentialModalProgressTask progressTask = - new SequentialModalProgressTask(project, templatePresentationText, true); - final boolean isBatch = BatchQuickFix.class.isAssignableFrom(myQuickfixClass); - final AbstractPerformFixesTask fixesTask = createTask(project, descriptions.toArray(new ProblemDescriptor[descriptions.size()]), progressTask, isBatch); + new SequentialModalProgressTask(project, presentationText, true); + final boolean isBatch = quickfixClass != null && BatchQuickFix.class.isAssignableFrom(quickfixClass); + final AbstractPerformFixesTask fixesTask = isBatch ? + new PerformBatchFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass) : + new PerformFixesTask(project, descriptions.toArray(ProblemDescriptor.EMPTY_ARRAY), progressTask, quickfixClass); CommandProcessor.getInstance().executeCommand(project, () -> { CommandProcessor.getInstance().markCurrentCommandAsGlobal(project); progressTask.setMinIterationTime(200); progressTask.setTask(fixesTask); ProgressManager.getInstance().run(progressTask); - }, templatePresentationText, null); - - if (!fixesTask.isApplicableFixFound()) { - HintManager.getInstance().showErrorHint(editor, "Unfortunately '" + myText + "' is currently not available for batch mode\n User interaction is required for each problem found"); - } + }, presentationText, null); + return fixesTask; } @Override @@ -120,23 +126,16 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority return false; } - @NotNull - private AbstractPerformFixesTask createTask(@NotNull Project project, - ProblemDescriptor[] descriptions, - SequentialModalProgressTask progressTask, - boolean isBatch) { - return isBatch ? - new PerformBatchFixesTask(project, descriptions, progressTask) : - new PerformFixesTask(project, descriptions, progressTask); - } - - private abstract class AbstractPerformFixesTask extends PerformFixesModalTask { + private static abstract class AbstractPerformFixesTask extends PerformFixesModalTask { private boolean myApplicableFixFound = false; + protected final Class myQuickfixClass; public AbstractPerformFixesTask(@NotNull Project project, - @NotNull CommonProblemDescriptor[] descriptors, - @NotNull SequentialModalProgressTask task) { + @NotNull CommonProblemDescriptor[] descriptors, + @NotNull SequentialModalProgressTask task, + @Nullable Class quickfixClass) { super(project, descriptors, task); + myQuickfixClass = quickfixClass; } protected abstract void collectFix(QuickFix fix, ProblemDescriptor descriptor, Project project); @@ -146,7 +145,7 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority final QuickFix[] fixes = descriptor.getFixes(); if (fixes != null && fixes.length > 0) { for (final QuickFix fix : fixes) { - if (fix != null && fix.getClass().isAssignableFrom(myQuickfixClass)) { + if (fix != null && (myQuickfixClass == null || fix.getClass().isAssignableFrom(myQuickfixClass))) { final ProblemDescriptor problemDescriptor = (ProblemDescriptor)descriptor; final PsiElement element = problemDescriptor.getPsiElement(); if (element != null && element.isValid()) { @@ -164,14 +163,15 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority } } - private class PerformBatchFixesTask extends AbstractPerformFixesTask { + private static class PerformBatchFixesTask extends AbstractPerformFixesTask { private final List myBatchModeDescriptors = new ArrayList<>(); private boolean myApplied = false; public PerformBatchFixesTask(@NotNull Project project, @NotNull CommonProblemDescriptor[] descriptors, - @NotNull SequentialModalProgressTask task) { - super(project, descriptors, task); + @NotNull SequentialModalProgressTask task, + @NotNull Class quickfixClass) { + super(project, descriptors, task, quickfixClass); } @Override @@ -204,11 +204,12 @@ public class CleanupInspectionIntention implements IntentionAction, HighPriority } } - private class PerformFixesTask extends AbstractPerformFixesTask { + private static class PerformFixesTask extends AbstractPerformFixesTask { public PerformFixesTask(@NotNull Project project, @NotNull CommonProblemDescriptor[] descriptors, - @NotNull SequentialModalProgressTask task) { - super(project, descriptors, task); + @NotNull SequentialModalProgressTask task, + @Nullable Class quickFixClass) { + super(project, descriptors, task, quickFixClass); } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java index aa16bf133356..f5fba8dec473 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/GlobalInspectionContextImpl.java @@ -20,10 +20,10 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.analysis.AnalysisUIOptions; import com.intellij.analysis.PerformAnalysisInBackgroundOption; import com.intellij.codeInsight.FileModificationService; -import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoProcessor; import com.intellij.codeInsight.daemon.impl.LocalInspectionsPass; import com.intellij.codeInspection.*; +import com.intellij.codeInspection.actions.CleanupInspectionIntention; import com.intellij.codeInspection.lang.GlobalInspectionContextExtension; import com.intellij.codeInspection.reference.RefElement; import com.intellij.codeInspection.reference.RefEntity; @@ -47,7 +47,6 @@ import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.TransactionGuard; import com.intellij.openapi.application.ex.ApplicationManagerEx; -import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.components.PathMacroManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; @@ -77,8 +76,9 @@ import com.intellij.psi.util.PsiUtilCore; import com.intellij.ui.GuiUtils; import com.intellij.ui.content.*; import com.intellij.util.*; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.*; import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.HashSet; import com.intellij.util.ui.UIUtil; import gnu.trove.THashSet; import org.jdom.Element; @@ -92,6 +92,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.lang.reflect.Constructor; import java.util.*; +import java.util.Queue; import java.util.concurrent.*; public class GlobalInspectionContextImpl extends GlobalInspectionContextBase implements GlobalInspectionContext { @@ -889,8 +890,6 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator(); final List lTools = new ArrayList<>(); - final LinkedHashMap> results = new LinkedHashMap<>(); - final SearchScope searchScope = scope.toSearchScope(); final TextRange range; if (searchScope instanceof LocalSearchScope) { @@ -909,47 +908,66 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp assert tools != null; return tools.getTool().getTool() instanceof CleanupLocalInspectionTool; }); + List descriptors = new ArrayList<>(); + Set files = new HashSet<>(); boolean includeDoNotShow = includeDoNotShow(profile); - scope.accept(new PsiElementVisitor() { - private int myCount; - @Override - public void visitFile(PsiFile file) { - if (progressIndicator != null) { - progressIndicator.setFraction((double)++myCount / fileCount); - } - if (isBinary(file)) return; - for (final Tools tools : inspectionTools) { - final InspectionToolWrapper tool = tools.getEnabledTool(file, includeDoNotShow); - if (tool instanceof LocalInspectionToolWrapper) { - lTools.add((LocalInspectionToolWrapper)tool); - tool.initialize(GlobalInspectionContextImpl.this); + final RefManagerImpl refManager = (RefManagerImpl)getRefManager(); + refManager.inspectionReadActionStarted(); + try { + scope.accept(new PsiElementVisitor() { + private int myCount; + @Override + public void visitFile(PsiFile file) { + if (progressIndicator != null) { + progressIndicator.setFraction((double)++myCount / fileCount); } - } - - if (!lTools.isEmpty()) { - final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(getProject()).getDocument(file), range != null ? range.getStartOffset() : 0, - range != null ? range.getEndOffset() : file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true, - HighlightInfoProcessor.getEmpty()); - Runnable runnable = () -> pass.doInspectInBatch(GlobalInspectionContextImpl.this, InspectionManager.getInstance(getProject()), lTools); - ApplicationManager.getApplication().runReadAction(runnable); - final List infos = pass.getInfos(); - if (searchScope instanceof LocalSearchScope) { - for (Iterator iterator = infos.iterator(); iterator.hasNext(); ) { - final HighlightInfo info = iterator.next(); - final TextRange infoRange = new TextRange(info.getStartOffset(), info.getEndOffset()); - if (!((LocalSearchScope)searchScope).containsRange(file, infoRange)) { - iterator.remove(); - } + if (isBinary(file)) return; + for (final Tools tools : inspectionTools) { + final InspectionToolWrapper tool = tools.getEnabledTool(file, includeDoNotShow); + if (tool instanceof LocalInspectionToolWrapper) { + lTools.add((LocalInspectionToolWrapper)tool); + tool.initialize(GlobalInspectionContextImpl.this); } } - if (!infos.isEmpty()) { - results.put(file, infos); + + if (!lTools.isEmpty()) { + final LocalInspectionsPass pass = new LocalInspectionsPass(file, PsiDocumentManager.getInstance(getProject()).getDocument(file), range != null ? range.getStartOffset() : 0, + range != null ? range.getEndOffset() : file.getTextLength(), LocalInspectionsPass.EMPTY_PRIORITY_RANGE, true, + HighlightInfoProcessor.getEmpty()); + Runnable runnable = () -> pass.doInspectInBatch(GlobalInspectionContextImpl.this, InspectionManager.getInstance(getProject()), lTools); + ApplicationManager.getApplication().runReadAction(runnable); + + List localDescriptors = new ArrayList<>(); + for (LocalInspectionToolWrapper tool : lTools) { + for (CommonProblemDescriptor descriptor : getPresentation(tool).getProblemDescriptors()) { + if (descriptor instanceof ProblemDescriptor) { + localDescriptors.add((ProblemDescriptor)descriptor); + } + } + } + + if (searchScope instanceof LocalSearchScope) { + for (Iterator iterator = localDescriptors.iterator(); iterator.hasNext(); ) { + final ProblemDescriptor descriptor = iterator.next(); + final TextRange infoRange = descriptor instanceof ProblemDescriptorBase ? ((ProblemDescriptorBase)descriptor).getTextRange() : null; + if (infoRange != null && !((LocalSearchScope)searchScope).containsRange(file, infoRange)) { + iterator.remove(); + } + } + } + if (!localDescriptors.isEmpty()) { + descriptors.addAll(localDescriptors); + files.add(file); + } } } - } - }); + }); + } + finally { + refManager.inspectionReadActionFinished(); + } - if (results.isEmpty()) { + if (files.isEmpty()) { GuiUtils.invokeLaterIfNeeded(() -> { if (commandName != null) { NOTIFICATION_GROUP.createNotification(InspectionsBundle.message("inspection.no.problems.message", scope.getFileCount(), scope.getDisplayName()), MessageType.INFO).notify(getProject()); @@ -961,21 +979,8 @@ public class GlobalInspectionContextImpl extends GlobalInspectionContextBase imp return; } Runnable runnable = () -> { - if (!FileModificationService.getInstance().preparePsiElementsForWrite(results.keySet())) return; - - final String title = "Code Cleanup"; - final SequentialModalProgressTask progressTask = new SequentialModalProgressTask(getProject(), title, true); - progressTask.setMinIterationTime(200); - progressTask.setTask(new SequentialCleanupTask(getProject(), results, progressTask)); - CommandProcessor.getInstance().executeCommand(getProject(), () -> { - if (commandName != null) { - CommandProcessor.getInstance().markCurrentCommandAsGlobal(getProject()); - } - ProgressManager.getInstance().run(progressTask); - if (postRunnable != null) { - ApplicationManager.getApplication().invokeLater(postRunnable); - } - }, title, null); + if (!FileModificationService.getInstance().preparePsiElementsForWrite(files)) return; + CleanupInspectionIntention.applyFixes(getProject(), "Code Cleanup", descriptors, null); }; TransactionGuard.submitTransaction(getProject(), runnable); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProvider.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProvider.java index 35f2ca182bb8..3251b80df54d 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProvider.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProvider.java @@ -20,6 +20,7 @@ */ package com.intellij.codeInspection.ex; +import com.intellij.codeInsight.daemon.impl.HighlightInfoType; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.QuickFix; import com.intellij.codeInspection.reference.RefDirectory; @@ -279,21 +280,25 @@ public abstract class InspectionRVContentProvider { continue; } } - for (RefElementNode parentNode : parentNodes) { - final List nodes = new ArrayList<>(); - TreeUtil.traverse(parentNode, new TreeUtil.Traverse() { - @Override - public boolean accept(final Object node) { - if (node instanceof ProblemDescriptionNode) { - nodes.add((ProblemDescriptionNode)node); + + //allow unused declaration to have structure at file level even when there are unused parameters + if (!HighlightInfoType.UNUSED_SYMBOL_SHORT_NAME.equals(toolWrapper.getShortName())) { + for (RefElementNode parentNode : parentNodes) { + final List nodes = new ArrayList<>(); + TreeUtil.traverse(parentNode, new TreeUtil.Traverse() { + @Override + public boolean accept(final Object node) { + if (node instanceof ProblemDescriptionNode) { + nodes.add((ProblemDescriptionNode)node); + } + return true; } - return true; + }); + if (nodes.isEmpty()) continue; + parentNode.removeAllChildren(); + for (ProblemDescriptionNode node : nodes) { + parentNode.add(node); } - }); - if (nodes.isEmpty()) continue; //FilteringInspectionTool == DeadCode - parentNode.removeAllChildren(); - for (ProblemDescriptionNode node : nodes) { - parentNode.add(node); } } for (RefElementNode node : parentNodes) { diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java index 57635c5a0c5f..01a27855fce9 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ex/InspectionRVContentProviderImpl.java @@ -81,7 +81,7 @@ public class InspectionRVContentProviderImpl extends InspectionRVContentProvider public QuickFixAction[] getQuickFixes(@NotNull final InspectionToolWrapper toolWrapper, @NotNull final InspectionTree tree) { final RefEntity[] refEntities = tree.getSelectedElements(); InspectionToolPresentation presentation = tree.getContext().getPresentation(toolWrapper); - return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree.getSelectedDescriptors()); + return refEntities.length == 0 ? null : presentation.getQuickFixes(refEntities, tree); } diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java b/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java deleted file mode 100644 index f72eabaebb82..000000000000 --- a/platform/lang-impl/src/com/intellij/codeInspection/ex/SequentialCleanupTask.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2000-2015 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.codeInspection.ex; - -import com.intellij.codeInsight.daemon.impl.HighlightInfo; -import com.intellij.openapi.actionSystem.ActionManager; -import com.intellij.openapi.application.AccessToken; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.WriteAction; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.PsiFile; -import com.intellij.util.SequentialModalProgressTask; -import com.intellij.util.SequentialTask; - -import java.util.*; - -class SequentialCleanupTask implements SequentialTask { - private static final Logger LOG = Logger.getInstance(SequentialCleanupTask.class); - - private final Project myProject; - private final List> myResults = new ArrayList<>(); - private final SequentialModalProgressTask myProgressTask; - private int myCount = 0; - - public SequentialCleanupTask(Project project, LinkedHashMap> results, SequentialModalProgressTask task) { - myProject = project; - for (Map.Entry> entry : results.entrySet()) { - PsiFile file = entry.getKey(); - List infos = entry.getValue(); - // sort from bottom to top - Collections.sort(infos, (info1, info2) -> info2.getStartOffset() - info1.getStartOffset()); - for (HighlightInfo info : infos) { - myResults.add(Pair.create(file, info)); - } - } - myProgressTask = task; - } - - @Override - public void prepare() {} - - @Override - public boolean isDone() { - return myCount > myResults.size() - 1; - } - - @Override - public boolean iteration() { - final Pair pair = myResults.get(myCount++); - final ProgressIndicator indicator = myProgressTask.getIndicator(); - if (indicator != null) { - indicator.setFraction((double) myCount/myResults.size()); - indicator.setText("Processing " + pair.first.getName()); - } - for (final Pair actionRange : pair.second.quickFixActionRanges) { - final AccessToken token = WriteAction.start(); - try { - actionRange.getFirst().getAction().invoke(myProject, null, pair.first); - } - catch (ProcessCanceledException e) { - throw e; - } - catch (Exception e) { - LOG.error(e); - } - finally { - token.finish(); - } - } - return true; - } - - @Override - public void stop() {} -} diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java index 1eea4e076c80..7111ed4853f5 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/DefaultInspectionToolPresentation.java @@ -618,8 +618,8 @@ public class DefaultInspectionToolPresentation implements ProblemDescriptionsPro @Override @Nullable - public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) { - return extractActiveFixes(refElements, getProblemElements(), allowedDescriptors); + public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, InspectionTree tree) { + return extractActiveFixes(refElements, getProblemElements(), tree != null ? tree.getSelectedDescriptors() : null); } @Override diff --git a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java index d77a3d7d34e6..be718f0fb4c6 100644 --- a/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java +++ b/platform/lang-impl/src/com/intellij/codeInspection/ui/InspectionToolPresentation.java @@ -80,7 +80,7 @@ public interface InspectionToolPresentation extends ProblemDescriptionsProcessor @NotNull Set getModuleProblems(); @Nullable - QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable CommonProblemDescriptor[] descriptors); + QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, @Nullable InspectionTree tree); @NotNull Map getProblemElements(); @NotNull diff --git a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateSettings.java b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateSettings.java index 3a93d1a617f5..b6e96738bded 100644 --- a/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateSettings.java +++ b/platform/lang-impl/src/com/intellij/ide/fileTemplates/impl/FileTemplateSettings.java @@ -52,7 +52,7 @@ public class FileTemplateSettings extends FileTemplatesLoader implements Persist @Nullable @Override public Element getState() { - Element element = null; + Element element = new Element("fileTemplateSettings"); for (FTManager manager : getAllManagers()) { Element templatesGroup = null; for (FileTemplateBase template : manager.getAllTemplates(true)) { @@ -75,9 +75,6 @@ public class FileTemplateSettings extends FileTemplatesLoader implements Persist if (templatesGroup == null) { templatesGroup = new Element(getXmlElementGroupName(manager)); - if (element == null) { - element = new Element("fileTemplateSettings"); - } element.addContent(templatesGroup); } templatesGroup.addContent(templateElement); diff --git a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewToolWindowFactory.java b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewToolWindowFactory.java index f4b3803a63d0..764228fc4ef5 100644 --- a/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewToolWindowFactory.java +++ b/platform/lang-impl/src/com/intellij/ide/projectView/impl/ProjectViewToolWindowFactory.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,13 +22,13 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowFactoryEx; +import com.intellij.openapi.wm.ToolWindowFactory; import org.jetbrains.annotations.NotNull; /** * @author yole */ -public class ProjectViewToolWindowFactory implements ToolWindowFactoryEx, DumbAware { +public class ProjectViewToolWindowFactory implements ToolWindowFactory, DumbAware { @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { ((ProjectViewImpl) ProjectView.getInstance(project)).setupImpl(toolWindow); diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java index 7cfc0ee621fa..3f0e5c0341f8 100644 --- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java +++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/header/InspectionToolsConfigurable.java @@ -667,9 +667,7 @@ public abstract class InspectionToolsConfigurable extends BaseConfigurable @Override public JComponent getPreferredFocusedComponent() { - final InspectionProfileImpl inspectionProfile = myProfiles.getProfilesComboBox().getSelectedProfile(); - SingleInspectionProfilePanel panel = getProfilePanel(inspectionProfile); - return panel == null ? null : panel.getPreferredFocusedComponent(); + return myProfilePanelHolder; } private void showProfile(InspectionProfileImpl profile) { diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java index cc198e18a140..7ae725e4ac62 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactory.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. @@ -23,8 +23,24 @@ import org.jetbrains.annotations.NotNull; * Performs lazy initialization of a toolwindow registered in plugin.xml. * * @author yole + * @author Konstantin Bulenkov * @see ToolWindowEP */ public interface ToolWindowFactory { void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow); + + /** + * Perform additional initialisation routine here + * @param window Tool Window + */ + default void init(ToolWindow window) {} + + /** + * Tool Window saves its state on project close and restore on when project opens + * In some cases, it is useful to postpone Tool Window activation until user explicitly activates it. + * Example: Tool Window initialisation takes huge amount of time and makes project loading slower. + * @return {@code true} if Tool Window should not be activated on start even if was opened previously. + * {@code false} otherwise. + */ + default boolean isDoNotActivateOnStart() {return false;} } diff --git a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactoryEx.java b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactoryEx.java index 2179adb0cefe..d5fbea89e151 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactoryEx.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/ToolWindowFactoryEx.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -17,7 +17,7 @@ package com.intellij.openapi.wm; /** * @author Dennis.Ushakov + * @deprecated use {@link ToolWindowFactory} */ public interface ToolWindowFactoryEx extends ToolWindowFactory { - void init(ToolWindow window); } diff --git a/platform/platform-impl/src/com/intellij/diagnostic/PluginConflictReporter.java b/platform/platform-impl/src/com/intellij/diagnostic/PluginConflictReporter.java new file mode 100644 index 000000000000..de6704382644 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/diagnostic/PluginConflictReporter.java @@ -0,0 +1,66 @@ +/* + * 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.diagnostic; + +import com.intellij.diagnostic.errordialog.PluginConflictDialog; +import com.intellij.ide.plugins.cl.PluginClassLoader; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.wm.WindowManager; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public enum PluginConflictReporter { + INSTANCE; + + public void reportConflictByClasses(@NotNull Collection> conflictingClasses) { + final Set foundPlugins = new HashSet<>(); + boolean hasConflictWithPlatform = false; + + if (conflictingClasses.size() < 2) { + throw new IllegalArgumentException("The conflict should has been caused by at least two classes"); + } + + for (Class aClass : conflictingClasses) { + final ClassLoader classLoader = aClass.getClassLoader(); + if (classLoader instanceof PluginClassLoader) { + foundPlugins.add(((PluginClassLoader)classLoader).getPluginId()); + } + else { + hasConflictWithPlatform = true; + } + } + + if (foundPlugins.isEmpty()) { + Logger.getInstance(PluginConflictReporter.class).warn("The conflict has not come from PluginClassLoader"); + return; + } + + boolean finalHasConflictWithPlatform = hasConflictWithPlatform; + ApplicationManager.getApplication().invokeLater(() -> { + final JFrame frame = WindowManager.getInstance().findVisibleFrame(); + if (frame != null) { + new PluginConflictDialog(frame, new ArrayList<>(foundPlugins), finalHasConflictWithPlatform).show(); + } + }); + } +} diff --git a/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.form b/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.form new file mode 100644 index 000000000000..b9a7ed6e56c4 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.form @@ -0,0 +1,40 @@ + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.java b/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.java new file mode 100644 index 000000000000..011231a47a8b --- /dev/null +++ b/platform/platform-impl/src/com/intellij/diagnostic/errordialog/PluginConflictDialog.java @@ -0,0 +1,242 @@ +/* + * 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.diagnostic.errordialog; + +import com.intellij.diagnostic.DiagnosticBundle; +import com.intellij.ide.plugins.IdeaPluginDescriptor; +import com.intellij.ide.plugins.PluginManager; +import com.intellij.ide.plugins.PluginManagerConfigurable; +import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.openapi.extensions.PluginId; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBRadioButton; +import com.intellij.util.ui.JBEmptyBorder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class PluginConflictDialog extends DialogWrapper { + public static final int WIDTH = 510; + + @NotNull + private final List myConflictingPlugins; + + private final boolean myIsConflictWithPlatform; + @Nullable + private final List myRadioButtons; + + private JPanel myContentPane; + + private JBLabel myTopMessageLabel; + + private JPanel myConflictingPluginsListPanel; + + private JBLabel myBottomMessageLabel; + + public PluginConflictDialog(@NotNull Component parent, + @NotNull List conflictingPlugins, + boolean isConflictWithPlatform) { + super(parent, false); + + myConflictingPlugins = conflictingPlugins; + myIsConflictWithPlatform = isConflictWithPlatform; + + if (myIsConflictWithPlatform) { + myRadioButtons = null; + } + else { + myRadioButtons = new ArrayList<>(); + } + + $$$setupUI$$$(); + setTitle(DiagnosticBundle.message("error.dialog.conflict.plugin.title")); + init(); + + myTopMessageLabel.setText(getTopMessageText(conflictingPlugins, isConflictWithPlatform)); + myBottomMessageLabel.setText(DiagnosticBundle.message("error.dialog.conflict.plugin.footer")); + + myTopMessageLabel.setPreferredSize(new Dimension(WIDTH, (int)myTopMessageLabel.getPreferredSize().getHeight())); + myContentPane.setPreferredSize(new Dimension(WIDTH, (int)myContentPane.getMinimumSize().getHeight())); + } + + private static String getTopMessageText(@NotNull List conflictingPlugins, boolean isConflictWithPlatform) { + final int pluginsNumber = conflictingPlugins.size(); + if (isConflictWithPlatform) { + return DiagnosticBundle.message("error.dialog.conflict.plugin.header.platform", pluginsNumber); + } + else { + final List names = conflictingPlugins.stream() + .map(PluginConflictDialog::getPluginNameOrId) + .map(s -> "" + s + "") + .collect(Collectors.toList()); + return DiagnosticBundle.message("error.dialog.conflict.plugin.header.each.other", + StringUtil.join(names.subList(0, pluginsNumber - 1), ", "), + names.get(pluginsNumber - 1)); + } + } + + private void $$$setupUI$$$() { + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myContentPane; + } + + private void createUIComponents() { + final ButtonGroup buttonGroup = new ButtonGroup(); + + myConflictingPluginsListPanel = new JPanel(new GridLayout(0, 1)); + final List pluginDescriptions = myConflictingPlugins.stream() + .map(plugin -> getChooserPanelForPlugin(buttonGroup, plugin)) + .collect(Collectors.toList()); + + if (!myIsConflictWithPlatform) { + pluginDescriptions.add(0, getChooserPanelForPlugin(buttonGroup, null)); + } + + for (JPanel panel : pluginDescriptions) { + myConflictingPluginsListPanel.add(panel); + } + + setUpDefaultSelection(); + } + + @NotNull + private JPanel getChooserPanelForPlugin(@NotNull ButtonGroup buttonGroup, @Nullable PluginId plugin) { + final JPanel panel = new JPanel(new BorderLayout()); + if (!myIsConflictWithPlatform) { + assert myRadioButtons != null; + + final JBRadioButton radioButton = new JBRadioButton(); + myRadioButtons.add(radioButton); + buttonGroup.add(radioButton); + + panel.add(radioButton, BorderLayout.WEST); + panel.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + radioButton.setSelected(true); + } + }); + } + + final JPanel descriptionPanel; + if (plugin != null) { + descriptionPanel = getPluginDescriptionPanel(plugin, !myIsConflictWithPlatform); + } + else { + descriptionPanel = getDisableAllPanel(); + } + descriptionPanel.setBorder(new JBEmptyBorder(10, myIsConflictWithPlatform ? 10 : 0, 10, 20)); + + panel.add(descriptionPanel, BorderLayout.CENTER); + return panel; + } + + private void setUpDefaultSelection() { + if (myIsConflictWithPlatform) { + return; + } + assert myRadioButtons != null && myRadioButtons.size() == myConflictingPlugins.size() + 1; + + for (int i = 0; i < myConflictingPlugins.size(); i++) { + final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(myConflictingPlugins.get(i)); + if (pluginDescriptor != null + && (pluginDescriptor.isBundled() || StringUtil.equalsIgnoreCase(pluginDescriptor.getVendor(), "JetBrains"))) { + myRadioButtons.get(i).setSelected(true); + return; + } + } + myRadioButtons.get(myRadioButtons.size() - 1).setSelected(true); + } + + @NotNull + private static JPanel getPluginDescriptionPanel(@NotNull PluginId plugin, boolean addUseWord) { + final JPanel panel = new JPanel(new BorderLayout()); + + final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(plugin); + if (pluginDescriptor == null) { + panel.add(new JBLabel(plugin.getIdString()), BorderLayout.CENTER); + return panel; + } + + final StringBuilder sb = new StringBuilder(""); + if (addUseWord) { + sb.append("Use "); + } + sb.append(pluginDescriptor.getName()); + if (pluginDescriptor.getVendor() != null) { + sb.append(" by ").append(pluginDescriptor.getVendor()); + } + sb.append(""); + panel.add(new JBLabel(sb.toString())); + return panel; + } + + @NotNull + private static String getPluginNameOrId(@NotNull PluginId pluginId) { + final IdeaPluginDescriptor pluginDescriptor = PluginManager.getPlugin(pluginId); + if (pluginDescriptor == null) { + return pluginId.getIdString(); + } + else { + return pluginDescriptor.getName(); + } + } + + @NotNull + private static JPanel getDisableAllPanel() { + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JBLabel(DiagnosticBundle.message("error.dialog.conflict.plugin.disable.all"))); + return panel; + } + + @NotNull + @Override + protected Action getOKAction() { + return new DisableAction(); + } + + private class DisableAction extends DialogWrapperAction { + protected DisableAction() { + super(DiagnosticBundle.message("error.dialog.disable.plugin.action.disable")); + putValue(DEFAULT_ACTION, Boolean.TRUE); + } + + @Override + protected void doAction(ActionEvent e) { + for (int i = 0; i < myConflictingPlugins.size(); ++i) { + if (myRadioButtons == null || !myRadioButtons.get(i).isSelected()) { + PluginManagerCore.disablePlugin(myConflictingPlugins.get(i).getIdString()); + } + } + close(OK_EXIT_CODE); + PluginManagerConfigurable.shutdownOrRestartApp(""); + } + } +} diff --git a/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java b/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java index cbc22c5f149e..793f11e029f3 100644 --- a/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java +++ b/platform/platform-impl/src/com/intellij/idea/IdeaLogger.java @@ -15,7 +15,9 @@ */ package com.intellij.idea; +import com.intellij.diagnostic.ImplementationConflictException; import com.intellij.diagnostic.LogMessageEx; +import com.intellij.diagnostic.PluginConflictReporter; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationInfoEx; import com.intellij.openapi.application.impl.ApplicationImpl; @@ -123,6 +125,10 @@ public class IdeaLogger extends Log4jBasedLogger { } } + if (t instanceof ImplementationConflictException) { + PluginConflictReporter.INSTANCE.reportConflictByClasses(((ImplementationConflictException)t).getConflictingClasses()); + } + String detailString = StringUtil.join(details, "\n"); if (ourErrorsOccurred == null) { diff --git a/platform/platform-impl/src/com/intellij/openapi/application/actions.kt b/platform/platform-impl/src/com/intellij/openapi/application/actions.kt index 820f04dee7da..2188fe08777f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/application/actions.kt +++ b/platform/platform-impl/src/com/intellij/openapi/application/actions.kt @@ -38,12 +38,21 @@ inline fun runBatchUpdate(messageBus: MessageBus, runnable: () -> T): T { /** * @exclude Internal use only */ -fun invokeAndWaitIfNeed(runnable: () -> Unit) { +fun invokeAndWaitIfNeed(runnable: () -> T): T { val app = ApplicationManager.getApplication() if (app == null) { - if (SwingUtilities.isEventDispatchThread()) runnable() else SwingUtilities.invokeAndWait(runnable) + if (SwingUtilities.isEventDispatchThread()) { + return runnable() + } + else { + var result: T? = null + SwingUtilities.invokeAndWait { result = runnable() } + return result as T + } } else { - app.invokeAndWait(runnable, ModalityState.defaultModalityState()) + var result: T? = null + app.invokeAndWait({ result = runnable() }, ModalityState.defaultModalityState()) + return result as T } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java index 84c4f7db2045..874685d1ac0a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretImpl.java @@ -493,7 +493,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret, Dumpable { } } - myEditor.getFoldingModel().flushCaretPosition(); + myEditor.getFoldingModel().flushCaretPosition(this); VerticalInfo oldInfo = myCaretInfo; LogicalPosition oldCaretPosition = myLogicalCaret; @@ -682,7 +682,7 @@ public class CaretImpl extends UserDataHolderBase implements Caret, Dumpable { updateVisualLineInfo(); - myEditor.getFoldingModel().flushCaretPosition(); + myEditor.getFoldingModel().flushCaretPosition(this); setLastColumnNumber(myLogicalCaret.column); myDesiredSelectionStartColumn = myDesiredSelectionEndColumn = -1; @@ -872,7 +872,6 @@ public class CaretImpl extends UserDataHolderBase implements Caret, Dumpable { } } - updateVisualLineInfo(); updateSelectionOnDocumentChange(); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java index df72e3819091..6a482d6c16f4 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/FoldingModelImpl.java @@ -523,10 +523,8 @@ public class FoldingModelImpl implements FoldingModelEx, PrioritizedInternalDocu return myFoldTextAttributes; } - public void flushCaretPosition() { - for (Caret caret : myEditor.getCaretModel().getAllCarets()) { - caret.putUserData(SAVED_CARET_POSITION, null); - } + void flushCaretPosition(@NotNull Caret caret) { + caret.putUserData(SAVED_CARET_POSITION, null); } void onBulkDocumentUpdateStarted() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java index c97831818eec..649fe18153ae 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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. @@ -555,9 +555,7 @@ public final class ToolWindowImpl implements ToolWindowEx { public void setContentFactory(ToolWindowFactory contentFactory) { myContentFactory = contentFactory; - if (contentFactory instanceof ToolWindowFactoryEx) { - ((ToolWindowFactoryEx)contentFactory).init(this); - } + contentFactory.init(this); } public void ensureContentInitialized() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java index ff006a1156e2..6de3fdc79d3f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowInfoImpl.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. @@ -263,7 +263,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo myId = element.getAttributeValue(ID_ATTR); myWasRead = true; try { - myActive = Boolean.valueOf(element.getAttributeValue(ACTIVE_ATTR)).booleanValue(); + myActive = Boolean.valueOf(element.getAttributeValue(ACTIVE_ATTR)).booleanValue() && canActivateOnStart(myId); } catch (NumberFormatException ignored) { } @@ -283,7 +283,7 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo } catch (IllegalArgumentException ignored) { } - myVisible = Boolean.valueOf(element.getAttributeValue(VISIBLE_ATTR)).booleanValue(); + myVisible = Boolean.valueOf(element.getAttributeValue(VISIBLE_ATTR)).booleanValue() && canActivateOnStart(myId); if (element.getAttributeValue(SHOW_STRIPE_BUTTON) != null) { myShowStripeButton = Boolean.valueOf(element.getAttributeValue(SHOW_STRIPE_BUTTON)).booleanValue(); } @@ -319,6 +319,16 @@ public final class WindowInfoImpl implements Cloneable,JDOMExternalizable, Windo myContentUiType = ToolWindowContentUiType.getInstance(element.getAttributeValue(CONTENT_UI_ATTR)); } + private static boolean canActivateOnStart(String id) { + for (ToolWindowEP ep : ToolWindowEP.EP_NAME.getExtensions()) { + if (id.equals(ep.id)) { + ToolWindowFactory factory = ep.getToolWindowFactory(); + return !factory.isDoNotActivateOnStart(); + } + } + return true; + } + /** * Sets new anchor. */ diff --git a/platform/platform-impl/src/com/intellij/reporting/Reporter.kt b/platform/platform-impl/src/com/intellij/reporting/Reporter.kt index 5da107a0da14..728f1bed7ca3 100644 --- a/platform/platform-impl/src/com/intellij/reporting/Reporter.kt +++ b/platform/platform-impl/src/com/intellij/reporting/Reporter.kt @@ -17,6 +17,7 @@ package com.intellij.reporting import com.google.gson.Gson import com.intellij.openapi.application.PermanentInstallationID +import com.intellij.openapi.diagnostic.Logger import org.apache.http.client.fluent.Request import org.apache.http.entity.ContentType @@ -32,7 +33,8 @@ private object Utils { object StatsSender { private val infoUrl = "https://www.jetbrains.com/config/features-service-status.json" - + private val LOG = Logger.getInstance(StatsSender::class.java) + private fun requestServerUrl(): String? { try { val response = Request.Get(infoUrl).execute().returnContent().asString() @@ -40,6 +42,7 @@ object StatsSender { if (info.isServiceAlive()) return info.url } catch (e: Exception) { + LOG.debug(e) } return null @@ -55,6 +58,7 @@ object StatsSender { } } catch (e: Exception) { + LOG.debug(e) } return false } diff --git a/platform/platform-resources-en/src/messages/DiagnosticBundle.properties b/platform/platform-resources-en/src/messages/DiagnosticBundle.properties index e26b4ae549e3..e4c6d820b884 100644 --- a/platform/platform-resources-en/src/messages/DiagnosticBundle.properties +++ b/platform/platform-resources-en/src/messages/DiagnosticBundle.properties @@ -92,5 +92,10 @@ error.dialog.attachment.path.column.title=Path error.dialog.attachment.include.column.title=Include error.attachments.tab.title=Attachments error.dialog.filecontent.title=File content +error.dialog.conflict.plugin.title=Initialization Failure +error.dialog.conflict.plugin.header.platform=The following plugin{0,choice,1#|2#s} conflict{0,choice,1#s|2#} with IDE platform: +error.dialog.conflict.plugin.header.each.other=

The following plugins conflict with each other: {0} and {1}

+error.dialog.conflict.plugin.footer=It is highly recommended to resolve this conflict by disabling redundant plugins. +error.dialog.conflict.plugin.disable.all=Disable all diagnostic.error.report.include.attachment.warning=Report will include attachment: ''{0}''. diagnostic.error.report.include.attachments.warning=Report will include {0} attachments. diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index ca0f3b785cd1..bd39fea46863 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -317,13 +317,13 @@ inspection.javadoc.html.not.required.label.text=Additional Not Required Html Att inspection.javadoc.html.not.required.dialog.title=Edit Additional Not Required Html Attributes inspection.required.attributes.display.name=Missing required attribute -inspection.unused.symbol.check.localvars=&Local variables (Editor only) -inspection.unused.symbol.check.fields=&Fields: -inspection.unused.symbol.check.methods=&Methods: -inspection.unused.symbol.check.accessors=&Getters/setters -inspection.unused.symbol.check.classes=&Classes: -inspection.unused.symbol.check.inner.classes=&Inner classes: -inspection.unused.symbol.check.parameters=&Parameters in +inspection.unused.symbol.check.localvars=Local variables (Editor only) +inspection.unused.symbol.check.fields=Fields: +inspection.unused.symbol.check.methods=Methods: +inspection.unused.symbol.check.accessors=Getters/setters +inspection.unused.symbol.check.classes=Classes: +inspection.unused.symbol.check.inner.classes=Inner classes: +inspection.unused.symbol.check.parameters=Parameters in inspection.results.for.profile.toolwindow.title=''{0}'' Profile on {1} inspection.results.for.inspection.toolwindow.title=''{0}'' Inspection on {1} diff --git a/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java b/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java index f925c43f6fcb..f628f6e7a365 100644 --- a/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java +++ b/platform/platform-tests/testSrc/com/intellij/ide/fileTemplates/impl/LightFileTemplatesTest.java @@ -182,12 +182,12 @@ public class LightFileTemplatesTest extends LightPlatformTestCase { FileTemplateBase template = (FileTemplateBase)myTemplateManager.getTemplate("templateWithLiveTemplate.txt"); assertTrue(template.isLiveTemplateEnabledByDefault()); FileTemplateSettings settings = ServiceManager.getService(ExportableFileTemplateSettings.class); - assertNull(settings.getState()); + assertEquals(0, settings.getState().getContentSize()); template.setLiveTemplateEnabled(false); Element state = settings.getState(); assertNotNull(state); template.setLiveTemplateEnabled(true); - assertNull(settings.getState()); + assertEquals(0, settings.getState().getContentSize()); } private FileTemplateManagerImpl myTemplateManager; diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt index a00f58e52583..abf0dd809862 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/scheme-impl.kt @@ -15,8 +15,11 @@ */ package com.intellij.configurationStore +import com.intellij.openapi.options.ExternalizableSchemeAdapter import com.intellij.openapi.options.Scheme import com.intellij.openapi.options.SchemeProcessor +import com.intellij.openapi.options.SchemeState +import com.intellij.util.isEmpty import org.jdom.Element import java.io.OutputStream import java.security.MessageDigest @@ -29,6 +32,8 @@ interface SchemeDataHolder { fun read(): Element fun updateDigest(scheme: MUTABLE_SCHEME) + + fun updateDigest(data: Element) } interface SerializableScheme { @@ -84,4 +89,35 @@ fun Element.digest(): ByteArray { val digest = MessageDigest.getInstance("SHA-1") serializeElementToBinary(this, DigestOutputStream(digest)) return digest.digest() +} + +abstract class SchemeWrapper(name: String) : ExternalizableSchemeAdapter(), SerializableScheme { + protected abstract val lazyScheme: Lazy + + val scheme: T + get() = lazyScheme.value + + val schemeState: SchemeState + get() = if (lazyScheme.isInitialized()) SchemeState.POSSIBLY_CHANGED else SchemeState.UNCHANGED + + init { + this.name = name + } +} + +class InitializedSchemeWrapper(scheme: T, private val writer: (scheme: T) -> Element) : SchemeWrapper(scheme.name) { + override val lazyScheme = lazyOf(scheme) + + override fun writeScheme() = writer(scheme) +} + +fun wrapState(element: Element): Element { + if (element.isEmpty()) { + element.name = "state" + return element + } + + val wrapper = Element("state") + wrapper.addContent(element) + return wrapper } \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/jdom.kt b/platform/projectModel-impl/src/com/intellij/jdom.kt index ef460e6902cd..f1e45ae5c543 100644 --- a/platform/projectModel-impl/src/com/intellij/jdom.kt +++ b/platform/projectModel-impl/src/com/intellij/jdom.kt @@ -82,6 +82,8 @@ fun Element.element(name: String): Element { return element } +fun Element.attribute(name: String, value: String?): Element = setAttribute(name, value) + fun Element.remove(name: String, transform: (child: Element) -> T): List { val result = SmartList() val groupIterator = getContent(ElementFilter(name)).iterator() diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java index 60a758a6ae6d..ba678c929ff9 100644 --- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java +++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java @@ -3147,10 +3147,23 @@ public class StringUtil extends StringUtilRt { public static LineSeparator detectSeparators(@NotNull CharSequence text) { int index = indexOfAny(text, "\n\r"); if (index == -1) return null; - if (startsWith(text, index, "\r\n")) return LineSeparator.CRLF; - if (text.charAt(index) == '\r') return LineSeparator.CR; - if (text.charAt(index) == '\n') return LineSeparator.LF; - throw new IllegalStateException(); + LineSeparator lineSeparator = findStartingLineSeparator(text, index); + if (lineSeparator == null) { + throw new AssertionError(); + } + return lineSeparator; + } + + @Nullable + public static LineSeparator findStartingLineSeparator(@NotNull CharSequence text, int startIndex) { + if (startIndex < 0 || startIndex >= text.length()) { + return null; + } + char ch = text.charAt(startIndex); + if (ch == '\r') { + return startIndex + 1 < text.length() && text.charAt(startIndex + 1) == '\n' ? LineSeparator.CRLF : LineSeparator.CR; + } + return ch == '\n' ? LineSeparator.LF : null; } @NotNull diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java index 569734335156..b8791aea3bf8 100644 --- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java @@ -373,6 +373,28 @@ public class StringUtilTest { assertEquals(LineSeparator.CRLF, StringUtil.detectSeparators("asd\r\nads\n")); } + @Test + public void testFindStartingLineSeparator() { + assertEquals(null, StringUtil.findStartingLineSeparator("", -1)); + assertEquals(null, StringUtil.findStartingLineSeparator("", 0)); + assertEquals(null, StringUtil.findStartingLineSeparator("", 1)); + assertEquals(null, StringUtil.findStartingLineSeparator("\nHello", -1)); + assertEquals(null, StringUtil.findStartingLineSeparator("\nHello", 1)); + assertEquals(null, StringUtil.findStartingLineSeparator("\nH\rel\nlo", 6)); + + assertEquals(LineSeparator.LF, StringUtil.findStartingLineSeparator("\nHello", 0)); + assertEquals(LineSeparator.LF, StringUtil.findStartingLineSeparator("\nH\rel\nlo", 5)); + assertEquals(LineSeparator.LF, StringUtil.findStartingLineSeparator("Hello\n", 5)); + + assertEquals(LineSeparator.CR, StringUtil.findStartingLineSeparator("\rH\r\nello", 0)); + assertEquals(LineSeparator.CR, StringUtil.findStartingLineSeparator("Hello\r", 5)); + assertEquals(LineSeparator.CR, StringUtil.findStartingLineSeparator("Hello\b\r", 6)); + + assertEquals(LineSeparator.CRLF, StringUtil.findStartingLineSeparator("\rH\r\nello", 2)); + assertEquals(LineSeparator.CRLF, StringUtil.findStartingLineSeparator("\r\nH\r\nello", 0)); + assertEquals(LineSeparator.CRLF, StringUtil.findStartingLineSeparator("\r\nH\r\nello\r\n", 9)); + } + @Test public void testFormatFileSize() { assertEquals("0B", StringUtil.formatFileSize(0)); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateCurrentRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateCurrentRevisionAction.java index 0103ef58d28f..65bff2ce30fc 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateCurrentRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateCurrentRevisionAction.java @@ -30,6 +30,8 @@ class AnnotateCurrentRevisionAction extends AnnotateRevisionAction { @Override protected VcsFileRevision getRevision(int lineNumber) { assert myProvider != null; + + if (lineNumber < 0 || lineNumber >= myAnnotation.getLineCount()) return null; return myProvider.getRevision(lineNumber); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java index dba8837c48da..248be76a3a2e 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotatePreviousRevisionAction.java @@ -31,10 +31,12 @@ class AnnotatePreviousRevisionAction extends AnnotateRevisionAction { @Override protected VcsFileRevision getRevision(int lineNumber) { assert myProvider != null; + if (lineNumber == UpToDateLineNumberProvider.ABSENT_LINE_NUMBER) { return myProvider.getLastRevision(); } else { + if (lineNumber < 0 || lineNumber >= myAnnotation.getLineCount()) return null; return myProvider.getPreviousRevision(lineNumber); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java index c51fb9d2e9d3..7bf3ce4c9f00 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateRevisionAction.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; abstract class AnnotateRevisionAction extends AnnotateRevisionActionBase implements DumbAware, UpToDateLineNumberListener { - @NotNull private final FileAnnotation myAnnotation; + @NotNull protected final FileAnnotation myAnnotation; @NotNull private final AbstractVcs myVcs; private int currentLine; @@ -83,7 +83,6 @@ abstract class AnnotateRevisionAction extends AnnotateRevisionActionBase impleme @Nullable @Override protected VcsFileRevision getFileRevision(@NotNull AnActionEvent e) { - if (currentLine < 0 || currentLine >= myAnnotation.getLineCount()) return null; return getRevision(currentLine); } diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XBreakpointType.java b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XBreakpointType.java index a41635140e74..d9005fd5a4e3 100644 --- a/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XBreakpointType.java +++ b/platform/xdebugger-api/src/com/intellij/xdebugger/breakpoints/XBreakpointType.java @@ -84,6 +84,10 @@ public abstract class XBreakpointType, P extends XBreak return mySuspendThreadSupported; } + public SuspendPolicy getDefaultSuspendPolicy() { + return SuspendPolicy.ALL; + } + public enum StandardPanels {SUSPEND_POLICY, ACTIONS, DEPENDENCY} public EnumSet getVisibleStandardPanels() { diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java index 8631b8fc901b..8dd934a48c94 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/BreakpointState.java @@ -53,10 +53,11 @@ public class BreakpointState, P extends XBreakpointProp public BreakpointState() { } - public BreakpointState(final boolean enabled, final String typeId, final long timeStamp) { + public BreakpointState(final boolean enabled, final String typeId, final long timeStamp, final SuspendPolicy suspendPolicy) { myEnabled = enabled; myTypeId = typeId; myTimeStamp = timeStamp; + mySuspendPolicy = suspendPolicy; } @Attribute("enabled") diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/LineBreakpointState.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/LineBreakpointState.java index c843d9ef53c1..534db7761a79 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/LineBreakpointState.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/LineBreakpointState.java @@ -16,6 +16,7 @@ package com.intellij.xdebugger.impl.breakpoints; import com.intellij.util.xmlb.annotations.Tag; +import com.intellij.xdebugger.breakpoints.SuspendPolicy; import com.intellij.xdebugger.breakpoints.XBreakpointProperties; import com.intellij.xdebugger.breakpoints.XLineBreakpoint; import com.intellij.xdebugger.breakpoints.XLineBreakpointType; @@ -33,8 +34,9 @@ public class LineBreakpointState

extends Breakp public LineBreakpointState() { } - public LineBreakpointState(final boolean enabled, final String typeId, final String fileUrl, final int line, boolean temporary, final long timeStamp) { - super(enabled, typeId, timeStamp); + public LineBreakpointState(final boolean enabled, final String typeId, final String fileUrl, final int line, boolean temporary, + final long timeStamp, final SuspendPolicy suspendPolicy) { + super(enabled, typeId, timeStamp, suspendPolicy); myFileUrl = fileUrl; myLine = line; myTemporary = temporary; diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java index 0c9f0bdd806c..f6038c693eb2 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/XBreakpointManagerImpl.java @@ -121,7 +121,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta boolean defaultBreakpoint) { BreakpointState state = new BreakpointState<>(enabled, type.getId(), - defaultBreakpoint ? 0 : myTime++); + defaultBreakpoint ? 0 : myTime++, type.getDefaultSuspendPolicy()); getBreakpointDefaults(type).applyDefaults(state); state.setGroup(myDefaultGroup); return new XBreakpointBase,T, BreakpointState>(type, this, properties, state); @@ -217,7 +217,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta boolean temporary) { ApplicationManager.getApplication().assertWriteAccessAllowed(); LineBreakpointState state = new LineBreakpointState<>(true, type.getId(), fileUrl, line, temporary, - myTime++); + myTime++, type.getDefaultSuspendPolicy()); getBreakpointDefaults(type).applyDefaults(state); state.setGroup(myDefaultGroup); XLineBreakpointImpl breakpoint = new XLineBreakpointImpl<>(type, this, properties, @@ -508,6 +508,7 @@ public class XBreakpointManagerImpl implements XBreakpointManager, PersistentSta private static BreakpointState createBreakpointDefaults(@NotNull XBreakpointType type) { BreakpointState state = new BreakpointState(); state.setTypeId(type.getId()); + state.setSuspendPolicy(type.getDefaultSuspendPolicy()); return state; } diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java index 947693068e21..2d2f918a01b6 100644 --- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java +++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/breakpoints/ui/XSuspendPolicyPanel.java @@ -169,7 +169,7 @@ public class XSuspendPolicyPanel extends XBreakpointPropertiesSubPanel { return mySuspendAll.isSelected() ? SuspendPolicy.ALL : SuspendPolicy.THREAD; } else { - return SuspendPolicy.ALL; + return myBreakpoint.getType().getDefaultSuspendPolicy(); } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteUnnecessaryStatementFix.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteUnnecessaryStatementFix.java index deb46eccd664..f05aa239df8e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteUnnecessaryStatementFix.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/fixes/DeleteUnnecessaryStatementFix.java @@ -56,6 +56,10 @@ public class DeleteUnnecessaryStatementFix extends InspectionGadgetsFix { if (statement == null) { return; } + deleteUnnecessaryStatement(statement); + } + + public static void deleteUnnecessaryStatement(PsiStatement statement) { final PsiElement parent = statement.getParent(); if (parent instanceof PsiIfStatement || parent instanceof PsiWhileStatement || diff --git a/plugins/copyright/copyright.iml b/plugins/copyright/copyright.iml index 126c6110fa43..e9b97f5b12bf 100644 --- a/plugins/copyright/copyright.iml +++ b/plugins/copyright/copyright.iml @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/plugins/copyright/src/CopyrightManager.kt b/plugins/copyright/src/CopyrightManager.kt new file mode 100644 index 000000000000..046b415dc40d --- /dev/null +++ b/plugins/copyright/src/CopyrightManager.kt @@ -0,0 +1,286 @@ +/* + * 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.copyright + +import com.intellij.configurationStore.* +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ModalityState +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.service +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.editor.EditorFactory +import com.intellij.openapi.editor.event.DocumentAdapter +import com.intellij.openapi.editor.event.DocumentEvent +import com.intellij.openapi.fileEditor.FileDocumentManager +import com.intellij.openapi.options.SchemeManagerFactory +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.startup.StartupActivity +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.InvalidDataException +import com.intellij.openapi.util.WriteExternalException +import com.intellij.openapi.util.text.StringUtil +import com.intellij.packageDependencies.DependencyValidationManager +import com.intellij.project.isDirectoryBased +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.util.attribute +import com.intellij.util.element +import com.maddyhome.idea.copyright.CopyrightProfile +import com.maddyhome.idea.copyright.actions.UpdateCopyrightProcessor +import com.maddyhome.idea.copyright.options.LanguageOptions +import com.maddyhome.idea.copyright.options.Options +import com.maddyhome.idea.copyright.util.FileTypeUtil +import com.maddyhome.idea.copyright.util.NewFileTracker +import org.jdom.Element +import java.util.* +import java.util.concurrent.atomic.AtomicReference +import java.util.function.Function + +private const val DEFAULT = "default" +private const val MODULE2COPYRIGHT = "module2copyright" +private const val COPYRIGHT = "copyright" +private const val ELEMENT = "element" +private const val MODULE = "module" + +private val LOG = Logger.getInstance(CopyrightManager::class.java) + +@State(name = "CopyrightManager", storages = arrayOf(Storage(value = "copyright/profiles_settings.xml", exclusive = true))) +class CopyrightManager(private val project: Project, schemeManagerFactory: SchemeManagerFactory) : PersistentStateComponent { + companion object { + @JvmStatic + fun getInstance(project: Project) = project.service() + } + + private var defaultCopyrightName: String? = null + + var defaultCopyright: CopyrightProfile? + get() = defaultCopyrightName?.let { schemeManager.findSchemeByName(it)?.scheme } + set(value) { + defaultCopyrightName = value?.name + } + + val scopeToCopyright = LinkedHashMap() + val options = Options() + + private val schemeManagerIprProvider = if (project.isDirectoryBased) null else SchemeManagerIprProvider() + + val schemeManager = schemeManagerFactory.create("copyright", object : LazySchemeProcessor, SchemeWrapper>() { + override fun createScheme(dataHolder: SchemeDataHolder>, + name: String, + attributeProvider: Function): SchemeWrapper { + return LazySchemeWrapper(name, dataHolder, schemeWriter) + } + + override fun getState(scheme: SchemeWrapper) = scheme.schemeState + + override fun isSchemeFile(name: CharSequence) = !StringUtil.equals(name, "profiles_settings.xml") + }, isUseOldFileNameSanitize = true, streamProvider = schemeManagerIprProvider) + + init { + val app = ApplicationManager.getApplication() + if (project.isDirectoryBased || !app.isUnitTestMode) { + schemeManager.loadSchemes() + } + } + + fun mapCopyright(scopeName: String, copyrightProfileName: String) { + scopeToCopyright.put(scopeName, copyrightProfileName) + } + + fun unmapCopyright(scopeName: String) { + scopeToCopyright.remove(scopeName) + } + + fun hasAnyCopyrights(): Boolean { + return defaultCopyrightName != null || !scopeToCopyright.isEmpty() + } + + override fun getState(): Element? { + val result = Element("settings") + try { + schemeManagerIprProvider?.writeState(result) + + if (!scopeToCopyright.isEmpty()) { + val map = Element(MODULE2COPYRIGHT) + for ((scopeName, profileName) in scopeToCopyright) { + map.element(ELEMENT) + .attribute(MODULE, scopeName) + .attribute(COPYRIGHT, profileName) + } + result.addContent(map) + } + + options.writeExternal(result) + } + catch (e: WriteExternalException) { + LOG.error(e) + return null + } + + defaultCopyrightName?.let { + result.setAttribute(DEFAULT, it) + } + + return wrapState(result) + } + + override fun loadState(state: Element) { + val data: Element? = state.getChild("settings") + + schemeManagerIprProvider?.let { + it.load(data) + schemeManager.reload() + } + + if (data == null) { + return + } + + val moduleToCopyright = data.getChild(MODULE2COPYRIGHT) + if (moduleToCopyright != null) { + for (element in moduleToCopyright.getChildren(ELEMENT)) { + scopeToCopyright.put(element.getAttributeValue(MODULE), element.getAttributeValue(COPYRIGHT)) + } + } + + try { + defaultCopyrightName = data.getAttributeValue(DEFAULT) + options.readExternal(data) + } + catch (e: InvalidDataException) { + LOG.error(e) + } + } + + fun addCopyright(profile: CopyrightProfile) { + schemeManager.addScheme(InitializedSchemeWrapper(profile, schemeWriter)) + } + + fun getCopyrights(): Collection = schemeManager.allSchemes.map { it.scheme } + + fun clearMappings() { + scopeToCopyright.clear() + } + + fun removeCopyright(copyrightProfile: CopyrightProfile) { + schemeManager.removeScheme(copyrightProfile.name) + + val it = scopeToCopyright.keys.iterator() + while (it.hasNext()) { + if (scopeToCopyright.get(it.next()) == copyrightProfile.name) { + it.remove() + } + } + } + + fun replaceCopyright(name: String, profile: CopyrightProfile) { + val existingScheme = schemeManager.findSchemeByName(name) + if (existingScheme == null) { + addCopyright(profile) + } + else { + existingScheme.scheme.copyFrom(profile) + } + } + + fun getCopyrightOptions(file: PsiFile): CopyrightProfile? { + val virtualFile = file.virtualFile + if (virtualFile == null || options.getOptions(virtualFile.fileType.name).getFileTypeOverride() == LanguageOptions.NO_COPYRIGHT) { + return null + } + + val validationManager = DependencyValidationManager.getInstance(project) + for (scopeName in scopeToCopyright.keys) { + val packageSet = validationManager.getScope(scopeName)?.value ?: continue + if (packageSet.contains(file, validationManager)) { + scopeToCopyright.get(scopeName)?.let { schemeManager.findSchemeByName(it) }?.let { return it.scheme } + } + } + return defaultCopyright + } +} + +private class CopyrightManagerPostStartupActivity : StartupActivity { + val newFileTracker = NewFileTracker() + + override fun runActivity(project: Project) { + Disposer.register(project, Disposable { newFileTracker.clear() }) + + EditorFactory.getInstance().eventMulticaster.addDocumentListener(object : DocumentAdapter() { + override fun documentChanged(e: DocumentEvent) { + val virtualFile = FileDocumentManager.getInstance().getFile(e.document) ?: return + val module = ProjectRootManager.getInstance(project).fileIndex.getModuleForFile(virtualFile) ?: return + if (!newFileTracker.poll(virtualFile) || + !FileTypeUtil.getInstance().isSupportedFile(virtualFile) || + PsiManager.getInstance(project).findFile(virtualFile) == null) { + return + } + + ApplicationManager.getApplication().invokeLater(Runnable { + if (!virtualFile.isValid) { + return@Runnable + } + + val file = PsiManager.getInstance(project).findFile(virtualFile) + if (file != null && file.isWritable) { + CopyrightManager.getInstance(project).getCopyrightOptions(file)?.let { + UpdateCopyrightProcessor(project, module, file).run() + } + } + }, ModalityState.NON_MODAL, project.disposed) + } + }, project) + } +} + +private fun wrapScheme(element: Element): Element { + val wrapper = Element("component") + .attribute("name", "CopyrightManager") + wrapper.addContent(element) + return wrapper +} + +private val schemeWriter = { scheme: CopyrightProfile -> + val element = Element("copyright") + scheme.writeExternal(element) + wrapScheme(element) +} + +private class LazySchemeWrapper(name: String, + dataHolder: SchemeDataHolder>, + private val writer: (scheme: CopyrightProfile) -> Element, + private val subStateTagName: String = "copyright") : SchemeWrapper(name) { + private val dataHolder = AtomicReference(dataHolder) + + override val lazyScheme = lazy { + val scheme = CopyrightProfile() + @Suppress("NAME_SHADOWING") + val dataHolder = this.dataHolder.getAndSet(null) + val element = dataHolder.read().getChild(subStateTagName) + scheme.readExternal(element) + dataHolder.updateDigest(writer(scheme)) + scheme + } + + override fun writeScheme(): Element { + val dataHolder = dataHolder.get() + return if (dataHolder == null) writer(scheme) else dataHolder.read() + } +} \ No newline at end of file diff --git a/plugins/copyright/src/META-INF/plugin.xml b/plugins/copyright/src/META-INF/plugin.xml index 87b49a360163..0a583be018b5 100644 --- a/plugins/copyright/src/META-INF/plugin.xml +++ b/plugins/copyright/src/META-INF/plugin.xml @@ -1,56 +1,50 @@ - - - - Copyright - com.intellij.copyright - - Copyright Notice. This plugin is used to ensure files in a project or module have - a consistent copyright notice. - - 8.1 - JetBrains - com.intellij.modules.java + Copyright + com.intellij.copyright + + Copyright Notice. This plugin is used to ensure files in a project or module have a consistent copyright notice. + + 8.1 + JetBrains + com.intellij.modules.java - - - - - - + + + + + + - - - com.maddyhome.idea.copyright.CopyrightManager - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java b/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java deleted file mode 100644 index be5cebfb2d87..000000000000 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/CopyrightManager.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * 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.maddyhome.idea.copyright; - -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.Application; -import com.intellij.openapi.application.ModalityState; -import com.intellij.openapi.components.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.EditorFactory; -import com.intellij.openapi.editor.event.DocumentAdapter; -import com.intellij.openapi.editor.event.DocumentEvent; -import com.intellij.openapi.editor.event.DocumentListener; -import com.intellij.openapi.fileEditor.FileDocumentManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.startup.StartupManager; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.packageDependencies.DependencyValidationManager; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.search.scope.packageSet.NamedScope; -import com.intellij.psi.search.scope.packageSet.PackageSet; -import com.maddyhome.idea.copyright.actions.UpdateCopyrightProcessor; -import com.maddyhome.idea.copyright.options.LanguageOptions; -import com.maddyhome.idea.copyright.options.Options; -import com.maddyhome.idea.copyright.util.FileTypeUtil; -import com.maddyhome.idea.copyright.util.NewFileTracker; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -@State(name = "CopyrightManager", storages = @Storage(value = "copyright", stateSplitter = CopyrightManager.CopyrightStateSplitter.class)) -public class CopyrightManager extends AbstractProjectComponent implements PersistentStateComponent { - private static final Logger LOG = Logger.getInstance("#" + CopyrightManager.class.getName()); - @Nullable - private CopyrightProfile myDefaultCopyright = null; - private final LinkedHashMap myModuleToCopyrights = new LinkedHashMap<>(); - private final Map myCopyrights = new TreeMap<>(); - private final Options myOptions = new Options(); - - public CopyrightManager(@NotNull Project project, - @NotNull final EditorFactory editorFactory, - @NotNull final Application application, - @NotNull final FileDocumentManager fileDocumentManager, - @NotNull final FileTypeUtil fileTypeUtil, - @NotNull final ProjectRootManager projectRootManager, - @NotNull final PsiManager psiManager, - @NotNull StartupManager startupManager) { - super(project); - if (!myProject.isDefault()) { - final NewFileTracker newFileTracker = NewFileTracker.getInstance(); - Disposer.register(myProject, new Disposable() { - @Override - public void dispose() { - newFileTracker.clear(); - } - }); - startupManager.runWhenProjectIsInitialized(() -> { - DocumentListener listener = new DocumentAdapter() { - @Override - public void documentChanged(DocumentEvent e) { - final Document document = e.getDocument(); - final VirtualFile virtualFile = fileDocumentManager.getFile(document); - if (virtualFile == null) return; - final Module module = projectRootManager.getFileIndex().getModuleForFile(virtualFile); - if (module == null) return; - if (!newFileTracker.poll(virtualFile)) return; - if (!fileTypeUtil.isSupportedFile(virtualFile)) return; - if (psiManager.findFile(virtualFile) == null) return; - application.invokeLater(() -> { - if (!virtualFile.isValid()) return; - final PsiFile file = psiManager.findFile(virtualFile); - if (file != null && file.isWritable()) { - final CopyrightProfile opts = getCopyrightOptions(file); - if (opts != null) { - new UpdateCopyrightProcessor(myProject, module, file).run(); - } - } - }, ModalityState.NON_MODAL, myProject.getDisposed()); - } - }; - editorFactory.getEventMulticaster().addDocumentListener(listener, myProject); - }); - } - } - - @NonNls - static final String COPYRIGHT = "copyright"; - @NonNls - private static final String MODULE2COPYRIGHT = "module2copyright"; - @NonNls - private static final String ELEMENT = "element"; - @NonNls - private static final String MODULE = "module"; - @NonNls - private static final String DEFAULT = "default"; - - public static CopyrightManager getInstance(Project project) { - return project.getComponent(CopyrightManager.class); - } - - @Override - @NonNls - @NotNull - public String getComponentName() { - return "CopyrightManager"; - } - - @Override - public Element getState() { - Element state = new Element("settings"); - - try { - if (!myCopyrights.isEmpty()) { - for (CopyrightProfile copyright : myCopyrights.values()) { - Element copyrightElement = new Element(COPYRIGHT); - copyright.serializeInto(copyrightElement, true); - if (!JDOMUtil.isEmpty(copyrightElement)) { - state.addContent(copyrightElement); - } - } - } - - if (!myModuleToCopyrights.isEmpty()) { - final Element map = new Element(MODULE2COPYRIGHT); - for (String moduleName : myModuleToCopyrights.keySet()) { - final Element setting = new Element(ELEMENT); - setting.setAttribute(MODULE, moduleName); - setting.setAttribute(COPYRIGHT, myModuleToCopyrights.get(moduleName)); - map.addContent(setting); - } - state.addContent(map); - } - - myOptions.writeExternal(state); - } - catch (WriteExternalException e) { - LOG.error(e); - return null; - } - - if (myDefaultCopyright != null) { - state.setAttribute(DEFAULT, myDefaultCopyright.getName()); - } - - return state; - } - - @Override - public void loadState(Element state) { - clearCopyrights(); - - final Element moduleToCopyright = state.getChild(MODULE2COPYRIGHT); - if (moduleToCopyright != null) { - for (Element element : moduleToCopyright.getChildren(ELEMENT)) { - myModuleToCopyrights.put(element.getAttributeValue(MODULE), element.getAttributeValue(COPYRIGHT)); - } - } - - try { - for (Element element : state.getChildren(COPYRIGHT)) { - final CopyrightProfile copyrightProfile = new CopyrightProfile(); - copyrightProfile.readExternal(element); - myCopyrights.put(copyrightProfile.getName(), copyrightProfile); - } - myDefaultCopyright = myCopyrights.get(StringUtil.notNullize(state.getAttributeValue(DEFAULT))); - myOptions.readExternal(state); - } - catch (InvalidDataException e) { - LOG.error(e); - } - } - - public Map getCopyrightsMapping() { - return myModuleToCopyrights; - } - - public void setDefaultCopyright(@Nullable CopyrightProfile copyright) { - myDefaultCopyright = copyright; - } - - @Nullable - public CopyrightProfile getDefaultCopyright() { - return myDefaultCopyright; - } - - public void addCopyright(CopyrightProfile copyrightProfile) { - myCopyrights.put(copyrightProfile.getName(), copyrightProfile); - } - - public void removeCopyright(CopyrightProfile copyrightProfile) { - myCopyrights.values().remove(copyrightProfile); - for (Iterator it = myModuleToCopyrights.keySet().iterator(); it.hasNext();) { - final String profileName = myModuleToCopyrights.get(it.next()); - if (profileName.equals(copyrightProfile.getName())) { - it.remove(); - } - } - } - - public void clearCopyrights() { - myDefaultCopyright = null; - myCopyrights.clear(); - myModuleToCopyrights.clear(); - } - - public void mapCopyright(String scopeName, String copyrightProfileName) { - myModuleToCopyrights.put(scopeName, copyrightProfileName); - } - - public void unmapCopyright(String scopeName) { - myModuleToCopyrights.remove(scopeName); - } - - public Collection getCopyrights() { - return myCopyrights.values(); - } - - public boolean hasAnyCopyrights() { - return myDefaultCopyright != null || !myModuleToCopyrights.isEmpty(); - } - - @Nullable - public CopyrightProfile getCopyrightOptions(@NotNull PsiFile file) { - final VirtualFile virtualFile = file.getVirtualFile(); - if (virtualFile == null || myOptions.getOptions(virtualFile.getFileType().getName()).getFileTypeOverride() == LanguageOptions.NO_COPYRIGHT) return null; - final DependencyValidationManager validationManager = DependencyValidationManager.getInstance(myProject); - for (String scopeName : myModuleToCopyrights.keySet()) { - final NamedScope namedScope = validationManager.getScope(scopeName); - if (namedScope != null) { - final PackageSet packageSet = namedScope.getValue(); - if (packageSet != null) { - if (packageSet.contains(file, validationManager)) { - final CopyrightProfile profile = myCopyrights.get(myModuleToCopyrights.get(scopeName)); - if (profile != null) { - return profile; - } - } - } - } - } - return myDefaultCopyright != null ? myDefaultCopyright : null; - } - - public Options getOptions() { - return myOptions; - } - - public void replaceCopyright(String displayName, CopyrightProfile copyrightProfile) { - if (myDefaultCopyright != null && Comparing.strEqual(myDefaultCopyright.getName(), displayName)) { - myDefaultCopyright = copyrightProfile; - } - myCopyrights.remove(displayName); - addCopyright(copyrightProfile); - } - - static final class CopyrightStateSplitter extends MainConfigurationStateSplitter { - @NotNull - @Override - protected String getComponentStateFileName() { - return "profiles_settings"; - } - - @NotNull - @Override - protected String getSubStateTagName() { - return COPYRIGHT; - } - } -} diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/AbstractFileProcessor.java b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/AbstractFileProcessor.java index fe6870b349f4..7b020a0e6597 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/AbstractFileProcessor.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/AbstractFileProcessor.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. @@ -17,6 +17,7 @@ package com.maddyhome.idea.copyright.actions; import com.intellij.codeInsight.FileModificationService; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; @@ -30,13 +31,12 @@ import com.intellij.openapi.roots.ContentIterator; import com.intellij.openapi.roots.ModuleFileIndex; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.ReadonlyStatusHandler; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.util.IncorrectOperationException; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.util.FileTypeUtil; import org.jetbrains.annotations.NotNull; @@ -51,39 +51,11 @@ public abstract class AbstractFileProcessor { private PsiDirectory directory = null; private PsiFile file = null; private PsiFile[] files = null; - private boolean subdirs = false; private final String message; private final String title; protected abstract Runnable preprocessFile(PsiFile file, boolean allowReplacement) throws IncorrectOperationException; - protected AbstractFileProcessor(Project project, String title, String message) { - myProject = project; - myModule = null; - directory = null; - subdirs = true; - this.title = title; - this.message = message; - } - - protected AbstractFileProcessor(Project project, Module module, String title, String message) { - myProject = project; - myModule = module; - directory = null; - subdirs = true; - this.title = title; - this.message = message; - } - - protected AbstractFileProcessor(Project project, PsiDirectory dir, boolean subdirs, String title, String message) { - myProject = project; - myModule = null; - directory = dir; - this.subdirs = subdirs; - this.message = message; - this.title = title; - } - protected AbstractFileProcessor(Project project, PsiFile file, String title, String message) { myProject = project; myModule = null; @@ -92,7 +64,7 @@ public abstract class AbstractFileProcessor { this.title = title; } - protected AbstractFileProcessor(Project project, PsiFile[] files, String title, String message, Runnable runnable) { + protected AbstractFileProcessor(Project project, PsiFile[] files, String title, String message) { myProject = project; myModule = null; this.files = files; @@ -102,7 +74,7 @@ public abstract class AbstractFileProcessor { public void run() { if (directory != null) { - process(directory, subdirs); + process(directory, false); } else if (files != null) { process(files); @@ -275,7 +247,7 @@ public abstract class AbstractFileProcessor { for (PsiFile psiFile : files) { vFiles.add(psiFile.getVirtualFile()); } - if (!ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(VfsUtil.toVirtualFileArray(vFiles)) + if (!ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(VfsUtilCore.toVirtualFileArray(vFiles)) .hasReadonlyFiles()) { if (!files.isEmpty()) { final Runnable[] resultRunnable = new Runnable[1]; @@ -296,15 +268,12 @@ public abstract class AbstractFileProcessor { if (opts != null && FileTypeUtil.isSupportedFile(local)) { files.add(local); } - } if (subdirs) { - PsiDirectory[] dirs = directory.getSubdirectories(); - for (PsiDirectory dir : dirs) { - findFiles(files, dir, subdirs); + for (PsiDirectory dir : directory.getSubdirectories()) { + findFiles(files, dir, true); } - } } diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java index 2a1b9c9df186..c077ccb6b7b1 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/GenerateCopyrightAction.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.maddyhome.idea.copyright.actions; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.module.Module; @@ -24,7 +24,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.ui.CopyrightProjectConfigurable; import com.maddyhome.idea.copyright.util.FileTypeUtil; import org.jetbrains.annotations.Nullable; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightAction.java b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightAction.java index 7d096633ab1d..b219fc4c28a6 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightAction.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightAction.java @@ -20,6 +20,7 @@ import com.intellij.analysis.AnalysisScope; import com.intellij.analysis.BaseAnalysisAction; import com.intellij.analysis.BaseAnalysisActionDialog; import com.intellij.codeInsight.FileModificationService; +import com.intellij.copyright.CopyrightManager; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.command.CommandProcessor; @@ -37,7 +38,6 @@ import com.intellij.psi.*; import com.intellij.ui.TitledSeparator; import com.intellij.util.SequentialModalProgressTask; import com.intellij.util.SequentialTask; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.pattern.FileUtil; import com.maddyhome.idea.copyright.util.FileTypeUtil; import org.jetbrains.annotations.NotNull; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightProcessor.java b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightProcessor.java index e2fc2cdfb9db..c11ea431faea 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightProcessor.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/actions/UpdateCopyrightProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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,6 +16,7 @@ package com.maddyhome.idea.copyright.actions; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.progress.ProgressIndicator; @@ -24,10 +25,8 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.EmptyRunnable; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.psi.UpdateCopyright; import com.maddyhome.idea.copyright.psi.UpdateCopyrightFactory; @@ -39,18 +38,6 @@ public class UpdateCopyrightProcessor extends AbstractFileProcessor public static final String TITLE = "Update Copyright"; public static final String MESSAGE = "Updating copyrights..."; - public UpdateCopyrightProcessor(Project project, Module module) - { - super(project, module, TITLE, MESSAGE); - setup(project, module); - } - - public UpdateCopyrightProcessor(Project project, Module module, PsiDirectory dir, boolean subdirs) - { - super(project, dir, subdirs, TITLE, MESSAGE); - setup(project, module); - } - public UpdateCopyrightProcessor(Project project, Module module, PsiFile file) { super(project, file, TITLE, MESSAGE); @@ -59,7 +46,7 @@ public class UpdateCopyrightProcessor extends AbstractFileProcessor public UpdateCopyrightProcessor(Project project, Module module, PsiFile[] files) { - super(project, files, TITLE, MESSAGE, null); + super(project, files, TITLE, MESSAGE); setup(project, module); } diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/pattern/VelocityHelper.java b/plugins/copyright/src/com/maddyhome/idea/copyright/pattern/VelocityHelper.java index d3c5e74a945d..94fe8871cfd9 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/pattern/VelocityHelper.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/pattern/VelocityHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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,6 +16,7 @@ package com.maddyhome.idea.copyright.pattern; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -23,7 +24,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiUtilCore; -import com.maddyhome.idea.copyright.CopyrightManager; import org.apache.commons.collections.ExtendedProperties; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/AbstractUpdateCopyright.java b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/AbstractUpdateCopyright.java index ad21b02c514a..a67b2ff727d3 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/AbstractUpdateCopyright.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/AbstractUpdateCopyright.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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,13 +16,13 @@ package com.maddyhome.idea.copyright.psi; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiManager; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.options.LanguageOptions; import com.maddyhome.idea.copyright.pattern.EntityUtil; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java index 02ee5ccb1502..77827b278585 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/psi/UpdatePsiFileCopyright.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. @@ -16,6 +16,7 @@ package com.maddyhome.idea.copyright.psi; +import com.intellij.copyright.CopyrightManager; import com.intellij.lang.Commenter; import com.intellij.lang.LanguageCommenters; import com.intellij.openapi.command.WriteCommandAction; @@ -31,7 +32,6 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.IncorrectOperationException; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.options.LanguageOptions; import com.maddyhome.idea.copyright.util.FileTypeUtil; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightConfigurable.java b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightConfigurable.java index d14dcdaf88fa..ae0938cc4fd0 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightConfigurable.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightConfigurable.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 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,6 +16,7 @@ package com.maddyhome.idea.copyright.ui; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider; import com.intellij.openapi.fileTypes.FileTypes; @@ -28,12 +29,12 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; import com.intellij.util.DocumentUtil; import com.intellij.util.containers.ContainerUtil; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.pattern.EntityUtil; import com.maddyhome.idea.copyright.pattern.VelocityHelper; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -59,7 +60,7 @@ public class CopyrightConfigurable extends NamedConfigurable { private JTextField myAllowReplaceTextField; private JPanel myEditorPanel; - public CopyrightConfigurable(Project project, CopyrightProfile copyrightProfile, Runnable updater) { + public CopyrightConfigurable(@NotNull Project project, CopyrightProfile copyrightProfile, Runnable updater) { super(true, updater); myProject = project; myCopyrightProfile = copyrightProfile; @@ -130,6 +131,7 @@ public class CopyrightConfigurable extends NamedConfigurable { catch (PatternSyntaxException e) { throw new ConfigurationException("Keyword pattern syntax is incorrect: " + e.getMessage()); } + myCopyrightProfile.setKeyword(keyword); myCopyrightProfile.setAllowReplaceKeyword(myAllowReplaceTextField.getText().trim()); CopyrightManager.getInstance(myProject).replaceCopyright(myDisplayName, myCopyrightProfile); diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java index 57bc6e9260b3..17b6d6753f5e 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/CopyrightProfilesPanel.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.maddyhome.idea.copyright.ui; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonShortcuts; @@ -37,14 +37,10 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; -import com.intellij.openapi.util.Condition; import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import com.intellij.util.IconUtil; import com.intellij.util.PlatformIcons; import com.intellij.util.containers.HashMap; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.options.ExternalOptionHelper; import org.jetbrains.annotations.Nls; @@ -90,15 +86,11 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se @Override protected void processRemovedItems() { Map profiles = getAllProfiles(); - final List deleted = new ArrayList<>(); - for (CopyrightProfile profile : myManager.getCopyrights()) { + for (CopyrightProfile profile : new ArrayList<>(myManager.getCopyrights())) { if (!profiles.containsValue(profile)) { - deleted.add(profile); + myManager.removeCopyright(profile); } } - for (CopyrightProfile profile : deleted) { - myManager.removeCopyright(profile); - } } @Override @@ -174,10 +166,10 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se @Override public void actionPerformed(AnActionEvent event) { - final String name = askForProfileName("Create Copyright Profile", ""); - if (name == null) return; - final CopyrightProfile copyrightProfile = new CopyrightProfile(name); - addProfileNode(copyrightProfile); + String name = askForProfileName("Create Copyright Profile", ""); + if (name != null) { + addProfileNode(new CopyrightProfile(name)); + } } }); result.add(new MyDeleteAction()); @@ -188,9 +180,12 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se @Override public void actionPerformed(AnActionEvent event) { - final String profileName = askForProfileName("Copy Copyright Profile", ""); - if (profileName == null) return; - final CopyrightProfile clone = new CopyrightProfile(); + String profileName = askForProfileName("Copy Copyright Profile", ""); + if (profileName == null) { + return; + } + + CopyrightProfile clone = new CopyrightProfile(); clone.copyFrom((CopyrightProfile)getSelectedObject()); clone.setName(profileName); addProfileNode(clone); @@ -268,7 +263,7 @@ public class CopyrightProfilesPanel extends MasterDetailsComponent implements Se }); } - private void addProfileNode(CopyrightProfile copyrightProfile) { + private void addProfileNode(@NotNull CopyrightProfile copyrightProfile) { final CopyrightConfigurable copyrightConfigurable = new CopyrightConfigurable(myProject, copyrightProfile, TREE_UPDATER); copyrightConfigurable.setModified(true); final MyNode node = new MyNode(copyrightConfigurable); diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/ProjectSettingsPanel.java b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/ProjectSettingsPanel.java index 541922f92269..98aac77dd502 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/ProjectSettingsPanel.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/ProjectSettingsPanel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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. @@ -15,15 +15,16 @@ */ package com.maddyhome.idea.copyright.ui; +import com.intellij.copyright.CopyrightManager; import com.intellij.ide.DataManager; import com.intellij.ide.util.scopeChooser.PackageSetChooserCombo; import com.intellij.ide.util.scopeChooser.ScopeChooserConfigurable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.options.ex.Settings; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.Comparing; -import com.intellij.packageDependencies.DefaultScopesProvider; import com.intellij.packageDependencies.DependencyValidationManager; import com.intellij.psi.search.scope.packageSet.CustomScopesProviderEx; import com.intellij.psi.search.scope.packageSet.NamedScope; @@ -34,9 +35,7 @@ import com.intellij.ui.ListCellRendererWrapper; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.components.editors.JBComboBoxTableCellEditorComponent; import com.intellij.ui.table.TableView; -import com.intellij.util.Function; import com.intellij.util.ui.*; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -58,7 +57,7 @@ public class ProjectSettingsPanel { private final TableView myScopeMappingTable; private final ListTableModel myScopeMappingModel; - private final JComboBox myProfilesComboBox = new JComboBox(); + private final JComboBox myProfilesComboBox = new ComboBox(); private final HyperlinkLabel myScopesLink = new HyperlinkLabel(); @@ -135,7 +134,7 @@ public class ProjectSettingsPanel { ElementProducer producer = new ElementProducer() { @Override public ScopeSetting createElement() { - return new ScopeSetting(DefaultScopesProvider.getAllScope(), myProfilesModel.getAllProfiles().values().iterator().next()); + return new ScopeSetting(CustomScopesProviderEx.getAllScope(), myProfilesModel.getAllProfiles().values().iterator().next()); } @Override @@ -151,14 +150,12 @@ public class ProjectSettingsPanel { } public boolean isModified() { - final CopyrightProfile defaultCopyright = myManager.getDefaultCopyright(); + CopyrightProfile defaultCopyright = myManager.getDefaultCopyright(); final Object selected = myProfilesComboBox.getSelectedItem(); - if (defaultCopyright != selected) { - if (selected == null) return true; - if (defaultCopyright == null) return true; - if (!defaultCopyright.equals(selected)) return true; + if (defaultCopyright != selected && (selected == null || defaultCopyright == null || !defaultCopyright.equals(selected))) { + return true; } - final Map map = myManager.getCopyrightsMapping(); + final Map map = myManager.getScopeToCopyright(); if (map.size() != myScopeMappingModel.getItems().size()) return true; final Iterator iterator = map.keySet().iterator(); for (ScopeSetting setting : myScopeMappingModel.getItems()) { @@ -174,22 +171,17 @@ public class ProjectSettingsPanel { } public void apply() { - Collection profiles = new ArrayList<>(myManager.getCopyrights()); - myManager.clearCopyrights(); - for (CopyrightProfile profile : profiles) { - myManager.addCopyright(profile); - } - final List settingList = myScopeMappingModel.getItems(); - for (ScopeSetting scopeSetting : settingList) { + myManager.setDefaultCopyright((CopyrightProfile)myProfilesComboBox.getSelectedItem()); + myManager.clearMappings(); + for (ScopeSetting scopeSetting : myScopeMappingModel.getItems()) { myManager.mapCopyright(scopeSetting.getScope().getName(), scopeSetting.getProfileName()); } - myManager.setDefaultCopyright((CopyrightProfile)myProfilesComboBox.getSelectedItem()); } public void reset() { myProfilesComboBox.setSelectedItem(myManager.getDefaultCopyright()); final List mappings = new ArrayList<>(); - final Map copyrights = myManager.getCopyrightsMapping(); + final Map copyrights = myManager.getScopeToCopyright(); final DependencyValidationManager manager = DependencyValidationManager.getInstance(myProject); final Set scopes2Unmap = new HashSet<>(); for (final String scopeName : copyrights.keySet()) { @@ -207,7 +199,6 @@ public class ProjectSettingsPanel { myScopeMappingModel.setItems(mappings); } - private class ScopeSetting { private NamedScope myScope; private CopyrightProfile myProfile; diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/TemplateCommentPanel.java b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/TemplateCommentPanel.java index 515afd30f3f0..ba2231a3ab8b 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/ui/TemplateCommentPanel.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/ui/TemplateCommentPanel.java @@ -16,6 +16,7 @@ package com.maddyhome.idea.copyright.ui; +import com.intellij.copyright.CopyrightManager; import com.intellij.openapi.editor.colors.EditorColorsManager; import com.intellij.openapi.editor.colors.EditorFontType; import com.intellij.openapi.fileTypes.FileType; @@ -27,7 +28,6 @@ import com.intellij.openapi.project.Project; import com.intellij.ui.DocumentAdapter; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.util.ui.UIUtil; -import com.maddyhome.idea.copyright.CopyrightManager; import com.maddyhome.idea.copyright.CopyrightProfile; import com.maddyhome.idea.copyright.options.LanguageOptions; import com.maddyhome.idea.copyright.options.Options; @@ -82,10 +82,7 @@ public class TemplateCommentPanel implements SearchableConfigurable { private void updateBox() { boolean enable = true; - if (!cbSeparatorBefore.isSelected()) { - enable = false; - } - else if (!cbSeparatorAfter.isSelected()) { + if (!cbSeparatorBefore.isSelected() || !cbSeparatorAfter.isSelected()) { enable = false; } else { @@ -336,8 +333,8 @@ public class TemplateCommentPanel implements SearchableConfigurable { mySeparatorCharLabel.setEnabled(true); updateBox(); } else { - UIUtil.setEnabled(myCommentTypePanel, enable, true); - UIUtil.setEnabled(myBorderPanel, enable, true); + UIUtil.setEnabled(myCommentTypePanel, false, true); + UIUtil.setEnabled(myBorderPanel, false, true); } } diff --git a/plugins/copyright/src/com/maddyhome/idea/copyright/util/NewFileTracker.java b/plugins/copyright/src/com/maddyhome/idea/copyright/util/NewFileTracker.java index ad68be5d10b6..84a91150c35a 100644 --- a/plugins/copyright/src/com/maddyhome/idea/copyright/util/NewFileTracker.java +++ b/plugins/copyright/src/com/maddyhome/idea/copyright/util/NewFileTracker.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. @@ -24,17 +24,14 @@ import java.util.Collections; import java.util.Set; public class NewFileTracker { - public static NewFileTracker getInstance() { - return instance; - } + private final Set newFiles = Collections.synchronizedSet(new THashSet()); public boolean poll(@NotNull VirtualFile file) { return newFiles.remove(file); } - private NewFileTracker() { - final VirtualFileManager virtualFileManager = VirtualFileManager.getInstance(); - virtualFileManager.addVirtualFileListener(new VirtualFileAdapter() { + public NewFileTracker() { + VirtualFileManager.getInstance().addVirtualFileListener(new VirtualFileAdapter() { @Override public void fileCreated(@NotNull VirtualFileEvent event) { if (event.isFromRefresh()) return; @@ -49,9 +46,6 @@ public class NewFileTracker { }); } - private final Set newFiles = Collections.synchronizedSet(new THashSet()); - private static final NewFileTracker instance = new NewFileTracker(); - public void clear() { newFiles.clear(); } diff --git a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java index 2eb5b138dd8b..e3ea1dc6003c 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java +++ b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java @@ -129,12 +129,13 @@ public class GitAnnotationProvider implements AnnotationProviderEx { assert vcs != null; VcsRevisionNumber actualRevision = revision != null ? revision : vcs.getDiffProvider().getCurrentRevision(file); + if (actualRevision != null) { Object annotatedData = myCache.get(repositoryFilePath, GitVcs.getKey(), actualRevision); - if (annotatedData instanceof CachedData) return restoreFromCache(file, revision, (CachedData)annotatedData); + if (annotatedData instanceof CachedData) return restoreFromCache(file, actualRevision, (CachedData)annotatedData); } - GitFileAnnotation fileAnnotation = doAnnotate(repositoryFilePath, revision, file); + GitFileAnnotation fileAnnotation = doAnnotate(repositoryFilePath, actualRevision, file); if (actualRevision != null) { myCache.put(repositoryFilePath, GitVcs.getKey(), actualRevision, cacheData(fileAnnotation)); diff --git a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java index 8ca02c145245..93bb1f47168f 100644 --- a/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java +++ b/plugins/git4idea/src/git4idea/annotate/GitFileAnnotation.java @@ -73,16 +73,15 @@ public class GitFileAnnotation extends FileAnnotation { } }; - public GitFileAnnotation(@NotNull final Project project, + public GitFileAnnotation(@NotNull Project project, @NotNull VirtualFile file, - @Nullable final VcsRevisionNumber revision, + @Nullable VcsRevisionNumber revision, @NotNull List lines) { super(project); myProject = project; myFile = file; myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(myProject)); - myBaseRevision = revision == null ? (myVcs.getDiffProvider().getCurrentRevision(file)) : revision; - + myBaseRevision = revision; myLines = lines; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspection.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspection.java index caa820acdcf2..51913e7c1ccb 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspection.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspection.java @@ -25,6 +25,7 @@ import com.intellij.psi.tree.TokenSet; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrTraditionalForClause; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import static com.intellij.psi.tree.TokenSet.andNot; @@ -79,6 +80,7 @@ public class GrUnnecessarySemicolonInspection extends GroovySuppressableInspecti } private static boolean isSemicolonUnnecessary(@NotNull PsiElement semicolon) { + if (semicolon.getParent() instanceof GrTraditionalForClause) return false; PsiElement next = PsiUtil.skipLeafSet(semicolon, true, FORWARD_SET); if (next == null) return true; if (next.getNode().getElementType() == mNLS) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java index 4a2e422f1aea..6391a469680a 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/lexer/TokenSets.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. @@ -294,9 +294,15 @@ public abstract class TokenSets { GroovyElementTypes.DISJUNCTION_TYPE_ELEMENT); - public static final TokenSet TYPE_DEFINITIONS = TokenSet.create(GroovyElementTypes.CLASS_DEFINITION, + public static final TokenSet TYPE_DEFINITIONS = TokenSet.create(GroovyElementTypes.CLASS_DEFINITION, GroovyElementTypes.ENUM_DEFINITION, GroovyElementTypes.INTERFACE_DEFINITION, GroovyElementTypes.ANNOTATION_DEFINITION, GroovyElementTypes.TRAIT_DEFINITION); + + public static final TokenSet METHOD_IDENTIFIERS = TokenSet.create( + GroovyTokenTypes.mIDENT, + GroovyTokenTypes.mGSTRING_LITERAL, + GroovyTokenTypes.mSTRING_LITERAL + ); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyAppLineMarkerContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyAppLineMarkerContributor.java index ed94d7927773..fce119831f11 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyAppLineMarkerContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyAppLineMarkerContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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. @@ -17,7 +17,8 @@ package org.jetbrains.plugins.groovy.testIntegration; import com.intellij.execution.application.ApplicationRunLineMarkerProvider; import com.intellij.psi.PsiElement; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; + +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.METHOD_IDENTIFIERS; /** * @author Dmitry Avdeev @@ -26,6 +27,6 @@ public class GroovyAppLineMarkerContributor extends ApplicationRunLineMarkerProv @Override protected boolean isIdentifier(PsiElement e) { - return e.getNode().getElementType() == GroovyTokenTypes.mIDENT; + return METHOD_IDENTIFIERS.contains(e.getNode().getElementType()); } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestLineMarkerContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestLineMarkerContributor.java index ebf5269f6f16..7050beaedbf1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestLineMarkerContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/testIntegration/GroovyTestLineMarkerContributor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2015 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,17 +16,17 @@ package org.jetbrains.plugins.groovy.testIntegration; import com.intellij.psi.PsiElement; -import com.intellij.psi.tree.IElementType; import com.intellij.testIntegration.TestRunLineMarkerProvider; -import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes; + +import static org.jetbrains.plugins.groovy.lang.lexer.TokenSets.METHOD_IDENTIFIERS; /** * @author Dmitry Avdeev */ public class GroovyTestLineMarkerContributor extends TestRunLineMarkerProvider { + @Override protected boolean isIdentifier(PsiElement e) { - IElementType type = e.getNode().getElementType(); - return type == GroovyTokenTypes.mIDENT || type == GroovyTokenTypes.mGSTRING_LITERAL; + return METHOD_IDENTIFIERS.contains(e.getNode().getElementType()); } } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy index a8a40e1bc168..2fd36afed0bc 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/codeInspection/style/GrUnnecessarySemicolonInspectionTest.groovy @@ -75,6 +75,10 @@ print(a); {->} doTest 'for (int i = 0; i < 10;) {}' } + void 'test traditional for without condition'() { + doTest 'for (int i = 0; ; i++) {}' + } + void 'test class members'() { doTest '''\ class A { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java index 4cf4e9310146..290a395fcdfc 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFxPsiUtil.java @@ -1198,7 +1198,7 @@ public class JavaFxPsiUtil { if (type != null && type.equalsToText(JavaFxCommonNames.JAVAFX_FXML_FXMLLOADER)) { final PsiElement parent = expression.getParent(); if (parent instanceof PsiLocalVariable) { - ReferencesSearch.search(parent, parent.getUseScope()).forEach(processor); + ReferencesSearch.search(parent).forEach(processor); final PsiClass controller = injectedController.get(); if (controller != null) { return false; diff --git a/plugins/settings-repository/src/authForm.kt b/plugins/settings-repository/src/authForm.kt index 1e63bc57179a..5f9e85368785 100644 --- a/plugins/settings-repository/src/authForm.kt +++ b/plugins/settings-repository/src/authForm.kt @@ -21,13 +21,12 @@ import com.intellij.layout.* import com.intellij.layout.CCFlags.* import com.intellij.layout.LCFlags.* import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.invokeAndWaitIfNeed import com.intellij.openapi.ui.dialog -import com.intellij.openapi.util.Computable import com.intellij.ui.DocumentAdapter import com.intellij.util.PathUtilRt import com.intellij.util.nullize import com.intellij.util.trimMiddle -import com.intellij.util.ui.UIUtil import javax.swing.JPasswordField import javax.swing.JTextField import javax.swing.event.DocumentEvent @@ -38,16 +37,16 @@ fun showAuthenticationForm(credentials: Credentials?, uri: String, host: String? } val isGitHub = host == "github.com" - val note = if (sshKeyFile == null) icsMessage(if (isGitHub) "login.github.note" else "login.other.git.provider.note") else null - var username = credentials?.userName - if (username == null && isGitHub && path != null && sshKeyFile == null) { - val firstSlashIndex = path.indexOf('/', 1) - username = path.substring(1, if (firstSlashIndex == -1) path.length else firstSlashIndex) - } + val note = if (sshKeyFile == null) icsMessage(if (isGitHub) "login.github.note" else "login.other.git.provider.note") else null + var username = credentials?.userName + if (username == null && isGitHub && path != null && sshKeyFile == null) { + val firstSlashIndex = path.indexOf('/', 1) + username = path.substring(1, if (firstSlashIndex == -1) path.length else firstSlashIndex) + } - val message = if (sshKeyFile == null) icsMessage("log.in.to", uri.trimMiddle(50)) else icsMessage("enter.your.password.for.ssh.key", PathUtilRt.getFileName(sshKeyFile)) + val message = if (sshKeyFile == null) icsMessage("log.in.to", uri.trimMiddle(50)) else icsMessage("enter.your.password.for.ssh.key", PathUtilRt.getFileName(sshKeyFile)) - return UIUtil.invokeAndWaitIfNeeded(Computable { + return invokeAndWaitIfNeed { val userField = JTextField(username) val passwordField = JPasswordField(credentials?.password.toString()) @@ -69,7 +68,7 @@ fun showAuthenticationForm(credentials: Credentials?, uri: String, host: String? title = "Settings Repository", resizable = false, centerPanel = centerPanel, - preferedFocusComponent = userField, + preferedFocusComponent = if (userField.parent == null) passwordField else userField, okActionEnabled = false) passwordField.document.addDocumentListener(object : DocumentAdapter() { @@ -87,5 +86,5 @@ fun showAuthenticationForm(credentials: Credentials?, uri: String, host: String? else { null } - }) + } } \ No newline at end of file diff --git a/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityBuilder.groovy b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityBuilder.groovy new file mode 100644 index 000000000000..f8deb6206539 --- /dev/null +++ b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityBuilder.groovy @@ -0,0 +1,43 @@ +/* + * 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 org.jetbrains.intellij.build.pycharm + +import org.codehaus.gant.GantBinding +import org.jetbrains.intellij.build.BuildContext +import org.jetbrains.intellij.build.BuildTasks +import org.jetbrains.intellij.build.JetBrainsBuildTools + +/** + * @author nik + */ +class PyCharmCommunityBuilder { + private final GantBinding binding + private final String home + + PyCharmCommunityBuilder(String home, GantBinding binding) { + this.home = home + this.binding = binding + } + + def build() { + def buildContext = BuildContext.createContext(binding.ant, binding.projectBuilder, binding.project, binding.global, + "$home/community", home, "$home/out/pycharmCE", new PyCharmCommunityProperties(home), + JetBrainsBuildTools.create("$home/build/lib/jet-sign.jar")) + def buildTasks = BuildTasks.create(buildContext) + buildTasks.compileModulesAndBuildDistributions() + buildTasks.zipProjectSources() + } +} \ No newline at end of file diff --git a/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityProperties.groovy b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityProperties.groovy new file mode 100644 index 000000000000..1e9b0aa55cc6 --- /dev/null +++ b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmCommunityProperties.groovy @@ -0,0 +1,116 @@ +/* + * 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 org.jetbrains.intellij.build.pycharm + +import org.jetbrains.intellij.build.* + +/** + * @author nik + */ +class PyCharmCommunityProperties extends PyCharmPropertiesBase { + PyCharmCommunityProperties(String home) { + super(home) + productCode = "PC" + platformPrefix = "PyCharmCore" + applicationInfoModule = "python-community-ide-resources" + brandingResourcePaths = ["$home/community/python/resources"] + + productLayout.platformApiModules = CommunityRepositoryModules.PLATFORM_API_MODULES + ["dom-openapi"] + productLayout.platformImplementationModules = CommunityRepositoryModules.PLATFORM_IMPLEMENTATION_MODULES + [ + "dom-impl", "python-community", "python-community-ide-resources", + "python-ide-community", "python-community-configure", "python-openapi", "python-psi-api", "platform-main" + ] + productLayout.bundledPluginModules = new File("$home/community/python/build/plugin-list.txt").readLines() + productLayout.mainModule = "main_pycharm_ce" + } + + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + super.copyAdditionalFiles(context, targetDirectory) + context.ant.copy(todir: "$targetDirectory/license") { + fileset(file: "$context.paths.communityHome/LICENSE.txt") + fileset(file: "$context.paths.communityHome/NOTICE.txt") + } + } + + @Override + String systemSelector(ApplicationInfoProperties applicationInfo) { + "PyCharmCE${applicationInfo.majorVersion}.${applicationInfo.minorVersionMainPart}" + } + + @Override + String baseArtifactName(ApplicationInfoProperties applicationInfo, String buildNumber) { + "pycharmPC-$buildNumber" + } + + @Override + WindowsDistributionCustomizer createWindowsCustomizer(String projectHome) { + return new PyCharmWindowsDistributionCustomizer() { + { + buildZipWithBundledOracleJre = true + installerImagesPath = "$projectHome/community/python/build/resources" + fileAssociations = [".py"] + } + + @Override + String fullNameIncludingEdition(ApplicationInfoProperties applicationInfo) { + "PyCharm Community Edition" + } + + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + super.copyAdditionalFiles(context, targetDirectory) + context.ant.copy(file: "$context.paths.projectHome/python/help/pycharmhelp.jar", todir: "$targetDirectory/help", failonerror: false) + } + } + } + + @Override + LinuxDistributionCustomizer createLinuxCustomizer(String projectHome) { + return new LinuxDistributionCustomizer() { + { + iconPngPath = "$projectHome/community/python/resources/PyCharmCore128.png" + } + @Override + String rootDirectoryName(ApplicationInfoProperties applicationInfo, String buildNumber) { + "pycharm-community-${applicationInfo.isEAP ? buildNumber : applicationInfo.fullVersion}" + } + + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + context.ant.copy(file: "$context.paths.projectHome/python/help/pycharmhelp.jar", todir: "$targetDirectory/help", failonerror: false) + } + } + } + + @Override + MacDistributionCustomizer createMacCustomizer(String projectHome) { + return new PyCharmMacDistributionCustomizer() { + { + icnsPath = "$projectHome/community/python/resources/PyCharmCore.icns" + bundleIdentifier = "com.jetbrains.pycharm" + helpId = "PY" + dmgImagePath = "$projectHome/community/python/build/DMG_background.png" + } + + @Override + String rootDirectoryName(ApplicationInfoProperties applicationInfo, String buildNumber) { + String suffix = applicationInfo.isEAP ? " ${applicationInfo.majorVersion}.${applicationInfo.minorVersion} EAP" : "" + "PyCharm CE${suffix}.app" + } + } + } +} \ No newline at end of file diff --git a/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmMacDistributionCustomizer.groovy b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmMacDistributionCustomizer.groovy new file mode 100644 index 000000000000..57a8b3a0c1f9 --- /dev/null +++ b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmMacDistributionCustomizer.groovy @@ -0,0 +1,54 @@ +/* + * 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. + */ +/* + * 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 org.jetbrains.intellij.build.pycharm + +import org.jetbrains.intellij.build.ApplicationInfoProperties +import org.jetbrains.intellij.build.BuildContext +import org.jetbrains.intellij.build.MacDistributionCustomizer + +/** + * @author nik + */ +class PyCharmMacDistributionCustomizer extends MacDistributionCustomizer { + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + context.ant.copy(todir: "$targetDirectory/skeletons") { + fileset(dir: "$context.paths.projectHome/community/python/skeletons") { + include(name: "skeletons-mac*.zip") + } + } + } + + @Override + Map customIdeaProperties(ApplicationInfoProperties applicationInfo) { + ["ide.mac.useNativeClipboard": "false"] + } +} diff --git a/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmPropertiesBase.groovy b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmPropertiesBase.groovy new file mode 100644 index 000000000000..9d7c7c31957e --- /dev/null +++ b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmPropertiesBase.groovy @@ -0,0 +1,72 @@ +/* + * 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. + */ +/* + * 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 org.jetbrains.intellij.build.pycharm + +import org.jetbrains.intellij.build.ApplicationInfoProperties +import org.jetbrains.intellij.build.BuildContext +import org.jetbrains.intellij.build.BuildTasks +import org.jetbrains.intellij.build.MacDistributionCustomizer +import org.jetbrains.intellij.build.ProductProperties +import org.jetbrains.intellij.build.WindowsDistributionCustomizer + +/** + * @author nik + */ +abstract class PyCharmPropertiesBase extends ProductProperties { + PyCharmPropertiesBase(String home) { + baseFileName = "pycharm" + reassignAltClickToMultipleCarets = true + productLayout.mainJarName = "pycharm.jar" + productLayout.additionalPlatformJars.put("pycharm-pydev.jar", "python-pydev") + additionalDirectoriesWithLicenses = ["$home/python/license"] + } + + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + def tasks = BuildTasks.create(context) + tasks.zipSourcesOfModules(["python-pydev"], "$targetDirectory/lib/src/pycharm-pydev-src.zip") + tasks.zipSourcesOfModules(["python-openapi", "python-psi-api"], "$targetDirectory/lib/src/pycharm-openapi-src.zip") + + context.ant.copy(todir: "$targetDirectory/helpers") { + fileset(dir: "$context.paths.projectHome/community/python/helpers") + } + context.ant.copy(todir: "$targetDirectory/help") { + fileset(dir: "$context.paths.projectHome/python/help") { + include(name: "*.pdf") + } + } + } + + @Override + String environmentVariableBaseName(ApplicationInfoProperties applicationInfo) { + "PYCHARM" + } +} \ No newline at end of file diff --git a/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmWindowsDistributionCustomizer.groovy b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmWindowsDistributionCustomizer.groovy new file mode 100644 index 000000000000..8a229400c594 --- /dev/null +++ b/python/build/groovy/org/jetbrains/intellij/build/pycharm/PyCharmWindowsDistributionCustomizer.groovy @@ -0,0 +1,54 @@ +/* + * 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. + */ +/* + * 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 org.jetbrains.intellij.build.pycharm + +import org.jetbrains.intellij.build.ApplicationInfoProperties +import org.jetbrains.intellij.build.BuildContext +import org.jetbrains.intellij.build.WindowsDistributionCustomizer + +/** + * @author nik + */ +class PyCharmWindowsDistributionCustomizer extends WindowsDistributionCustomizer { + @Override + void copyAdditionalFiles(BuildContext context, String targetDirectory) { + context.ant.copy(todir: "$targetDirectory/skeletons") { + fileset(dir: "$context.paths.projectHome/community/python/skeletons") { + include(name: "skeletons-win*.zip") + } + } + } + + @Override + String rootDirectoryName(ApplicationInfoProperties applicationInfo, String buildNumber) { + "" + } +} diff --git a/python/build/paths.nsi b/python/build/paths.nsi deleted file mode 100644 index 3f8b0a427865..000000000000 --- a/python/build/paths.nsi +++ /dev/null @@ -1,6 +0,0 @@ -; Installer images -!define IMAGES_LOCATION "${COMMUNITY_DIR}\python\build\resources" -;!define LICENSE_FILE "${BASE_DIR}\python\license\PyCharm_Preview_License" -!define PRODUCT_PROPERTIES_FILE "${BASE_DIR}\out\pycharmCE\layout\bin\idea.properties" -!define PRODUCT_VM_OPTIONS_NAME pycharm*.exe.vmoptions -!define PRODUCT_VM_OPTIONS_FILE "${BASE_DIR}\out\pycharmCE\win\bin\${PRODUCT_VM_OPTIONS_NAME}" diff --git a/python/build/plugin-list.txt b/python/build/plugin-list.txt index 5da4136c5bea..85dc46bf17d1 100644 --- a/python/build/plugin-list.txt +++ b/python/build/plugin-list.txt @@ -1,21 +1,13 @@ -cvsIntegration -cvs-core cvs-plugin -javacvs-src -smartcvs-src svn4idea git4idea remote-servers-git hg4idea -tasks tasks-core -tasks-api -jira github terminal IntelliLang IntelliLang-xml -IntelliLang-js IntelliLang-python rest python-rest diff --git a/python/build/pycharm64_community_launcher.properties b/python/build/pycharm64_community_launcher.properties deleted file mode 100644 index 3453c65d52e6..000000000000 --- a/python/build/pycharm64_community_launcher.properties +++ /dev/null @@ -1,11 +0,0 @@ -IDS_JDK_ENV_VAR=PYCHARM_JDK_64 -IDS_JDK_ONLY=true -IDS_APP_TITLE=__IDE-NAME__ Launcher -IDS_VM_OPTIONS_PATH=%USERPROFILE%\\.__PRODUCT_PATHS_SELECTOR__ -IDS_VM_OPTION_ERRORFILE=-XX:ErrorFile=%USERPROFILE%\\java_error_in___product_uc___%p.log -IDS_VM_OPTION_HEAPDUMPPATH=-XX:HeapDumpPath=%USERPROFILE%\\java_error_in___product_uc__.hprof -IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER -IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES -IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME__64_VM_OPTIONS -IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__ -IDS_VM_OPTIONS=-Didea.platform.prefix=PyCharmCore -Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__ diff --git a/python/build/pycharm_community_build.gant b/python/build/pycharm_community_build.gant index 6213ba96fcb2..78b902fd3467 100644 --- a/python/build/pycharm_community_build.gant +++ b/python/build/pycharm_community_build.gant @@ -1,403 +1,12 @@ -import org.jetbrains.jps.LayoutInfo +import org.jetbrains.intellij.build.impl.BuildUtils +import org.jetbrains.jps.gant.JpsGantTool +import org.jetbrains.jps.idea.IdeaProjectLoader -import static org.jetbrains.jps.idea.IdeaProjectLoader.guessHome +includeTool << JpsGantTool -setProperty("home", guessHome(this as Script)) - -includeTargets << new File("${guessHome(this as Script)}/build/scripts/utils.gant") -includeTargets << new File("${guessHome(this)}/build/scripts/libLicenses.gant") - -requireProperty("buildNumber", requireProperty("build.number", snapshot)) - -setProperty("ch", home) -setProperty("pythonCommunityHome", "$home/python") - -// load ApplicationInfo.xml properties -ant.xmlproperty(file: "$pythonCommunityHome/python-community-ide-resources/resources/idea/PyCharmCoreApplicationInfo.xml", collapseAttributes: "true") - -setProperty("system_selector", "PyCharmCE${versionSelector()}") -setProperty("dryRun", false) -setProperty("jdk16", guessJdk()) - -//modules to compile -setProperty("pluginFilter", new File("$pythonCommunityHome/build/plugin-list.txt").readLines()) - -private List pycharmPlatformApiModules() { - return [platformApiModules, "dom-openapi"].flatten() -} - - -private List pycharmImplementationModules() { //modules to put into pycharm.jar - return [platformImplementationModules, "dom-impl", "python-community", "python-community-ide-resources", - "python-ide-community", "python-community-configure", "python-openapi", "python-psi-api", "platform-main"].flatten() -} - -private List modules() { - return [ - "python-pydev", "colorSchemes", pycharmPlatformApiModules(), pycharmImplementationModules(), pluginFilter - ].flatten() -} - -private List approvedJars() { - def normalizedHome = ch.replace('\\', '/') - def normalizedPythonHome = pythonCommunityHome.replace('\\', '/') - return ["$normalizedHome/lib/", "$normalizedPythonHome/lib/", "$normalizedHome/xml/relaxng/lib/"] -} - -class Paths { - final sandbox - final distAll - final distWin - final distMac - final distUnix - final artifacts - final ideaSystem - final ideaConfig - - def Paths(String home) { - sandbox = "$home/out/pycharmCE" - - distAll = "$sandbox/layout" - distWin = "$sandbox/win" - distMac = "$sandbox/mac" - distUnix = "$sandbox/unix" - artifacts = "$sandbox/artifacts" - - ideaSystem = "$sandbox/system" - ideaConfig = "$sandbox/config" - } -} - -setProperty("paths", new Paths(home)) -setProperty("buildName", "PC-$buildNumber") - -target('default': "Build artifacts") { - - loadProject() - - projectBuilder.stage("Cleaning up sandbox folder") - - projectBuilder.targetFolder = "${paths.sandbox}/classes" - projectBuilder.dryRun = dryRun - - if (!dryRun) { - forceDelete(paths.sandbox) - ant.mkdir(dir: paths.sandbox) - } - - ant.tstamp() { - format(property: "todayYear", pattern: "yyyy") - } - - ant.patternset(id: "resources.included") { - include(name: "**/*.properties") - include(name: "fileTemplates/**/*") - include(name: "inspectionDescriptions/**/*") - include(name: "intentionDescriptions/**/*") - include(name: "tips/**/*") - include(name: "search/**/*") - } - - ant.patternset(id: "resources.excluded") { - exclude(name: "**/*.properties") - exclude(name: "fileTemplates/**/*") - exclude(name: "fileTemplates") - exclude(name: "inspectionDescriptions/**/*") - exclude(name: "inspectionDescriptions") - exclude(name: "intentionDescriptions/**/*") - exclude(name: "intentionDescriptions") - exclude(name: "tips/**/*") - exclude(name: "tips") - } - - zipSources(home, paths.artifacts) - - def usedJars = buildModulesAndCollectUsedJars(modules(), approvedJars(), ["/ant/"]) - - layoutCommunity("${paths.sandbox}/classes/production", usedJars) - - /* - buildNSIS([paths.distAll, paths.distWin], - "$home/python/build/strings.nsi", "$home/python/build/paths.nsi", - "pycharm", false, true, system_selector) - */ - - /* - signMacZip("pycharm") - buildDmg("pycharm", "${home}/python/build/DMG_background.png") - */ -} - -public layoutCommunity(String classesPath, Set usedJars) { - setProperty("pluginFilter", new File("$pythonCommunityHome/build/plugin-list.txt").readLines()) - - if (usedJars == null) { - usedJars = collectUsedJars(modules(), approvedJars(), ["/ant/"], null) - } - - def appInfo = appInfoFile(classesPath) - def paths = new Paths(home) - buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], { - projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_ce"), false).each { - ant.pathelement(location: it) - } - }, "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true") - - if (!dryRun) { - wireBuildDate("PC-${buildNumber}", appInfo) - } - - Map args = [ - buildNumber: "PC-${buildNumber}", - system_selector: system_selector, - ide_jvm_args: "-Didea.platform.prefix=PyCharmCore -Didea.no.jre.check=true"] - - LayoutInfo layoutInfo = layoutFull(args, paths.distAll, usedJars) - generateLicensesTable("$paths.artifacts/third-party-libraries.txt", layoutInfo.usedModules); - - layoutWin(args, paths.distWin) - layoutUnix(args, paths.distUnix) - layoutMac(args, paths.distMac) - - ant.echo(message: "PC-${buildNumber}", file: "${paths.distAll}/build.txt") - - def launcher = "${paths.distWin}/bin/pycharm.exe" - def launcher64 = "${paths.distWin}/bin/pycharm64.exe" - List resourcePaths = ["$ch/community-resources/src", - "$ch/platform/icons/src", - "$pythonCommunityHome/python-community-ide-resources/resources", - "$pythonCommunityHome/resources"] - buildWinLauncher("$ch", "$ch/bin/WinLauncher/WinLauncher.exe", launcher, - appInfo, "$pythonCommunityHome/build/pycharm_community_launcher.properties", system_selector, resourcePaths) - buildWinLauncher("$ch", "$ch/bin/WinLauncher/WinLauncher64.exe", launcher64, - appInfo, "$pythonCommunityHome/build/pycharm64_community_launcher.properties", system_selector, resourcePaths) - - List pathsDist = new File("${home}/out/pycharm/jdk.win/jre").exists() ? [paths.distAll, paths.distWin, "${home}/out/pycharm/jdk.win"] : [paths.distAll, paths.distWin] - buildWinZip("${paths.artifacts}/pycharmPC-${buildNumber}.zip", pathsDist) - - //win oracle jdk - if (new File("${home}/out/pycharm/jdk.oracle.win/jre").exists()) { - buildWinZip("${paths.artifacts}/pycharmPC-${buildNumber}-oracle-win.zip", [paths.distAll, paths.distWin, "${home}/out/pycharm/jdk.oracle.win"]) - } - - String tarRoot = isEap() ? "pycharm-community-$buildNumber" : "pycharm-community-${p("component.version.major")}.${p("component.version.minor")}" - buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}-no-jdk.tar", [paths.distAll, paths.distUnix]) - requireProperty("jdk.linux", "false") - if (p("jdk.linux") != "false") { - buildTarGz(tarRoot, "$paths.artifacts/pycharmPC-${buildNumber}.tar", [paths.distAll, paths.distUnix, "${home}/out/pycharm/jdk.linux"], ["jre/jre/bin/*"]) - } - - String macAppRoot = isEap() ? "PyCharm CE ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm CE.app/Contents" - buildMacZip(macAppRoot, "${paths.artifacts}/pycharmPC-${buildNumber}.mac.zip", [paths.distAll], paths.distMac) -} - -private layoutPlugins(layouts) { - dir("plugins") { - layouts.layoutPlugin("rest") - layouts.layoutPlugin("python-rest") - layouts.layoutPlugin("ipnb") { - fileset(dir: "$pythonCommunityHome/ipnb/lib") - } - } - - layouts.layoutCommunityPlugins(ch) -} - -private String appInfoFile(String classesPath) { - return "$classesPath/python-community-ide-resources/idea/PyCharmCoreApplicationInfo.xml" -} - -private layoutFull(Map args, String target, Set usedJars) { - def openapiModules = pycharmPlatformApiModules() - def superLayouts = includeFile("$ch/build/scripts/layouts.gant") - - reassignAltClickToMultipleCarets("$ch") - - def result = layout(target) { - dir("lib") { - jar("util.jar") { - module("util") - module("util-rt") - } - - jar("openapi.jar") { - openapiModules.each { module it } - } - - jar("annotations.jar") { - module("annotations-common") - module("annotations") - } - jar("extensions.jar") { module("extensions") } - - jar(([name: "pycharm.jar", duplicate: "preserve"])) { - pycharmImplementationModules().each { - module(it) { - exclude(name: "**/tips/**") - } - } - } - - jar("pycharm-pydev.jar") { - module("python-pydev") - } - - jar("bootstrap.jar") { module("bootstrap") } - jar("resources.jar") { - module("platform-resources") - module("colorSchemes") - } - - jar("forms_rt.jar") { - module("forms_rt") - } - - //noinspection GroovyAssignabilityCheck - jar([name: "resources_en.jar", duplicate: "preserve"]) { - // custom resources should go first - module("python-community-ide-resources") { - ant.patternset { - include(name: "**/tips/**") - } - } - module("platform-resources-en") { - ant.patternset { - exclude(name: "tips/images/switcher.png") - exclude(name: "tips/images/navigateToFilePath.gif") - } - } - } - - jar("icons.jar") { module("icons") } - jar("boot.jar") { module("boot") } - - usedJars.each { - fileset(file: it) - } - - fileset(dir: "$ch/build/kotlinc/lib") { - include(name: "kotlin-runtime.jar") - include(name: "kotlin-reflect.jar") - } - - dir("libpty") { - fileset(dir: "$ch/lib/libpty") { - exclude(name: "*.txt") - } - } - - dir("ext") { - fileset(dir: "$ch/lib") { - include(name: "cglib*.jar") - } - } - - dir("src") { - fileset(dir: "$ch/lib/src") { - include(name: "trove4j_changes.txt") - include(name: "trove4j_src.jar") - } - - jar("pycharm-pydev-src.zip") { - fileset(dir: "$pythonCommunityHome/pydevSrc") - } - jar("pycharm-openapi-src.zip") { - fileset(dir: "$pythonCommunityHome/openapi/src") - fileset(dir: "$pythonCommunityHome/psi-api/src") - } - } - } - - dir("help") { - fileset(dir: "$home/python/help") { - include(name: "*.pdf") - } - } - - dir("helpers") { - fileset(dir: "$pythonCommunityHome/helpers") - } - - dir("license") { - fileset(dir: "$ch/license") - fileset(dir: "$ch") { - include(name: "LICENSE.txt") - include(name: "NOTICE.txt") - } - } - - layoutPlugins(superLayouts) - - dir("bin") { - fileset(dir: "$ch/bin") { - exclude(name: "appletviewer.policy") - include(name: "*.*") - } - } - } - patchPropertiesFile(target, args + [appendices: ["$home/build/conf/ideaJNC.properties"]]) - return result -} - -private layoutWin(Map args, String target) { - layout(target) { - dir("bin") { - fileset(dir: "$ch/bin/win") { - exclude(name: "breakgen*") - } - } - - dir("skeletons") { - fileset(dir: "$pythonCommunityHome/skeletons") { - include(name: "skeletons-win*.zip") - } - } - } - - winScripts(target, ch, "pycharm.bat", args) - winVMOptions(target, null, "pycharm.exe", "pycharm64.exe") - ant.copy(file: "$home/python/help/pycharmhelp.jar", todir: "$target/help", failonerror: false) -} - -private layoutUnix(Map args, String target) { - layout(target) { - dir("bin") { - fileset(dir: "$ch/bin/linux") { - exclude(name: "libbreakgen*") - } - } - } - - ant.copy(file: "$pythonCommunityHome/resources/PyCharmCore128.png", tofile: "$target/bin/pycharm.png") - - unixScripts(target, ch, "pycharm.sh", args) - unixVMOptions(target, "pycharm") - - ant.copy(file: "$home/python/help/pycharmhelp.jar", todir: "$target/help", failonerror: false) -} - -private layoutMac(Map _args, String target) { - layout(target) { - dir("bin") { - fileset(dir: "$home/bin") { - include(name: "*.jnilib") - } - } - - dir("skeletons") { - fileset(dir: "$pythonCommunityHome/skeletons") { - include(name: "skeletons-mac*.zip") - } - } - } - - Map args = new HashMap(_args) - args.icns = "$pythonCommunityHome/resources/PyCharmCore.icns" - args.bundleIdentifier = "com.jetbrains.pycharm" - args.platform_prefix = "PyCharmCore" - args.help_id = "PY" - args."idea.properties.path" = "${paths.distAll}/bin/idea.properties" - args."idea.properties" = ["idea.no.jre.check": true, "ide.mac.useNativeClipboard": "false"]; - args.executable = "pycharm" - layoutMacApp(target, ch, args) +target("default": "Default") { + String home = new File(IdeaProjectLoader.guessHome(this)).parentFile.absolutePath + BuildUtils.addToClassPath("$home/build/groovy", ant) + BuildUtils.addToClassPath("$home/community/python/build/groovy", ant) + Class.forName("org.jetbrains.intellij.build.pycharm.PyCharmCommunityBuilder").constructors[0].newInstance(home, binding).build() } diff --git a/python/build/pycharm_community_launcher.properties b/python/build/pycharm_community_launcher.properties deleted file mode 100644 index 83de195036d8..000000000000 --- a/python/build/pycharm_community_launcher.properties +++ /dev/null @@ -1,11 +0,0 @@ -IDS_JDK_ENV_VAR=PYCHARM_JDK -IDS_JDK_ONLY=false -IDS_APP_TITLE=__IDE-NAME__ Launcher -IDS_VM_OPTIONS_PATH=%USERPROFILE%\\.__PRODUCT_PATHS_SELECTOR__ -IDS_VM_OPTION_ERRORFILE=-XX:ErrorFile=%USERPROFILE%\\java_error_in___product_uc___%p.log -IDS_VM_OPTION_HEAPDUMPPATH=-XX:HeapDumpPath=%USERPROFILE%\\java_error_in___product_uc__.hprof -IDC_WINLAUNCHER=__IDE-NAME___LAUNCHER -IDS_PROPS_ENV_VAR=__IDE-NAME___PROPERTIES -IDS_VM_OPTIONS_ENV_VAR=__IDE-NAME___VM_OPTIONS -IDS_ERROR_LAUNCHING_APP=Error launching __IDE-NAME__ -IDS_VM_OPTIONS=-Didea.platform.prefix=PyCharmCore -Didea.paths.selector=__PRODUCT_PATHS_SELECTOR__ diff --git a/python/build/python-community-build.iml b/python/build/python-community-build.iml index 8665f6c2b0e4..1ecb47b47e83 100644 --- a/python/build/python-community-build.iml +++ b/python/build/python-community-build.iml @@ -2,10 +2,14 @@ - + + + + + \ No newline at end of file diff --git a/python/build/resources/PC_instCom.ico b/python/build/resources/install.ico similarity index 100% rename from python/build/resources/PC_instCom.ico rename to python/build/resources/install.ico diff --git a/python/build/resources/pycharm_inst.ico b/python/build/resources/pycharm_inst.ico deleted file mode 100644 index 6c75bcdbc441..000000000000 Binary files a/python/build/resources/pycharm_inst.ico and /dev/null differ diff --git a/python/build/resources/pycharm_uninst.ico b/python/build/resources/pycharm_uninst.ico deleted file mode 100644 index a5b9ad86ae94..000000000000 Binary files a/python/build/resources/pycharm_uninst.ico and /dev/null differ diff --git a/python/build/resources/PC_uninstCom.ico b/python/build/resources/uninstall.ico similarity index 100% rename from python/build/resources/PC_uninstCom.ico rename to python/build/resources/uninstall.ico diff --git a/python/build/strings.nsi b/python/build/strings.nsi deleted file mode 100644 index c3f32aa21191..000000000000 --- a/python/build/strings.nsi +++ /dev/null @@ -1,16 +0,0 @@ -!define MANUFACTURER "JetBrains" -!define MUI_PRODUCT "PyCharm Community Edition" -!define PRODUCT_FULL_NAME "JetBrains PyCharm Community Edition" -!define PRODUCT_EXE_FILE "pycharm.exe" -!define PRODUCT_EXE_FILE_64 "pycharm64.exe" -!define PRODUCT_ICON_FILE "PC_instCom.ico" -!define PRODUCT_UNINST_ICON_FILE "PC_uninstCom.ico" -!define PRODUCT_LOGO_FILE "logo.bmp" -!define PRODUCT_HEADER_FILE "headerlogo.bmp" -!define ASSOCIATION ".py" -!define UNINSTALL_WEB_PAGE "feedback_web_page" - -; if SHOULD_SET_DEFAULT_INSTDIR != 0 then default installation directory will be directory where highest-numbered RubyMine build has been installed -; set to 1 for release build -!define SHOULD_SET_DEFAULT_INSTDIR "0" - diff --git a/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy b/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy index 22d7ae924ab7..6720888d2c20 100644 --- a/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy +++ b/python/educational-python/build/groovy/org/jetbrains/intellij/build/pycharm/edu/PyCharmEduProperties.groovy @@ -1,55 +1,33 @@ package org.jetbrains.intellij.build.pycharm.edu -import org.jetbrains.intellij.build.ApplicationInfoProperties -import org.jetbrains.intellij.build.BuildContext -import org.jetbrains.intellij.build.BuildTasks -import org.jetbrains.intellij.build.CommunityLibraryLicenses -import org.jetbrains.intellij.build.CommunityRepositoryModules -import org.jetbrains.intellij.build.LinuxDistributionCustomizer -import org.jetbrains.intellij.build.MacDistributionCustomizer -import org.jetbrains.intellij.build.ProductProperties -import org.jetbrains.intellij.build.WindowsDistributionCustomizer +import org.jetbrains.intellij.build.* +import org.jetbrains.intellij.build.pycharm.PyCharmMacDistributionCustomizer +import org.jetbrains.intellij.build.pycharm.PyCharmPropertiesBase +import org.jetbrains.intellij.build.pycharm.PyCharmWindowsDistributionCustomizer /** * @author nik */ -class PyCharmEduProperties extends ProductProperties { +class PyCharmEduProperties extends PyCharmPropertiesBase { PyCharmEduProperties(String home) { - baseFileName = "pycharm" + super(home) productCode = "PE" platformPrefix = "PyCharmEdu" applicationInfoModule = "educational-python" brandingResourcePaths = ["$home/community/python/educational-python/resources"] - additionalIDEPropertiesFilePaths = ["$home/build/conf/ideaJNC.properties"] - reassignAltClickToMultipleCarets = true - productLayout.mainJarName = "pycharm.jar" productLayout.mainModule = "main_pycharm_edu" productLayout.platformApiModules = CommunityRepositoryModules.PLATFORM_API_MODULES + ["dom-openapi"] productLayout.platformImplementationModules = CommunityRepositoryModules.PLATFORM_IMPLEMENTATION_MODULES + [ "dom-impl", "python-community", "python-community-ide-resources", "python-ide-community", "python-community-configure", "educational-python", "python-openapi", "python-psi-api", "platform-main" ] - productLayout.additionalPlatformJars.put("pycharm-pydev.jar", "python-pydev") productLayout.bundledPluginModules = new File("$home/community/python/educational-python/build/plugin-list.txt").readLines() - - allLibraryLicenses = CommunityLibraryLicenses.LICENSES_LIST } @Override void copyAdditionalFiles(BuildContext context, String targetDirectory) { - def tasks = BuildTasks.create(context) - tasks.zipSourcesOfModules(["python-pydev"], "$targetDirectory/lib/src/pycharm-pydev-src.zip") - tasks.zipSourcesOfModules(["python-openapi", "python-psi-api"], "$targetDirectory/lib/src/pycharm-openapi-src.zip") - - context.ant.copy(todir: "$targetDirectory/helpers") { - fileset(dir: "$context.paths.projectHome/community/python/helpers") - } - context.ant.copy(todir: "$targetDirectory/help") { - fileset(dir: "$context.paths.projectHome/python/help") { - include(name: "*.pdf") - } - } + super.copyAdditionalFiles(context, targetDirectory) context.ant.copy(todir: "$targetDirectory/license") { fileset(file: "$context.paths.communityHome/LICENSE.txt") fileset(file: "$context.paths.communityHome/NOTICE.txt") @@ -66,14 +44,9 @@ class PyCharmEduProperties extends ProductProperties { "pycharmEDU-$buildNumber" } - @Override - String environmentVariableBaseName(ApplicationInfoProperties applicationInfo) { - "PYCHARM" - } - @Override WindowsDistributionCustomizer createWindowsCustomizer(String projectHome) { - return new WindowsDistributionCustomizer() { + return new PyCharmWindowsDistributionCustomizer() { { buildZipWithBundledOracleJre = true installerImagesPath = "$projectHome/community/python/educational-python/build/resources" @@ -84,17 +57,13 @@ class PyCharmEduProperties extends ProductProperties { } @Override - String rootDirectoryName(ApplicationInfoProperties applicationInfo, String buildNumber) { - "" + String fullNameIncludingEdition(ApplicationInfoProperties applicationInfo) { + "PyCharm Edu" } @Override void copyAdditionalFiles(BuildContext context, String targetDirectory) { - context.ant.copy(todir: "$targetDirectory/skeletons") { - fileset(dir: "$context.paths.projectHome/community/python/skeletons") { - include(name: "skeletons-win*.zip") - } - } + super.copyAdditionalFiles(context, targetDirectory) context.ant.copy(file: "$context.paths.projectHome/python/help/pycharm-eduhelp.jar", todir: "$targetDirectory/help", failonerror: false) } } @@ -121,27 +90,13 @@ class PyCharmEduProperties extends ProductProperties { @Override MacDistributionCustomizer createMacCustomizer(String projectHome) { - return new MacDistributionCustomizer() { + return new PyCharmMacDistributionCustomizer() { { icnsPath = "$projectHome/community/python/educational-python/resources/PyCharmEdu.icns" bundleIdentifier = "com.jetbrains.pycharm" helpId = "PE" dmgImagePath = "$projectHome/community/python/educational-python/build/DMG_background.png" } - - @Override - void copyAdditionalFiles(BuildContext context, String targetDirectory) { - context.ant.copy(todir: "$targetDirectory/skeletons") { - fileset(dir: "$context.paths.projectHome/community/python/skeletons") { - include(name: "skeletons-mac*.zip") - } - } - } - - @Override - Map customIdeaProperties(ApplicationInfoProperties applicationInfo) { - ["ide.mac.useNativeClipboard": "false"] - } } } } \ No newline at end of file diff --git a/python/educational-python/build/pycharm_edu_build.gant b/python/educational-python/build/pycharm_edu_build.gant index e18e98c60dfe..09c69eaf4e30 100644 --- a/python/educational-python/build/pycharm_edu_build.gant +++ b/python/educational-python/build/pycharm_edu_build.gant @@ -7,6 +7,7 @@ includeTool << JpsGantTool target("default": "Default") { String home = new File(IdeaProjectLoader.guessHome(this)).parentFile.absolutePath BuildUtils.addToClassPath("$home/build/groovy", ant) + BuildUtils.addToClassPath("$home/community/python/build/groovy", ant) BuildUtils.addToClassPath("$home/community/python/educational-python/build/groovy", ant) Class.forName("org.jetbrains.intellij.build.pycharm.edu.PyCharmEduBuilder").constructors[0].newInstance(home, binding).build() } diff --git a/python/educational-python/build/python-edu-build.iml b/python/educational-python/build/python-edu-build.iml index 1ecb47b47e83..275262d81506 100644 --- a/python/educational-python/build/python-edu-build.iml +++ b/python/educational-python/build/python-edu-build.iml @@ -11,5 +11,6 @@ + \ No newline at end of file diff --git a/python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py b/python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py new file mode 100644 index 000000000000..b846fb4e5586 --- /dev/null +++ b/python/helpers/pydev/_pydev_bundle/_pydev_calltip_util.py @@ -0,0 +1,158 @@ +''' +License: Apache 2.0 +Author: Yuli Fitterman +''' +# noinspection PyBroadException +import types + +from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_PY3K + +try: + import inspect +except: + try: + from _pydev_imps import _pydev_inspect as inspect + except: + import traceback; + + traceback.print_exc() # Ok, no inspect available (search will not work)from _pydevd_bundle.pydevd_constants import IS_JYTHON, IS_PY3K + +from _pydev_bundle._pydev_imports_tipper import signature_from_docstring + + +def is_bound_method(obj): + if isinstance(obj, types.MethodType): + return getattr(obj, '__self__', getattr(obj, 'im_self', None)) is not None + else: + return False + + +def get_class_name(instance): + return getattr(getattr(instance, "__class__", None), "__name__", None) + + +def get_bound_class_name(obj): + my_self = getattr(obj, '__self__', getattr(obj, 'im_self', None)) + if my_self is None: + return None + return get_class_name(my_self) + + +def get_description(obj): + try: + ob_call = obj.__call__ + except: + ob_call = None + + if isinstance(obj, type) or type(obj).__name__ == 'classobj': + fob = getattr(obj, '__init__', lambda: None) + if not isinstance(fob, (types.FunctionType, types.MethodType)): + fob = obj + elif is_bound_method(ob_call): + fob = ob_call + else: + fob = obj + + argspec = "" + fn_name = None + fn_class = None + if isinstance(fob, (types.FunctionType, types.MethodType)): + spec_info = inspect.getfullargspec(fob) if IS_PY3K else inspect.getargspec(fob) + argspec = inspect.formatargspec(*spec_info) + fn_name = getattr(fob, '__name__', None) + if isinstance(obj, type) or type(obj).__name__ == 'classobj': + fn_name = "__init__" + fn_class = getattr(obj, "__name__", "UnknownClass") + elif is_bound_method(obj) or is_bound_method(ob_call): + fn_class = get_bound_class_name(obj) or "UnknownClass" + + else: + fn_name = getattr(fob, '__name__', None) + fn_self = getattr(fob, '__self__', None) + if fn_self is not None and not isinstance(fn_self, types.ModuleType): + fn_class = get_class_name(fn_self) + + doc_string = get_docstring(ob_call) if is_bound_method(ob_call) else get_docstring(obj) + return create_method_stub(fn_name, fn_class, argspec, doc_string) + + +def create_method_stub(fn_name, fn_class, argspec, doc_string): + if fn_name and argspec: + doc_string = "" if doc_string is None else doc_string + fn_stub = create_function_stub(fn_name, argspec, doc_string, indent=1 if fn_class else 0) + if fn_class: + expr = fn_class if fn_name == '__init__' else fn_class + '().' + fn_name + return create_class_stub(fn_class, fn_stub) + "\n" + expr + else: + expr = fn_name + return fn_stub + "\n" + expr + elif doc_string: + if fn_name: + restored_signature, _ = signature_from_docstring(doc_string, fn_name) + if restored_signature: + return create_method_stub(fn_name, fn_class, restored_signature, doc_string) + return create_function_stub('unknown', '(*args, **kwargs)', doc_string) + '\nunknown' + + else: + return '' + + +def get_docstring(obj): + if obj is not None: + try: + if IS_JYTHON: + # Jython + doc = obj.__doc__ + if doc is not None: + return doc + + from _pydev_bundle import _pydev_jy_imports_tipper + + is_method, infos = _pydev_jy_imports_tipper.ismethod(obj) + ret = '' + if is_method: + for info in infos: + ret += info.get_as_doc() + return ret + + else: + + doc = inspect.getdoc(obj) + if doc is not None: + return doc + except: + pass + else: + return '' + try: + # if no attempt succeeded, try to return repr()... + return repr(obj) + except: + try: + # otherwise the class + return str(obj.__class__) + except: + # if all fails, go to an empty string + return '' + + +def create_class_stub(class_name, contents): + return "class %s(object):\n%s" % (class_name, contents) + + +def create_function_stub(fn_name, fn_argspec, fn_docstring, indent=0): + def shift_right(string, prefix): + return ''.join(prefix + line for line in string.splitlines(True)) + + fn_docstring = shift_right(inspect.cleandoc(fn_docstring), " " * (indent + 1)) + ret = ''' +def %s%s: + """%s""" + pass +''' % (fn_name, fn_argspec, fn_docstring) + ret = ret[1:] # remove first /n + ret = ret.replace('\t', " ") + if indent: + prefix = " " * indent + ret = shift_right(ret, prefix) + return ret diff --git a/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py b/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py index c05c04e521b0..7ee92090f0e8 100644 --- a/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py +++ b/python/helpers/pydev/_pydev_bundle/_pydev_imports_tipper.py @@ -1,5 +1,5 @@ -import os.path import inspect +import os.path import sys from _pydev_bundle._pydev_tipper_common import do_find @@ -222,96 +222,7 @@ def generate_imports_tip_for_module(obj_to_complete, dirComps=None, getattr=geta args = '(%s)' % (r) except TypeError: #ok, let's see if we can get the arguments from the doc - args = '()' - try: - found = False - if len(doc) > 0: - if IS_IPY: - #Handle case where we have the situation below - #sort(self, object cmp, object key) - #sort(self, object cmp, object key, bool reverse) - #sort(self) - #sort(self, object cmp) - - #Or: sort(self: list, cmp: object, key: object) - #sort(self: list, cmp: object, key: object, reverse: bool) - #sort(self: list) - #sort(self: list, cmp: object) - if hasattr(obj, '__name__'): - name = obj.__name__+'(' - - - #Fix issue where it was appearing sort(aa)sort(bb)sort(cc) in the same line. - lines = doc.splitlines() - if len(lines) == 1: - c = doc.count(name) - if c > 1: - doc = ('\n'+name).join(doc.split(name)) - - - major = '' - for line in doc.splitlines(): - if line.startswith(name) and line.endswith(')'): - if len(line) > len(major): - major = line - if major: - args = major[major.index('('):] - found = True - - - if not found: - i = doc.find('->') - if i < 0: - i = doc.find('--') - if i < 0: - i = doc.find('\n') - if i < 0: - i = doc.find('\r') - - - if i > 0: - s = doc[0:i] - s = s.strip() - - #let's see if we have a docstring in the first line - if s[-1] == ')': - start = s.find('(') - if start >= 0: - end = s.find('[') - if end <= 0: - end = s.find(')') - if end <= 0: - end = len(s) - - args = s[start:end] - if not args[-1] == ')': - args = args + ')' - - - #now, get rid of unwanted chars - l = len(args) - 1 - r = [] - for i in xrange(len(args)): - if i == 0 or i == l: - r.append(args[i]) - else: - r.append(check_char(args[i])) - - args = ''.join(r) - - if IS_IPY: - if args.startswith('(self:'): - i = args.find(',') - if i >= 0: - args = '(self'+args[i:] - else: - args = '(self)' - i = args.find(')') - if i > 0: - args = args[:i+1] - - except: - pass + args, doc = signature_from_docstring(doc, getattr(obj, '__name__', None)) retType = TYPE_FUNCTION @@ -350,5 +261,90 @@ def generate_imports_tip_for_module(obj_to_complete, dirComps=None, getattr=geta return ret +def signature_from_docstring(doc, obj_name): + args = '()' + try: + found = False + if len(doc) > 0: + if IS_IPY: + # Handle case where we have the situation below + # sort(self, object cmp, object key) + # sort(self, object cmp, object key, bool reverse) + # sort(self) + # sort(self, object cmp) + # Or: sort(self: list, cmp: object, key: object) + # sort(self: list, cmp: object, key: object, reverse: bool) + # sort(self: list) + # sort(self: list, cmp: object) + if obj_name: + name = obj_name + '(' + # Fix issue where it was appearing sort(aa)sort(bb)sort(cc) in the same line. + lines = doc.splitlines() + if len(lines) == 1: + c = doc.count(name) + if c > 1: + doc = ('\n' + name).join(doc.split(name)) + + major = '' + for line in doc.splitlines(): + if line.startswith(name) and line.endswith(')'): + if len(line) > len(major): + major = line + if major: + args = major[major.index('('):] + found = True + + if not found: + i = doc.find('->') + if i < 0: + i = doc.find('--') + if i < 0: + i = doc.find('\n') + if i < 0: + i = doc.find('\r') + + if i > 0: + s = doc[0:i] + s = s.strip() + + # let's see if we have a docstring in the first line + if s[-1] == ')': + start = s.find('(') + if start >= 0: + end = s.find('[') + if end <= 0: + end = s.find(')') + if end <= 0: + end = len(s) + + args = s[start:end] + if not args[-1] == ')': + args = args + ')' + + # now, get rid of unwanted chars + l = len(args) - 1 + r = [] + for i in xrange(len(args)): + if i == 0 or i == l: + r.append(args[i]) + else: + r.append(check_char(args[i])) + + args = ''.join(r) + + if IS_IPY: + if args.startswith('(self:'): + i = args.find(',') + if i >= 0: + args = '(self' + args[i:] + else: + args = '(self)' + i = args.find(')') + if i > 0: + args = args[:i + 1] + + except: + pass + return args, doc diff --git a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py index e9d0a6998a87..9d612005e9f3 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_console_utils.py @@ -1,17 +1,15 @@ -import os - from _pydev_bundle.pydev_imports import xmlrpclib, _queue, Exec -import sys -from _pydevd_bundle.pydevd_constants import IS_JYTHON +from _pydev_bundle._pydev_calltip_util import get_description from _pydev_imps._pydev_saved_modules import thread -from _pydevd_bundle import pydevd_xml from _pydevd_bundle import pydevd_vars +from _pydevd_bundle import pydevd_xml +from _pydevd_bundle.pydevd_constants import IS_JYTHON from _pydevd_bundle.pydevd_utils import * # @UnusedWildImport -import traceback -#======================================================================================================================= + +# ======================================================================================================================= # Null -#======================================================================================================================= +# ======================================================================================================================= class Null: """ Gotten from: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/68205 @@ -54,39 +52,39 @@ class Null: return 0 -#======================================================================================================================= +# ======================================================================================================================= # BaseStdIn -#======================================================================================================================= +# ======================================================================================================================= class BaseStdIn: def __init__(self, original_stdin=sys.stdin, *args, **kwargs): try: self.encoding = sys.stdin.encoding except: - #Not sure if it's available in all Python versions... + # Not sure if it's available in all Python versions... pass self.original_stdin = original_stdin def readline(self, *args, **kwargs): - #sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything - #This could happen if the user had done input('enter number).<-- upon entering this, that message would appear, - #which is not something we want. + # sys.stderr.write('Cannot readline out of the console evaluation\n') -- don't show anything + # This could happen if the user had done input('enter number).<-- upon entering this, that message would appear, + # which is not something we want. return '\n' def isatty(self): - return False #not really a file + return False # not really a file def write(self, *args, **kwargs): - pass #not available StdIn (but it can be expected to be in the stream interface) + pass # not available StdIn (but it can be expected to be in the stream interface) def flush(self, *args, **kwargs): - pass #not available StdIn (but it can be expected to be in the stream interface) + pass # not available StdIn (but it can be expected to be in the stream interface) def read(self, *args, **kwargs): - #in the interactive interpreter, a read and a readline are the same. + # in the interactive interpreter, a read and a readline are the same. return self.readline() def close(self, *args, **kwargs): - pass #expected in StdIn + pass # expected in StdIn def __getattr__(self, item): # it's called if the attribute wasn't found @@ -95,9 +93,9 @@ class BaseStdIn: raise AttributeError("%s has no attribute %s" % (self.original_stdin, item)) -#======================================================================================================================= +# ======================================================================================================================= # StdIn -#======================================================================================================================= +# ======================================================================================================================= class StdIn(BaseStdIn): ''' Object to be added to stdin (to emulate it as non-blocking while the next line arrives) @@ -110,16 +108,18 @@ class StdIn(BaseStdIn): self.host = host def readline(self, *args, **kwargs): - #Ok, callback into the client to get the new input + # Ok, callback into the client to get the new input try: server = xmlrpclib.Server('http://%s:%s' % (self.host, self.client_port)) requested_input = server.RequestInput() if not requested_input: - return '\n' #Yes, a readline must return something (otherwise we can get an EOFError on the input() call). + return '\n' # Yes, a readline must return something (otherwise we can get an EOFError on the input() call). return requested_input except: return '\n' + def close(self, *args, **kwargs): + pass # expected in StdIn #======================================================================================================================= # DebugConsoleStdIn @@ -155,9 +155,10 @@ class CodeFragment: if not code_fragment.is_single_line: self.is_single_line = False -#======================================================================================================================= + +# ======================================================================================================================= # BaseInterpreterInterface -#======================================================================================================================= +# ======================================================================================================================= class BaseInterpreterInterface: def __init__(self, mainThread): self.mainThread = mainThread @@ -206,15 +207,15 @@ class BaseInterpreterInterface: try: help = None if 'pydoc' in sys.modules: - pydoc = sys.modules['pydoc'] #Don't import it if it still is not there. + pydoc = sys.modules['pydoc'] # Don't import it if it still is not there. if hasattr(pydoc, 'help'): - #You never know how will the API be changed, so, let's code defensively here + # You never know how will the API be changed, so, let's code defensively here help = pydoc.help if not hasattr(help, 'input'): help = None except: - #Just ignore any error here + # Just ignore any error here pass more = False @@ -222,7 +223,7 @@ class BaseInterpreterInterface: sys.stdin = self.create_std_in(debugger, original_in) try: if help is not None: - #This will enable the help() function to work. + # This will enable the help() function to work. try: try: help.input = sys.stdin @@ -268,7 +269,6 @@ class BaseInterpreterInterface: return more - def do_add_exec(self, codeFragment): ''' Subclasses should override. @@ -277,7 +277,6 @@ class BaseInterpreterInterface: ''' raise NotImplementedError() - def get_namespace(self): ''' Subclasses should override. @@ -286,66 +285,48 @@ class BaseInterpreterInterface: ''' raise NotImplementedError() + def __resolve_reference__(self, text): + """ - def getDescription(self, text): - try: - obj = None - if '.' not in text: + :type text: str + """ + obj = None + if '.' not in text: + try: + obj = self.get_namespace()[text] + except KeyError: + pass + + if obj is None: try: - obj = self.get_namespace()[text] - except KeyError: - return '' - - else: - try: - splitted = text.split('.') - obj = self.get_namespace()[splitted[0]] - for t in splitted[1:]: - obj = getattr(obj, t) - except: - return '' - - if obj is not None: - try: - if sys.platform.startswith("java"): - #Jython - doc = obj.__doc__ - if doc is not None: - return doc - - from _pydev_bundle import _pydev_jy_imports_tipper - - is_method, infos = _pydev_jy_imports_tipper.ismethod(obj) - ret = '' - if is_method: - for info in infos: - ret += info.get_as_doc() - return ret - - else: - #Python and Iron Python - import inspect #@UnresolvedImport - - doc = inspect.getdoc(obj) - if doc is not None: - return doc + obj = self.get_namespace()['__builtins__'][text] except: pass - try: - #if no attempt succeeded, try to return repr()... - return repr(obj) - except: + if obj is None: try: - #otherwise the class - return str(obj.__class__) + obj = getattr(self.get_namespace()['__builtins__'], text, None) except: - #if all fails, go to an empty string - return '' - except: - traceback.print_exc() - return '' + pass + else: + try: + last_dot = text.rindex('.') + parent_context = text[0:last_dot] + res = pydevd_vars.eval_in_context(parent_context, self.get_namespace(), self.get_namespace()) + obj = getattr(res, text[last_dot + 1:]) + except: + pass + return obj + + def getDescription(self, text): + try: + obj = self.__resolve_reference__(text) + if obj is None: + return '' + return get_description(obj) + except: + return '' def do_exec_code(self, code, is_single_line): try: @@ -364,7 +345,6 @@ class BaseInterpreterInterface: def execLine(self, line): return self.do_exec_code(line, True) - def execMultipleLines(self, lines): if IS_JYTHON: for line in lines.split('\n'): @@ -372,9 +352,8 @@ class BaseInterpreterInterface: else: return self.do_exec_code(lines, False) - def interrupt(self): - self.buffer = None # Also clear the buffer when it's interrupted. + self.buffer = None # Also clear the buffer when it's interrupted. try: if self.interruptable: called = False @@ -412,10 +391,10 @@ class BaseInterpreterInterface: pass if not called: - if hasattr(thread, 'interrupt_main'): #Jython doesn't have it + if hasattr(thread, 'interrupt_main'): # Jython doesn't have it thread.interrupt_main() else: - self.mainThread._thread.interrupt() #Jython + self.mainThread._thread.interrupt() # Jython return True except: traceback.print_exc() @@ -495,11 +474,11 @@ class BaseInterpreterInterface: Used to show console with variables connection. Always return a frame where the locals map to our internal namespace. ''' - VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java - VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java + VIRTUAL_FRAME_ID = "1" # matches PyStackFrameConsole.java + VIRTUAL_CONSOLE_ID = "console_main" # matches PyThreadConsole.java if thread_id == VIRTUAL_CONSOLE_ID and frame_id == VIRTUAL_FRAME_ID: f = FakeFrame() - f.f_globals = {} #As globals=locals here, let's simply let it empty (and save a bit of network traffic). + f.f_globals = {} # As globals=locals here, let's simply let it empty (and save a bit of network traffic). f.f_locals = self.get_namespace() return f else: @@ -527,7 +506,7 @@ class BaseInterpreterInterface: except: # This happens on Jython embedded in host eclipse traceback.print_exc() - sys.stderr.write('pydevd is not available, cannot connect\n',) + sys.stderr.write('pydevd is not available, cannot connect\n', ) from _pydev_bundle import pydev_localhost threading.currentThread().__pydevd_id__ = "console_main" @@ -589,9 +568,10 @@ class BaseInterpreterInterface: # it to run in the main thread. self.exec_queue.put(do_enable_gui) -#======================================================================================================================= + +# ======================================================================================================================= # FakeFrame -#======================================================================================================================= +# ======================================================================================================================= class FakeFrame: ''' Used to show console with variables connection. diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py index 70566d248c16..1c3f2a3ee69a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py @@ -139,6 +139,7 @@ CMD_STEP_INTO_MY_CODE = 144 CMD_GET_CONCURRENCY_EVENT = 145 CMD_SHOW_RETURN_VALUES = 146 CMD_INPUT_REQUESTED = 147 +CMD_GET_DESCRIPTION = 148 CMD_VERSION = 501 CMD_RETURN = 502 @@ -193,6 +194,7 @@ ID_TO_MEANING = { '145': 'CMD_GET_CONCURRENCY_EVENT', '146': 'CMD_SHOW_RETURN_VALUES', '147': 'CMD_INPUT_REQUESTED', + '148': 'CMD_GET_DESCRIPTION', '501': 'CMD_VERSION', '502': 'CMD_RETURN', @@ -700,6 +702,12 @@ class NetCommandFactory: except Exception: return self.make_error_message(seq, get_exception_traceback_str()) + def make_get_description_message(self, seq, payload): + try: + return NetCommand(CMD_GET_DESCRIPTION, seq, payload) + except Exception: + return self.make_error_message(seq, get_exception_traceback_str()) + def make_get_frame_message(self, seq, payload): try: return NetCommand(CMD_GET_FRAME, seq, payload) @@ -1135,6 +1143,36 @@ class InternalGetCompletions(InternalThreadCommand): cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error evaluating expression " + exc) dbg.writer.add_command(cmd) + +# ======================================================================================================================= +# InternalGetDescription +# ======================================================================================================================= +class InternalGetDescription(InternalThreadCommand): + """ Fetch the variable description stub from the debug console + """ + + def __init__(self, seq, thread_id, frame_id, expression): + self.sequence = seq + self.thread_id = thread_id + self.frame_id = frame_id + self.expression = expression + + def do_it(self, dbg): + """ Get completions and write back to the client + """ + try: + frame = pydevd_vars.find_frame(self.thread_id, self.frame_id) + description = pydevd_console.get_description(frame, self.thread_id, self.frame_id, self.expression) + description = pydevd_vars.make_valid_xml_value(quote(description, '/>_= \t')) + description_xml = '' % description + cmd = dbg.cmd_factory.make_get_description_message(self.sequence, description_xml) + dbg.writer.add_command(cmd) + except: + exc = get_exception_traceback_str() + cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error in fetching description" + exc) + dbg.writer.add_command(cmd) + + #======================================================================================================================= # InternalGetBreakpointException #======================================================================================================================= diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_console.py b/python/helpers/pydev/_pydevd_bundle/pydevd_console.py index d35cdc9df39d..b48daae2703a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_console.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_console.py @@ -1,17 +1,17 @@ '''An helper file for the pydev debugger (REPL) console ''' -from code import InteractiveConsole import sys import traceback +from code import InteractiveConsole from _pydev_bundle import _pydev_completer -from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str -from _pydevd_bundle.pydevd_vars import make_valid_xml_value -from _pydev_bundle.pydev_imports import Exec -from _pydevd_bundle.pydevd_io import IOBuf from _pydev_bundle.pydev_console_utils import BaseInterpreterInterface, BaseStdIn +from _pydev_bundle.pydev_imports import Exec from _pydev_bundle.pydev_override import overrides from _pydevd_bundle import pydevd_save_locals +from _pydevd_bundle.pydevd_io import IOBuf +from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str +from _pydevd_bundle.pydevd_vars import make_valid_xml_value CONSOLE_OUTPUT = "output" CONSOLE_ERROR = "error" @@ -160,6 +160,12 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface): except: self.showtraceback() + def get_namespace(self): + dbg_namespace = {} + dbg_namespace.update(self.frame.f_globals) + dbg_namespace.update(self.frame.f_locals) # locals later because it has precedence over the actual globals + return dbg_namespace + #======================================================================================================================= # InteractiveConsoleCache @@ -175,6 +181,7 @@ class InteractiveConsoleCache: def get_interactive_console(thread_id, frame_id, frame, console_message): """returns the global interactive console. interactive console should have been initialized by this time + :rtype: DebugConsole """ if InteractiveConsoleCache.thread_id == thread_id and InteractiveConsoleCache.frame_id == frame_id: return InteractiveConsoleCache.interactive_console_instance @@ -218,6 +225,16 @@ def execute_console_command(frame, thread_id, frame_id, line, buffer_output=True return console_message +def get_description(frame, thread_id, frame_id, expression): + console_message = ConsoleMessage() + interpreter = get_interactive_console(thread_id, frame_id, frame, console_message) + try: + interpreter.frame = frame + return interpreter.getDescription(expression) + finally: + interpreter.frame = None + + def get_completions(frame, act_tok): """ fetch all completions, create xml for the same return the completions xml diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py b/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py index 2b7783cbe8ca..dec84ed73369 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py @@ -16,11 +16,10 @@ from _pydevd_bundle.pydevd_comm import CMD_RUN, CMD_VERSION, CMD_LIST_THREADS, C CMD_SET_PY_EXCEPTION, CMD_GET_FILE_CONTENTS, CMD_SET_PROPERTY_TRACE, CMD_ADD_EXCEPTION_BREAK, \ CMD_REMOVE_EXCEPTION_BREAK, CMD_LOAD_SOURCE, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \ CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression, InternalConsoleGetCompletions, \ - CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE,\ - CMD_SHOW_RETURN_VALUES, ID_TO_MEANING + CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE, \ + CMD_SHOW_RETURN_VALUES, ID_TO_MEANING, CMD_GET_DESCRIPTION, InternalGetDescription from _pydevd_bundle.pydevd_constants import get_thread_id, IS_PY3K, DebugInfoHolder, dict_contains, dict_keys, dict_pop, \ STATE_RUN -import pydevd_file_utils def process_net_command(py_db, cmd_id, seq, text): @@ -229,6 +228,14 @@ def process_net_command(py_db, cmd_id, seq, text): except: traceback.print_exc() + elif cmd_id == CMD_GET_DESCRIPTION: + try: + + thread_id, frame_id, expression = text.split('\t', 2) + int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression) + py_db.post_internal_command(int_cmd, thread_id) + except: + traceback.print_exc() elif cmd_id == CMD_GET_FRAME: thread_id, frame_id, scope = text.split('\t', 2) diff --git a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java index 860cef734a1d..3cd3c0809bdd 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/resolve/PyResolveContext.java @@ -24,17 +24,22 @@ import org.jetbrains.annotations.NotNull; public class PyResolveContext { private final boolean myAllowImplicits; private final boolean myAllowProperties; + private final boolean myAllowRemote; private final TypeEvalContext myTypeEvalContext; + private PyResolveContext(boolean allowImplicits, boolean allowProperties) { myAllowImplicits = allowImplicits; myAllowProperties = allowProperties; myTypeEvalContext = null; + myAllowRemote = false; } - private PyResolveContext(boolean allowImplicits, boolean allowProperties, TypeEvalContext typeEvalContext) { + + private PyResolveContext(boolean allowImplicits, boolean allowProperties, boolean allowRemote, TypeEvalContext typeEvalContext) { myAllowImplicits = allowImplicits; myAllowProperties = allowProperties; + myAllowRemote = allowRemote; myTypeEvalContext = typeEvalContext; } @@ -46,6 +51,10 @@ public class PyResolveContext { return myAllowProperties; } + public boolean allowRemote() { + return myAllowRemote; + } + private static final PyResolveContext ourDefaultContext = new PyResolveContext(true, true); private static final PyResolveContext ourNoImplicitsContext = new PyResolveContext(false, true); private static final PyResolveContext ourNoPropertiesContext = new PyResolveContext(false, false); @@ -63,11 +72,15 @@ public class PyResolveContext { } public PyResolveContext withTypeEvalContext(@NotNull TypeEvalContext context) { - return new PyResolveContext(myAllowImplicits, myAllowProperties, context); + return new PyResolveContext(myAllowImplicits, myAllowProperties, myAllowRemote, context); } public PyResolveContext withoutImplicits() { - return new PyResolveContext(false, myAllowProperties, myTypeEvalContext); + return new PyResolveContext(false, myAllowProperties, myAllowRemote, myTypeEvalContext); + } + + public PyResolveContext withRemote() { + return new PyResolveContext(myAllowImplicits, myAllowProperties, true, myTypeEvalContext); } public TypeEvalContext getTypeEvalContext() { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index 941e39343ba4..9090238a6a45 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -30,7 +30,9 @@ public abstract class AbstractCommand { public static final int LOAD_SOURCE = 124; public static final int SMART_STEP_INTO = 128; public static final int EXIT = 129; - + public static final int GET_DESCRIPTION = 148; + + public static final int CALL_SIGNATURE_TRACE = 130; public static final int CMD_SET_PY_EXCEPTION = 131; @@ -52,6 +54,7 @@ public abstract class AbstractCommand { public static final int SHOW_RETURN_VALUES = 146; public static final int INPUT_REQUESTED = 147; + public static final int ERROR = 901; public static final int VERSION = 501; diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java new file mode 100644 index 000000000000..ca216c7eb02e --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java @@ -0,0 +1,47 @@ +package com.jetbrains.python.debugger.pydev; + +import com.jetbrains.python.debugger.PyDebugValue; +import com.jetbrains.python.debugger.PyDebuggerException; + +/** + * @author traff + */ +public class GetDescriptionCommand extends AbstractFrameCommand { + + private String myActionToken; + private String result = null; + + public GetDescriptionCommand(final RemoteDebugger debugger, String threadId, String frameId, final String myActionToken) { + super(debugger, GET_DESCRIPTION, threadId, frameId); + this.myActionToken = myActionToken; + } + + + @Override + public boolean isResponseExpected() { + return true; + } + + @Override + protected void processResponse(ProtocolFrame response) throws PyDebuggerException { + super.processResponse(response); + try { + PyDebugValue pyDebugValue = ProtocolParser.parseValue(response.getPayload(), getDebugger().getDebugProcess()); + result = pyDebugValue.getValue(); + } + catch (Exception e) { + throw new PyDebuggerException("cant obtain completions", e); + } + } + + + @Override + protected void buildPayload(Payload payload) { + super.buildPayload(payload); + payload.add(myActionToken); + } + + public String getResult() { + return result; + } +} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java index 042b455f3f1b..9b3231974b93 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java @@ -518,6 +518,11 @@ public class MultiProcessDebugger implements ProcessDebugger { return debugger(threadId).getCompletions(threadId, frameId, prefix); } + @Override + public String getDescription(String threadId, String frameId, String cmd) { + return debugger(threadId).getDescription(threadId, frameId, cmd); + } + @Override public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) { for (RemoteDebugger d : allDebuggers()) { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java index 99c8908ab5c9..186dd53a569d 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java @@ -87,6 +87,9 @@ public interface ProcessDebugger { List getCompletions(String threadId, String frameId, String prefix); + String getDescription(String threadId, String frameId, String cmd); + + void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory); void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory); diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java index 34b860897cc5..71c7ab7d745f 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java @@ -5,6 +5,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.debugger.*; import com.thoughtworks.xstream.io.naming.NoNameCoder; import com.thoughtworks.xstream.io.xml.XppReader; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.xmlpull.mxp1.MXParser; @@ -383,33 +384,14 @@ public class ProtocolParser { } private static String readString(final XppReader reader, final String name, final String fallback) throws PyDebuggerException { - final String value; - try { - value = read(reader, name); - } - catch (PyDebuggerException e) { - if (fallback != null) { - return fallback; - } - else { - throw e; - } - } - return decode(value); + final String value = read(reader, name, fallback == null); + return value == null ? fallback : value; } private static int readInt(final XppReader reader, final String name, final Integer fallback) throws PyDebuggerException { - final String value; - try { - value = read(reader, name); - } - catch (PyDebuggerException e) { - if (fallback != null) { - return fallback; - } - else { - throw e; - } + final String value = read(reader, name, fallback == null); + if (value == null) { + return fallback; } try { return Integer.parseInt(value); @@ -419,11 +401,12 @@ public class ProtocolParser { } } - private static String read(final XppReader reader, final String name) throws PyDebuggerException { + @Contract("_, _, true -> !null") + private static String read(final XppReader reader, final String name, boolean isRequired) throws PyDebuggerException { final String value = reader.getAttribute(name); - if (value == null) { + if (value == null && isRequired) { throw new PyDebuggerException("Attribute not found: " + name); } - return value; + return value == null ? null : decode(value); } } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 457947dc9431..3149e42efa5e 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -761,6 +761,13 @@ public class RemoteDebugger implements ProcessDebugger { return command.getCompletions(); } + @Override + public String getDescription(String threadId, String frameId, String cmd) { + final GetDescriptionCommand command = new GetDescriptionCommand(this, threadId, frameId, cmd); + execute(command); + return command.getResult(); + } + @Override public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) { execute(factory.createAddCommand(this)); diff --git a/python/src/com/jetbrains/python/PyParameterInfoHandler.java b/python/src/com/jetbrains/python/PyParameterInfoHandler.java index d704f26ae5ca..4307c6d6d0fa 100644 --- a/python/src/com/jetbrains/python/PyParameterInfoHandler.java +++ b/python/src/com/jetbrains/python/PyParameterInfoHandler.java @@ -65,7 +65,7 @@ public class PyParameterInfoHandler implements ParameterInfoHandler environmentVariables, @NotNull - PyConsoleOptions.PyConsoleSettings settingsProvider, + PyConsoleOptions.PyConsoleSettings settingsProvider, String... statementsToExecute) { super(project, consoleType.getTitle(), workingDir); mySdk = sdk; @@ -316,6 +316,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Connecting to Console", false) { - @Override - public void run(@NotNull final ProgressIndicator indicator) { - indicator.setText("Connecting to console..."); - try { - initAndRun(myStatementsToExecute); + UIUtil + .invokeLaterIfNeeded(() -> ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Connecting to Console", false) { + @Override + public void run(@NotNull final ProgressIndicator indicator) { + indicator.setText("Connecting to console..."); + try { + initAndRun(myStatementsToExecute); + } + catch (final Exception e) { + LOG.warn("Error running console", e); + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + showErrorsInConsole(e); + } + }); + } } - catch (final Exception e) { - LOG.warn("Error running console", e); - UIUtil.invokeAndWaitIfNeeded(new Runnable() { - @Override - public void run() { - showErrorsInConsole(e); - } - }); - } - } - })); + })); } private void showErrorsInConsole(Exception e) { @@ -564,7 +566,8 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory %d) on IDE side, " + - "port %d (=> %d) on pydevconsole.py side", myPorts[1], remotePorts.second, myPorts[0], remotePorts.first)); + "port %d (=> %d) on pydevconsole.py side", myPorts[1], remotePorts.second, myPorts[0], + remotePorts.first)); } myPydevConsoleCommunication = new PydevRemoteConsoleCommunication(getProject(), myPorts[0], remoteProcess, myPorts[1]); @@ -575,7 +578,8 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory { + private final ConsoleCommunication myCommunication; private final String myPrefix; + private final boolean myAllowRemoteResolve; public PydevConsoleReference(final PyReferenceExpression expression, - final ConsoleCommunication communication, - final String prefix) { + final ConsoleCommunication communication, final String prefix, boolean allowRemoteResolve) { super(expression, true); myCommunication = communication; myPrefix = prefix; + myAllowRemoteResolve = allowRemoteResolve; } @NotNull public ResolveResult[] multiResolve(boolean incompleteCode) { - return ResolveResult.EMPTY_ARRAY; + if (!myAllowRemoteResolve) { + return RatedResolveResult.EMPTY_ARRAY; + } + PyExpression pyExpression = resolveToDummyDescription(); + if (pyExpression == null) { + return RatedResolveResult.EMPTY_ARRAY; + } + + if (pyExpression instanceof PyReferenceExpression) { + final PsiReference redirectedRef = pyExpression.getReference(); + if (redirectedRef != null) { + PsiElement resolved = redirectedRef.resolve(); + if (resolved != null) { + return new ResolveResult[]{new RatedResolveResult(RatedResolveResult.RATE_HIGH, resolved)}; + } + } + } + + return RatedResolveResult.EMPTY_ARRAY; + + } + + public PyElement getDocumentationElement() { + return resolveToDummyDescription(); + } + + + private PyExpression resolveToDummyDescription() { + String qualifiedName = myElement.getText(); + if (qualifiedName == null) { + return null; + } + String description; + try { + + description = myCommunication.getDescription(qualifiedName); + if (Strings.isNullOrEmpty(description)) { + return null; + } + } + catch (Exception e) { + return null; + } + + PyElementGenerator generator = PyElementGenerator.getInstance(myElement.getProject()); + PyFile dummyFile = (PyFile)generator.createDummyFile(LanguageLevel.forElement(myElement), description); + Module module = ModuleUtilCore.findModuleForPsiElement(myElement); + if (module != null) { + dummyFile.putUserData(ModuleUtilCore.KEY_MODULE, module); + } + + List statements = dummyFile.getStatements(); + PyStatement pyStatement = statements.get(statements.size() - 1); + return pyStatement instanceof PyExpressionStatement ? ((PyExpressionStatement)pyStatement).getExpression() : null; } @NotNull @@ -71,8 +126,7 @@ public class PydevConsoleReference extends PsiPolyVariantReferenceBase 1) { diff --git a/python/src/com/jetbrains/python/debugger/dataframe/DataFrameTableCellRenderer.java b/python/src/com/jetbrains/python/debugger/dataframe/DataFrameTableCellRenderer.java index 76946ce79e43..72eec940f578 100644 --- a/python/src/com/jetbrains/python/debugger/dataframe/DataFrameTableCellRenderer.java +++ b/python/src/com/jetbrains/python/debugger/dataframe/DataFrameTableCellRenderer.java @@ -41,6 +41,11 @@ class DataFrameTableCellRenderer extends DefaultTableCellRenderer implements Col myColored = colored; } + @Override + public boolean getColored() { + return myColored; + } + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col); diff --git a/python/src/com/jetbrains/python/psi/PyFileElementType.java b/python/src/com/jetbrains/python/psi/PyFileElementType.java index 6358424b5d55..11cd013273ee 100644 --- a/python/src/com/jetbrains/python/psi/PyFileElementType.java +++ b/python/src/com/jetbrains/python/psi/PyFileElementType.java @@ -106,7 +106,7 @@ public class PyFileElementType extends IStubFileElementType { final Project project = psi.getProject(); final PsiBuilderFactory factory = PsiBuilderFactory.getInstance(); final PsiBuilder builder = factory.createBuilder(project, node, lexer, getLanguage(), node.getChars()); - final PyParser parser = new PyConsoleParser(consoleData); + final PyParser parser = new PyConsoleParser(consoleData, getLanguageLevel(psi)); return parser.parse(this, builder).getFirstChildNode(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 417b7f495632..5915ff454435 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -83,9 +83,9 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere final ConsoleCommunication communication = file.getCopyableUserData(PydevConsoleRunner.CONSOLE_KEY); if (communication != null) { if (qualifier != null) { - return new PydevConsoleReference(this, communication, qualifier.getText() + "."); + return new PydevConsoleReference(this, communication, qualifier.getText() + ".", context.allowRemote()); } - return new PydevConsoleReference(this, communication, ""); + return new PydevConsoleReference(this, communication, "", context.allowRemote()); } if (qualifier != null) { diff --git a/updater/testSrc/com/intellij/updater/PatchTest.java b/updater/testSrc/com/intellij/updater/PatchTest.java index 6c8631edfb4d..b120c63db4de 100644 --- a/updater/testSrc/com/intellij/updater/PatchTest.java +++ b/updater/testSrc/com/intellij/updater/PatchTest.java @@ -35,7 +35,7 @@ public class PatchTest extends PatchTestCase { public void testDigestFiles() throws Exception { Patch patch = createPatch(); Map checkSums = patch.digestFiles(getDataDir(), Collections.emptyList(), false, TEST_UI); - assertEquals(9, checkSums.size()); + assertEquals(11, checkSums.size()); } @Test @@ -43,6 +43,7 @@ public class PatchTest extends PatchTestCase { Patch patch = createPatch(); assertThat(patch.getActions()).containsOnly( new CreateAction(patch, "newDir/newFile.txt"), + new CreateAction(patch, "newDir/"), new UpdateAction(patch, "Readme.txt", CHECKSUMS.README_TXT), new UpdateZipAction(patch, "lib/annotations.jar", Collections.singletonList("org/jetbrains/annotations/NewClass.class"), @@ -67,6 +68,7 @@ public class PatchTest extends PatchTestCase { assertThat(patch.getActions()).containsOnly( new CreateAction(patch, "newDir/newFile.txt"), + new CreateAction(patch, "newDir/"), new UpdateZipAction(patch, "lib/annotations.jar", Collections.singletonList("org/jetbrains/annotations/NewClass.class"), Collections.singletonList("org/jetbrains/annotations/Nullable.class"), diff --git a/xml/dom-openapi/src/com/intellij/util/xml/ModuleContentRootSearchScope.java b/xml/dom-openapi/src/com/intellij/util/xml/ModuleContentRootSearchScope.java index 2b54b14d8564..8d5b065a699e 100644 --- a/xml/dom-openapi/src/com/intellij/util/xml/ModuleContentRootSearchScope.java +++ b/xml/dom-openapi/src/com/intellij/util/xml/ModuleContentRootSearchScope.java @@ -15,39 +15,16 @@ */ package com.intellij.util.xml; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NotNull; +import com.intellij.psi.search.DelegatingGlobalSearchScope; -public class ModuleContentRootSearchScope extends GlobalSearchScope { - private final ModuleRootManager myRootManager; - private final Module myModule; +/** + * @deprecated use {@link Module#getModuleContentScope()} + */ +public class ModuleContentRootSearchScope extends DelegatingGlobalSearchScope { public ModuleContentRootSearchScope(final Module module) { - super(module.getProject()); - myRootManager = ModuleRootManager.getInstance(module); - myModule = module; + super(module.getModuleContentScope()); } - @Override - public boolean contains(@NotNull final VirtualFile file) { - return myRootManager.getFileIndex().isInContent(file); - } - - @Override - public int compare(@NotNull final VirtualFile file1, @NotNull final VirtualFile file2) { - return 0; - } - - @Override - public boolean isSearchInModuleContent(@NotNull final Module aModule) { - return aModule == myModule; - } - - @Override - public boolean isSearchInLibraries() { - return false; - } }