diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant index b4ae0799980d..43af3735db31 100644 --- a/build/scripts/dist.gant +++ b/build/scripts/dist.gant @@ -101,7 +101,7 @@ def layoutAll(Map args, String home, String out, Paths _paths = null, buildJps = layouts.layout_core(home, paths.artifacts_core) notifyArtifactBuilt(paths.artifacts_core) if (buildJps) { - layouts.layoutCommunityJps(home, paths.artifacts_jps) + layouts.layoutJps(home, paths.artifacts_jps, args.buildNumber, {}) notifyArtifactBuilt(paths.artifacts_jps) } diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant index 10e21b7c7ee9..ea7d98d24d85 100644 --- a/build/scripts/layouts.gant +++ b/build/scripts/layouts.gant @@ -703,75 +703,76 @@ def layoutAndroid(String androidHome) { } } -def layoutCommunityJps(String home, String target) { - layout(target) { - jar("util.jar") { - module("annotations") - module("util-rt") - module("util") - } - - jar("jps-launcher.jar") { - module("jps-launcher") - } - - jar("jps-model.jar") { - module("jps-model-api") - module("jps-model-impl") - module("jps-model-serialization") - } - jar("jps-builders.jar") { - module("forms_rt") - module("forms-compiler") - module("instrumentation-util") - module("jps-builders") - module("jps-plugin-system") - module("jps-standalone-builder") - module("java-runtime") - } - jar("groovy-jps-plugin.jar") { - module("groovy-jps-plugin") - module("groovy-rt-constants") - } - jar("groovy_rt.jar") { - module("groovy_rt") - } - jar("ui-designer-jps-plugin.jar") { module("ui-designer-jps-plugin") } - - - jar("maven-jps-plugin.jar") { module("maven-jps-plugin") } - fileset(dir: "$home/plugins/maven/maven3-server-impl/lib/maven3/lib") {include(name: "plexus-utils-*.jar")} - - jar("eclipse-jps-plugin.jar") { - module("common-eclipse-util") - module("eclipse-jps-plugin") - } - jar("devkit-jps-plugin.jar") { module("devkit-jps-plugin") } - jar("intellilang-jps-plugin.jar") { module("intellilang-jps-plugin") } - fileset(dir: "$home/lib") { - include(name: "jdom.jar") - include(name: "jna.jar") - include(name: "trove4j.jar") - include(name: "asm4-all.jar") - include(name: "nanoxml-*.jar") - include(name: "protobuf-*.jar") - include(name: "cli-parser-*.jar") - include(name: "log4j.jar") - include(name: "jgoodies-forms.jar") - include(name: "ecj*.jar") - include(name: "jsr166e.jar") - } - fileset(dir: "$home/jps/lib") { - include(name: "optimizedFileManager.jar") - } - dir("test") { - jar("jps-build-test.jar") { - moduleTests("jps-builders") - moduleTests("jps-model-tests") - moduleTests("jps-serialization-tests") +def layoutJps(String home, String targetDir, String buildNumber, Closure additionalJars) { + layout(targetDir) { + zip("standalone-jps-${buildNumber}.zip") { + jar("util.jar") { + module("annotations") + module("util-rt") + module("util") } + + jar("jps-launcher.jar") { + module("jps-launcher") + } + + jar("jps-model.jar") { + module("jps-model-api") + module("jps-model-impl") + module("jps-model-serialization") + } + jar("jps-builders.jar") { + module("forms_rt") + module("forms-compiler") + module("instrumentation-util") + module("jps-builders") + module("jps-plugin-system") + module("jps-standalone-builder") + module("java-runtime") + } + jar("groovy-jps-plugin.jar") { + module("groovy-jps-plugin") + module("groovy-rt-constants") + } + jar("groovy_rt.jar") { + module("groovy_rt") + } + jar("ui-designer-jps-plugin.jar") { module("ui-designer-jps-plugin") } + + + jar("maven-jps-plugin.jar") { module("maven-jps-plugin") } + fileset(dir: "$home/plugins/maven/maven3-server-impl/lib/maven3/lib") {include(name: "plexus-utils-*.jar")} + + jar("eclipse-jps-plugin.jar") { + module("common-eclipse-util") + module("eclipse-jps-plugin") + } + jar("devkit-jps-plugin.jar") { module("devkit-jps-plugin") } + jar("intellilang-jps-plugin.jar") { module("intellilang-jps-plugin") } + fileset(dir: "$home/lib") { + include(name: "jdom.jar") + include(name: "jna.jar") + include(name: "trove4j.jar") + include(name: "asm4-all.jar") + include(name: "nanoxml-*.jar") + include(name: "protobuf-*.jar") + include(name: "cli-parser-*.jar") + include(name: "log4j.jar") + include(name: "jgoodies-forms.jar") + include(name: "ecj*.jar") + include(name: "jsr166e.jar") + } + fileset(dir: "$home/jps/lib") { + include(name: "optimizedFileManager.jar") + } + jar("ant-jps-plugin.jar") { module("ant-jps-plugin") } + additionalJars() + } + jar("jps-build-test-${buildNumber}.jar") { + moduleTests("jps-builders") + moduleTests("jps-model-tests") + moduleTests("jps-serialization-tests") } - jar("ant-jps-plugin.jar") { module("ant-jps-plugin") } } } diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java index 52bcf8acce32..e17b8af10827 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/FramesPanel.java @@ -17,6 +17,7 @@ package com.intellij.debugger.ui; import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerInvocationUtil; +import com.intellij.debugger.SourcePosition; import com.intellij.debugger.actions.DebuggerActions; import com.intellij.debugger.engine.DebugProcessImpl; import com.intellij.debugger.engine.DebuggerManagerThreadImpl; @@ -59,7 +60,9 @@ import com.intellij.ui.components.panels.Wrapper; import com.intellij.util.Alarm; import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.VMDisconnectedException; +import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -76,7 +79,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; -public class FramesPanel extends UpdatableDebuggerView { +public class FramesPanel extends UpdatableDebuggerView implements DataProvider { private static final Icon FILTER_STACK_FRAMES_ICON = AllIcons.Debugger.Class_filter; private final JComboBox myThreadsCombo; @@ -147,6 +150,21 @@ public class FramesPanel extends UpdatableDebuggerView { return myStateManager; } + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (CommonDataKeys.PSI_FILE.is(dataId)) { + DebuggerContextImpl context = myStateManager.getContext(); + if (context != null) { + SourcePosition position = context.getSourcePosition(); + if (position != null) { + return position.getFile(); + } + } + } + return null; + } + private class FramesListener implements ListSelectionListener { boolean myIsEnabled = true; diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java index 72ad0f26efa1..77a928abfb6b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/GenericsHighlightUtil.java @@ -358,8 +358,8 @@ public class GenericsHighlightUtil { if (inheritedSubstitutor != null) { final PsiTypeParameter[] typeParameters = superClass.getTypeParameters(); for (PsiTypeParameter typeParameter : typeParameters) { - PsiType type1 = GenericsUtil.eliminateWildcards(inheritedSubstitutor.substitute(typeParameter)); - PsiType type2 = GenericsUtil.eliminateWildcards(superTypeSubstitutor.substitute(typeParameter)); + PsiType type1 = inheritedSubstitutor.substitute(typeParameter); + PsiType type2 = superTypeSubstitutor.substitute(typeParameter); if (!Comparing.equal(type1, type2)) { String description = JavaErrorMessages.message("generics.cannot.be.inherited.with.different.type.arguments", diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index c9649a026fbb..1225fe6cbe2a 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -48,7 +48,6 @@ import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.RefactoringBundle; import com.intellij.refactoring.introduceParameter.Util; import com.intellij.refactoring.listeners.RefactoringEventData; -import com.intellij.refactoring.listeners.RefactoringEventListener; import com.intellij.refactoring.rename.NonCodeUsageInfoFactory; import com.intellij.refactoring.rename.RenameJavaVariableProcessor; import com.intellij.refactoring.util.*; @@ -1265,7 +1264,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { if (parentStatement != null) { PsiElement parent = ref.getParent(); while (!parent.equals(parentStatement)) { - if (parent instanceof PsiStatement && !(parent instanceof PsiDeclarationStatement)) { + if (parent instanceof PsiExpressionStatement) { String text = "{\n}"; PsiBlockStatement blockStatement = (PsiBlockStatement)myFactory.createStatementFromText(text, null); blockStatement = (PsiBlockStatement)myCodeStyleManager.reformat(blockStatement); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/cache/TypeInfo.java b/java/java-psi-impl/src/com/intellij/psi/impl/cache/TypeInfo.java index 41a6d35c3e0c..9a078bbc9573 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/cache/TypeInfo.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/cache/TypeInfo.java @@ -33,7 +33,7 @@ import com.intellij.psi.stubs.StubElement; import com.intellij.psi.stubs.StubInputStream; import com.intellij.psi.stubs.StubOutputStream; import com.intellij.psi.tree.IElementType; -import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.SmartList; import com.intellij.util.io.StringRef; import gnu.trove.TObjectIntHashMap; import org.jetbrains.annotations.NotNull; @@ -81,19 +81,19 @@ public class TypeInfo { private static final int HAS_ARRAY_COUNT = 0x40; private static final int HAS_ELLIPSIS = 0x80; - private static final TypeInfo NULL = new TypeInfo((StringRef)null, (byte)0, false, ContainerUtil.emptyList()); + private static final TypeInfo NULL = new TypeInfo((StringRef)null, (byte)0, false, PsiAnnotationStub.EMPTY_ARRAY); public final StringRef text; public final byte arrayCount; public final boolean isEllipsis; - private final List myAnnotationStubs; + private final PsiAnnotationStub[] myAnnotationStubs; - public TypeInfo(String text, byte arrayCount, boolean ellipsis, @NotNull List annotationStubs) { + public TypeInfo(String text, byte arrayCount, boolean ellipsis, @NotNull PsiAnnotationStub[] annotationStubs) { this(StringRef.fromString(text == null ? null : internFrequentType(text)), arrayCount, ellipsis, annotationStubs); } - private TypeInfo(StringRef text, byte arrayCount, boolean isEllipsis, @NotNull List annotationStubs) { + private TypeInfo(StringRef text, byte arrayCount, boolean isEllipsis, @NotNull PsiAnnotationStub[] annotationStubs) { this.text = text; this.arrayCount = arrayCount; this.isEllipsis = isEllipsis; @@ -105,15 +105,19 @@ public class TypeInfo { PsiModifierListStub modifierList = (PsiModifierListStub)owner.findChildStubByType(JavaStubElementTypes.MODIFIER_LIST); if (modifierList == null) return this; - List annotationStubs = ContainerUtil.newArrayList(); + List annotationStubs = null; for (StubElement child : modifierList.getChildrenStubs()) { if (!(child instanceof PsiAnnotationStub)) continue; PsiAnnotationStub annotationStub = (PsiAnnotationStub)child; if (PsiImplUtil.isTypeAnnotation(annotationStub.getPsiElement())) { + if (annotationStubs == null) annotationStubs = new SmartList(); annotationStubs.add(annotationStub); } } - return new TypeInfo(text, arrayCount, isEllipsis, annotationStubs); + + PsiAnnotationStub[] stubArray = PsiAnnotationStub.EMPTY_ARRAY; + if (annotationStubs != null) stubArray = annotationStubs.toArray(new PsiAnnotationStub[annotationStubs.size()]); + return new TypeInfo(text, arrayCount, isEllipsis, stubArray); } @NotNull @@ -185,7 +189,7 @@ public class TypeInfo { text = LightTreeUtil.toFilteredString(tree, typeElement, null); } - return new TypeInfo(text, arrayCount, isEllipsis, ContainerUtil.emptyList()); + return new TypeInfo(text, arrayCount, isEllipsis, PsiAnnotationStub.EMPTY_ARRAY); } @NotNull @@ -198,7 +202,7 @@ public class TypeInfo { typeText = typeText.substring(0, typeText.length() - 2); } - return new TypeInfo(typeText, arrayCount, isEllipsis, ContainerUtil.emptyList()); + return new TypeInfo(typeText, arrayCount, isEllipsis, PsiAnnotationStub.EMPTY_ARRAY); } @NotNull @@ -225,7 +229,7 @@ public class TypeInfo { StringRef text = frequentIndex == 0 ? record.readName() : StringRef.fromString(ourIndexFrequentType[frequentIndex]); - return new TypeInfo(text, arrayCount, hasEllipsis, ContainerUtil.emptyList()); + return new TypeInfo(text, arrayCount, hasEllipsis, PsiAnnotationStub.EMPTY_ARRAY); } public static void writeTYPE(@NotNull StubOutputStream dataStream, @NotNull TypeInfo typeInfo) throws IOException { @@ -254,7 +258,7 @@ public class TypeInfo { if (typeInfo == NULL || typeInfo.text == null) { return null; } - if (typeInfo.arrayCount == 0 && typeInfo.myAnnotationStubs.isEmpty()) { + if (typeInfo.arrayCount == 0 && typeInfo.myAnnotationStubs.length == 0) { return typeInfo.text.getString(); } 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 3878101a4436..37a1eb60ca3d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -37,7 +37,6 @@ import java.lang.reflect.Array; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.regex.Pattern; @@ -387,7 +386,7 @@ public class StubBuildingVisitor extends ClassVisitor { if (dim > 0) { type = type.getElementType(); } - return new TypeInfo(getTypeText(type), (byte)dim, false, Collections.emptyList()); //todo read annos from .class file + return new TypeInfo(getTypeText(type), (byte)dim, false, PsiAnnotationStub.EMPTY_ARRAY); //todo read annos from .class file } private static final String[] parameterNames = {"p1", "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9"}; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiAnnotationStub.java b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiAnnotationStub.java index 424ff045a118..27e3f0bdd9c3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiAnnotationStub.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/java/stubs/PsiAnnotationStub.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,8 @@ import com.intellij.psi.stubs.StubElement; * @author max */ public interface PsiAnnotationStub extends StubElement { + PsiAnnotationStub[] EMPTY_ARRAY = new PsiAnnotationStub[0]; + String getText(); PsiAnnotation getPsiElement(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java index 847d7f313141..b046de964cdf 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaDocElementType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -33,22 +33,24 @@ import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.reflect.ConstructorAccessor; import java.lang.reflect.Constructor; public interface JavaDocElementType { class JavaDocCompositeElementType extends IJavaDocElementType implements ICompositeElementType { - private final Constructor myConstructor; + private final ConstructorAccessor myConstructor; private JavaDocCompositeElementType(@NonNls final String debugName, final Class nodeClass) { super(debugName); - myConstructor = ReflectionUtil.getDefaultConstructor(nodeClass); + Constructor constructor = ReflectionUtil.getDefaultConstructor(nodeClass); + myConstructor = ReflectionUtil.getConstructorAccessor(constructor); } @NotNull @Override public ASTNode createCompositeNode() { - return ReflectionUtil.createInstance(myConstructor); + return ReflectionUtil.createInstanceViaConstructorAccessor(myConstructor); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java index 14bc9b457614..4fbbad26964d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaElementType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -35,12 +35,13 @@ import com.intellij.util.diff.FlyweightCapableTreeStructure; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.reflect.ConstructorAccessor; import java.lang.reflect.Constructor; public interface JavaElementType { class JavaCompositeElementType extends IJavaElementType implements ICompositeElementType { - private final Constructor myConstructor; + private final ConstructorAccessor myConstructor; private JavaCompositeElementType(@NonNls final String debugName, final Class nodeClass) { this(debugName, nodeClass, false); @@ -48,13 +49,14 @@ public interface JavaElementType { private JavaCompositeElementType(@NonNls final String debugName, final Class nodeClass, final boolean leftBound) { super(debugName, leftBound); - myConstructor = ReflectionUtil.getDefaultConstructor(nodeClass); + Constructor constructor = ReflectionUtil.getDefaultConstructor(nodeClass); + myConstructor = ReflectionUtil.getConstructorAccessor(constructor); } @NotNull @Override public ASTNode createCompositeNode() { - return ReflectionUtil.createInstance(myConstructor); + return ReflectionUtil.createInstanceViaConstructorAccessor(myConstructor); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousInheritance/pck/AmbiguousMethodCall.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousInheritance/pck/AmbiguousMethodCall.java index 580a30a72403..5eab22e56d86 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousInheritance/pck/AmbiguousMethodCall.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/ambiguousInheritance/pck/AmbiguousMethodCall.java @@ -7,7 +7,7 @@ interface A interface B extends A { } -class C & B> +class C & B> { void foo(T x) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams.java index 2adff2f8f495..180b75572c6e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams.java @@ -18,7 +18,7 @@ interface IA2 {} interface IB2 extends IA2 {} class A2 { - & IB2> void foo(){} + & IB2> void foo(){} } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams1.java new file mode 100644 index 000000000000..f7fda29752d4 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/InheritedWithDifferentArgsInTypeParams1.java @@ -0,0 +1,10 @@ +import java.util.List; + +interface Base { +} + +interface Middle extends Base> { +} + +interface Child extends Middle, Base> { +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java index 2adff2f8f495..a1c0d83bc64a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/InheritedWithDifferentArgsInTypeParams.java @@ -18,7 +18,7 @@ interface IA2 {} interface IB2 extends IA2 {} class A2 { - & IB2> void foo(){} + <T extends IA2 & IB2> void foo(){} } diff --git a/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java b/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java new file mode 100644 index 000000000000..1df5d47a74ab --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java @@ -0,0 +1,26 @@ +import java.util.ArrayList; +import java.util.List; + +class Test { + List foo(String[] strs) + { + final List result = new ArrayList(); + int start = -1; + for (int i = 0; i < strs.length; i++) + { + if (idx(i) == 42 && start == -1) + { + start = i; + } else if (idx(i) != 24 && start != -1) + { + result.add("".substring(idx(start))); + } + } + return result; + } + + private static int idx(int i) { + return i; + } + +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java.after b/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java.after new file mode 100644 index 000000000000..e43e7e849a44 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/MethodInsideChangeIfStatement.java.after @@ -0,0 +1,22 @@ +import java.util.ArrayList; +import java.util.List; + +class Test { + List foo(String[] strs) + { + final List result = new ArrayList(); + int start = -1; + for (int i = 0; i < strs.length; i++) + { + if (i == 42 && start == -1) + { + start = i; + } else if (i != 24 && start != -1) + { + result.add("".substring(start)); + } + } + return result; + } + +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index 9b8861a5a01c..529065446905 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -238,6 +238,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { public void testIDEA106964() throws Exception { doTest5(false);} public void testIDEA107782() throws Exception { doTest5(false);} public void testInheritedWithDifferentArgsInTypeParams() throws Exception { doTest5(false);} + public void testInheritedWithDifferentArgsInTypeParams1() throws Exception { doTest5(false);} public void testIllegalForwardReferenceInTypeParameterDefinition() throws Exception { doTest5(false);} public void testIDEA57877() throws Exception { doTest5(false);} diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java index ec5ab9e53e96..c77b344f6722 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineMethodTest.java @@ -260,6 +260,10 @@ public class InlineMethodTest extends LightRefactoringTestCase { doTest(true); } + public void testMethodInsideChangeIfStatement() throws Exception { + doTest(); + } + private void doTestInlineThisOnly() { @NonNls String fileName = "/refactoring/inlineMethod/" + getTestName(false) + ".java"; configureByFile(fileName); diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java index 497790713243..c972c6bb38b0 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java @@ -16,7 +16,6 @@ package com.intellij.application.options.codeStyle.arrangement.match; import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; import com.intellij.application.options.codeStyle.arrangement.ui.ArrangementEditorAware; import com.intellij.application.options.codeStyle.arrangement.ui.ArrangementRepresentationAware; @@ -28,8 +27,10 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; import com.intellij.psi.codeStyle.arrangement.std.ArrangementUiComponent; import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens; +import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.table.JBTable; import com.intellij.util.ui.AbstractTableCellEditor; import gnu.trove.TIntArrayList; @@ -349,10 +350,10 @@ public class ArrangementMatchingRulesControl extends JBTable { } myEditorRow = rowToEdit + 1; ArrangementEditorComponent editor = new ArrangementEditorComponent(this, myEditorRow, myEditor); - Container parent = getParent(); int width = getBounds().width; - if (parent instanceof JViewport) { - width -= ((JScrollPane)parent.getParent()).getVerticalScrollBar().getWidth(); + JScrollPane scrollPane = JBScrollPane.findScrollPane(getParent()); + if (scrollPane != null) { + width -= scrollPane.getVerticalScrollBar().getWidth(); } editor.applyAvailableWidth(width); myEditor.reset(rowToEdit); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java index 14d471e082fc..0b638cde5891 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/lookup/impl/CompletionExtender.java @@ -16,6 +16,7 @@ package com.intellij.codeInsight.lookup.impl; import com.intellij.ui.ListExpandableItemsHandler; +import com.intellij.ui.components.JBScrollPane; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -31,9 +32,10 @@ public class CompletionExtender extends ListExpandableItemsHandler { list.addComponentListener(new ComponentAdapter() { @Override public void componentShown(ComponentEvent e) { - if (myComponent.getParent() != null && myComponent.getParent().getParent() instanceof JScrollPane) { - final JScrollBar verticalScrollBar = ((JScrollPane)myComponent.getParent().getParent()).getVerticalScrollBar(); - final JScrollBar horizontalScrollBar = ((JScrollPane)myComponent.getParent().getParent()).getVerticalScrollBar(); + JScrollPane scrollPane = JBScrollPane.findScrollPane(myComponent); + if (scrollPane != null) { + final JScrollBar verticalScrollBar = scrollPane.getVerticalScrollBar(); + final JScrollBar horizontalScrollBar = scrollPane.getVerticalScrollBar(); final AdjustmentListener listener = new AdjustmentListener() { @Override public void adjustmentValueChanged(AdjustmentEvent e) { diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java index 0d3c52e41ff8..165e2be8b320 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java @@ -362,11 +362,11 @@ public class TemplateState implements Disposable { mySegments.addSegment(segmentOffset, segmentOffset); } - LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString()); + LOG.assertTrue(myTemplateRange.isValid(), getRangesDebugInfo()); calcResults(false); - LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString()); + LOG.assertTrue(myTemplateRange.isValid(), getRangesDebugInfo()); calcResults(false); //Fixed SCR #[vk500] : all variables should be recalced twice on start. - LOG.assertTrue(myTemplateRange.isValid(), myTemplateRange.toString()); + LOG.assertTrue(myTemplateRange.isValid(), getRangesDebugInfo()); doReformat(null); int nextVariableNumber = getNextVariableNumber(-1); @@ -392,6 +392,16 @@ public class TemplateState implements Disposable { }); } + private String getRangesDebugInfo() { + return myTemplateRange.toString() + + "\ntemplateKey: " + + myTemplate.getKey() + + "\ntemplateText: " + + myTemplate.getTemplateText() + + "\ntemplateString: " + + myTemplate.getString(); + } + private void doReformat(final TextRange range) { RangeMarker rangeMarker = null; if (range != null) { diff --git a/platform/lang-impl/src/com/intellij/execution/console/BasicGutterContentProvider.java b/platform/lang-impl/src/com/intellij/execution/console/BasicGutterContentProvider.java new file mode 100644 index 000000000000..ec146652aae8 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/execution/console/BasicGutterContentProvider.java @@ -0,0 +1,77 @@ +package com.intellij.execution.console; + +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.JBColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +public class BasicGutterContentProvider extends GutterContentProvider { + public static final String EVAL_OUT_MARKER = "\u200C"; + public static final String EVAL_IN_MARKER = EVAL_OUT_MARKER + EVAL_OUT_MARKER; + + @Override + public boolean hasText() { + return false; + } + + @Nullable + @Override + public String getText(int line, @NotNull Editor editor) { + return null; + } + + @Nullable + @Override + public String getToolTip(int line, @NotNull Editor editor) { + return null; + } + + @Override + public void doAction(int line, @NotNull Editor editor) { + } + + @Override + public void beforeEvaluate(@NotNull Editor editor) { + Document document = editor.getDocument(); + document.insertString(document.getTextLength(), EVAL_IN_MARKER); + } + + @Override + public boolean drawIcon(int line, @NotNull Graphics g, int y, @NotNull Editor editor) { + int markerCount = getMarkerCount(line, editor.getDocument()); + if (markerCount == EVAL_OUT_MARKER.length() || markerCount == EVAL_IN_MARKER.length()) { + g.setColor(JBColor.GRAY); + g.drawString(markerCount == EVAL_IN_MARKER.length() ? ">" : "<", 3, y); + return true; + } + return false; + } + + @Override + public final boolean isShowSeparatorLine(int line, @NotNull Editor editor) { + Document document = editor.getDocument(); + if ((line + 1) >= document.getLineCount()) { + return true; + } + + int markerCount = getMarkerCount(line, document); + if (markerCount == EVAL_IN_MARKER.length()) { + return getMarkerCount(line + 1, document) != EVAL_OUT_MARKER.length(); + } + else { + return doIsShowSeparatorLine(line, editor, document); + } + } + + protected boolean doIsShowSeparatorLine(int line, @NotNull Editor editor, @NotNull Document document) { + return true; + } + + private static int getMarkerCount(int line, @NotNull Document document) { + return StringUtil.countChars(document.getImmutableCharSequence(), EVAL_IN_MARKER.charAt(0), document.getLineStartOffset(line), true); + } +} \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java b/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java index c2eed1a09cd3..d0a4691c3d9f 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java +++ b/platform/lang-impl/src/com/intellij/execution/console/GutterContentProvider.java @@ -28,7 +28,7 @@ public abstract class GutterContentProvider { public abstract void doAction(int line, @NotNull Editor editor); - public abstract void drawIcon(int line, @NotNull Graphics g, int y, @NotNull Editor editor); + public abstract boolean drawIcon(int line, @NotNull Graphics g, int y, @NotNull Editor editor); public boolean isShowSeparatorLine(int line, @NotNull Editor editor) { return true; diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java index 9bbd5b53fd50..185379c60f92 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java @@ -179,7 +179,6 @@ public final class LanguageConsoleBuilder { } private final static class GutteredLanguageConsole extends LanguageConsoleImpl { - @Nullable private final GutterContentProvider gutterContentProvider; @Nullable private final PairFunction psiFileFactory; @@ -193,13 +192,13 @@ public final class LanguageConsoleBuilder { setShowSeparatorLine(false); - this.gutterContentProvider = gutterContentProvider; + this.gutterContentProvider = gutterContentProvider == null ? new BasicGutterContentProvider() : gutterContentProvider; this.psiFileFactory = psiFileFactory; } @Override boolean isHistoryViewerForceAdditionalColumnsUsage() { - return gutterContentProvider == null; + return false; } @Override @@ -222,7 +221,7 @@ public final class LanguageConsoleBuilder { protected void setupEditorDefault(@NotNull EditorEx editor) { super.setupEditorDefault(editor); - if (editor == getConsoleEditor() || gutterContentProvider == null) { + if (editor == getConsoleEditor()) { return; } @@ -283,12 +282,7 @@ public final class LanguageConsoleBuilder { @Override protected void doAddPromptToHistory() { - if (gutterContentProvider == null) { - super.doAddPromptToHistory(); - } - else { - gutterContentProvider.beforeEvaluate(getHistoryViewer()); - } + gutterContentProvider.beforeEvaluate(getHistoryViewer()); } private final class GutterUpdateScheduler extends DocumentAdapter implements DocumentBulkUpdateListener { @@ -350,10 +344,7 @@ public final class LanguageConsoleBuilder { private void documentCleared() { gutterSizeUpdater = null; - lineEndGutter.documentCleared(); - - assert gutterContentProvider != null; gutterContentProvider.documentCleared(getHistoryViewer()); } @@ -419,7 +410,6 @@ public final class LanguageConsoleBuilder { int actualStartLine = startLine == 0 ? 0 : startLine - 1; int y = (actualStartLine + 1) * lineHeight; g.setColor(editor.getColorsScheme().getColor(EditorColors.INDENT_GUIDE_COLOR)); - assert gutterContentProvider != null; for (int visualLine = actualStartLine; visualLine < endLine; visualLine++) { if (gutterContentProvider.isShowSeparatorLine(editor.visualToLogicalPosition(new VisualPosition(visualLine, 0)).line, editor)) { g.drawLine(0, y, clip.width, y); diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java index c15e00acfbf3..bb646a81ee46 100644 --- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java +++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java @@ -583,6 +583,9 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider { public void queueUiUpdate(boolean forceScrollToEnd) { myForceScrollToEnd.compareAndSet(false, forceScrollToEnd); + if (myUpdateQueue.isDisposed()) { + return; + } myUpdateQueue.request(); } diff --git a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java index acd4a017fc1a..7a52248840ad 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java @@ -69,8 +69,6 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc protected void initComponents() { myProgramParametersComponent = LabeledComponent.create(new RawCommandLineEditor(), ExecutionBundle.message("run.configuration.program.parameters")); - - final JPanel panel = new JPanel(new BorderLayout()); myWorkingDirectoryField = new TextFieldWithBrowseButton(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -91,6 +89,8 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc super.installPathCompletion(FileChooserDescriptorFactory.createSingleFolderDescriptor()); } }; + + final JPanel panel = new JPanel(new BorderLayout()); panel.add(myWorkingDirectoryField, BorderLayout.CENTER); final FixedSizeButton button = new FixedSizeButton(myWorkingDirectoryField); @@ -171,7 +171,7 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc @Override public void setAnchor(JComponent anchor) { - this.myAnchor = anchor; + myAnchor = anchor; myProgramParametersComponent.setAnchor(anchor); myWorkingDirectoryComponent.setAnchor(anchor); myEnvVariablesComponent.setAnchor(anchor); diff --git a/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java b/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java index 0cd5d1677bcb..af2ea11eaea4 100644 --- a/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java +++ b/platform/lang-impl/src/com/intellij/execution/util/ProgramParametersConfigurator.java @@ -56,12 +56,12 @@ public class ProgramParametersConfigurator { public String getWorkingDir(CommonProgramRunConfigurationParameters configuration, Project project, Module module) { String workingDirectory = configuration.getWorkingDirectory(); String defaultWorkingDir = getDefaultWorkingDir(project); - - if (workingDirectory == null || workingDirectory.trim().length() == 0) { + if (StringUtil.isEmptyOrSpaces(workingDirectory)) { workingDirectory = defaultWorkingDir; + if (workingDirectory == null) { + return null; + } } - if (workingDirectory == null) - return null; workingDirectory = expandPath(workingDirectory, module, project); if (!FileUtil.isAbsolute(workingDirectory) && defaultWorkingDir != null) { if (("$" + PathMacroUtil.MODULE_DIR_MACRO_NAME + "$").equals(workingDirectory)) { diff --git a/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java index 9a29e09d0a92..fbe0d3070009 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/RangeMarkerWindow.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -157,4 +157,11 @@ public class RangeMarkerWindow implements RangeMarkerEx { public void dispose() { myHostMarker.dispose(); } + + @Override + public String toString() { + return "RangeMarkerWindow" + (isGreedyToLeft() ? "[" : "(") + (isValid() ? "valid" : "invalid") + "," + + getStartOffset() + "," + getEndOffset() + + (isGreedyToRight() ? "]" : ")") + " " + getId(); + } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java index e35eb60018d9..be946e68c7eb 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java @@ -1317,7 +1317,9 @@ public class Messages { setButtonsAlignment(SwingConstants.CENTER); setDoNotAskOption(doNotAskOption); init(); - MacUtil.adjustFocusTraversal(myDisposable); + if (isMacSheetEmulation()) { + MacUtil.adjustFocusTraversal(myDisposable); + } } @NotNull diff --git a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java index 4311a6e4f909..72c85333b773 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBScrollPane.java @@ -60,6 +60,23 @@ public class JBScrollPane extends JScrollPane { init(); } + public static JScrollPane findScrollPane(Component c) { + if (c == null) return null; + + if (!(c instanceof JViewport)) { + c = c.getParent(); + if (!(c instanceof JViewport)) return null; + } + + c = c.getParent(); + if (c instanceof JLayeredPane) { + c = c.getParent(); + } + if (!(c instanceof JBScrollPane)) return null; + + return (JBScrollPane)c; + } + @Override public void setVerticalScrollBar(JScrollBar c) { JScrollBar old = getVerticalScrollBar(); diff --git a/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java b/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java index 17d754de1470..998c51ee825f 100644 --- a/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java +++ b/platform/platform-api/src/com/intellij/ui/components/ZoomingDelegate.java @@ -86,8 +86,7 @@ public class ZoomingDelegate { } protected void scrollTo(int voffset, int hoffset) { - JViewport viewport = (JViewport)myViewportComponent; - JScrollPane pane = (JScrollPane)viewport.getParent(); + JScrollPane pane = JBScrollPane.findScrollPane(myViewportComponent); JScrollBar vsb = pane.getVerticalScrollBar(); vsb.setValue(voffset); JScrollBar hsb = pane.getHorizontalScrollBar(); diff --git a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java index 7433fa66eef7..7c740c9821cb 100644 --- a/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java +++ b/platform/platform-api/src/com/intellij/util/ui/ButtonlessScrollBarUI.java @@ -62,7 +62,9 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { private final AdjustmentListener myAdjustmentListener; private final MouseMotionAdapter myMouseMotionListener; private final MouseAdapter myMouseListener; - private final AWTEventListener myAWTListener; + private final HierarchyListener myHierarchyListener; + private final AWTEventListener myAWTMouseListener; + private boolean myAWTMouseListenerAdded; public static final int DELAY_FRAMES = 4; public static final int FRAMES_COUNT = 10 + DELAY_FRAMES; @@ -126,19 +128,33 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { } }; - myAWTListener = new AWTEventListener() { + myHierarchyListener = new HierarchyListener() { @Override + public void hierarchyChanged(HierarchyEvent e) { + if (e.getChanged() == scrollbar + && (HierarchyEvent.DISPLAYABILITY_CHANGED & e.getChangeFlags()) != 0) { + updateAWTMotionListener(false); + } + } + }; + myAWTMouseListener = new AWTEventListener() { public void eventDispatched(AWTEvent event) { if (event.getID() == MouseEvent.MOUSE_MOVED) { - // user is moving mouse outside of the scrollbar and fade-out hasn't started yet - if (!myMouseOverScrollbar && !myMacScrollbarHidden && myMacScrollbarFadeLevel == 0) { - resetMacScrollbarFadeout(); + + // user is moving inside the scrollpane of the scrollbar and fade-out hasn't started yet + Container scrollpane = SwingUtilities.getAncestorOfClass(JScrollPane.class, scrollbar); + if (scrollpane != null) { + Point loc = ((MouseEvent)event).getLocationOnScreen(); + SwingUtilities.convertPointFromScreen(loc, scrollpane); + if (scrollpane.contains(loc) && !myMacScrollbarHidden && myMacScrollbarFadeLevel == 0) { + resetMacScrollbarFadeout(); + } } } } }; } - + protected static boolean isMacScrollbar() { return UIUtil.isUnderNativeMacLookAndFeel() && !Registry.is("ui.no.mac.scrollbar"); } @@ -252,11 +268,27 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { scrollbar.addAdjustmentListener(myAdjustmentListener); scrollbar.addMouseListener(myMouseListener); scrollbar.addMouseMotionListener(myMouseMotionListener); - //Toolkit.getDefaultToolkit().addAWTEventListener(myAWTListener, AWTEvent.MOUSE_MOTION_EVENT_MASK); - + + scrollbar.addHierarchyListener(myHierarchyListener); + updateAWTMotionListener(false); + resetMacScrollbarFadeout(); } + private void updateAWTMotionListener(boolean forceRemove) { + boolean shouldAdd = scrollbar.isDisplayable(); + + if (myAWTMouseListenerAdded && (!shouldAdd || forceRemove)) { + Toolkit.getDefaultToolkit().removeAWTEventListener(myAWTMouseListener); + myAWTMouseListenerAdded = false; + } + + if (!myAWTMouseListenerAdded && shouldAdd && !forceRemove) { + Toolkit.getDefaultToolkit().addAWTEventListener(myAWTMouseListener, AWTEvent.MOUSE_MOTION_EVENT_MASK); + myAWTMouseListenerAdded = true; + } + } + private void initRegularThumbAnimator() { myThumbFadeAnimator = new Animator("Regular scrollbar thumb animator", FRAMES_COUNT, FRAMES_COUNT * 50, false) { @Override @@ -333,6 +365,13 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { super.uninstallListeners(); } + scrollbar.removeAdjustmentListener(myAdjustmentListener); + scrollbar.removeMouseListener(myMouseListener); + scrollbar.removeMouseMotionListener(myMouseMotionListener); + + scrollbar.removeHierarchyListener(myHierarchyListener); + updateAWTMotionListener(true); + Disposer.dispose(myThumbFadeAnimator); myThumbFadeAnimator = null; @@ -340,11 +379,6 @@ public class ButtonlessScrollBarUI extends BasicScrollBarUI { myMouseOverScrollbarExpandAnimator = null; Disposer.dispose(myMacScrollbarFadeAnimator); myMacScrollbarFadeAnimator = null; - - scrollbar.removeAdjustmentListener(myAdjustmentListener); - scrollbar.removeMouseListener(myMouseListener); - scrollbar.removeMouseMotionListener(myMouseMotionListener); - //Toolkit.getDefaultToolkit().removeAWTEventListener(myAWTListener); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/IgnoredFileCache.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/IgnoredFileCache.java index d55dbc73a453..8663cbe6b769 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/IgnoredFileCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/IgnoredFileCache.java @@ -22,24 +22,24 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.NewVirtualFile; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; import com.intellij.openapi.vfs.newvfs.events.VFilePropertyChangeEvent; -import com.intellij.util.containers.IntArrayList; +import com.intellij.util.containers.ConcurrentBitSet; +import com.intellij.util.containers.ConcurrentIntObjectMap; +import com.intellij.util.containers.StripedLockIntObjectConcurrentHashMap; import com.intellij.util.messages.MessageBusConnection; -import gnu.trove.TIntHashSet; import org.jetbrains.annotations.NotNull; -import java.util.BitSet; import java.util.List; /** * @author peter */ class IgnoredFileCache { - private final BitSet myCheckedIds = new BitSet(); - private final TIntHashSet myIgnoredIds = new TIntHashSet(); + private final ConcurrentBitSet myCheckedIds = new ConcurrentBitSet(); + private final ConcurrentIntObjectMap myIgnoredIds = new StripedLockIntObjectConcurrentHashMap(); private final IgnoredPatternSet myIgnoredPatterns; - private int myVfsEventNesting = 0; + private volatile int myVfsEventNesting = 0; - IgnoredFileCache(IgnoredPatternSet ignoredPatterns) { + IgnoredFileCache(@NotNull IgnoredPatternSet ignoredPatterns) { myIgnoredPatterns = ignoredPatterns; MessageBusConnection connect = ApplicationManager.getApplication().getMessageBus().connect(); connect.subscribe(VirtualFileManager.VFS_CHANGES, new BulkFileListener() { @@ -56,43 +56,27 @@ class IgnoredFileCache { myVfsEventNesting--; } - private void clearCacheForChangedFiles(List events) { - final IntArrayList ids = collectChangedIds(events); - synchronized (myCheckedIds) { - for (int i : ids.toArray()) { - myCheckedIds.clear(i); - } - } - } - - private IntArrayList collectChangedIds(List events) { - final IntArrayList ids = new IntArrayList(); + private void clearCacheForChangedFiles(@NotNull List events) { for (final VFileEvent event : events) { VirtualFile file = event.getFile(); - if (!(file instanceof NewVirtualFile)) { - continue; - } - - if (event instanceof VFilePropertyChangeEvent) { + if (file instanceof NewVirtualFile && event instanceof VFilePropertyChangeEvent) { int id = ((NewVirtualFile)file).getId(); if (id >= 0) { - ids.add(id); + myCheckedIds.clear(id); + myIgnoredIds.remove(id); } } } - return ids; } }); } void clearCache() { - synchronized (myCheckedIds) { - myCheckedIds.clear(); - myIgnoredIds.clear(); - } + myCheckedIds.clear(); + myIgnoredIds.clear(); } - boolean isFileIgnored(VirtualFile file) { + boolean isFileIgnored(@NotNull VirtualFile file) { if (myVfsEventNesting != 0 || !(file instanceof NewVirtualFile)) { return isFileIgnoredNoCache(file); } @@ -102,25 +86,23 @@ class IgnoredFileCache { return isFileIgnoredNoCache(file); } - synchronized (myCheckedIds) { - if (myCheckedIds.get(id)) { - return myIgnoredIds.contains(id); - } + ConcurrentBitSet checkedIds = myCheckedIds; + if (checkedIds.get(id)) { + return myIgnoredIds.containsKey(id); } boolean result = isFileIgnoredNoCache(file); - synchronized (myCheckedIds) { - myCheckedIds.set(id); - if (result) { - myIgnoredIds.add(id); - } else { - myIgnoredIds.remove(id); - } + if (result) { + myIgnoredIds.put(id, Boolean.TRUE); } + else { + myIgnoredIds.remove(id); + } + checkedIds.set(id); return result; } - private boolean isFileIgnoredNoCache(VirtualFile file) { + private boolean isFileIgnoredNoCache(@NotNull VirtualFile file) { return myIgnoredPatterns.isIgnored(file.getName()); } } diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java index 3f2c4abebf7f..a16886740be6 100644 --- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java +++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/FileNameCache.java @@ -55,8 +55,9 @@ public class FileNameCache { Object rawName = convertToBytesIfAsciiString(name); IntObjectLinkedMap.MapEntry entry = new IntObjectLinkedMap.MapEntry(id, rawName); - synchronized (ourNameCache[stripe]) { - return ourNameCache[stripe].cacheEntry(entry); + IntSLRUCache> cache = ourNameCache[stripe]; + synchronized (cache) { + return cache.cacheEntry(entry); } } @@ -91,8 +92,9 @@ public class FileNameCache { @NotNull private static IntObjectLinkedMap.MapEntry getEntry(int id) { final int stripe = calcStripeIdFromNameId(id); - synchronized (ourNameCache[stripe]) { - IntObjectLinkedMap.MapEntry entry = ourNameCache[stripe].getCachedEntry(id); + IntSLRUCache> cache = ourNameCache[stripe]; + synchronized (cache) { + IntObjectLinkedMap.MapEntry entry = cache.getCachedEntry(id); if (entry != null) { return entry; } diff --git a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java index 1277d6df7ced..486f88b00945 100644 --- a/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java +++ b/platform/platform-impl/src/com/intellij/ui/BalloonImpl.java @@ -502,7 +502,7 @@ public class BalloonImpl implements Balloon, IdeTooltip.Ui { myLayeredPane.remove(myComp); createComponent(); - if (!new Rectangle(myComp.getSize()).contains(new Rectangle(myLayeredPane.getSize()))) { // Balloon is bigger than window, don't show it at all. + if (!new Rectangle(myLayeredPane.getSize()).contains(new Rectangle(myComp.getSize()))) { // Balloon is bigger than window, don't show it at all. myLayeredPane = null; hide(); return; diff --git a/platform/platform-impl/src/com/intellij/ui/ExpansionHint.java b/platform/platform-impl/src/com/intellij/ui/ExpansionHint.java index edff33c28ae7..0746b54312a1 100644 --- a/platform/platform-impl/src/com/intellij/ui/ExpansionHint.java +++ b/platform/platform-impl/src/com/intellij/ui/ExpansionHint.java @@ -37,9 +37,6 @@ public class ExpansionHint implements Hint { myListeners = ContainerUtil.newSmartList(); } - /** - * Shows the hint as the window. - */ @Override public void show(@NotNull JComponent parentComponent, int x, int y, @Nullable JComponent focusBackComponent, @Nullable HintHint hh) { myPopup = JBPopupFactory.getInstance().createComponentPopupBuilder(myComponent, null) @@ -63,10 +60,6 @@ public class ExpansionHint implements Hint { return myComponent.isShowing(); } - public JComponent getComponent() { - return myComponent; - } - @Override public void hide() { if (myPopup != null) { diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 898b55aae3ea..37464e9f8c15 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -67,6 +67,7 @@ + diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt index fbe99dd6d4c4..0796f382f06a 100644 --- a/platform/platform-resources/src/brokenPlugins.txt +++ b/platform/platform-resources/src/brokenPlugins.txt @@ -2,7 +2,7 @@ // Each line contains plugin ID and list of versions that are broken. // If plugin name or version contains a space you can quote it like in command line. -NodeJS 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 +NodeJS 134.1276 134.1163 134.1145 134.1081 134.1039 134.985 134.680 134.31 134.307 134.262 134.198 134.125 136.1141 com.jetbrains.php 133.982 133.679 133.51 133.326 131.98 131.374 131.332 131.235 131.205 130.1639 130.1481 130.1176 129.91 129.814 129.672 129.362 127.67 127.100 126.334 123.66 122.875 121.62 121.390 121.215 121.12 com.jetbrains.lang.ejs 131.17 131.12 com.jetbrains.twig 133.51 130.1639 diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputLineSplitter.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputLineSplitter.java index 14a94953ab65..1ee0b76183ee 100644 --- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputLineSplitter.java +++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/OutputLineSplitter.java @@ -131,8 +131,9 @@ public abstract class OutputLineSplitter { myStdOutChunks.clear(); } + final boolean isTCLikeFakeOutput = chunks.size() == 1; for (OutputChunk chunk : chunks) { - onLineAvailable(chunk.getText(), chunk.getKey(), false); + onLineAvailable(chunk.getText(), chunk.getKey(), isTCLikeFakeOutput); } } diff --git a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestsEventsConverterTest.java b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestsEventsConverterTest.java index 409d9923b6ac..2fafd4957935 100644 --- a/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestsEventsConverterTest.java +++ b/platform/smRunner/testSrc/com/intellij/execution/testframework/sm/runner/OutputToGeneralTestsEventsConverterTest.java @@ -43,35 +43,40 @@ public class OutputToGeneralTestsEventsConverterTest extends BaseSMTRunnerTestCa } public void testLineBreaks_ServiceMessage() { - doCheckOutptut("\n##teamcity[enteredTheMatrix timestamp = '2011-06-03T13:00:08.259+0400']\n", "[stdout]\n", true); + doCheckOutptut("\n##teamcity[enteredTheMatrix timestamp = '2011-06-03T13:00:08.259+0400']\n", "", true); } public void testLineBreaks_NormalOutput() { doCheckOutptut("\na\nb\n\nc\n", "[stdout]\n" + - "[stdout]a\n" + - "[stdout]b\n" + + "[stdout]a" + "[stdout]\n" + - "[stdout]c\n", + "[stdout]b" + + "[stdout]\n" + + "[stdout]\n" + + "[stdout]c" + + "[stdout]\n", true); } public void testLineBreaks_OutptutAndCommands() { doCheckOutptut("\na\n##teamcity[enteredTheMatrix timestamp = '2011-06-03T13:00:08.259+0400']\nb\n##teamcity[enteredTheMatrix timestamp = '2011-06-03T13:00:08.259+0400']\n\nc\n", "[stdout]\n" + - "[stdout]a\n" + - "[stdout]b\n" + + "[stdout]a" + + "[stdout]b" + "[stdout]\n" + - "[stdout]c\n", + "[stdout]c" + + "[stdout]\n", true); } public void testLineBreaks_AutoSplitIfProcessHandlerDoestSupportIt() { doCheckOutptut("\na\n##teamcity[enteredTheMatrix timestamp = '2011-06-03T13:00:08.259+0400']\nb\n##teamcity[testCount count = '1' timestamp = '2011-06-03T13:00:08.259+0400']\n\nc\n", "[stdout]\n" + - "[stdout]a\n" + - "[stdout]b\n" + + "[stdout]a" + + "[stdout]b" + "[stdout]\n" + - "[stdout]c\n", + "[stdout]c" + + "[stdout]\n", false); } diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java index 1cdbe4fa91a2..4eb294025dd7 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformTestCase.java @@ -34,7 +34,6 @@ import com.intellij.idea.IdeaLogger; import com.intellij.idea.IdeaTestApplication; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataProvider; -import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationEx; @@ -444,7 +443,7 @@ public abstract class LightPlatformTestCase extends UsefulTestCase implements Da } }); - assertEmpty(unsavedDocuments); + assertEmpty("There are unsaved documents", Arrays.asList(unsavedDocuments)); } } diff --git a/platform/util/src/com/intellij/util/NewInstanceFactory.java b/platform/util/src/com/intellij/util/NewInstanceFactory.java index 8fc93edace02..cf888f86d88e 100644 --- a/platform/util/src/com/intellij/util/NewInstanceFactory.java +++ b/platform/util/src/com/intellij/util/NewInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.intellij.util; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Factory; +import org.jetbrains.annotations.NotNull; import java.lang.reflect.Constructor; @@ -25,7 +26,7 @@ public class NewInstanceFactory implements Factory { private final Constructor myConstructor; private final Object[] myArgs; - private NewInstanceFactory(Constructor constructor, Object[] args) { + private NewInstanceFactory(@NotNull Constructor constructor, @NotNull Object[] args) { myConstructor = constructor; myArgs = args; } @@ -41,7 +42,7 @@ public class NewInstanceFactory implements Factory { } } - public static Factory fromClass(final Class clazz) { + public static Factory fromClass(@NotNull final Class clazz) { try { return new NewInstanceFactory(clazz.getConstructor(ArrayUtil.EMPTY_CLASS_ARRAY), ArrayUtil.EMPTY_OBJECT_ARRAY); } diff --git a/platform/util/src/com/intellij/util/ReflectionUtil.java b/platform/util/src/com/intellij/util/ReflectionUtil.java index 8cd891e1fc35..e930aca65fa9 100644 --- a/platform/util/src/com/intellij/util/ReflectionUtil.java +++ b/platform/util/src/com/intellij/util/ReflectionUtil.java @@ -16,12 +16,14 @@ package com.intellij.util; +import com.intellij.Patches; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.reflect.ConstructorAccessor; import java.lang.reflect.*; import java.util.ArrayList; @@ -347,6 +349,59 @@ public class ReflectionUtil { } } + static { + // method getConstructorAccessorMethod is not necessary since JDK7, use acquireConstructorAccessor return value instead + assert Patches.USE_REFLECTION_TO_ACCESS_JDK7; + } + private static final Method acquireConstructorAccessorMethod; + private static final Method getConstructorAccessorMethod; + static { + try { + Method accessor = Constructor.class.getDeclaredMethod("acquireConstructorAccessor"); + accessor.setAccessible(true); + acquireConstructorAccessorMethod = accessor; + Method get = Constructor.class.getDeclaredMethod("getConstructorAccessor"); + get.setAccessible(true); + getConstructorAccessorMethod = get; + } + catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + + @NotNull + public static ConstructorAccessor getConstructorAccessor(@NotNull Constructor constructor) { + constructor.setAccessible(true); + // it is faster to invoke constructor via sun.reflect.ConstructorAccessor; it avoids AccessibleObject.checkAccess() + try { + acquireConstructorAccessorMethod.invoke(constructor); + return (ConstructorAccessor)getConstructorAccessorMethod.invoke(constructor); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + + @NotNull + public static T createInstanceViaConstructorAccessor(@NotNull ConstructorAccessor constructorAccessor, + @NotNull Object... arguments) { + try { + return (T)constructorAccessor.newInstance(arguments); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + @NotNull + public static T createInstanceViaConstructorAccessor(@NotNull ConstructorAccessor constructorAccessor) { + try { + return (T)constructorAccessor.newInstance(ArrayUtil.EMPTY_OBJECT_ARRAY); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + @NotNull public static T createInstance(@NotNull Constructor constructor, @NotNull Object... args) { try { diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentBitSet.java b/platform/util/src/com/intellij/util/containers/ConcurrentBitSet.java index 34083f36a1f6..38e44df366ab 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentBitSet.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentBitSet.java @@ -1,415 +1,96 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. - * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * + * Copyright 2000-2014 JetBrains s.r.o. * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * + * http://www.apache.org/licenses/LICENSE-2.0 * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - package com.intellij.util.containers; -import com.intellij.util.ArrayUtil; -import com.intellij.util.concurrency.AtomicFieldUpdater; -import sun.misc.Unsafe; +import org.jetbrains.annotations.NotNull; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.LongBuffer; -import java.util.Arrays; +import java.util.concurrent.atomic.AtomicLongArray; +import java.util.concurrent.atomic.AtomicReferenceArray; /** - * This class implements a vector of bits that grows as needed. Each - * component of the bit set has a {@code boolean} value. The - * bits of a {@code BitSet} are indexed by nonnegative integers. - * Individual indexed bits can be examined, set, or cleared. One - * {@code BitSet} may be used to modify the contents of another - * {@code BitSet} through logical AND, logical inclusive OR, and - * logical exclusive OR operations. - *

- *

By default, all bits in the set initially have the value - * {@code false}. - *

- *

Every bit set has a current size, which is the number of bits - * of space currently in use by the bit set. Note that the size is - * related to the implementation of a bit set, so it may change with - * implementation. The length of a bit set relates to logical length - * of a bit set and is defined independently of implementation. - *

- *

Unless otherwise noted, passing a null parameter to any of the - * methods in a {@code BitSet} will result in a - * {@code NullPointerException}. - *

- *

A {@code BitSet} is not safe for multithreaded use without - * external synchronization. + * This class is a thread-safe version of the + * {@code java.util.BitSet} except for some methods which don't make sense in concurrent environment or those i was too lazy to implement. * - * @author Arthur van Hoff - * @author Michael McCloskey - * @author Martin Buchholz - * @since JDK1.0 + * Implementation is based on "Lock-free Dynamically Resizable Arrays" by Dechev, Pirkelbauer, Bjarne Stroustrup. + * http://www.stroustrup.com/lock-free-vector.pdf + * + * @see java.util.BitSet */ public class ConcurrentBitSet { - public static final AtomicFieldUpdater FIELD_UPDATER = - AtomicFieldUpdater.forFieldOfType(ConcurrentBitSet.class, long[].class); - /* - * BitSets are packed into arrays of "words." Currently a word is - * a long, which consists of 64 bits, requiring 6 address bits. - * The choice of word size is determined purely by performance concerns. - */ + /** + * An array of 32 longword vectors. + * Vector at index "i" has length of (1 << i) long words. + * Each long word stores next 64 bits part of the set. + * Therefore the i-th bit of the set is stored in {@code arrays.get(arrayIndex(i)).get(wordIndexInArray(i))} word in the {@code 1L << i} position. + */ + private final AtomicReferenceArray arrays = new AtomicReferenceArray(32); + private static int arrayIndex(int bitIndex) { + int i = (bitIndex >> ADDRESS_BITS_PER_WORD) + 1; + return 31 - Integer.numberOfLeadingZeros(i); + } + private static int wordIndexInArray(int bitIndex) { + int i = (bitIndex >> ADDRESS_BITS_PER_WORD) + 1; + return clearHighestBit(i); + } + + private static int clearHighestBit(int index) { + int i = index>>1; + i |= i >> 1; + i |= i >> 2; + i |= i >> 4; + i |= i >> 8; + i |= i >> 16; + return index & i; + } + + /* BitSets are packed into arrays of "words." Currently a word is + a long, which consists of 64 bits, requiring 6 address bits. + The choice of word size is determined purely by performance concerns. + */ private static final int ADDRESS_BITS_PER_WORD = 6; private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; - private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1; /* Used to shift left or right for a partial word mask */ - private static final long WORD_MASK = 0xffffffffffffffffL; - - /** - * The internal field corresponding to the serialField "bits". - */ - private volatile long[] words; - - - /** - * Given a bit index, return word index containing it. - */ - private static int wordIndex(int bitIndex) { - return bitIndex >> ADDRESS_BITS_PER_WORD; - } - - /** - * Creates a new bit set. All bits are initially {@code false}. - */ - public ConcurrentBitSet() { - initWords(BITS_PER_WORD); - } - - /** - * Creates a bit set whose initial size is large enough to explicitly - * represent bits with indices in the range {@code 0} through - * {@code nbits-1}. All bits are initially {@code false}. - * - * @param nbits the initial size of the bit set - * @throws NegativeArraySizeException if the specified initial size - * is negative - */ - public ConcurrentBitSet(int nbits) { - // nbits can't be negative; size 0 is OK - if (nbits < 0) { - throw new NegativeArraySizeException("nbits < 0: " + nbits); - } - - initWords(nbits); - } - - private void initWords(int nbits) { - words = new long[wordIndex(nbits - 1) + 1]; - } - - /** - * Creates a bit set using words as the internal representation. - * The last word (if there is one) must be non-zero. - */ - private ConcurrentBitSet(long[] words) { - this.words = words; - } - - /** - * Returns a new bit set containing all the bits in the given long array. - *

- *

More precisely, - *
{@code BitSet.valueOf(longs).get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} - *
for all {@code n < 64 * longs.length}. - *

- *

This method is equivalent to - * {@code BitSet.valueOf(LongBuffer.wrap(longs))}. - * - * @param longs a long array containing a little-endian representation - * of a sequence of bits to be used as the initial bits of the - * new bit set - * @return a {@code BitSet} containing all the bits in the long array - * @since 1.7 - */ - public static ConcurrentBitSet valueOf(long[] longs) { - int n; - for (n = longs.length; n > 0 && longs[n - 1] == 0; n--) { - ; - } - return new ConcurrentBitSet(Arrays.copyOf(longs, n)); - } - - /** - * Returns a new bit set containing all the bits in the given long - * buffer between its position and limit. - *

- *

More precisely, - *
{@code BitSet.valueOf(lb).get(n) == ((lb.get(lb.position()+n/64) & (1L<<(n%64))) != 0)} - *
for all {@code n < 64 * lb.remaining()}. - *

- *

The long buffer is not modified by this method, and no - * reference to the buffer is retained by the bit set. - * - * @param lb a long buffer containing a little-endian representation - * of a sequence of bits between its position and limit, to be - * used as the initial bits of the new bit set - * @return a {@code BitSet} containing all the bits in the buffer in the - * specified range - * @since 1.7 - */ - public static ConcurrentBitSet valueOf(LongBuffer lb) { - lb = lb.slice(); - int n; - for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--) { - ; - } - long[] words = new long[n]; - lb.get(words); - return new ConcurrentBitSet(words); - } - - /** - * Returns a new bit set containing all the bits in the given byte array. - *

- *

More precisely, - *
{@code BitSet.valueOf(bytes).get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} - *
for all {@code n < 8 * bytes.length}. - *

- *

This method is equivalent to - * {@code BitSet.valueOf(ByteBuffer.wrap(bytes))}. - * - * @param bytes a byte array containing a little-endian - * representation of a sequence of bits to be used as the - * initial bits of the new bit set - * @return a {@code BitSet} containing all the bits in the byte array - * @since 1.7 - */ - public static ConcurrentBitSet valueOf(byte[] bytes) { - return ConcurrentBitSet.valueOf(ByteBuffer.wrap(bytes)); - } - - /** - * Returns a new bit set containing all the bits in the given byte - * buffer between its position and limit. - *

- *

More precisely, - *
{@code BitSet.valueOf(bb).get(n) == ((bb.get(bb.position()+n/8) & (1<<(n%8))) != 0)} - *
for all {@code n < 8 * bb.remaining()}. - *

- *

The byte buffer is not modified by this method, and no - * reference to the buffer is retained by the bit set. - * - * @param bb a byte buffer containing a little-endian representation - * of a sequence of bits between its position and limit, to be - * used as the initial bits of the new bit set - * @return a {@code BitSet} containing all the bits in the buffer in the - * specified range - * @since 1.7 - */ - public static ConcurrentBitSet valueOf(ByteBuffer bb) { - bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN); - int n; - for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--) { - ; - } - long[] words = new long[(n + 7) / 8]; - bb.limit(n); - int i = 0; - while (bb.remaining() >= 8) { - words[i++] = bb.getLong(); - } - for (int remaining = bb.remaining(), j = 0; j < remaining; j++) { - words[i] |= (bb.get() & 0xffL) << 8 * j; - } - return new ConcurrentBitSet(words); - } - - /** - * Returns a new byte array containing all the bits in this bit set. - *

- *

More precisely, if - *
{@code byte[] bytes = s.toByteArray();} - *
then {@code bytes.length == (s.length()+7)/8} and - *
{@code s.get(n) == ((bytes[n/8] & (1<<(n%8))) != 0)} - *
for all {@code n < 8 * bytes.length}. - * - * @return a byte array containing a little-endian representation - * of all the bits in this bit set - * @since 1.7 - */ - public byte[] toByteArray() { - long[] words = this.words; - int n = words.length; - if (n == 0) { - return new byte[0]; - } - int len = 8 * (n - 1); - for (long x = words[n - 1]; x != 0; x >>>= 8) { - len++; - } - byte[] bytes = new byte[len]; - ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); - for (int i = 0; i < n - 1; i++) { - bb.putLong(words[i]); - } - for (long x = words[n - 1]; x != 0; x >>>= 8) { - bb.put((byte)(x & 0xff)); - } - return bytes; - } - - /** - * Returns a new long array containing all the bits in this bit set. - *

- *

More precisely, if - *
{@code long[] longs = s.toLongArray();} - *
then {@code longs.length == (s.length()+63)/64} and - *
{@code s.get(n) == ((longs[n/64] & (1L<<(n%64))) != 0)} - *
for all {@code n < 64 * longs.length}. - * - * @return a long array containing a little-endian representation - * of all the bits in this bit set - * @since 1.7 - */ - public long[] toLongArray() { - long[] words = this.words; - return Arrays.copyOf(words, words.length); - } - - /** - * Ensures that the BitSet can hold enough words. - * - * @param wordsRequired the minimum acceptable number of words. - */ - private long[] ensureCapacity(int wordsRequired) { - long[] newWords; - long[] words; - do { - words = this.words; - if (words.length >= wordsRequired) { - newWords = words; - break; - } - int request = Math.max(3 * words.length / 2, wordsRequired); - newWords = Arrays.copyOf(words, request); - } while (!FIELD_UPDATER.compareAndSet(this, words, newWords)); - return newWords; - } - - /** - * Ensures that the BitSet can accommodate a given wordIndex, - * temporarily violating the invariants. The caller must - * restore the invariants before returning to the user, - * possibly using recalculateWordsInUse(). - * - * @param wordIndex the index to be accommodated. - */ - private long[] expandTo(int wordIndex) { - int wordsRequired = wordIndex + 1; - return ensureCapacity(wordsRequired); - } - - /** - * Checks that fromIndex ... toIndex is a valid range of bit indices. - */ - private static void checkRange(int fromIndex, int toIndex) { - if (fromIndex < 0) { - throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); - } - if (toIndex < 0) { - throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex); - } - if (fromIndex > toIndex) { - throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + - " > toIndex: " + toIndex); - } - } + private static final long WORD_MASK = -1L; /** * Sets the bit at the specified index to the complement of its * current value. * * @param bitIndex the index of the bit to flip + * @return new bit value * @throws IndexOutOfBoundsException if the specified index is negative - * @since 1.4 */ - public void flip(int bitIndex) { + public boolean flip(int bitIndex) { if (bitIndex < 0) { throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); } - int wordIndex = wordIndex(bitIndex); + AtomicLongArray array = getOrCreateArray(bitIndex); - while (true) { - long[] words = expandTo(wordIndex); - long word; - long newWord; - do { - word = words[wordIndex]; - newWord = word ^ (1L << bitIndex); - } - while (!compareAndSet(words, wordIndex, word, newWord)); - if (words == this.words) break; - } - } + int wordIndexInArray = wordIndexInArray(bitIndex); - /** - * Sets each bit from the specified {@code fromIndex} (inclusive) to the - * specified {@code toIndex} (exclusive) to the complement of its current - * value. - * - * @param fromIndex index of the first bit to flip - * @param toIndex index after the last bit to flip - * @throws IndexOutOfBoundsException if {@code fromIndex} is negative, - * or {@code toIndex} is negative, or {@code fromIndex} is - * larger than {@code toIndex} - * @since 1.4 - */ - public void flip(int fromIndex, int toIndex) { - checkRange(fromIndex, toIndex); - - if (fromIndex == toIndex) { - return; - } - - int startWordIndex = wordIndex(fromIndex); - int endWordIndex = wordIndex(toIndex - 1); - - - long firstWordMask = WORD_MASK << fromIndex; - long lastWordMask = WORD_MASK >>> -toIndex; - long[] words = expandTo(endWordIndex); - if (startWordIndex == endWordIndex) { - // Case 1: One word - words[startWordIndex] ^= firstWordMask & lastWordMask; - } - else { - // Case 2: Multiple words - // Handle first word - words[startWordIndex] ^= firstWordMask; - - // Handle intermediate words, if any - for (int i = startWordIndex + 1; i < endWordIndex; i++) { - words[i] ^= WORD_MASK; - } - - // Handle last word - words[endWordIndex] ^= lastWordMask; + long word; + long newWord; + do { + word = array.get(wordIndexInArray); + newWord = word ^ (1L << bitIndex); } + while (!array.compareAndSet(wordIndexInArray, word, newWord)); + return (newWord & (1L << bitIndex)) != 0; } /** @@ -417,26 +98,22 @@ public class ConcurrentBitSet { * * @param bitIndex a bit index * @throws IndexOutOfBoundsException if the specified index is negative - * @since JDK1.0 */ public void set(int bitIndex) { if (bitIndex < 0) { throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); } - int wordIndex = wordIndex(bitIndex); + AtomicLongArray array = getOrCreateArray(bitIndex); - long[] words = expandTo(wordIndex); - while (true) { - long word; - long newWord; - do { - word = words[wordIndex]; - newWord = word | (1L << bitIndex); - } - while (!compareAndSet(words, wordIndex, word, newWord)); - if (words == this.words) break; + int wordIndexInArray = wordIndexInArray(bitIndex); + long word; + long newWord; + do { + word = array.get(wordIndexInArray); + newWord = word | (1L << bitIndex); } + while (!array.compareAndSet(wordIndexInArray, word, newWord)); } /** @@ -445,7 +122,6 @@ public class ConcurrentBitSet { * @param bitIndex a bit index * @param value a boolean value to set * @throws IndexOutOfBoundsException if the specified index is negative - * @since 1.4 */ public void set(int bitIndex, boolean value) { if (value) { @@ -456,79 +132,56 @@ public class ConcurrentBitSet { } } - - /** * Sets the bit specified by the index to {@code false}. * * @param bitIndex the index of the bit to be cleared * @throws IndexOutOfBoundsException if the specified index is negative - * @since JDK1.0 */ public void clear(int bitIndex) { if (bitIndex < 0) { throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); } - int wordIndex = wordIndex(bitIndex); - long[] words = this.words; - if (wordIndex >= words.length) { - return; + AtomicLongArray array = getOrCreateArray(bitIndex); + + int wordIndexInArray = wordIndexInArray(bitIndex); + long word; + long newWord; + do { + word = array.get(wordIndexInArray); + newWord = word & ~ (1L << bitIndex); } + while (!array.compareAndSet(wordIndexInArray, word, newWord)); + } - while (true) { - long word; - long newWord; - do { - word = words[wordIndex]; - newWord = word & ~(1L << bitIndex); - } - while (!compareAndSet(words, wordIndex, word, newWord)); - if (words == this.words) break; + @NotNull + private AtomicLongArray getOrCreateArray(int bitIndex) { + int arrayIndex = arrayIndex(bitIndex); + AtomicLongArray array; + + // while loop is here because of clear() method + while ((array = arrays.get(arrayIndex)) == null) { + arrays.compareAndSet(arrayIndex, null, new AtomicLongArray(1< words.length) throw new IndexOutOfBoundsException(); - return ((long) index << shift) + base; - } - - private static boolean compareAndSet(long[] words, int wordIndex, long expectedWord, long targetWord) { - return UNSAFE.compareAndSwapLong(words, indexToOffset(words, wordIndex), expectedWord, targetWord); - } /** - * Sets all of the bits in this BitSet to {@code false}. - * - * @since 1.4 + * Clear method in presense of concurrency complicates everything to no end. + * PLEASE REWRITE EVERY OTHER METHOD IF EVER DECIDE TO IMPLEMENT THIS */ public void clear() { - words = ArrayUtil.EMPTY_LONG_ARRAY; + for (int i=0; i len) { - toIndex = len; - } - - ConcurrentBitSet result = new ConcurrentBitSet(toIndex - fromIndex); - int targetWords = wordIndex(toIndex - fromIndex - 1) + 1; - int sourceIndex = wordIndex(fromIndex); - boolean wordAligned = (fromIndex & BIT_INDEX_MASK) == 0; - - // Process all words but the last word - for (int i = 0; i < targetWords - 1; i++, sourceIndex++) { - result.words[i] = wordAligned ? words[sourceIndex] : - words[sourceIndex] >>> fromIndex | - words[sourceIndex + 1] << -fromIndex; - } - - // Process the last word - long lastWordMask = WORD_MASK >>> -toIndex; - result.words[targetWords - 1] = - (toIndex - 1 & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK) - ? /* straddles source words */ - words[sourceIndex] >>> fromIndex | - (words[sourceIndex + 1] & lastWordMask) << -fromIndex - : - (words[sourceIndex] & lastWordMask) >>> fromIndex; - - return result; - } - - /** - * Returns the index of the first bit that is set to {@code true} - * that occurs on or after the specified starting index. If no such - * bit exists then {@code -1} is returned. - *

- *

To iterate over the {@code true} bits in a {@code BitSet}, - * use the following loop: - *

- *

 {@code
-   * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
-   *     // operate on index i here
-   * }}
- * - * @param fromIndex the index to start checking from (inclusive) - * @return the index of the next set bit, or {@code -1} if there - * is no such bit - * @throws IndexOutOfBoundsException if the specified index is negative - * @since 1.4 - */ + * Returns the index of the first bit that is set to {@code true} + * that occurs on or after the specified starting index. If no such + * bit exists then {@code -1} is returned. + *

+ *

To iterate over the {@code true} bits, + * use the following loop: + *

+ *

 {@code
+  * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+  *     // operate on index i here
+  * }}
+ * + * @param fromIndex the index to start checking from (inclusive) + * @return the index of the next set bit, or {@code -1} if there + * is no such bit + * @throws IndexOutOfBoundsException if the specified index is negative + */ public int nextSetBit(int fromIndex) { if (fromIndex < 0) { - throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); + throw new IndexOutOfBoundsException("bitIndex < 0: " + fromIndex); } - int u = wordIndex(fromIndex); - long[] words = this.words; - if (u >= words.length) { + int arrayIndex; + AtomicLongArray array = null; + for (arrayIndex = arrayIndex(fromIndex); arrayIndex < arrays.length() && (array = arrays.get(arrayIndex)) == null; arrayIndex++); + if (array == null) { return -1; } - long word = words[u] & WORD_MASK << fromIndex; + int wordIndexInArray = wordIndexInArray(fromIndex); + + long word = array.get(wordIndexInArray) & (WORD_MASK << fromIndex); while (true) { if (word != 0) { - return u * BITS_PER_WORD + Long.numberOfTrailingZeros(word); + return ((1<= words.length) { - return fromIndex; + int arrayIndex = arrayIndex(fromIndex); + AtomicLongArray array = arrays.get(arrayIndex); + int wordIndexInArray = wordIndexInArray(fromIndex); + if (array == null) { + return ((1< - *

To iterate over the {@code true} bits in a {@code BitSet}, - * use the following loop: - *

- *

 {@code
-   * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
-   *     // operate on index i here
-   * }}
- * - * @param fromIndex the index to start checking from (inclusive) - * @return the index of the previous set bit, or {@code -1} if there - * is no such bit - * @throws IndexOutOfBoundsException if the specified index is less - * than {@code -1} - * @since 1.7 - */ - public int previousSetBit(int fromIndex) { - if (fromIndex < 0) { - if (fromIndex == -1) { - return -1; - } - throw new IndexOutOfBoundsException( - "fromIndex < -1: " + fromIndex); - } - - int u = wordIndex(fromIndex); - long[] words = this.words; - if (u >= words.length) { - return length() - 1; - } - - long word = words[u] & WORD_MASK >>> -(fromIndex + 1); - - while (true) { - if (word != 0) { - return (u + 1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); - } - if (u-- == 0) { - return -1; - } - word = words[u]; - } - } - - /** - * Returns the index of the nearest bit that is set to {@code false} - * that occurs on or before the specified starting index. - * If no such bit exists, or if {@code -1} is given as the - * starting index, then {@code -1} is returned. - * - * @param fromIndex the index to start checking from (inclusive) - * @return the index of the previous clear bit, or {@code -1} if there - * is no such bit - * @throws IndexOutOfBoundsException if the specified index is less - * than {@code -1} - * @since 1.7 - */ - public int previousClearBit(int fromIndex) { - if (fromIndex < 0) { - if (fromIndex == -1) { - return -1; - } - throw new IndexOutOfBoundsException( - "fromIndex < -1: " + fromIndex); - } - - int u = wordIndex(fromIndex); - long[] words = this.words; - if (u >= words.length) { - return fromIndex; - } - - long word = ~words[u] & WORD_MASK >>> -(fromIndex + 1); - - while (true) { - if (word != 0) { - return (u + 1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); - } - if (u-- == 0) { - return -1; - } - word = ~words[u]; - } - } - - /** - * Returns the "logical size" of this {@code BitSet}: the index of - * the highest set bit in the {@code BitSet} plus one. Returns zero - * if the {@code BitSet} contains no set bits. - * - * @return the logical size of this {@code BitSet} - * @since 1.2 - */ - public int length() { - long[] words = this.words; - if (words.length == 0) { - return 0; - } - - return BITS_PER_WORD * (words.length - 1) + - BITS_PER_WORD - Long.numberOfLeadingZeros(words[words.length - 1]); - } - - - /** - * Returns true if the specified {@code BitSet} has any bits set to - * {@code true} that are also set to {@code true} in this {@code BitSet}. - * - * @param set {@code BitSet} to intersect with - * @return boolean indicating whether this {@code BitSet} intersects - * the specified {@code BitSet} - * @since 1.4 - */ - public boolean intersects(ConcurrentBitSet set) { - long[] w = words; - long[] sw = set.words; - for (int i = Math.min(w.length, sw.length) - 1; i >= 0; i--) { - if ((w[i] & sw[i]) != 0) { - return true; - } - } - return false; - } - - /** - * Returns the number of bits set to {@code true} in this {@code BitSet}. - * - * @return the number of bits set to {@code true} in this {@code BitSet} - * @since 1.4 - */ - public int cardinality() { - int sum = 0; - long[] words = this.words; - for (int i = 0; i < words.length; i++) { - sum += Long.bitCount(words[i]); - } - return sum; - } - - - - - - /** - * Returns the hash code value for this bit set. The hash code depends - * only on which bits are set within this {@code BitSet}. - *

- *

The hash code is defined to be the result of the following - * calculation: - *

 {@code
-   * public int hashCode() {
-   *     long h = 1234;
-   *     long[] words = toLongArray();
-   *     for (int i = words.length; --i >= 0; )
-   *         h ^= words[i] * (i + 1);
-   *     return (int)((h >> 32) ^ h);
-   * }}
- * Note that the hash code changes if the set of bits is altered. - * - * @return the hash code value for this bit set - */ + * Returns the hash code value for this bit set. The hash code depends + * only on which bits are set. + *

+ *

The hash code is defined to be the result of the following + * calculation: + *

 {@code
+  * public int hashCode() {
+  *     long h = 1234;
+  *     for (int i = words.length; --i >= 0; )
+  *         h ^= words[i] * (i + 1);
+  *     return (int)((h >> 32) ^ h);
+  * }}
+ * Note that the hash code changes if the set of bits is altered. + * + * @return the hash code value for this bit set + */ public int hashCode() { long h = 1234; - long[] words = this.words; - for (int i = words.length; --i >= 0; ) { - h ^= words[i] * (i + 1); + for (int a = 0; a> 32 ^ h); } + /** - * Returns the number of bits of space actually in use by this - * {@code BitSet} to represent bit values. - * The maximum element in the set is the size - 1st element. - * - * @return the number of bits currently in this bit set - */ + * Returns the number of bits of space actually in use + * + * @return the number of bits currently in this bit set + */ public int size() { - return words.length * BITS_PER_WORD; + int a; + for (a = arrays.length() - 1; a >= 0; a--) { + AtomicLongArray array = arrays.get(a); + if (array != null) break; + } + return ((1<((BitSet)obj).get(k) == this.get(k) - * must be true. The current sizes of the two bit sets are not compared. - * - * @param obj the object to compare with - * @return {@code true} if the objects are the same; - * {@code false} otherwise - * @see #size() - */ + * Compares this object against the specified object. + * The result is {@code true} if and only if the argument is + * not {@code null} and is a {@code ConcurrentBitSet} object that has + * exactly the same set of bits set to {@code true} as this bit + * set. That is, for every nonnegative {@code int} index {@code k}, + *
((ConcurrentBitSet)obj).get(k) == this.get(k)
+ * must be true. The current sizes of the two bit sets are not compared. + * + * @param obj the object to compare with + * @return {@code true} if the objects are the same; + * {@code false} otherwise + * @see #size() + */ public boolean equals(Object obj) { if (!(obj instanceof ConcurrentBitSet)) { return false; @@ -886,16 +363,15 @@ public class ConcurrentBitSet { ConcurrentBitSet set = (ConcurrentBitSet)obj; - long[] words = this.words; - long[] setWords = set.words; - if (words.length != setWords.length) { - return false; - } - - // Check words in use by both BitSets - for (int i = 0; i < words.length; i++) { - if (words[i] != setWords[i]) { - return false; + for (int i = 0; i < arrays.length(); i++) { + AtomicLongArray array1 = arrays.get(i); + AtomicLongArray array2 = set.arrays.get(i); + if (array1 == null && array2 == null) continue; + int size = array1 == null ? array2.length() : array1.length(); + for (int k=0; k - *

Example: - *

-   * BitSet drPepper = new BitSet();
- * Now {@code drPepper.toString()} returns "{@code {}}". - *
-   * drPepper.set(2);
- * Now {@code drPepper.toString()} returns "{@code {2}}". - *
-   * drPepper.set(4);
-   * drPepper.set(10);
- * Now {@code drPepper.toString()} returns "{@code {2, 4, 10}}". - * - * @return a string representation of this bit set - */ + * Returns a string representation of this bit set. For every index + * which contains a bit in the set + * state, the decimal representation of that index is included in + * the result. Such indices are listed in order from lowest to + * highest, separated by ", " (a comma and a space) and + * surrounded by braces, resulting in the usual mathematical + * notation for a set of integers. + * + * @return a string representation of this bit set + */ public String toString() { - - long[] words = this.words; - int numBits = words.length > 128 ? - cardinality() : words.length * BITS_PER_WORD; - StringBuilder b = new StringBuilder(6 * numBits + 2); + StringBuilder b = new StringBuilder(); b.append('{'); int i = nextSetBit(0); diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java index d70ef92d98e7..09eb36c84272 100644 --- a/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java +++ b/platform/util/src/com/intellij/util/containers/ConcurrentHashMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -18,6 +18,7 @@ package com.intellij.util.containers; import com.intellij.util.ConcurrencyUtil; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.concurrency.AtomicFieldUpdater; import gnu.trove.TObjectHashingStrategy; import jsr166e.CountedCompleter; import jsr166e.ForkJoinPool; @@ -7137,32 +7138,7 @@ public class ConcurrentHashMap extends AbstractMap implements Concur * @return a sun.misc.Unsafe */ private static Unsafe getUnsafe() { - try { - return Unsafe.getUnsafe(); - } - catch (SecurityException tryReflectionInstead) { - } - try { - return AccessController.doPrivileged - (new PrivilegedExceptionAction() { - @Override - public Unsafe run() throws Exception { - Class k = Unsafe.class; - for (Field f : k.getDeclaredFields()) { - f.setAccessible(true); - Object x = f.get(null); - if (k.isInstance(x)) { - return k.cast(x); - } - } - throw new NoSuchFieldError("the Unsafe"); - } - }); - } - catch (PrivilegedActionException e) { - throw new RuntimeException("Could not initialize intrinsics", - e.getCause()); - } + return AtomicFieldUpdater.getUnsafe(); } ////////////////////// IJ specific diff --git a/platform/util/src/com/intellij/util/text/StringFactory.java b/platform/util/src/com/intellij/util/text/StringFactory.java index 85ae65e2b655..c34dd1fe17b3 100644 --- a/platform/util/src/com/intellij/util/text/StringFactory.java +++ b/platform/util/src/com/intellij/util/text/StringFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,11 @@ */ package com.intellij.util.text; +import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NotNull; import sun.reflect.ConstructorAccessor; import java.lang.reflect.Constructor; -import java.lang.reflect.Method; public class StringFactory { // String(char[], boolean). Works since JDK1.7, earlier JDKs have too slow reflection anyway @@ -29,11 +29,7 @@ public class StringFactory { ConstructorAccessor constructorAccessor = null; try { Constructor newC = String.class.getDeclaredConstructor(char[].class, boolean.class); - newC.setAccessible(true); - // it is faster to invoke constructor via sun.reflect.ConstructorAccessor; it avoids AccessibleObject.checkAccess() - Method accessor = Constructor.class.getDeclaredMethod("acquireConstructorAccessor"); - accessor.setAccessible(true); - constructorAccessor = (ConstructorAccessor)accessor.invoke(newC); + constructorAccessor = ReflectionUtil.getConstructorAccessor(newC); } catch (Exception ignored) { } @@ -50,12 +46,7 @@ public class StringFactory { @NotNull public static String createShared(@NotNull char[] chars) { if (ourConstructorAccessor != null) { - try { - return (String)ourConstructorAccessor.newInstance(new Object[]{chars, Boolean.TRUE}); - } - catch (Exception e) { - throw new RuntimeException(e); - } + return ReflectionUtil.createInstanceViaConstructorAccessor(ourConstructorAccessor, chars, Boolean.TRUE); } return new String(chars); } diff --git a/platform/util/testSrc/com/intellij/util/containers/ConcurrentBitSetTest.java b/platform/util/testSrc/com/intellij/util/containers/ConcurrentBitSetTest.java new file mode 100644 index 000000000000..a7e315a4099e --- /dev/null +++ b/platform/util/testSrc/com/intellij/util/containers/ConcurrentBitSetTest.java @@ -0,0 +1,124 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.containers; + +import junit.framework.TestCase; + +public class ConcurrentBitSetTest extends TestCase { + public void test() { + ConcurrentBitSet bitSet = new ConcurrentBitSet(); + final ConcurrentBitSet emptySet = new ConcurrentBitSet(); + int N = 3000; + assertEquals(0, bitSet.nextClearBit(0)); + assertEquals(bitSet, emptySet); + for (int i=0; i headers, @NotNull HttpVerb verb) throws IOException { if (EventQueue.isDispatchThread() && !ApplicationManager.getApplication().isUnitTestMode()) { - LOG.warn("Network operation in EDT"); + LOG.warn("Network operation in EDT"); // TODO: fix } HttpMethod method = null; @@ -152,6 +160,17 @@ public class GithubApiUtil { ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8")); } break; + case PATCH: + method = new PostMethod(uri) { // TODO: httpclient 4.x + @Override + public String getName() { + return "PATCH"; + } + }; + if (requestBody != null) { + ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8")); + } + break; case GET: method = new GetMethod(uri); break; @@ -408,7 +427,8 @@ public class GithubApiUtil { public static void askForTwoFactorCodeSMS(@NotNull GithubAuthData auth) { try { postRequest(auth, "/authorizations", null, ACCEPT_V3_JSON); - } catch (IOException e) { + } + catch (IOException e) { LOG.info(e); } } @@ -441,25 +461,78 @@ public class GithubApiUtil { } @NotNull - public static String getScopedToken(@NotNull GithubAuthData auth, @NotNull Collection scopes, @Nullable String note) + public static String getScopedToken(@NotNull GithubAuthData auth, @NotNull Collection scopes, @NotNull String note) throws IOException { + GithubAuthorization token = findToken(auth, note); + if (token == null) { + return getNewScopedToken(auth, scopes, note).getToken(); + } + if (token.getScopes().containsAll(scopes)) { + return token.getToken(); + } + return updateTokenScopes(auth, token, scopes).getToken(); + } + + @NotNull + private static GithubAuthorization updateTokenScopes(@NotNull GithubAuthData auth, + @NotNull GithubAuthorization token, + @NotNull Collection scopes) throws IOException { try { - String path = "/authorizations"; + String path = "/authorizations/" + token.getId(); - GithubAuthorizationRequest request = new GithubAuthorizationRequest(new ArrayList(scopes), note, null); - GithubAuthorization response = - createDataFromRaw(fromJson(postRequest(auth, path, gson.toJson(request)), GithubAuthorizationRaw.class), GithubAuthorization.class); + GithubAuthorizationUpdateRequest request = new GithubAuthorizationUpdateRequest(new ArrayList(scopes)); - return response.getToken(); + return createDataFromRaw(fromJson(patchRequest(auth, path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class), + GithubAuthorization.class); } catch (GithubConfusingException e) { - e.setDetails("Can't get token: scopes - " + scopes); + e.setDetails("Can't update token: scopes - " + scopes); throw e; } } @NotNull - public static String getMasterToken(@NotNull GithubAuthData auth, @Nullable String note) throws IOException { + private static GithubAuthorization getNewScopedToken(@NotNull GithubAuthData auth, + @NotNull Collection scopes, + @NotNull String note) + throws IOException { + try { + String path = "/authorizations"; + + GithubAuthorizationCreateRequest request = new GithubAuthorizationCreateRequest(new ArrayList(scopes), note, null); + + return createDataFromRaw(fromJson(postRequest(auth, path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class), + GithubAuthorization.class); + } + catch (GithubConfusingException e) { + e.setDetails("Can't create token: scopes - " + scopes + " - note " + note); + throw e; + } + } + + @Nullable + private static GithubAuthorization findToken(@NotNull GithubAuthData auth, @NotNull String note) throws IOException { + try { + String path = "/authorizations"; + + PagedRequest request = + new PagedRequest(path, GithubAuthorization.class, GithubAuthorizationRaw[].class, ACCEPT_V3_JSON); + + List tokens = request.getAll(auth); + + for (GithubAuthorization token : tokens) { + if (note.equals(token.getNote())) return token; + } + return null; + } + catch (GithubConfusingException e) { + e.setDetails("Can't get available tokens"); + throw e; + } + } + + @NotNull + public static String getMasterToken(@NotNull GithubAuthData auth, @NotNull String note) throws IOException { // "repo" - read/write access to public/private repositories // "gist" - create/delete gists List scopes = Arrays.asList("repo", "gist"); @@ -468,7 +541,7 @@ public class GithubApiUtil { } @NotNull - public static String getReadOnlyToken(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @Nullable String note) + public static String getReadOnlyToken(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @NotNull String note) throws IOException { GithubRepo repository = getDetailedRepoInfo(auth, user, repo); @@ -543,10 +616,14 @@ public class GithubApiUtil { // One of this may not exist in GitHub enterprise try { repos.addAll(getMembershipRepos(auth)); - } catch (GithubStatusCodeException ignore) {} + } + catch (GithubStatusCodeException ignore) { + } try { repos.addAll(getWatchedRepos(auth)); - } catch (GithubStatusCodeException ignore) {} + } + catch (GithubStatusCodeException ignore) { + } return repos; } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorization.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorization.java index ad34cbd7865f..d5ac4275152f 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorization.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorization.java @@ -16,6 +16,7 @@ package org.jetbrains.plugins.github.api; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -23,12 +24,16 @@ import java.util.List; * @author Aleksey Pivovarov */ public class GithubAuthorization { + private final long myId; + @Nullable private final String myNote; @NotNull private final String myToken; @NotNull private final List myScopes; - public GithubAuthorization(@NotNull String token, @NotNull List scopes) { + public GithubAuthorization(long id, @NotNull String token, @NotNull List scopes, @Nullable String note) { + myId = id; myToken = token; myScopes = scopes; + myNote = note; } @NotNull @@ -40,4 +45,13 @@ public class GithubAuthorization { public List getScopes() { return myScopes; } + + @Nullable + public String getNote() { + return myNote; + } + + public long getId() { + return myId; + } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRequest.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationCreateRequest.java similarity index 86% rename from plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRequest.java rename to plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationCreateRequest.java index 705cdbd950e7..6f6d28b0de85 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRequest.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationCreateRequest.java @@ -24,13 +24,13 @@ import java.util.List; * @author Aleksey Pivovarov */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) -class GithubAuthorizationRequest { +class GithubAuthorizationCreateRequest { @NotNull private final List scopes; @Nullable private final String note; @Nullable private final String noteUrl; - public GithubAuthorizationRequest(@NotNull List scopes, @Nullable String note, @Nullable String noteUrl) { + public GithubAuthorizationCreateRequest(@NotNull List scopes, @Nullable String note, @Nullable String noteUrl) { this.scopes = scopes; this.note = note; this.noteUrl = noteUrl; diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRaw.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRaw.java index 0af5a6e24d33..3abddbd00aa2 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRaw.java +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationRaw.java @@ -34,7 +34,7 @@ class GithubAuthorizationRaw implements DataConstructor { @SuppressWarnings("ConstantConditions") public GithubAuthorization createAuthorization() { - return new GithubAuthorization(token, scopes); + return new GithubAuthorization(id, token, scopes, note); } @SuppressWarnings("unchecked") diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationUpdateRequest.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationUpdateRequest.java new file mode 100644 index 000000000000..8173d5a95345 --- /dev/null +++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubAuthorizationUpdateRequest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.github.api; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Aleksey Pivovarov + */ +@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) +class GithubAuthorizationUpdateRequest { + @NotNull private final List addScopes; + + public GithubAuthorizationUpdateRequest(@NotNull List newScopes) { + this.addScopes = newScopes; + } +} diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index 059be25cb7e3..400be7248f87 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -131,7 +131,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor