diff --git a/README.md b/README.md index 995ed97309b5..3fe0bb0a5ed0 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ and build numbers for older releases of IntelliJ IDEA can be found on the page o If you intend to make open source contributions to the IntelliJ Platform, see [Contributing to the IntelliJ Project](http://www.jetbrains.org/display/IJOS/Contribute) for more information. +_**Tags:**_ The GitHub repository doesn't contain any tags for performance reasons. If you need to check out a tag, fetch it from [the repository mirror](git://git.jetbrains.org/idea/community.git) which contains all of them. There are scripts `fetch-tag.sh` and `list-tags.sh` which simplify the task. + _**Speed Tip:**_ If the complete repository history isn't needed then using a shallow clone (`git clone --depth 1`) will save significant time. These Git operations can also be done through the [IntelliJ IDEA user interface](https://www.jetbrains.com/help/idea/using-git-integration.html). diff --git a/build/conf/nsis/idea.nsi b/build/conf/nsis/idea.nsi index 806516db0b0b..b2b4a7fedea4 100644 --- a/build/conf/nsis/idea.nsi +++ b/build/conf/nsis/idea.nsi @@ -563,7 +563,7 @@ update_install_dir: ${LogText} "" ${LogText} " NOTE: Specified install dir: $INSTDIR is required administrative rights." ${LogText} " It is corresponding with the admin mode in silent config file." - ${LogText} " But installation has been run with user mode. So install dir has been changed to: " + ${LogText} " But installation has been run with user mode. So install folder has been changed to the default: " StrCpy $INSTDIR "$LOCALAPPDATA\${MANUFACTURER}\${PRODUCT_WITH_VER}" ${LogText} " $INSTDIR " ${LogText} "" @@ -1313,7 +1313,10 @@ uac_elevate: uac_err: Abort uac_elevation_aborted: - IfSilent done set_install_dir + IfSilent 0 set_install_dir + ${LogText} "" + ${LogText} " NOTE: UAC elevation has been aborted. Installation dir will be changed." + ${LogText} "" set_install_dir: StrCpy $INSTDIR "$LOCALAPPDATA\${MANUFACTURER}\${PRODUCT_WITH_VER}" goto done diff --git a/fetch-tag.sh b/fetch-tag.sh new file mode 100755 index 000000000000..ecfb44880b09 --- /dev/null +++ b/fetch-tag.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# +# Fetches the given tag and creates it locally. +# Usage: ./fetch-tag.sh +# Example: ./fetch-tag.sh idea/183.4139.22 + + +if [[ -z "$1" ]] ; then + echo " + Usage: ./fetch-tag.sh + Example: ./fetch-tag.sh idea/183.4139.22" + exit 1 +fi + +TAG="$1" + +set -e # Any command which returns non-zero exit code will cause this shell script to exit immediately + +git fetch -q git://git.jetbrains.org/idea/community.git $TAG +git tag $TAG FETCH_HEAD + +HASH=`git rev-parse $TAG` + +echo "The tag $TAG has been created at $HASH" + diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java index 170ab8e576ab..7fac237ac2b1 100644 --- a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java +++ b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java @@ -14,7 +14,7 @@ import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.JavaStackFrame; import com.intellij.debugger.engine.SuspendContextImpl; import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerUtilsImpl; +import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.debugger.jdi.StackFrameProxyImpl; import com.intellij.debugger.settings.DebuggerSettings; import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl; @@ -328,9 +328,8 @@ public class PopFrameAction extends DebuggerAction implements DumbAware { enable = proxy.getVirtualMachine().canPopFrames(); } - Project project = e.getProject(); if((ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) - && project != null && DebuggerUtilsImpl.isCurrentJavaDebugProcess(project)) { + && DebuggerUtilsEx.isInJavaSession(e)) { e.getPresentation().setEnabled(enable); } else { diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java index 3ce1a41f1308..09541281c39f 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java @@ -733,6 +733,7 @@ public class DebuggerSession implements AbstractDebuggerSession { @Override protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) { + notification.hideBalloon(); SuspendContextImpl suspendContext = SoftReference.dereference(myContextRef); if (suspendContext != null) { switchContext(suspendContext); diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java index 10639c6f86a0..c5a579410366 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsImpl.java @@ -5,7 +5,6 @@ import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.actions.DebuggerAction; import com.intellij.debugger.engine.DebugProcess; import com.intellij.debugger.engine.DebugProcessImpl; -import com.intellij.debugger.engine.JavaDebugProcess; import com.intellij.debugger.engine.StackFrameContext; import com.intellij.debugger.engine.evaluation.CodeFragmentKind; import com.intellij.debugger.engine.evaluation.EvaluateException; @@ -35,8 +34,6 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.net.NetUtils; import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters; import com.intellij.util.xmlb.XmlSerializer; -import com.intellij.xdebugger.XDebugSession; -import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.XExpression; import com.intellij.xdebugger.impl.breakpoints.XExpressionState; import com.sun.jdi.*; @@ -290,9 +287,4 @@ public class DebuggerUtilsImpl extends DebuggerUtilsEx{ } return StreamEx.empty(); } - - public static boolean isCurrentJavaDebugProcess(@NotNull Project project) { - XDebugSession session = XDebuggerManager.getInstance(project).getCurrentSession(); - return session != null && session.getDebugProcess() instanceof JavaDebugProcess; - } } \ No newline at end of file diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractValue.java index 9b4c82d5940b..f1a6a0a1cb82 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractValue.java @@ -16,9 +16,9 @@ package com.intellij.codeInspection.dataFlow; import com.intellij.codeInspection.dataFlow.value.*; -import com.intellij.psi.PsiPrimitiveType; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import com.intellij.util.Function; +import com.siyeh.ig.psiutils.MethodCallUtils; import org.jetbrains.annotations.NotNull; import java.util.OptionalInt; @@ -30,6 +30,37 @@ public abstract class ContractValue { } abstract DfaValue makeDfaValue(DfaValueFactory factory, DfaCallArguments arguments); + + public DfaValue fromCall(DfaValueFactory factory, PsiCallExpression call) { + PsiMethod method = call.resolveMethod(); + if (method == null) return DfaUnknownValue.getInstance(); + PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList == null) return DfaUnknownValue.getInstance(); + DfaValue qualifierValue = null; + if (call instanceof PsiMethodCallExpression) { + PsiExpression qualifier = ((PsiMethodCallExpression)call).getMethodExpression().getQualifierExpression(); + qualifierValue = factory.createValue(qualifier); + } + if (qualifierValue == null) { + qualifierValue = DfaUnknownValue.getInstance(); + } + boolean varArgCall = MethodCallUtils.isVarArgCall(call); + PsiExpression[] args = argumentList.getExpressions(); + PsiParameter[] parameters = method.getParameterList().getParameters(); + DfaValue[] argValues = new DfaValue[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + PsiParameter parameter = parameters[i]; + DfaValue argValue = null; + if (i < args.length && (!varArgCall || i < parameters.length - 1)) { + argValue = factory.createValue(args[i]); + } + if (argValue == null) { + argValue = DfaUnknownValue.getInstance(); + } + argValues[i] = argValue; + } + return makeDfaValue(factory, new DfaCallArguments(qualifierValue, argValues, JavaMethodContractUtil.isPure(method))); + } /** * @param other other contract condition diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotation.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotation.java new file mode 100644 index 000000000000..b76df920c376 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotation.java @@ -0,0 +1,82 @@ +// 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. +package com.intellij.codeInsight; + +import com.intellij.psi.PsiModifierListOwner; +import com.intellij.psi.PsiNameValuePair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Wrapper for info about external annotation. + */ +public class ExternalAnnotation { + + /** + * Annotation owner + */ + @NotNull + private final PsiModifierListOwner owner; + + /** + * Annotation name + */ + @NotNull + private final String annotationFQName; + + /** + * Annotation content + */ + @Nullable + private final PsiNameValuePair[] values; + + public ExternalAnnotation(@NotNull PsiModifierListOwner owner, + @NotNull String annotationFQName, + @Nullable PsiNameValuePair[] values) { + this.owner = owner; + this.annotationFQName = annotationFQName; + this.values = values; + } + + @NotNull + public PsiModifierListOwner getOwner() { + return owner; + } + + @NotNull + public String getAnnotationFQName() { + return annotationFQName; + } + + public PsiNameValuePair[] getValues() { + return values; + } + + @Override + public String toString() { + return "ExternalAnnotation{" + + "owner=" + owner + + ", annotationFQName='" + annotationFQName + '\'' + + ", values=" + Arrays.toString(values) + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExternalAnnotation that = (ExternalAnnotation)o; + return Objects.equals(owner, that.owner) && + Objects.equals(annotationFQName, that.annotationFQName) && + Arrays.equals(values, that.values); + } + + @Override + public int hashCode() { + int result = Objects.hash(owner, annotationFQName); + result = 31 * result + Arrays.hashCode(values); + return result; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index 79fbeeb822dd..385494af553c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -46,17 +46,18 @@ import com.intellij.openapi.vfs.*; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; import com.intellij.psi.codeStyle.JavaCodeStyleSettings; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.Processor; -import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.messages.MessageBus; import com.intellij.util.ui.OptionsMessageDialog; -import gnu.trove.THashSet; +import one.util.streamex.StreamEx; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,10 +66,10 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; /** * @author anna @@ -117,7 +118,6 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } - final String packageName = ((PsiJavaFile)containingFile).getPackageName(); final VirtualFile containingVirtualFile = containingFile.getVirtualFile(); LOG.assertTrue(containingVirtualFile != null); final List entries = ProjectRootManager.getInstance(project).getFileIndex().getOrderEntriesForFile(containingVirtualFile); @@ -125,13 +125,14 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM notifyAfterAnnotationChanging(listOwner, annotationFQName, false); return; } + ExternalAnnotation annotation = new ExternalAnnotation(listOwner, annotationFQName, value); for (final OrderEntry entry : entries) { if (entry instanceof ModuleOrderEntry) continue; VirtualFile[] roots = AnnotationOrderRootType.getFiles(entry); roots = filterByReadOnliness(roots); if (roots.length > 0) { - chooseRootAndAnnotateExternally(listOwner, annotationFQName, fromFile, project, packageName, roots, value); + chooseRootAndAnnotateExternally(roots, annotation); } else { if (application.isUnitTestMode() || application.isHeadlessEnvironment()) { @@ -140,7 +141,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM } DumbService.getInstance(project).setAlternativeResolveEnabled(true); try { - if (!setupRootAndAnnotateExternally(entry, project, listOwner, annotationFQName, fromFile, packageName, value)) { + if (!setupRootAndAnnotateExternally(entry, project, annotation)) { throw new CanceledConfigurationException(); } } @@ -152,6 +153,244 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM } } + private void annotateExternally(@NotNull VirtualFile root, @NotNull ExternalAnnotation annotation) { + annotateExternally(root, Collections.singletonList(annotation)); + } + + /** + * Tries to add external annotations into given root if possible. + * Notifies about each addition result separately. + */ + public void annotateExternally(@NotNull VirtualFile root, @NotNull List annotations) { + Project project = myPsiManager.getProject(); + + Map, List> annotationsByFiles = annotations.stream() + .collect(Collectors.groupingBy(annotation -> Optional.ofNullable(getFileForAnnotations(root, annotation.getOwner(), project)))); + + WriteCommandAction.writeCommandAction(project).run(() -> { + try { + for (Map.Entry, List> entry : annotationsByFiles.entrySet()) { + XmlFile annotationsFile = entry.getKey().orElse(null); + List fileAnnotations = entry.getValue(); + annotateExternally(annotationsFile, fileAnnotations); + } + + UndoManager.getInstance(project).undoableActionPerformed(new BasicUndoableAction() { + @Override + public void undo() { + dropCache(); + notifyChangedExternally(); + } + + @Override + public void redo() { + dropCache(); + notifyChangedExternally(); + } + }); + } finally { + dropCache(); + } + }); + } + + private void annotateExternally(@Nullable XmlFile annotationsFile, @NotNull List annotations) { + XmlTag rootTag = extractRootTag(annotationsFile); + + TreeMap> ownerToAnnotations = StreamEx.of(annotations) + .mapToEntry(annotation -> StringUtil.escapeXml(getExternalName(annotation.getOwner())), Function.identity()) + .distinct() + .grouping(() -> new TreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder()))); + + if (rootTag == null) { + ownerToAnnotations.values().stream().flatMap(List::stream).forEach(annotation -> + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false)); + return; + } + + List savedAnnotations = new ArrayList<>(); + XmlTag startTag = null; + + for (Map.Entry> entry : ownerToAnnotations.entrySet()) { + @NonNls String ownerName = entry.getKey(); + List annotationList = entry.getValue(); + for (ExternalAnnotation annotation : annotationList) { + + if (ownerName == null) { + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); + continue; + } + + try { + startTag = addAnnotation(rootTag, ownerName, annotation, startTag); + savedAnnotations.add(annotation); + } + catch (IncorrectOperationException e) { + LOG.error(e); + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); + } + finally { + dropCache(); + markForUndo(annotation.getOwner().getContainingFile()); + } + } + } + + commitChanges(annotationsFile); + savedAnnotations.forEach(annotation -> + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), true)); + } + + @Contract("null -> null") + private static XmlTag extractRootTag(XmlFile annotationsFile) { + if (annotationsFile == null) { + return null; + } + + XmlDocument document = annotationsFile.getDocument(); + if (document == null) { + return null; + } + + return document.getRootTag(); + } + + private static void markForUndo(@Nullable PsiFile containingFile) { + if (containingFile == null) { + return; + } + + VirtualFile virtualFile = containingFile.getVirtualFile(); + if (virtualFile != null && virtualFile.isInLocalFileSystem()) { + UndoUtil.markPsiFileForUndo(containingFile); + } + } + + /** + * Adds annotation sub tag after startTag. + * If startTag is {@code null} searches for all sub tags of rootTag and starts from the first. + * + * @param rootTag root tag to insert subtag into + * @param ownerName annotations owner name + * @param annotation external annotation + * @param startTag start tag + * @return added sub tag + */ + @NotNull + private XmlTag addAnnotation(@NotNull XmlTag rootTag, @NotNull String ownerName, + @NotNull ExternalAnnotation annotation, @Nullable XmlTag startTag) { + if (startTag == null) { + startTag = PsiTreeUtil.findChildOfType(rootTag, XmlTag.class); + } + + XmlTag prevItem = null; + XmlTag curItem = startTag; + + while (curItem != null) { + XmlTag addedItem = addAnnotation(rootTag, ownerName, annotation, curItem, prevItem); + if (addedItem != null) { + return addedItem; + } + + prevItem = curItem; + curItem = PsiTreeUtil.getNextSiblingOfType(curItem, XmlTag.class); + } + + return addItemTag(rootTag, prevItem, ownerName, annotation); + } + + /** + * Adds annotation sub tag into curItem or between prevItem and curItem. + * Adds into curItem if curItem contains external annotations for owner. + * Adds between curItem and prevItem if owner's external name < cur item owner external name. + * Otherwise does nothing, returns null. + * + * @param rootTag root tag to insert sub tag into + * @param ownerName annotation owner + * @param annotation external annotation + * @param curItem current item with annotations + * @param prevItem previous item with annotations + * @return added tag + */ + @Nullable + private XmlTag addAnnotation(@NotNull XmlTag rootTag, @NotNull String ownerName, @NotNull ExternalAnnotation annotation, + @NotNull XmlTag curItem, @Nullable XmlTag prevItem) { + + @NonNls String curItemName = curItem.getAttributeValue("name"); + if (curItemName == null) { + curItem.delete(); + return null; + } + + int compare = ownerName.compareTo(curItemName); + + if (compare == 0) { + //already have external annotations for owner + return appendItemAnnotation(curItem, annotation); + } + + if (compare < 0) { + return addItemTag(rootTag, prevItem, ownerName, annotation); + } + + return null; + } + + @NotNull + private XmlTag addItemTag(@NotNull XmlTag rootTag, + @Nullable XmlTag anchor, + @NotNull String ownerName, + @NotNull ExternalAnnotation annotation) { + XmlElementFactory elementFactory = XmlElementFactory.getInstance(myPsiManager.getProject()); + XmlTag newItemTag = elementFactory.createTagFromText(createItemTag(ownerName, annotation)); + + PsiElement addedElement = rootTag.addAfter(newItemTag, anchor); + if (!(addedElement instanceof XmlTag)) { + throw new IncorrectOperationException("Failed to add annotation " + annotation + " after " + anchor); + } + + return (XmlTag)addedElement; + } + + /** + * Appends annotation sub tag into itemTag. It can happen only if item tag belongs to annotation owner. + * + * @param itemTag item tag with annotations + * @param annotation external annotation + */ + private XmlTag appendItemAnnotation(@NotNull XmlTag itemTag, @NotNull ExternalAnnotation annotation) { + @NonNls String annotationFQName = annotation.getAnnotationFQName(); + PsiNameValuePair[] values = annotation.getValues(); + + XmlElementFactory elementFactory = XmlElementFactory.getInstance(myPsiManager.getProject()); + + XmlTag anchor = null; + for (XmlTag itemAnnotation : itemTag.getSubTags()) { + String curAnnotationName = itemAnnotation.getAttributeValue("name"); + if (curAnnotationName == null) { + itemAnnotation.delete(); + continue; + } + + if (annotationFQName.equals(curAnnotationName)) { + // found tag for same annotation, replacing + itemAnnotation.delete(); + break; + } + + anchor = itemAnnotation; + } + + XmlTag newAnnotationTag = elementFactory.createTagFromText(createAnnotationTag(annotationFQName, values)); + + PsiElement addedElement = itemTag.addAfter(newAnnotationTag, anchor); + if (!(addedElement instanceof XmlTag)) { + throw new IncorrectOperationException("Failed to add annotation " + annotation + " after " + anchor); + } + + return itemTag; + } + @Nullable private List findExternalAnnotationsXmlFiles(@NotNull PsiModifierListOwner listOwner) { List psiFiles = findExternalAnnotationsFiles(listOwner); @@ -169,39 +408,17 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM private boolean setupRootAndAnnotateExternally(@NotNull final OrderEntry entry, @NotNull final Project project, - @NotNull final PsiModifierListOwner listOwner, - @NotNull final String annotationFQName, - @NotNull final PsiFile fromFile, - @NotNull final String packageName, - @Nullable final PsiNameValuePair[] value) { + @NotNull final ExternalAnnotation annotation) { final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor(); descriptor.setTitle(ProjectBundle.message("external.annotations.root.chooser.title", entry.getPresentableName())); descriptor.setDescription(ProjectBundle.message("external.annotations.root.chooser.description")); final VirtualFile newRoot = FileChooser.chooseFile(descriptor, project, null); if (newRoot == null) { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); return false; } - String externalName = getExternalName(listOwner); - WriteCommandAction.writeCommandAction(project).run(() -> { - appendChosenAnnotationsRoot(entry, newRoot); - XmlFile xmlFileInRoot = findXmlFileInRoot(findExternalAnnotationsXmlFiles(listOwner), newRoot); - if (xmlFileInRoot != null) { //file already exists under appeared content root - if (!FileModificationService.getInstance().preparePsiElementForWrite(xmlFileInRoot)) { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - return; - } - annotateExternally(listOwner, annotationFQName, xmlFileInRoot, fromFile, value, externalName); - } - else { - final XmlFile annotationsXml = createAnnotationsXml(newRoot, packageName); - if (annotationsXml != null) { - List createdFiles = new SmartList<>(annotationsXml); - cacheExternalAnnotations(packageName, fromFile, createdFiles); - } - annotateExternally(listOwner, annotationFQName, annotationsXml, fromFile, value, externalName); - } - }); + WriteCommandAction.writeCommandAction(project).run(() -> appendChosenAnnotationsRoot(entry, newRoot)); + annotateExternally(newRoot, annotation); return true; } @@ -220,23 +437,17 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM return null; } - private void chooseRootAndAnnotateExternally(@NotNull final PsiModifierListOwner listOwner, - @NotNull final String annotationFQName, - @NotNull final PsiFile fromFile, - @NotNull final Project project, - @NotNull final String packageName, - @NotNull VirtualFile[] roots, - @Nullable final PsiNameValuePair[] value) { + private void chooseRootAndAnnotateExternally(@NotNull VirtualFile[] roots, @NotNull ExternalAnnotation annotation) { if (roots.length > 1) { JBPopupFactory.getInstance().createListPopup(new BaseListPopupStep("Annotation Roots", roots) { @Override public void canceled() { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); + notifyAfterAnnotationChanging(annotation.getOwner(), annotation.getAnnotationFQName(), false); } @Override public PopupStep onChosen(@NotNull final VirtualFile file, final boolean finalChoice) { - annotateExternally(file, listOwner, project, packageName, annotationFQName, fromFile, value); + annotateExternally(file, annotation); return FINAL_CHOICE; } @@ -253,7 +464,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM }).showInBestPositionFor(DataManager.getInstance().getDataContext()); } else { - annotateExternally(roots[0], listOwner, project, packageName, annotationFQName, fromFile, value); + annotateExternally(roots[0], annotation); } } @@ -263,55 +474,6 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM return VfsUtilCore.toVirtualFileArray(result); } - private void annotateExternally(@NotNull final VirtualFile root, - @NotNull final PsiModifierListOwner listOwner, - @NotNull final Project project, - @NotNull final String packageName, - @NotNull final String annotationFQName, - @NotNull final PsiFile fromFile, - @Nullable final PsiNameValuePair[] value) { - List xmlFiles = findExternalAnnotationsXmlFiles(listOwner); - - final XmlFile existingXml = findXmlFileInRoot(xmlFiles, root); - if (existingXml != null && !FileModificationService.getInstance().preparePsiElementForWrite(existingXml)) { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - return; - } - - Set annotationFiles = xmlFiles == null ? new THashSet<>() : new THashSet<>(xmlFiles); - String externalName = getExternalName(listOwner); - WriteCommandAction.writeCommandAction(project).run(() -> { - if (existingXml != null) { - annotateExternally(listOwner, annotationFQName, existingXml, fromFile, value, externalName); - } - else { - XmlFile newXml = createAnnotationsXml(root, packageName); - if (newXml == null) { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - } - else { - annotationFiles.add(newXml); - cacheExternalAnnotations(packageName, fromFile, new SmartList<>(annotationFiles)); - annotateExternally(listOwner, annotationFQName, newXml, fromFile, value, externalName); - } - } - - UndoManager.getInstance(project).undoableActionPerformed(new BasicUndoableAction() { - @Override - public void undo() { - dropCache(); - notifyChangedExternally(); - } - - @Override - public void redo() { - dropCache(); - notifyChangedExternally(); - } - }); - }); - } - @Override public boolean deannotate(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { ApplicationManager.getApplication().assertIsDispatchThread(); @@ -544,71 +706,6 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM dropCache(); } - private void annotateExternally(@NotNull final PsiModifierListOwner listOwner, - @NotNull final String annotationFQName, - @Nullable final XmlFile xmlFile, - @NotNull final PsiFile codeUsageFile, - @Nullable final PsiNameValuePair[] values, - @Nullable final String externalName) { - if (xmlFile == null) { - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - return; - } - try { - final XmlDocument document = xmlFile.getDocument(); - if (document != null) { - final XmlTag rootTag = document.getRootTag(); - if (externalName == null) { - LOG.info("member without external name: " + listOwner); - } - if (rootTag != null && externalName != null) { - XmlTag anchor = null; - for (XmlTag item : rootTag.getSubTags()) { - int compare = Comparing.compare(externalName, StringUtil.unescapeXml(item.getAttributeValue("name"))); - if (compare == 0) { - anchor = null; - for (XmlTag annotation : item.getSubTags()) { - compare = Comparing.compare(annotationFQName, annotation.getAttributeValue("name")); - if (compare == 0) { - annotation.delete(); - break; - } - anchor = annotation; - } - XmlTag newTag = XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText( - createAnnotationTag(annotationFQName, values)); - item.addAfter(newTag, anchor); - commitChanges(xmlFile); - notifyAfterAnnotationChanging(listOwner, annotationFQName, true); - return; - } - if (compare < 0) break; - anchor = item; - } - @NonNls String text = - "\n"; - text += createAnnotationTag(annotationFQName, values); - text += ""; - rootTag.addAfter(XmlElementFactory.getInstance(myPsiManager.getProject()).createTagFromText(text), anchor); - commitChanges(xmlFile); - notifyAfterAnnotationChanging(listOwner, annotationFQName, true); - return; - } - } - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - } - catch (IncorrectOperationException e) { - LOG.error(e); - notifyAfterAnnotationChanging(listOwner, annotationFQName, false); - } - finally { - dropCache(); - if (codeUsageFile.getVirtualFile().isInLocalFileSystem()) { - UndoUtil.markPsiFileForUndo(codeUsageFile); - } - } - } - private static void sortItems(@NotNull XmlFile xmlFile) { XmlDocument document = xmlFile.getDocument(); if (document == null) { @@ -653,6 +750,13 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM FileDocumentManager.getInstance().saveDocument(doc); } + @NonNls + @NotNull + private static String createItemTag(@NotNull String ownerName, @NotNull ExternalAnnotation annotation) { + String annotationTag = createAnnotationTag(annotation.getAnnotationFQName(), annotation.getValues()); + return String.format("%s", ownerName, annotationTag); + } + @NonNls @NotNull @VisibleForTesting @@ -689,6 +793,7 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM } catch (IOException e) { LOG.error(e); + return null; } } root = subdir; @@ -711,6 +816,32 @@ public class ExternalAnnotationsManagerImpl extends ReadableExternalAnnotationsM return null; } + @Nullable + private XmlFile getFileForAnnotations(@NotNull VirtualFile root, @NotNull PsiModifierListOwner owner, Project project) { + return WriteCommandAction.writeCommandAction(project).compute(() -> { + final PsiFile containingFile = owner.getOriginalElement().getContainingFile(); + if (!(containingFile instanceof PsiJavaFile)) { + return null; + } + String packageName = ((PsiJavaFile)containingFile).getPackageName(); + + List annotationsFiles = findExternalAnnotationsXmlFiles(owner); + + XmlFile fileInRoot = findXmlFileInRoot(annotationsFiles, root); + if (fileInRoot != null && FileModificationService.getInstance().preparePsiElementForWrite(fileInRoot)) { + return fileInRoot; + } + + XmlFile newAnnotationsFile = createAnnotationsXml(root, packageName); + if (newAnnotationsFile == null) { + return null; + } + + registerExternalAnnotations(containingFile, newAnnotationsFile); + return newAnnotationsFile; + }); + } + @Override public boolean hasAnnotationRootsForFile(@NotNull VirtualFile file) { if (hasAnyAnnotationsRoots()) { diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java index 824783f6705f..0a3b4cbb1ae7 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/SurroundWithTryCatchFix.java @@ -28,6 +28,7 @@ import com.intellij.psi.*; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; import com.siyeh.ig.psiutils.ControlFlowUtils; +import com.siyeh.ig.psiutils.ExpressionUtils; import org.jetbrains.annotations.NotNull; /** @@ -43,7 +44,7 @@ public class SurroundWithTryCatchFix implements IntentionAction { element instanceof PsiResourceVariable || (element instanceof PsiExpression && !(element instanceof PsiMethodReferenceExpression) && - ControlFlowUtils.canExtractStatement((PsiExpression)element, false))) { + ControlFlowUtils.canExtractStatement(ExpressionUtils.getTopLevelExpression((PsiExpression)element)))) { myElement = element; } } @@ -78,7 +79,7 @@ public class SurroundWithTryCatchFix implements IntentionAction { editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(0, 0)); if (myElement instanceof PsiExpression) { - myElement = RefactoringUtil.ensureCodeBlock((PsiExpression)myElement); + myElement = RefactoringUtil.ensureCodeBlock(ExpressionUtils.getTopLevelExpression((PsiExpression)myElement)); } myElement = RefactoringUtil.getParentStatement(myElement, false); if (myElement == null) return; diff --git a/java/java-impl/src/com/intellij/codeInspection/ReadWriteStringCanBeUsedInspection.java b/java/java-impl/src/com/intellij/codeInspection/ReadWriteStringCanBeUsedInspection.java index e3e6cbde6976..5c77a1be31ac 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ReadWriteStringCanBeUsedInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ReadWriteStringCanBeUsedInspection.java @@ -43,7 +43,7 @@ public class ReadWriteStringCanBeUsedInspection extends AbstractBaseJavaLocalIns ProblemHighlightType highlight; String message = "Can be replaced with 'Files.writeString()'"; if (level.isAtLeast(LanguageLevel.JDK_12) || isNonUtf8Charset(bytesExpression.getArgumentList().getExpressions()[0])) { - highlight = ProblemHighlightType.WARNING; + highlight = ProblemHighlightType.GENERIC_ERROR_OR_WARNING; } else { highlight = ProblemHighlightType.INFORMATION; } diff --git a/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java b/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java index a963301e68f6..f23e5e093640 100644 --- a/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/ReplaceNullCheckInspection.java @@ -62,8 +62,8 @@ public class ReplaceNullCheckInspection extends AbstractBaseJavaLocalInspectionT PsiStatement nextToDelete = context.myNextToDelete; int maybeImplicitElseLength = nextToDelete != null ? nextToDelete.getTextLength() : 0; boolean isInfoLevel = noWarningReplacementBigger && ifStatement.getTextLength() + maybeImplicitElseLength - context.getLenAfterReplace() < MINIMAL_WARN_DELTA_SIZE; - if (!isOnTheFly && isInfoLevel) return; ProblemHighlightType highlight = getHighlight(context, isInfoLevel); + if (!isOnTheFly && highlight == ProblemHighlightType.INFORMATION) return; holder.registerProblem(ifStatement.getFirstChild(), InspectionsBundle.message("inspection.require.non.null.message", method), highlight, new ReplaceWithRequireNonNullFix(method, false)); } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java index 3c43714e25a7..e4868dc4a333 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java @@ -378,12 +378,17 @@ public abstract class BaseExternalAnnotationsManager extends ExternalAnnotations throw new UnsupportedOperationException(); } - void cacheExternalAnnotations(@SuppressWarnings("UnusedParameters") @NotNull String packageName, - @NotNull PsiFile fromFile, - @NotNull List annotationFiles) { + protected void registerExternalAnnotations(@NotNull PsiFile fromFile, @NotNull PsiFile annotationsFile) { VirtualFile virtualFile = fromFile.getVirtualFile(); if (virtualFile != null) { - myExternalAnnotationsCache.put(virtualFile, annotationFiles); + myExternalAnnotationsCache.compute(virtualFile, (k, v) -> { + if (v == null || v == NULL_LIST) { + return new SmartList<>(annotationsFile); + } + + v.add(annotationsFile); + return v; + }); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index 1f8382f2658c..f4c4de056864 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -59,7 +59,6 @@ public class StubBuildingVisitor extends ClassVisitor { private final Function myMapping; private final boolean myAnonymousInner; private final boolean myLocalClassInner; - private boolean myAsm6Mode; private String myInternalName; private PsiClassStub myResult; private PsiModifierListStub myModList; @@ -79,8 +78,6 @@ public class StubBuildingVisitor extends ClassVisitor { myMapping = createMapping(classSource); myAnonymousInner = anonymousInner; myLocalClassInner = localClassInner; - //noinspection ConstantConditions - myAsm6Mode = ASM_API <= Opcodes.ASM6 || classSource == null && innersStrategy.getClass().getName().startsWith("org.jetbrains.kotlin."); } public PsiClassStub getResult() { @@ -277,7 +274,6 @@ public class StubBuildingVisitor extends ClassVisitor { if (innerClass != null) { StubBuildingVisitor visitor = new StubBuildingVisitor<>(innerClass, myInnersStrategy, myResult, access, innerName, isAnonymousInner, isLocalClassInner); - visitor.myAsm6Mode = myAsm6Mode; myInnersStrategy.accept(innerClass, visitor); } } @@ -391,8 +387,7 @@ public class StubBuildingVisitor extends ClassVisitor { newReferenceList(JavaStubElementTypes.THROWS_LIST, stub, ArrayUtil.toStringArray(info.throwTypes)); - boolean noSynthetics = myAsm6Mode && isConstructor && hasSignature && Type.getArgumentTypes(desc).length == info.argTypes.size(); - int paramIgnoreCount = noSynthetics ? 0 : isEnumConstructor ? 2 : isInnerClassConstructor ? 1 : 0; + int paramIgnoreCount = isEnumConstructor ? 2 : isInnerClassConstructor ? 1 : 0; int localVarIgnoreCount = isEnumConstructor ? 3 : isInnerClassConstructor ? 2 : !isStatic ? 1 : 0; return new MethodAnnotationCollectingVisitor(stub, modList, paramStubs, paramIgnoreCount, localVarIgnoreCount, myMapping); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/afterIncomplete.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/afterIncomplete.java new file mode 100644 index 000000000000..d12c542f78e6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/afterIncomplete.java @@ -0,0 +1,13 @@ +// "Surround with try/catch" "true" +class C { + native boolean foo() throws Exception; + + void test() { + try { + if(foo() && foo()) + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/beforeIncomplete.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/beforeIncomplete.java new file mode 100644 index 000000000000..ba4ed3ea0097 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/surroundWithTry/beforeIncomplete.java @@ -0,0 +1,9 @@ +// "Surround with try/catch" "true" +class C { + native boolean foo() throws Exception; + + void test() { + if(foo() && foo()) + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/commonIfParts/afterAnonymous.java b/java/java-tests/testData/inspection/commonIfParts/afterAnonymous.java index 6ac3815e06d9..255333aba1fc 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterAnonymous.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterAnonymous.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterArrayInitializer.java b/java/java-tests/testData/inspection/commonIfParts/afterArrayInitializer.java index 67f303331aaa..81e2185553bb 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterArrayInitializer.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterArrayInitializer.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionPure.java b/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionPure.java index a1c926fb38f1..64a76e1a0612 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionPure.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionPure.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionWithSideEfects.java b/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionWithSideEfects.java index 315813bf0323..3b11201f7fb1 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionWithSideEfects.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCallWithSideEffectsConditionWithSideEfects.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if (may change semantics)" "INFORMATION" +// "Extract common part with variables from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtract.java b/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtract.java index fa2056423865..661d54f7efe8 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtract.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtract.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtractMultiple.java b/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtractMultiple.java index 003b82dad9fb..4a5eb49222a3 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtractMultiple.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCommonTailVariableExtractMultiple.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCommonVariableDefinition.java b/java/java-tests/testData/inspection/commonIfParts/afterCommonVariableDefinition.java index 2d5b949c397a..5ebcbc274bff 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCommonVariableDefinition.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCommonVariableDefinition.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateIfElse.java b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateIfElse.java index 3973372b01db..358a48a2599f 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateIfElse.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateIfElse.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturn.java b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturn.java index 1149c5ceea83..bfbe0e0a4175 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturn.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturn.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnFoldedIf.java b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnFoldedIf.java index d26bd993fac0..bcbb24fe8d60 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnFoldedIf.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnFoldedIf.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing.java b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing.java index 94756f6e4e6b..4c30c6471896 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing2.java b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing2.java index 6deece8e855e..f1ec1194cda9 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing2.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterCompleteDuplicateImplicitReturnNothing2.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNames.java b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNames.java index 2a82cc0bdeae..76b57cf3e6fe 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNames.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNames.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVar.java b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVar.java index 4ee7aa2444f2..6a5a1c521b3b 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVar.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVar.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVarDifferentInitializers.java b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVarDifferentInitializers.java index 00c85b03f7f5..baf7bfcf48ec 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVarDifferentInitializers.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterDifferentNamesFinalVarDifferentInitializers.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterImplicitElseReturnValue.java b/java/java-tests/testData/inspection/commonIfParts/afterImplicitElseReturnValue.java index 6410cea7cf46..630daf06e334 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterImplicitElseReturnValue.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterImplicitElseReturnValue.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces.java b/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces.java index 4ef6723dabc1..9abef918c064 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces2.java b/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces2.java index 4ef6723dabc1..9abef918c064 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces2.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterInconsistentBraces2.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterIncrement.java b/java/java-tests/testData/inspection/commonIfParts/afterIncrement.java index 7c6a8cc2b2df..1da0e6262a34 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterIncrement.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterIncrement.java @@ -1,4 +1,4 @@ -// "Extract common part from if (may change semantics)" "INFORMATION" +// "Extract common part from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterPureField.java b/java/java-tests/testData/inspection/commonIfParts/afterPureField.java index 7e59268b2b73..5d02d93b50d5 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterPureField.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterPureField.java @@ -1,4 +1,4 @@ -// "Extract common part from if (may change semantics)" "INFORMATION" +// "Extract common part from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterThenElseComments.java b/java/java-tests/testData/inspection/commonIfParts/afterThenElseComments.java index ed2e9017bd60..205c6fd58d33 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterThenElseComments.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterThenElseComments.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.io.*; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterThenRemove.java b/java/java-tests/testData/inspection/commonIfParts/afterThenRemove.java index 4f15f42afe57..cab8b14a328f 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterThenRemove.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterThenRemove.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/afterThenRemoveComments.java b/java/java-tests/testData/inspection/commonIfParts/afterThenRemoveComments.java index ebe7bac7fde8..57f9371a7278 100644 --- a/java/java-tests/testData/inspection/commonIfParts/afterThenRemoveComments.java +++ b/java/java-tests/testData/inspection/commonIfParts/afterThenRemoveComments.java @@ -1,4 +1,4 @@ -// "Extract variables from if " "true" +// "Extract variables from 'if'" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeAnonymous.java b/java/java-tests/testData/inspection/commonIfParts/beforeAnonymous.java index c41a25a4126f..847a1b6e9784 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeAnonymous.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeAnonymous.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeArrayInitializer.java b/java/java-tests/testData/inspection/commonIfParts/beforeArrayInitializer.java index eb2700caa29e..82d1532c78e0 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeArrayInitializer.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeArrayInitializer.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionPure.java b/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionPure.java index 75d737110d60..a0b522aa2bcc 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionPure.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionPure.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionWithSideEfects.java b/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionWithSideEfects.java index 1528e55be4ea..54cc846a4eae 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionWithSideEfects.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCallWithSideEffectsConditionWithSideEfects.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if (may change semantics)" "INFORMATION" +// "Extract common part with variables from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailDependsOnInBranchVar.java b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailDependsOnInBranchVar.java index 5e4c0b2c4cad..31e98f78c142 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailDependsOnInBranchVar.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailDependsOnInBranchVar.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "false" +// "Extract common part with variables from 'if'" "false" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtract.java b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtract.java index c077286511a0..58e96a90be7a 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtract.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtract.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtractMultiple.java b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtractMultiple.java index 3a5e848aeffd..1c797c6eef23 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtractMultiple.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCommonTailVariableExtractMultiple.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCommonVariableDefinition.java b/java/java-tests/testData/inspection/commonIfParts/beforeCommonVariableDefinition.java index 4baea10ae816..a85344b58b3d 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCommonVariableDefinition.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCommonVariableDefinition.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateIfElse.java b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateIfElse.java index fe6e7bd0cf78..fbf8a97777a4 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateIfElse.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateIfElse.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturn.java b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturn.java index 02c427d0595f..4e5c62a2607a 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturn.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturn.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnFoldedIf.java b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnFoldedIf.java index bb2df605f8e5..3d96fad220c7 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnFoldedIf.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnFoldedIf.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing.java b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing.java index 50adcdb02497..d81d69f7cf08 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing2.java b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing2.java index 8c98116d8636..916dc76ddcd5 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing2.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeCompleteDuplicateImplicitReturnNothing2.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentAnnotations.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentAnnotations.java index 6f80f29ba7a6..36a1258907e4 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentAnnotations.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentAnnotations.java @@ -1,4 +1,4 @@ -// "Fix all 'Common parts of if statement branches can be extracted' problems in file" "false" +// "Fix all 'Common parts of 'if' statement branches can be extracted' problems in file" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNames.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNames.java index 2af8d5b518d3..cd066b4101c7 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNames.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNames.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesExistingName.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesExistingName.java index eceb02d9436e..cb228efa4bf2 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesExistingName.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesExistingName.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "false" +// "Extract common part removing branch" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalAndNonFinalVar.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalAndNonFinalVar.java index 10d8b0d28ba2..94e778dfe330 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalAndNonFinalVar.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalAndNonFinalVar.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "false" +// "Extract common part removing branch" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVar.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVar.java index 1e2f20e07898..9728e34225af 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVar.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVar.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVarDifferentInitializers.java b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVarDifferentInitializers.java index f142706121f0..ffbe15eee61b 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVarDifferentInitializers.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeDifferentNamesFinalVarDifferentInitializers.java @@ -1,4 +1,4 @@ -// "Extract common part with variables from if " "true" +// "Extract common part with variables from 'if'" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturn.java b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturn.java index c8c7078d94eb..12744e536b79 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturn.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturn.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "false" +// "Collapse 'if' statement" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnLoop.java b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnLoop.java index 8c7597794319..5ceafa4bd76e 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnLoop.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnLoop.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "false" +// "Collapse 'if' statement" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnValue.java b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnValue.java index 562288a95b4c..0e270df2f443 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnValue.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseReturnValue.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseSideEffectsPreserved.java b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseSideEffectsPreserved.java index 90d2e1230cf6..49908921b051 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseSideEffectsPreserved.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeImplicitElseSideEffectsPreserved.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "false" +// "Collapse 'if' statement" "false" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces.java b/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces.java index 8082d64bda27..a9c79084f6c1 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces2.java b/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces2.java index 54a06a6bcf54..e0fdf0c46c17 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces2.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeInconsistentBraces2.java @@ -1,4 +1,4 @@ -// "Collapse if statement " "true" +// "Collapse 'if' statement" "true" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeIncrement.java b/java/java-tests/testData/inspection/commonIfParts/beforeIncrement.java index 783d9c78d71e..fdc28f77aaa6 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeIncrement.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeIncrement.java @@ -1,4 +1,4 @@ -// "Extract common part from if (may change semantics)" "INFORMATION" +// "Extract common part from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforePureField.java b/java/java-tests/testData/inspection/commonIfParts/beforePureField.java index c95cc378df98..66df46b47c3b 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforePureField.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforePureField.java @@ -1,4 +1,4 @@ -// "Extract common part from if (may change semantics)" "INFORMATION" +// "Extract common part from 'if' (may change semantics)" "INFORMATION" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatementChain.java b/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatementChain.java index 09c4ff79dced..69af73bd4221 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatementChain.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatementChain.java @@ -1,4 +1,4 @@ -// "Extract common part from if " "false" +// "Extract common part from 'if'" "false" public class Main { diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatements.java b/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatements.java index a37ac789ad33..a27fb4fb1f30 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatements.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeSimilarStatements.java @@ -1,4 +1,4 @@ -// "Extract common part from if " "false" +// "Extract common part from 'if'" "false" public class Main { public static void main(String[] args) { diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeThenElseComments.java b/java/java-tests/testData/inspection/commonIfParts/beforeThenElseComments.java index d81f453932a4..94d249e8603a 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeThenElseComments.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeThenElseComments.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.io.*; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeThenRemove.java b/java/java-tests/testData/inspection/commonIfParts/beforeThenRemove.java index 919b8836e68d..5f89672e331e 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeThenRemove.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeThenRemove.java @@ -1,4 +1,4 @@ -// "Extract common part removing branch " "true" +// "Extract common part removing branch" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeThenRemoveComments.java b/java/java-tests/testData/inspection/commonIfParts/beforeThenRemoveComments.java index 103dc6998f62..3be68e20a3e5 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeThenRemoveComments.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeThenRemoveComments.java @@ -1,4 +1,4 @@ -// "Extract variables from if " "true" +// "Extract variables from 'if'" "true" import java.util.Collection; import java.util.List; diff --git a/java/java-tests/testData/inspection/commonIfParts/beforeWithoutElse.java b/java/java-tests/testData/inspection/commonIfParts/beforeWithoutElse.java index bdb59f2ef766..78f304471b8a 100644 --- a/java/java-tests/testData/inspection/commonIfParts/beforeWithoutElse.java +++ b/java/java-tests/testData/inspection/commonIfParts/beforeWithoutElse.java @@ -1,4 +1,4 @@ -// "Common parts of if statement can be extracted" "false" +// "Common parts of 'if' statement can be extracted" "false" import java.util.List; import java.util.Map; diff --git a/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringForNameUtf16.java b/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringForNameUtf16.java index f9fc1326d063..9c7131a07b67 100644 --- a/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringForNameUtf16.java +++ b/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringForNameUtf16.java @@ -1,4 +1,4 @@ -// "Replace with 'Files.writeString()'" "WARNING" +// "Replace with 'Files.writeString()'" "GENERIC_ERROR_OR_WARNING" import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.charset.Charset; diff --git a/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringUtf16.java b/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringUtf16.java index c06360844d71..315d8928cdbb 100644 --- a/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringUtf16.java +++ b/java/java-tests/testData/inspection/filesReadWriteString/afterWriteStringUtf16.java @@ -1,4 +1,4 @@ -// "Replace with 'Files.writeString()'" "WARNING" +// "Replace with 'Files.writeString()'" "GENERIC_ERROR_OR_WARNING" import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.charset.Charset; diff --git a/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringForNameUtf16.java b/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringForNameUtf16.java index 1a02c8c96e0f..89582f176d2f 100644 --- a/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringForNameUtf16.java +++ b/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringForNameUtf16.java @@ -1,4 +1,4 @@ -// "Replace with 'Files.writeString()'" "WARNING" +// "Replace with 'Files.writeString()'" "GENERIC_ERROR_OR_WARNING" import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.charset.Charset; diff --git a/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringUtf16.java b/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringUtf16.java index fce72e2f8c98..aceff5bded03 100644 --- a/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringUtf16.java +++ b/java/java-tests/testData/inspection/filesReadWriteString/beforeWriteStringUtf16.java @@ -1,4 +1,4 @@ -// "Replace with 'Files.writeString()'" "WARNING" +// "Replace with 'Files.writeString()'" "GENERIC_ERROR_OR_WARNING" import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.charset.Charset; diff --git a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaIntentionPolicy.java b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaIntentionPolicy.java index fb927da66441..f3864fa3dffe 100644 --- a/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaIntentionPolicy.java +++ b/java/java-tests/testSrc/com/intellij/java/propertyBased/JavaIntentionPolicy.java @@ -22,7 +22,6 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.testFramework.propertyBased.IntentionPolicy; import com.siyeh.ig.psiutils.ExpressionUtils; -import com.siyeh.ipp.psiutils.ErrorUtil; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -195,7 +194,6 @@ class JavaParenthesesPolicy extends JavaIntentionPolicy { break; } if (parent instanceof PsiVariable && expression instanceof PsiArrayInitializerExpression) break; - if (ErrorUtil.containsDeepError(parent)) break; result.add(expression); element = expression.getParent(); } diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/AnnotatedElementInspectionBase.java b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/AnnotatedElementInspectionBase.java index 531ec80ea810..dd61047f14cc 100644 --- a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/AnnotatedElementInspectionBase.java +++ b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/AnnotatedElementInspectionBase.java @@ -3,11 +3,15 @@ package com.intellij.codeInspection; import com.intellij.analysis.JvmAnalysisBundle; import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilCore; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.uast.UImportStatement; @@ -31,7 +35,7 @@ public abstract class AnnotatedElementInspectionBase extends LocalInspectionTool protected abstract void createProblem(@NotNull PsiReference reference, @NotNull ProblemsHolder holder); protected boolean shouldProcessElement(@NotNull PsiModifierListOwner element) { - return true; + return isLibraryElement(element); } @@ -133,4 +137,12 @@ public abstract class AnnotatedElementInspectionBase extends LocalInspectionTool // references are not PsiQualifiedReference for annotation attributes return StringUtil.getShortName(reference.getCanonicalText()); } + + private static boolean isLibraryElement(@NotNull PsiElement element) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return true; + } + VirtualFile containingVirtualFile = PsiUtilCore.getVirtualFile(element); + return containingVirtualFile != null && ProjectFileIndex.getInstance(element.getProject()).isInLibraryClasses(containingVirtualFile); + } } \ No newline at end of file diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/ScheduledForRemovalInspection.java b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/ScheduledForRemovalInspection.java index 2011e2d2ad14..b1fb318c4b4f 100644 --- a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/ScheduledForRemovalInspection.java +++ b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/ScheduledForRemovalInspection.java @@ -2,7 +2,6 @@ package com.intellij.codeInspection; import com.intellij.analysis.JvmAnalysisBundle; -import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/UnstableApiUsageInspection.java b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/UnstableApiUsageInspection.java index f2f976334441..9e5c859d44d7 100644 --- a/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/UnstableApiUsageInspection.java +++ b/jvm/jvm-analysis-impl/src/com/intellij/codeInspection/UnstableApiUsageInspection.java @@ -3,13 +3,7 @@ package com.intellij.codeInspection; import com.intellij.analysis.JvmAnalysisBundle; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiModifierListOwner; import com.intellij.psi.PsiReference; -import com.intellij.psi.util.PsiUtilCore; import com.siyeh.ig.ui.ExternalizableStringSet; import org.jetbrains.annotations.NotNull; @@ -41,11 +35,6 @@ public class UnstableApiUsageInspection extends AnnotatedElementInspectionBase { holder.registerProblem(reference, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING); } - @Override - protected boolean shouldProcessElement(@NotNull PsiModifierListOwner element) { - return isLibraryElement(element); - } - @NotNull @Override public JPanel createOptionsPanel() { @@ -60,12 +49,4 @@ public class UnstableApiUsageInspection extends AnnotatedElementInspectionBase { panel.add(annotationsListControl, BorderLayout.CENTER); return panel; } - - private static boolean isLibraryElement(@NotNull PsiElement element) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - return true; - } - VirtualFile containingVirtualFile = PsiUtilCore.getVirtualFile(element); - return containingVirtualFile != null && ProjectFileIndex.getInstance(element.getProject()).isInLibraryClasses(containingVirtualFile); - } } diff --git a/list-tags.sh b/list-tags.sh new file mode 100755 index 000000000000..1066d1e0ad59 --- /dev/null +++ b/list-tags.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# +# Lists all tags available in the repository. +# Usage: ./list-tags.sh + +git ls-remote --tags git://git.jetbrains.org/idea/community.git diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java index ef86ec309f74..9d4ddbe457fa 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/action/ExternalSystemRunConfigurationMenu.java @@ -43,8 +43,10 @@ public class ExternalSystemRunConfigurationMenu extends DefaultActionGroup imple ProjectSystemId projectSystemId = ExternalSystemDataKeys.EXTERNAL_SYSTEM_ID.getData(e.getDataContext()); Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); for (int i = executors.length; --i >= 0; ) { - final ProgramRunner runner = ProgramRunner.getRunner(executors[i].getId(), settings.getConfiguration()); - AnAction action = new ExecuteExternalSystemRunConfigurationAction(executors[i], runner != null, project, projectSystemId, settings); + Executor executor = executors[i]; + if(!executor.isApplicable(project)) continue; + final ProgramRunner runner = ProgramRunner.getRunner(executor.getId(), settings.getConfiguration()); + AnAction action = new ExecuteExternalSystemRunConfigurationAction(executor, runner != null, project, projectSystemId, settings); addAction(action, Constraints.FIRST); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java index 0f08e38caa01..da478ab876fe 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/view/LineLayout.java @@ -595,6 +595,11 @@ abstract class LineLayout { this.endOffset = endOffset; } + @Override + public int hashCode() { + return startOffset * 31 + endOffset; + } + private void ensureLayout(@NotNull EditorView view, BidiRun run, int line) { if (isReal()) { view.getTextLayoutCache().onChunkAccess(this); diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/UpdateStrategyCustomization.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/UpdateStrategyCustomization.java index 7e4f3cc2d2b4..5e15912ebc89 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/UpdateStrategyCustomization.java +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/UpdateStrategyCustomization.java @@ -17,6 +17,7 @@ package com.intellij.openapi.updateSettings; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.updateSettings.impl.ChannelStatus; +import com.intellij.openapi.util.BuildNumber; import org.jetbrains.annotations.NotNull; /** @@ -34,4 +35,15 @@ public class UpdateStrategyCustomization { public boolean isChannelActive(@NotNull ChannelStatus channel) { return channel != ChannelStatus.MILESTONE; } + + /** + * Returns {@code true} if the both passed builds correspond to the same major version of the IDE. The platform uses this method when several + * new builds are available, to suggest updating to the build from the same major version, i.e. IntelliJ IDEA 2018.2.5 will suggest to + * update to 2018.2.6, not to 2018.3. + *
+ * Override this method if major versions of your IDE doesn't directly correspond to major version of the IntelliJ platform. + */ + public boolean haveSameMajorVersion(@NotNull BuildNumber build1, @NotNull BuildNumber build2) { + return build1.getBaselineVersion() == build2.getBaselineVersion(); + } } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.kt b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.kt index a84f971a3db8..c539031057dd 100644 --- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.kt +++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/UpdateStrategy.kt @@ -1,6 +1,7 @@ // 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. package com.intellij.openapi.updateSettings.impl +import com.intellij.openapi.updateSettings.UpdateStrategyCustomization import com.intellij.openapi.util.BuildNumber import com.intellij.util.containers.MultiMap import com.intellij.util.graph.GraphAlgorithms @@ -14,8 +15,6 @@ class UpdateStrategy(private val currentBuild: BuildNumber, private val updates: LOADED, CONNECTION_ERROR, NOTHING_LOADED } - private val lineage = currentBuild.baselineVersion - fun checkForUpdates(): CheckForUpdateResult { val product = updates[currentBuild.productCode] if (product == null || product.channels.isEmpty()) { @@ -43,10 +42,11 @@ class UpdateStrategy(private val currentBuild: BuildNumber, private val updates: candidate.number.asStringWithoutProductCode() !in ignoredBuilds && candidate.target?.inRange(currentBuild) ?: true - private fun compareBuilds(n1: BuildNumber, n2: BuildNumber) = - if (n1.baselineVersion == lineage && n2.baselineVersion != lineage) 1 - else if (n2.baselineVersion == lineage && n1.baselineVersion != lineage) -1 - else n1.compareTo(n2) + private fun compareBuilds(n1: BuildNumber, n2: BuildNumber): Int { + val customization = UpdateStrategyCustomization.getInstance() + val preferSameMajorVersion = customization.haveSameMajorVersion(currentBuild, n1).compareTo(customization.haveSameMajorVersion(currentBuild, n2)) + return if (preferSameMajorVersion != 0) preferSameMajorVersion else n1.compareTo(n2) + } private fun patches(newBuild: BuildInfo, product: Product, from: BuildNumber): UpdateChain? { val single = newBuild.patches.find { it.isAvailable && it.fromBuild.compareTo(from) == 0 } diff --git a/platform/platform-impl/src/com/intellij/ui/LightweightHint.java b/platform/platform-impl/src/com/intellij/ui/LightweightHint.java index 76742c48cd03..54df07ba2aa7 100644 --- a/platform/platform-impl/src/com/intellij/ui/LightweightHint.java +++ b/platform/platform-impl/src/com/intellij/ui/LightweightHint.java @@ -216,8 +216,8 @@ public class LightweightHint extends UserDataHolderBase implements Hint { } myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(actualComponent, myFocusRequestor) - .setRequestFocus(hintHint.isRequestFocus()) - .setFocusable(hintHint.isRequestFocus()) + .setRequestFocus(myFocusRequestor != null || hintHint.isRequestFocus()) + .setFocusable(myFocusRequestor != null || hintHint.isRequestFocus()) .setResizable(myResizable) .setMovable(myTitle != null) .setTitle(myTitle) diff --git a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java index 3a390f68adbb..c9a92897df7a 100755 --- a/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java +++ b/platform/platform-impl/src/com/intellij/ui/messages/SheetController.java @@ -60,7 +60,7 @@ public class SheetController implements Disposable { private static final int GAP_BETWEEN_BUTTONS = 5; - private static final String SPACE_OR_LINE_SEPARATOR_PATTERN = "[\\s" + System.getProperty("line.separator") + "]+"; + private static final String SPACE_OR_LINE_SEPARATOR_PATTERN = "([\\s" + System.getProperty("line.separator") + "]|(
))+"; // SHEET public int SHEET_WIDTH = 400; diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties index 6216fbd2f726..549c049c3579 100644 --- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties +++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties @@ -260,11 +260,11 @@ inspection.export.error.writing.to=Error writing to {0}: {1} inspection.common.if.parts.family=Extract common parts of 'if' statement inspection.common.if.parts.family.else.if=Merge 'else if' statement -inspection.common.if.parts.message.variables.only=Extract variables from 'if' {0} -inspection.common.if.parts.message.with.variables.extract=Extract common part with variables from 'if' {0} -inspection.common.if.parts.message.without.variables.extract=Extract common part from 'if' {0} -inspection.common.if.parts.message.whole.branch=Extract common part removing branch {0} -inspection.common.if.parts.message.complete.duplicate=Collapse 'if' statement {0} +inspection.common.if.parts.message.variables.only=Extract variables from ''if''{0} +inspection.common.if.parts.message.with.variables.extract=Extract common part with variables from ''if''{0} +inspection.common.if.parts.message.without.variables.extract=Extract common part from ''if''{0} +inspection.common.if.parts.message.whole.branch=Extract common part removing branch{0} +inspection.common.if.parts.message.complete.duplicate=Collapse ''if'' statement{0} inspection.common.if.parts.message.complete.duplicate.side.effect=Collapse 'if' statement and extract side effect inspection.common.if.parts.description='if' statement with common parts diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestExecutionPolicy.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestExecutionPolicy.java index f536864ad28e..d92b95de9488 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestExecutionPolicy.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestExecutionPolicy.java @@ -13,10 +13,15 @@ import com.intellij.psi.PsiFile; import com.intellij.testFramework.TestModeFlagListener; import com.intellij.testFramework.TestModeFlags; import com.intellij.testFramework.UsefulTestCase; +import com.intellij.testFramework.fixtures.impl.LightTempDirTestFixtureImpl; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** + * Allows to customize the test execution environment for the entire test execution without modifying the source code + * of tests. To specify a test execution policy, set the system property "idea.test.execution.policy" to the FQ name + * of a class implementing this interface. + * * @author yole */ public abstract class IdeaTestExecutionPolicy implements TestModeFlagListener { @@ -24,9 +29,26 @@ public abstract class IdeaTestExecutionPolicy implements TestModeFlagListener { TestModeFlags.addListener(this); } - public abstract void setUp(Project project, Disposable testRootDisposable, String testDataPath); - public abstract TempDirTestFixture createTempDirTestFixture(); - public abstract boolean runInDispatchThread(); + /** + * Performs the setup required in this test execution mode. + */ + public void setUp(Project project, Disposable testRootDisposable, String testDataPath) { + } + + /** + * Creates the fixture for working with temporary files. + */ + public TempDirTestFixture createTempDirTestFixture() { + return new LightTempDirTestFixtureImpl(true); + } + + /** + * If true, the test method is invoked in the EDT. Otherwise, it runs on the test runner thread. + */ + public boolean runInDispatchThread() { + return true; + } + public void testFileConfigured(@NotNull PsiFile file) { } diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/SkipWithExecutionPolicy.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/SkipWithExecutionPolicy.java index 9889fff47cd9..dbe62ffa53e6 100644 --- a/platform/testFramework/src/com/intellij/testFramework/fixtures/SkipWithExecutionPolicy.java +++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/SkipWithExecutionPolicy.java @@ -6,6 +6,10 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +/** + * Marks a test as not applicable to a given test execution policy. If the value of this annotation + * matches the {@link IdeaTestExecutionPolicy#getName()} of the current test execution policy, the test will be skipped. + */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface SkipWithExecutionPolicy { diff --git a/platform/testFramework/src/com/intellij/testFramework/propertyBased/InvokeIntention.java b/platform/testFramework/src/com/intellij/testFramework/propertyBased/InvokeIntention.java index 85b4db7c18ed..5c6eafac17ac 100644 --- a/platform/testFramework/src/com/intellij/testFramework/propertyBased/InvokeIntention.java +++ b/platform/testFramework/src/com/intellij/testFramework/propertyBased/InvokeIntention.java @@ -107,7 +107,9 @@ public class InvokeIntention extends ActionOnFile { List intentions = getAvailableIntentions(editor, file); // Do not reuse originally passed offset here, sometimes it's adjusted by Editor PsiElement currentElement = file.findElementAt(editor.getCaretModel().getOffset()); - intentions = wrapAndCheck(env, editor, currentElement, containsErrorElements, hasErrors, intentions); + if (!containsErrorElements) { + intentions = wrapAndCheck(env, editor, currentElement, hasErrors, intentions); + } IntentionAction intention = chooseIntention(env, intentions); if (intention == null) return; @@ -195,7 +197,6 @@ public class InvokeIntention extends ActionOnFile { private List wrapAndCheck(Environment env, Editor editor, PsiElement currentElement, - boolean containsErrorElements, boolean hasErrors, List intentions) { if (currentElement == null) return intentions; @@ -228,14 +229,13 @@ public class InvokeIntention extends ActionOnFile { List messages = new ArrayList<>(); boolean newContainsErrorElements = MadTestingUtil.containsErrorElements(getFile().getViewProvider()); - if (newContainsErrorElements != containsErrorElements) { - messages.add(newContainsErrorElements ? "File contains parse errors after wrapping" : "File parse errors were fixed after wrapping"); + if (newContainsErrorElements) { + messages.add("File contains parse errors after wrapping"); } else { - boolean newHasErrors = !highlightErrors(project, editor).isEmpty() || containsErrorElements; + boolean newHasErrors = !highlightErrors(project, editor).isEmpty(); if (newHasErrors != hasErrors) { - messages - .add(newHasErrors ? "File contains errors after wrapping" : "File errors were fixed after wrapping"); + messages.add(newHasErrors ? "File contains errors after wrapping" : "File errors were fixed after wrapping"); } } intentions = getAvailableIntentions(editor, file); diff --git a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java index 2255d1e31951..ae5efcb554fd 100644 --- a/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java +++ b/platform/util/src/com/intellij/util/io/CompressedAppendableFile.java @@ -60,6 +60,9 @@ public class CompressedAppendableFile { static final String INCOMPLETE_CHUNK_LENGTH_FILE_EXTENSION = ".s"; + private static int ourFilesCount; + private final int myCount = ourFilesCount++; + public CompressedAppendableFile(File file) { this(file, 32768); } @@ -590,4 +593,9 @@ public class CompressedAppendableFile { return buf[0] & 0xFF; } } + + @Override + public int hashCode() { + return myCount; + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java index d8a2f0c74c9c..09085fb8072c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/IfStatementWithIdenticalBranchesInspection.java @@ -61,7 +61,7 @@ public class IfStatementWithIdenticalBranchesInspection extends AbstractBaseJava if (!isOnTheFly) return; highlightType = ProblemHighlightType.INFORMATION; } - holder.registerProblem(result.myElementToHighlight, InspectionsBundle.message("inspection.common.if.parts.description"), highlightType, result.myFix); + holder.registerProblem(result.myElementToHighlight, result.myMessage, highlightType, result.myFix); } } } @@ -455,7 +455,7 @@ public class IfStatementWithIdenticalBranchesInspection extends AbstractBaseJava @NotNull private String getMessage(boolean mayChangeSemantics) { - String mayChangeSemanticsText = mayChangeSemantics ? "(may change semantics)" : ""; + String mayChangeSemanticsText = mayChangeSemantics ? " (may change semantics)" : ""; return InspectionsBundle.message(myBundleKey, mayChangeSemanticsText); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java index eca6840035a1..287b577ca062 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ControlFlowUtils.java @@ -899,27 +899,17 @@ public class ControlFlowUtils { } /** - * @param expression expression to check - * @return true if given expression is always executed and can be converted to a statement + * @param expression expression to check + * @return true if given expression can be extracted to a statement */ public static boolean canExtractStatement(PsiExpression expression) { - return canExtractStatement(expression, true); - } - - /** - * @param expression expression to check - * @param checkExecuted if true, expression will be considered non-extractable if it is not always executed within its topmost expression - * (e.g. appears in then/else branches in ?: expression) - * @return true if given expression can be converted to a statement - */ - public static boolean canExtractStatement(PsiExpression expression, boolean checkExecuted) { PsiElement cur = expression; PsiElement parent = cur.getParent(); while(parent instanceof PsiExpression || parent instanceof PsiExpressionList) { if(parent instanceof PsiLambdaExpression) { return true; } - if (checkExecuted && parent instanceof PsiPolyadicExpression) { + if (parent instanceof PsiPolyadicExpression) { PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent; IElementType type = polyadicExpression.getOperationTokenType(); if (type.equals(JavaTokenType.ANDAND) && polyadicExpression.getOperands()[0] != cur) { @@ -937,7 +927,7 @@ public class ControlFlowUtils { return (polyParent instanceof PsiReturnStatement) || (polyParent instanceof PsiLambdaExpression); } } - if (checkExecuted && parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != cur) { + if (parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != cur) { return false; } if(parent instanceof PsiMethodCallExpression) { @@ -951,7 +941,7 @@ public class ControlFlowUtils { } if (parent instanceof PsiStatement) { PsiElement grandParent = parent.getParent(); - if (checkExecuted && grandParent instanceof PsiForStatement && ((PsiForStatement)grandParent).getUpdate() == parent) { + if (grandParent instanceof PsiForStatement && ((PsiForStatement)grandParent).getUpdate() == parent) { return false; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java index 0dc45042dc6e..6fcd6dc972a6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -1394,4 +1394,24 @@ public class ExpressionUtils { public static boolean isArrayCreationExpression(@NotNull PsiNewExpression expression) { return expression.getArrayInitializer() != null || expression.getArrayDimensions().length > 0; } + + /** + * Returns ancestor expression for given subexpression which parent is not an expression anymore (except lambda) + * + * @param expression an expression to find its ancestor + * @return a top-level expression for given expression (may return an expression itself) + */ + @NotNull + public static PsiExpression getTopLevelExpression(@NotNull PsiExpression expression) { + while(true) { + PsiElement parent = expression.getParent(); + if (parent instanceof PsiExpression && !(parent instanceof PsiLambdaExpression)) { + expression = (PsiExpression)parent; + } else if (parent instanceof PsiExpressionList && parent.getParent() instanceof PsiExpression) { + expression = (PsiExpression)parent.getParent(); + } else { + return expression; + } + } + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ReorderingUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ReorderingUtils.java index b5d8bc7feae5..ff2b4b6b1843 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ReorderingUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ReorderingUtils.java @@ -4,9 +4,10 @@ package com.siyeh.ig.psiutils; import com.intellij.codeInsight.Nullability; import com.intellij.codeInsight.NullableNotNullManager; import com.intellij.codeInspection.dataFlow.*; -import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.ContractReturnValue.BooleanReturnValue; +import com.intellij.codeInspection.dataFlow.value.DfaRelationValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; -import com.intellij.openapi.util.TextRange; +import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiLiteralUtil; @@ -15,11 +16,14 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.ObjectUtils; import com.intellij.util.ThreeState; -import one.util.streamex.StreamEx; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.function.Function; import java.util.function.Supplier; public class ReorderingUtils { @@ -68,9 +72,21 @@ public class ReorderingUtils { } } if (parent instanceof PsiConditionalExpression) { - if (((PsiConditionalExpression)parent).getCondition() == expression) { + PsiConditionalExpression ternary = (PsiConditionalExpression)parent; + PsiExpression condition = ternary.getCondition(); + if (condition == expression) { return canExtract(ancestor, parent); } + ThreeState result; + if (isSideEffectFree(condition, false) && + isSideEffectFree(expression, false)) { + result = ThreeState.YES; + } else { + boolean isNecessary = + areConditionsNecessaryFor(new PsiExpression[]{condition}, expression, ternary.getElseExpression() == expression); + result = isNecessary ? ThreeState.NO : ThreeState.UNSURE; + } + return and(result, () -> canExtract(ancestor, parent)); } if (parent instanceof PsiLambdaExpression) { return ThreeState.NO; @@ -120,153 +136,272 @@ public class ReorderingUtils { if (operandIndex == 0) return ThreeState.YES; IElementType tokenType = polyadicExpression.getOperationTokenType(); if (tokenType != JavaTokenType.ANDAND && tokenType != JavaTokenType.OROR) return ThreeState.UNSURE; - PsiExpression[] expressionOperands = polyadicExpression.getOperands(); - if (operandIndex < 0 || operandIndex >= expressionOperands.length) { + PsiExpression[] operands = polyadicExpression.getOperands(); + if (operandIndex < 0 || operandIndex >= operands.length) { throw new IndexOutOfBoundsException("operandIndex = "+operandIndex); } - PsiExpression[] operands = Arrays.copyOfRange(expressionOperands, 0, operandIndex + 1); - if (Arrays.stream(operands).allMatch(expression -> isSideEffectFree(expression, false))) { + if (Arrays.stream(operands, 0, operandIndex + 1).allMatch(expression -> isSideEffectFree(expression, false))) { return ThreeState.YES; } - if (lastOperandImpliesPrevious(polyadicExpression, operands)) { + boolean and = polyadicExpression.getOperationTokenType() == JavaTokenType.ANDAND; + PsiExpression lastOperand = operands[operandIndex]; + if (areConditionsNecessaryFor(Arrays.copyOf(operands, operandIndex), lastOperand, !and)) { return ThreeState.NO; } return ThreeState.UNSURE; } - private enum ExceptionKind { - NullDereference { - @Override - boolean isNecessaryCheck(PsiExpression operand, PsiExpression condition, boolean negated) { - if (condition instanceof PsiBinaryExpression) { - IElementType tokenType = ((PsiBinaryExpression)condition).getOperationTokenType(); - if (tokenType.equals(negated ? JavaTokenType.EQEQ : JavaTokenType.NE)) { - PsiExpression left = ((PsiBinaryExpression)condition).getLOperand(); - PsiExpression right = ((PsiBinaryExpression)condition).getROperand(); - if (ExpressionUtils.isNullLiteral(left)) { - return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(right, operand); - } - if (ExpressionUtils.isNullLiteral(right)) { - return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(left, operand); + private static boolean hasContract(PsiExpression expression, PsiExpression operand, ContractReturnValue value) { + expression = PsiUtil.skipParenthesizedExprDown(expression); + if (value.equals(ContractReturnValue.returnNull()) && + EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(operand, expression)) { + return true; + } + if (expression instanceof PsiMethodCallExpression) { + PsiMethodCallExpression call = (PsiMethodCallExpression)expression; + PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList.isEmpty()) return false; + List contracts = JavaMethodContractUtil.getMethodCallContracts(call); + for (MethodContract contract : contracts) { + if (contract.getReturnValue().equals(value)) { + List conditions = contract.getConditions(); + if (conditions.size() == 1) { + ContractValue condition = conditions.get(0); + int argIndex = condition.getNullCheckedArgument(true).orElse(-1); + if (argIndex >= 0) { + PsiExpression[] args = argumentList.getExpressions(); + if (argIndex < args.length) { + PsiExpression arg = args[argIndex]; + if (hasContract(arg, operand, ContractReturnValue.returnNull())) { + return true; + } + } } } } - return false; } - - @Override - PsiExpression extractOperand(PsiExpression expression) { - if (expression instanceof PsiLiteralExpression || - expression instanceof PsiParenthesizedExpression || - expression instanceof PsiTypeCastExpression || - expression instanceof PsiConditionalExpression || - NullabilityUtil.getExpressionNullability(expression) == Nullability.NOT_NULL) { - return null; - } - PsiExpression realExpression = expression; - while (realExpression.getParent() instanceof PsiParenthesizedExpression || - realExpression.getParent() instanceof PsiTypeCastExpression || - (realExpression.getParent() instanceof PsiConditionalExpression && - realExpression != ((PsiConditionalExpression)realExpression.getParent()).getCondition())) { - realExpression = (PsiExpression)realExpression.getParent(); - } - PsiElement parent = realExpression.getParent(); - if (parent instanceof PsiReferenceExpression || parent instanceof PsiArrayAccessExpression) { - return expression; - } - if (parent instanceof PsiPolyadicExpression) { - IElementType tokenType = ((PsiPolyadicExpression)parent).getOperationTokenType(); - if (tokenType.equals(JavaTokenType.PLUS)) { - if (TypeUtils.isJavaLangString(((PsiPolyadicExpression)parent).getType())) { - return null; - } - } - return expression; - } - PsiParameter parameter = MethodCallUtils.getParameterForArgument(realExpression); - if (parameter != null && NullableNotNullManager.isNotNull(parameter)) { - return expression; - } - return null; - } - }, - ClassCast { - @Override - boolean isNecessaryCheck(PsiExpression operand, PsiExpression condition, boolean negated) { - if (negated) return false; - if (condition instanceof PsiInstanceOfExpression) { - PsiExpression op = ((PsiInstanceOfExpression)condition).getOperand(); - return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(op, operand); - } - return false; - } - - @Override - PsiExpression extractOperand(PsiExpression expression) { - if (expression instanceof PsiTypeCastExpression) { - return ((PsiTypeCastExpression)expression).getOperand(); - } - return null; - } - }, - ArrayIndex { - @Override - boolean isNecessaryCheck(PsiExpression operand, PsiExpression condition, boolean negated) { - if (condition instanceof PsiBinaryExpression) { - IElementType token = ((PsiBinaryExpression)condition).getOperationTokenType(); - if (ComparisonUtils.isComparisonOperation(token) && !token.equals(JavaTokenType.EQEQ) && !token.equals(JavaTokenType.NE)) { - PsiExpression left = ((PsiBinaryExpression)condition).getLOperand(); - PsiExpression right = ((PsiBinaryExpression)condition).getROperand(); - return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(left, operand) || - EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(right, operand); - } - } - return false; - } - - @Override - PsiExpression extractOperand(PsiExpression expression) { - if (expression instanceof PsiArrayAccessExpression) { - return ((PsiArrayAccessExpression)expression).getIndexExpression(); - } - return null; - } - }; - - abstract boolean isNecessaryCheck(PsiExpression operand, PsiExpression condition, boolean negated); - - abstract PsiExpression extractOperand(PsiExpression expression); + } + return false; } + + private abstract static class ExceptionProblem { + final PsiExpression myOperand; - private static class Problem { - private final ExceptionKind myKind; - private final PsiExpression myOperand; - - private Problem(ExceptionKind kind, PsiExpression operand) { - myKind = kind; + ExceptionProblem(PsiExpression operand) { myOperand = operand; } - @NotNull - static List fromExpression(PsiExpression expression) { - List problems = new ArrayList<>(); - for (ExceptionKind kind : ExceptionKind.values()) { - PsiExpression operand = kind.extractOperand(expression); - if (operand != null) { - problems.add(new Problem(kind, operand)); + abstract boolean isNecessaryCheck(PsiExpression condition, boolean negated); + } + + static final class NullDereferenceExceptionProblem extends ExceptionProblem { + private NullDereferenceExceptionProblem(PsiExpression operand) { + super(operand); + } + + @Override + boolean isNecessaryCheck(PsiExpression condition, boolean negated) { + if (condition instanceof PsiBinaryExpression) { + IElementType tokenType = ((PsiBinaryExpression)condition).getOperationTokenType(); + if (tokenType.equals(JavaTokenType.EQEQ) || tokenType.equals(JavaTokenType.NE)) { + boolean notNull = negated != tokenType.equals(JavaTokenType.EQEQ); + ContractReturnValue returnValue = notNull ? ContractReturnValue.returnNotNull() : ContractReturnValue.returnNull(); + PsiExpression left = ((PsiBinaryExpression)condition).getLOperand(); + PsiExpression right = ((PsiBinaryExpression)condition).getROperand(); + if (ExpressionUtils.isNullLiteral(left)) { + return hasContract(right, myOperand, returnValue); + } + if (ExpressionUtils.isNullLiteral(right)) { + return hasContract(left, myOperand, returnValue); + } } } - return problems; + return hasContract(condition, myOperand, ContractReturnValue.returnBoolean(negated)); } + static NullDereferenceExceptionProblem from(PsiExpression expression) { + if (expression instanceof PsiLiteralExpression || + expression instanceof PsiParenthesizedExpression || + expression instanceof PsiTypeCastExpression || + expression instanceof PsiConditionalExpression || + NullabilityUtil.getExpressionNullability(expression) == Nullability.NOT_NULL) { + return null; + } + PsiExpression realExpression = expression; + while (realExpression.getParent() instanceof PsiParenthesizedExpression || + realExpression.getParent() instanceof PsiTypeCastExpression || + (realExpression.getParent() instanceof PsiConditionalExpression && + realExpression != ((PsiConditionalExpression)realExpression.getParent()).getCondition())) { + realExpression = (PsiExpression)realExpression.getParent(); + } + PsiElement parent = realExpression.getParent(); + if (parent instanceof PsiReferenceExpression || parent instanceof PsiArrayAccessExpression) { + return new NullDereferenceExceptionProblem(expression); + } + if (parent instanceof PsiPolyadicExpression) { + IElementType tokenType = ((PsiPolyadicExpression)parent).getOperationTokenType(); + if (tokenType.equals(JavaTokenType.PLUS)) { + if (TypeUtils.isJavaLangString(((PsiPolyadicExpression)parent).getType())) { + return null; + } + } + return new NullDereferenceExceptionProblem(expression); + } + PsiParameter parameter = MethodCallUtils.getParameterForArgument(realExpression); + if (parameter != null && NullableNotNullManager.isNotNull(parameter)) { + return new NullDereferenceExceptionProblem(expression); + } + return null; + } + } + + static final class ClassCastExceptionProblem extends ExceptionProblem { + private ClassCastExceptionProblem(PsiExpression operand) { + super(operand); + } + + @Override boolean isNecessaryCheck(PsiExpression condition, boolean negated) { - return myKind.isNecessaryCheck(myOperand, condition, negated); + if (negated) return false; + if (condition instanceof PsiInstanceOfExpression) { + PsiExpression op = ((PsiInstanceOfExpression)condition).getOperand(); + return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(op, myOperand); + } + return false; + } + + static ClassCastExceptionProblem from(PsiExpression expression) { + if (expression instanceof PsiTypeCastExpression) { + return new ClassCastExceptionProblem(((PsiTypeCastExpression)expression).getOperand()); + } + return null; + } + } + + static final class ArrayIndexExceptionProblem extends ExceptionProblem { + private ArrayIndexExceptionProblem(PsiExpression operand) { + super(operand); + } + + @Override + boolean isNecessaryCheck(PsiExpression condition, boolean negated) { + if (condition instanceof PsiBinaryExpression) { + IElementType token = ((PsiBinaryExpression)condition).getOperationTokenType(); + if (ComparisonUtils.isComparisonOperation(token) && !token.equals(JavaTokenType.EQEQ) && !token.equals(JavaTokenType.NE)) { + PsiExpression left = ((PsiBinaryExpression)condition).getLOperand(); + PsiExpression right = ((PsiBinaryExpression)condition).getROperand(); + return EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(left, myOperand) || + EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(right, myOperand); + } + } + return false; + } + + static ArrayIndexExceptionProblem from(PsiExpression expression) { + if (expression instanceof PsiArrayAccessExpression) { + return new ArrayIndexExceptionProblem(((PsiArrayAccessExpression)expression).getIndexExpression()); + } + return null; + } + } + + static final class ContractFailExceptionProblem extends ExceptionProblem { + private final DfaValueFactory myFactory; + private final List myConditions; + + ContractFailExceptionProblem(DfaValueFactory factory, List conditions) { + super(null); + myFactory = factory; + myConditions = conditions; + } + + @Override + boolean isNecessaryCheck(PsiExpression condition, boolean negated) { + if (condition instanceof PsiMethodCallExpression) { + PsiMethodCallExpression call = (PsiMethodCallExpression)condition; + List contracts = JavaMethodContractUtil.getMethodCallContracts(call); + if (contracts.isEmpty()) return false; + for (MethodContract contract : contracts) { + if (!(contract.getReturnValue() instanceof BooleanReturnValue)) continue; + boolean retValue = ((BooleanReturnValue)contract.getReturnValue()).getValue(); + List conditions = contract.getConditions(); + if (conditions.size() != 1) continue; + ContractValue cond = conditions.get(0); + DfaValue value = cond.fromCall(myFactory, call); + if (value instanceof DfaRelationValue) { + if (myConditions.contains(retValue == negated ? value : value.createNegated())) { + return true; + } + } + } + return false; + } + if (condition instanceof PsiBinaryExpression) { + PsiBinaryExpression binOp = (PsiBinaryExpression)condition; + DfaRelationValue.RelationType relationType = DfaRelationValue.RelationType.fromElementType(binOp.getOperationTokenType()); + if (relationType != null) { + PsiExpression left = binOp.getLOperand(); + PsiExpression right = binOp.getROperand(); + DfaValue leftVal = myFactory.createValue(left); + DfaValue rightVal = myFactory.createValue(right); + DfaValue value1 = myFactory.createCondition(leftVal, relationType, rightVal); + DfaValue value2 = myFactory.createCondition(rightVal, relationType.getFlipped(), leftVal); + if (value1 instanceof DfaRelationValue) { + if (myConditions.contains(negated ? value1 : value1.createNegated())) { + return true; + } + } + if (value2 instanceof DfaRelationValue) { + if (myConditions.contains(negated ? value2 : value2.createNegated())) { + return true; + } + } + } + } + return false; + } + + static ContractFailExceptionProblem from(PsiExpression expression) { + if (expression instanceof PsiCallExpression) { + PsiCallExpression call = (PsiCallExpression)expression; + List contracts = JavaMethodContractUtil.getMethodCallContracts(call); + contracts = ContainerUtil.filter(contracts, c -> c.getReturnValue().isFail() && c.getConditions().size() == 1); + if (contracts.isEmpty()) return null; + DfaValueFactory factory = new DfaValueFactory(null, false); + List conditions = new ArrayList<>(); + for (MethodContract contract : contracts) { + ContractValue condition = contract.getConditions().get(0); + DfaValue conditionValue = condition.fromCall(factory, call); + if (conditionValue instanceof DfaRelationValue) { + conditions.add((DfaRelationValue)conditionValue); + } + } + return new ContractFailExceptionProblem(factory, conditions); + } + return null; } } + private static final List> PROBLEM_EXTRACTORS = Arrays.asList( + NullDereferenceExceptionProblem::from, ClassCastExceptionProblem::from, ArrayIndexExceptionProblem::from, + ContractFailExceptionProblem::from + ); + + @NotNull + static List fromExpression(PsiExpression expression) { + List problems = new ArrayList<>(); + for (Function extractor : PROBLEM_EXTRACTORS) { + ExceptionProblem exceptionProblem = extractor.apply(expression); + if (exceptionProblem != null) { + problems.add(exceptionProblem); + } + } + return problems; + } + private static boolean areConditionsNecessaryFor(PsiExpression[] conditions, PsiExpression operand, boolean negated) { - List problems = SyntaxTraverser.psiTraverser(operand) - .traverse().filter(PsiExpression.class).flatMap(Problem::fromExpression).filter(Objects::nonNull) + List problems = SyntaxTraverser.psiTraverser(operand) + .traverse().filter(PsiExpression.class).flatMap(ReorderingUtils::fromExpression).filter(Objects::nonNull) .toList(); if (problems.isEmpty()) return false; for (PsiExpression condition : conditions) { @@ -275,7 +410,7 @@ public class ReorderingUtils { return false; } - private static boolean isConditionNecessary(PsiExpression condition, List problems, boolean negated) { + private static boolean isConditionNecessary(PsiExpression condition, List problems, boolean negated) { condition = PsiUtil.skipParenthesizedExprDown(condition); if (condition == null) return false; if (BoolUtils.isNegation(condition)) { @@ -300,7 +435,7 @@ public class ReorderingUtils { return true; } } - for (Problem problem : problems) { + for (ExceptionProblem problem : problems) { if (problem.isNecessaryCheck(condition, negated)) { return true; } @@ -308,29 +443,6 @@ public class ReorderingUtils { return false; } - private static boolean lastOperandImpliesPrevious(PsiPolyadicExpression expression, PsiExpression[] operands) { - assert operands.length > 1; - boolean and = expression.getOperationTokenType() == JavaTokenType.ANDAND; - if (Arrays.stream(operands).anyMatch(e -> !PsiTreeUtil.processElements(e, element -> !isErroneous(element)))) return false; - PsiExpression lastOperand = operands[operands.length - 1]; - if (areConditionsNecessaryFor(Arrays.copyOf(operands, operands.length - 1), lastOperand, !and)) return true; - String expressionText = StreamEx.of(operands, 0, operands.length - 1).prepend(lastOperand) - .map(PsiExpression::getText).joining(and ? " && " : " || "); - PsiElementFactory factory = JavaPsiFacade.getElementFactory(expression.getProject()); - PsiPolyadicExpression expressionToAnalyze = (PsiPolyadicExpression)factory.createExpressionFromText(expressionText, expression); - PsiExpression[] newOperands = expressionToAnalyze.getOperands(); - Map map = computeOperandValues(expressionToAnalyze, false); - ThreeState state = ThreeState.fromBoolean(and); - Set redundantOperands = StreamEx.of(newOperands).skip(1).filterBy(map::get, state).toSet(); - if (redundantOperands.isEmpty()) return false; - if (operands.length == 2) { - return !Boolean.valueOf(and).equals(DfaUtil.computeValue(operands[0])); - } - expressionText = StreamEx.of(operands, 0, operands.length - 1).map(PsiExpression::getText).joining(and ? " && " : " || "); - expressionToAnalyze = (PsiPolyadicExpression)factory.createExpressionFromText(expressionText, expression); - return !computeOperandValues(expressionToAnalyze, false).values().contains(state); - } - private static boolean isErroneous(PsiElement element) { return element instanceof PsiErrorElement || element instanceof PsiLiteralExpression && @@ -379,39 +491,4 @@ public class ReorderingUtils { return true; }); } - - @NotNull - public static Map computeOperandValues(PsiPolyadicExpression expressionToAnalyze, boolean skipNullityUpdate) { - DataFlowRunner runner = new StandardDataFlowRunner(false, expressionToAnalyze); - Map values = new HashMap<>(); - StandardInstructionVisitor visitor = new StandardInstructionVisitor() { - @Override - protected boolean checkNotNullable(DfaMemoryState state, - DfaValue value, - @Nullable NullabilityProblemKind.NullabilityProblem problem) { - return skipNullityUpdate || super.checkNotNullable(state, value, problem); - } - - @Override - protected void beforeExpressionPush(@NotNull DfaValue value, - @NotNull PsiExpression expression, - @Nullable TextRange range, - @NotNull DfaMemoryState state) { - super.beforeExpressionPush(value, expression, range, state); - if (PsiUtil.skipParenthesizedExprUp(expression.getParent()) != expressionToAnalyze) return; - ThreeState old = values.get(expression); - if (old == ThreeState.UNSURE) return; - ThreeState result = ThreeState.UNSURE; - if (value instanceof DfaConstValue) { - Object bool = ((DfaConstValue)value).getValue(); - if (bool instanceof Boolean) { - result = ThreeState.fromBoolean((Boolean)bool); - } - } - values.put(expression, old == null || old == result ? result : ThreeState.UNSURE); - } - }; - RunnerResult result = runner.analyzeMethod(expressionToAnalyze, visitor); - return result == RunnerResult.OK ? values : Collections.emptyMap(); - } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConditionCoveredByFurtherConditionInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConditionCoveredByFurtherConditionInspection.java index b5024eb5de2b..5e4d7ce681e1 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConditionCoveredByFurtherConditionInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/controlflow/ConditionCoveredByFurtherConditionInspection.java @@ -3,7 +3,14 @@ package com.siyeh.ig.controlflow; import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.codeInspection.dataFlow.DfaUtil; +import com.intellij.codeInspection.dataFlow.*; +import com.intellij.codeInspection.dataFlow.value.DfaConstValue; +import com.intellij.codeInspection.dataFlow.value.DfaValue; +import com.intellij.openapi.application.Application; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Attachment; +import com.intellij.openapi.diagnostic.RuntimeExceptionWithAttachments; +import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiExpressionTrimRenderer; @@ -16,11 +23,9 @@ import com.siyeh.ig.psiutils.ReorderingUtils; import one.util.streamex.IntStreamEx; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; +import java.util.*; public class ConditionCoveredByFurtherConditionInspection extends AbstractBaseJavaLocalInspectionTool { @NotNull @@ -97,10 +102,19 @@ public class ConditionCoveredByFurtherConditionInspection extends AbstractBaseJa Object value = DfaUtil.computeValue(operands.get(0)); return Boolean.valueOf(and).equals(value) ? new int[]{0} : ArrayUtil.EMPTY_INT_ARRAY; } - PsiPolyadicExpression expressionToAnalyze = (PsiPolyadicExpression)JavaPsiFacade.getElementFactory(context.getProject()) - .createExpressionFromText(StreamEx.ofReversed(operands).map(PsiElement::getText).joining(and ? " && " : " || "), context); + String text = StreamEx.ofReversed(operands).map(PsiElement::getText).joining(and ? " && " : " || "); + PsiExpression expression = JavaPsiFacade.getElementFactory(context.getProject()).createExpressionFromText(text, context); + if (!(expression instanceof PsiPolyadicExpression)) { + Application application = ApplicationManager.getApplication(); + if (application.isEAP() || application.isInternal()) { + throw new RuntimeExceptionWithAttachments("Unexpected expression type: " + expression.getClass().getName(), + new Attachment("reversed.txt", text)); + } + return ArrayUtil.EMPTY_INT_ARRAY; + } + PsiPolyadicExpression expressionToAnalyze = (PsiPolyadicExpression)expression; List reversedOperands = Arrays.asList(expressionToAnalyze.getOperands()); - Map values = ReorderingUtils.computeOperandValues(expressionToAnalyze, true); + Map values = computeOperandValues(expressionToAnalyze); return StreamEx.ofKeys(values, ThreeState.fromBoolean(and)::equals) .mapToInt(operand -> IntStreamEx.ofIndices(reversedOperands, op -> PsiTreeUtil.isAncestor(op, operand, false)) .findFirst().orElse(0)) @@ -108,4 +122,39 @@ public class ConditionCoveredByFurtherConditionInspection extends AbstractBaseJa .toArray(); } } + + @NotNull + private static Map computeOperandValues(PsiPolyadicExpression expressionToAnalyze) { + DataFlowRunner runner = new StandardDataFlowRunner(false, expressionToAnalyze); + Map values = new HashMap<>(); + StandardInstructionVisitor visitor = new StandardInstructionVisitor() { + @Override + protected boolean checkNotNullable(DfaMemoryState state, + DfaValue value, + @Nullable NullabilityProblemKind.NullabilityProblem problem) { + return true; + } + + @Override + protected void beforeExpressionPush(@NotNull DfaValue value, + @NotNull PsiExpression expression, + @Nullable TextRange range, + @NotNull DfaMemoryState state) { + super.beforeExpressionPush(value, expression, range, state); + if (PsiUtil.skipParenthesizedExprUp(expression.getParent()) != expressionToAnalyze) return; + ThreeState old = values.get(expression); + if (old == ThreeState.UNSURE) return; + ThreeState result = ThreeState.UNSURE; + if (value instanceof DfaConstValue) { + Object bool = ((DfaConstValue)value).getValue(); + if (bool instanceof Boolean) { + result = ThreeState.fromBoolean((Boolean)bool); + } + } + values.put(expression, old == null || old == result ? result : ThreeState.UNSURE); + } + }; + RunnerResult result = runner.analyzeMethod(expressionToAnalyze, visitor); + return result == RunnerResult.OK ? values : Collections.emptyMap(); + } } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html index 7a2ca93f11e4..279b636a6baf 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/StringEqualsEmptyString.html @@ -1,11 +1,12 @@ -Reports .equals() being called to compare a String with an empty string. -Using .isEmpty() is more clear and could be slightly more performant. +Reports cases when .equals() is called to compare a String with an empty string. In this case, using .isEmpty() is better as +it shows you exactly what you're checking.

