Merge remote-tracking branch 'origin/master'

This commit is contained in:
Konstantin Bulenkov
2016-07-12 21:36:24 +02:00
79 changed files with 827 additions and 305 deletions
@@ -34,5 +34,9 @@ abstract class LinuxDistributionCustomizer {
*/
abstract String rootDirectoryName(String buildNumber)
/**
* Override this method to copy additional files to Linux distribution of the product.
* @param targetDirectory contents of this directory will be packed into .tar.gz archive under {@link #rootDirectoryName(java.lang.String)}
*/
void copyAdditionalFiles(BuildContext context, String targetDirectory) {}
}
@@ -19,12 +19,24 @@ package org.jetbrains.intellij.build
* @author nik
*/
abstract class MacDistributionCustomizer {
/**
* Path to icns file containing 32x32 product icon for Mac OS distribution
*/
String icnsPath
/**
* The minimum version of Mac OS where the product is allowed to be installed
*/
String minOSXVersion = "10.8"
String helpId = ""
String docTypes = null
List<String> urlSchemes = []
List<String> architectures = ["x86_64"]
/**
* If {@code true} YourKit agent will be automatically attached when an EAP build of the product starts under Mac OS. This property is
* taken into account only if {@link ProductProperties#enableYourkitAgentInEAP} is {@code true}.
*/
boolean enableYourkitAgentInEAP = true
/**
@@ -106,6 +106,10 @@ public abstract class ProductProperties {
* directories of Windows, Linux and Mac OS distributions. If {@code null} no agent files will be bundled.
*/
String yourkitAgentBinariesDirectoryPath = null
/**
* If {@code true} YourKit agent will be automatically attached when an EAP build of the product starts. It makes sense only if {@link #yourkitAgentBinariesDirectoryPath} is non-null.
*/
boolean enableYourkitAgentInEAP = false
List<String> excludedPlugins = []
@@ -54,6 +54,11 @@ abstract class WindowsDistributionCustomizer {
*/
abstract String rootDirectoryName(String buildNumber)
/**
* Override this method to copy additional files to Windows distribution of the product.
* @param targetDirectory contents of this directory will be packed into zip archive and exe installer, so when the product is installed
* it'll be placed under its root directory.
*/
void copyAdditionalFiles(BuildContext context, String targetDirectory) {}
String uninstallFeedbackPageUrl(ApplicationInfoProperties applicationInfo) {
+6 -8
View File
@@ -876,16 +876,14 @@ binding.setVariable("signExecutableFiles", { String binDir ->
})
binding.setVariable("bundledJDKs"){
bundledJDK(false, paths.sandbox)
bundledJDK(false)
}
binding.setVariable("bundledJDK64s"){
bundledJDK(true, paths.sandbox)
bundledJDK(true)
}
binding.setVariable("prepareBundledJDKs", { String targetDir -> bundledJDK(false, targetDir)})
private bundledJDK(boolean win64, String targetDir) {
private bundledJDK(boolean win64) {
requireProperty("artifact.linux.no.jdk", "true")
requireProperty("artifact.mac.no.jdk", "true")
requireProperty("jdk.oracle.win", "jdk8u")
@@ -897,11 +895,11 @@ private bundledJDK(boolean win64, String targetDir) {
def jdkDir = new File("${home}/build/jdk/win")
if (p("jdk.oracle.win") != "false" && (jdkDir.exists() && jdkDir.isDirectory())) {
setProperty("winJDK", getPathToBundledJDK(jdkDir, p("jdk.oracle.win"), (win64 ? "x64.tar.gz": "x86.tar.gz")))
extractRedistJre(winJDK, "$targetDir/jdk.oracle.win/jre")
extractRedistJre(winJDK, "${paths.sandbox}/jdk.oracle.win/jre")
}
if (p("jdk.win") != "false" && (jdkDir.exists() && jdkDir.isDirectory())) {
setProperty("winCustomJDKx32", getPathToBundledJDK(jdkDir, p("jdk.win"), (win64 ? "x64.tar.gz": "x86.tar.gz")))
extractRedistJre(winCustomJDKx32, "$targetDir/jdk.win/jre")
extractRedistJre(winCustomJDKx32, "${paths.sandbox}/jdk.win/jre")
}
jdkDir = new File("${home}/build/jdk/mac")
if (p("jdk.mac") != "false" && (jdkDir.exists() && jdkDir.isDirectory())) {
@@ -910,7 +908,7 @@ private bundledJDK(boolean win64, String targetDir) {
jdkDir = new File("${home}/build/jdk/linux")
if (p("jdk.linux") != "false" && (jdkDir.exists() && jdkDir.isDirectory())) {
setProperty("linuxJDK", getPathToBundledJDK(jdkDir, p("jdk.linux"), ".tar.gz"))
extractRedistJre(linuxJDK, "$targetDir/jdk.linux/jre")
extractRedistJre(linuxJDK, "${paths.sandbox}/jdk.linux/jre")
}
}
}
@@ -167,7 +167,15 @@ public class UnusedDeclarationPresentation extends DefaultInspectionToolPresenta
@Override
public QuickFixAction[] getQuickFixes(@NotNull final RefEntity[] refElements, CommonProblemDescriptor[] allowedDescriptors) {
return myQuickFixActions;
boolean showFixes = false;
for (RefEntity element : refElements) {
if (!getIgnoredRefElements().contains(element) && element.isValid()) {
showFixes = true;
break;
}
}
return showFixes ? myQuickFixActions : QuickFixAction.EMPTY;
}
final QuickFixAction[] myQuickFixActions;
@@ -223,7 +223,14 @@ open class StateStorageManagerImpl(private val rootTagName: String,
throw IllegalArgumentException("Extension is missing for storage file: $filePath")
}
val effectiveRoamingType = if (roamingType == RoamingType.DEFAULT && collapsedPath == StoragePathMacros.WORKSPACE_FILE) RoamingType.DISABLED else roamingType
val effectiveRoamingType: RoamingType
if (roamingType != RoamingType.DISABLED && (collapsedPath == StoragePathMacros.WORKSPACE_FILE || collapsedPath == "other.xml")) {
effectiveRoamingType = RoamingType.DISABLED
}
else {
effectiveRoamingType = roamingType
}
val storage = createFileBasedStorage(filePath, collapsedPath, effectiveRoamingType)
if (isUseVfsListener == ThreeState.YES && storage is StorageVirtualFileTracker.TrackedStorage) {
virtualFileTracker?.put(filePath, storage)
@@ -663,6 +663,15 @@ public class VfsUtilCore {
return components;
}
public static boolean hasInvalidFiles(@NotNull Iterable<VirtualFile> files) {
for (VirtualFile file : files) {
if (!file.isValid()) {
return true;
}
}
return false;
}
/**
* this collection will keep only distinct files/folders, e.g. C:\foo\bar will be removed when C:\foo is added
*/
@@ -55,7 +55,7 @@ public class AdditionalIndexableFileSet implements IndexableFileSet {
private Set<VirtualFile> getDirectories() {
Set<VirtualFile> directories = cachedDirectories;
if (directories == null || filesInvalidated(directories) || filesInvalidated(cachedFiles)) {
if (directories == null || VfsUtilCore.hasInvalidFiles(directories) || VfsUtilCore.hasInvalidFiles(cachedFiles)) {
directories = collectFilesAndDirectories();
}
return directories;
@@ -83,15 +83,6 @@ public class AdditionalIndexableFileSet implements IndexableFileSet {
return directories;
}
public static boolean filesInvalidated(Set<VirtualFile> files) {
for (VirtualFile file : files) {
if (!file.isValid()) {
return true;
}
}
return false;
}
@Override
public boolean isInSet(@NotNull VirtualFile file) {
return VfsUtilCore.isUnder(file, getDirectories()) || cachedFiles.contains(file);
@@ -19,7 +19,6 @@ import com.intellij.codeInspection.CommonProblemDescriptor;
import com.intellij.codeInspection.ProblemDescriptorBase;
import com.intellij.diff.tools.util.FoldingModelSupport;
import com.intellij.diff.util.DiffDrawUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.FoldRegion;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.ex.DocumentEx;
@@ -39,19 +38,10 @@ import java.util.stream.Collectors;
*/
public class ProblemPreviewEditorPresentation {
private final static int VIEW_ADDITIONAL_OFFSET = 4;
private final static Logger LOG = Logger.getInstance(ProblemPreviewEditorPresentation.class);
private final EditorEx myEditor;
private final InspectionResultsView myView;
private final SortedSet<PreviewEditorFoldingRegion> myFoldedRegions = new TreeSet<>(new Comparator<PreviewEditorFoldingRegion>() {
@Override
public int compare(PreviewEditorFoldingRegion r1, PreviewEditorFoldingRegion r2) {
if (r1 == r2) return 0;
final int diff = r1.startLine - r2.startLine;
LOG.assertTrue(diff != 0);
return diff;
}
});
private final SortedSet<PreviewEditorFoldingRegion> myFoldedRegions = new TreeSet<>(Comparator.comparing(x -> x.startLine));
private final DocumentEx myDocument;
public ProblemPreviewEditorPresentation(EditorEx editor, InspectionResultsView view) {
@@ -122,7 +122,7 @@ public class RefElementNode extends SuppressableInspectionTreeNode {
@Override
public int getProblemCount(boolean allowSuppressed) {
return isLeaf() ? myPresentation.getIgnoredRefElements().contains(getElement()) ? 0 : 1 : super.getProblemCount(allowSuppressed);
return isLeaf() ? myPresentation.getIgnoredRefElements().contains(getElement()) && !(allowSuppressed && isAlreadySuppressedFromView() && isValid()) ? 0 : 1 : super.getProblemCount(allowSuppressed);
}
@Override
@@ -21,6 +21,7 @@ import com.intellij.codeInspection.ex.InspectionManagerEx;
import com.intellij.codeInspection.ex.InspectionToolWrapper;
import com.intellij.codeInspection.reference.RefElement;
import com.intellij.codeInspection.reference.RefEntity;
import com.intellij.codeInspection.ui.ProblemDescriptionNode;
import com.intellij.codeInspection.ui.SuppressableInspectionTreeNode;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -38,6 +39,7 @@ import com.intellij.util.containers.Queue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -137,16 +139,19 @@ public class SuppressActionSequentialTask implements SequentialTask {
}
final RefElement containerRef = refEntity.getRefManager().getReference(container);
final Set<Object> suppressedNodes = myContext.getView().getSuppressedNodes(wrapper.getShortName());
if (containerRef != null) {
Queue<RefEntity> toIgnoreInView = new Queue<RefEntity>(1);
toIgnoreInView.addLast(containerRef);
while (!toIgnoreInView.isEmpty()) {
final RefEntity entity = toIgnoreInView.pullFirst();
final CommonProblemDescriptor[] descriptors = myContext.getPresentation(wrapper).getIgnoredElements().get(entity);
if (descriptors != null) {
for (CommonProblemDescriptor problemDescriptor : descriptors) {
myContext.getView().getSuppressedNodes(wrapper.getShortName()).add(problemDescriptor);
if (node instanceof ProblemDescriptionNode) {
final CommonProblemDescriptor[] descriptors = myContext.getPresentation(wrapper).getIgnoredElements().get(entity);
if (descriptors != null) {
Collections.addAll(suppressedNodes, descriptors);
}
} else {
suppressedNodes.add(entity);
}
final List<RefEntity> children = entity.getChildren();
if (children != null) {
@@ -156,7 +161,9 @@ public class SuppressActionSequentialTask implements SequentialTask {
}
}
}
myContext.getView().getSuppressedNodes(wrapper.getShortName()).add(descriptor);
if (node instanceof ProblemDescriptionNode) {
suppressedNodes.add(descriptor);
}
}
catch (IncorrectOperationException e1) {
LOG.error(e1);
@@ -22,6 +22,7 @@ import com.intellij.lang.LanguageUtil;
import com.intellij.lang.PerFileMappings;
import com.intellij.lang.PerFileMappingsBase;
import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.components.PersistentStateComponent;
@@ -44,14 +45,14 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.psi.LanguageSubstitutor;
import com.intellij.psi.LanguageSubstitutors;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.PairConsumer;
import com.intellij.util.PathUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.IndexableSetContributor;
import com.intellij.util.indexing.LightDirectoryIndex;
import com.intellij.util.messages.MessageBus;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -59,9 +60,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.*;
@State(name = "ScratchFileService", storages = @Storage("scratches.xml"))
@@ -72,22 +71,14 @@ public class ScratchFileServiceImpl extends ScratchFileService implements Persis
private final LightDirectoryIndex<RootType> myIndex;
private final MyLanguages myScratchMapping = new MyLanguages();
protected ScratchFileServiceImpl(MessageBus messageBus) {
myIndex = new LightDirectoryIndex<RootType>(messageBus.connect(), NULL_TYPE) {
@Override
protected void collectRoots(@NotNull PairConsumer<VirtualFile, RootType> consumer) {
LocalFileSystem fileSystem = LocalFileSystem.getInstance();
for (RootType r : RootType.getAllRootIds()) {
String root = getRootPath(r);
VirtualFile rootFile = fileSystem.findFileByPath(root);
if (rootFile != null) {
consumer.consume(rootFile, r);
}
}
protected ScratchFileServiceImpl(Application application) {
myIndex = new LightDirectoryIndex<RootType>(application, NULL_TYPE, index -> {
LocalFileSystem fileSystem = LocalFileSystem.getInstance();
for (RootType r : RootType.getAllRootIds()) {
index.putInfo(fileSystem.findFileByPath(getRootPath(r)), r);
}
};
initFileOpenedListener(messageBus);
});
initFileOpenedListener(application.getMessageBus());
}
@NotNull
@@ -101,7 +92,6 @@ public class ScratchFileServiceImpl extends ScratchFileService implements Persis
public RootType getRootType(@Nullable VirtualFile file) {
if (file == null) return null;
VirtualFile directory = file.isDirectory() ? file : file.getParent();
if (!(directory instanceof VirtualFileWithId)) return null;
RootType result = myIndex.getInfoForFile(directory);
return result == NULL_TYPE ? null : result;
}
@@ -314,4 +304,26 @@ public class ScratchFileServiceImpl extends ScratchFileService implements Persis
private static Language getLanguageByFileName(@Nullable VirtualFile file) {
return file == null ? null : LanguageUtil.getFileTypeLanguage(FileTypeManager.getInstance().getFileTypeByFileName(file.getName()));
}
public static class IndexSetContributor extends IndexableSetContributor {
@NotNull
@Override
public Set<VirtualFile> getAdditionalRootsToIndex() {
ScratchFileService instance = ScratchFileService.getInstance();
LocalFileSystem fileSystem = LocalFileSystem.getInstance();
HashSet<VirtualFile> result = ContainerUtil.newHashSet();
for (RootType rootType : RootType.getAllRootIds()) {
if (rootType.isHidden()) continue;
ContainerUtil.addIfNotNull(result, fileSystem.findFileByPath(instance.getRootPath(rootType)));
}
return result;
}
@NotNull
@Override
public Set<VirtualFile> getAdditionalProjectRootsToIndex(@NotNull Project project) {
return Collections.emptySet();
}
}
}
@@ -42,6 +42,7 @@ import com.intellij.refactoring.RefactoringBundle;
import com.intellij.ui.ReplacePromptDialog;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -49,7 +50,7 @@ import java.util.*;
* @author Dennis.Ushakov
*/
public class ExtractMethodHelper {
public static void processDuplicates(@NotNull final PsiElement callElement,
public static void processDuplicates(@Nullable final PsiElement callElement,
@NotNull final PsiElement generatedMethod,
@NotNull final List<PsiElement> scope,
@NotNull final SimpleDuplicatesFinder finder,
@@ -60,7 +61,7 @@ public class ExtractMethodHelper {
replaceDuplicates(callElement, editor, replacer, finder.findDuplicates(scope, generatedMethod));
return;
}
final Project project = callElement.getProject();
final Project project = generatedMethod.getProject();
ProgressManager.getInstance().run(new Task.Backgroundable(project, RefactoringBundle.message("searching.for.duplicates"), true) {
public void run(@NotNull ProgressIndicator indicator) {
if (myProject == null || myProject.isDisposed()) return;
@@ -115,7 +116,7 @@ public class ExtractMethodHelper {
* @param duplicates discovered duplicates of extracted code fragment
* @see #collectDuplicates(SimpleDuplicatesFinder, List, PsiElement)
*/
public static void replaceDuplicates(@NotNull PsiElement callElement,
public static void replaceDuplicates(@Nullable PsiElement callElement,
@NotNull Editor editor,
@NotNull Consumer<Pair<SimpleMatch, PsiElement>> replacer,
@NotNull List<SimpleMatch> duplicates) {
@@ -124,7 +125,12 @@ public class ExtractMethodHelper {
.message("0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method",
ApplicationNamesInfo.getInstance().getProductName(), duplicates.size());
final boolean isUnittest = ApplicationManager.getApplication().isUnitTestMode();
final Project project = callElement.getProject();
final Project project = callElement != null ? callElement.getProject() : editor.getProject();
if (project == null) {
Messages.showErrorDialog(editor.getComponent(), "Cannot find project.");
return;
}
final int exitCode = !isUnittest ? Messages.showYesNoDialog(project, message,
RefactoringBundle.message("refactoring.extract.method.dialog.title"),
Messages.getInformationIcon()) :
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.ide.scratch;
package com.intellij.util.indexing;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileTypes.FileTypeEvent;
import com.intellij.openapi.fileTypes.FileTypeListener;
import com.intellij.openapi.fileTypes.FileTypeManager;
@@ -23,7 +25,7 @@ import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileWithId;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.util.PairConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ConcurrentIntObjectMap;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBusConnection;
@@ -33,23 +35,27 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* This is a light version of DirectoryIndexImpl.
* This is a light version of DirectoryIndexImpl
*
* @author gregsh
*/
abstract class LightDirectoryIndex<T> {
public final class LightDirectoryIndex<T> {
private final ConcurrentIntObjectMap<T> myInfoCache = ContainerUtil.createConcurrentIntObjectMap();
private final T myDefValue;
private final Consumer<LightDirectoryIndex<T>> myInitializer;
public LightDirectoryIndex(@NotNull MessageBusConnection connection, @NotNull T defValue) {
public LightDirectoryIndex(@NotNull Disposable parentDisposable, @NotNull T defValue, @NotNull Consumer<LightDirectoryIndex<T>> initializer) {
myDefValue = defValue;
reinitRoots();
myInitializer = initializer;
resetIndex();
MessageBusConnection connection = ApplicationManager.getApplication().getMessageBus().connect(parentDisposable);
connection.subscribe(FileTypeManager.TOPIC, new FileTypeListener.Adapter() {
@Override
public void fileTypesChanged(@NotNull FileTypeEvent event) {
reinitRoots();
resetIndex();
}
});
connection.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() {
@Override
public void before(@NotNull List<? extends VFileEvent> events) {
@@ -60,7 +66,7 @@ abstract class LightDirectoryIndex<T> {
for (VFileEvent event : events) {
VirtualFile file = event.getFile();
if (file == null || file.isDirectory()) {
reinitRoots();
resetIndex();
break;
}
}
@@ -68,15 +74,20 @@ abstract class LightDirectoryIndex<T> {
});
}
public void reinitRoots() {
public void resetIndex() {
myInfoCache.clear();
collectRoots((file, info) -> cacheInfo(file, info));
myInitializer.consume(this);
}
protected abstract void collectRoots(@NotNull PairConsumer<VirtualFile, T> consumer);
public void putInfo(@Nullable VirtualFile file, @NotNull T value) {
if (!(file instanceof VirtualFileWithId)) return;
cacheInfo(file, value);
}
@NotNull
public T getInfoForFile(@NotNull VirtualFile file) {
public T getInfoForFile(@Nullable VirtualFile file) {
if (!(file instanceof VirtualFileWithId)) return myDefValue;
VirtualFile dir;
if (!file.isDirectory()) {
T info = getCachedInfo(file);
@@ -39,8 +39,7 @@ public enum EffectPainter implements RegionPainter<Paint> {
}
else if (paint != null && width > 0 && height > 0) {
int h = height > 6 && Registry.is("ide.text.effect.wave.new.scale") ? height >> 1 : 3;
double pos = Registry.doubleValue("ide.text.effect.line.new.pos");
y += height < 3 ? 1 : (int)((double)height - h * pos);
y += height - 1 - h / 2;
g.setPaint(paint);
g.drawLine(x, y, x + width, y);
}
@@ -60,25 +59,17 @@ public enum EffectPainter implements RegionPainter<Paint> {
WavePainter.forColor(g.getColor()).paint(g, x, x + width, y + height);
}
else if (paint != null && width > 0 && height > 0) {
boolean simple = height < 5;
int h = height > 6 && Registry.is("ide.text.effect.wave.new.scale") ? height >> 1 : 3;
if (h != height) {
y += height - h;
height = h;
}
g = (Graphics2D)g.create(x, y, width, height);
g.clipRect(0, -1, width, height + 1); // 1px for Retina painting
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(paint);
int length = 2 * height - 2; // the spatial period of the wave
g.clipRect(0, 0, width, height);
int h = height > 6 && Registry.is("ide.text.effect.wave.new.scale") ? height >> 1 : 3;
int length = 2 * h - 2; // the spatial period of the wave
double dx = -((x % length + length) % length); // normalize
double upper = 0;
double upper = height - h;
double lower = height - 1;
Path2D path = new Path2D.Double();
path.moveTo(dx, lower);
if (simple) {
if (height < 6) {
g.setStroke(STROKE);
double size = (double)length / 2;
while (true) {
@@ -91,7 +82,7 @@ public enum EffectPainter implements RegionPainter<Paint> {
else {
double size = (double)length / 4;
double prev = dx - size / 2;
double center = lower / 2;
double center = (upper + lower) / 2;
while (true) {
path.quadTo(prev += size, lower, dx += size, center);
if (dx > width) break;
@@ -103,6 +94,8 @@ public enum EffectPainter implements RegionPainter<Paint> {
if (dx > width) break;
}
}
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(paint);
g.draw(path);
g.dispose();
}
@@ -112,7 +112,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
private int myInEditorPaintCounter; // EDT only
private final long myStartTime;
@Nullable
private final Splash mySplash;
private Splash mySplash;
private boolean myDoNotSave;
private volatile boolean myDisposeInProgress;
@@ -420,6 +420,7 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
token.finish();
}
myLoaded = true;
mySplash = null;
createLocatorFile();
}
@@ -21,38 +21,82 @@ import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import java.awt.*;
import java.awt.event.AWTEventListener;
import java.util.List;
import java.util.Objects;
import static com.intellij.icons.AllIcons.Ide.Shadow.Popup.*;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
/**
* @author Sergey.Malenkov
*/
final class WindowShadowPainter extends AbstractPainter {
final class WindowShadowPainter extends AbstractPainter implements AWTEventListener {
private static final ShadowPainter PAINTER = new ShadowPainter(Top, Top_right, Right, Bottom_right, Bottom, Bottom_left, Left, Top_left);
private static final long MASK = AWTEvent.WINDOW_EVENT_MASK | AWTEvent.WINDOW_STATE_EVENT_MASK | AWTEvent.COMPONENT_EVENT_MASK;
private List<Rectangle> myShadows;
private Component myComponent;
WindowShadowPainter() {
setNeedsRepaint(true);
@Override
public boolean needsRepaint() {
return true;
}
@Override
public void eventDispatched(AWTEvent event) {
Component component = myComponent;
if (component == null) return;
Window window = UIUtil.getWindow(component);
if (window == null) return;
Object source = event.getSource();
if (source instanceof Window && SwingUtilities.isDescendingFrom((Window)source, window)) {
List<Rectangle> shadows = myShadows;
myShadows = getShadows(component, window);
if (!Objects.equals(myShadows, shadows)) component.repaint();
}
}
@Override
public void executePaint(Component component, Graphics2D g) {
Window window = UIUtil.getWindow(component);
if (window != null) {
Point point = new Point();
SwingUtilities.convertPointToScreen(point, component);
paintShadows(component, g, point, window.getOwnedWindows());
setNeedsRepaint(true);
if (myComponent != component) {
boolean add = myComponent == null;
myComponent = component;
myShadows = getShadows(component, window);
if (add) Toolkit.getDefaultToolkit().addAWTEventListener(this, MASK);
}
List<Rectangle> shadows = myShadows;
if (shadows != null) {
for (Rectangle bounds : shadows) {
PAINTER.paintShadow(component, g, bounds.x, bounds.y, bounds.width, bounds.height);
}
}
}
else if (myComponent != null) {
Toolkit.getDefaultToolkit().removeAWTEventListener(this);
myComponent = null;
}
}
private static void paintShadows(Component component, Graphics2D g, Point point, Window... windows) {
private static List<Rectangle> getShadows(Component component, Window window) {
Point point = new Point();
SwingUtilities.convertPointToScreen(point, component);
return getShadows(null, point, window.getOwnedWindows());
}
private static List<Rectangle> getShadows(List<Rectangle> list, Point point, Window... windows) {
if (windows != null) {
for (Window window : windows) {
Rectangle bounds = getShadowBounds(point, window);
if (bounds != null) PAINTER.paintShadow(component, g, bounds.x, bounds.y, bounds.width, bounds.height);
paintShadows(component, g, point, window.getOwnedWindows());
if (bounds != null) {
if (list == null) list = newArrayList();
list.add(bounds);
}
list = getShadows(list, point, window.getOwnedWindows());
}
}
return list;
}
private static Rectangle getShadowBounds(Point point, Window window) {
@@ -359,6 +359,7 @@
<fileIconProvider implementation="com.intellij.ide.scratch.ScratchFileServiceImpl$FilePresentation"/>
<editorTabTitleProvider implementation="com.intellij.ide.scratch.ScratchFileServiceImpl$FilePresentation"/>
<syntaxHighlighter factoryClass="com.intellij.ide.scratch.ScratchFileServiceImpl$Highlighter" order="first"/>
<indexedRootsProvider implementation="com.intellij.ide.scratch.ScratchFileServiceImpl$IndexSetContributor"/>
<scratch.rootType implementation="com.intellij.ide.scratch.ScratchRootType" />
<scratch.rootType implementation="com.intellij.execution.console.HistoryRootType"/>
@@ -768,8 +768,6 @@ editor.rainbow.identifiers.description=Rainbow identifiers in editor
ide.text.effect.line.new=false
ide.text.effect.line.new.description=Enables new line painter for text
ide.text.effect.line.new.pos=0.5
ide.text.effect.line.new.pos.description=Changes a line position
ide.text.effect.wave.new=false
ide.text.effect.wave.new.description=Enables new wave painter for text
ide.text.effect.wave.new.scale=false
@@ -2385,7 +2385,7 @@
level="WARNING" implementationClass="com.siyeh.ig.style.ConstantOnRHSOfComparisonInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="ControlFlowStatementWithoutBraces" bundle="com.siyeh.InspectionGadgetsBundle"
key="control.flow.statement.without.braces.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.code.style.issues" enabledByDefault="false" level="WARNING"
groupKey="group.names.code.style.issues" enabledByDefault="true" level="INFORMATION"
implementationClass="com.siyeh.ig.style.ControlFlowStatementWithoutBracesInspection"/>
<localInspection groupPath="Java" language="JAVA" shortName="EqualsCalledOnEnumConstant" bundle="com.siyeh.InspectionGadgetsBundle"
key="equals.called.on.enum.constant.display.name" groupBundle="messages.InspectionsBundle"
@@ -1004,7 +1004,7 @@ too.broad.scope.problem.descriptor=Scope of variable <code>#ref</code> is too br
return.this.problem.descriptor=Return of <code>#ref</code> #loc
constant.on.lhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on left side of comparison #loc
constant.on.rhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on right side of comparison #loc
control.flow.statement.without.braces.problem.descriptor=<code>#ref</code> without braces #loc
control.flow.statement.without.braces.problem.descriptor=<code>{0}</code> without braces #loc
missorted.modifiers.problem.descriptor=Missorted modifiers <code>#ref</code> #loc
cstyle.array.variable.declaration.problem.descriptor=C-style array declaration of {0, choice, 1#field|2#parameter|3#local variable} <code>#ref</code> #loc
cstyle.array.method.declaration.problem.descriptor=C-style array declaration of the return type of method <code>#ref()</code>#loc
@@ -1335,6 +1335,7 @@ introduce.variable.quickfix=Introduce variable
introduce.variable.may.change.semantics.quickfix=Introduce variable (may change semantics)
flip.comparison.quickfix=Flip comparison
control.flow.statement.without.braces.add.quickfix=Add braces
control.flow.statement.without.braces.message=Add braces to ''{0}'' statement
extends.object.remove.quickfix=Remove redundant 'extends Object'
implicit.call.to.super.ignore.option=Ignore for direct subclasses of 'java.lang.Object'
implicit.call.to.super.make.explicit.quickfix=Make call to 'super()' explicit
@@ -15,6 +15,8 @@
*/
package com.siyeh.ig;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.openapi.util.TextRange;
@@ -183,10 +185,7 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor {
if (!location.isPhysical() || location.getTextLength() == 0 && !(location instanceof PsiFile)) {
return;
}
final InspectionGadgetsFix[] fixes = createFixes(infos);
for (InspectionGadgetsFix fix : fixes) {
fix.setOnTheFly(onTheFly);
}
final LocalQuickFix[] fixes = createAndInitFixes(infos);
final String description = inspection.buildErrorString(infos);
holder.registerProblem(location, description, highlightType, fixes);
}
@@ -201,13 +200,30 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor {
if (location.getTextLength() == 0 || length == 0) {
return;
}
final LocalQuickFix[] fixes = createAndInitFixes(infos);
final String description = inspection.buildErrorString(infos);
final TextRange range = new TextRange(offset, offset + length);
holder.registerProblem(location, description, highlightType, range, fixes);
}
protected final void registerErrorAtRange(@NotNull PsiElement startLocation, @NotNull PsiElement endLocation, Object... infos) {
if (startLocation.getTextLength() == 0 && startLocation == endLocation) {
return;
}
final LocalQuickFix[] fixes = createAndInitFixes(infos);
final String description = inspection.buildErrorString(infos);
final ProblemDescriptor problemDescriptor = holder.getManager()
.createProblemDescriptor(startLocation, endLocation, description, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, onTheFly, fixes);
holder.registerProblem(problemDescriptor);
}
@NotNull
private LocalQuickFix[] createAndInitFixes(Object[] infos) {
final InspectionGadgetsFix[] fixes = createFixes(infos);
for (InspectionGadgetsFix fix : fixes) {
fix.setOnTheFly(onTheFly);
}
final String description = inspection.buildErrorString(infos);
final TextRange range = new TextRange(offset, offset + length);
holder.registerProblem(location, description, highlightType, range, fixes);
return fixes;
}
@NotNull
@@ -15,8 +15,12 @@
*/
package com.siyeh.ig.style;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.InspectionProfile;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
@@ -24,12 +28,17 @@ import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.PsiReplacementUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
public class ControlFlowStatementWithoutBracesInspection
extends BaseInspection {
private static final String DO_TEXT = "do";
private static final String ELSE_TEXT = "else";
private static final String FOR_TEXT = "for";
private static final String IF_TEXT = "if";
private static final String WHILE_TEXT = "while";
@Override
@NotNull
public String getDisplayName() {
@@ -41,38 +50,52 @@ public class ControlFlowStatementWithoutBracesInspection
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message(
"control.flow.statement.without.braces.problem.descriptor");
"control.flow.statement.without.braces.problem.descriptor", infos);
}
@Override
public InspectionGadgetsFix buildFix(Object... infos) {
return new ControlFlowStatementFix();
if (infos.length == 1 && infos[0] instanceof String) {
return new ControlFlowStatementFix((String)infos[0]);
}
return null;
}
private static class ControlFlowStatementFix extends InspectionGadgetsFix {
private final String myKeywordText;
public ControlFlowStatementFix(String keywordText) {
myKeywordText = keywordText;
}
@Override
@NotNull
public String getName() {
return InspectionGadgetsBundle.message(
"control.flow.statement.without.braces.add.quickfix");
"control.flow.statement.without.braces.message", myKeywordText);
}
@Override
@NotNull
public String getFamilyName() {
return getName();
return InspectionGadgetsBundle.message(
"control.flow.statement.without.braces.add.quickfix");
}
@Override
protected void doFix(Project project, ProblemDescriptor descriptor)
throws IncorrectOperationException {
final PsiElement element = descriptor.getPsiElement();
final PsiElement element = descriptor.getStartElement();
final PsiElement parent = element.getParent();
if (!(parent instanceof PsiStatement)) {
final PsiStatement statement;
if (element instanceof PsiStatement) {
statement = (PsiStatement)element;
}
else if ((parent instanceof PsiStatement)) {
statement = (PsiStatement)parent;
}
else {
return;
}
final PsiStatement statement = (PsiStatement)parent;
@NonNls final String elementText = element.getText();
final PsiStatement statementWithoutBraces;
if (statement instanceof PsiLoopStatement) {
final PsiLoopStatement loopStatement =
@@ -81,7 +104,10 @@ public class ControlFlowStatementWithoutBracesInspection
}
else if (statement instanceof PsiIfStatement) {
final PsiIfStatement ifStatement = (PsiIfStatement)statement;
if ("if".equals(elementText)) {
if (element == ifStatement.getElseElement()) {
statementWithoutBraces = ifStatement.getElseBranch();
}
else {
statementWithoutBraces = ifStatement.getThenBranch();
if (statementWithoutBraces == null) {
return;
@@ -93,9 +119,6 @@ public class ControlFlowStatementWithoutBracesInspection
nextSibling.delete();
}
}
else {
statementWithoutBraces = ifStatement.getElseBranch();
}
}
else {
return;
@@ -111,11 +134,18 @@ public class ControlFlowStatementWithoutBracesInspection
@Override
public BaseInspectionVisitor buildVisitor() {
return new ControlFlowStatementVisitor();
final String shortName = getShortName();
final HighlightDisplayKey key = HighlightDisplayKey.find(shortName);
return new ControlFlowStatementVisitor(key);
}
private static class ControlFlowStatementVisitor
extends BaseInspectionVisitor {
private HighlightDisplayKey myKey;
public ControlFlowStatementVisitor(HighlightDisplayKey key) {
myKey = key;
}
@Override
public void visitDoWhileStatement(PsiDoWhileStatement statement) {
@@ -124,7 +154,7 @@ public class ControlFlowStatementWithoutBracesInspection
if (body == null || body instanceof PsiBlockStatement) {
return;
}
registerStatementError(statement);
registerKeywordOrStatementError(statement, DO_TEXT);
}
@Override
@@ -134,7 +164,7 @@ public class ControlFlowStatementWithoutBracesInspection
if (body == null || body instanceof PsiBlockStatement) {
return;
}
registerStatementError(statement);
registerKeywordOrStatementError(statement, FOR_TEXT);
}
@Override
@@ -144,7 +174,7 @@ public class ControlFlowStatementWithoutBracesInspection
if (body == null || body instanceof PsiBlockStatement) {
return;
}
registerStatementError(statement);
registerKeywordOrStatementError(statement, FOR_TEXT);
}
@Override
@@ -154,8 +184,15 @@ public class ControlFlowStatementWithoutBracesInspection
if (thenBranch == null) {
return;
}
boolean highlightOnlyKeyword = isHighlightOnlyKeyword(statement);
if (!(thenBranch instanceof PsiBlockStatement)) {
registerStatementError(statement);
if (highlightOnlyKeyword) {
registerStatementError(statement, IF_TEXT);
}
else {
final PsiElement startElement = statement.getFirstChild();
registerErrorAtRange(startElement != null ? startElement : thenBranch, thenBranch, IF_TEXT);
}
}
final PsiStatement elseBranch = statement.getElseBranch();
if (elseBranch == null) {
@@ -167,7 +204,12 @@ public class ControlFlowStatementWithoutBracesInspection
if (elseKeyword == null) {
return;
}
registerError(elseKeyword);
if (highlightOnlyKeyword) {
registerError(elseKeyword, ELSE_TEXT);
}
else {
registerErrorAtRange(elseKeyword, elseBranch, ELSE_TEXT);
}
}
}
@@ -178,7 +220,30 @@ public class ControlFlowStatementWithoutBracesInspection
if (body == null || body instanceof PsiBlockStatement) {
return;
}
registerStatementError(statement);
registerKeywordOrStatementError(statement, WHILE_TEXT);
}
private void registerKeywordOrStatementError(PsiStatement statement, String text) {
boolean highlightOnlyKeyword = isHighlightOnlyKeyword(statement);
if (highlightOnlyKeyword) {
registerStatementError(statement, text);
}
else {
registerError(statement, text);
}
}
private boolean isHighlightOnlyKeyword(PsiElement element) {
if (!isOnTheFly()) {
return true;
}
if (myKey != null) {
final Project project = element.getProject();
final InspectionProfile profile = InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
HighlightDisplayLevel errorLevel = profile.getErrorLevel(myKey, element);
return !HighlightDisplayLevel.DO_NOT_SHOW.equals(errorLevel);
}
return false;
}
}
}
@@ -0,0 +1,9 @@
class T {
void f(String[] a) {
int j = 0;
do {
System.out.println(a[j++]);
}
while (j < a.length);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
int j = 0;
do System.out.println<caret>(a[j++]);
while (j < a.length);
}
}
@@ -0,0 +1,9 @@
class T {
void f(String[] a) {
int j = 0;
do {
System.out.println(a[j++]);
}
while (j < a.length);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
int j = 0;
do System.out.println(a[j++]);
while (j < a<caret>.length);
}
}
@@ -0,0 +1,9 @@
class T {
void f(String[] a) {
int j = 0;
do {
System.out.println(a[j++]);
}
while (j < a.length);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
int j = 0;
do System.out.println(a[j++]);<caret>
while (j < a.length);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
for (String s : a) {
System.out.println(s);
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
for (String s : a)
System.out.println(s)<caret>;
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
for (String s : a) {
System.out.println(s);
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
for (String s : <caret>a)
System.out.println(s);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
for (String s : a) {
System.out.println(s);
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
<caret>for (String s : a)
System.out.println(s);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
for<caret> (int i = 0; i < a.length; i++)
System.out.println(a[i]);
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0) {
System.out.println("no");
} else
System.out.println(a.length);
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0)
System<caret>.out.println("no");
else
System.out.println(a.length);
}
}
@@ -0,0 +1,9 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.out.println("no");
else {
System.out.println(a.length);
}
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.out.println("no");
else
System<caret>.out.println(a.length);
}
}
@@ -0,0 +1,9 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.out.println("no");
else {
System.out.println(a.length);
}
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.out.println("no");
<caret>else
System.out.println(a.length);
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0) {
System.out.println("no");
} else
System.out.println(a.length);
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
<caret>if (a.length == 0)
System.out.println("no");
else
System.out.println(a.length);
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.out.println("no"); <caret>
else
System.out.println(a.length);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
if (a.length == 0) {
System.out.println("no");
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
if (a.length == 0)
System.<caret>out.println("no");
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
if (a.length == 0) {
System.out.println("no");
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
if (a.length<caret> == 0)
System.out.println("no");
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
if (a.length == 0) {
System.out.println("no");
}
}
}
@@ -0,0 +1,6 @@
class T {
void f(String[] a) {
<caret>if (a.length == 0)
System.out.println("no");
}
}
@@ -0,0 +1,8 @@
class T {
void f(String[] a) {
int k = 0;
while (k < a.length) {
System.out.println(a[k++]);
}
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
int k = 0;
while <caret>(k < a.length)
System.out.println(a[k++]);
}
}
@@ -0,0 +1,7 @@
class T {
void f(String[] a) {
int k = 0;<caret>
while (k < a.length)
System.out.println(a[k++]);
}
}
@@ -0,0 +1,29 @@
class T {
void f(String[] a) {
for (String s : a)
System.out.println(s);
if (a.length == 0)
System.out.println("no");
else
System.out.println(a.length);
for (int i = 0; i < a.length; i++)
System.out.println(a[i]);
int j = 0;
do System.out.println(a[j++]);
while (j < a.length);
int k = 0;
while (k < a.length)
System.out.println(a[k++]);
if (a.length == 0)
System.out.println("no");
if (a.length == 0) {
} else
System.out.println(a.length);
}
}
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>ControlFlowStatements.java</file>
<line>3</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;for&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>6</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;if&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>8</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;else&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>11</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;for&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>15</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;do&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>19</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;while&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>22</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;if&lt;/code&gt; without braces #loc</description>
</problem>
<problem>
<file>ControlFlowStatements.java</file>
<line>26</line>
<problem_class>Control flow statement without braces</problem_class>
<description>&lt;code&gt;else&lt;/code&gt; without braces #loc</description>
</problem>
</problems>
@@ -116,8 +116,9 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas
}
public IntentionAction findIntention(@NotNull final String hint) {
final List<IntentionAction> allIntentions = myFixture.getAvailableIntentions();
final List<IntentionAction> intentions =
ContainerUtil.findAll(myFixture.getAvailableIntentions(),
ContainerUtil.findAll(allIntentions,
intentionAction -> intentionAction instanceof QuickFixWrapper &&
intentionAction.getText().equals(hint));
Assert.assertFalse("\"" + hint + "\" not in " + intentions, intentions.isEmpty());
@@ -0,0 +1,75 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.fixes.braces;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.IGQuickFixesTestCase;
import com.siyeh.ig.style.ControlFlowStatementWithoutBracesInspection;
/**
* @author Pavel.Dolgov
*/
public class ControlFlowStatementWithoutBracesFixTest extends IGQuickFixesTestCase {
public void testSimpleIfBody() { doTest("if"); }
public void testSimpleIfExpression() { doTest("if"); }
public void testSimpleIfKeyword() { doTest("if"); }
public void testFullIfBody() { doTest("if"); }
public void testFullIfKeyword() { doTest("if"); }
public void testFullIfElseBody() { doTest("else"); }
public void testFullIfElseKeyword() { doTest("else"); }
public void testFullIfMiddle() { assertQuickfixNotAvailable(getMessagePrefix()); }
public void testDoBody() { doTest("do"); }
public void testDoExpression() { doTest("do"); }
public void testDoMiddle() { doTest("do"); }
public void testForEachBody() { doTest("for"); }
public void testForEachExpression() { doTest("for"); }
public void testForEachKeyword() { doTest("for"); }
public void testForIndex() { doTest("for"); }
public void testWhile() { doTest("while"); }
public void testWhileOutside() { assertQuickfixNotAvailable(getMessagePrefix()); }
@Override
protected void setUp() throws Exception {
super.setUp();
myRelativePath = "statement_without_braces";
}
@Override
protected BaseInspection getInspection() {
return new ControlFlowStatementWithoutBracesInspection();
}
protected void doTest(String keyword) {
super.doTest(getMessage(keyword));
}
private static String getMessage(String keyword) {
return InspectionGadgetsBundle.message("control.flow.statement.without.braces.message", keyword);
}
private static String getMessagePrefix() {
final String message = InspectionGadgetsBundle.message("control.flow.statement.without.braces.message", "@");
final int index = message.indexOf("@");
if (index >= 0) return message.substring(0, index);
return message;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ig.style;
import com.siyeh.ig.IGInspectionTestCase;
/**
* @author Pavel.Dolgov
*/
public class ControlFlowStatementWithoutBracesInspectionTest extends IGInspectionTestCase {
public void test() {
doTest("com/siyeh/igtest/style/statements_without_braces", new ControlFlowStatementWithoutBracesInspection());
}
}
@@ -351,11 +351,6 @@
<bundleName>com.siyeh.IntentionPowerPackBundle</bundleName>
<categoryKey>intention.category.control.flow</categoryKey>
</intentionAction>
<intentionAction>
<className>com.siyeh.ipp.braces.AddBracesIntention</className>
<bundleName>com.siyeh.IntentionPowerPackBundle</bundleName>
<categoryKey>intention.category.control.flow</categoryKey>
</intentionAction>
<intentionAction>
<className>com.siyeh.ipp.braces.RemoveBracesIntention</className>
<bundleName>com.siyeh.IntentionPowerPackBundle</bundleName>
@@ -90,7 +90,6 @@ flip.comparison.intention.family.name=Flip Comparison
flip.conjunction.intention.family.name=Flip Conjunction Operands
negate.comparison.intention.family.name=Negate Comparison
remove.braces.intention.family.name=Remove Braces
add.braces.intention.family.name=Add Braces
flip.commutative.method.call.intention.family.name=Flip Commutative Method Call
constant.subexpression.intention.family.name=Compute Constant Value for Subexpression
extract.increment.intention.family.name=Extract Increment
@@ -172,7 +171,6 @@ flip.smth.intention.name1=Flip ''{0}'' (changes semantics)
flip.comparison.intention.name=Flip ''{0}'' to ''{1}''
negate.comparison.intention.name=Negate ''{0}''
negate.comparison.intention.name1=Negate ''{0}'' to ''{1}''
add.braces.intention.name=Add braces to ''{0}'' statement
remove.braces.intention.name=Remove braces from ''{0}'' statement
flip.commutative.method.call.intention.name=Flip ''.{0}()''
flip.commutative.method.call.intention.name1=Flip ''.{0}()'' (may change semantics)
@@ -1,51 +0,0 @@
/*
* Copyright 2003-2006 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.siyeh.ipp.braces;
import com.intellij.psi.*;
import com.intellij.util.IncorrectOperationException;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
public class AddBracesIntention extends BaseBracesIntention {
@NotNull
protected PsiElementPredicate getElementPredicate() {
return new PsiElementPredicate() {
@Override
public boolean satisfiedBy(PsiElement element) {
final PsiStatement statement = getSurroundingStatement(element);
return statement != null && !(statement instanceof PsiBlockStatement);
}
};
}
@NotNull
@Override
protected String getMessageKey() {
return "add.braces.intention.name";
}
protected void processIntention(@NotNull PsiElement element) throws IncorrectOperationException {
final PsiStatement statement = getSurroundingStatement(element);
if (statement == null) {
return;
}
final String newStatement = "{\n" + statement.getText() + "\n}";
PsiReplacementUtil.replaceStatement(statement, newStatement);
}
}
@@ -1,8 +0,0 @@
public class X {
int f(boolean b) {
if (b) {
return 1;
}
return 0;
}
}
@@ -1,6 +0,0 @@
public class X {
int f(boolean b) {
if (b) <spot>return 1</spot>;
return 0;
}
}
@@ -1,6 +0,0 @@
<html>
<body>
This intention adds braces to control flow statements without
braces.
</body>
</html>
@@ -18,7 +18,6 @@ package org.jetbrains.idea.devkit;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationType;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.projectWizard.NewProjectWizardTestCase;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
@@ -46,14 +45,4 @@ public class PluginProjectWizardTest extends NewProjectWizardTestCase {
VirtualFile[] files = FileEditorManager.getInstance(project).getOpenFiles();
assertEquals(1, files.length);
}
public void testProjectWithoutSdk() throws Exception {
try {
createProjectFromTemplate(PluginModuleType.getInstance().getName(), null, null);
fail("Exception should be thrown");
}
catch (Exception e) {
assertEquals(IdeBundle.message("prompt.confirm.project.no.jdk"), e.getMessage());
}
}
}
@@ -26,6 +26,7 @@ import org.apache.http.message.BasicHeader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubConnection.PagedRequest;
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException;
import org.jetbrains.plugins.github.exceptions.GithubConfusingException;
import org.jetbrains.plugins.github.exceptions.GithubJsonException;
import org.jetbrains.plugins.github.exceptions.GithubStatusCodeException;
@@ -289,12 +290,12 @@ public class GithubApiUtil {
try {
repos.addAll(getMembershipRepos(connection));
}
catch (GithubStatusCodeException ignore) {
catch (GithubAuthenticationException | GithubStatusCodeException ignore) {
}
try {
repos.addAll(getWatchedRepos(connection));
}
catch (GithubStatusCodeException ignore) {
catch (GithubAuthenticationException | GithubStatusCodeException ignore) {
}
return repos;
@@ -130,7 +130,7 @@ abstract class BaseRepositoryManager(protected val dir: Path) : RepositoryManage
*/
protected abstract fun addToIndex(file: Path, path: String, content: ByteArray, size: Int)
override fun delete(path: String) {
override fun delete(path: String): Boolean {
LOG.debug { "Remove $path"}
lock.write {
@@ -138,8 +138,11 @@ abstract class BaseRepositoryManager(protected val dir: Path) : RepositoryManage
// delete could be called for non-existent file
if (file.exists()) {
delete(file, path)
return true
}
}
return false
}
private fun delete(file: Path, path: String) {
+19 -16
View File
@@ -242,23 +242,26 @@ class IcsApplicationLoadListener : ApplicationLoadListener {
val repositoryManager = icsManager.repositoryManager
if (repositoryManager.isRepositoryExists() && repositoryManager is GitRepositoryManager) {
if (repositoryManager.renameDirectory(linkedMapOf(
Pair("\$ROOT_CONFIG$", null),
Pair("_mac/\$ROOT_CONFIG$", "_mac"),
Pair("_windows/\$ROOT_CONFIG$", "_windows"),
Pair("_linux/\$ROOT_CONFIG$", "_linux"),
Pair("_freebsd/\$ROOT_CONFIG$", "_freebsd"),
Pair("_unix/\$ROOT_CONFIG$", "_unix"),
Pair("_unknown/\$ROOT_CONFIG$", "_unknown"),
val migrateSchemes = repositoryManager.renameDirectory(linkedMapOf(
Pair("\$ROOT_CONFIG$", null),
Pair("_mac/\$ROOT_CONFIG$", "_mac"),
Pair("_windows/\$ROOT_CONFIG$", "_windows"),
Pair("_linux/\$ROOT_CONFIG$", "_linux"),
Pair("_freebsd/\$ROOT_CONFIG$", "_freebsd"),
Pair("_unix/\$ROOT_CONFIG$", "_unix"),
Pair("_unknown/\$ROOT_CONFIG$", "_unknown"),
Pair("\$APP_CONFIG$", null),
Pair("_mac/\$APP_CONFIG$", "_mac"),
Pair("_windows/\$APP_CONFIG$", "_windows"),
Pair("_linux/\$APP_CONFIG$", "_linux"),
Pair("_freebsd/\$APP_CONFIG$", "_freebsd"),
Pair("_unix/\$APP_CONFIG$", "_unix"),
Pair("_unknown/\$APP_CONFIG$", "_unknown")
))) {
Pair("\$APP_CONFIG$", null),
Pair("_mac/\$APP_CONFIG$", "_mac"),
Pair("_windows/\$APP_CONFIG$", "_windows"),
Pair("_linux/\$APP_CONFIG$", "_linux"),
Pair("_freebsd/\$APP_CONFIG$", "_freebsd"),
Pair("_unix/\$APP_CONFIG$", "_unix"),
Pair("_unknown/\$APP_CONFIG$", "_unknown")
))
val removeOtherXml = repositoryManager.delete("other.xml")
if (migrateSchemes || removeOtherXml) {
// schedule push to avoid merge conflicts
application.invokeLater({ icsManager.autoSyncManager.autoSync(force = true) })
}
@@ -46,7 +46,7 @@ interface RepositoryManager {
*/
fun write(path: String, content: ByteArray, size: Int): Boolean
fun delete(path: String)
fun delete(path: String): Boolean
fun processChildren(path: String, filter: (name: String) -> Boolean, processor: (name: String, inputStream: InputStream) -> Boolean)
@@ -113,6 +113,24 @@ public class PyPsiUtils {
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class);
}
/**
* Finds first non-whitespace sibling after given PSI element but stops at first whitespace containing line feed.
*/
@Nullable
public static PsiElement getNextNonWhitespaceSiblingOnSameLine(@NotNull PsiElement element) {
PsiElement cur = element.getNextSibling();
while (cur != null) {
if (!(cur instanceof PsiWhiteSpace)) {
return cur;
}
else if (cur.textContains('\n')) {
break;
}
cur = cur.getNextSibling();
}
return null;
}
/**
* Finds first non-whitespace sibling after given AST node.
*/
@@ -62,7 +62,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
@Override
public int getStubVersion() {
// Don't forget to update versions of indexes that use the updated stub-based elements
return 56;
return 57;
}
@Nullable
@@ -890,6 +890,16 @@ public class PyUtil {
}
}
/**
* Returns the line comment that immediately precedes statement list of the given compound statement. Python parser ensures
* that it follows the statement header, i.e. it's directly after the colon, not on its own line.
*/
@Nullable
public static PsiComment getCommentOnHeaderLine(@NotNull PyStatementListContainer container) {
final PyStatementList statementList = container.getStatementList();
return as(PyPsiUtils.getPrevNonWhitespaceSibling(statementList), PsiComment.class);
}
public static class KnownDecoratorProviderHolder {
public static PyKnownDecoratorProvider[] KNOWN_DECORATOR_PROVIDERS = Extensions.getExtensions(PyKnownDecoratorProvider.EP_NAME);
@@ -579,12 +579,12 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
@Nullable
@Override
public PsiComment getTypeComment() {
final PyStatementList statements = getStatementList();
final PsiComment inlineComment = as(PyPsiUtils.getPrevNonWhitespaceSibling(statements), PsiComment.class);
final PsiComment inlineComment = PyUtil.getCommentOnHeaderLine(this);
if (inlineComment != null && PyTypingTypeProvider.getTypeCommentValue(inlineComment.getText()) != null) {
return inlineComment;
}
final PyStatementList statements = getStatementList();
if (statements.getStatements().length != 0) {
final PsiComment comment = as(statements.getFirstChild(), PsiComment.class);
if (comment != null && PyTypingTypeProvider.getTypeCommentValue(comment.getText()) != null) {
@@ -62,6 +62,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.jetbrains.python.psi.PyUtil.as;
/**
* @author yole
*/
@@ -682,34 +684,21 @@ public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpression
@Nullable
@Override
public PsiComment getTypeComment() {
final PsiElement commentContainer = PsiTreeUtil.getParentOfType(this,
PyAssignmentStatement.class,
PyWithStatement.class,
PyForPart.class);
if (commentContainer != null) {
final PsiComment comment = getSameLineTrailingCommentChild(commentContainer);
if (comment != null && PyTypingTypeProvider.getTypeCommentValue(comment.getText()) != null) {
return comment;
PsiComment comment = null;
final PyAssignmentStatement assignment = PsiTreeUtil.getParentOfType(this, PyAssignmentStatement.class);
if (assignment != null) {
final PyExpression assignedValue = assignment.getAssignedValue();
if (assignedValue != null) {
comment = as(PyPsiUtils.getNextNonWhitespaceSiblingOnSameLine(assignedValue), PsiComment.class);
}
}
return null;
}
@Nullable
private static PsiComment getSameLineTrailingCommentChild(@NotNull PsiElement element) {
PsiElement child = element.getFirstChild();
while (true) {
if (child == null) {
return null;
else {
final PyStatementListContainer forOrWith = PsiTreeUtil.getParentOfType(this, PyForPart.class, PyWithStatement.class);
if (forOrWith != null) {
comment = PyUtil.getCommentOnHeaderLine(forOrWith);
}
if (child instanceof PsiComment) {
return (PsiComment)child;
}
if (child.getText().contains("\n")) {
return null;
}
child = child.getNextSibling();
}
return comment != null && PyTypingTypeProvider.getTypeCommentValue(comment.getText()) != null ? comment : null;
}
@Nullable
@@ -36,7 +36,6 @@ import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
import com.jetbrains.python.psi.stubs.PyClassNameIndex;
import com.jetbrains.python.psi.stubs.PyNamedTupleStub;
import com.jetbrains.python.psi.stubs.PyVariableNameIndex;
import com.jetbrains.python.psi.types.PyClassType;
import com.jetbrains.python.psi.types.PyType;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.toolbox.Maybe;
@@ -439,39 +438,6 @@ public class PyStubsTest extends PyTestCase {
assertNotParsed(file);
}
// PY-18741
public void testParameterTypeComment() {
final PyFile file = getTestFile();
final PyFunction func = file.findTopLevelFunction("func");
assertNotNull(func);
final PyParameter[] parameters = func.getParameterList().getParameters();
assertSize(2, parameters);
final PyNamedParameter param = assertInstanceOf(parameters[0], PyNamedParameter.class);
final String annotation = param.getTypeCommentAnnotation();
assertEquals("int", annotation);
assertNotParsed(file);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), file);
final PyType paramType = context.getType(param);
assertInstanceOf(paramType, PyClassType.class);
assertNotParsed(file);
}
public void testTargetExpressionTypeComment() {
final PyFile file = getTestFile();
final PyTargetExpression target = file.findTopLevelAttribute("x");
assertNotNull(target);
final String annotation = target.getTypeCommentAnnotation();
assertEquals("int", annotation);
assertNotParsed(file);
final TypeEvalContext context = TypeEvalContext.codeAnalysis(myFixture.getProject(), file);
final PyType paramType = context.getType(target);
assertInstanceOf(paramType, PyClassType.class);
assertNotParsed(file);
}
public void testFullyQualifiedNamedTuple() {
doTestNamedTuple(
QualifiedName.fromDottedString("collections.namedtuple")
@@ -303,6 +303,17 @@ public class PyTypingTest extends PyTestCase {
" expr = c1, c2\n");
}
// PY-19220
public void testMultiLineAssignmentComment() {
doTest("List[str]",
"from typing import List\n" +
"\n" +
"expr = [\n" +
" a,\n" +
" b,\n" +
"] # type: List[str]");
}
public void testForLoopComment() {
doTest("int",
"def foo(xs):\n" +