From 110f5e10adba8d7ee37cd30ca9d96ebc68fabf95 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 7 May 2015 16:47:27 +0200 Subject: [PATCH 1/8] IG: care for lambda's in"Field accessed in both synchronized and unsynchronized contexts" inspection --- .../src/com/siyeh/ig/threading/VariableAccessVisitor.java | 8 ++++++++ .../FieldAccessedSynchronizedAndUnsynchronized.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java index ccf65acb98df..e2f168608f1d 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java @@ -61,6 +61,14 @@ class VariableAccessVisitor extends JavaRecursiveElementVisitor { m_inSynchronizedContext = wasInSync; } + @Override + public void visitLambdaExpression(PsiLambdaExpression expression) { + final boolean wasInSync = m_inSynchronizedContext; + m_inSynchronizedContext = false; + super.visitLambdaExpression(expression); + m_inSynchronizedContext = wasInSync; + } + @Override public void visitReferenceExpression(@NotNull PsiReferenceExpression ref) { super.visitReferenceExpression(ref); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java index 61e2e8a45bcd..1029047cff85 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java @@ -4,12 +4,14 @@ public class FieldAccessedSynchronizedAndUnsynchronized { private final Object m_lock = new Object(); private Object m_contents = new Object(); + private Object a; public void foo() { synchronized(m_lock) { m_contents = new Object(); + a = new Object(); } getContents(); } @@ -24,6 +26,12 @@ public class FieldAccessedSynchronizedAndUnsynchronized getContents(); } + public synchronized void g() { + Runnable r = () -> { + System.out.println(a); + }; + } + } class Test { private Object object; From 15d0233c5ac4d89b816f4f21aa02672edd087b12 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 7 May 2015 16:57:23 +0200 Subject: [PATCH 2/8] IDEA-20012 (assert on Thread.holdsLock is ignored by inspections which validate synchronization) --- .../ig/psiutils/SynchronizationUtil.java | 62 +++++++++++++++++-- .../ig/threading/VariableAccessVisitor.java | 10 +++ .../CallToNativeMethodWhileLocked.java | 10 ++- ...AccessedSynchronizedAndUnsynchronized.java | 7 +++ 4 files changed, 80 insertions(+), 9 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SynchronizationUtil.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SynchronizationUtil.java index 297a862a2c1d..69bee7a7fab9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SynchronizationUtil.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/SynchronizationUtil.java @@ -16,12 +16,11 @@ package com.siyeh.ig.psiutils; import com.intellij.psi.*; -import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.*; public class SynchronizationUtil { - private SynchronizationUtil() { - } + private SynchronizationUtil() {} public static boolean isInSynchronizedContext(PsiElement element) { final PsiElement context = @@ -29,10 +28,61 @@ public class SynchronizationUtil { if (context instanceof PsiSynchronizedStatement) { return true; } - if (!(context instanceof PsiMethod)) { + if (context instanceof PsiMethod) { + final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)context; + if (modifierListOwner.hasModifierProperty(PsiModifier.SYNCHRONIZED)) { + return true; + } + } + if (context instanceof PsiMethod || context instanceof PsiLambdaExpression) { + final HoldsLockAssertionVisitor visitor = new HoldsLockAssertionVisitor(); + context.accept(visitor); + final PsiAssertStatement assertStatement = visitor.getAssertStatement(); + return assertStatement != null && assertStatement.getTextOffset() + assertStatement.getTextLength() < element.getTextOffset(); + } + return false; + } + + public static boolean isCallToHoldsLock(PsiExpression expression) { + expression = ParenthesesUtils.stripParentheses(expression); + if (!(expression instanceof PsiMethodCallExpression)) { return false; } - final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)context; - return modifierListOwner.hasModifierProperty(PsiModifier.SYNCHRONIZED); + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; + final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); + final String name = methodExpression.getReferenceName(); + if (!"holdsLock".equals(name)) { + return false; + } + final PsiMethod method = methodCallExpression.resolveMethod(); + if (method == null) { + return false; + } + final PsiClass aClass = method.getContainingClass(); + return com.intellij.psi.util.InheritanceUtil.isInheritor(aClass, "java.lang.Thread"); + } + + private static class HoldsLockAssertionVisitor extends JavaRecursiveElementVisitor { + private PsiAssertStatement myAssertStatement = null; + + @Override + public void visitAssertStatement(PsiAssertStatement statement) { + if (myAssertStatement != null) return; + super.visitAssertStatement(statement); + final PsiExpression condition = statement.getAssertCondition(); + if (isCallToHoldsLock(condition)) { + myAssertStatement = statement; + } + } + + @Override + public void visitElement(PsiElement element) { + if (myAssertStatement != null) return; + super.visitElement(element); + } + + public PsiAssertStatement getAssertStatement() { + return myAssertStatement; + } } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java index e2f168608f1d..c1035e374ed9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/VariableAccessVisitor.java @@ -21,6 +21,7 @@ import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PropertyUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashMap; +import com.siyeh.ig.psiutils.SynchronizationUtil; import org.jetbrains.annotations.NotNull; import java.util.Collection; @@ -136,6 +137,15 @@ class VariableAccessVisitor extends JavaRecursiveElementVisitor { m_inSynchronizedContext = wasInSync; } + @Override + public void visitAssertStatement(PsiAssertStatement statement) { + final PsiExpression condition = statement.getAssertCondition(); + if (SynchronizationUtil.isCallToHoldsLock(condition)) { + m_inSynchronizedContext = true; + } + super.visitAssertStatement(statement); + } + @Override public void visitMethod(@NotNull PsiMethod method) { if (method.hasModifierProperty(PsiModifier.PRIVATE)) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/call_to_native_method_while_locked/CallToNativeMethodWhileLocked.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/call_to_native_method_while_locked/CallToNativeMethodWhileLocked.java index 75e89d147a73..9e92fbb62307 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/call_to_native_method_while_locked/CallToNativeMethodWhileLocked.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/call_to_native_method_while_locked/CallToNativeMethodWhileLocked.java @@ -3,12 +3,16 @@ package com.siyeh.igtest.threading.call_to_native_method_while_locked; public class CallToNativeMethodWhileLocked { synchronized void a() { - Double.doubleToLongBits(9.7); + Double.doubleToRawLongBits(9.7); Runnable r = () -> { - Double.doubleToLongBits(123.4); + Double.doubleToRawLongBits(123.4); }; new Object() { - long l = Double.doubleToLongBits(42.0); + long l = Double.doubleToRawLongBits(42.0); + }; + Runnable s = () -> { + assert Thread.holdsLock(this); + Double.doubleToRawLongBits(40.0); }; } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java index 1029047cff85..a46cd52de9df 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/field_accessed_synchronized_and_unsynchronized/FieldAccessedSynchronizedAndUnsynchronized.java @@ -5,6 +5,7 @@ public class FieldAccessedSynchronizedAndUnsynchronized private final Object m_lock = new Object(); private Object m_contents = new Object(); private Object a; + private Object b; public void foo() { @@ -12,6 +13,7 @@ public class FieldAccessedSynchronizedAndUnsynchronized { m_contents = new Object(); a = new Object(); + b = new Object(); } getContents(); } @@ -32,6 +34,11 @@ public class FieldAccessedSynchronizedAndUnsynchronized }; } + public void h() { + assert Thread.holdsLock(m_lock); + System.out.println(b); + } + } class Test { private Object object; From 631354d68f69f21e9347fbacc0506fe91d524016 Mon Sep 17 00:00:00 2001 From: Vyacheslav Karpukhin Date: Thu, 7 May 2015 16:44:33 +0200 Subject: [PATCH 3/8] AppCode: Java 8 charset-related fix --- .../util/src/com/intellij/ui/mac/foundation/Foundation.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java index f4ad998b1cd4..bcbf741fbe10 100644 --- a/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java +++ b/platform/util/src/com/intellij/ui/mac/foundation/Foundation.java @@ -188,7 +188,9 @@ public class Foundation { public static String getEncodingName(long nsStringEncoding) { long cfEncoding = myFoundationLibrary.CFStringConvertNSStringEncodingToEncoding(nsStringEncoding); ID pointer = myFoundationLibrary.CFStringConvertEncodingToIANACharSetName(cfEncoding); - return toStringViaUTF8(pointer); + String name = toStringViaUTF8(pointer); + if ("macintosh".equals(name)) name = "MacRoman"; // JDK8 does not recognize IANA's "macintosh" alias + return name; } public static long getEncodingCode(@Nullable String encodingName) { From 78bec84a7e9bf70e57036c474abf7dbcb66401fc Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Thu, 7 May 2015 18:07:41 +0300 Subject: [PATCH 4/8] IDEA-139975 Quicksearch input doesn't change its position when window is resized --- .../src/com/intellij/ui/SpeedSearchBase.java | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 51fa97249359..754c6219b11d 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -46,10 +46,7 @@ import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; import java.awt.*; -import java.awt.event.FocusAdapter; -import java.awt.event.FocusEvent; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; +import java.awt.event.*; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ListIterator; @@ -72,6 +69,22 @@ public abstract class SpeedSearchBase extends SpeedSear public SpeedSearchBase(Comp component) { myComponent = component; + myComponent.addComponentListener(new ComponentAdapter() { + @Override + public void componentHidden(ComponentEvent event) { + manageSearchPopup(null); + } + + @Override + public void componentMoved(ComponentEvent event) { + moveSearchPopup(); + } + + @Override + public void componentResized(ComponentEvent event) { + moveSearchPopup(); + } + }); myComponent.addFocusListener(new FocusAdapter() { @Override public void focusLost(FocusEvent e) { @@ -568,7 +581,11 @@ public abstract class SpeedSearchBase extends SpeedSear return; } myPopupLayeredPane.add(mySearchPopup, JLayeredPane.POPUP_LAYER); - if (myPopupLayeredPane == null) return; // See # 27482. Somewho it does happen... + moveSearchPopup(); + } + + private void moveSearchPopup() { + if (myComponent == null || mySearchPopup == null || myPopupLayeredPane == null) return; Point lPaneP = myPopupLayeredPane.getLocationOnScreen(); Point componentP = getComponentLocationOnScreen(); Rectangle r = getComponentVisibleRect(); From 86f7d9b8aa4a676ad0784aebc9e44e6709a6fbfb Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Thu, 7 May 2015 17:42:26 +0200 Subject: [PATCH 5/8] platform: handling of incorrect URLs in JarLoader restored --- .../util/src/com/intellij/util/lang/JarLoader.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/platform/util/src/com/intellij/util/lang/JarLoader.java b/platform/util/src/com/intellij/util/lang/JarLoader.java index 0c5499f4c2d5..68c0bfb5479e 100644 --- a/platform/util/src/com/intellij/util/lang/JarLoader.java +++ b/platform/util/src/com/intellij/util/lang/JarLoader.java @@ -16,15 +16,14 @@ package com.intellij.util.lang; import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import sun.misc.Resource; -import java.io.File; import java.io.IOException; import java.lang.ref.SoftReference; -import java.net.URISyntaxException; import java.net.URL; import java.util.Enumeration; import java.util.zip.ZipEntry; @@ -53,13 +52,8 @@ class JarLoader extends Loader { } } - private File getFileUrl() throws IOException { - try { - return new File(myURL.toURI()); - } - catch (URISyntaxException e) { - throw new IOException(e); - } + private String getFileUrl() throws IOException { + return FileUtil.unquote(myURL.getFile()); } @NotNull From db5866e800e4ba558c85739b234716822323fbff Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 7 May 2015 17:42:27 +0200 Subject: [PATCH 6/8] Registry key to control bold underline height in editor --- platform/util/resources/misc/registry.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index f21505687c03..29526593cfac 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -539,6 +539,9 @@ editor.xcode.like.scrollbar.description=Enables auto-hideable Xcode-like editor editor.config.stop.at.project.root=true editor.config.stop.at.project.root.description=Stops searching for .editorconfig at project root (requires project reopening) +editor.bold.underline.height=2 +editor.bold.underline.height.description=Underline height for EffectType.BOLD_LINE_UNDERSCORE + JDK8042508.bug.fixed=false JDK8042508.bug.fixed.description=Disable check for type variable until javac bug is fixed From 09c1ee8495ecec4bb7fc7e210efd8152ec1bed06 Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 7 May 2015 17:43:37 +0200 Subject: [PATCH 7/8] refactor bold underline painting, remove code duplication, use Registry for line height --- .../com/intellij/openapi/editor/impl/EditorImpl.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java index 31860b3d197f..240644d0e7b6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java @@ -2332,8 +2332,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi UIUtil.drawLine(g, end.x, y1, end.x + charWidth - 1, y1); } else if (attributes.getEffectType() == EffectType.BOLD_LINE_UNDERSCORE) { - UIUtil.drawLine(g, end.x, y - 1, end.x + charWidth - 1, y - 1); - UIUtil.drawLine(g, end.x, y, end.x + charWidth - 1, y); + drawBoldLineUnderScore(g, end.x, y - 1, charWidth - 1); } else if (attributes.getEffectType() != EffectType.BOXED) { UIUtil.drawLine(g, end.x, y, end.x + charWidth - 1, y); @@ -2342,6 +2341,11 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } } + private static void drawBoldLineUnderScore(Graphics g, int x, int y, int width) { + int height = JBUI.scale(Registry.intValue("editor.bold.underline.height", 2)); + g.fillRect(x, y, width, height); + } + @Override public int getMaxWidthInRange(int startOffset, int endOffset) { if (myUseNewRendering) return myView.getMaxWidthInRange(startOffset, endOffset); @@ -3423,8 +3427,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi } else if (effectType == EffectType.BOLD_LINE_UNDERSCORE) { g.setColor(effectColor); - UIUtil.drawLine(g, xStart, y, xEnd, y); - UIUtil.drawLine(g, xStart, y + 1, xEnd, y + 1); + drawBoldLineUnderScore(g, xStart, y, xEnd-xStart); g.setColor(savedColor); } else if (effectType == EffectType.STRIKEOUT) { From 01f502fd4403e918df477a3a1c082b918e1f78eb Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Thu, 7 May 2015 17:45:14 +0200 Subject: [PATCH 8/8] call fireContentChanged when set selected item --- .../src/com/intellij/ui/AbstractCollectionComboBoxModel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/platform-api/src/com/intellij/ui/AbstractCollectionComboBoxModel.java b/platform/platform-api/src/com/intellij/ui/AbstractCollectionComboBoxModel.java index c5413ccdf6e0..4eea91dcb2e5 100644 --- a/platform/platform-api/src/com/intellij/ui/AbstractCollectionComboBoxModel.java +++ b/platform/platform-api/src/com/intellij/ui/AbstractCollectionComboBoxModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -45,6 +45,7 @@ public abstract class AbstractCollectionComboBoxModel extends AbstractListMod public void setSelectedItem(@Nullable Object anItem) { //noinspection unchecked mySelection = (T)anItem; + update(); } @Override