- The check like "".equals(str) returns false when str is null, so - an explicit null-check could be inserted when replacing with isEmpty(). - Use a checkbox below to suppress warning when value could be nullable. + Some checks, for example, the "".equals(str) check, return false when str is null. It means that an explicit null-check + could be inserted when you are replacing .equals() with isEmpty(). Use a checkbox below to suppress the warning when a + string value could be nullable. +

\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/psiutils/ReorderingUtilsTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/psiutils/ReorderingUtilsTest.java index 582fb23bbe73..abbff7a8fd4d 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/psiutils/ReorderingUtilsTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/psiutils/ReorderingUtilsTest.java @@ -1,6 +1,7 @@ // 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. package com.siyeh.ig.psiutils; +import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.ide.highlighter.JavaFileType; import com.intellij.psi.*; import com.intellij.testFramework.LightCodeInsightTestCase; @@ -9,56 +10,97 @@ import org.intellij.lang.annotations.Language; public class ReorderingUtilsTest extends LightCodeInsightTestCase { private static final String PREFIX = "import java.util.Optional;\n" + + "import java.util.List;\n" + "/** @noinspection all*/\n" + - "class X {boolean test(Object obj, String str, int x, int y, String[] arr, Optional opt) { return "; + "class X {Object test(Object obj, String str, int x, int y, String[] arr, " + + "Optional opt, List list) { return "; @SuppressWarnings("UnnecessarySemicolon") - private static final String SUFFIX = ";}}"; + private static final String SUFFIX = ";} static Object nullNull(Object obj) {return obj == null ? null : obj.hashCode();}}"; + private static final String SELECTION_START = "/*<*/"; + private static final String SELECTION_END = "/*>*/"; public void testSimple() { - checkCanBeReordered("x > 0 && x < 10", 1, ThreeState.YES); - checkCanBeReordered("arr == null && x > 10 && y < 5", 2, ThreeState.YES); + checkCanBeReordered("x > 0 && /*<*/x < 10/*>*/", ThreeState.YES); + checkCanBeReordered("arr == null && x > 10 && /*<*/y < 5/*>*/", ThreeState.YES); } public void testTrueFirst() { - checkCanBeReordered("x > 10 && x > 0 && x > arr.length", 2, ThreeState.UNSURE); - checkCanBeReordered("(x > 10 || x < 20) && x > arr.length", 1, ThreeState.UNSURE); + checkCanBeReordered("x > 10 && x > 0 && /*<*/x > arr.length/*>*/", ThreeState.UNSURE); + checkCanBeReordered("(x > 10 || x < 20) && /*<*/x > arr.length/*>*/", ThreeState.UNSURE); } public void testNpe() { - checkCanBeReordered("obj != null && obj.hashCode() > 10", 1, ThreeState.NO); - checkCanBeReordered("obj == null || obj.hashCode() > 10", 1, ThreeState.NO); - checkCanBeReordered("arr != null && obj.hashCode() > 10", 1, ThreeState.UNSURE); + checkCanBeReordered("obj != null && /*<*/obj.hashCode() > 10/*>*/", ThreeState.NO); + checkCanBeReordered("obj == null || /*<*/obj.hashCode() > 10/*>*/", ThreeState.NO); + checkCanBeReordered("arr != null && /*<*/obj.hashCode() > 10/*>*/", ThreeState.UNSURE); } public void testCast() { - checkCanBeReordered("obj instanceof String && ((String)obj).isEmpty()", 1, ThreeState.NO); - checkCanBeReordered("obj instanceof String && test(null, (String)obj, 0,0, null, Optional.empty())", 1, ThreeState.NO); - checkCanBeReordered("obj instanceof Integer && ((Number)obj).intValue() == 0", 1, ThreeState.NO); + checkCanBeReordered("obj instanceof String && /*<*/((String)obj).isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("obj instanceof String && /*<*/nullNull((String)obj) == null/*>*/", ThreeState.NO); + checkCanBeReordered("obj instanceof Integer && /*<*/((Number)obj).intValue() == 0/*>*/", ThreeState.NO); + } + + public void testContract() { + checkCanBeReordered("new Object().equals(obj) && /*<*/obj.hashCode() == 0/*>*/", ThreeState.NO); + checkCanBeReordered("nullNull(obj) != null && /*<*/obj.hashCode() == 0/*>*/", ThreeState.NO); + checkCanBeReordered("nullNull(obj) == null || /*<*/obj.hashCode() == 0/*>*/", ThreeState.NO); + checkCanBeReordered("nullNull(nullNull(obj)) == null || /*<*/obj.hashCode() == 0/*>*/", ThreeState.NO); } public void testArrayBounds() { - checkCanBeReordered("x >= 0 && arr[x].isEmpty()", 1, ThreeState.NO); - checkCanBeReordered("x < arr.length && arr[x].isEmpty()", 1, ThreeState.NO); - checkCanBeReordered("x >= 0 && x < arr.length && arr[x].isEmpty()", 2, ThreeState.NO); - checkCanBeReordered("y >= 0 && arr[x].isEmpty()", 1, ThreeState.UNSURE); - checkCanBeReordered("x > 0 && arr[x].isEmpty()", 1, ThreeState.NO); + checkCanBeReordered("x >= 0 && /*<*/arr[x].isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("x < arr.length && /*<*/arr[x].isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("x >= 0 && x < arr.length && /*<*/arr[x].isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("y >= 0 && /*<*/arr[x].isEmpty()/*>*/", ThreeState.UNSURE); + checkCanBeReordered("x > 0 && /*<*/arr[x].isEmpty()/*>*/", ThreeState.NO); // Not supported - checkCanBeReordered("x > 0 && arr[x-1].isEmpty()", 1, ThreeState.UNSURE); + checkCanBeReordered("x > 0 && /*<*/arr[x-1].isEmpty()/*>*/", ThreeState.UNSURE); + } + + public void testStringBounds() { + checkCanBeReordered("x >= 0 && /*<*/str.charAt(x) == 'a'/*>*/", ThreeState.NO); + checkCanBeReordered("y >= 0 && /*<*/str.charAt(x) == 'a'/*>*/", ThreeState.UNSURE); + checkCanBeReordered("x < str.length() && /*<*/str.charAt(x) == 'a'/*>*/", ThreeState.NO); + checkCanBeReordered("x <= str.length() && /*<*/str.substring(x) == 'a'/*>*/", ThreeState.NO); + // Not supported + checkCanBeReordered("x < str.length() && /*<*/str.substring(x) == 'a'/*>*/", ThreeState.UNSURE); + } + + public void testListBounds() { + checkCanBeReordered("x >= 0 && /*<*/list.get(x).isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("x < list.size() && /*<*/list.get(x).isEmpty()/*>*/", ThreeState.NO); + checkCanBeReordered("list.size() > x && /*<*/list.get(x).isEmpty()/*>*/", ThreeState.NO); } public void testOptional() { - checkCanBeReordered("opt.isPresent() && opt.get().isEmpty()", 1, ThreeState.NO); + checkCanBeReordered("opt.isPresent() && /*<*/opt.get().isEmpty()/*>*/", ThreeState.NO); + } + + public void testTernary() { + checkCanBeReordered("x > y ? /*<*/y/*>*/ : x", ThreeState.YES); + checkCanBeReordered("str == null ? \"\" : /*<*/str.trim()/*>*/", ThreeState.NO); + checkCanBeReordered("str != null ? /*<*/str.trim()/*>*/ : \"\"", ThreeState.NO); + checkCanBeReordered("str != null ? \"\" : /*<*/str.trim()/*>*/", ThreeState.UNSURE); + checkCanBeReordered("str == null ? /*<*/str.trim()/*>*/ : \"\"", ThreeState.UNSURE); } private static void checkCanBeReordered(@Language(value = "JAVA", prefix = PREFIX, suffix = SUFFIX) String expressionText, - int operand, ThreeState expectedResult) { String file = PREFIX + expressionText + SUFFIX; PsiJavaFile javaFile = (PsiJavaFile)PsiFileFactory.getInstance(getProject()).createFileFromText("X.java", JavaFileType.INSTANCE, file); PsiCodeBlock body = javaFile.getClasses()[0].getMethods()[0].getBody(); assertNotNull(body); - PsiPolyadicExpression expression = (PsiPolyadicExpression)((PsiReturnStatement)body.getStatements()[0]).getReturnValue(); + PsiExpression expression = ((PsiReturnStatement)body.getStatements()[0]).getReturnValue(); assertNotNull(expression); - assertSame(expressionText, expectedResult, ReorderingUtils.canExtract(expression, expression.getOperands()[operand])); + int startOffset = expressionText.indexOf(SELECTION_START); + assertTrue(startOffset >= 0); + int endOffset = expressionText.indexOf(SELECTION_END); + assertTrue(endOffset >= 0); + int expressionStart = expression.getTextRange().getStartOffset(); + PsiExpression subExpression = CodeInsightUtil.findExpressionInRange(javaFile, startOffset + SELECTION_START.length() + expressionStart, + endOffset + expressionStart); + assertNotNull(subExpression); + assertSame(expressionText, expectedResult, ReorderingUtils.canExtract(expression, subExpression)); } } \ No newline at end of file diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java index 9bfba6912726..1c492447c87e 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntBuildMessageView.java @@ -85,6 +85,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private AntBuildFileBase myBuildFile; private final List myTargets; private final List myAdditionalProperties; + @AntMessage.Priority private int myPriorityThreshold = PRIORITY_INFO; private volatile int myErrorCount; private volatile int myWarningCount; @@ -181,7 +182,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O return myPriorityThreshold == PRIORITY_DEBUG; } - private synchronized void changeDetalizationLevel(int priorityThreshold) { + private synchronized void changeDetalizationLevel(@AntMessage.Priority int priorityThreshold) { myPriorityThreshold = priorityThreshold; TreeView.TreeSelection selection = myTreeView.getSelection(); @@ -393,7 +394,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O addCommand(new StartTaskCommand(taskName)); } - public void outputMessage(final String text, final int priority) { + public void outputMessage(final String text, @AntMessage.Priority int priority) { final AntMessage customizedMessage = getCustomizedMessage(text, priority); final AntMessage message = customizedMessage != null ? customizedMessage @@ -403,7 +404,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O } @Nullable - private AntMessage getCustomizedMessage(final String text, final int priority) { + private AntMessage getCustomizedMessage(final String text, @AntMessage.Priority int priority) { AntMessage customizedMessage = null; for (AntMessageCustomizer customizer : myMessageCustomizers) { @@ -416,7 +417,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O return customizedMessage; } - public void outputError(String error, int priority) { + public void outputError(String error, @AntMessage.Priority int priority) { updateErrorAndWarningCounters(priority); final AntMessage message = createErrorMessage(priority, error); addCommand(new AddMessageCommand(message)); @@ -433,7 +434,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O } - private void updateErrorAndWarningCounters(int priority) { + private void updateErrorAndWarningCounters(@AntMessage.Priority int priority) { if (priority == PRIORITY_ERR) { myErrorCount++; } @@ -465,7 +466,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O return null; } - private static AntMessage createErrorMessage(int priority, String text) { + private static AntMessage createErrorMessage(@AntMessage.Priority int priority, String text) { text = StringUtil.trimStart(text, FILE_PREFIX); int afterLineNumberIndex = text.indexOf(": "); // end of file_name_and_line_number sequence @@ -623,12 +624,14 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O } private abstract static class LogCommand { + @AntMessage.Priority private final int myPriority; - LogCommand(int priority) { + LogCommand(@AntMessage.Priority int priority) { myPriority = priority; } + @AntMessage.Priority final int getPriority() { return myPriority; } @@ -652,7 +655,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class StartBuildCommand extends MessageCommand { StartBuildCommand(String buildName) { - super(new AntMessage(MessageType.BUILD, 0, buildName, null, 0, 0)); + super(new AntMessage(MessageType.BUILD, PRIORITY_ERR, buildName, null, 0, 0)); } @Override @@ -663,7 +666,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class BuildFailedCommand extends MessageCommand { BuildFailedCommand(String buildName) { - super(new AntMessage(MessageType.ERROR, 0, AntBundle.message("cannot.start.build.name.error.message", buildName), null, 0, 0)); + super(new AntMessage(MessageType.ERROR, PRIORITY_ERR, AntBundle.message("cannot.start.build.name.error.message", buildName), null, 0, 0)); } @Override @@ -676,7 +679,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private final String myFinishStatusText; FinishBuildCommand(String finishStatusText) { - super(0); + super(PRIORITY_ERR); myFinishStatusText = finishStatusText; } @@ -688,7 +691,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class StartTargetCommand extends MessageCommand { StartTargetCommand(String targetName) { - super(new AntMessage(MessageType.TARGET, 0, targetName, null, 0, 0)); + super(new AntMessage(MessageType.TARGET, PRIORITY_ERR, targetName, null, 0, 0)); } @Override @@ -699,7 +702,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class FinishTargetCommand extends LogCommand { FinishTargetCommand() { - super(0); + super(PRIORITY_ERR); } @Override @@ -710,7 +713,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class StartTaskCommand extends MessageCommand { StartTaskCommand(String taskName) { - super(new AntMessage(MessageType.TASK, 0, taskName, null, 0, 0)); + super(new AntMessage(MessageType.TASK, PRIORITY_ERR, taskName, null, 0, 0)); } @Override @@ -721,7 +724,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O private static final class FinishTaskCommand extends LogCommand { FinishTaskCommand() { - super(0); + super(PRIORITY_ERR); } @Override diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessage.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessage.java index d11862076664..c88288485d83 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessage.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessage.java @@ -18,12 +18,15 @@ package com.intellij.lang.ant.config.execution; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.ArrayUtil; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.StringTokenizer; public final class AntMessage { private final AntBuildMessageView.MessageType myType; + @Priority private final int myPriority; private final String myText; private final String[] myTextLines; @@ -31,7 +34,7 @@ public final class AntMessage { private final int myLine; private final int myColumn; - public AntMessage(AntBuildMessageView.MessageType type, int priority, String text, VirtualFile file, int line, int column) { + public AntMessage(AntBuildMessageView.MessageType type, @Priority int priority, String text, VirtualFile file, int line, int column) { myType = type; myPriority = priority; myFile = file; @@ -46,7 +49,7 @@ public final class AntMessage { myTextLines = ArrayUtil.toStringArray(lines); } - public AntMessage(AntBuildMessageView.MessageType type, int priority, String[] lines, VirtualFile file, int line, int column) { + public AntMessage(AntBuildMessageView.MessageType type, @Priority int priority, String[] lines, VirtualFile file, int line, int column) { myType = type; myPriority = priority; myFile = file; @@ -60,6 +63,7 @@ public final class AntMessage { return myType; } + @Priority public int getPriority() { return myPriority; } @@ -83,4 +87,12 @@ public final class AntMessage { public int getColumn() { return myColumn; } + + @NotNull + public AntMessage withText(@NotNull String text) { + return new AntMessage(getType(), getPriority(), text, getFile(), getLine(), getColumn()); + } + + @MagicConstant(intValues = {AntBuildMessageView.PRIORITY_ERR, AntBuildMessageView.PRIORITY_WARN, AntBuildMessageView.PRIORITY_INFO, AntBuildMessageView.PRIORITY_VERBOSE, AntBuildMessageView.PRIORITY_DEBUG}) + public @interface Priority {} } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessageCustomizer.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessageCustomizer.java index 76fc7d15dacb..355126b9f89a 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessageCustomizer.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntMessageCustomizer.java @@ -8,7 +8,7 @@ public abstract class AntMessageCustomizer { public static final ExtensionPointName EP_NAME = ExtensionPointName.create("AntSupport.AntMessageCustomizer"); @Nullable - public AntMessage createCustomizedMessage(String text, int priority) { + public AntMessage createCustomizedMessage(String text, @AntMessage.Priority int priority) { return null; } } diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java index e781aad86447..e096d9177e59 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java @@ -118,7 +118,7 @@ public class OutputParser{ } - protected final void processTag(char tagName, final String tagValue, final int priority) { + protected final void processTag(char tagName, final String tagValue, @AntMessage.Priority int priority) { if (LOG.isDebugEnabled()) { LOG.debug(String.valueOf(tagName) + priority + "=" + tagValue); } @@ -139,7 +139,7 @@ public class OutputParser{ } if (IdeaAntLogger2.MESSAGE == tagName) { - myMessageView.outputMessage(tagValue, fixPriority(priority)); + myMessageView.outputMessage(tagValue, priority); } else if (IdeaAntLogger2.TARGET == tagName) { myMessageView.startTarget(tagValue); @@ -170,7 +170,8 @@ public class OutputParser{ } } - private static int fixPriority(int priority) { + @AntMessage.Priority + static int fixPriority(int priority) { if (priority == AntBuildMessageView.PRIORITY_ERR || priority == AntBuildMessageView.PRIORITY_WARN || priority == AntBuildMessageView.PRIORITY_INFO || diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser2.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser2.java index 913125cc7fe5..b1086243e80e 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser2.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser2.java @@ -65,7 +65,7 @@ final class OutputParser2 extends OutputParser implements PacketProcessor, Input } } else { - int priority = reader.readInt(); + int priority = fixPriority(reader.readInt()); char contentType = reader.readChar(); String message = reader.readLimitedString(); if (id == IdeaAntLogger2.BUILD_END) { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java index 37a276658044..bc53a1db0f02 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/TreeView.java @@ -240,8 +240,7 @@ public final class TreeView implements AntOutputView, OccurenceNavigator { @Override public void addJavacMessage(AntMessage message, String url) { final String builder = printMessage(message, url); - addJavacMessageImpl(new AntMessage(message.getType(), message.getPriority(), builder.toString() + message.getText(), - message.getFile(), message.getLine(), message.getColumn())); + addJavacMessageImpl(message.withText(builder + message.getText())); } @NotNull @@ -287,9 +286,7 @@ public final class TreeView implements AntOutputView, OccurenceNavigator { while (tokenizer.hasMoreElements()) { String line = (String)tokenizer.nextElement(); if (exceptionRootNode == null) { - AntMessage newMessage = new AntMessage(exception.getType(), exception.getPriority(), line, exception.getFile(), exception.getLine(), - exception.getColumn()); - exceptionRootNode = new MessageNode(newMessage, myProject, true); + exceptionRootNode = new MessageNode(exception.withText(line), myProject, true); myMessageItems.add(exceptionRootNode); } else if (showFullTrace) { diff --git a/plugins/devkit/devkit-core/src/completion/UiDefaultsHardcodedKeys.java b/plugins/devkit/devkit-core/src/completion/UiDefaultsHardcodedKeys.java index 9f95df7015d7..93c9bf2f857e 100644 --- a/plugins/devkit/devkit-core/src/completion/UiDefaultsHardcodedKeys.java +++ b/plugins/devkit/devkit-core/src/completion/UiDefaultsHardcodedKeys.java @@ -1361,6 +1361,7 @@ public final class UiDefaultsHardcodedKeys { "TabbedPane.hoverColor", "TabbedPane.underlineColor", "TabbedPane.disabledUnderlineColor", + "Table.stripeColor", "TitlePane.background", "ToolTip.actions.background", "ToolWindow.Button.hoverBackground", diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/navigation/KtLightClassCompatibilityTest.kt b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/navigation/KtLightClassCompatibilityTest.kt index 87fef6cd9d17..555328f4f387 100644 --- a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/navigation/KtLightClassCompatibilityTest.kt +++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/navigation/KtLightClassCompatibilityTest.kt @@ -8,7 +8,7 @@ class KtLightClassCompatibilityTest : LightCodeInsightFixtureTestCase() { fun testEnumConstructor() { myFixture.addFileToProject("pkg/MyEnum.kt", """ package pkg - enum class MyEnum(s1: String, @java.lang.Deprecated s2: String) { + enum class MyEnum(str1: String, @java.lang.Deprecated str2: String) { VAL("+", "-") }""".trimMargin()) checkConstructor("pkg.MyEnum") @@ -18,7 +18,7 @@ class KtLightClassCompatibilityTest : LightCodeInsightFixtureTestCase() { myFixture.addFileToProject("pkg/MyOuter.kt", """ package pkg class MyOuter() { - inner class MyInner(s1: String, @java.lang.Deprecated s2: String) + inner class MyInner(str1: String, @java.lang.Deprecated str2: String) }""".trimMargin()) checkConstructor("pkg.MyOuter.MyInner") } @@ -27,7 +27,7 @@ class KtLightClassCompatibilityTest : LightCodeInsightFixtureTestCase() { myFixture.addFileToProject("pkg/MyOuter.kt", """ package pkg class MyOuter() { - class MyNested(s1: String, @java.lang.Deprecated s2: String) + class MyNested(str1: String, @java.lang.Deprecated str2: String) }""".trimMargin()) checkConstructor("pkg.MyOuter.MyNested") } @@ -38,6 +38,8 @@ class KtLightClassCompatibilityTest : LightCodeInsightFixtureTestCase() { assertEquals(1, constructors.size) val parameters = constructors[0].parameters assertEquals(2, parameters.size) + assertEquals("str1", parameters[0].name) + assertEquals("str2", parameters[1].name) assertFalse(parameters[0].hasAnnotation(CommonClassNames.JAVA_LANG_DEPRECATED)) assertTrue(parameters[1].hasAnnotation(CommonClassNames.JAVA_LANG_DEPRECATED)) } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index 098d8de7a8ea..eedf76b5c14b 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -36,10 +36,7 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; import org.jetbrains.plugins.groovy.lang.psi.impl.*; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.literals.GrLiteralImpl; import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrReferenceTypeEnhancer; -import org.jetbrains.plugins.groovy.lang.psi.util.GdkMethodUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GrTraitUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.lang.psi.util.*; import org.jetbrains.plugins.groovy.lang.resolve.DependentResolver; import org.jetbrains.plugins.groovy.lang.resolve.GroovyResolver; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -51,7 +48,7 @@ import java.util.*; import static kotlin.LazyKt.lazy; import static org.jetbrains.plugins.groovy.lang.psi.GroovyTokenSets.REFERENCE_DOTS; -import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyLValueUtil.isLValue; +import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyLValueUtil.getRValue; import static org.jetbrains.plugins.groovy.lang.psi.util.GroovyLValueUtil.isRValue; import static org.jetbrains.plugins.groovy.lang.resolve.GrReferenceResolveRunnerKt.resolveReferenceExpression; @@ -72,9 +69,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl isRValue(this) ? new GrRValueExpressionReference(this) : null ); - private final Lazy myLValueReference = lazy( - () -> isLValue(this) ? new GrLValueExpressionReference(this) : null - ); + private final Lazy myLValueReference = lazy(() -> { + RValue rValue = getRValue(this); + return rValue == null ? null : new GrLValueExpressionReference(this, rValue.getArgument()); + }); @Override public void accept(@NotNull GroovyElementVisitor visitor) { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt index dc843d1e8101..8c705224b98e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionReference.kt @@ -1,8 +1,23 @@ // 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. package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions +import com.intellij.psi.PsiElement +import org.jetbrains.plugins.groovy.lang.psi.GroovyElementTypes import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrSuperReferenceResolver.resolveSuperExpression +import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrThisReferenceResolver.resolveThisExpression +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil +import org.jetbrains.plugins.groovy.lang.resolve.GrReferenceResolveRunner +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor +import org.jetbrains.plugins.groovy.lang.resolve.api.Argument import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyCachingReference +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyLValueProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyRValueProcessor +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolveKind +import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolveKind.* +import java.util.* abstract class GrReferenceExpressionReference(ref: GrReferenceExpressionImpl) : GroovyCachingReference(ref) { @@ -14,19 +29,64 @@ abstract class GrReferenceExpressionReference(ref: GrReferenceExpressionImpl) : return doResolveNonStatic(incomplete) } - abstract fun doResolveNonStatic(incomplete: Boolean): Collection + protected open fun doResolveNonStatic(incomplete: Boolean): Collection { + val expression = element + val name = expression.referenceName ?: return emptyList() + val kinds = expression.resolveKinds() + val processor = buildProcessor(name, expression, kinds) + GrReferenceResolveRunner(expression, processor).resolveReferenceExpression() + return processor.results + } + + protected abstract fun buildProcessor(name: String, place: PsiElement, kinds: Set): GrResolverProcessor<*> } class GrRValueExpressionReference(ref: GrReferenceExpressionImpl) : GrReferenceExpressionReference(ref) { override fun doResolveNonStatic(incomplete: Boolean): Collection { - return element.doPolyResolve(incomplete, true) + val expression = element + if (expression.parent is GrMethodCall || incomplete) { + return expression.doPolyResolve(incomplete, true) + } + + expression.handleSpecialCases()?.let { + return it + } + return super.doResolveNonStatic(incomplete) + } + + override fun buildProcessor(name: String, place: PsiElement, kinds: Set): GrResolverProcessor<*> { + return GroovyRValueProcessor(name, place, kinds) } } -class GrLValueExpressionReference(ref: GrReferenceExpressionImpl) : GrReferenceExpressionReference(ref) { +class GrLValueExpressionReference(ref: GrReferenceExpressionImpl, private val argument: Argument?) : GrReferenceExpressionReference(ref) { - override fun doResolveNonStatic(incomplete: Boolean): Collection { - return element.doPolyResolve(incomplete, false) + override fun buildProcessor(name: String, place: PsiElement, kinds: Set): GrResolverProcessor<*> { + return GroovyLValueProcessor(name, place, kinds) { + if (argument == null) null else arrayOf(argument.type) + } + } +} + +private fun GrReferenceExpression.handleSpecialCases(): Collection? { + when (referenceNameElement?.node?.elementType) { + GroovyElementTypes.KW_THIS -> return resolveThisExpression(this) + GroovyElementTypes.KW_SUPER -> return resolveSuperExpression(this) + GroovyElementTypes.KW_CLASS -> { + if (!PsiUtil.isCompileStatic(this) && qualifier?.type == null) { + return emptyList() + } + } + } + return null +} + +private fun GrReferenceExpressionImpl.resolveKinds(): Set { + return if (isQualified) { + EnumSet.of(FIELD, PROPERTY, VARIABLE) + } + else { + EnumSet.of(FIELD, PROPERTY, VARIABLE, BINDING) } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/lValueUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/lValueUtil.kt index f96bf9a44814..a8ddeb64fba8 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/lValueUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/lValueUtil.kt @@ -1,6 +1,4 @@ -/* - * Copyright 2000-2017 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-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. @file:JvmName("GroovyLValueUtil") package org.jetbrains.plugins.groovy.lang.psi.util @@ -9,6 +7,8 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssign import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrTuple +import org.jetbrains.plugins.groovy.lang.resolve.api.Argument +import org.jetbrains.plugins.groovy.lang.resolve.api.ExpressionArgument /** * The expression is a rValue when it is in rValue position or it's a lValue of operator assignment. @@ -29,3 +29,17 @@ fun GrExpression.isLValue(): Boolean { else -> false } } + +class RValue(val argument: Argument?) + +/** + * @return non-null result iff this expression is an l-value + */ +fun GrExpression.getRValue(): RValue? { + val parent = parent + return when (parent) { + is GrTuple -> RValue(null) + is GrAssignmentExpression -> if (this !== parent.lValue) null else RValue(ExpressionArgument(parent)) + else -> null + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiUtil.kt index 540ff7978121..89825537ec07 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/util/psiUtil.kt @@ -47,3 +47,5 @@ fun GrExpression?.isThisExpression(): Boolean { fun GrOperatorExpression.multiResolve(): Array { return reference?.multiResolve(false) ?: GroovyResolveResult.EMPTY_ARRAY } + +fun elementInfo(element: PsiElement): String = "Element: $element; class: ${element.javaClass}; text: ${element.text}" diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt index a17d5677aebf..147c9e9af0aa 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/ResolveUtil.kt @@ -21,17 +21,20 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.DefaultConstructor +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrBindingVariable import org.jetbrains.plugins.groovy.lang.psi.util.skipSameTypeParents +import org.jetbrains.plugins.groovy.lang.resolve.api.GroovyProperty import org.jetbrains.plugins.groovy.lang.resolve.imports.importedNameKey import org.jetbrains.plugins.groovy.lang.resolve.processors.DynamicMembersHint import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolveKind -import org.jetbrains.plugins.groovy.lang.resolve.processors.GroovyResolverProcessor val log: Logger = logger(::log) @JvmField val NON_CODE: Key = Key.create("groovy.process.non.code.members") +val sorryCannotKnowElementKind: Key = Key.create("groovy.skip.kind.check.please") + fun initialState(processNonCodeMembers: Boolean): ResolveState = ResolveState.initial().put(NON_CODE, processNonCodeMembers) fun ResolveState.processNonCodeMembers(): Boolean = get(NON_CODE).let { it == null || it } @@ -74,9 +77,9 @@ fun PsiScopeProcessor.shouldProcessLocals(): Boolean = shouldProcess(GroovyResol fun PsiScopeProcessor.shouldProcessFields(): Boolean = shouldProcess(GroovyResolveKind.FIELD) -fun PsiScopeProcessor.shouldProcessMethods(): Boolean { - return ResolveUtil.shouldProcessMethods(getHint(ElementClassHint.KEY)) -} +fun PsiScopeProcessor.shouldProcessMethods(): Boolean = shouldProcess(GroovyResolveKind.METHOD) + +fun PsiScopeProcessor.shouldProcessProperties(): Boolean = shouldProcess(GroovyResolveKind.PROPERTY) fun PsiScopeProcessor.shouldProcessClasses(): Boolean { return ResolveUtil.shouldProcessClasses(getHint(ElementClassHint.KEY)) @@ -95,10 +98,6 @@ fun PsiScopeProcessor.shouldProcessTypeParameters(): Boolean { return groovyKindHint.shouldProcess(GroovyResolveKind.TYPE_PARAMETER) } -fun PsiScopeProcessor.shouldProcessProperties(): Boolean { - return this is GroovyResolverProcessor && isPropertyResolve -} - private fun PsiScopeProcessor.shouldProcess(kind: GroovyResolveKind): Boolean { val resolveKindHint = getHint(GroovyResolveKind.HINT_KEY) if (resolveKindHint != null) return resolveKindHint.shouldProcess(kind) @@ -159,3 +158,16 @@ fun valid(allCandidates: Collection): List): List { return if (allCandidates.size <= 1) allCandidates else valid(allCandidates) } + +fun getResolveKind(element: PsiNamedElement): GroovyResolveKind? { + return when (element) { + is PsiClass -> GroovyResolveKind.CLASS + is PsiPackage -> GroovyResolveKind.PACKAGE + is PsiMethod -> GroovyResolveKind.METHOD + is PsiField -> GroovyResolveKind.FIELD + is GrBindingVariable -> GroovyResolveKind.BINDING + is PsiVariable -> GroovyResolveKind.VARIABLE + is GroovyProperty -> GroovyResolveKind.PROPERTY + else -> null + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/Argument.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/Argument.kt new file mode 100644 index 000000000000..2b34c70c8345 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/Argument.kt @@ -0,0 +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. +package org.jetbrains.plugins.groovy.lang.resolve.api + +import com.intellij.psi.PsiType + +interface Argument { + + val type: PsiType? +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/ExpressionArgument.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/ExpressionArgument.kt new file mode 100644 index 000000000000..8493748c78d0 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/api/ExpressionArgument.kt @@ -0,0 +1,10 @@ +// 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. +package org.jetbrains.plugins.groovy.lang.resolve.api + +import com.intellij.psi.PsiType +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression + +class ExpressionArgument(val expression: GrExpression) : Argument { + + override val type: PsiType? get() = expression.type +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt index c30fe2e7dfb5..861f2e8cd0fa 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/caches/fileCache.kt @@ -11,6 +11,7 @@ import com.intellij.util.containers.MostlySingularMultiMap import org.jetbrains.plugins.groovy.lang.resolve.AnnotationHint import org.jetbrains.plugins.groovy.lang.resolve.getName import org.jetbrains.plugins.groovy.lang.resolve.imports.importedNameKey +import org.jetbrains.plugins.groovy.lang.resolve.sorryCannotKnowElementKind private data class ElementWithState(val element: PsiElement, val state: ResolveState) @@ -46,10 +47,16 @@ class FileCacheBuilderProcessor(private val annotationResolve: Boolean) : PsiSco private class FileDeclarationsCache(private val declarations: MostlySingularMultiMap) : DeclarationHolder { override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { + val newState = state.put(sorryCannotKnowElementKind, true) val declarationProcessor = { (element, cachedState): ElementWithState -> - processor.execute(element, state.putAll(cachedState)) + processor.execute(element, newState.putAll(cachedState)) } val name = processor.getName(state) - return if (name == null) declarations.processAllValues(declarationProcessor) else declarations.processForKey(name, declarationProcessor) + return if (name == null) { + declarations.processAllValues(declarationProcessor) + } + else { + declarations.processForKey(name, declarationProcessor) + } } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorAwareResolverProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorAwareResolverProcessor.kt new file mode 100644 index 000000000000..b0bbfd7bd1ec --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/AccessorAwareResolverProcessor.kt @@ -0,0 +1,76 @@ +// 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. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.psi.PsiElement +import com.intellij.psi.scope.ElementClassHint +import com.intellij.psi.scope.PsiScopeProcessor +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil.filterSameSignatureCandidates +import org.jetbrains.plugins.groovy.lang.resolve.singleOrValid + +abstract class AccessorAwareResolverProcessor( + name: String, + place: PsiElement, + kinds: Set +) : KindsResolverProcessor(name, place, kinds), + GrResolverProcessor, + ElementClassHint, + DynamicMembersHint, + MultiProcessor { + + init { + @Suppress("LeakingThis") hint(ElementClassHint.KEY, this) + @Suppress("LeakingThis") hint(DynamicMembersHint.KEY, this) + } + + final override fun shouldProcessProperties(): Boolean = true + + final override fun shouldProcessMethods(): Boolean = false + + final override fun shouldProcess(kind: ElementClassHint.DeclarationKind): Boolean { + return kind != ElementClassHint.DeclarationKind.METHOD && kinds.any { kind in it.declarationKinds } + } + + final override fun getProcessors(): Collection = listOf(this) + accessorProcessors + + protected abstract val accessorProcessors: Collection> + + private val accessorCandidates get() = accessorProcessors.flatMap { it.results } + + private fun getCandidates(kind: GroovyResolveKind): List { + val result = getCandidate(kind)?.let(::listOf) ?: emptyList() + return if (kind == GroovyResolveKind.PROPERTY) result + accessorCandidates else result + } + + final override val results: List + get() { + val variables = getCandidates(GroovyResolveKind.VARIABLE) + if (variables.isNotEmpty()) { + return variables + } + + val properties = singleOrValid(getCandidates(GroovyResolveKind.PROPERTY)) + if (!properties.isEmpty()) { + return if (properties.size <= 1) properties else ContainerUtil.newSmartList(properties[0]) + } + + val fields = getCandidates(GroovyResolveKind.FIELD) + if (!fields.isEmpty()) { + return fields + } + + if (properties.isNotEmpty()) { + return properties + } + + val bindings = getCandidates(GroovyResolveKind.BINDING) + if (bindings.isNotEmpty()) { + return bindings + } + + // TODO this is used to choose between two same methods from some class and its superclass, which is questionable + return getAllCandidates() + filterSameSignatureCandidates(accessorCandidates) + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyLValueProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyLValueProcessor.kt new file mode 100644 index 000000000000..af0a181382ff --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyLValueProcessor.kt @@ -0,0 +1,23 @@ +// 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. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.lang.java.beans.PropertyKind +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import org.jetbrains.plugins.groovy.lang.psi.util.isPropertyName +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor + +class GroovyLValueProcessor( + name: String, + place: PsiElement, + kinds: Set, + argumentTypes: () -> Array? +) : AccessorAwareResolverProcessor(name, place, kinds) { + + override val accessorProcessors: Collection> = if (name.isPropertyName()) { + listOf(AccessorProcessor(name, PropertyKind.SETTER, argumentTypes, place)) + } + else { + emptyList() + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyRValueProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyRValueProcessor.kt new file mode 100644 index 000000000000..2988f2b7441f --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/GroovyRValueProcessor.kt @@ -0,0 +1,24 @@ +// 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. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.lang.java.beans.PropertyKind +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiType +import org.jetbrains.plugins.groovy.lang.psi.util.isPropertyName +import org.jetbrains.plugins.groovy.lang.resolve.GrResolverProcessor + +class GroovyRValueProcessor( + name: String, + place: PsiElement, + kinds: Set +) : AccessorAwareResolverProcessor(name, place, kinds) { + + override val accessorProcessors: Collection> = if (name.isPropertyName()) + listOf( + AccessorProcessor(name, PropertyKind.GETTER, { PsiType.EMPTY_ARRAY }, place), + AccessorProcessor(name, PropertyKind.BOOLEAN_GETTER, { PsiType.EMPTY_ARRAY }, place) + ) + else { + emptyList() + } +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/KindsResolverProcessor.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/KindsResolverProcessor.kt new file mode 100644 index 000000000000..09422dbfca9d --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/KindsResolverProcessor.kt @@ -0,0 +1,72 @@ +// 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. +package org.jetbrains.plugins.groovy.lang.resolve.processors + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiNamedElement +import com.intellij.psi.ResolveState +import com.intellij.psi.scope.NameHint +import com.intellij.psi.scope.ProcessorWithHints +import com.intellij.util.enumMapOf +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.util.elementInfo +import org.jetbrains.plugins.groovy.lang.resolve.BaseGroovyResolveResult +import org.jetbrains.plugins.groovy.lang.resolve.getName +import org.jetbrains.plugins.groovy.lang.resolve.getResolveKind +import org.jetbrains.plugins.groovy.lang.resolve.sorryCannotKnowElementKind + +open class KindsResolverProcessor( + protected val name: String, + protected val place: PsiElement, + protected val kinds: Set +) : ProcessorWithHints(), + NameHint, + GroovyResolveKind.Hint { + + init { + @Suppress("LeakingThis") hint(NameHint.KEY, this) + @Suppress("LeakingThis") hint(GroovyResolveKind.HINT_KEY, this) + } + + final override fun getName(state: ResolveState): String? = name + + final override fun shouldProcess(kind: GroovyResolveKind): Boolean = kind in kinds + + private val candidates = enumMapOf() + + final override fun execute(element: PsiElement, state: ResolveState): Boolean { + if (element !is PsiNamedElement) return true + require(element.isValid) { + "Invalid element. ${elementInfo(element)}" + } + + val elementName = getName(state, element) + if (name != elementName) return true + + val kind = requireNotNull(getResolveKind(element)) { + "Unknown kind. ${elementInfo(element)}" + } + + if (state[sorryCannotKnowElementKind] == true) { + if (kind !in kinds) { + // return without exception + return true + } + } + else { + require(kind in kinds) { + "Unneeded kind. ${elementInfo(element)}" + } + } + + if (kind in candidates) { + return true + } + + candidates[kind] = BaseGroovyResolveResult(element, place, state) + return true + } + + fun getCandidate(kind: GroovyResolveKind): GroovyResolveResult? = candidates[kind] + + fun getAllCandidates(): List = candidates.values.toList() +} diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/GroovyInferenceSessionBuilder.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/GroovyInferenceSessionBuilder.kt index 7f00948104b8..1230eeb32f88 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/GroovyInferenceSessionBuilder.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/GroovyInferenceSessionBuilder.kt @@ -7,7 +7,6 @@ import com.intellij.psi.PsiType import com.intellij.psi.PsiTypeParameter import com.intellij.psi.util.PsiTreeUtil import com.intellij.psi.util.TypeConversionUtil -import com.intellij.util.ArrayUtil import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils import org.jetbrains.plugins.groovy.lang.psi.GroovyFile import org.jetbrains.plugins.groovy.lang.psi.api.GroovyMethodResult @@ -34,8 +33,6 @@ class GroovyInferenceSessionBuilder(private val ref: GrReferenceExpression, priv private var startFromTop = false - private var siteTypeParams: Array = PsiTypeParameter.EMPTY_ARRAY - fun resolveMode(skipClosureBlock: Boolean): GroovyInferenceSessionBuilder { this.skipClosureBlock = skipClosureBlock return this @@ -51,32 +48,21 @@ class GroovyInferenceSessionBuilder(private val ref: GrReferenceExpression, priv return this } - fun addReturnConstraint(returnType: PsiType?): GroovyInferenceSessionBuilder { - left = returnType - return this - } - fun addReturnConstraint(): GroovyInferenceSessionBuilder { val methodCall = ref.parent as? GrMethodCall ?: return this left = getReturnConstraintType(getMostTopLevelCall(methodCall)) return this } - fun addTypeParams(typeParams: Array): GroovyInferenceSessionBuilder { - siteTypeParams = ArrayUtil.mergeArrays(siteTypeParams, typeParams) - return this - } - fun build(): GroovyInferenceSession { if (startFromTop) { - val session = GroovyInferenceSession(siteTypeParams, PsiSubstitutor.EMPTY, ref, closureSkipList, skipClosureBlock) + val session = GroovyInferenceSession(PsiTypeParameter.EMPTY_ARRAY, PsiSubstitutor.EMPTY, ref, closureSkipList, skipClosureBlock) val methodCall = ref.parent as? GrMethodCall ?: return session session.addConstraint(ExpressionConstraint(getMostTopLevelCall(methodCall), left)) return session } else { - val typeParameters = ArrayUtil.mergeArrays(siteTypeParams, candidate.method.typeParameters) - val session = GroovyInferenceSession(typeParameters, candidate.siteSubstitutor, ref, closureSkipList, skipClosureBlock) + val session = GroovyInferenceSession(candidate.method.typeParameters, candidate.siteSubstitutor, ref, closureSkipList, skipClosureBlock) session.addConstraint(MethodCallConstraint(ref, candidate)) val left = left ?: return session @@ -92,12 +78,12 @@ class GroovyInferenceSessionBuilder(private val ref: GrReferenceExpression, priv var topLevel: GrMethodCall = call while (true) { val parent = topLevel.parent - val gparent = parent?.parent + val grandParent = parent?.parent topLevel = if (parent is GrMethodCall) { parent } - else if (parent is GrArgumentList && gparent is GrMethodCall) { - gparent + else if (parent is GrArgumentList && grandParent is GrMethodCall) { + grandParent } else { return topLevel @@ -107,7 +93,7 @@ class GroovyInferenceSessionBuilder(private val ref: GrReferenceExpression, priv private fun getReturnConstraintType(call: GrMethodCall): PsiType? { val parent = call.parent - val gparent = parent?.parent + val grandParent = parent?.parent val parentMethod = PsiTreeUtil.getParentOfType(parent, GrMethod::class.java, true, GrClosableBlock::class.java) if (parent is GrReturnStatement && parentMethod != null) { @@ -122,8 +108,8 @@ class GroovyInferenceSessionBuilder(private val ref: GrReferenceExpression, priv val lValue = PsiUtil.skipParentheses(parent.lValue, false) return if (lValue is GrExpression && lValue !is GrIndexProperty) lValue.nominalType else null } - else if (parent is GrArgumentList && gparent is GrNewExpression) { // TODO: fix with moving constructor resolve to new API - with(gparent) { + else if (parent is GrArgumentList && grandParent is GrNewExpression) { // TODO: fix with moving constructor resolve to new API + with(grandParent) { val resolveResult = advancedResolve() if (resolveResult is GroovyMethodResult) { val methodCandidate = MethodCandidate(resolveResult.element, resolveResult.partialSubstitutor, diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt index 62ab715edf1a..58988ebbf12e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ext/logback/LogbackDelegateMemberContributor.kt @@ -21,6 +21,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.DELEGATES_TO_STRATEGY_KEY import org.jetbrains.plugins.groovy.lang.resolve.delegatesTo.getContainingCall +import org.jetbrains.plugins.groovy.lang.resolve.shouldProcessMethods import org.jetbrains.plugins.groovy.lang.resolve.wrapClassType class LogbackDelegateMemberContributor : NonCodeMembersContributor() { @@ -28,6 +29,9 @@ class LogbackDelegateMemberContributor : NonCodeMembersContributor() { override fun getParentClassName(): String = componentDelegateFqn override fun processDynamicElements(qualifierType: PsiType, processor: PsiScopeProcessor, place: PsiElement, state: ResolveState) { + if (!processor.shouldProcessMethods()) { + return + } val name = processor.getHint(NameHint.KEY)?.getName(state) val componentClass = getComponentClass(place) ?: return val componentProcessor = ComponentProcessor(processor, place, name) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java index 4016deda1811..dce1e8be54f3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java @@ -1,18 +1,4 @@ -/* - * 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-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. package org.jetbrains.plugins.groovy.gant; import com.intellij.psi.*; @@ -32,6 +18,7 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtilKt; import org.jetbrains.plugins.groovy.runner.GroovyScriptUtil; /** @@ -95,7 +82,7 @@ public class GantMemberContributor extends NonCodeMembersContributor { } } - if (!antTasksProcessed) { + if (!antTasksProcessed && ResolveUtilKt.shouldProcessMethods(processor)) { processAntTasks(processor, place, state); } } diff --git a/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml b/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml index 0b843a1ef82a..e8fd3edd725b 100644 --- a/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml +++ b/plugins/junit5_rt_tests/intellij.junit.v5.rt.tests.iml @@ -47,6 +47,8 @@ + + @@ -55,6 +57,8 @@ + +
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenRunConfigurationMenu.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenRunConfigurationMenu.java index ae6fda9f3ecb..47707b9f3160 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenRunConfigurationMenu.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenRunConfigurationMenu.java @@ -37,8 +37,10 @@ public class MavenRunConfigurationMenu extends DefaultActionGroup implements Dum Executor[] executors = ExecutorRegistry.getInstance().getRegisteredExecutors(); for (int i = executors.length; --i >= 0; ) { - final ProgramRunner runner = ProgramRunner.getRunner(executors[i].getId(), settings.getConfiguration()); - AnAction action = new ExecuteMavenRunConfigurationAction(executors[i], runner != null, settings); + Executor executor = executors[i]; + if(!executor.isApplicable(project)) continue; + final ProgramRunner runner = ProgramRunner.getRunner(executor.getId(), settings.getConfiguration()); + AnAction action = new ExecuteMavenRunConfigurationAction(executor, runner != null, settings); addAction(action, Constraints.FIRST); } diff --git a/python/helpers/pydev/_pydev_bundle/pydev_umd.py b/python/helpers/pydev/_pydev_bundle/pydev_umd.py index 224676fa6fd4..b434fc6cd26c 100644 --- a/python/helpers/pydev/_pydev_bundle/pydev_umd.py +++ b/python/helpers/pydev/_pydev_bundle/pydev_umd.py @@ -156,7 +156,7 @@ def runfile(filename, args=None, wdir=None, is_module=False, global_vars=None): __umd__.run(verbose=verbose) if global_vars is None: - m = save_main_module(filename) + m = save_main_module(filename, 'pydev_umd') global_vars = m.__dict__ try: global_vars['__builtins__'] = __builtins__ diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py b/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py index 755116c55c6f..d346ef149c51 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_utils.py @@ -13,19 +13,20 @@ import sys from _pydev_bundle import pydev_log -def save_main_module(file): +def save_main_module(file, module_name): # patch provided by: Scott Schlesier - when script is run, it does not # use globals from pydevd: # This will prevent the pydevd script from contaminating the namespace for the script to be debugged # pretend pydevd is not the main module, and # convince the file to be debugged that it was loaded as main - original_main = sys.modules['__main__'] + sys.modules[module_name] = sys.modules['__main__'] + sys.modules[module_name].__name__ = module_name from imp import new_module m = new_module('__main__') sys.modules['__main__'] = m - if hasattr(original_main, '__loader__'): - m.__loader__ = getattr(original_main, '__loader__') + if hasattr(sys.modules[module_name], '__loader__'): + m.__loader__ = getattr(sys.modules[module_name], '__loader__') m.__file__ = file return m diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py index bc629b3eae05..d8ea988a3b8a 100644 --- a/python/helpers/pydev/pydevconsole.py +++ b/python/helpers/pydev/pydevconsole.py @@ -72,7 +72,7 @@ class InterpreterInterface(BaseInterpreterInterface): self._input_error_printed = False def save_main(self): - m = save_main_module('') + m = save_main_module('', 'pydevconsole') self.namespace = m.__dict__ try: self.namespace['__builtins__'] = __builtins__ diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index 1ee93092853a..c96745480cf2 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -1013,7 +1013,7 @@ class PyDB: file = new_target if globals is None: - m = save_main_module(file) + m = save_main_module(file, 'pydevd') globals = m.__dict__ try: globals['__builtins__'] = __builtins__