diff --git a/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java b/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java index 5d35743f1f9b..8e3a664fb859 100644 --- a/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java +++ b/java/debugger/debugger-agent/src/com/intellij/rt/debugger/agent/CaptureAgent.java @@ -168,7 +168,7 @@ public class CaptureAgent { Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { - if (className != null) { + if (className != null && classBeingRedefined == null) { // we do not support redefinition or retransform List classPoints = myInstrumentPoints.get(className); if (classPoints != null) { try { diff --git a/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryType.java b/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryType.java index eee1695e9594..d612f2ee5ac0 100644 --- a/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryType.java +++ b/java/idea-ui/src/com/intellij/framework/library/DownloadableLibraryType.java @@ -15,7 +15,7 @@ */ package com.intellij.framework.library; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.libraries.*; import com.intellij.openapi.roots.libraries.ui.LibraryEditorComponent; @@ -117,7 +117,7 @@ public abstract class DownloadableLibraryType extends LibraryType= startOffset && offset < endOffset || catchSection.getFirstChild().getTextRange().contains(startOffset)) { + if (firstToMove == null) firstToMove = catchSection; + lastToMove = catchSection; + } + } + if (firstToMove == null) return false; if (!sanityCheck(firstToMove)) { return info.prohibitMove(); } - - PsiCatchSection lastToMove = firstToMove; - while (true) { - final PsiCatchSection next = PsiTreeUtil.getNextSiblingOfType(lastToMove, PsiCatchSection.class); - if (next == null || next.getTextRange().getStartOffset() >= endOffset) { - break; - } - lastToMove = next; + if (element instanceof PsiWhiteSpace && element.getNextSibling() instanceof PsiStatement + || PsiTreeUtil.getParentOfType(element, PsiStatement.class, true, PsiMember.class) != tryStatement) { + // nonsensical selection + return info.prohibitMove(); } + final PsiCatchSection sibling = down ? PsiTreeUtil.getNextSiblingOfType(lastToMove, PsiCatchSection.class) : PsiTreeUtil.getPrevSiblingOfType(firstToMove, PsiCatchSection.class); diff --git a/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java b/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java index b52b5113f334..5e4fe3382743 100644 --- a/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java +++ b/java/java-impl/src/com/intellij/ide/actions/CreateModuleInfoAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions; import com.intellij.codeInsight.daemon.impl.analysis.JavaModuleGraphUtil; @@ -9,6 +9,7 @@ import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; import com.intellij.ide.fileTemplates.actions.CreateFromTemplateActionBase; +import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.LangDataKeys; @@ -45,10 +46,16 @@ public class CreateModuleInfoAction extends CreateFromTemplateActionBase { e.getPresentation().setEnabledAndVisible(false); } else { - e.getPresentation().setVisible(true); PsiDirectory target = getTargetDirectory(ctx, view); - e.getPresentation().setEnabled( - target != null && PsiUtil.isLanguageLevel9OrHigher(target) && JavaModuleGraphUtil.findDescriptorByElement(target) == null); + boolean isActionAvailable = + target != null && PsiUtil.isLanguageLevel9OrHigher(target) && JavaModuleGraphUtil.findDescriptorByElement(target) == null; + if (ActionPlaces.isPopupPlace(e.getPlace())) { + e.getPresentation().setVisible(isActionAvailable); + } + else { + e.getPresentation().setVisible(true); + e.getPresentation().setEnabled(isActionAvailable); + } } } diff --git a/java/java-tests/testSrc/com/intellij/java/psi/StubAstSwitchTest.groovy b/java/java-tests/testSrc/com/intellij/java/psi/StubAstSwitchTest.groovy index 5df0c063482d..d356b5275660 100644 --- a/java/java-tests/testSrc/com/intellij/java/psi/StubAstSwitchTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/psi/StubAstSwitchTest.groovy @@ -107,7 +107,7 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { latch.await() } - void "test external modification of a stubbed file with smart pointer switches the file to AST"() { + void "test smart pointer survives an external modification of a stubbed file"() { PsiFile file = myFixture.addFileToProject("A.java", "class A {}") def oldClass = JavaPsiFacade.getInstance(project).findClass("A", GlobalSearchScope.allScope(project)) def pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(oldClass) @@ -121,7 +121,6 @@ class StubAstSwitchTest extends LightCodeInsightFixtureTestCase { ApplicationManager.application.runWriteAction { VfsUtil.saveText(file.virtualFile, "import java.util.*; class A {}; class B {}") } assert pointer.element == oldClass - assert ((PsiFileImpl)file).treeElement } void "test do not parse when resolving references inside an anonymous class"() { diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java b/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java index 72f232f44bb2..f2d2a410dbef 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java @@ -53,6 +53,8 @@ public interface JsonLikePsiWalker { return element.getTextRange(); } + default boolean acceptsEmptyRoot() { return false; } + @Nullable static JsonLikePsiWalker getWalker(@NotNull final PsiElement element, JsonSchemaObject schemaObject) { if (JSON_ORIGINAL_PSI_WALKER.handles(element)) return JSON_ORIGINAL_PSI_WALKER; diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonLikeSyntaxAdapter.java b/json/src/com/jetbrains/jsonSchema/extension/JsonLikeSyntaxAdapter.java index 5f0cf91424d1..ee3628084b72 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonLikeSyntaxAdapter.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonLikeSyntaxAdapter.java @@ -2,6 +2,8 @@ package com.jetbrains.jsonSchema.extension; import com.intellij.psi.PsiElement; +import com.intellij.psi.impl.source.tree.LeafPsiElement; +import com.jetbrains.jsonSchema.impl.JsonSchemaType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,8 +11,11 @@ public interface JsonLikeSyntaxAdapter { @Nullable PsiElement getPropertyValue(PsiElement property); @NotNull default PsiElement adjustValue(@NotNull PsiElement value) { return value; } @Nullable String getPropertyName(PsiElement property); - @NotNull PsiElement createProperty(@NotNull final String name, @NotNull final String value); - boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement); + @NotNull PsiElement createProperty(@NotNull final String name, @NotNull final String value, PsiElement element); + boolean ensureComma(PsiElement self, PsiElement newElement); void removeIfComma(PsiElement forward); boolean fixWhitespaceBefore(PsiElement initialElement, PsiElement element); + @NotNull String getDefaultValueFromType(@Nullable JsonSchemaType type); + PsiElement adjustNewProperty(PsiElement element); + PsiElement adjustPropertyAnchor(LeafPsiElement element); } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java index 401ce69b37d3..f956e530be63 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java @@ -12,6 +12,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; import com.intellij.util.ThreeState; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.extension.JsonLikeSyntaxAdapter; @@ -193,14 +194,14 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker { @NotNull @Override - public PsiElement createProperty(@NotNull String name, @NotNull String value) { + public PsiElement createProperty(@NotNull String name, @NotNull String value, PsiElement element) { return myGenerator.createProperty(name, value); } @Override - public boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement) { - if (backward instanceof JsonProperty) { - self.addAfter(myGenerator.createComma(), backward); + public boolean ensureComma(PsiElement self, PsiElement newElement) { + if (newElement instanceof JsonProperty && self instanceof JsonProperty) { + self.getParent().addAfter(myGenerator.createComma(), self); return true; } return false; @@ -217,6 +218,22 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker { public boolean fixWhitespaceBefore(PsiElement initialElement, PsiElement element) { return true; } + + @NotNull + @Override + public String getDefaultValueFromType(@Nullable JsonSchemaType type) { + return type == null ? "" : type.getDefaultValue(); + } + + @Override + public PsiElement adjustNewProperty(PsiElement element) { + return element; + } + + @Override + public PsiElement adjustPropertyAnchor(LeafPsiElement element) { + throw new IncorrectOperationException("Shouldn't use leafs for insertion in pure JSON!"); + } }; } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java index 8d5aa28fc7aa..5580a2cfc506 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java @@ -300,7 +300,7 @@ class JsonSchemaAnnotatorChecker { if (object.shouldCheckIntegralRequirements()) { final Set required = schema.getRequired(); if (required != null) { - HashSet requiredNames = ContainerUtil.newHashSet(required); + HashSet requiredNames = ContainerUtil.newLinkedHashSet(required); requiredNames.removeAll(set); if (!requiredNames.isEmpty()) { JsonValidationError.MissingMultiplePropsIssueData data = createMissingPropertiesData(schema, requiredNames); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java index 11a9e1795581..06ff66f53123 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java @@ -131,7 +131,7 @@ public class JsonSchemaComplianceChecker { myHolder.registerProblem(psiElement, range, value); } else { - myHolder.registerProblem(psiElement, range, value, fix); + myHolder.registerProblem(range.isEmpty() ? psiElement.getContainingFile() : psiElement, range, value, fix); } } @@ -142,7 +142,7 @@ public class JsonSchemaComplianceChecker { if (!isTop) ref.set(el); return isTop; }); - return ref.isNull() ? null : walker.createValueAdapter(ref.get()); + return ref.isNull() ? (walker.acceptsEmptyRoot() ? walker.createValueAdapter(element) : null) : walker.createValueAdapter(ref.get()); } private boolean checkIfAlreadyProcessed(@NotNull PsiElement property) { diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java index c93c65c06031..c4d9637add0d 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java @@ -408,9 +408,9 @@ public class JsonSchemaReader { private static MyReader createRequired() { return (element, object, queue) -> { if (element instanceof JsonArray) { - object.setRequired(((JsonArray)element).getValueList().stream() + object.setRequired(ContainerUtil.newLinkedHashSet(((JsonArray)element).getValueList().stream() .filter(notEmptyString()) - .map(el -> StringUtil.unquoteString(el.getText())).collect(Collectors.toSet())); + .map(el -> StringUtil.unquoteString(el.getText())).collect(Collectors.toList()))); } }; } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java index 9d682e772ca3..37107c2329e9 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaServiceImpl.java @@ -2,7 +2,7 @@ package com.jetbrains.jsonSchema.impl; import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.json.JsonUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; @@ -85,7 +85,7 @@ public class JsonSchemaServiceImpl implements JsonSchemaService { throw e; } catch (Exception e) { - Logger.getInstance(JsonSchemaService.class).error(PluginManagerCore.createPluginException(e.getMessage(), e, factory.getClass())); + PluginException.logPluginError(Logger.getInstance(JsonSchemaService.class), e.getMessage(), e, factory.getClass()); } } return providers; diff --git a/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java b/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java index 7214d1463076..6eaba37593f1 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java +++ b/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java @@ -19,12 +19,14 @@ import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.DocumentUtil; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.jsonSchema.extension.JsonLikeSyntaxAdapter; -import com.jetbrains.jsonSchema.impl.JsonSchemaType; import com.jetbrains.jsonSchema.impl.JsonValidationError; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -60,12 +62,13 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix hadComma = Ref.create(false); + VirtualFile file = element.getContainingFile().getVirtualFile(); PsiElement newElement = performFix(element, hadComma); // if we have more than one property, don't expand templates and don't move the caret if (newElement == null) return; PsiElement value = myQuickFixAdapter.getPropertyValue(newElement); - FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(element.getContainingFile().getVirtualFile()); + FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(file); EditorEx editor = EditorUtil.getEditorEx(fileEditor); assert editor != null; if (value == null) { @@ -83,7 +86,12 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix { Template template = builder.buildInlineTemplate(); template.setToReformat(true); @@ -92,23 +100,43 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix hadComma) { - if (element == null) return null; + public PsiElement performFix(@Nullable PsiElement node, @NotNull Ref hadComma) { + if (node == null) return null; + PsiElement element = node instanceof PsiFile ? node.getFirstChild() : node; Ref newElementRef = Ref.create(null); WriteAction.run(() -> { boolean isSingle = myData.myMissingPropertyIssues.size() == 1; - for (JsonValidationError.MissingPropertyIssueData issue: myData.myMissingPropertyIssues) { + PsiElement processedElement = element; + List reverseOrder + = ContainerUtil.reverse(ContainerUtil.newArrayList(myData.myMissingPropertyIssues)); + for (JsonValidationError.MissingPropertyIssueData issue: reverseOrder) { Object defaultValueObject = issue.defaultValue; String defaultValue = defaultValueObject instanceof String ? StringUtil.wrapWithDoubleQuote(defaultValueObject.toString()) : null; - PsiElement newElement = element - .addBefore( - myQuickFixAdapter.createProperty(issue.propertyName, defaultValue == null ? getDefaultValueFromType(issue) : defaultValue), - element.getLastChild()); - PsiElement backward = PsiTreeUtil.skipWhitespacesBackward(newElement); - hadComma.set(myQuickFixAdapter.ensureComma(backward, element, newElement)); + PsiElement property = myQuickFixAdapter.createProperty(issue.propertyName, defaultValue == null + ? myQuickFixAdapter + .getDefaultValueFromType(issue.propertyType) + : defaultValue, element); + PsiElement newElement; + if (processedElement instanceof LeafPsiElement) { + newElement = myQuickFixAdapter.adjustPropertyAnchor((LeafPsiElement)processedElement).addBefore(property, null); + } + else { + if (processedElement == element) { + newElement = processedElement.addBefore(property, processedElement.getLastChild()); + } + else { + newElement = processedElement.getParent().addBefore(property, processedElement); + } + } + PsiElement adjusted = myQuickFixAdapter.adjustNewProperty(newElement); + hadComma.set(myQuickFixAdapter.ensureComma(adjusted, PsiTreeUtil.skipWhitespacesForward(newElement))); + if (!hadComma.get()) { + hadComma.set(processedElement == element && myQuickFixAdapter.ensureComma(PsiTreeUtil.skipWhitespacesBackward(newElement), adjusted)); + } + processedElement = adjusted; if (isSingle) { - newElementRef.set(newElement); + newElementRef.set(adjusted); } } }); @@ -116,12 +144,6 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix(private val component: Persisten throw e } catch (e: Throwable) { - LOG.error(PluginManagerCore.createPluginException("Cannot get state after load", e, component.javaClass)) + PluginException.logPluginError(LOG, "Cannot get state after load", e, component.javaClass) null } diff --git a/platform/core-api/src/com/intellij/diagnostic/PluginException.java b/platform/core-api/src/com/intellij/diagnostic/PluginException.java index b42adae40822..4e2d5bf288d4 100644 --- a/platform/core-api/src/com/intellij/diagnostic/PluginException.java +++ b/platform/core-api/src/com/intellij/diagnostic/PluginException.java @@ -15,6 +15,7 @@ */ package com.intellij.diagnostic; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; @@ -25,7 +26,7 @@ import org.jetbrains.annotations.Nullable; * some contract of IntelliJ Platform. If such exceptions are thrown or logged via {@link com.intellij.openapi.diagnostic.Logger#error(Throwable)} * method and reported to JetBrains by user, they may be automatically attributed to corresponding plugins. * - *

If the problem is caused by a class, use {@link com.intellij.ide.plugins.PluginManagerCore#createPluginException} to create + *

If the problem is caused by a class, use {@link #createByClass} to create * an instance. If the problem is caused by an extension, implement {@link com.intellij.openapi.extensions.PluginAware} in its extension class * to get the plugin ID. */ @@ -58,4 +59,20 @@ public class PluginException extends RuntimeException { String message = super.getMessage(); return myPluginId != null ? StringUtil.notNullize(message) + " [Plugin: " + myPluginId + "]" : message; } + + /** + * Creates an exception caused by a problem in a plugin's code. + * @param pluginClass a problematic class which caused the error + */ + public static PluginException createByClass(@NotNull String errorMessage, @Nullable Throwable cause, @NotNull Class pluginClass) { + return PluginProblemReporter.getInstance().createPluginExceptionByClass(errorMessage, cause, pluginClass); + } + + /** + * Log an error caused by a problem in a plugin's code. + * @param pluginClass a problematic class which caused the error + */ + public static void logPluginError(@NotNull Logger logger, @NotNull String errorMessage, @Nullable Throwable cause, @NotNull Class pluginClass) { + logger.error(createByClass(errorMessage, cause, pluginClass)); + } } diff --git a/platform/core-api/src/com/intellij/diagnostic/PluginProblemReporter.java b/platform/core-api/src/com/intellij/diagnostic/PluginProblemReporter.java new file mode 100644 index 000000000000..38b58bccb6e9 --- /dev/null +++ b/platform/core-api/src/com/intellij/diagnostic/PluginProblemReporter.java @@ -0,0 +1,29 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.diagnostic; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ServiceManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +interface PluginProblemReporter { + static PluginProblemReporter getInstance() { + if (ApplicationManager.getApplication() == null) { + //if the application isn't initialized yet return silly implementation which reports all plugins problems as platform ones + return new PluginProblemReporter() { + @NotNull + @Override + public PluginException createPluginExceptionByClass(@NotNull String errorMessage, + @Nullable Throwable cause, + @NotNull Class pluginClass) { + return new PluginException(errorMessage, cause, null); + } + }; + } + + return ServiceManager.getService(PluginProblemReporter.class); + } + + @NotNull + PluginException createPluginExceptionByClass(@NotNull String errorMessage, @Nullable Throwable cause, @NotNull Class pluginClass); +} diff --git a/platform/core-api/src/com/intellij/lang/LighterASTNode.java b/platform/core-api/src/com/intellij/lang/LighterASTNode.java index 4daea1987e58..e4b613a170be 100644 --- a/platform/core-api/src/com/intellij/lang/LighterASTNode.java +++ b/platform/core-api/src/com/intellij/lang/LighterASTNode.java @@ -29,4 +29,8 @@ public interface LighterASTNode { int getStartOffset(); int getEndOffset(); + + default int getTextLength() { + return getEndOffset() - getStartOffset(); + } } \ No newline at end of file diff --git a/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java b/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java index d7ac848fbaaa..91df81b2e3dd 100644 --- a/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java +++ b/platform/core-api/src/com/intellij/lang/TreeBackedLighterAST.java @@ -88,6 +88,11 @@ public class TreeBackedLighterAST extends LighterAST { return myNode.getStartOffset() + myNode.getTextLength(); } + @Override + public int getTextLength() { + return myNode.getTextLength(); + } + @Override public boolean equals(final Object o) { if (this == o) return true; diff --git a/platform/core-impl/src/com/intellij/diagnostic/PluginProblemReporterImpl.java b/platform/core-impl/src/com/intellij/diagnostic/PluginProblemReporterImpl.java new file mode 100644 index 000000000000..d2413d068e92 --- /dev/null +++ b/platform/core-impl/src/com/intellij/diagnostic/PluginProblemReporterImpl.java @@ -0,0 +1,14 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.diagnostic; + +import com.intellij.ide.plugins.PluginManagerCore; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +class PluginProblemReporterImpl implements PluginProblemReporter { + @NotNull + @Override + public PluginException createPluginExceptionByClass(@NotNull String errorMessage, @Nullable Throwable cause, @NotNull Class pluginClass) { + return PluginManagerCore.createPluginException(errorMessage, cause, pluginClass); + } +} diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java index fffac90d13ad..764eeec0ac9d 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java @@ -342,8 +342,7 @@ public class PluginManagerCore { } /** - * Creates an exception caused by a problem in a plugin's code. - * @param pluginClass a problematic class which caused the error + * This is an internal method, use {@link PluginException#createByClass(String, Throwable, Class)} instead. */ @NotNull public static PluginException createPluginException(@NotNull String errorMessage, @Nullable Throwable cause, 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 359d7812b5a5..97c7315d58e6 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 @@ -409,7 +409,7 @@ public abstract class ComponentManagerImpl extends UserDataHolderBase implements // component may have been already loaded by PicoContainer, so fire error only if components are really different if (!instance.equals(loadedComponent)) { String errorMessage = "Component name collision: " + componentName + " " + (loadedComponent == null ? "null" : loadedComponent.getClass()) + " and " + instance.getClass(); - LOG.error(PluginManagerCore.createPluginException(errorMessage, null, instance.getClass())); + PluginException.logPluginError(LOG, errorMessage, null, instance.getClass()); } } else { diff --git a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java index 461f5cdcf52d..05b381567a87 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java +++ b/platform/core-impl/src/com/intellij/psi/impl/DocumentCommitThread.java @@ -2,7 +2,7 @@ package com.intellij.psi.impl; import com.google.common.annotations.VisibleForTesting; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.lang.FileASTNode; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.*; @@ -717,7 +717,7 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi "; file name:" + file.getName() + "; type:" + file.getFileType() + "; lang:" + file.getLanguage(); - LOG.error(PluginManagerCore.createPluginException(errorMessage, null, file.getLanguage().getClass())); + PluginException.logPluginError(LOG, errorMessage, null, file.getLanguage().getClass()); file.putUserData(BlockSupport.DO_NOT_REPARSE_INCREMENTALLY, Boolean.TRUE); try { @@ -727,7 +727,7 @@ public class DocumentCommitThread implements Runnable, Disposable, DocumentCommi diffLog.doActualPsiChange(file); if (oldFileNode.getTextLength() != document.getTextLength()) { - LOG.error(PluginManagerCore.createPluginException("PSI is broken beyond repair in: " + file, null, file.getLanguage().getClass())); + PluginException.logPluginError(LOG, "PSI is broken beyond repair in: " + file, null, file.getLanguage().getClass()); } } finally { diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/FileContextUtil.java b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/FileContextUtil.java index e507e7010e32..643dd1d89401 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/resolve/FileContextUtil.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/resolve/FileContextUtil.java @@ -39,7 +39,6 @@ public class FileContextUtil { @Nullable public static PsiFile getContextFile(@NotNull PsiElement element) { - if (!element.isValid()) return null; PsiFile file = element.getContainingFile(); if (file == null) return null; PsiElement context = file.getContext(); diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java index 2f4eae945a40..ab0cd73e7dcc 100644 --- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java +++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/LazyParseableElement.java @@ -19,7 +19,7 @@ */ package com.intellij.psi.impl.source.tree; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Attachment; import com.intellij.openapi.diagnostic.LogUtil; @@ -223,7 +223,7 @@ public class LazyParseableElement extends CompositeElement { child = child.getTreeNext(); } if (length != text.length()) { - LOG.error("Text mismatch in " + LogUtil.objectAndClass(getElementType()), PluginManagerCore.createPluginException("Text mismatch", null, getElementType().getClass()), + LOG.error("Text mismatch in " + LogUtil.objectAndClass(getElementType()), PluginException.createByClass("Text mismatch", null, getElementType().getClass()), new Attachment("code.txt", text.toString())); } } diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt index 560e09bf3732..128ce3de0a42 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.kt @@ -577,9 +577,9 @@ class UISettings @JvmOverloads constructor(private val notRoamableOptions: NotRo state.editorAAType = AntialiasingType.SUBPIXEL } - if (state.fontSize != UISettingsState.defFontSize) { - fontSize = state.fontSize - state.fontSize = UISettingsState.defFontSize + if (state.fontSize != 0) { + fontSize = UISettings.restoreFontSize(state.fontSize, state.fontScale) + state.fontSize = 0 } if (state.fontScale != 0f) { fontScale = state.fontScale diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettingsState.kt b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettingsState.kt index 2fc811050855..c1fc874ff5d3 100644 --- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettingsState.kt +++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettingsState.kt @@ -28,7 +28,7 @@ class UISettingsState : BaseState() { @get:OptionTag("FONT_SIZE") @Deprecated("", replaceWith = ReplaceWith("NotRoamableUiOptions.fontSize")) - var fontSize by property(defFontSize) + var fontSize by property(0) @get:OptionTag("FONT_SCALE") @Deprecated("", replaceWith = ReplaceWith("NotRoamableUiOptions.fontScale")) diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java index 436bca2ae9b6..23a3910defeb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/ExternalToolPass.java @@ -7,7 +7,6 @@ import com.intellij.codeInsight.daemon.HighlightDisplayKey; import com.intellij.codeInsight.daemon.impl.analysis.HighlightingLevelManager; import com.intellij.codeInspection.ex.InspectionProfileImpl; import com.intellij.diagnostic.PluginException; -import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.lang.ExternalLanguageAnnotators; import com.intellij.lang.Language; import com.intellij.lang.annotation.Annotation; @@ -241,8 +240,7 @@ public class ExternalToolPass extends ProgressableTextEditorHighlightingPass { String path = file != null ? file.getPath() : root.getName(); final PluginException pluginException = - PluginManagerCore.createPluginException("annotator: " + annotator + " (" + annotator.getClass() + ")", - t, annotator.getClass()); + PluginException.createByClass("annotator: " + annotator + " (" + annotator.getClass() + ")", t, annotator.getClass()); LOG.error("ExternalToolPass: ", pluginException, new Attachment("root_path.txt", path)); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java index 9155fd46c7b2..1f088e7fc594 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/LocalInspectionsPass.java @@ -13,7 +13,7 @@ import com.intellij.codeInspection.*; import com.intellij.codeInspection.ex.*; import com.intellij.codeInspection.ui.InspectionToolPresentation; import com.intellij.concurrency.JobLauncher; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.injected.editor.DocumentWindow; import com.intellij.lang.Language; import com.intellij.lang.annotation.HighlightSeverity; @@ -542,7 +542,7 @@ public class LocalInspectionsPass extends ProgressableTextEditorHighlightingPass "' (" + tool.getClass() + ") was invoked for. Message: '" + descriptor + "'.\nElement' containing file: " + context + "\nInspection invoked for file: " + myContext + "\n"; - LOG.error(PluginManagerCore.createPluginException(errorMessage, null, tool.getClass())); + PluginException.logPluginError(LOG, errorMessage, null, tool.getClass()); } boolean isInjected = myInspectInjectedPsi && file != getFile(); if (!isInjected) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java index a0a5fe1577f2..e34d7f847bc2 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/navigation/actions/GotoDeclarationAction.java @@ -8,9 +8,9 @@ import com.intellij.codeInsight.TargetElementUtil; import com.intellij.codeInsight.actions.BaseCodeInsightAction; import com.intellij.codeInsight.hint.HintManager; import com.intellij.codeInsight.navigation.NavigationUtil; +import com.intellij.diagnostic.PluginException; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.find.actions.ShowUsagesAction; -import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.ide.util.DefaultPsiElementCellRenderer; import com.intellij.ide.util.EditSourceUtil; import com.intellij.injected.editor.EditorWindow; @@ -344,9 +344,9 @@ public class GotoDeclarationAction extends BaseCodeInsightAction implements Code private static boolean assertNotNullElements(@NotNull PsiElement[] result, Class clazz) { for (PsiElement element : result) { if (element == null) { - LOG.error(PluginManagerCore.createPluginException( + PluginException.logPluginError(LOG, "Null target element is returned by 'getGotoDeclarationTargets' in " + clazz.getName(), null, clazz - )); + ); return false; } } diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.kt b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.kt index e0fc06a87128..a25e90eff7e7 100644 --- a/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.kt +++ b/platform/lang-impl/src/com/intellij/execution/impl/RunnerAndConfigurationSettingsImpl.kt @@ -4,6 +4,7 @@ package com.intellij.execution.impl import com.intellij.configurationStore.SerializableScheme import com.intellij.configurationStore.deserializeAndLoadState import com.intellij.configurationStore.serializeStateInto +import com.intellij.diagnostic.PluginException import com.intellij.execution.ExecutionBundle import com.intellij.execution.Executor import com.intellij.execution.ExecutorRegistry @@ -508,7 +509,7 @@ class RunnerAndConfigurationSettingsImpl @JvmOverloads constructor(val manager: return settings.getOrPut(runner) { createSettings(runner) } } catch (e: AbstractMethodError) { - RunManagerImpl.LOG.error(PluginManagerCore.createPluginException("Update failed for: ${configuration.type.displayName}, runner: ${runner.runnerId}", e, runner.javaClass)) + PluginException.logPluginError(RunManagerImpl.LOG, "Update failed for: ${configuration.type.displayName}, runner: ${runner.runnerId}", e, runner.javaClass) return null } } diff --git a/platform/lang-impl/src/com/intellij/formatting/RangesAssert.java b/platform/lang-impl/src/com/intellij/formatting/RangesAssert.java index 58649d0224a6..6ffb7370c9c9 100644 --- a/platform/lang-impl/src/com/intellij/formatting/RangesAssert.java +++ b/platform/lang-impl/src/com/intellij/formatting/RangesAssert.java @@ -2,7 +2,7 @@ package com.intellij.formatting; import com.intellij.diagnostic.AttachmentFactory; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.lang.Language; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.TextRange; @@ -55,7 +55,7 @@ class RangesAssert { buffer.append('\n'); } - Throwable t = problematicLanguageClass != null ? PluginManagerCore.createPluginException("", null, problematicLanguageClass) : null; + Throwable t = problematicLanguageClass != null ? PluginException.createByClass("", null, problematicLanguageClass) : null; LOG.error(messageBuffer.toString(), t, AttachmentFactory.createContext(buffer)); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java index cb6399861965..88569af071d3 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoFileItemProvider.java @@ -3,6 +3,7 @@ package com.intellij.ide.actions; import com.intellij.ide.util.gotoByName.*; import com.intellij.navigation.ChooseByNameContributor; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbService; @@ -39,6 +40,7 @@ import java.util.*; * @author peter */ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { + private static final Logger LOG = Logger.getInstance("#com.intellij.ide.actions.GotoFileItemProvider"); private final Project myProject; private final GotoFileModel myModel; @@ -54,21 +56,29 @@ public class GotoFileItemProvider extends DefaultChooseByNameItemProvider { boolean everywhere, @NotNull ProgressIndicator indicator, @NotNull Processor consumer) { - PsiFileSystemItem absolute = getFileByAbsolutePath(pattern); - if (absolute != null && !consumer.process(absolute)) { - return true; - } + long start = System.currentTimeMillis(); + try { + PsiFileSystemItem absolute = getFileByAbsolutePath(pattern); + if (absolute != null && !consumer.process(absolute)) { + return true; + } - if (pattern.startsWith("./") || pattern.startsWith(".\\")) { - pattern = pattern.substring(1); - } + if (pattern.startsWith("./") || pattern.startsWith(".\\")) { + pattern = pattern.substring(1); + } - if (!processItemsForPattern(base, pattern, everywhere, consumer, indicator)) { - return false; + if (!processItemsForPattern(base, pattern, everywhere, consumer, indicator)) { + return false; + } + String fixed = FixingLayoutMatcher.fixLayout(pattern); + return fixed == null || processItemsForPattern(base, fixed, everywhere, consumer, indicator); + } + finally { + if (LOG.isDebugEnabled()) { + LOG.debug("Goto File \"" + pattern + "\" took " + (System.currentTimeMillis() - start) + " ms"); + } } - String fixed = FixingLayoutMatcher.fixLayout(pattern); - return fixed == null || processItemsForPattern(base, fixed, everywhere, consumer, indicator); } private boolean processItemsForPattern(@NotNull ChooseByNameBase base, diff --git a/platform/lang-impl/src/com/intellij/ide/impl/dataRules/PsiElementFromSelectionsRule.java b/platform/lang-impl/src/com/intellij/ide/impl/dataRules/PsiElementFromSelectionsRule.java index 852a23454ac6..d61fd3717f19 100644 --- a/platform/lang-impl/src/com/intellij/ide/impl/dataRules/PsiElementFromSelectionsRule.java +++ b/platform/lang-impl/src/com/intellij/ide/impl/dataRules/PsiElementFromSelectionsRule.java @@ -16,7 +16,7 @@ package com.intellij.ide.impl.dataRules; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.diagnostic.Logger; @@ -34,7 +34,7 @@ public class PsiElementFromSelectionsRule implements GetDataRule { if (!(data instanceof Object[])) { String errorMessage = "Value for data key 'PlatformDataKeys.SELECTED_ITEMS' must be of type Object[], but " + data.getClass() + " is returned by " + dataProvider.getClass(); - LOG.error(PluginManagerCore.createPluginException(errorMessage, null, dataProvider.getClass())); + PluginException.logPluginError(LOG, errorMessage, null, dataProvider.getClass()); return null; } diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java index 7b6a982b6256..fff54a28d50d 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/ContributorsBasedGotoByModel.java @@ -2,7 +2,7 @@ package com.intellij.ide.util.gotoByName; import com.intellij.concurrency.JobLauncher; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.ide.util.NavigationItemListCellRenderer; import com.intellij.navigation.ChooseByNameContributor; import com.intellij.navigation.ChooseByNameContributorEx; @@ -191,7 +191,7 @@ public abstract class ContributorsBasedGotoByModel implements ChooseByNameModelE for (NavigationItem item : itemsByName) { canceled.checkCanceled(); if (item == null) { - LOG.error(PluginManagerCore.createPluginException("null item from contributor " + contributor + " for name " + name, null, contributor.getClass())); + PluginException.logPluginError(LOG, "null item from contributor " + contributor + " for name " + name, null, contributor.getClass()); continue; } diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java index 80c247fb5593..434b6b380d35 100644 --- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.openapi.fileEditor.impl; import com.intellij.ide.highlighter.HighlighterFactory; @@ -104,28 +104,29 @@ final class TestEditorManagerImpl extends FileEditorManagerEx implements Disposa private Pair openFileImpl3(OpenFileDescriptor openFileDescriptor, boolean focusEditor) { VirtualFile file = openFileDescriptor.getFile(); + boolean isNewEditor = !myVirtualFile2Editor.containsKey(file); // for non-text editors. uml, etc final FileEditorProvider provider = file.getUserData(FileEditorProvider.KEY); + Pair result; if (provider != null && provider.accept(getProject(), file)) { - return Pair.create(new FileEditor[]{provider.createEditor(getProject(), file)}, new FileEditorProvider[]{provider}); + result = Pair.create(new FileEditor[]{provider.createEditor(getProject(), file)}, new FileEditorProvider[]{provider}); + } + else { + //text editor + Editor editor = doOpenTextEditor(openFileDescriptor); + final FileEditor fileEditor = TextEditorProvider.getInstance().getTextEditor(editor); + final FileEditorProvider fileEditorProvider = getProvider(); + result = Pair.create(new FileEditor[]{fileEditor}, new FileEditorProvider[]{fileEditorProvider}); } - //text editor - boolean isNewEditor = !myVirtualFile2Editor.containsKey(openFileDescriptor.getFile()); - Editor editor = doOpenTextEditor(openFileDescriptor); - final FileEditor fileEditor = TextEditorProvider.getInstance().getTextEditor(editor); - final FileEditorProvider fileEditorProvider = getProvider(); - Pair result = Pair.create(new FileEditor[]{fileEditor}, new FileEditorProvider[]{fileEditorProvider}); - modifyTabWell(() -> { - myTestEditorSplitter.openAndFocusTab(file, fileEditor, fileEditorProvider); + myTestEditorSplitter.openAndFocusTab(file, result.first[0], result.second[0]); if (isNewEditor) { eventPublisher().fileOpened(this, file); } }); - return result; } @@ -343,7 +344,16 @@ final class TestEditorManagerImpl extends FileEditorManagerEx implements Disposa @Override public FileEditor getSelectedEditor(@NotNull VirtualFile file) { final Editor editor = getEditor(file); - return editor == null ? null : TextEditorProvider.getInstance().getTextEditor(editor); + if (editor != null) { + return TextEditorProvider.getInstance().getTextEditor(editor); + } + + Pair editorAndProvider = myTestEditorSplitter.getEditorAndProvider(file); + if (editorAndProvider != null) { + return editorAndProvider.first; + } + + return null; } @Override diff --git a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleTypeManagerImpl.java b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleTypeManagerImpl.java index a563e3727011..10b5658f1249 100644 --- a/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleTypeManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/module/impl/ModuleTypeManagerImpl.java @@ -2,7 +2,6 @@ package com.intellij.openapi.module.impl; import com.intellij.diagnostic.PluginException; -import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.*; @@ -33,7 +32,7 @@ public class ModuleTypeManagerImpl extends ModuleTypeManager { public void registerModuleType(ModuleType type, boolean classpathProvider) { for (ModuleType oldType : myModuleTypes.keySet()) { if (oldType.getId().equals(type.getId())) { - LOG.error(PluginManagerCore.createPluginException("Trying to register a module type that clashes with existing one. Old=" + oldType + ", new = " + type, null, type.getClass())); + PluginException.logPluginError(LOG, "Trying to register a module type that clashes with existing one. Old=" + oldType + ", new = " + type, null, type.getClass()); return; } } diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java index da778d79f69f..de51df4c8bdb 100644 --- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java +++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/PushedFilePropertiesUpdaterImpl.java @@ -6,7 +6,7 @@ package com.intellij.openapi.roots.impl; import com.intellij.ProjectTopics; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.openapi.application.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -318,7 +318,7 @@ public class PushedFilePropertiesUpdaterImpl extends PushedFilePropertiesUpdater } } catch (AbstractMethodError ame) { // acceptsDirectory is missed - if (pusher != null) throw PluginManagerCore.createPluginException("Failed to apply pusher " + pusher.getClass(), ame, pusher.getClass()); + if (pusher != null) throw PluginException.createByClass("Failed to apply pusher " + pusher.getClass(), ame, pusher.getClass()); throw ame; } } diff --git a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java index 2427bd68f109..7a4c29f46dec 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/PredefinedSearchScopeProviderImpl.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.psi.search; import com.intellij.ide.IdeBundle; @@ -15,6 +15,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.module.*; +import com.intellij.openapi.project.DumbUnawareHider; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; @@ -40,7 +41,6 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import javax.swing.*; import java.util.*; public class PredefinedSearchScopeProviderImpl extends PredefinedSearchScopeProvider { @@ -252,11 +252,8 @@ public class PredefinedSearchScopeProviderImpl extends PredefinedSearchScopeProv return; } final String name = content.getDisplayName(); - final JComponent component = content.getComponent(); - if (!(component instanceof HierarchyBrowserBase)) { - return; - } - final HierarchyBrowserBase hierarchyBrowserBase = (HierarchyBrowserBase)component; + final DumbUnawareHider dumbUnawareHider = (DumbUnawareHider)content.getComponent(); + final HierarchyBrowserBase hierarchyBrowserBase = (HierarchyBrowserBase)dumbUnawareHider.getContent(); final PsiElement[] elements = hierarchyBrowserBase.getAvailableElements(); if (elements.length > 0) { result.add(new LocalSearchScope(elements, "Hierarchy '" + name + "' (visible nodes only)")); diff --git a/platform/lang-impl/src/com/intellij/psi/search/ProjectScopeBuilderImpl.java b/platform/lang-impl/src/com/intellij/psi/search/ProjectScopeBuilderImpl.java index 1ab649c69de6..5053a3838b12 100644 --- a/platform/lang-impl/src/com/intellij/psi/search/ProjectScopeBuilderImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/search/ProjectScopeBuilderImpl.java @@ -8,6 +8,8 @@ import com.intellij.openapi.module.UnloadedModuleDescription; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.impl.DirectoryInfo; +import com.intellij.openapi.roots.impl.ProjectFileIndexImpl; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiBundle; import org.jetbrains.annotations.NotNull; @@ -75,7 +77,14 @@ public class ProjectScopeBuilderImpl extends ProjectScopeBuilder { if (searchOutsideRootModel) break; } - return new ProjectAndLibrariesScope(myProject, searchOutsideRootModel); + return new ProjectAndLibrariesScope(myProject, searchOutsideRootModel) { + @Override + public boolean contains(@NotNull VirtualFile file) { + DirectoryInfo info = ((ProjectFileIndexImpl)myProjectFileIndex).getInfoForFileOrDirectory(file); + return info.isInProject(file) && + (info.getModule() != null || info.hasLibraryClassRoot() || info.isInLibrarySource(file)); + } + }; } @NotNull diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubVersionMap.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubVersionMap.java index 84a0161b3bbd..c8b9ff6abb43 100644 --- a/platform/lang-impl/src/com/intellij/psi/stubs/StubVersionMap.java +++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubVersionMap.java @@ -15,7 +15,7 @@ */ package com.intellij.psi.stubs; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.lang.Language; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.ParserDefinition; @@ -227,8 +227,8 @@ class StubVersionMap { IStubFileElementType elementType = (IStubFileElementType)owner; if (elementType.getLanguage() instanceof TemplateLanguage && elementType.getStubVersion() < IStubFileElementType.getTemplateStubVersion()) { - LOG.error(PluginManagerCore.createPluginException(elementType.getLanguage() + " stub version should call super.getStubVersion()", - null, elementType.getClass())); + PluginException.logPluginError(LOG, elementType.getLanguage() + " stub version should call super.getStubVersion()", + null, elementType.getClass()); } return elementType.getStubVersion(); } else { diff --git a/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt b/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt index 8aeb5ca909f2..34c4295d2263 100644 --- a/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt +++ b/platform/platform-impl/src/com/intellij/configurationStore/storeUtil.kt @@ -2,6 +2,7 @@ package com.intellij.configurationStore import com.intellij.diagnostic.IdeErrorsDialog +import com.intellij.diagnostic.PluginException import com.intellij.ide.SaveAndSyncHandler import com.intellij.ide.SaveAndSyncHandlerImpl import com.intellij.ide.plugins.PluginManagerCore @@ -127,7 +128,7 @@ fun getStateSpec(persistentStateComponent: PersistentStateComponent): Sta fun getStateSpecOrError(componentClass: Class>): State { return getStateSpec(componentClass) - ?: throw PluginManagerCore.createPluginException("No @State annotation found in $componentClass", null, componentClass) + ?: throw PluginException.createByClass("No @State annotation found in $componentClass", null, componentClass) } fun getStateSpec(originalClass: Class<*>): State? { diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 3d338624b9c3..cbc7ba45f2e9 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -352,6 +352,8 @@ + diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java index 51a78604694d..67a71a94c16e 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectNode.java @@ -17,10 +17,8 @@ package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Disposer; import com.intellij.util.SmartList; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -142,8 +140,6 @@ final class ObjectNode { exceptions.add(e); } removeFromObjectTree(); - - handleExceptions(exceptions); } @Override @@ -152,22 +148,6 @@ final class ObjectNode { }); } - private static void handleExceptions(List exceptions) { - if (!exceptions.isEmpty()) { - for (Throwable exception : exceptions) { - if (!(exception instanceof ProcessCanceledException)) { - LOG.error(exception); - } - } - - ProcessCanceledException pce = ContainerUtil.findInstance(exceptions, ProcessCanceledException.class); - if (pce != null) { - throw pce; - } - exceptions.clear(); - } - } - void removeFromObjectTree() { synchronized (myTree.treeLock) { myTree.putNode(myObject, null); diff --git a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java index 46ce75b15358..e7050fcb1806 100644 --- a/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java +++ b/platform/util/src/com/intellij/openapi/util/objectTree/ObjectTree.java @@ -17,6 +17,7 @@ package com.intellij.openapi.util.objectTree; import com.intellij.openapi.Disposable; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.util.Disposer; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; @@ -26,7 +27,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicLong; public final class ObjectTree { @@ -150,16 +154,18 @@ public final class ObjectTree { } } else { + SmartList exceptions = new SmartList(); ObjectNode parent; synchronized (treeLock) { parent = node.getParent(); } - node.execute(action, new SmartList()); + node.execute(action, exceptions); if (parent != null) { synchronized (treeLock) { parent.removeChild(node); } } + handleExceptions(exceptions); } } finally { @@ -169,6 +175,21 @@ public final class ObjectTree { } } + private static void handleExceptions(List exceptions) { + if (!exceptions.isEmpty()) { + for (Throwable exception : exceptions) { + if (!(exception instanceof ProcessCanceledException)) { + LOG.error(exception); + } + } + + ProcessCanceledException pce = ContainerUtil.findInstance(exceptions, ProcessCanceledException.class); + if (pce != null) { + throw pce; + } + } + } + public boolean isDisposing(@NotNull T disposable) { List> guard = getNodesInExecution(); //noinspection SynchronizationOnLocalVariableOrMethodParameter diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SerializationUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SerializationUtils.java index becaec520526..5029f1a22297 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SerializationUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SerializationUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2018 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2019 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -124,7 +124,7 @@ public class SerializationUtils { if (type instanceof PsiClassType) { final PsiClassType classType = (PsiClassType)type; final PsiClass psiClass = classType.resolve(); - if (psiClass == null || psiClass.isInterface() || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) { + if (psiClass == null || psiClass.hasModifierProperty(PsiModifier.ABSTRACT)) { // to avoid false positives return true; } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/NonCodeMembersContributor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/NonCodeMembersContributor.java index aa210a31301f..5b458c70806e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/NonCodeMembersContributor.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/NonCodeMembersContributor.java @@ -79,13 +79,16 @@ public abstract class NonCodeMembersContributor { if (aClass != null) { for (String superClassName : ClassUtil.getSuperClassesWithCache(aClass).keySet()) { + ProgressManager.checkCanceled(); for (NonCodeMembersContributor enhancer : ourClassSpecifiedContributors.get(superClassName)) { + ProgressManager.checkCanceled(); if (!invokeContributor(qualifierType, place, state, aClass, allDelegates, enhancer)) return false; } } } for (NonCodeMembersContributor contributor : ourAllTypeContributors) { + ProgressManager.checkCanceled(); if (!invokeContributor(qualifierType, place, state, aClass, allDelegates, contributor)) return false; } @@ -102,8 +105,8 @@ public abstract class NonCodeMembersContributor { PsiClass aClass, List allDelegates, NonCodeMembersContributor enhancer) { - ProgressManager.checkCanceled(); for (MyDelegatingScopeProcessor delegatingProcessor : allDelegates) { + ProgressManager.checkCanceled(); enhancer.processDynamicElements(qualifierType, aClass, delegatingProcessor, place, state); if (!delegatingProcessor.wantMore) { return false; diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/impl/constructors.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/impl/constructors.kt index ce2595bc6b56..d237b3858e43 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/impl/constructors.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/impl/constructors.kt @@ -1,8 +1,9 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package org.jetbrains.plugins.groovy.lang.resolve.impl import com.intellij.psi.* import com.intellij.psi.scope.ElementClassHint +import com.intellij.psi.scope.NameHint import com.intellij.psi.scope.ProcessorWithHints import com.intellij.util.SmartList import org.jetbrains.plugins.groovy.lang.psi.util.elementInfo @@ -28,19 +29,23 @@ private fun classConstructors(clazz: PsiClass): List { } private fun runtimeConstructors(clazz: PsiClass, place: PsiElement): List { - val processor = ConstructorProcessor() + val name = clazz.name ?: return emptyList() + val processor = ConstructorProcessor(name) val qualifierType = JavaPsiFacade.getElementFactory(clazz.project).createType(clazz) processNonCodeMembers(qualifierType, processor, place, ResolveState.initial()) return processor.candidates } -private class ConstructorProcessor : ProcessorWithHints(), GroovyResolveKind.Hint, ElementClassHint { +private class ConstructorProcessor(private val name: String) : ProcessorWithHints(), NameHint, GroovyResolveKind.Hint, ElementClassHint { init { + hint(NameHint.KEY, this) hint(GroovyResolveKind.HINT_KEY, this) hint(ElementClassHint.KEY, this) } + override fun getName(state: ResolveState): String? = name + override fun shouldProcess(kind: GroovyResolveKind): Boolean = kind == GroovyResolveKind.METHOD override fun shouldProcess(kind: ElementClassHint.DeclarationKind): Boolean = kind == ElementClassHint.DeclarationKind.METHOD diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlArrayAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlArrayAdapter.java index d5269e83531b..139dffa0d05a 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlArrayAdapter.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlArrayAdapter.java @@ -89,7 +89,11 @@ public class YamlArrayAdapter implements JsonArrayValueAdapter { List adapters = ContainerUtil.newArrayListWithCapacity(items.size()); for (YAMLSequenceItem item: items) { YAMLValue value = item.getValue(); - if (value == null) continue; + if (value == null) { + JsonValueAdapter emptyAdapter = YamlPropertyAdapter.createEmptyValueAdapter(item.getFirstChild(), true); + if (emptyAdapter != null) adapters.add(emptyAdapter); + continue; + } adapters.add(YamlPropertyAdapter.createValueAdapterByType(value)); } return adapters; diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyObjectAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyObjectAdapter.java new file mode 100644 index 000000000000..7a0fefca551d --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyObjectAdapter.java @@ -0,0 +1,74 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.yaml.schema; + +import com.intellij.psi.PsiElement; +import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter; +import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter; +import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class YamlEmptyObjectAdapter implements JsonObjectValueAdapter { + private final PsiElement myElement; + + public YamlEmptyObjectAdapter(PsiElement element) { + myElement = element; + } + + @Override + public boolean isObject() { + return true; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isStringLiteral() { + return false; + } + + @Override + public boolean isNumberLiteral() { + return false; + } + + @Override + public boolean isBooleanLiteral() { + return false; + } + + @NotNull + @Override + public List getPropertyList() { + return ContainerUtil.emptyList(); + } + + @Override + public boolean isNull() { + return false; + } + + @NotNull + @Override + public PsiElement getDelegate() { + return myElement; + } + + @Nullable + @Override + public JsonObjectValueAdapter getAsObject() { + return this; + } + + @Nullable + @Override + public JsonArrayValueAdapter getAsArray() { + return null; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyValueAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyValueAdapter.java new file mode 100644 index 000000000000..0e4ae2a6ee7d --- /dev/null +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlEmptyValueAdapter.java @@ -0,0 +1,65 @@ +// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.yaml.schema; + +import com.intellij.psi.PsiElement; +import com.jetbrains.jsonSchema.extension.adapters.JsonArrayValueAdapter; +import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter; +import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class YamlEmptyValueAdapter implements JsonValueAdapter { + private final PsiElement myElement; + + public YamlEmptyValueAdapter(PsiElement element) { + myElement = element; + } + + @Override + public boolean isObject() { + return false; + } + + @Override + public boolean isArray() { + return false; + } + + @Override + public boolean isStringLiteral() { + return false; + } + + @Override + public boolean isNumberLiteral() { + return false; + } + + @Override + public boolean isBooleanLiteral() { + return false; + } + + @Override + public boolean isNull() { + return true; + } + + @NotNull + @Override + public PsiElement getDelegate() { + return myElement; + } + + @Nullable + @Override + public JsonObjectValueAdapter getAsObject() { + return null; + } + + @Nullable + @Override + public JsonArrayValueAdapter getAsArray() { + return null; + } +} diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java index 22b554af66b9..7833f92d27d9 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java @@ -12,11 +12,13 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.ThreeState; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.extension.JsonLikeSyntaxAdapter; import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter; import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter; +import com.jetbrains.jsonSchema.impl.JsonSchemaType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.yaml.YAMLElementGenerator; @@ -67,6 +69,11 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { return element instanceof YAMLFile || element instanceof YAMLDocument; } + @Override + public boolean acceptsEmptyRoot() { + return true; + } + @Override public PsiElement findElementToCheck(@NotNull PsiElement element) { PsiElement current = element; @@ -87,7 +94,8 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { @Nullable @Override public JsonValueAdapter createValueAdapter(@NotNull PsiElement element) { - return element instanceof YAMLValue ? YamlPropertyAdapter.createValueAdapterByType((YAMLValue)element) : null; + return element instanceof YAMLValue ? YamlPropertyAdapter.createValueAdapterByType((YAMLValue)element) + : (element instanceof YAMLDocument ? new YamlEmptyObjectAdapter(element) : null); } @Override @@ -229,7 +237,7 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { assert property instanceof YAMLKeyValue; YAMLValue value = ((YAMLKeyValue)property).getValue(); if (value == null) return null; - return adjustValue(property); + return adjustValue(value); } @NotNull @@ -249,16 +257,30 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { return ((YAMLKeyValue)property).getName(); } + private YAMLKeyValue findPrecedingKeyValueWithNoValue(PsiElement element) { + if (PsiUtilCore.getElementType(element) == YAMLTokenTypes.INDENT) { + PsiElement prev = element.getPrevSibling(); + prev = prev == null ? null : prev.getPrevSibling(); + if (prev instanceof YAMLKeyValue && ((YAMLKeyValue)prev).getValue() == null) { + return (YAMLKeyValue)prev; + } + } + return null; + } + @NotNull @Override - public PsiElement createProperty(@NotNull String name, @NotNull String value) { - return myGenerator.createYamlKeyValue(name, StringUtil.unquoteString(value)); + public PsiElement createProperty(@NotNull String name, @NotNull String value, PsiElement element) { + YAMLKeyValue keyValue = myGenerator.createYamlKeyValue(name, StringUtil.unquoteString(value)); + return element instanceof YAMLDocument || findPrecedingKeyValueWithNoValue(element) != null + ? myGenerator.createDummyYamlWithText(keyValue.getText()).getDocuments().get(0).getFirstChild() + : keyValue; } @Override - public boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement) { - if (newElement instanceof YAMLKeyValue) { - newElement.getParent().addAfter(myGenerator.createEol(), newElement); + public boolean ensureComma(PsiElement self, PsiElement newElement) { + if (newElement instanceof YAMLKeyValue && self instanceof YAMLKeyValue) { + self.getParent().addAfter(myGenerator.createEol(), self); } return false; } @@ -279,6 +301,33 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { public boolean fixWhitespaceBefore(PsiElement initialElement, PsiElement element) { return initialElement instanceof YAMLValue && initialElement != element; } + + @NotNull + @Override + public String getDefaultValueFromType(@Nullable JsonSchemaType type) { + if (type == null) return ""; + if (type == JsonSchemaType._object) return " "; + if (type == JsonSchemaType._array) return " - "; + return type.getDefaultValue(); + } + + @Override + public PsiElement adjustNewProperty(PsiElement element) { + if (element instanceof YAMLMapping) return element.getFirstChild(); + return element; + } + + @Override + public PsiElement adjustPropertyAnchor(LeafPsiElement element) { + YAMLKeyValue keyValue = findPrecedingKeyValueWithNoValue(element); + assert keyValue != null: "Should come here only for YAMLKeyValue with no value and a following indent"; + keyValue.addBefore(myGenerator.createEol(), null); + keyValue.addBefore(myGenerator.createIndent(element.getTextLength()), null); + PsiElement prev = element.getPrevSibling(); + if (prev != null) prev.delete(); + element.delete(); + return keyValue; + } }; } diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonSchemaHighlightingInspection.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonSchemaHighlightingInspection.java index a3a3733b3f6c..f996ca0b9b1d 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonSchemaHighlightingInspection.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonSchemaHighlightingInspection.java @@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.yaml.YAMLBundle; import org.jetbrains.yaml.psi.YAMLDocument; import org.jetbrains.yaml.psi.YAMLFile; +import org.jetbrains.yaml.psi.YAMLValue; import org.jetbrains.yaml.psi.YamlPsiElementVisitor; import javax.swing.*; @@ -54,9 +55,9 @@ public class YamlJsonSchemaHighlightingInspection extends LocalInspectionTool { List documents = ((YAMLFile)file).getDocuments(); if (documents.size() != 1) return PsiElementVisitor.EMPTY_VISITOR; - PsiElement root = documents.get(0).getTopLevelValue(); - if (root == null) return PsiElementVisitor.EMPTY_VISITOR; - + YAMLDocument document = documents.get(0); + YAMLValue topLevelValue = document.getTopLevelValue(); + PsiElement root = topLevelValue == null ? document : topLevelValue; JsonSchemaService service = JsonSchemaService.Impl.get(file.getProject()); VirtualFile virtualFile = file.getViewProvider().getVirtualFile(); if (!service.isApplicableToFile(virtualFile)) return PsiElementVisitor.EMPTY_VISITOR; diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlPropertyAdapter.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlPropertyAdapter.java index 1dd21044f1ee..32b022d564ea 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlPropertyAdapter.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlPropertyAdapter.java @@ -3,12 +3,16 @@ package org.jetbrains.yaml.schema; import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.PsiElement; +import com.intellij.psi.TokenType; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter; import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter; import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLTokenTypes; import org.jetbrains.yaml.psi.*; import java.util.Collection; @@ -36,7 +40,9 @@ public class YamlPropertyAdapter implements JsonPropertyAdapter { @Override public Collection getValues() { YAMLValue value = myProperty.getValue(); - return value == null ? ContainerUtil.emptyList() : Collections.singletonList(createValueAdapterByType(value)); + return value != null + ? Collections.singletonList(createValueAdapterByType(value)) + : ContainerUtil.createMaybeSingletonList(createEmptyValueAdapter(myProperty, false)); } @NotNull @@ -64,4 +70,23 @@ public class YamlPropertyAdapter implements JsonPropertyAdapter { if (value instanceof YAMLSequence) return new YamlArrayAdapter((YAMLSequence) value); return new YamlGenericValueAdapter(value); } + + @Nullable + public static JsonValueAdapter createEmptyValueAdapter(@NotNull PsiElement context, boolean pinSelf) { + if (context instanceof YAMLKeyValue && ((YAMLKeyValue)context).getValue() == null) { + PsiElement next = PsiTreeUtil.skipWhitespacesForward(context); + if (PsiUtilCore.getElementType(next) == YAMLTokenTypes.EOL) { + next = PsiTreeUtil.skipWhitespacesForward(next); + if (PsiUtilCore.getElementType(next) == YAMLTokenTypes.INDENT && !(PsiTreeUtil.skipWhitespacesForward(next) instanceof YAMLKeyValue)) { + // potentially empty object after newline+indent + return new YamlEmptyObjectAdapter(next); + } + } + } + PsiElement nextSibling = context.getNextSibling(); + PsiElement nodeToHighlight = PsiUtilCore.getElementType(nextSibling) == TokenType.WHITE_SPACE + ? nextSibling + : (pinSelf ? context : context.getLastChild()); + return nodeToHighlight == null ? null : new YamlEmptyValueAdapter(nodeToHighlight); + } } diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java index 4809cbb7acae..3c47234d86d0 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaHighlightingTest.java @@ -809,4 +809,80 @@ public class YamlByJsonSchemaHighlightingTest extends JsonSchemaHighlightingTest " }\n" + "}", "x: 2.99792458e8"); } + + public void testTreatEmptyValueAsNull() throws Exception { + doTest("{\n" + + " \"properties\": {\n" + + " \"x\": {\n" + + " \"type\": \"number\"\n" + + " }\n" + + " }\n" + + "}", "x: "); + doTest("{\n" + + " \"properties\": {\n" + + " \"x\": {\n" + + " \"type\": \"null\"\n" + + " }\n" + + " }\n" + + "}", "x: "); + } + + public void testEmptyValueInArray() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"array\",\n" + + " \"items\": {\n" + + " \"type\": \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + "}", "versionAsStringArray:\n" + + " - \n" + + " -\n" + + " - a"); + } + + public void testEmptyFile() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"array\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"versionAsStringArray\"]\n" + + "}", ""); + } + + public void testEmptyValueBetweenProps() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"object\",\n" + + " \"properties\": {\n" + + " \"xxx\": {\n" + + " \"type\": \"number\"\n" + + " },\n" + + " \"yyy\": {\n" + + " \"type\": \"string\"\n" + + " },\n" + + " \"zzz\": {\n" + + " \"type\": \"number\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"xxx\", \"yyy\", \"zzz\"]\n" + + " }\n" + + " },\n" + + " \"required\": [\"versionAsStringArray\"]\n" + + "}", "versionAsStringArray:\n" + + " zzz: 0\n" + + " yyy: \n" + + " xxx: 0"); + } } diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java index 9a67307ea70e..c8e08ca150aa 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java @@ -48,4 +48,69 @@ public class YamlByJsonSchemaQuickFixTest extends JsonSchemaQuickFixTestBase { "}", "a: 5\nb: 6\nc: 7", "Remove prohibited property 'b'", "a: 5\n" + "c: 7"); } + + public void testEmptyFile() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"array\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"versionAsStringArray\"]\n" + + "}", "", "Add missing property 'versionAsStringArray'", "versionAsStringArray:\n" + + " - "); + } + + public void testEmptyObject() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"object\",\n" + + " \"properties\": {\n" + + " \"xxx\": {\n" + + " \"type\": \"array\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"xxx\"]\n" + + " }\n" + + " },\n" + + " \"required\": [\"versionAsStringArray\"]\n" + + "}", "versionAsStringArray:\n" + + " ", "Add missing property 'xxx'", "versionAsStringArray:\n" + + " xxx:\n" + + " - "); + } + + public void testEmptyObjectMultipleProps() throws Exception { + doTest("{\n" + + " \"type\": \"object\",\n" + + "\n" + + " \"properties\": {\n" + + " \"versionAsStringArray\": {\n" + + " \"type\": \"object\",\n" + + " \"properties\": {\n" + + " \"xxx\": {\n" + + " \"type\": \"number\"\n" + + " },\n" + + " \"yyy\": {\n" + + " \"type\": \"string\"\n" + + " },\n" + + " \"zzz\": {\n" + + " \"type\": \"number\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"xxx\", \"yyy\", \"zzz\"]\n" + + " }\n" + + " },\n" + + " \"required\": [\"versionAsStringArray\"]\n" + + "}", "versionAsStringArray:\n" + + " ","Add missing properties 'xxx', 'yyy', 'zzz'", "versionAsStringArray:\n" + + " xxx: 0\n" + + " yyy:\n" + + " zzz: 0"); + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 4709754f8dd6..38bab08cec6c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -2,7 +2,7 @@ package com.jetbrains.python.psi.impl; import com.intellij.codeInsight.controlflow.Instruction; -import com.intellij.ide.plugins.PluginManagerCore; +import com.intellij.diagnostic.PluginException; import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Ref; @@ -385,7 +385,7 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere } } catch (AbstractMethodError e) { - LOG.info(PluginManagerCore.createPluginException("Failed to get expression type via " + provider.getClass(), e, provider.getClass())); + LOG.info(PluginException.createByClass("Failed to get expression type via " + provider.getClass(), e, provider.getClass())); } } return null;